From a71465e935a178478d269e828550b7e3fc475fab Mon Sep 17 00:00:00 2001
From: bnewbold <bnewbold@robocracy.org>
Date: Sat, 14 Jan 2017 19:37:09 -0800
Subject: basic LaTeX transpiling

---
 src/lib.rs             |  1 +
 src/transpile_js.rs    |  2 +-
 src/transpile_latex.rs | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 101 insertions(+), 1 deletion(-)
 create mode 100644 src/transpile_latex.rs

(limited to 'src')

diff --git a/src/lib.rs b/src/lib.rs
index 4c32d66..cf88d3b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,6 +11,7 @@ pub extern crate modelica_parser;
 pub mod modelica_model;
 pub mod transpile_scheme;
 pub mod transpile_js;
+pub mod transpile_latex;
 
 use std::path::Path;
 use std::fs;
diff --git a/src/transpile_js.rs b/src/transpile_js.rs
index 269e900..4150b12 100644
--- a/src/transpile_js.rs
+++ b/src/transpile_js.rs
@@ -57,7 +57,7 @@ impl TranspileJS for Expr {
             BinExpr(op, ref l, ref r) => {
                 Ok(format!("({} {:?} {})", try!(l.repr_js()), op, try!(r.repr_js())))
             }
-            Array(_) => bail!("Array unimplemented"),
+            Array(_) => unimplemented!(),
         }
     }
 }
diff --git a/src/transpile_latex.rs b/src/transpile_latex.rs
new file mode 100644
index 0000000..1c777d2
--- /dev/null
+++ b/src/transpile_latex.rs
@@ -0,0 +1,99 @@
+
+extern crate modelica_parser;
+
+use self::modelica_parser::*;
+use errors::Result;
+
+pub trait TranspileLaTeX {
+    fn repr_latex(&self) -> Result<String>;
+}
+
+
+impl TranspileLaTeX for ModelicaModel {
+    fn repr_latex(&self) -> Result<String> {
+
+        let mut result = r#"\begin{array}{rcl}"#.to_string() + "\n";
+
+        for eq in &self.equations {
+            result += &format!("  {} & = & {} \\\\\n",
+                try!(eq.lhs.repr_latex()),
+                try!(eq.rhs.repr_latex()));
+        }
+        result += "\n";
+        result += r#"\end{array}"#;
+        Ok(result)
+    }
+}
+
+fn is_latexy_ident(s: &str) -> bool {
+    let latexy_idents = [
+        "alpha", "Alpha", "beta", "gamma", "Gamma", "delta", "Delta",
+        "epsilon", "zeta", "eta", "theta", "Theta", "iota", "kappa", "lambda",
+        "Lambda", "mu", "nu", "xi", "Xi", "omicron", "pi", "Pi", "rho",
+        "sigma", "Sigma", "tau", "upsilon", "phi", "Phi", "chi", "psi", "Psi",
+        "omega", "Omega"];
+    latexy_idents.contains(&s)
+}
+
+impl TranspileLaTeX for Expr {
+    fn repr_latex(&self) -> Result<String> {
+        use modelica_parser::Expr::*;
+        use modelica_parser::MathUnaryFunc::*;
+        use modelica_parser::BinOperator::*;
+        match *self {
+            Integer(e) => Ok(format!("{}", e)),
+            Float(e) => Ok(format!("{}", e)),
+            Boolean(true) => Ok(format!("true")),
+            Boolean(false) => Ok(format!("false")),
+            StringLiteral(ref s) => Ok(format!("\\text{{ {} }}", s)),
+            // Tries to do script for simple cases ("M_1")
+            Ident(ref e) => {
+                if e.contains('_') {
+                    let split: Vec<&str> = e.splitn(2, '_').collect();
+                    Ok(format!(r"{}{}_{{ {}{} }}",
+                        if is_latexy_ident(split[0]) { "\\" } else { "" },
+                        split[0],
+                        if is_latexy_ident(split[1]) { "\\" } else { "" },
+                        split[1]))
+                } else {
+                    Ok(format!("{}{}",
+                        if is_latexy_ident(e) { "\\" } else { "" },
+                        e))
+                }
+            },
+            // Treate simple derivatives (common case) differently from complex
+            // (destructuring with 'box' keyword is still unstable)
+            Der(ref e) =>
+                if let &Ident(_) = e.as_ref() {
+                    Ok(format!("\\frac{{ d {} }}{{ dt }}", try!(e.repr_latex())))
+                } else {
+                    Ok(format!("\\frac{{ d }}{{ dt }} {}", try!(e.repr_latex())))
+                },
+            Sign(ref e) => Ok(format!("\\sign{{ {} }}", try!(e.repr_latex()))),
+            // LaTeX depends on the unary
+            MathUnaryExpr(Abs, ref e) => Ok(format!("\\left\\|{}\\right\\|", try!(e.repr_latex()))),
+            MathUnaryExpr(Sqrt, ref e) => Ok(format!("\\sqrt{{ {} }}", try!(e.repr_latex()))),
+            MathUnaryExpr(Log10, ref e) => Ok(format!("\\log_{{10}}{{ {} }} ", try!(e.repr_latex()))),
+            MathUnaryExpr(func, ref e) => Ok(format!("\\{:?}{{ {} }}", func, try!(e.repr_latex()))),
+            // LaTeX depends on binexpr
+            BinExpr(Divide, ref l, ref r) => 
+                Ok(format!("\\frac{{ {} }}{{ {} }}",
+                        try!(l.repr_latex()),
+                        try!(r.repr_latex()))),
+            BinExpr(Multiply, ref l, ref r) =>
+                Ok(format!("{} \\cdot {}",
+                        try!(l.repr_latex()),
+                        try!(r.repr_latex()))),
+            BinExpr(Exponentiate, ref l, ref r) =>
+                Ok(format!("{}^{{ {} }}",
+                        try!(l.repr_latex()),
+                        try!(r.repr_latex()))),
+            BinExpr(op, ref l, ref r) =>
+                Ok(format!("\\left({} {:?} {}\\right)",
+                        try!(l.repr_latex()),
+                        op,
+                        try!(r.repr_latex()))),
+            Array(_) => unimplemented!(),
+        }
+    }
+}
-- 
cgit v1.2.3