├── .gitignore
├── AssemblyInfo.cs
├── Constructs
├── FunctionOperation.cs
├── IConstruct.cs
├── Operation.cs
└── Variable.cs
├── Converters
├── BooleanTypeConverter.cs
├── DateTimeTypeConverter.cs
├── NumberTypeConverter.cs
└── TextTypeConverter.cs
├── Engine
├── Engine.cs
├── Expression.cs
├── ExpressionParseOnDemand.cs
├── ExpressionParsed.cs
├── Token.cs
└── Tokenizer.cs
├── Functions
├── ArrayFunction.cs
├── Average.cs
├── Format.cs
├── Function.cs
├── If.cs
├── Len.cs
├── Max.cs
├── Min.cs
├── Sum.cs
└── Today.cs
├── HiSystems.Interpreter.MonoTouch.csproj
├── HiSystems.Interpreter.csproj
├── HiSystems.Interpreter.sln
├── Library
└── PeekableEnumerator.cs
├── Literals
├── Array.cs
├── Boolean.cs
├── DateTime.cs
├── Literal.cs
├── Number.cs
└── Text.cs
├── Operators
├── AddOperator.cs
├── AndOperator.cs
├── DivideOperator.cs
├── EqualToOperator.cs
├── GreaterThanOperator.cs
├── GreaterThanOrEqualToOperator.cs
├── LessThanOperator.cs
├── LessThanOrEqualToOperator.cs
├── ModulusOperator.cs
├── MultiplyOperator.cs
├── NotEqualToOperator.cs
├── Operator.cs
├── OrOperator.cs
└── SubtractOperator.cs
└── readme.md
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | #ignore thumbnails created by windows
3 | Thumbs.db
4 | #Ignore files build by Visual Studio
5 | *.obj
6 | *.exe
7 | *.pdb
8 | *.user
9 | *.aps
10 | *.pch
11 | *.vspscc
12 | *_i.c
13 | *_p.c
14 | *.ncb
15 | *.suo
16 | *.tlb
17 | *.tlh
18 | *.bak
19 | *.cache
20 | *.ilk
21 | *.log
22 | [Bb]in
23 | [Dd]ebug*/
24 | *.lib
25 | *.sbr
26 | obj/
27 | [Rr]elease*/
28 | _ReSharper*/
29 | [Tt]est[Rr]esult*
30 |
--------------------------------------------------------------------------------
/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyTitle("Interperter")]
6 | [assembly: AssemblyDescription("")]
7 | [assembly: AssemblyConfiguration("")]
8 | [assembly: AssemblyCompany("HiSystems")]
9 | [assembly: AssemblyProduct("HiSystems.Interperter")]
10 | [assembly: AssemblyCopyright("HiSystems Copyright © 2012")]
11 | [assembly: AssemblyTrademark("")]
12 | [assembly: AssemblyCulture("")]
13 | [assembly: ComVisible(false)]
14 | [assembly: AssemblyVersion("1.2.0.0")]
15 | [assembly: AssemblyFileVersion("1.2.0.0")]
16 |
--------------------------------------------------------------------------------
/Constructs/FunctionOperation.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Performs the actual execution of a function, resolving and passing all of the function arguments.
29 | ///
30 | public class FunctionOperation : IConstruct
31 | {
32 | private Function function;
33 | private IConstruct[] arguments = null;
34 |
35 | public FunctionOperation(Function function, IConstruct[] arguments)
36 | {
37 | if (function == null)
38 | throw new ArgumentNullException();
39 |
40 | this.function = function;
41 | this.arguments = arguments;
42 | }
43 |
44 | Literal IConstruct.Transform()
45 | {
46 | // Translation of the arguments does not occur here - it occurs in the Function.
47 | // Sometimes it is necessary that the arguments are not translated, for example by functions that interpret variables as meaning something else.
48 |
49 | return function.Execute(this.arguments);
50 | }
51 |
52 | ///
53 | /// The function that will be executed when this construct is transformed.
54 | ///
55 | public Function Function
56 | {
57 | get
58 | {
59 | return this.function;
60 | }
61 | }
62 |
63 | ///
64 | /// The arguments supplied to the function
65 | ///
66 | public IConstruct[] Arguments
67 | {
68 | get
69 | {
70 | return this.arguments;
71 | }
72 | }
73 |
74 | public override string ToString()
75 | {
76 | return this.function.ToString();
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Constructs/IConstruct.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Interface for all constructs that return a value of some kind:
29 | /// function, literal, operation, variable, array.
30 | ///
31 | public interface IConstruct
32 | {
33 | ///
34 | /// Transforms/executes and returns the value from this construct:
35 | /// For Functions: executes the function and returns the result as a literal.
36 | /// For Operations: returns the result of the mathematical or logical operation and returns a literal (Number, Boolean for example).
37 | /// For Variables: returns the value from the variable's associated construct - i.e. calls Variable.Construct.Transform().
38 | /// For Literals: returns the literal value i.e. itself.
39 | /// For Arrays: returns the array value, i.e itself.
40 | ///
41 | Literal Transform();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Constructs/Operation.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 |
21 | using System;
22 | using System.Collections.Generic;
23 | using System.Linq;
24 | using System.Text;
25 |
26 | namespace HiSystems.Interpreter
27 | {
28 | ///
29 | /// Represents a left hand side value an operation and a right hand side value.
30 | ///
31 | public class Operation : IConstruct
32 | {
33 | private const int PrecedenceUndefined = -1;
34 |
35 | private IConstruct leftValue;
36 | private Operator @operator;
37 | private IConstruct rightValue;
38 | private int precedence = PrecedenceUndefined;
39 |
40 | internal Operation()
41 | {
42 | }
43 |
44 | ///
45 | /// Indicates the left hand side value, and right hand side values
46 | /// and the operation to be applied to the left hand side and right
47 | /// hand side values.
48 | ///
49 | public Operation(IConstruct leftValue, Operator operation, IConstruct rightValue)
50 | {
51 | if (leftValue == null || rightValue == null || operation == null)
52 | throw new ArgumentNullException();
53 |
54 | this.leftValue = leftValue;
55 | this.@operator = operation;
56 | this.rightValue = rightValue;
57 | }
58 |
59 | Literal IConstruct.Transform ()
60 | {
61 | return this.@operator.Execute(this.leftValue, this.rightValue);
62 | }
63 |
64 | ///
65 | /// Represents the relatively ordering precedence for this expression.
66 | /// The precedence is not an absolute value but a relative value.
67 | /// If two expressions have the same precedence then they are evaluated from left to right.
68 | /// The highest precedence value indicates that the expression will be executed first.
69 | ///
70 | internal int Precedence
71 | {
72 | get
73 | {
74 | return this.precedence;
75 | }
76 |
77 | set
78 | {
79 | if (value <= PrecedenceUndefined)
80 | throw new ArgumentException(value.ToString());
81 |
82 | this.precedence = value;
83 | }
84 | }
85 |
86 | internal bool PrecedenceIsSet
87 | {
88 | get
89 | {
90 | return this.precedence != PrecedenceUndefined;
91 | }
92 | }
93 |
94 | ///
95 | /// The left-hand-side value that the operation will use.
96 | ///
97 | public IConstruct LeftValue
98 | {
99 | get
100 | {
101 | return this.leftValue;
102 | }
103 |
104 | internal set
105 | {
106 | if (value == null)
107 | throw new ArgumentNullException();
108 |
109 | this.leftValue = value;
110 | }
111 | }
112 |
113 | ///
114 | /// The operator that will be executed when this operation is executed.
115 | ///
116 | public Operator Operator
117 | {
118 | get
119 | {
120 | return this.@operator;
121 | }
122 |
123 | internal set
124 | {
125 | if (value == null)
126 | throw new ArgumentNullException();
127 |
128 | this.@operator = value;
129 | }
130 | }
131 |
132 | ///
133 | /// The right-hand-side value that the operation will use.
134 | ///
135 | public IConstruct RightValue
136 | {
137 | get
138 | {
139 | return this.rightValue;
140 | }
141 |
142 | internal set
143 | {
144 | if (value == null)
145 | throw new ArgumentNullException();
146 |
147 | this.rightValue = value;
148 | }
149 | }
150 |
151 | public override string ToString()
152 | {
153 | return this.leftValue.ToString() + " " + this.@operator.Token + " " + this.rightValue.ToString();
154 | }
155 |
156 | // ///
157 | // /// Returns all of the items in the expression tree (including this root node).
158 | // ///
159 | // public IConstruct[] GetAllItems()
160 | // {
161 | // var items = new List();
162 | //
163 | // GetAllItems(items, this);
164 | //
165 | // return items.ToArray();
166 | // }
167 | //
168 | // private void GetAllItems(List items, IConstruct value)
169 | // {
170 | // items.Add(value);
171 | //
172 | // if (value is Operation)
173 | // {
174 | // GetAllItems(items, ((Operation)value).LeftValue);
175 | // GetAllItems(items, ((Operation)value).RightValue);
176 | // }
177 | // }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/Constructs/Variable.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Represents a variable value that is resolved when first accessed.
29 | ///
30 | public class Variable : IConstruct
31 | {
32 | private string name;
33 | private IConstruct construct;
34 |
35 | ///
36 | ///
37 | public Variable(string name)
38 | : this(name, null)
39 | {
40 | }
41 |
42 | ///
43 | ///
44 | public Variable(string name, IConstruct value)
45 | {
46 | if (String.IsNullOrEmpty(name))
47 | throw new ArgumentNullException("Name");
48 |
49 | this.name = name;
50 | this.construct = value;
51 | }
52 |
53 | public string Name
54 | {
55 | get
56 | {
57 | return this.name;
58 | }
59 | }
60 |
61 | ///
62 | /// The associated literal value that should be associated with this variable.
63 | /// This value should be set before the IConstruct.Transform() function is called.
64 | ///
65 | public IConstruct Value
66 | {
67 | get
68 | {
69 | return this.construct;
70 | }
71 |
72 | set
73 | {
74 | if (value == null)
75 | throw new ArgumentNullException();
76 |
77 | this.construct = value;
78 | }
79 | }
80 |
81 | Literal IConstruct.Transform()
82 | {
83 | if (this.construct == null)
84 | throw new InvalidOperationException(String.Format("Variable {0} has not been set", this.name));
85 |
86 | return this.construct.Transform();
87 | }
88 |
89 | public override string ToString()
90 | {
91 | return this.name + ": " + (this.construct == null ? String.Empty : this.construct.ToString());
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/Converters/BooleanTypeConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Globalization;
4 |
5 | namespace HiSystems.Interpreter.Converters
6 | {
7 | public class BooleanTypeConverter : TypeConverter
8 | {
9 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
10 | {
11 | return sourceType == typeof(bool);
12 | }
13 |
14 | public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
15 | {
16 | return destinationType == typeof(Boolean) || destinationType == typeof(Literal);
17 | }
18 |
19 | public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
20 | {
21 | var boolean = value as Boolean;
22 | return boolean == null ? default(bool) : (bool)boolean;
23 | }
24 |
25 | public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
26 | {
27 | var boolean = (bool)value;
28 | return (Boolean)boolean;
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/Converters/DateTimeTypeConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Globalization;
4 |
5 | namespace HiSystems.Interpreter.Converters
6 | {
7 | public class DateTimeTypeConverter : TypeConverter
8 | {
9 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
10 | {
11 | return sourceType == typeof (System.DateTime);
12 | }
13 |
14 | public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
15 | {
16 | return destinationType == typeof(DateTime) || destinationType == typeof(Literal); ;
17 | }
18 |
19 | public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
20 | {
21 | var date = default(DateTime);
22 | if (value is System.DateTime)
23 | {
24 | date = (System.DateTime) value;
25 | }
26 |
27 | return new DateTime(date);
28 | }
29 |
30 | public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
31 | {
32 | var date = value as DateTime;
33 | if (date != null)
34 | {
35 | return (System.DateTime)date;
36 | }
37 |
38 | return default(System.DateTime);
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/Converters/NumberTypeConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Globalization;
5 | using System.Linq;
6 |
7 | namespace HiSystems.Interpreter.Converters
8 | {
9 | public class NumberTypeConverter : TypeConverter
10 | {
11 | private readonly IEnumerable _supportedTypes = new[] {typeof(int), typeof(double), typeof(decimal), typeof(Literal)};
12 |
13 | public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
14 | {
15 | return _supportedTypes.Contains(destinationType);
16 | }
17 |
18 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
19 | {
20 | return sourceType == typeof(Number);
21 | }
22 |
23 | public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
24 | {
25 | return value == null ? new Number(0) : new Number((decimal)value);
26 | }
27 |
28 | public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
29 | {
30 | var number = value as Number;
31 |
32 | if (destinationType == typeof(int))
33 | {
34 | return number == null ? default(int) : (int)(decimal)number;
35 | }
36 |
37 | if (destinationType == typeof(decimal))
38 | {
39 | return number == null ? default(decimal) : (decimal)number;
40 | }
41 |
42 | return number == null ? default(double) : (double)number;
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/Converters/TextTypeConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Globalization;
4 |
5 | namespace HiSystems.Interpreter.Converters
6 | {
7 | public class TextTypeConverter : TypeConverter
8 | {
9 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
10 | {
11 | return sourceType == typeof(string);
12 | }
13 |
14 | public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
15 | {
16 | return destinationType == typeof(string) || destinationType == typeof(Literal);
17 | }
18 |
19 | public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
20 | {
21 | return new Text((value as string) ?? string.Empty);
22 | }
23 |
24 | public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
25 | {
26 | var text = value as Text;
27 | return text == null ? string.Empty : (string) text;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/Engine/Engine.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 | using System.Diagnostics;
25 |
26 | namespace HiSystems.Interpreter
27 | {
28 | ///
29 | /// The interpreter engine interprets single expressions that can contain;
30 | /// - variables
31 | /// - functions (custom functions also)
32 | /// - operators (mathematical / logical)
33 | /// - literals (numbers, dates, strings)
34 | /// - parentheses - for precedence
35 | /// The Parse function will interpret the expression and return an Expression object.
36 | /// The expression can be supplied with the appropriate variables.
37 | /// And then executed via the Expression.Execute() function.
38 | /// Example expressions:
39 | /// 'IF(A > B, A, B)' -- requires calling Expression.Variables["A"] = (Number)1; Expression.Variables["B"] = (Number)2;
40 | /// 'true or false'
41 | /// '(1 + 2) * 3 / 4'
42 | ///
43 | /// See readme.md for further examples.
44 | ///
45 | public class Engine
46 | {
47 | private class OperatorAndPrecedence
48 | {
49 | public Operator Operation;
50 | public int Precedence;
51 | }
52 |
53 | private abstract class TranslatedToken
54 | {
55 | }
56 |
57 | private class ConstructToken : TranslatedToken
58 | {
59 | private IConstruct value;
60 |
61 | public ConstructToken(IConstruct value)
62 | {
63 | if (value == null)
64 | throw new ArgumentNullException();
65 |
66 | this.value = value;
67 | }
68 |
69 | public IConstruct Value
70 | {
71 | get
72 | {
73 | return this.value;
74 | }
75 | }
76 |
77 | public override string ToString()
78 | {
79 | return this.value.ToString();
80 | }
81 | }
82 |
83 | private class OperatorToken : TranslatedToken
84 | {
85 | private Operator operation;
86 |
87 | public OperatorToken(Operator operation)
88 | {
89 | if (operation == null)
90 | throw new ArgumentNullException();
91 |
92 | this.operation = operation;
93 | }
94 |
95 | public Operator Value
96 | {
97 | get
98 | {
99 | return this.operation;
100 | }
101 | }
102 |
103 | public override string ToString()
104 | {
105 | return this.operation.Token.ToString();
106 | }
107 | }
108 |
109 | private class LeftParenthesisToken : TranslatedToken
110 | {
111 | public override string ToString()
112 | {
113 | return "(";
114 | }
115 | }
116 |
117 | private class RightParenthesisToken : TranslatedToken
118 | {
119 | public override string ToString()
120 | {
121 | return ")";
122 | }
123 | }
124 |
125 | private class ReservedWord
126 | {
127 | ///
128 | /// The word that identifies the reserved word.
129 | ///
130 | public string Word;
131 |
132 | ///
133 | /// The construct that identifies the keyword.
134 | ///
135 | public IConstruct Construct;
136 | }
137 |
138 | ///
139 | ///
140 | ///
141 | /// The precendence level is a relative level and is used to indicate the relative.
142 | /// A higher integer value means that it is performed first / before other operations.
143 | /// Operations with the same precedence level are executed left to right.
144 | /// Any new operations should be added to this list so that the tokens can be appropriately parsed
145 | /// by the parsing engine.
146 | ///
147 | private static OperatorAndPrecedence[] allOperators = new [] {
148 | new OperatorAndPrecedence() { Operation = new MultiplyOperator(), Precedence = 6 },
149 | new OperatorAndPrecedence() { Operation = new DivideOperator(), Precedence = 6 },
150 | new OperatorAndPrecedence() { Operation = new ModulusOperator(), Precedence = 6 },
151 | new OperatorAndPrecedence() { Operation = new AddOperator(), Precedence = 5 },
152 | new OperatorAndPrecedence() { Operation = new SubtractOperator(), Precedence = 5 },
153 | new OperatorAndPrecedence() { Operation = new LessThanOperator(), Precedence = 4 },
154 | new OperatorAndPrecedence() { Operation = new LessThanOrEqualToOperator(), Precedence = 4 },
155 | new OperatorAndPrecedence() { Operation = new GreaterThanOperator(), Precedence = 4 },
156 | new OperatorAndPrecedence() { Operation = new GreaterThanOrEqualToOperator(), Precedence = 4 },
157 | new OperatorAndPrecedence() { Operation = new EqualToOperator(), Precedence = 3 },
158 | new OperatorAndPrecedence() { Operation = new NotEqualToOperator(), Precedence = 3 },
159 | new OperatorAndPrecedence() { Operation = new AndOperator(), Precedence = 2 },
160 | new OperatorAndPrecedence() { Operation = new OrOperator(), Precedence = 1 }
161 | };
162 |
163 | ///
164 | /// Indicates which tokens of type Identifier need to be translated into special tokens.
165 | ///
166 | private static ReservedWord[] reservedWords = new []
167 | {
168 | new ReservedWord() { Word = "true", Construct = new Boolean(true) },
169 | new ReservedWord() { Word = "false", Construct = new Boolean(false) }
170 | };
171 |
172 | ///
173 | ///
174 | private static int parenthesisPrecendence;
175 | private List allFunctions = new List();
176 |
177 | static Engine()
178 | {
179 | // Parentheses have higher precedence than all operations
180 | parenthesisPrecendence = allOperators
181 | .Select(item => item.Precedence)
182 | .Max() + 1;
183 | }
184 |
185 | ///
186 | /// Creates a new engine that can be used to parse expressions.
187 | ///
188 | public Engine()
189 | {
190 | Register(new Sum());
191 | Register(new Average());
192 | Register(new If());
193 | Register(new Format());
194 | Register(new Max());
195 | Register(new Min());
196 | Register(new ArrayFunction());
197 | Register(new Today());
198 | Register(new Len());
199 | }
200 |
201 | ///
202 | /// Registers the function, so that the function can be utilised by the engine.
203 | /// Must be called before Engine.Parse() otherwise the function will not be recognised.
204 | ///
205 | public void Register(Function function)
206 | {
207 | allFunctions.Add(function);
208 | }
209 |
210 | ///
211 | /// Parses the expression and prepares it for execution.
212 | /// The returned Expression can then be populated with variables if necessary
213 | /// and then executed via Expression.Execute().
214 | ///
215 | public Expression Parse(string expression)
216 | {
217 | var variablesList = new List();
218 |
219 | return new ExpressionParsed(expression, ParseToConstruct(expression, variablesList), variablesList);
220 | }
221 |
222 | ///
223 | /// Returns an expression that is not compiled, thereby deferring parsing/compilation into the future and decreasing load time.
224 | /// The expression is compiled on demand / just-in-time on the first call to Expression.Execute() or Expression.Variables.
225 | /// Any syntax errors with the expression will NOT be thrown from this function, only on the first call to Execute() or Variables.
226 | /// Usage of the returned Expression is identical to an Expression returned from Engine.Parse().
227 | ///
228 | public Expression ParseOnDemand(string expression)
229 | {
230 | return new ExpressionParseOnDemand(ParseToConstruct, expression);
231 | }
232 |
233 | ///
234 | /// Parses the expression and prepares it for execution.
235 | ///
236 | private IConstruct ParseToConstruct(string expression, List currentVariables)
237 | {
238 | return GetConstructFromTokens(Tokenizer.Parse(expression), currentVariables);
239 | }
240 |
241 | ///
242 | /// Creates the construct from a set of tokens.
243 | /// This is used to parse an entire expression and also an expression from a function's argument.
244 | ///
245 | private IConstruct GetConstructFromTokens(List tokens, List currentVariables)
246 | {
247 | // Translate the tokens to meaningful tokens such as a variables, functions and operators
248 | // Unknown or unexpected tokens will cause an exception to be thrown
249 | var translatedTokens = TranslateTokens(tokens, currentVariables);
250 |
251 | // If there is only one item in the expression (i.e. a function or number and no operations)
252 | if (translatedTokens.Count == 1)
253 | {
254 | return ((ConstructToken)translatedTokens[0]).Value;
255 | }
256 | else
257 | {
258 | // Converts the tokens to the initial flat tree structure.
259 | // The tree structure is flat (one level) and each Expression node is returned in the list.
260 | var expressions = TranslateTokensToOperations(translatedTokens);
261 |
262 | // Using the parentheses from the translated tokens determine the expression ordering
263 | SetExpressionPrecedenceFromParentheses(expressions.GetEnumerator(), translatedTokens.GetEnumerator(), depth: 0);
264 |
265 | // Set the ordering precedence based on the
266 | SetExpressionPrecedenceFromOperators(expressions.GetEnumerator(), translatedTokens.GetEnumerator());
267 |
268 | // Enumerate through the ordered nodes and branch tree appropriately
269 | return TranslateToTreeUsingPrecedence(expressions);
270 | }
271 | }
272 |
273 | ///
274 | /// Translates the tokens into meaningful functions, operations and values.
275 | ///
276 | private List TranslateTokens(List tokens, List currentVariables)
277 | {
278 | var translatedTokens = new List();
279 | var tokensEnum = new PeekableEnumerator(tokens);
280 |
281 | while (tokensEnum.MoveNext())
282 | {
283 | var token = tokensEnum.Current;
284 |
285 | switch (token.Type)
286 | {
287 | case TokenType.Number:
288 | translatedTokens.Add(new ConstructToken(Number.Parse(token.Value)));
289 | break;
290 | case TokenType.Identifier:
291 | var operationForTokenIdentifier = allOperators
292 | .Select(item => item.Operation)
293 | .SingleOrDefault(item => item.Token.Equals(token.Value));
294 |
295 | if (operationForTokenIdentifier != null)
296 | translatedTokens.Add(new OperatorToken(operationForTokenIdentifier));
297 | else
298 | translatedTokens.Add(new ConstructToken(TranslateIdentifierToken(tokensEnum, currentVariables)));
299 | break;
300 | case TokenType.LeftParenthesis:
301 | translatedTokens.Add(new LeftParenthesisToken());
302 | break;
303 | case TokenType.RightParenthesis:
304 | translatedTokens.Add(new RightParenthesisToken());
305 | break;
306 | case TokenType.Text:
307 | translatedTokens.Add(new ConstructToken(new Text(token.Value)));
308 | break;
309 | case TokenType.DateTime:
310 | translatedTokens.Add(new ConstructToken(new DateTime(System.DateTime.Parse(token.Value))));
311 | break;
312 | case TokenType.Other:
313 | var operationForToken = allOperators
314 | .Select(item => item.Operation)
315 | .SingleOrDefault(item => item.Token.Equals(token.Value));
316 |
317 | if (operationForToken != null)
318 | translatedTokens.Add(new OperatorToken(operationForToken));
319 | else
320 | throw new InvalidOperationException(token.Value + " in an unknown operation");
321 |
322 | break;
323 | default:
324 | throw new NotImplementedException();
325 | }
326 | }
327 |
328 | return translatedTokens;
329 | }
330 |
331 | ///
332 | /// Translates the tokens to a set of operations. Each operation points to two child nodes of type ConstructToken.
333 | /// For example, 1 + 2 * 3 equates to 2 Operations:
334 | /// Operation1: LeftNode = 1, RightNode = 2.
335 | /// Operation2: LeftNode = 2, RightNode = 3,
336 | /// Expression 1 and 2 both link to the same Value (node 2).
337 | /// This link is eventually broken and re-linked as the tree structure is created basd on the operation ordering.
338 | ///
339 | ///
340 | /// Ignores processing of any other tokens that are not values or operations (parentheses for example) as
341 | /// they are required for the ordering aspect of the translation process.
342 | ///
343 | private static List TranslateTokensToOperations(List tokens)
344 | {
345 | var expectingOperation = false;
346 | var expressions = new List();
347 | var currentExpression = new Operation();
348 |
349 | foreach (var token in tokens)
350 | {
351 | if (token is ConstructToken) // function, variable or number
352 | {
353 | if (expectingOperation)
354 | throw new InvalidOperationException("Expecting operation not a value; " + token.ToString());
355 |
356 | expectingOperation = true; // on next iteration an operator is expected
357 | }
358 | else if (token is OperatorToken)
359 | {
360 | if (!expectingOperation)
361 | throw new InvalidOperationException("Expecting value not an operation; " + token.ToString());
362 |
363 | expectingOperation = false; // on next iteration an operator is not expected
364 | }
365 |
366 | if (token is ConstructToken) // function, variable or number
367 | {
368 | if (currentExpression.LeftValue == null)
369 | currentExpression.LeftValue = ((ConstructToken)token).Value;
370 | else if (currentExpression.RightValue == null)
371 | {
372 | currentExpression.RightValue = ((ConstructToken)token).Value;
373 | expressions.Add(currentExpression);
374 | currentExpression = new Operation();
375 | currentExpression.LeftValue = ((ConstructToken)token).Value;
376 | }
377 | }
378 | else if (token is OperatorToken)
379 | {
380 | currentExpression.Operator = ((OperatorToken)token).Value;
381 | }
382 | }
383 |
384 | return expressions;
385 | }
386 |
387 | ///
388 | /// Sets the precedence of the operators based on the parentheses defined in the token sequence.
389 | /// Each time a left parenthesis is found, the depth incremented and precedence set to a multiple (parenthesisPrecendence * depth).
390 | /// This is because within each parenthesis the precedence is higher, but there still needs to be precedence for the operators.
391 | /// The precedence for the operators is set on a subsequent pass.
392 | /// For example: 1 + (2 + 3 * 4), items 3 and 4 must be given higher precedence than the 2 + 3 because of the order of operations.
393 | /// So, if parenthesisPrecendence is 10, + is 1, * is 2 then precedence for the operators + + * would be 1,11,12.
394 | /// For 1 + 2 + 3 * 4, then the precedence for the operators + + * would be 1,1,2.
395 | ///
396 | private static void SetExpressionPrecedenceFromParentheses(IEnumerator expressions, IEnumerator translatedTokens, int depth)
397 | {
398 | while (translatedTokens.MoveNext())
399 | {
400 | var token = translatedTokens.Current;
401 |
402 | if (token is LeftParenthesisToken)
403 | {
404 | SetExpressionPrecedenceFromParentheses(expressions, translatedTokens, depth + 1);
405 | }
406 | else if (token is OperatorToken)
407 | {
408 | expressions.MoveNext();
409 | // find the associated expression that is using the operator object instance
410 | var expression = expressions.Current;
411 |
412 | if (expression.PrecedenceIsSet)
413 | throw new InvalidOperationException("Expression precedence should not be set");
414 |
415 | // Set the precedence explicitly considering this is the first pass: 'expression.PrecedenceSet == false'
416 | expression.Precedence = depth * parenthesisPrecendence;
417 | }
418 | else if (token is RightParenthesisToken)
419 | {
420 | break;
421 | }
422 | }
423 |
424 | if (depth > 0 && !(translatedTokens.Current is RightParenthesisToken))
425 | throw new InvalidOperationException("Missing ending right parenthesis token");
426 | }
427 |
428 | ///
429 | /// Sets the precedence of the operators based on the associated precedence.
430 | /// Assumes that previous passes (for the parentheses) have already set the precedence.
431 | /// Therefore, the value is incremented by the associated precedence.
432 | ///
433 | ///
434 | private static void SetExpressionPrecedenceFromOperators(IEnumerator expressions, IEnumerator translatedTokens)
435 | {
436 | while (translatedTokens.MoveNext())
437 | {
438 | var token = translatedTokens.Current;
439 |
440 | if (token is OperatorToken)
441 | {
442 | expressions.MoveNext();
443 | // find the associated expression that is using the operator object instance
444 | var expression = expressions.Current;
445 | expression.Precedence += allOperators.Where(item => item.Operation == ((OperatorToken)token).Value).Single().Precedence;
446 | }
447 | }
448 | }
449 |
450 | ///
451 | /// Builds the tree from a flattened tree with doubly linked nodes / items to a list a tree with one expression at the top.
452 | /// Basically, high precedence items are processed first and pushed to the bottom of the tree
453 | /// so that they are executed first (their results feed into the other expressions, which feeds into other results etc.).
454 | /// The tree is built based on the precedence value setup on previous passes.
455 | ///
456 | ///
457 | ///
458 | private static Operation TranslateToTreeUsingPrecedence(List expressions)
459 | {
460 | var expressionsOrdered = expressions
461 | .Select((item, index) => new { Expression = item, LeftToRightIndex = index })
462 | .OrderByDescending(item => item.Expression.Precedence)
463 | .ThenBy(item => item.LeftToRightIndex) // for expressions with the same precedence order from left to right
464 | .Select(item => item.Expression) // remove the LeftToRightIndex now that it has been ordered correctly
465 | .GetEnumerator();
466 |
467 | while (expressionsOrdered.MoveNext() && expressions.Count > 1)
468 | {
469 | var orderedExpression = expressionsOrdered.Current;
470 | var orderedExpressionIndex = expressions.IndexOf(orderedExpression);
471 |
472 | // If there is an expression before this expression in the normal left to right index
473 | // then get it to point to this expression rather than the Value node that is shared with another expression.
474 | // Effectively, the orderedExpression is "pushed" to the bottom of the tree
475 | if (orderedExpressionIndex > 0)
476 | {
477 | var previousExpression = expressions[orderedExpressionIndex - 1];
478 | previousExpression.RightValue = orderedExpression;
479 | }
480 |
481 | // If there is an expression after this expression in the normal left to right index
482 | // then get it to point to this expression rather than the Value node that is shared with another expression.
483 | // Effectively, the orderedExpression is "pushed" to the bottom of the tree
484 | if (orderedExpressionIndex < expressions.Count - 1)
485 | {
486 | var nextExpression = expressions[orderedExpressionIndex + 1];
487 | nextExpression.LeftValue = orderedExpression;
488 | }
489 |
490 | // this expression has been pushed to the bottom of the tree (for an upside down tree)
491 | expressions.Remove(orderedExpression);
492 | }
493 |
494 | return expressions[0];
495 | }
496 |
497 | ///
498 | /// Enumerates through the tokens, searching for tokens XX,XX,XX where XX are arguments to the function and possibly a sub expression.
499 | /// When a ')' is found then the end of the arguments is presumed to have been found.
500 | ///
501 | /// Expected to be currently pointing to the name of the function. The next token SHOULD be a '('
502 | private IConstruct[] GetFunctionArguments(PeekableEnumerator tokensEnum, List currentVariables)
503 | {
504 | var arguments = new List();
505 | var functionName = tokensEnum.Current.Value;
506 |
507 | if (!(tokensEnum.MoveNext() && tokensEnum.Current.Type == TokenType.LeftParenthesis))
508 | throw new InvalidOperationException(String.Format("{0} arguments; first token should be '(' not '{1}'", functionName, tokensEnum.Current.Value));
509 | else if (tokensEnum.Current.Type == TokenType.LeftParenthesis && tokensEnum.CanPeek && tokensEnum.Peek.Type == TokenType.RightParenthesis)
510 | // No arguments were specified - empty parentheses were specified
511 | tokensEnum.MoveNext(); // consume the left parenthesis token and point it to the right parenthesis token - i.e. the end of the function
512 | else
513 | {
514 | bool reachedEndOfArguments = false;
515 |
516 | while (!reachedEndOfArguments)
517 | {
518 | arguments.Add(GetConstructFromTokens(GetFunctionArgumentTokens(functionName, tokensEnum, currentVariables), currentVariables));
519 |
520 | // tokensEnum.Current will be the last token processed by GetFunctionArgumentTokens()
521 | if (tokensEnum.Current.Type == TokenType.RightParenthesis)
522 | reachedEndOfArguments = true;
523 | }
524 | }
525 |
526 | return arguments.ToArray();
527 | }
528 |
529 | ///
530 | /// Gets the function's next argument's tokens by traversing the tokens until the next , or ) is found (which is not within a function).
531 | /// Does not return the , or ) character that terminated the argument expression - it is also consumed.
532 | ///
533 | /// Only used in order to provide useful exceptions / errors.
534 | /// Should be pointing to the token that indicates the start of a function argument; either a ( or , character.
535 | private static List GetFunctionArgumentTokens(string functionName, PeekableEnumerator tokensEnum, List currentVariables)
536 | {
537 | var argumentTokens = new List ();
538 |
539 | int functionDepth = 0;
540 | bool reachedEndOfArgument = false;
541 |
542 | while (!reachedEndOfArgument && tokensEnum.MoveNext())
543 | {
544 | var token = tokensEnum.Current;
545 |
546 | // found the argument's terminating comma or right parenthesis
547 | if (functionDepth == 0 && (token.Type == TokenType.Comma || token.Type == TokenType.RightParenthesis))
548 | reachedEndOfArgument = true;
549 | else
550 | {
551 | argumentTokens.Add(token);
552 |
553 | if (token.Type == TokenType.LeftParenthesis)
554 | functionDepth++;
555 | else if (token.Type == TokenType.RightParenthesis)
556 | functionDepth--;
557 | }
558 | }
559 |
560 | if (argumentTokens.Count == 0)
561 | throw new InvalidOperationException(String.Format("{0} has an empty argument", functionName));
562 | else if (!reachedEndOfArgument)
563 | throw new InvalidOperationException(String.Format("{0} is missing a terminating argument character; ',' or ')'", functionName));
564 |
565 | return argumentTokens;
566 | }
567 |
568 | ///
569 | /// Translates an identifier as either a function, variable name or key word.
570 | /// A function will match a registered function name and have a left parenthesis token following it, otherwise it is a variable.
571 | ///
572 | private IConstruct TranslateIdentifierToken (PeekableEnumerator tokensEnum, List currentVariables)
573 | {
574 | var identifierToken = tokensEnum.Current;
575 |
576 | var reservedWordForToken = reservedWords.SingleOrDefault(reserverWord => identifierToken == reserverWord.Word);
577 |
578 | if (reservedWordForToken != null)
579 | {
580 | return reservedWordForToken.Construct;
581 | }
582 | else
583 | {
584 | if (tokensEnum.CanPeek && tokensEnum.Peek.Type == TokenType.LeftParenthesis)
585 | {
586 | var functionForToken = allFunctions.SingleOrDefault(aFunction => identifierToken == aFunction.Name);
587 |
588 | if (functionForToken == null)
589 | throw new InvalidOperationException(String.Format("Function '{0}' is undefined", identifierToken));
590 | else
591 | return new FunctionOperation(functionForToken, GetFunctionArguments(tokensEnum, currentVariables));
592 | }
593 | else
594 | {
595 | // ensure there is only one Variable instance for the same variable name
596 | var variable = currentVariables.SingleOrDefault(aVariable => identifierToken == aVariable.Name);
597 |
598 | if (variable == null)
599 | {
600 | var newVariable = new Variable(tokensEnum.Current.Value);
601 | currentVariables.Add(newVariable);
602 | return newVariable;
603 | }
604 | else
605 | return variable;
606 | }
607 | }
608 | }
609 | }
610 | }
611 |
--------------------------------------------------------------------------------
/Engine/Expression.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Represents an expression and the variables defined in the expression.
29 | /// This is the base class for an already compiled expression or a just-in-time compiled expression.
30 | ///
31 | public abstract class Expression : IConstruct
32 | {
33 | ///
34 | /// Only used for error reporting and debugging as the ToString return value.
35 | ///
36 | private string expression;
37 |
38 | ///
39 | /// Initializes a new instance of the class.
40 | ///
41 | ///
42 | /// Root construct in the expression tree. Calling IConstruct.Transform will return the actual value.
43 | ///
44 | internal Expression(string expression)
45 | {
46 | if (String.IsNullOrEmpty(expression))
47 | throw new ArgumentNullException();
48 |
49 | this.expression = expression;
50 | }
51 |
52 | ///
53 | /// Returns the calculated value for the expression.
54 | /// Any variables should be set before calling this function.
55 | /// Will typically return a Number or Boolean literal value (depending on the type of expression).
56 | ///
57 | public abstract Literal Execute();
58 |
59 | ///
60 | /// Returns the calculated value for the expression.
61 | /// Any variables should be set before calling this function.
62 | /// Casts the return value to type T (of type Literal)
63 | ///
64 | public T Execute() where T : Literal
65 | {
66 | Literal result = this.Execute();
67 |
68 | if (!(result is T))
69 | throw new InvalidCastException(String.Format("Return value from '{0}' is of type {1}, not of type {2}", this.expression, result.GetType().Name, typeof(T).Name));
70 |
71 | return (T)result;
72 | }
73 |
74 | ///
75 | /// Returns a dictionary containing all of the variables that were defined in the expression.
76 | /// If a variable is defined in multiple locations only one variable object is available in the dictionary.
77 | /// Variables are tokens/identifiers that could not be resolved to an operator or function name.
78 | /// Each variable should be assigned a value i.e: Variables["MyVariable"].Literal = (Number)1;
79 | ///
80 | public abstract IDictionary Variables { get; }
81 |
82 | ///
83 | /// The original / source expression which this expression represents.
84 | ///
85 | protected string Source
86 | {
87 | get
88 | {
89 | return this.expression;
90 | }
91 | }
92 |
93 | ///
94 | /// Converts a string value to an Expression that when Execute()'d will return the same Text literal value.
95 | ///
96 | public static implicit operator Expression(string stringLiteral)
97 | {
98 | return new ExpressionParsed("\"" + stringLiteral + "\"", new Text(stringLiteral), new List());
99 | }
100 |
101 | ///
102 | /// Converts a bool value to an Expression that when Execute()'d will return the same bool literal value.
103 | ///
104 | public static implicit operator Expression(bool value)
105 | {
106 | return new ExpressionParsed(value.ToString(), new Boolean(value), new List());
107 | }
108 |
109 | /// Returns a distinct list of variables from the expression.
110 | ///
111 | protected static IDictionary TranslateVariablesToDictionary(List variables)
112 | {
113 | return variables.ToDictionary(variable => variable.Name, variable => variable);
114 | }
115 |
116 | ///
117 | /// Allows for an expression to also be considered as a construct.
118 | /// Used when an expression references an identifier which is also a separate expression.
119 | /// Allowing an expression to reference a chain of expressions.
120 | ///
121 | Literal IConstruct.Transform()
122 | {
123 | return this.Execute();
124 | }
125 |
126 | public override string ToString()
127 | {
128 | return expression;
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/Engine/ExpressionParseOnDemand.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 |
23 | namespace HiSystems.Interpreter
24 | {
25 | ///
26 | /// Represents an expression where compiling / parsing is deferred to when required.
27 | ///
28 | internal class ExpressionParseOnDemand : Expression
29 | {
30 | internal delegate IConstruct ParseToConstructDelegate(string expression, List variables);
31 |
32 | ///
33 | /// The callback that will convert the string expression to a construct when required.
34 | ///
35 | private ParseToConstructDelegate parseToConstruct;
36 |
37 | ///
38 | /// The root construct of the expression tree.
39 | /// When null indicates that the expression has not been parsed.
40 | ///
41 | private IConstruct construct = null;
42 |
43 | ///
44 | /// All of the variables defined in the expression.
45 | ///
46 | private IDictionary variables;
47 |
48 | public ExpressionParseOnDemand(ParseToConstructDelegate parseToConstruct, string expression)
49 | : base(expression)
50 | {
51 | if (parseToConstruct == null)
52 | throw new ArgumentNullException();
53 |
54 | this.parseToConstruct = parseToConstruct;
55 | }
56 |
57 | ///
58 | /// Returns the calculated value for the expression.
59 | /// Any variables should be set before calling this function.
60 | /// Will typically return a Number or Boolean literal value (depending on the type of expression).
61 | ///
62 | public override Literal Execute()
63 | {
64 | EnsureExpressionParsed();
65 |
66 | return construct.Transform();
67 | }
68 |
69 | ///
70 | /// Returns a dictionary containing all of the variables that were defined in the expression.
71 | /// If a variable is defined in multiple locations only one variable object is available in the dictionary.
72 | /// Variables are tokens/identifiers that could not be resolved to an operator or function name.
73 | /// Each variable should be assigned a value i.e: Variables["MyVariable"].Literal = (Number)1;
74 | ///
75 | public override IDictionary Variables
76 | {
77 | get
78 | {
79 | EnsureExpressionParsed();
80 |
81 | return this.variables;
82 | }
83 | }
84 |
85 | ///
86 | /// Parses the expression if it has not yet been parsed.
87 | ///
88 | private void EnsureExpressionParsed()
89 | {
90 | if (this.construct == null)
91 | {
92 | var variablesList = new List();
93 | this.construct = this.parseToConstruct(base.Source, variablesList);
94 | this.variables = TranslateVariablesToDictionary(variablesList);
95 | }
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/Engine/ExpressionParsed.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 |
23 | namespace HiSystems.Interpreter
24 | {
25 | ///
26 | /// Represents an expression that has been parsed and can be executed immediately without compilation/parsing.
27 | ///
28 | internal class ExpressionParsed : Expression
29 | {
30 | ///
31 | /// The root construct of the expression tree.
32 | ///
33 | private IConstruct construct;
34 |
35 | ///
36 | /// All of the variables defined in the expression.
37 | ///
38 | private IDictionary variables;
39 |
40 | internal ExpressionParsed(string expression, IConstruct value, List variables)
41 | : base(expression)
42 | {
43 | if (value == null)
44 | throw new ArgumentNullException();
45 |
46 | this.construct = value;
47 | this.variables = TranslateVariablesToDictionary(variables);
48 | }
49 |
50 | ///
51 | /// Returns the calculated value for the expression.
52 | /// Any variables should be set before calling this function.
53 | /// Will typically return a Number or Boolean literal value (depending on the type of expression).
54 | ///
55 | public override Literal Execute()
56 | {
57 | return construct.Transform();
58 | }
59 |
60 | ///
61 | /// Returns a dictionary containing all of the variables that were defined in the expression.
62 | /// If a variable is defined in multiple locations only one variable object is available in the dictionary.
63 | /// Variables are tokens/identifiers that could not be resolved to an operator or function name.
64 | /// Each variable should be assigned a value i.e: Variables["MyVariable"].Literal = (Number)1;
65 | ///
66 | public override IDictionary Variables
67 | {
68 | get
69 | {
70 | return this.variables;
71 | }
72 | }
73 | }
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/Engine/Token.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | internal enum TokenType
28 | {
29 | ///
30 | /// Number
31 | ///
32 | Number,
33 |
34 | ///
35 | /// Function, variable name or reserved word
36 | ///
37 | Identifier,
38 |
39 | ///
40 | /// '(' character.
41 | ///
42 | LeftParenthesis,
43 |
44 | ///
45 | /// ')' character.
46 | ///
47 | RightParenthesis,
48 |
49 | ///
50 | /// ',' character.
51 | ///
52 | Comma,
53 |
54 | ///
55 | /// String literal, surrounded/delimited by a " character
56 | ///
57 | Text,
58 |
59 | ///
60 | /// Only used during parsing - the tokenizer will not return a whitespace token.
61 | ///
62 | Whitespace,
63 |
64 | ///
65 | /// Value is surrounded by # characters.
66 | ///
67 | DateTime,
68 |
69 | ///
70 | /// Any other token that is not one of the other token types specified in this enum.
71 | /// Usually a special character such as '*' or '^'.
72 | ///
73 | Other
74 | }
75 |
76 | ///
77 | /// Represents a character or string that is a unique token type.
78 | ///
79 | internal class Token
80 | {
81 | private string value;
82 | private TokenType type;
83 |
84 | public Token(string token, TokenType type)
85 | {
86 | if (token == null)
87 | throw new ArgumentNullException();
88 |
89 | this.value = token;
90 | this.type = type;
91 | }
92 |
93 | public Token()
94 | {
95 | this.value = String.Empty;
96 | this.type = TokenType.Other;
97 | }
98 |
99 | public Token(char token, TokenType type)
100 | {
101 | this.value = token.ToString();
102 | this.type = type;
103 | }
104 |
105 | internal string Value
106 | {
107 | get
108 | {
109 | return this.value;
110 | }
111 | }
112 |
113 | internal TokenType Type
114 | {
115 | get
116 | {
117 | return this.type;
118 | }
119 | }
120 |
121 | public override string ToString()
122 | {
123 | return this.value;
124 | }
125 |
126 | public override bool Equals(Object value)
127 | {
128 | if (value is string)
129 | return AreEqual(this, (string)value);
130 | else
131 | return false;
132 | }
133 |
134 | public static bool operator ==(Token token1, string token2)
135 | {
136 | return AreEqual(token1, token2);
137 | }
138 |
139 | public static bool operator !=(Token token1, string token2)
140 | {
141 | return !AreEqual(token1, token2);
142 | }
143 |
144 | private static bool AreEqual(Token token1, string token2)
145 | {
146 | if (Object.Equals(token1, null) && Object.Equals(token2, null))
147 | return true;
148 | else if (Object.Equals(token1, null) || Object.Equals(token2, null))
149 | return false;
150 | else
151 | return token1.value.Equals(token2, StringComparison.InvariantCultureIgnoreCase);
152 | }
153 |
154 | public override int GetHashCode ()
155 | {
156 | return base.GetHashCode ();
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/Engine/Tokenizer.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | internal static class Tokenizer
28 | {
29 | ///
30 | /// Preliminary tokenization of the expression.
31 | /// Tokenizes numeric values, alpha values, parentheses, commas and other tokens.
32 | /// Any whitespace is removed.
33 | ///
34 | public static List Parse(string expression)
35 | {
36 | const char LeftParenthesis = '(';
37 | const char RightParenthesis = ')';
38 | const char Comma = ',';
39 | const char NumericNegative = '-';
40 | const char DateTimeDelimiter = '#';
41 |
42 | var whitespaceCharacters = new[] { ' ', '\t' };
43 | var numericCharacters = new[] { '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
44 | var identifierCharacters = new[] { '_', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
45 | var identifierSecondaryCharacters = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; // other characters that can be used as identifiers - but cannot be a starting character
46 | var textDelimiters = new[] { '\"', '\'' };
47 | bool isNumericNegative = false;
48 | bool parsingText = false;
49 | bool parsingDateTime = false;
50 |
51 | var tokens = new List();
52 | var currentTokenType = TokenType.Other;
53 | var currentToken = String.Empty;
54 | char currentTextDelimiter = '\0';
55 | var characterTokenType = TokenType.Other;
56 | var expressionEnumerator = new PeekableEnumerator(expression);
57 | var characterString = String.Empty;
58 |
59 | while (expressionEnumerator.MoveNext())
60 | {
61 | var tokenIsSeparateCharacter = false;
62 | var character = expressionEnumerator.Current;
63 |
64 | // if the character is a '-' and the subsequent character is a numeric character then this is a negative number.
65 | // otherwise it is some other character TokenType.Other -- probably a subtraction operator.
66 | isNumericNegative = character == NumericNegative && expressionEnumerator.CanPeek && numericCharacters.Contains(expressionEnumerator.Peek);
67 |
68 | if (textDelimiters.Contains(character) || parsingText)
69 | {
70 | if (textDelimiters.Contains(character) && !parsingText) // started parsing
71 | {
72 | characterTokenType = TokenType.Text;
73 | characterString = String.Empty; // consume character
74 | currentTextDelimiter = character;
75 | parsingText = true;
76 | }
77 | else if (character == currentTextDelimiter && parsingText) // finished parsing
78 | {
79 | characterString = String.Empty; // consume character
80 | parsingText = false;
81 | }
82 | else
83 | characterString = character.ToString();
84 | }
85 | else if (character == DateTimeDelimiter || parsingDateTime)
86 | {
87 | if (!parsingDateTime) // started parsing
88 | {
89 | characterTokenType = TokenType.DateTime;
90 | characterString = String.Empty; // consume character
91 | parsingDateTime = true;
92 | }
93 | else if (character == DateTimeDelimiter) // finished parsing
94 | {
95 | characterString = String.Empty; // consume character
96 | parsingDateTime = false;
97 | }
98 | else
99 | characterString = character.ToString();
100 | }
101 | else if (whitespaceCharacters.Contains(character))
102 | {
103 | characterTokenType = TokenType.Whitespace;
104 | characterString = String.Empty; // consume character
105 | }
106 | else if (identifierCharacters.Contains(character) || (currentTokenType == TokenType.Identifier && identifierSecondaryCharacters.Contains(character)))
107 | {
108 | characterTokenType = TokenType.Identifier;
109 | characterString = character.ToString();
110 | }
111 | else if (numericCharacters.Contains(character) || isNumericNegative)
112 | {
113 | characterTokenType = TokenType.Number;
114 | characterString = character.ToString();
115 | }
116 | else if (character == LeftParenthesis)
117 | {
118 | characterTokenType = TokenType.LeftParenthesis;
119 | characterString = character.ToString();
120 | tokenIsSeparateCharacter = true;
121 | }
122 | else if (character == RightParenthesis)
123 | {
124 | characterTokenType = TokenType.RightParenthesis;
125 | characterString = character.ToString();
126 | tokenIsSeparateCharacter = true;
127 | }
128 | else if (character == Comma)
129 | {
130 | characterTokenType = TokenType.Comma;
131 | characterString = character.ToString();
132 | tokenIsSeparateCharacter = true;
133 | }
134 | else
135 | {
136 | characterTokenType = TokenType.Other;
137 | characterString = character.ToString();
138 | }
139 |
140 | if (currentTokenType == characterTokenType && !tokenIsSeparateCharacter)
141 | currentToken += characterString;
142 | else
143 | {
144 | if (currentToken.Length > 0 || currentTokenType == TokenType.Text)
145 | tokens.Add(new Token(currentToken, currentTokenType));
146 |
147 | currentToken = characterString;
148 | currentTokenType = characterTokenType;
149 | }
150 | }
151 |
152 | if (currentToken.Length > 0 || currentTokenType == TokenType.Text)
153 | tokens.Add(new Token(currentToken, currentTokenType));
154 |
155 | return tokens;
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/Functions/ArrayFunction.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Returns an array from a list of items.
29 | /// Usage: Array(item1, item2, ...)
30 | /// Example: Array(1, 2, 3)
31 | ///
32 | public class ArrayFunction : Function
33 | {
34 | public override string Name
35 | {
36 | get
37 | {
38 | return "Array";
39 | }
40 | }
41 |
42 | public override Literal Execute(IConstruct[] arguments)
43 | {
44 | base.EnsureArgumentCountIsAtLeast(arguments, 1);
45 |
46 | return new Array(arguments.Select(argument => argument.Transform()).ToArray());
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Functions/Average.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Accepts one argument of type Array containing objects of type Number.
29 | /// Usage: AVG(array)
30 | /// Example: Avg(Array(1, 2, 3))
31 | ///
32 | public class Average : Function
33 | {
34 | public override string Name
35 | {
36 | get
37 | {
38 | return "AVG";
39 | }
40 | }
41 |
42 | public override Literal Execute(IConstruct[] arguments)
43 | {
44 | base.EnsureArgumentCountIs(arguments, 1);
45 |
46 | return new Number(base.GetTransformedArgumentDecimalArray(arguments, argumentIndex:0).Average());
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Functions/Format.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// The format for numeric values utilises the standard or custom numeric string formats.
29 | /// If format is omitted then the value is converted to the most appropriate string representation.
30 | /// Usage: Format(value [, format])
31 | /// Example: Format(1, '0.0')
32 | ///
33 | public class Format : Function
34 | {
35 | public override string Name
36 | {
37 | get
38 | {
39 | return "Format";
40 | }
41 | }
42 |
43 | public override Literal Execute(IConstruct[] arguments)
44 | {
45 | base.EnsureArgumentCountIsBetween(arguments, 1, 2);
46 |
47 | var value = base.GetTransformedArgument(arguments, argumentIndex: 0);
48 |
49 | string format;
50 |
51 | if (arguments.Length > 1)
52 | format = base.GetTransformedArgument(arguments, argumentIndex: 1);
53 | else
54 | format = null;
55 |
56 | if (value is Number)
57 | {
58 | if (format == null)
59 | return (Text)((Number)value).ToString();
60 | else
61 | return (Text)((Number)value).ToString(format);
62 | }
63 | else if (value is HiSystems.Interpreter.DateTime)
64 | {
65 | if (format == null)
66 | return (Text)((HiSystems.Interpreter.DateTime)value).ToString();
67 | else
68 | return (Text)((HiSystems.Interpreter.DateTime)value).ToString(format);
69 | }
70 | else
71 | throw new NotImplementedException(value.GetType().Name);
72 | }
73 | }
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/Functions/Function.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Represents a function that can be executed with a set of function arguments and return a function value.
29 | ///
30 | public abstract class Function
31 | {
32 | ///
33 | /// The unique name of the function that is used to identify the function in the token stream.
34 | ///
35 | public abstract string Name { get; }
36 |
37 | public abstract Literal Execute(IConstruct[] arguments);
38 |
39 | public Function()
40 | {
41 | }
42 |
43 | ///
44 | /// Throws an exception if the number of arguments supplied does not match the expected number of arguments.
45 | ///
46 | protected void EnsureArgumentCountIs(IConstruct[] arguments, int expectedArgumentCount)
47 | {
48 | if (expectedArgumentCount != arguments.Length)
49 | throw new InvalidOperationException(String.Format("{0} has been supplied {1} arguments, but expects {2} arguments", this.Name, arguments.Length, expectedArgumentCount));
50 | }
51 |
52 | ///
53 | /// Throws an exception if the number of arguments supplied is less then the minimum required number of arguments.
54 | /// Useful when the function can receive optional or a variable number of arguments.
55 | ///
56 | protected void EnsureArgumentCountIsAtLeast(IConstruct[] arguments, int minimumArgumentCount)
57 | {
58 | if (minimumArgumentCount > arguments.Length)
59 | throw new InvalidOperationException(String.Format("{0} has been supplied {1} arguments, but expects at least {2} arguments", this.Name, arguments.Length, minimumArgumentCount));
60 | }
61 |
62 | ///
63 | /// Throws an exception if the number of arguments supplied is less then the minimum required number of arguments.
64 | /// Or throws an exception if the number of arguments supplied is greater then the maximum allowable number of arguments.
65 | /// Useful when the function can receive optional or a variable number of arguments.
66 | ///
67 | protected void EnsureArgumentCountIsBetween(IConstruct[] arguments, int minimumArgumentCount, int maximumArgumentCount)
68 | {
69 | EnsureArgumentCountIsAtLeast(arguments, minimumArgumentCount);
70 |
71 | if (maximumArgumentCount < arguments.Length)
72 | throw new InvalidOperationException(String.Format("{0} has been supplied {1} arguments, but expects at most {2} arguments", this.Name, arguments.Length, maximumArgumentCount));
73 | }
74 |
75 | ///
76 | /// Returns an array of decimal values from a construct which must be of type Array.
77 | /// Minimise the use of this function because it will traverse and execute the entire expression tree if the construct represents an operation or function.
78 | /// 0 based index - error messages are reported as 1 based indexes
79 | ///
80 | protected decimal[] GetTransformedArgumentDecimalArray(IConstruct[] arguments, int argumentIndex)
81 | {
82 | return this.GetTransformedArgumentArray(arguments, argumentIndex).Select(number => (decimal)number).ToArray();
83 | }
84 |
85 | ///
86 | /// Returns an array of T values from a construct which must be of type Array.
87 | /// Minimise the use of this function because it will traverse and execute the entire expression tree if the construct represents an operation or function.
88 | /// 0 based index - error messages are reported as 1 based indexes
89 | ///
90 | protected T[] GetTransformedArgumentArray(IConstruct[] arguments, int argumentIndex) where T : Literal
91 | {
92 | var argument = GetArgument(arguments, argumentIndex);
93 | var transformedArgument = argument.Transform();
94 |
95 | var transformedArray = CastArgumentToType(transformedArgument, argumentIndex).Select(construct => construct.Transform());
96 |
97 | if (!transformedArray.All(item => item is T))
98 | throw new InvalidOperationException(String.Format("{0} argument {1} does not contain only {2} values and cannot be used with the {3} function", argument.ToString(), argumentIndex + 1, typeof(T).Name, this.Name));
99 |
100 | return transformedArray.Cast().ToArray();
101 | }
102 |
103 | ///
104 | /// Gets the argument and transforms/executes it and returns it as of type T.
105 | /// If the transformed result is not of type T then an exception is thrown.
106 | /// Minimise the use of this function because it will traverse and execute the entire expression tree if the construct represents an operation or function.
107 | /// 0 based index - error messages are reported as 1 based indexes
108 | ///
109 | protected T GetTransformedArgument(IConstruct[] arguments, int argumentIndex) where T : Literal
110 | {
111 | var argument = GetArgument(arguments, argumentIndex);
112 | var transformedArgument = argument.Transform();
113 |
114 | return CastArgumentToType(transformedArgument, argumentIndex);
115 | }
116 |
117 | ///
118 | /// Returns the argument (un-transformed).
119 | /// Throws an exception if there is no argument at the index.
120 | ///
121 | /// 0 based index - error messages are reported as 1 based indexes
122 | private IConstruct GetArgument(IConstruct[] arguments, int argumentIndex)
123 | {
124 | if (argumentIndex >= arguments.Length)
125 | throw new ArgumentException(String.Format("Function {0} is missing argument {1}.", this.Name, argumentIndex + 1));
126 |
127 | return arguments[argumentIndex];
128 | }
129 |
130 | ///
131 | /// Throws an exception if the argument passed, via the argument index is not the expected type.
132 | /// ArgumentIndex is only used for the error message and should match the index of the argument that is passed.
133 | ///
134 | private T CastArgumentToType(IConstruct argument, int argumentIndex)
135 | {
136 | if (!(argument is T))
137 | throw new InvalidOperationException(String.Format("Argument {1}: {0} is not of type {2} and cannot be used with the {3} function", argument.ToString(), argumentIndex + 1, typeof(T).Name, this.Name));
138 |
139 | return (T)argument;
140 | }
141 |
142 | public override string ToString()
143 | {
144 | return this.Name + "()";
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/Functions/If.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Based on the condition / expression returns the true or false result.
29 | /// Usage: If(condition, trueResult, falseResult)
30 | /// Example: If(1 = 1, 'Yes', 'No')
31 | ///
32 | public class If : Function
33 | {
34 | public override string Name
35 | {
36 | get
37 | {
38 | return "If";
39 | }
40 | }
41 |
42 | public override Literal Execute(IConstruct[] arguments)
43 | {
44 | base.EnsureArgumentCountIs(arguments, 3);
45 |
46 | var condition = base.GetTransformedArgument(arguments, argumentIndex: 0);
47 |
48 | if (condition)
49 | return base.GetTransformedArgument(arguments, argumentIndex: 1);
50 | else
51 | return base.GetTransformedArgument(arguments, argumentIndex: 2);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Functions/Len.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Accepts one argument of type string for which the length is returned.
29 | /// Usage: Len(text)
30 | /// Example: Len('abc')
31 | ///
32 | public class Len : Function
33 | {
34 | public override string Name
35 | {
36 | get
37 | {
38 | return "LEN";
39 | }
40 | }
41 |
42 | public override Literal Execute(IConstruct[] arguments)
43 | {
44 | base.EnsureArgumentCountIs(arguments, 1);
45 |
46 | return new Number(base.GetTransformedArgument(arguments, argumentIndex:0).Length);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Functions/Max.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Returns the maximum numeric value from an array.
29 | /// Usage: Max(array)
30 | /// Example: Max(Array(1, 2, 3))
31 | ///
32 | public class Max : Function
33 | {
34 | public override string Name
35 | {
36 | get
37 | {
38 | return "MAX";
39 | }
40 | }
41 |
42 | public override Literal Execute(IConstruct[] arguments)
43 | {
44 | base.EnsureArgumentCountIs(arguments, 1);
45 |
46 | return new Number(base.GetTransformedArgumentDecimalArray(arguments, argumentIndex:0).Max());
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Functions/Min.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Returns the minimum numeric value from an array.
29 | /// Usage: Min(array)
30 | /// Example: Min(Array(1, 2, 3))
31 | ///
32 | public class Min : Function
33 | {
34 | public override string Name
35 | {
36 | get
37 | {
38 | return "Min";
39 | }
40 | }
41 |
42 | public override Literal Execute(IConstruct[] arguments)
43 | {
44 | base.EnsureArgumentCountIs(arguments, 1);
45 |
46 | return new Number(base.GetTransformedArgumentDecimalArray(arguments, argumentIndex:0).Min());
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Functions/Sum.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Returns the sum total of the numeric values from an array.
29 | /// Usage: Sum(array)
30 | /// Example: Sum(Array(1, 2, 3))
31 | ///
32 | public class Sum : Function
33 | {
34 | public override string Name
35 | {
36 | get
37 | {
38 | return "SUM";
39 | }
40 | }
41 |
42 | public override Literal Execute(IConstruct[] arguments)
43 | {
44 | base.EnsureArgumentCountIs(arguments, 1);
45 |
46 | return new Number(base.GetTransformedArgumentDecimalArray(arguments, argumentIndex:0).Sum());
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Functions/Today.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Returns today's date.
29 | /// Usage: Today()
30 | ///
31 | public class Today : Function
32 | {
33 | public override string Name
34 | {
35 | get
36 | {
37 | return "TODAY";
38 | }
39 | }
40 |
41 | public override Literal Execute(IConstruct[] arguments)
42 | {
43 | base.EnsureArgumentCountIs(arguments, 0);
44 |
45 | return new DateTime(System.DateTime.Today);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/HiSystems.Interpreter.MonoTouch.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {B7F045FA-2E47-40EE-9501-B407C52D9D19}
9 | {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
10 | Library
11 | HiSystems.Interpreter
12 | HiSystems-Interpreter
13 | Xamarin.iOS
14 | v1.0
15 |
16 |
17 | True
18 | full
19 | False
20 | bin\Debug
21 | DEBUG;
22 | prompt
23 | 4
24 | False
25 |
26 |
27 | none
28 | True
29 | bin\Release
30 | prompt
31 | 4
32 | False
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 |
--------------------------------------------------------------------------------
/HiSystems.Interpreter.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {65D25F1E-BD7D-4B5E-8457-DD8A4813DD30}
9 | Library
10 | Properties
11 | HiSystems.Interpreter
12 | HiSystems.Interpreter
13 | v3.5
14 | 512
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
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 |
103 |
--------------------------------------------------------------------------------
/HiSystems.Interpreter.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HiSystems.Interpreter", "HiSystems.Interpreter.csproj", "{65D25F1E-BD7D-4B5E-8457-DD8A4813DD30}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {65D25F1E-BD7D-4B5E-8457-DD8A4813DD30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {65D25F1E-BD7D-4B5E-8457-DD8A4813DD30}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {65D25F1E-BD7D-4B5E-8457-DD8A4813DD30}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {65D25F1E-BD7D-4B5E-8457-DD8A4813DD30}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/Library/PeekableEnumerator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | internal class PeekableEnumerator : IEnumerator
28 | {
29 | private IEnumerator peekingEnumerator;
30 | private T current = default(T);
31 | private T peeked;
32 |
33 | public PeekableEnumerator(IEnumerable enumerable)
34 | {
35 | this.peekingEnumerator = enumerable.GetEnumerator();
36 | MoveNextInternal();
37 | }
38 |
39 | public T Current
40 | {
41 | get
42 | {
43 | return current;
44 | }
45 | }
46 |
47 | ///
48 | /// Returns the item ahead of the current item being enumerated.
49 | ///
50 | public T Peek
51 | {
52 | get
53 | {
54 | return peeked;
55 | }
56 | }
57 |
58 | ///
59 | /// Indicates whether there is another item ahead of the current item.
60 | ///
61 | public bool CanPeek
62 | {
63 | get
64 | {
65 | return peeked != null;
66 | }
67 | }
68 |
69 | object System.Collections.IEnumerator.Current
70 | {
71 | get
72 | {
73 | return current;
74 | }
75 | }
76 |
77 | public bool MoveNext()
78 | {
79 | this.current = this.peeked;
80 |
81 | // if reached end of the enumeration
82 | if (Object.Equals(this.current, default(T)))
83 | return false;
84 | else
85 | {
86 | MoveNextInternal();
87 | return true;
88 | }
89 | }
90 |
91 | private void MoveNextInternal()
92 | {
93 | if (this.peekingEnumerator.MoveNext())
94 | this.peeked = this.peekingEnumerator.Current;
95 | else
96 | this.peeked = default(T);
97 | }
98 |
99 | public void Reset()
100 | {
101 | this.peekingEnumerator.Reset();
102 |
103 | MoveNextInternal();
104 | }
105 |
106 | public void Dispose()
107 | {
108 | this.peekingEnumerator.Dispose();
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Literals/Array.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Represents an array of constructs.
29 | /// Potentially an array of literals, variables or functions.
30 | ///
31 | public class Array : Literal, IEnumerable
32 | {
33 | private List items = new List();
34 |
35 | public Array(decimal[] values)
36 | {
37 | items.AddRange(values.Select(item => (Number)item).ToArray());
38 | }
39 |
40 | public Array(IConstruct[] values)
41 | {
42 | items.AddRange(values);
43 | }
44 |
45 | public static implicit operator List(Array array)
46 | {
47 | return array.items;
48 | }
49 |
50 | public static implicit operator Array(IConstruct[] constructs)
51 | {
52 | return new Array(constructs);
53 | }
54 |
55 | public override string ToString()
56 | {
57 | return "Array";
58 | }
59 |
60 | System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
61 | {
62 | return items.GetEnumerator();
63 | }
64 |
65 | IEnumerator IEnumerable.GetEnumerator ()
66 | {
67 | return items.GetEnumerator();
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Literals/Boolean.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System.Collections.Generic;
21 | using System.ComponentModel;
22 | using System.Linq;
23 | using System.Text;
24 | using HiSystems.Interpreter.Converters;
25 |
26 | namespace HiSystems.Interpreter
27 | {
28 | ///
29 | /// Represents an immutable boolean value.
30 | ///
31 | [TypeConverter(typeof(BooleanTypeConverter))]
32 | public class Boolean : Literal
33 | {
34 | private bool value;
35 |
36 | public Boolean(bool value)
37 | {
38 | this.value = value;
39 | }
40 |
41 | public override string ToString()
42 | {
43 | return value.ToString();
44 | }
45 |
46 | public static implicit operator bool(Boolean boolean)
47 | {
48 | return boolean.value;
49 | }
50 |
51 | public static implicit operator Boolean(bool value)
52 | {
53 | return new Boolean(value);
54 | }
55 |
56 | public static Boolean operator==(Boolean value1, Boolean value2)
57 | {
58 | return AreEqual(value1, value2);
59 | }
60 |
61 | public static Boolean operator!=(Boolean value1, Boolean value2)
62 | {
63 | return !AreEqual(value1, value2);
64 | }
65 |
66 | public static Boolean operator&(Boolean value1, Boolean value2)
67 | {
68 | return value1.value & value2.value;
69 | }
70 |
71 | public static Boolean operator|(Boolean value1, Boolean value2)
72 | {
73 | return value1.value | value2.value;
74 | }
75 |
76 | public static Boolean operator!(Boolean value)
77 | {
78 | return new Boolean(!value.value);
79 | }
80 |
81 | public static bool operator true(Boolean value)
82 | {
83 | return value.value;
84 | }
85 |
86 | public static bool operator false(Boolean value)
87 | {
88 | return !value.value;
89 | }
90 |
91 | public override int GetHashCode()
92 | {
93 | return base.GetHashCode();
94 | }
95 |
96 | public override bool Equals (object obj)
97 | {
98 | if (obj == null || !(obj is Boolean))
99 | return false;
100 | else
101 | return AreEqual(this, (Boolean)obj);
102 | }
103 |
104 | private static Boolean AreEqual(Boolean value1, Boolean value2)
105 | {
106 | if (ReferenceEquals(value1, null) || ReferenceEquals(value2, null))
107 | return new Boolean(false);
108 | else
109 | return new Boolean(value1.value == value2.value);
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Literals/DateTime.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.ComponentModel;
23 | using System.Linq;
24 | using System.Text;
25 | using HiSystems.Interpreter.Converters;
26 |
27 | namespace HiSystems.Interpreter
28 | {
29 | ///
30 | /// Represents an immutable date / time value.
31 | ///
32 | [TypeConverter(typeof(DateTimeTypeConverter))]
33 | public class DateTime : Literal
34 | {
35 | private System.DateTime value;
36 |
37 | public DateTime(System.DateTime value)
38 | {
39 | this.value = value;
40 | }
41 |
42 | public override string ToString()
43 | {
44 | return value.ToString();
45 | }
46 |
47 | public string ToString(string format)
48 | {
49 | return value.ToString(format);
50 | }
51 |
52 | public static implicit operator System.DateTime(DateTime date)
53 | {
54 | return date.value;
55 | }
56 |
57 | public static implicit operator DateTime(System.DateTime value)
58 | {
59 | return new DateTime(value);
60 | }
61 |
62 | public static Boolean operator==(DateTime value1, DateTime value2)
63 | {
64 | return AreEqual(value1, value2);
65 | }
66 |
67 | public static Boolean operator!=(DateTime value1, DateTime value2)
68 | {
69 | return !AreEqual(value1, value2);
70 | }
71 |
72 | public static DateTime operator+(DateTime date, Number days)
73 | {
74 | return new DateTime(date.value.AddDays((double)days));
75 | }
76 |
77 | public static DateTime operator-(DateTime date, Number days)
78 | {
79 | return new DateTime(date.value.AddDays(-(double)days));
80 | }
81 |
82 | public static Number operator-(DateTime date1, DateTime date2)
83 | {
84 | return new Number(Convert.ToDecimal((date1.value - date2.value).TotalDays));
85 | }
86 |
87 | public static Boolean operator>(DateTime value1, DateTime value2)
88 | {
89 | return new Boolean(value1.value > value2.value);
90 | }
91 |
92 | public static Boolean operator>=(DateTime value1, DateTime value2)
93 | {
94 | return new Boolean(value1.value >= value2.value);
95 | }
96 |
97 | public static Boolean operator<(DateTime value1, DateTime value2)
98 | {
99 | return new Boolean(value1.value < value2.value);
100 | }
101 |
102 | public static Boolean operator<=(DateTime value1, DateTime value2)
103 | {
104 | return new Boolean(value1.value <= value2.value);
105 | }
106 |
107 | public override bool Equals(object obj)
108 | {
109 | if (obj == null || !(obj is DateTime))
110 | return false;
111 | else
112 | return AreEqual(this, (DateTime)obj);
113 | }
114 |
115 | public override int GetHashCode()
116 | {
117 | return base.GetHashCode();
118 | }
119 |
120 | private static Boolean AreEqual(DateTime value1, DateTime value2)
121 | {
122 | if (ReferenceEquals(value1, null) || ReferenceEquals(value2, null))
123 | return new Boolean(false);
124 | else
125 | return new Boolean(value1.value == value2.value);
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/Literals/Literal.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 |
22 | namespace HiSystems.Interpreter
23 | {
24 | ///
25 | /// Base class for all literals / concrete values, such as a number, boolean, string etc.
26 | ///
27 | public abstract class Literal : IConstruct
28 | {
29 | ///
30 | /// A literal does not need to be transformed or executed like a function or operation.
31 | /// So return this construct as is.
32 | ///
33 | Literal IConstruct.Transform()
34 | {
35 | return this;
36 | }
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/Literals/Number.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.ComponentModel;
22 | using System.Text;
23 | using HiSystems.Interpreter.Converters;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Represents an immutable numeric value.
29 | ///
30 | [TypeConverter(typeof(NumberTypeConverter))]
31 | public class Number : Literal
32 | {
33 | private decimal value;
34 |
35 | public Number(decimal value)
36 | {
37 | this.value = value;
38 | }
39 |
40 | public override string ToString()
41 | {
42 | return value.ToString();
43 | }
44 |
45 | public string ToString(string format)
46 | {
47 | return value.ToString(format);
48 | }
49 |
50 | public static implicit operator decimal(Number number)
51 | {
52 | return number.value;
53 | }
54 |
55 | public static implicit operator double(Number number)
56 | {
57 | return (double)number.value;
58 | }
59 |
60 | public static implicit operator Number(decimal value)
61 | {
62 | return new Number(value);
63 | }
64 |
65 | public static implicit operator Number(double value)
66 | {
67 | return new Number((decimal)value);
68 | }
69 |
70 | public static implicit operator Number(int value)
71 | {
72 | return new Number((decimal)value);
73 | }
74 |
75 | public static Number Parse(string value)
76 | {
77 | return new Number(Decimal.Parse(value));
78 | }
79 |
80 | public static Boolean operator==(Number value1, Number value2)
81 | {
82 | return AreEqual(value1, value2);
83 | }
84 |
85 | public static Boolean operator!=(Number value1, Number value2)
86 | {
87 | return !AreEqual(value1, value2);
88 | }
89 |
90 | public static Number operator+(Number value1, Number value2)
91 | {
92 | return new Number(value1.value + value2.value);
93 | }
94 |
95 | public static Number operator-(Number value1, Number value2)
96 | {
97 | return new Number(value1.value - value2.value);
98 | }
99 |
100 | public static Number operator/(Number value1, Number value2)
101 | {
102 | return new Number(value1.value / value2.value);
103 | }
104 |
105 | public static Boolean operator>(Number value1, Number value2)
106 | {
107 | return new Boolean(value1.value > value2.value);
108 | }
109 |
110 | public static Boolean operator>=(Number value1, Number value2)
111 | {
112 | return new Boolean(value1.value >= value2.value);
113 | }
114 |
115 | public static Boolean operator<(Number value1, Number value2)
116 | {
117 | return new Boolean(value1.value < value2.value);
118 | }
119 |
120 | public static Boolean operator<=(Number value1, Number value2)
121 | {
122 | return new Boolean(value1.value <= value2.value);
123 | }
124 |
125 | public static Number operator*(Number value1, Number value2)
126 | {
127 | return new Number(value1.value * value2.value);
128 | }
129 |
130 | public static Number operator%(Number value1, Number value2)
131 | {
132 | return new Number(value1.value % value2.value);
133 | }
134 |
135 | public override bool Equals (object obj)
136 | {
137 | if (obj == null || !(obj is Number))
138 | return false;
139 | else
140 | return AreEqual(this, (Number)obj);
141 | }
142 |
143 | private static Boolean AreEqual(Number value1, Number value2)
144 | {
145 | if (ReferenceEquals(value1, null) || ReferenceEquals(value2, null))
146 | return new Boolean(false);
147 | else
148 | return new Boolean(value1.value == value2.value);
149 | }
150 |
151 | public override int GetHashCode()
152 | {
153 | return base.GetHashCode();
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/Literals/Text.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.ComponentModel;
22 | using HiSystems.Interpreter.Converters;
23 |
24 | namespace HiSystems.Interpreter
25 | {
26 | [TypeConverter(typeof(TextTypeConverter))]
27 | public class Text : Literal
28 | {
29 | private string value;
30 |
31 | public Text(string value)
32 | {
33 | this.value = value;
34 | }
35 |
36 | public static implicit operator string(Text text)
37 | {
38 | return text.value;
39 | }
40 |
41 | public static implicit operator Text(string text)
42 | {
43 | return new Text(text);
44 | }
45 |
46 | public static Boolean operator==(Text value1, Text value2)
47 | {
48 | return AreEqual(value1, value2);
49 | }
50 |
51 | public static Boolean operator!=(Text value1, Text value2)
52 | {
53 | return !AreEqual(value1, value2);
54 | }
55 |
56 | public static Text operator+(Text value1, Text value2)
57 | {
58 | return new Text(value1.value + value2.value);
59 | }
60 |
61 | ///
62 | /// Returns the length of the text.
63 | ///
64 | public int Length
65 | {
66 | get
67 | {
68 | return this.value.Length;
69 | }
70 | }
71 |
72 | public override bool Equals(object obj)
73 | {
74 | if (obj == null || !(obj is Text))
75 | return false;
76 | else
77 | return AreEqual(this, (Text)obj);
78 | }
79 |
80 | private static Boolean AreEqual(Text value1, Text value2)
81 | {
82 | if (ReferenceEquals(value1, null) || ReferenceEquals(value2, null))
83 | return new Boolean(false);
84 | else
85 | return new Boolean(value1.value.Equals(value2.value, StringComparison.InvariantCulture));
86 | }
87 |
88 | public override int GetHashCode()
89 | {
90 | return base.GetHashCode();
91 | }
92 |
93 | public override string ToString()
94 | {
95 | return value.ToString();
96 | }
97 | }
98 | }
99 |
100 |
--------------------------------------------------------------------------------
/Operators/AddOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Adds two numeric values, text or a date and numeric value (adds days).
29 | /// Usage:
30 | /// numericValue + numericValue
31 | /// dateTime + numericDays
32 | /// text + textToConcatenate
33 | /// Examples:
34 | /// 1 + 2
35 | /// #2000-01-01# + 1
36 | /// 'ab' + 'c'
37 | ///
38 | public class AddOperator : Operator
39 | {
40 | public AddOperator()
41 | {
42 | }
43 |
44 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
45 | {
46 | var argument1Transformed = base.GetTransformedConstruct(argument1);
47 | var argument2Transformed = base.GetTransformedConstruct(argument2);
48 |
49 | if (argument1Transformed is Number && argument2Transformed is Number)
50 | return ((Number)argument1Transformed) + ((Number)argument2Transformed);
51 | else if (argument1Transformed is DateTime && argument2Transformed is Number)
52 | return ((DateTime)argument1Transformed) + ((Number)argument2Transformed);
53 | else if (argument1Transformed is Text && argument2Transformed is Text)
54 | return ((Text)argument1Transformed) + ((Text)argument2Transformed);
55 | else
56 | throw new InvalidOperationException(String.Format("Add operator requires arguments of type Number, DateTime or Text. Argument types are {0} {1}.", argument1Transformed.GetType().Name, argument2Transformed.GetType().Name));
57 | }
58 |
59 | public override string Token
60 | {
61 | get
62 | {
63 | return "+";
64 | }
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Operators/AndOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Logical And operator.
29 | /// Usage: booleanValue AND booleanValue
30 | /// Example: true AND false
31 | ///
32 | public class AndOperator : Operator
33 | {
34 | public AndOperator()
35 | {
36 | }
37 |
38 | ///
39 | /// Non-zero arguments are considered true.
40 | ///
41 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
42 | {
43 | return base.GetTransformedConstruct(argument1) && base.GetTransformedConstruct(argument2);
44 | }
45 |
46 | public override string Token
47 | {
48 | get
49 | {
50 | return "AND";
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Operators/DivideOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Divides numeric values.
29 | /// Usage: numericValue / numericValue
30 | /// Example: 1 / 2
31 | ///
32 | public class DivideOperator : Operator
33 | {
34 | public DivideOperator()
35 | {
36 | }
37 |
38 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
39 | {
40 | var argument2Value = base.GetTransformedConstruct(argument2);
41 |
42 | if (argument2Value == 0)
43 | throw new DivideByZeroException(argument2.ToString());
44 |
45 | return base.GetTransformedConstruct(argument1) / argument2Value;
46 | }
47 |
48 | public override string Token
49 | {
50 | get
51 | {
52 | return "/";
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Operators/EqualToOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Compares two numeric, text, boolean or datetime values.
29 | /// Usage:
30 | /// numericValue = numericValue
31 | /// booleanValue = booleanValue
32 | /// text = text
33 | /// dateTime = dateTime
34 | /// Examples:
35 | /// 1 = 2
36 | /// true = false
37 | /// 'a' = 'b'
38 | /// #2000-1-1# = #2000-1-2#
39 | ///
40 | public class EqualToOperator : Operator
41 | {
42 | public EqualToOperator()
43 | {
44 | }
45 |
46 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
47 | {
48 | var argument1Transformed = base.GetTransformedConstruct(argument1);
49 | var argument2Transformed = base.GetTransformedConstruct(argument2);
50 |
51 | if (argument1Transformed is Number && argument2Transformed is Number)
52 | return ((Number)argument1Transformed) == ((Number)argument2Transformed);
53 | else if (argument1Transformed is Boolean && argument2Transformed is Boolean)
54 | return ((Boolean)argument1Transformed) == ((Boolean)argument2Transformed);
55 | else if (argument1Transformed is DateTime && argument2Transformed is DateTime)
56 | return ((DateTime)argument1Transformed) == ((DateTime)argument2Transformed);
57 | else if (argument1Transformed is Text && argument2Transformed is Text)
58 | return ((Text)argument1Transformed) == ((Text)argument2Transformed);
59 | else
60 | throw new InvalidOperationException(String.Format("Equality operator requires arguments of type Number, DateTime or Boolean. Argument types are {0} {1}.", argument1Transformed.GetType().Name, argument2Transformed.GetType().Name));
61 | }
62 |
63 | public override string Token
64 | {
65 | get
66 | {
67 | return "=";
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Operators/GreaterThanOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Compares two numeric or datetime values.
29 | /// Usage:
30 | /// numericValue > numericValue
31 | /// dateTime > dateTime
32 | /// Examples:
33 | /// 1 > 2
34 | /// #2000-01-02# > #2000-01-01#
35 | ///
36 | public class GreaterThanOperator : Operator
37 | {
38 | public GreaterThanOperator()
39 | {
40 | }
41 |
42 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
43 | {
44 | var argument1Transformed = base.GetTransformedConstruct(argument1);
45 | var argument2Transformed = base.GetTransformedConstruct(argument2);
46 |
47 | if (argument1Transformed is Number && argument2Transformed is Number)
48 | return ((Number)argument1Transformed) > ((Number)argument2Transformed);
49 | else if (argument1Transformed is DateTime && argument2Transformed is DateTime)
50 | return ((DateTime)argument1Transformed) > ((DateTime)argument2Transformed);
51 | else
52 | throw new InvalidOperationException(String.Format("Greater than operator requires arguments of type Number or DateTime. Argument types are {0} {1}.", argument1Transformed.GetType().Name, argument2Transformed.GetType().Name));
53 | }
54 |
55 | public override string Token
56 | {
57 | get
58 | {
59 | return ">";
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Operators/GreaterThanOrEqualToOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Compares two numeric or datetime values.
29 | /// Usage:
30 | /// numericValue >= numericValue
31 | /// dateTime >= dateTime
32 | /// Examples:
33 | /// 1 >= 2
34 | /// #2000-01-02# >= #2000-01-01#
35 | ///
36 | public class GreaterThanOrEqualToOperator : Operator
37 | {
38 | public GreaterThanOrEqualToOperator()
39 | {
40 | }
41 |
42 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
43 | {
44 | var argument1Transformed = base.GetTransformedConstruct(argument1);
45 | var argument2Transformed = base.GetTransformedConstruct(argument2);
46 |
47 | if (argument1Transformed is Number && argument2Transformed is Number)
48 | return ((Number)argument1Transformed) >= ((Number)argument2Transformed);
49 | else if (argument1Transformed is DateTime && argument2Transformed is DateTime)
50 | return ((DateTime)argument1Transformed) >= ((DateTime)argument2Transformed);
51 | else
52 | throw new InvalidOperationException(String.Format("Greater than or equal to operator requires arguments of type Number or DateTime. Argument types are {0} {1}.", argument1Transformed.GetType().Name, argument2Transformed.GetType().Name));
53 | }
54 |
55 | public override string Token
56 | {
57 | get
58 | {
59 | return ">=";
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Operators/LessThanOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Compares two numeric or datetime values.
29 | /// Usage:
30 | /// numericValue < numericValue
31 | /// dateTime < dateTime
32 | /// Examples:
33 | /// 1 < 2
34 | /// #2000-01-02# < #2000-01-01#
35 | ///
36 | public class LessThanOperator : Operator
37 | {
38 | public LessThanOperator()
39 | {
40 | }
41 |
42 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
43 | {
44 | var argument1Transformed = base.GetTransformedConstruct(argument1);
45 | var argument2Transformed = base.GetTransformedConstruct(argument2);
46 |
47 | if (argument1Transformed is Number && argument2Transformed is Number)
48 | return ((Number)argument1Transformed) < ((Number)argument2Transformed);
49 | else if (argument1Transformed is DateTime && argument2Transformed is DateTime)
50 | return ((DateTime)argument1Transformed) < ((DateTime)argument2Transformed);
51 | else
52 | throw new InvalidOperationException(String.Format("Less than operator requires arguments of type Number or DateTime. Argument types are {0} {1}.", argument1Transformed.GetType().Name, argument2Transformed.GetType().Name));
53 | }
54 |
55 | public override string Token
56 | {
57 | get
58 | {
59 | return "<";
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Operators/LessThanOrEqualToOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Compares two numeric or datetime values.
29 | /// Usage:
30 | /// numericValue <= numericValue
31 | /// dateTime <= dateTime
32 | /// Examples:
33 | /// 1 <= 2
34 | /// #2000-01-02# <= #2000-01-0
35 | ///
36 | public class LessThanOrEqualToOperator : Operator
37 | {
38 | public LessThanOrEqualToOperator()
39 | {
40 | }
41 |
42 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
43 | {
44 | var argument1Transformed = base.GetTransformedConstruct(argument1);
45 | var argument2Transformed = base.GetTransformedConstruct(argument2);
46 |
47 | if (argument1Transformed is Number && argument2Transformed is Number)
48 | return ((Number)argument1Transformed) <= ((Number)argument2Transformed);
49 | else if (argument1Transformed is DateTime && argument2Transformed is DateTime)
50 | return ((DateTime)argument1Transformed) <= ((DateTime)argument2Transformed);
51 | else
52 | throw new InvalidOperationException(String.Format("Less than or equal to operator requires arguments of type Number or DateTime. Argument types are {0} {1}.", argument1Transformed.GetType().Name, argument2Transformed.GetType().Name));
53 | }
54 |
55 | public override string Token
56 | {
57 | get
58 | {
59 | return "<=";
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Operators/ModulusOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Returns the modulus from two numeric values.
29 | /// Usage: numericValue % numericValue
30 | /// Example: 1 % 2
31 | ///
32 | public class ModulusOperator : Operator
33 | {
34 | public ModulusOperator()
35 | {
36 | }
37 |
38 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
39 | {
40 | return base.GetTransformedConstruct(argument1) % base.GetTransformedConstruct(argument2);
41 | }
42 |
43 | public override string Token
44 | {
45 | get
46 | {
47 | return "%";
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Operators/MultiplyOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Multiplies two numeric values.
29 | /// Usage: numericValue * numericValue
30 | /// Example: 1 * 2
31 | ///
32 | public class MultiplyOperator : Operator
33 | {
34 | public MultiplyOperator()
35 | {
36 | }
37 |
38 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
39 | {
40 | return base.GetTransformedConstruct(argument1) * base.GetTransformedConstruct(argument2);
41 | }
42 |
43 | public override string Token
44 | {
45 | get
46 | {
47 | return "*";
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Operators/NotEqualToOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Compares two numeric, text, boolean or datetime values.
29 | /// Usage:
30 | /// numericValue <> numericValue
31 | /// booleanValue <> booleanValue
32 | /// text <> text
33 | /// dateTime = dateTime
34 | /// Examples:
35 | /// 1 <> 2
36 | /// true <> false
37 | /// 'a' <> 'b'
38 | /// #2000-1-1# <> #2000-1-2#
39 | ///
40 | public class NotEqualToOperator : Operator
41 | {
42 | private EqualToOperator equalToOperator = new EqualToOperator();
43 |
44 | public NotEqualToOperator()
45 | {
46 | }
47 |
48 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
49 | {
50 | return !(Boolean)equalToOperator.Execute(argument1, argument2);
51 | }
52 |
53 | public override string Token
54 | {
55 | get
56 | {
57 | return "<>";
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Operators/Operator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Base class for all arithmetic / logical / equality operators.
29 | ///
30 | public abstract class Operator
31 | {
32 | ///
33 | /// The unique token that indicates this operation.
34 | /// For special character tokens (non alpha-numeric characters) this can be at most 2 characters.
35 | /// For example '*' for multiply, or '/' for divide.
36 | ///
37 | public abstract string Token { get; }
38 |
39 | ///
40 | /// Should execute the operation and return the appropriate construct.
41 | ///
42 | internal abstract Literal Execute(IConstruct argument1, IConstruct argument2);
43 |
44 | ///
45 | /// Gets the construct and transforms/executes it and returns it as of type T.
46 | /// If the transformed result is not of type T then an exception is thrown.
47 | /// Minimise the use of this function because it will traverse and execute the entire expression tree if the construct represents an operation or function.
48 | ///
49 | protected T GetTransformedConstruct(IConstruct construct) where T : Literal
50 | {
51 | var transformedConstruct = construct.Transform();
52 |
53 | return CastConstructToType(transformedConstruct);
54 | }
55 |
56 | ///
57 | /// Throws an exception if the argument passed is not the expected type.
58 | ///
59 | private T CastConstructToType(IConstruct construct)
60 | {
61 | if (!(construct is T))
62 | throw new InvalidOperationException(String.Format("{0} construct is not of type {1} and cannot be used with the {2} operator", construct.ToString(), typeof(T).Name, this.Token));
63 |
64 | return (T)construct;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Operators/OrOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Logical Or operator.
29 | /// Usage: booleanValue OR booleanValue
30 | /// Example: true OR false
31 | ///
32 | public class OrOperator : Operator
33 | {
34 | public OrOperator()
35 | {
36 | }
37 |
38 | ///
39 | /// Non-zero arguments are considered true.
40 | ///
41 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
42 | {
43 | return base.GetTransformedConstruct(argument1) || base.GetTransformedConstruct(argument2);
44 | }
45 |
46 | public override string Token
47 | {
48 | get
49 | {
50 | return "OR";
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Operators/SubtractOperator.cs:
--------------------------------------------------------------------------------
1 | /* _________________________________________________
2 |
3 | (c) Hi-Integrity Systems 2012. All rights reserved.
4 | www.hisystems.com.au - Toby Wicks
5 | github.com/hisystems/Interpreter
6 |
7 | Licensed under the Apache License, Version 2.0 (the "License");
8 | you may not use this file except in compliance with the License.
9 | You may obtain a copy of the License at
10 |
11 | http://www.apache.org/licenses/LICENSE-2.0
12 |
13 | Unless required by applicable law or agreed to in writing, software
14 | distributed under the License is distributed on an "AS IS" BASIS,
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | See the License for the specific language governing permissions and
17 | limitations under the License.
18 | ___________________________________________________ */
19 |
20 | using System;
21 | using System.Collections.Generic;
22 | using System.Linq;
23 | using System.Text;
24 |
25 | namespace HiSystems.Interpreter
26 | {
27 | ///
28 | /// Subtracts one numeric value from another or the number of days from a datetime value, or the difference between two dates.
29 | /// Usage:
30 | /// numericValue - numericValue
31 | /// dateTime - numericDays
32 | /// dateTime - dateTime
33 | /// Examples:
34 | /// 1 - 2
35 | /// #2000-01-01# - 1
36 | /// #2000-01-02# - #2000-01-01#
37 | ///
38 | public class SubtractOperator : Operator
39 | {
40 | public SubtractOperator()
41 | {
42 | }
43 |
44 | internal override Literal Execute(IConstruct argument1, IConstruct argument2)
45 | {
46 | var argument1Transformed = base.GetTransformedConstruct(argument1);
47 | var argument2Transformed = base.GetTransformedConstruct(argument2);
48 |
49 | if (argument1Transformed is Number && argument2Transformed is Number)
50 | return ((Number)argument1Transformed) - ((Number)argument2Transformed);
51 | else if (argument1Transformed is DateTime && argument2Transformed is Number)
52 | return ((DateTime)argument1Transformed) - ((Number)argument2Transformed);
53 | else if (argument1Transformed is DateTime && argument2Transformed is DateTime)
54 | return (((DateTime)argument1Transformed) - ((DateTime)argument2Transformed));
55 | else
56 | throw new InvalidOperationException(String.Format("Subtract operator requires arguments of type Number or DateTime. Argument types are {0} {1}.", argument1Transformed.GetType().Name, argument2Transformed.GetType().Name));
57 | }
58 |
59 | public override string Token
60 | {
61 | get
62 | {
63 | return "-";
64 | }
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | Interpreter
2 | ===========
3 |
4 | Overview
5 | --------
6 | The Interpreter is an expression interpreter written in pure C#. It parses any mathematical or logical expression and returns a result. The return result depends on the return type of the last function / operation. An expression can contain variables that can be supplied before the expression is executed and the result returned.
7 |
8 | Video Tutorial
9 | --------------
10 | The video overview and tutorial is available here: http://youtu.be/D9UGHPQpKP4
11 |
12 | ### Examples:
13 | 1. Passing a variable to the expression. The example below parses the expression and creates the expression tree via Engine.Parse(). The variables are then supplied to the expression and the expression executed via Execute().
14 | ```csharp
15 | var expression = new Engine().Parse("SUM(A) * 2 - B");
16 | expression.Variables["A"].Value = new Array(new decimal[] { 1, 2, 3, 4 });
17 | expression.Variables["B"].Value = new Number(10);
18 | decimal result = expression.Execute();
19 | ```
20 |
21 | 2. Using an IF function:
22 | ```csharp
23 | decimal result = new Engine().Parse("IF(1 < 2, 10, 20)").Execute();
24 | ```
25 |
26 | 3. Custom functions can provide support for accessing data from a database:
27 | ```csharp
28 | class GetMyDataFunction : Function
29 | {
30 | public override string Name
31 | {
32 | get
33 | {
34 | return "GETMYDATA";
35 | }
36 | }
37 |
38 | public override Literal Execute(IConstruct[] arguments)
39 | {
40 | base.EnsureArgumentCountIs(arguments, 2);
41 |
42 | var tableName = base.GetTransformedArgument(arguments, 0);
43 | var fieldName = base.GetTransformedArgument(arguments, 1);
44 |
45 | // Retrieve data using tableName and fieldName and return Array.
46 | // This return value can then be used by any functions that accept Array as an argument such as SUM().
47 | // return new Array(new decimal[] { 1, 2, 3, 4 });
48 | }
49 | }
50 |
51 | var engine = new Engine();
52 | engine.Register(new GetMyDataFunction());
53 | decimal result = Engine.Parse("SUM(GETMYDATA('MyTable', 'MyField'))").Execute();
54 | ```
55 |
56 | 4. Custom functions that manipulate values:
57 | ```csharp
58 | class NegateNumber : Function
59 | {
60 | public override string Name
61 | {
62 | get
63 | {
64 | return "NEGATE";
65 | }
66 | }
67 |
68 | public override Literal Execute(IConstruct[] arguments)
69 | {
70 | base.EnsureArgumentCountIs(arguments, 1);
71 |
72 | decimal inputValue = base.GetTransformedArgument(arguments, argumentIndex: 0);
73 |
74 | return new Number(-inputValue);
75 | }
76 | }
77 |
78 | var engine = new Engine();
79 | engine.Register(new NegateNumber());
80 | decimal result = Engine.Parse("NEGATE(1)").Execute();
81 | ```
82 |
83 | 5. Working with numbers:
84 | ```csharp
85 | var expression = new Engine().Parse("Sum(Array(1, 2, 3, 4, 5)) / 2");
86 | decimal result = expression.Execute();
87 | ```
88 |
89 | 6. Working with text:
90 | ```csharp
91 | var expression = new Engine().Parse("'$ ' + Format(Amount, '0.00')");
92 | expression.Variables["Amount"].Value = (Number)1;
93 | string result = expression.Execute();
94 | ```
95 |
96 | 7. Working with dates:
97 | ```csharp
98 | var expression = new Engine().Parse("Today() > #2000-1-1#");
99 | bool result = expression.Execute();
100 | ```
101 |
102 | 8. Working with logical operators and parentheses:
103 | ```csharp
104 | var expression = new Engine().Parse("1 < 2 AND (2 > 3 OR 3 < 4)");
105 | bool result = expression.Execute();
106 | ```
107 |
108 | 9. Executing multiple expressions:
109 | ```csharp
110 | var engine = new Engine();
111 |
112 | var expression1 = engine.Parse("A + 2");
113 | expression1.Variables["A"].Value = (Number)1;
114 |
115 | var expression2 = engine.Parse("Expression1 + 3");
116 | expression2.Variables["Expression1"].Value = expression1;
117 |
118 | decimal result = expression2.Execute();
119 | ```
120 |
121 | ### Supported Functions
122 | * SUM(array)
123 | * AVG(array)
124 | * IF(condition, trueResult, falseResult)
125 | * Array(item1, item2, ...)
126 | * Format(value [, format]) -- Formats a number or date/time
127 | * Len(text) -- returns the length of a string
128 | * Custom functions can be created by extending Function and registered it via `Engine.Register(Function)`
129 |
130 | ### Supported data types (can be extended)
131 | * Number/decimal
132 | - Example: 1.0
133 | * Boolean
134 | - Supports constants 'true' and 'false'
135 | - Example: true <> false
136 | * Array
137 | - Can contain all data types
138 | - Data types can be mixed in the same array
139 | - Example: Array(1, 2, 3, 4)
140 | * Text
141 | - Delimited by " or ' characters
142 | - Exampe: 'ABC'
143 | * Date/Time
144 | - Surrounded by '#' characters
145 | - Example: #2000-01-30 12:30:03#
146 |
147 | ### Supported functions (can be extended)
148 | * If(condition, trueResult, falseResult)
149 | - Example: If(1 > 2, 10, 20)
150 | * Max(array)
151 | - Example: Max(Array(1, 2, 3))
152 | * Min(array)
153 | - Example: Min(Array(1, 2, 3))
154 | * Sum(array):
155 | - Example: Sum(Array(1, 2, 3))
156 | * Today:
157 | - Returns the date component (no time component) for today.
158 | - Example: Today() + 1 -- returns the date for tomorrow
159 | * Len(text)
160 | - Returns the length of a string
161 | - Example: Len('abc') -- returns 3
162 |
163 | ### Supported Operations (can be extended)
164 | * + - addition (numbers, date/time + number, string concatenation)
165 | * - - subtraction (numbers, date/time - number)
166 | * / - divide
167 | * * - multiply
168 | * = - equal
169 | * <> - not equal to
170 | * < - less than
171 | * > - greater than
172 | * >= - greater than or equal to
173 | * <= - less than or equal to
174 | * OR - logical or
175 | * AND - logical and
176 |
177 | Supported Platforms
178 | -------------------
179 | Supported platforms are Windows and MonoTouch/Mono.
180 |
181 | License
182 | -------
183 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
184 |
185 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
186 |
187 | Unit Tests
188 | ----------
189 | The unit test project is available in a separate repository on [Github here](https://github.com/hisystems/Interpreter-UnitTests). It is also a good resource for examples on how to utilise the library. To run the unit tests project in conjunction with the library it must be located in the same directory as the library.
190 |
191 | For example:
192 |
193 | /Interpreter
194 | /Interpreter.UnitTests
195 |
--------------------------------------------------------------------------------