rink_core/ast/
mod.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use crate::output::Digits;
6use crate::types::Numeric;
7use chrono_tz::Tz;
8use serde_derive::Serialize;
9use std::fmt;
10
11mod def;
12mod expr;
13mod query;
14#[cfg(test)]
15mod test;
16
17pub use def::{DatePattern, Def, DefEntry, Defs, ExprString, Property};
18pub use expr::{Expr, Precedence};
19pub use query::{Conversion, Query};
20
21#[derive(Debug, Clone, Serialize, Copy, Eq, PartialEq)]
22#[serde(rename_all = "camelCase")]
23pub enum Degree {
24    Celsius,
25    Fahrenheit,
26    Reaumur,
27    Romer,
28    Delisle,
29    Newton,
30}
31
32#[derive(Debug, Clone, Serialize, PartialEq)]
33pub enum DateToken {
34    Literal(String),
35    Number(String, Option<String>),
36    Colon,
37    Dash,
38    Space,
39    Plus,
40    Error(String),
41}
42
43#[derive(Debug, Clone, Serialize, Copy, Eq, PartialEq)]
44#[serde(rename_all = "camelCase")]
45pub enum BinOpType {
46    Add,
47    Sub,
48    Frac,
49    Pow,
50    Equals,
51    ShiftL,
52    ShiftR,
53    Mod,
54    And,
55    Or,
56    Xor,
57}
58
59impl BinOpType {
60    pub fn symbol(self) -> &'static str {
61        match self {
62            BinOpType::Add => " + ",
63            BinOpType::Sub => " - ",
64            BinOpType::Frac => " / ",
65            BinOpType::Pow => "^",
66            BinOpType::Equals => " = ",
67            BinOpType::ShiftL => " << ",
68            BinOpType::ShiftR => " >> ",
69            BinOpType::Mod => " mod ",
70            BinOpType::And => " and ",
71            BinOpType::Or => " or ",
72            BinOpType::Xor => " xor ",
73        }
74    }
75}
76
77#[derive(Debug, Clone, Serialize, PartialEq)]
78pub struct BinOpExpr {
79    pub op: BinOpType,
80    pub left: Box<Expr>,
81    pub right: Box<Expr>,
82}
83
84#[derive(Debug, Clone, Serialize, Copy, Eq, PartialEq)]
85#[serde(rename_all = "camelCase")]
86#[serde(untagged)]
87pub enum UnaryOpType {
88    Negative,
89    Positive,
90    Degree(Degree),
91}
92
93#[derive(Debug, Clone, Serialize, PartialEq)]
94pub struct UnaryOpExpr {
95    pub op: UnaryOpType,
96    pub expr: Box<Expr>,
97}
98
99#[derive(Debug, Clone, Copy, Serialize, PartialEq)]
100#[serde(rename_all = "camelCase")]
101pub enum Function {
102    Sqrt,
103    Exp,
104    Ln,
105    Log2,
106    Log10,
107    Sin,
108    Cos,
109    Tan,
110    Asin,
111    Acos,
112    Atan,
113    Sinh,
114    Cosh,
115    Tanh,
116    Asinh,
117    Acosh,
118    Atanh,
119    Log,
120    Hypot,
121    Atan2,
122}
123
124impl Function {
125    pub fn name(&self) -> &str {
126        match *self {
127            Function::Sqrt => "sqrt",
128            Function::Exp => "exp",
129            Function::Ln => "ln",
130            Function::Log2 => "log2",
131            Function::Log10 => "log10",
132            Function::Sin => "sin",
133            Function::Cos => "cos",
134            Function::Tan => "tan",
135            Function::Asin => "asin",
136            Function::Acos => "acos",
137            Function::Atan => "atan",
138            Function::Sinh => "sinh",
139            Function::Cosh => "cosh",
140            Function::Tanh => "tanh",
141            Function::Asinh => "asinh",
142            Function::Acosh => "acosh",
143            Function::Atanh => "atanh",
144            Function::Log => "log",
145            Function::Hypot => "hypot",
146            Function::Atan2 => "atan2",
147        }
148    }
149
150    pub fn from_name(s: &str) -> Option<Self> {
151        let func = match s {
152            "sqrt" => Function::Sqrt,
153            "exp" => Function::Exp,
154            "ln" => Function::Ln,
155            "log2" => Function::Log2,
156            "log10" => Function::Log10,
157            "sin" => Function::Sin,
158            "cos" => Function::Cos,
159            "tan" => Function::Tan,
160            "asin" => Function::Asin,
161            "acos" => Function::Acos,
162            "atan" => Function::Atan,
163            "sinh" => Function::Sinh,
164            "cosh" => Function::Cosh,
165            "tanh" => Function::Tanh,
166            "asinh" => Function::Asinh,
167            "acosh" => Function::Acosh,
168            "atanh" => Function::Atanh,
169            "log" => Function::Log,
170            "hypot" => Function::Hypot,
171            "atan2" => Function::Atan2,
172            _ => return None,
173        };
174        Some(func)
175    }
176}
177
178impl fmt::Display for Degree {
179    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
180        match *self {
181            Degree::Celsius => write!(fmt, "°C"),
182            Degree::Fahrenheit => write!(fmt, "°F"),
183            Degree::Newton => write!(fmt, "°N"),
184            Degree::Reaumur => write!(fmt, "°Ré"),
185            Degree::Romer => write!(fmt, "°Rø"),
186            Degree::Delisle => write!(fmt, "°De"),
187        }
188    }
189}
190
191impl Degree {
192    pub fn name_base_scale(&self) -> (&str, &str, &str) {
193        match *self {
194            Degree::Celsius => ("C", "zerocelsius", "kelvin"),
195            Degree::Fahrenheit => ("F", "zerofahrenheit", "degrankine"),
196            Degree::Reaumur => ("Ré", "zerocelsius", "reaumur_absolute"),
197            Degree::Romer => ("Rø", "zeroromer", "romer_absolute"),
198            Degree::Delisle => ("De", "zerodelisle", "delisle_absolute"),
199            Degree::Newton => ("N", "zerocelsius", "newton_absolute"),
200        }
201    }
202}
203
204impl fmt::Display for DateToken {
205    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
206        match *self {
207            DateToken::Literal(ref l) => write!(fmt, "{}", l),
208            DateToken::Number(ref i, None) => write!(fmt, "{}", i),
209            DateToken::Number(ref i, Some(ref f)) => write!(fmt, "{}.{}", i, f),
210            DateToken::Colon => write!(fmt, ":"),
211            DateToken::Dash => write!(fmt, "-"),
212            DateToken::Space => write!(fmt, " "),
213            DateToken::Plus => write!(fmt, "+"),
214            DateToken::Error(ref e) => write!(fmt, "<{}>", e),
215        }
216    }
217}
218
219#[cfg(test)]
220mod tests {
221    use crate::ast::DateToken;
222
223    use super::Function;
224
225    const FUNCTIONS: &'static [Function] = &[
226        Function::Sqrt,
227        Function::Exp,
228        Function::Ln,
229        Function::Log2,
230        Function::Log10,
231        Function::Sin,
232        Function::Cos,
233        Function::Tan,
234        Function::Asin,
235        Function::Acos,
236        Function::Atan,
237        Function::Sinh,
238        Function::Cosh,
239        Function::Tanh,
240        Function::Asinh,
241        Function::Acosh,
242        Function::Atanh,
243        Function::Log,
244        Function::Hypot,
245        Function::Atan2,
246    ];
247
248    #[test]
249    fn roundtrip_function_names() {
250        for &func in FUNCTIONS {
251            assert_eq!(Function::from_name(func.name()), Some(func));
252        }
253    }
254
255    #[test]
256    fn date_tokens_display() {
257        assert_eq!(DateToken::Colon.to_string(), ":");
258        assert_eq!(DateToken::Dash.to_string(), "-");
259        assert_eq!(DateToken::Space.to_string(), " ");
260        assert_eq!(DateToken::Plus.to_string(), "+");
261        assert_eq!(DateToken::Literal("a".to_owned()).to_string(), "a");
262        assert_eq!(DateToken::Number("123".to_owned(), None).to_string(), "123");
263        assert_eq!(
264            DateToken::Number("123".to_owned(), Some("456".to_owned())).to_string(),
265            "123.456"
266        );
267        assert_eq!(DateToken::Error("test".to_owned()).to_string(), "<test>");
268    }
269}