aboutsummaryrefslogtreecommitdiffstats
path: root/src/repr_latex.rs
blob: b5426e80b508379690b87c69380a16ac95719d0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139

extern crate modelica_parser;

use self::modelica_parser::*;
use errors::Result;

pub trait ReprLaTeX {
    fn repr_latex(&self) -> Result<String>;
}

pub trait ReprVarsHTML {
    fn repr_vars_html(&self) -> Result<String>;
}

impl ReprLaTeX 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)
    }
}

impl ReprVarsHTML for ModelicaModel {

    fn repr_vars_html(&self) -> Result<String> {

        let mut rows = vec![];
        for c in &self.components {
            rows.push(format!(r#"<tr><td>\({name}\)</td>
                                     <td>{prefix}</td>
                                     <td>{description}</td>
                                     <td>\({default}\)</td>
                                     <td>{specifier}</td>
                                 </tr>"#,
                prefix = if let Some(ref cp) = c.prefix {
                    format!("{:?}", cp) }
                    else { "free".to_string() },
                specifier = c.specifier,
                name = try!(Expr::Ident(c.name.clone()).repr_latex()),
                default = if let Some(ref v) = c.value {
                    try!(v.repr_latex()) }
                    else { "".to_string() },
                description = if let Some(ref d) = c.description {
                    d.clone() }
                    else { "".to_string() }));
        }
        let rows = rows.join("\n");
        Ok(format!(r#"<table>
            <tr><th>Variable</th>
                <th>Type</th>
                <th>Description</th>
                <th>Value (default)</th>
                <th>Datatype</th>
            {rows}
            </table>"#,
                rows = rows))
    }
}

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 ReprLaTeX 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!(),
        }
    }
}