private void OnSemanticsValidate(object sender, SemanticsValidateEventArgs e) { bool ignoreCase = AP.IgnoreCase; AleExpressionParser P = sender as AleExpressionParser; // We want for some reasons that "Rnd" can't be a variable name if ((e.Term.HashCode == -1028829980 && !ignoreCase && e.Term.Value.ToString() == "Rnd") || (e.Term.HashCode == 1843313028 && ignoreCase && e.Term.Value.ToString() == "RND")) { AleTerm parent = e.Term.Parent; if (e.Term.TypeOfTerm == AleTermType.Variable && (parent == null || parent.Operation == null || !parent.Operation.IsClassOperator || e.Term != parent[1])) { P.SetError(e.Term.Token.StartInOrigin, AleExpressionParser.ERROR_INVALIDVARIABLE); } } }
private void btnPerfomance_Click(object sender, EventArgs e) { List <AleToken> list; List <AleTerm> Terms = new List <AleTerm>(); AleTerm T = null; /* * lblInfo.Text = ""; * txtResult.Text = ""; * * AP.Options = (AP.IgnoreCase ? AleSimpleLexer.OPTION_IGNORECASE : 0) + * AleExpressionParser.OPTION_ALLOWEMPTYLISTMEMBER + * (chkStrictSyntax.Checked ? AleExpressionParser.OPTION_STRICTSYNTAX : 0) + * AleExpressionParser.OPTION_ALLOWEMPTYPARAMS + * AleExpressionParser.OPTION_ALLOWEMPTYINDEX + * AleExpressionParser.OPTION_ALLOWMULTIDIMINDEXES + * AleExpressionParser.OPTION_STRICTINDEXES; * * AP.Text = expr_; * AP.VarPrefix = cboPrefix.Text == "" ? '\0' : cboPrefix.Text[0]; * AP.EndOfExpression = "; 'end of expression' 'stoṕ herẽ'"; */ AP.Constants = new Dictionary <string, object>(AP.IgnoreCase ? StringComparer.CurrentCultureIgnoreCase : StringComparer.CurrentCulture); AP.Constants.Add("true", true); AP.Constants.Add("false", false); AP.Constants.Add("pi", Math.PI); AP.Constants.Add("π", Math.PI); //AP.Constants.Add("2pi", 2 * Math.PI); //AP.Constants.Add("2π", 2 * Math.PI); AP.Constants.Add("e", Math.E); AP.Constants.Add("null", null); AP.SemanticsValidate += OnSemanticsValidate; int res = 0; while (res < AP.Text.Length) { res = AP.Tokenize(out list, res); if (AP.ErrorCode == AleExpressionParser.ERROR_OK) { T = AP.Parse(list); } if (AP.ErrorCode != AleExpressionParser.ERROR_OK) { ShowError(AP); return; } if (T != null) { Terms.Add(T); } } if (Terms.Count == 0) { return; } //btnParse.Enabled = false; //btnEval.Enabled = false; //btnPerfomance.Enabled = false; string S; AleTermResult val = new AleTermResult(); DateTime t1 = DateTime.Now; int N = 1000000; for (int i = N; i > 0 && val.ErrorCode == AleTermResult.ERROR_OK; i--) { if (i % 10000 == 0) { //lblInfo.Text = i.ToString(); Application.DoEvents(); } foreach (AleTerm t in Terms) { t.Evaluate(out val, OnEvaluate, OnAssign); if (val.ErrorCode != AleTermResult.ERROR_OK) { break; } } } DateTime t2 = DateTime.Now; if (val.ErrorCode == AleTermResult.ERROR_OK) { TimeSpan dt = t2.Subtract(t1); S = "Evaluation speed: " + (N / dt.TotalSeconds).ToString() + " expressions per second"; //txtResult.Text = S; } //else txtResult.Text = "Error \"" + val.ErrorMessage() + "\" in line:" + AP.ErrorPosToLine(val.ErrorPos).ToString() + " col:" + AP.ErrorPosToCol(val.ErrorPos).ToString() + "\u000d\u000a"; //btnParse.Enabled = true; //btnEval.Enabled = true; //btnPerfomance.Enabled = true; }
public double Evaluate(string expr) { List <AleToken> list; AleTerm T = null; //lblInfo.Text = ""; AP.Options = (AP.IgnoreCase ? AleExpressionParser.OPTION_IGNORECASE : 0) + AleExpressionParser.OPTION_ALLOWEMPTYLISTMEMBER + (/*chkStrictSyntax.Checked ?*/ AleExpressionParser.OPTION_STRICTSYNTAX /*: 0*/) + AleExpressionParser.OPTION_ALLOWEMPTYPARAMS + AleExpressionParser.OPTION_ALLOWEMPTYINDEX + AleExpressionParser.OPTION_ALLOWMULTIDIMINDEXES + AleExpressionParser.OPTION_STRICTINDEXES; AP.Text = expr; AP.VarPrefix = /*cboPrefix.Text == "" ?*/ '\0' /*: cboPrefix.Text[0]*/; AP.EndOfExpression = "; 'end of expression' 'stoṕ herẽ'"; AP.Constants = new Dictionary <string, object>(AP.IgnoreCase ? StringComparer.CurrentCultureIgnoreCase : StringComparer.CurrentCulture); AP.Constants.Add("true", true); AP.Constants.Add("false", false); AP.Constants.Add("pi", Math.PI); AP.Constants.Add("π", Math.PI); //AP.Constants.Add("2pi", 2 * Math.PI); //AP.Constants.Add("2π", 2 * Math.PI); AP.Constants.Add("e", Math.E); AP.Constants.Add("null", null); AP.SemanticsValidate += OnSemanticsValidate; int res = 0; AleTermResult val; while (res < AP.Text.Length) { res = AP.Tokenize(out list, res); if (AP.ErrorCode == AleExpressionParser.ERROR_OK) { T = AP.Parse(list); } if (AP.ErrorCode != AleExpressionParser.ERROR_OK) { // invalid expression ShowError(AP); } if (T != null) { if (!T.Evaluate(out val, OnEvaluate, OnAssign)) { // undefined value throw new Exception("undefined"); //string err = "Error \"" + val.ErrorMessage() + "\" in line:" + AP.ErrorPosToLine(val.ErrorPos).ToString() + " col:" + AP.ErrorPosToCol(val.ErrorPos).ToString() + "\u000d\u000a"; //txtExpression.SelectionStart = val.ErrorPos; //txtExpression.SelectionLength = 1; //txtExpression.Focus(); } //else if (val.Value != null) txtResult.Text += val.Value.ToString() + " : expression result type = " + val.Value.GetType().ToString() + "\u000d\u000a"; //else txtResult.Text += "<null>\u000d\u000a"; //TypeCode vType = Type.GetTypeCode(val.Value.GetType()); //if (vType == TypeCode.Boolean) // continue; if (res == AP.Text.Length) // end of expression reached { return(Convert.ToDouble(val.Value.ToString())); } } } return(0); }
private void InitMyOperations() { AP.AddOperation(new AleOperation(AP.IgnoreCase ? "ITEM" : "Item") { /* 'Parameters' property describes arguments of operation (function). * Number of Tuples in list defines number of arguments of function. * Each Tuple describes each argument of function. * First item of Tuple describes type of argument for "run-time" checking. * TypeCode.Object value of this item means that any object can be passed as argument and it is concern of 'Evaluator' delegate to check type of passed object and correctly use it. * Second item defines default value for argument. When it is null - argument is required. * When it is not null - argument is not required and second item is a default value passed instead. */ Parameters = new List <Tuple <TypeCode, object> >() { new Tuple <TypeCode, object>(TypeCode.Int32, null) }, /* 'ObjectTypeCode' defines if operation (function) is a class method. * Default value for 'ObjectTypeCode' set by constructor is TypeCode.Empty. It means that function is not a class method. * 'ObjectTypeCode' is used by parser to correctly select operation and during evaluation for "run-time" checking of class instance passed to delegate in 'parameters' argument. * 'ObjectTypeCode' can be TypeCode.Object. It means that class instance of any type can be passed to delegate. */ InstanceTypeCode = TypeCode.Object, /* delegate which is called to evaluate operation. * 'term' is a element of a parsed expression tree. * 'parameters' is a structure with operation arguments. When number of arguments is 3 or less, they are passed in 'FirstParam', 'SecondParam' and 'ThirdParam' fields. * When number of arguments is 4 or more, they are passed in 'Parameters' field (List<object>) * Store result of evaluation or information about error in 'result' structure */ Evaluator = delegate(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result) { Dictionary <string, ChemicalElement> elements = parameters.ClassInstance as Dictionary <string, ChemicalElement>; if (elements != null) { int i = 0; int k = Convert.ToInt32(parameters.FirstParam); foreach (KeyValuePair <string, ChemicalElement> element in elements) { if (i == k) { result.Value = element.Value; return(true); } i++; } result.SetError(AleTermResult.ERROR_KEYNOTFOUND, term.Token.StartInOrigin); } else { result.SetError(AleTermResult.ERROR_UNKNOWNMETHOD, term.Token.StartInOrigin); } return(false); } }); AP.AddOperation(new AleOperation(AP.IgnoreCase ? "RAND" : "Rand") { Parameters = new List <Tuple <TypeCode, object> >() { new Tuple <TypeCode, object>(TypeCode.Double, Double.MinValue), new Tuple <TypeCode, object>(TypeCode.Double, Double.MaxValue) }, Evaluator = delegate(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result) { //if (parameters.ActualParamsCount == 1) result.Value = rnd.Next(Convert.ToInt32(parameters.FirstParam)); //else if (parameters.ActualParamsCount == 2) result.Value = rnd.Next(Convert.ToInt32(parameters.FirstParam), Convert.ToInt32(parameters.SecondParam)); //else result.Value = rnd.Next(); if (parameters.ActualParamsCount == 1) { result.Value = Convert.ToDouble(parameters.FirstParam) * rnd.NextDouble(); } else if (parameters.ActualParamsCount == 2) { double a = Convert.ToDouble(parameters.FirstParam); double b = Convert.ToDouble(parameters.SecondParam); result.Value = (a - b) * rnd.NextDouble() + b; } else { result.Value = rnd.NextDouble(); } return(true); } }); AP.AddOperation(new AleOperation(AP.IgnoreCase ? "IIF" : "Iif") { Parameters = new List <Tuple <TypeCode, object> >() { new Tuple <TypeCode, object>(TypeCode.Boolean, null), new Tuple <TypeCode, object>(TypeCode.Object, null), new Tuple <TypeCode, object>(TypeCode.Object, null) }, Evaluator = delegate(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result) { if ((bool)parameters.FirstParam) { result.Value = parameters.SecondParam; } else { result.Value = parameters.ThirdParam; } return(true); } }); // the "↑" power operator. x↑y means Math.Pow(x,y), x↑ means Math.Pow(x,2) // this overloaded constructor creates operator (not function) description. First argument is a operator literal, second is a precedence of operator, third is an associativity AP.AddOperation(new AleOperation("↑", 2000, AleOperation.OPERATOR_YFX + AleOperation.OPERATOR_YF) { // there is no need to initialize Parameters field for operators. It is not used for operators evaluation. Only for functions. Evaluator = delegate(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result) { AleTerm t1 = term[0]; AleTermResult a; if (!t1.Evaluate(out a, OnEvaluate, OnAssign) && result.SetError(a.ErrorCode, a.ErrorPos)) { return(false); } AleTermResult b = new AleTermResult(); if (term.Count == 2) { AleTerm t2 = term[1]; if (!t2.Evaluate(out b, OnEvaluate, OnAssign) && result.SetError(b.ErrorCode, b.ErrorPos)) { return(false); } } else { b.Value = 2.0; } TypeCode optype = AleTerm.OperationType(a.Value, b.Value); switch (optype) { case TypeCode.Double: case TypeCode.Decimal: case TypeCode.UInt64: case TypeCode.Int64: case TypeCode.UInt32: case TypeCode.Int32: result.Value = Math.Pow(Convert.ToDouble(a.Value), Convert.ToDouble(b.Value)); return(true); default: result.SetError(AleTermResult.ERROR_INCOMPATIBLETYPES, term.Token.StartInOrigin); return(false); } } }); //// "❗" factorial operator (\u2757 char). //AP.AddOperation(new AleOperation("❗", 1800, AleOperation.OPERATOR_YF) // "!" factorial operator AP.AddOperation(new AleOperation("!", 1800, AleOperation.OPERATOR_YF) { Evaluator = delegate(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result) { AleTerm t1 = term[0]; AleTermResult a; if (!t1.Evaluate(out a, OnEvaluate, OnAssign) && result.SetError(a.ErrorCode, a.ErrorPos)) { return(false); } // check if integer value //if (!AleTerm.ValidForOperationType(a.Value, TypeCode.Int32) && result.SetError(AleTermResult.ERROR_INCOMPATIBLETYPES, term.Token.StartInOrigin)) return false; double nDouble = Convert.ToDouble(a.Value); if (nDouble != Math.Floor(nDouble)) { result.SetError(AleTermResult.ERROR_INCOMPATIBLETYPES, term.Token.StartInOrigin); return(false); } // check if allowed value int n = Convert.ToInt32(a.Value); if (n < 1 && result.SetError(AleTermResult.ERROR_EVALUATION, term.Token.StartInOrigin)) { return(false); } double fac_n = 1; while (n > 1) { fac_n *= n; n--; } result.Value = fac_n; return(true); } }); // disabled: not functional //// "²" square operator //AP.AddOperation(new AleOperation("²", 1800, AleOperation.OPERATOR_YF) //{ // Evaluator = delegate(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result) // { // AleTerm t1 = term[0]; // AleTermResult a; // if (!t1.Evaluate(out a, OnEvaluate, OnAssign) && result.SetError(a.ErrorCode, a.ErrorPos)) return false; // TypeCode optype = AleTerm.OperationType(a.Value, null); // switch (optype) // { // case TypeCode.Double: // result.Value = Math.Pow(Convert.ToDouble(a.Value), 2); // return true; // case TypeCode.Decimal: // result.Value = Convert.ToDecimal(Math.Pow(Convert.ToDouble(a.Value), 2)); // return true; // case TypeCode.UInt64: // result.Value = Convert.ToUInt64(Math.Pow(Convert.ToUInt64(a.Value), 2)); // return true; // case TypeCode.Int64: // result.Value = Convert.ToInt64(Math.Pow(Convert.ToInt64(a.Value), 2)); // return true; // case TypeCode.UInt32: // result.Value = Convert.ToUInt32(Math.Pow(Convert.ToUInt32(a.Value), 2)); // return true; // case TypeCode.Int32: // result.Value = Convert.ToInt32(Math.Pow(Convert.ToInt32(a.Value), 2)); // return true; // default: // result.SetError(AleTermResult.ERROR_INCOMPATIBLETYPES, term.Token.StartInOrigin); // return false; // } // } //}); AP.AddOperation(new AleOperation(AP.IgnoreCase ? "REVERSE" : "Reverse") { // Parameters = null - method has no parameters InstanceTypeCode = TypeCode.String, Evaluator = delegate(AleTerm term, ref OperationEvalParameters parameters, ref AleTermResult result) { StringBuilder s = new StringBuilder(parameters.ClassInstance.ToString()); int n = s.Length; int m = (n--) / 2; char c; for (int i = 0; i < m; i++) { c = s[i]; s[i] = s[n - i]; s[n - i] = c; } result.Value = s; return(true); } }); }
// assignment private void OnAssign(AleTerm term, AleTermAssignArgs e) { bool ignoreCase = AP.IgnoreCase; /* VARIABLES * e.Instance is null. * e.Name - name of variable (in uppercase when we ignore case) * e.NameHash - hash of e.Name (obtained by GetHashCode()) * e.Indexes is null * e.Value - value that we assign */ if (e.Instance == null) { // variables X and Money if (e.NameHash == -842352648 && e.Name == "X") { X = Convert.ToDouble(e.Value); } else if ((e.NameHash == 1602047654 && !ignoreCase && e.Name == "Money") || (e.NameHash == 2068757350 && ignoreCase && e.Name == "MONEY")) { Money = Convert.ToDecimal(e.Value); } else { Variables[e.Name] = e.Value; // variables stored in Variables collection } return; } /* MEMBERS OF CLASSES (class operator '.') * e.Instance - instance of class. * e.Name - name of class property (in uppercase when we ignore case) * e.NameHash - hash of e.Name (obtained by GetHashCode()) * e.Indexes is null * e.Value - value that we assign */ if (!String.IsNullOrEmpty(e.Name)) { if (e.Instance is ChemicalElement) { ChemicalElement element = e.Instance as ChemicalElement; if ((e.NameHash == 1644092087 && !ignoreCase && e.Name == "Symbol") || (e.NameHash == 2104510327 && ignoreCase && e.Name == "SYMBOL")) { element.Symbol = e.Value.ToString(); } else if ((e.NameHash == 452724692 && !ignoreCase && e.Name == "Weight") || (e.NameHash == 917337236 && ignoreCase && e.Name == "WEIGHT")) { element.Weight = Convert.ToDouble(e.Value); } else if ((e.NameHash == 62725275 && !ignoreCase && e.Name == "Name") || (e.NameHash == 462326075 && ignoreCase && e.Name == "NAME")) { element.Name = e.Value.ToString(); } else if ((e.NameHash == 1405338047 && !ignoreCase && e.Name == "ElectronConfig") || (e.NameHash == -641811116 && ignoreCase && e.Name == "ELECTRONCONFIG")) { element.ElectronConfig = e.Value.ToString(); } else { e.SetError(AleTermResult.ERROR_UNKNOWNPROPERTY, term.Token.StartInOrigin); } return; } // elements of dictionary <string, object> (json-like object constant assigned to some variable before) if (e.Instance is Dictionary <string, object> ) { Dictionary <string, object> dict = e.Instance as Dictionary <string, object>; dict[e.Name] = e.Value; // this may add new properties to object return; } e.SetError(AleTermResult.ERROR_UNKNOWNELEMENT, term.Token.StartInOrigin); return; } /* ELEMENTS OF ARRAYS AND COLLECTIONS (index operator) * e.Instance - instance of array or collection. * e.Name == "" * e.NameHash == 0 * e.Indexes - list<object> with indexes or keys * e.Value - value that we assign */ Type typ = e.Instance.GetType(); // elements of dictionary <string, ChemicalElement> (Variables["Elements"] member) if (e.Instance is Dictionary <string, ChemicalElement> ) { if (e.Indexes.Count != 1 && e.SetError(AleTermResult.ERROR_INVALIDKEYS, term.Token.StartInOrigin)) { return; } Dictionary <string, ChemicalElement> elements = e.Instance as Dictionary <string, ChemicalElement>; elements[e.Indexes[0].ToString()] = e.Value as ChemicalElement; return; } // elements of array constant (initialization list) assigned to some variable before if (e.Instance is Dictionary <object, object> ) { Dictionary <object, object> list = e.Instance as Dictionary <object, object>; if (e.Indexes.Count == 1) { // set value to some element of array if (AleTerm.ValidForOperationType(e.Indexes[0], TypeCode.Int32)) { list[Convert.ToInt32(e.Indexes[0])] = e.Value; } else { list[e.Indexes[0]] = e.Value; } } else if (e.Indexes.Count == 0 && (term.Parser.Options & AleExpressionParser.OPTION_ALLOWEMPTYINDEX) != 0) { // add new element to array (MyArray[] = newValue) int MaxKey = Int32.MinValue; foreach (KeyValuePair <object, object> kv in list) { if (kv.Key is Int32 && (int)kv.Key > MaxKey) { MaxKey = (int)kv.Key; } } if (MaxKey < Int32.MaxValue) { list[MaxKey + 1] = e.Value; } else { e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin); } } else { e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin); } return; } // elements of int[,] (Matrix1, Matrix2) if (typ.IsArray && typ.FullName == "System.Int32[,]") { if (e.Indexes.Count != 2 && e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin)) { return; } if (!AleTerm.ValidForOperationType(e.Value, TypeCode.Int32) && e.SetError(AleTermResult.ERROR_INCOMPATIBLETYPES, term.Token.StartInOrigin)) { return; } int[,] Matrix = e.Instance as int[, ]; try { Matrix[Convert.ToInt32(e.Indexes[0]), Convert.ToInt32(e.Indexes[1])] = Convert.ToInt32(e.Value); } catch { e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin); } return; } e.SetError(AleTermResult.ERROR_UNKNOWNELEMENT, term.Token.StartInOrigin); }
// evaluation private void OnEvaluate(AleTerm term, AleTermEvaluateArgs e) { bool ignoreCase = AP.IgnoreCase; object res; /* VARIABLES * e.Instance is null * e.Name - name of variable (in uppercase when we ignore case) * e.NameHash - hash of e.Name (obtained by GetHashCode()) * e.Indexes is null when we evaluate variable * e.Result - stores value of variable */ if (e.Instance == null) { // variables stored in X and Money if (e.NameHash == -842352648 && e.Name == "X") { e.Result = X; } else if ((e.NameHash == 1602047654 && !ignoreCase && e.Name == "Money") || (e.NameHash == 2068757350 && ignoreCase && e.Name == "MONEY")) { e.Result = Money; } else { // variables stored in Variables collection if (Variables.TryGetValue(e.Name, out res)) { e.Result = res; } else { res = (int)0; Variables.Add(e.Name, res); e.Result = res; } } return; } /* MEMBERS OF CLASSES (class operator '.') * e.Instance - instance of class. * e.Name - name of class property (in uppercase when we ignore case) * e.NameHash - hash of e.Name (obtained by GetHashCode()) * e.Indexes is null when we evaluate class property * e.Result - stores value of property or result of method */ if (!String.IsNullOrEmpty(e.Name)) { if (e.Instance is Dictionary <string, ChemicalElement> ) // Count of ChemicalElements in collection (and other properties here) { Dictionary <string, ChemicalElement> elements = e.Instance as Dictionary <string, ChemicalElement>; if ((e.NameHash == 2002596872 && !ignoreCase && e.Name == "Count") || (e.NameHash == -1825660792 && ignoreCase && e.Name == "COUNT")) { e.Result = elements.Count; } else { e.SetError(AleTermResult.ERROR_UNKNOWNPROPERTY, term.Token.StartInOrigin); } } else if (e.Instance is ChemicalElement) // ChemicalElement properties { ChemicalElement element = e.Instance as ChemicalElement; if ((e.NameHash == 1644092087 && !ignoreCase && e.Name == "Symbol") || (e.NameHash == 2104510327 && ignoreCase && e.Name == "SYMBOL")) { e.Result = element.Symbol; } else if ((e.NameHash == 452724692 && !ignoreCase && e.Name == "Weight") || (e.NameHash == 917337236 && ignoreCase && e.Name == "WEIGHT")) { e.Result = element.Weight; } else if ((e.NameHash == 62725275 && !ignoreCase && e.Name == "Name") || (e.NameHash == 462326075 && ignoreCase && e.Name == "NAME")) { e.Result = element.Name; } else if ((e.NameHash == 1405338047 && !ignoreCase && e.Name == "ElectronConfig") || (e.NameHash == -641811116 && ignoreCase && e.Name == "ELECTRONCONFIG")) { e.Result = element.ElectronConfig; } else { e.SetError(AleTermResult.ERROR_UNKNOWNPROPERTY, term.Token.StartInOrigin); } } return; } /* ELEMENTS OF ARRAYS AND COLLECTIONS (index operator) * e.Instance - instance of array or collection. * e.Name == "" * e.NameHash == 0 * e.Indexes is List<object> with indexes of array or keys of collection * e.Result - stores value of member */ // elements of dictionary <string, ChemicalElement> if (e.Instance is Dictionary <string, ChemicalElement> ) { if (e.Indexes.Count != 1 && e.SetError(AleTermResult.ERROR_INVALIDKEYS, term.Token.StartInOrigin)) { return; } Dictionary <string, ChemicalElement> elements = e.Instance as Dictionary <string, ChemicalElement>; ChemicalElement elem; if (elements.TryGetValue(e.Indexes[0].ToString(), out elem)) { e.Result = elem; } else { e.SetError(AleTermResult.ERROR_KEYNOTFOUND, term.Token.StartInOrigin); } return; } Type typ = e.Instance.GetType(); // elements of int[,] (matrix1, matrix2) if (typ.IsArray && typ.FullName == "System.Int32[,]") { if (e.Indexes.Count != 2 && e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin)) { return; } int[,] Matrix = e.Instance as int[, ]; try { e.Result = Matrix[Convert.ToInt32(e.Indexes[0]), Convert.ToInt32(e.Indexes[1])]; } catch { e.SetError(AleTermResult.ERROR_INVALIDINDEXES, term.Token.StartInOrigin); } return; } }