Updated Odia Language along with FUEL implementation
[gcalctool.git] / src / equation.vala
blob7582894d1d60184dcdcb7272fdae3a668d7a85ef
1 /*
2 * Copyright (C) 2004-2008 Sami Pietila
3 * Copyright (C) 2008-2012 Robert Ancell.
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 2 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9 * license.
12 public int sub_atoi (string data)
14 const unichar digits[] = {'₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉'};
16 var index = 0;
17 unichar c;
18 int value = 0;
19 while (data.get_next_char (ref index, out c))
21 var is_subdigit = false;
22 for (var i = 0; i < digits.length; i++)
24 if (c == digits[i])
26 value = value * 10 + i;
27 is_subdigit = true;
28 break;
31 if (!is_subdigit)
32 return -1;
35 return value;
38 public int super_atoi (string data)
40 const unichar digits[] = {'⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'};
42 var index = 0;
43 unichar c;
44 data.get_next_char (ref index, out c);
45 int sign = 1;
46 if (c == '⁻')
47 sign = -1;
48 else
49 index = 0;
51 int value = 0;
52 while (data.get_next_char (ref index, out c))
54 var is_superdigit = false;
55 for (var i = 0; i < digits.length; i++)
57 if (c == digits[i])
59 value = value * 10 + i;
60 is_superdigit = true;
61 break;
64 if (!is_superdigit)
65 return 0;
68 return sign * value;
71 public string mp_error_code_to_string (ErrorCode error_code)
73 switch (error_code)
75 case ErrorCode.NONE:
76 return "ErrorCode.NONE";
77 case ErrorCode.INVALID:
78 return "ErrorCode.INVALID";
79 case ErrorCode.OVERFLOW:
80 return "ErrorCode.OVERFLOW";
81 case ErrorCode.UNKNOWN_VARIABLE:
82 return "ErrorCode.UNKNOWN_VARIABLE";
83 case ErrorCode.UNKNOWN_FUNCTION:
84 return "ErrorCode.UNKNOWN_FUNCTION";
85 case ErrorCode.UNKNOWN_CONVERSION:
86 return "ErrorCode.UNKNOWN_CONVERSION";
87 case ErrorCode.MP:
88 return "ErrorCode.MP";
89 default:
90 return "Unknown parser error";
94 public enum ErrorCode
96 NONE,
97 INVALID,
98 OVERFLOW,
99 UNKNOWN_VARIABLE,
100 UNKNOWN_FUNCTION,
101 UNKNOWN_CONVERSION,
105 public class Equation
107 public int base;
108 public int wordlen;
109 public AngleUnit angle_units;
110 private string expression;
112 public Equation (string expression)
114 this.expression = expression;
117 public new Number? parse (out ErrorCode error_code = null, out string error_token = null, out uint error_start = null, out uint error_end = null)
119 var parser = new EquationParser (this, expression);
120 mp_clear_error ();
122 var z = parser.parse (out error_code, out error_token, out error_start, out error_end);
124 /* Error during parsing */
125 if (error_code != ErrorCode.NONE)
126 return null;
128 if (mp_get_error () != null)
130 error_code = ErrorCode.MP;
131 return null;
134 return z;
137 public virtual bool variable_is_defined (string name)
139 return false;
142 public virtual Number? get_variable (string name)
144 return null;
147 public virtual void set_variable (string name, Number x)
151 public virtual bool function_is_defined (string name)
153 return false;
156 public virtual Number? get_function (string name, Number x)
158 return null;
161 public virtual Number? convert (Number x, string x_units, string z_units)
163 return null;
167 private class EquationParser : Parser
169 private Equation equation;
171 public EquationParser (Equation equation, string expression)
173 base (expression, equation.base, equation.wordlen);
174 this.equation = equation;
177 protected override bool variable_is_defined (string name)
179 /* FIXME: Make more generic */
180 if (name == "e" || name == "i" || name == "π")
181 return true;
183 return equation.variable_is_defined (name);
186 protected override Number? get_variable (string name)
188 if (name == "e")
189 return new Number.eulers ();
190 else if (name == "i")
191 return new Number.i ();
192 else if (name == "π")
193 return new Number.pi ();
194 else
195 return equation.get_variable (name);
198 protected override void set_variable (string name, Number x)
200 // Reserved words, e, π, mod, and, or, xor, not, abs, log, ln, sqrt, int, frac, sin, cos, ...
201 if (name == "e" || name == "i" || name == "π")
202 return; // FALSE
204 equation.set_variable (name, x);
207 // FIXME: Accept "2sin" not "2 sin", i.e. let the tokenizer collect the multiple
208 // Parser then distinguishes between "sin"="s*i*n" or "sin5" = "sin 5" = "sin (5)"
209 // i.e. numbers+letters = variable or function depending on following arg
210 // letters+numbers = numbers+letters+numbers = function
212 protected override bool function_is_defined (string name)
214 var lower_name = name.down ();
216 /* FIXME: Make more generic */
217 if (lower_name == "log" ||
218 (lower_name.has_prefix ("log") && sub_atoi (lower_name.substring (3)) >= 0) ||
219 lower_name == "ln" ||
220 lower_name == "sqrt" ||
221 lower_name == "abs" ||
222 lower_name == "sgn" ||
223 lower_name == "arg" ||
224 lower_name == "conj" ||
225 lower_name == "int" ||
226 lower_name == "frac" ||
227 lower_name == "floor" ||
228 lower_name == "ceil" ||
229 lower_name == "round" ||
230 lower_name == "re" ||
231 lower_name == "im" ||
232 lower_name == "sin" || lower_name == "cos" || lower_name == "tan" ||
233 lower_name == "asin" || lower_name == "acos" || lower_name == "atan" ||
234 lower_name == "sin⁻¹" || lower_name == "cos⁻¹" || lower_name == "tan⁻¹" ||
235 lower_name == "sinh" || lower_name == "cosh" || lower_name == "tanh" ||
236 lower_name == "sinh⁻¹" || lower_name == "cosh⁻¹" || lower_name == "tanh⁻¹" ||
237 lower_name == "asinh" || lower_name == "acosh" || lower_name == "atanh" ||
238 lower_name == "ones" ||
239 lower_name == "twos")
240 return true;
242 return equation.function_is_defined (name);
245 protected override Number? get_function (string name, Number x)
247 var lower_name = name.down ();
249 // FIXME: Re Im ?
251 if (lower_name == "log")
252 return x.logarithm (10); // FIXME: Default to ln
253 else if (lower_name.has_prefix ("log"))
255 var number_base = sub_atoi (lower_name.substring (3));
256 if (number_base < 0)
257 return null;
258 else
259 return x.logarithm (number_base);
261 else if (lower_name == "ln")
262 return x.ln ();
263 else if (lower_name == "sqrt") // √x
264 return x.sqrt ();
265 else if (lower_name == "abs") // |x|
266 return x.abs ();
267 else if (lower_name == "sgn")
268 return x.sgn ();
269 else if (lower_name == "arg")
270 return x.arg (equation.angle_units);
271 else if (lower_name == "conj")
272 return x.conjugate ();
273 else if (lower_name == "int")
274 return x.integer_component ();
275 else if (lower_name == "frac")
276 return x.fractional_component ();
277 else if (lower_name == "floor")
278 return x.floor ();
279 else if (lower_name == "ceil")
280 return x.ceiling ();
281 else if (lower_name == "round")
282 return x.round ();
283 else if (lower_name == "re")
284 return x.real_component ();
285 else if (lower_name == "im")
286 return x.imaginary_component ();
287 else if (lower_name == "sin")
288 return x.sin (equation.angle_units);
289 else if (lower_name == "cos")
290 return x.cos (equation.angle_units);
291 else if (lower_name == "tan")
292 return x.tan (equation.angle_units);
293 else if (lower_name == "sin⁻¹" || lower_name == "asin")
294 return x.asin (equation.angle_units);
295 else if (lower_name == "cos⁻¹" || lower_name == "acos")
296 return x.acos (equation.angle_units);
297 else if (lower_name == "tan⁻¹" || lower_name == "atan")
298 return x.atan (equation.angle_units);
299 else if (lower_name == "sinh")
300 return x.sinh ();
301 else if (lower_name == "cosh")
302 return x.cosh ();
303 else if (lower_name == "tanh")
304 return x.tanh ();
305 else if (lower_name == "sinh⁻¹" || lower_name == "asinh")
306 return x.asinh ();
307 else if (lower_name == "cosh⁻¹" || lower_name == "acosh")
308 return x.acosh ();
309 else if (lower_name == "tanh⁻¹" || lower_name == "atanh")
310 return x.atanh ();
311 else if (lower_name == "ones")
312 return x.ones_complement (equation.wordlen);
313 else if (lower_name == "twos")
314 return x.twos_complement (equation.wordlen);
315 else
316 return equation.get_function (name, x);
319 protected override Number? convert (Number x, string x_units, string z_units)
321 return equation.convert (x, x_units, z_units);