4using System.Globalization;
6using System.Reflection;
8using System.Threading.Tasks;
42 private readonly
static object searchSynch =
new object();
43 private static Dictionary<Type, Dictionary<Type, ITypeConverter>> converters =
null;
44 private static Dictionary<string, FunctionRef> functions =
null;
45 private static Dictionary<string, IConstant> constants =
null;
46 private static Dictionary<string, IKeyWord> customKeyWords =
null;
47 private static readonly Dictionary<Type, ICustomStringOutput> output =
new Dictionary<Type, ICustomStringOutput>();
48 internal static readonly Dictionary<string, bool> keywords = GetKeywords();
51 private readonly
string script;
52 private readonly
string source;
55 private readonly
int len;
56 private bool containsImplicitPrint =
false;
57 private bool canSkipWhitespace =
true;
102 this.len = this.script.Length;
104 this.root = this.ParseSequence();
105 if (this.pos < this.len)
106 throw new SyntaxException(
"Unexpected end of script.", this.pos, this.script);
111 Types.OnInvalidated += Types_OnInvalidated;
114 private static void Types_OnInvalidated(
object Sender, EventArgs e)
125 private static Dictionary<string, bool> GetKeywords()
127 Dictionary<string, bool> Result =
new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase)
131 {
"CARTESIAN",
true },
143 {
"INHERITS",
true },
144 {
"INTERSECT",
true },
145 {
"INTERSECTION",
true },
168 if (customKeyWords is
null)
171 foreach (
IKeyWord KeyWord
in customKeyWords.Values)
173 Result[KeyWord.
KeyWord.ToUpper()] =
true;
175 string[] Aliases = KeyWord.
Aliases;
176 if (!(Aliases is
null))
178 foreach (
string s
in Aliases)
179 Result[s.ToUpper()] =
true;
183 if (!(Aliases is
null))
185 foreach (
string s
in Aliases)
186 Result[s.ToUpper()] =
true;
193 internal int Position => this.pos;
195 internal bool EndOfScript => this.pos >= this.len;
196 internal bool InScript => this.pos < this.len;
198 internal bool CanSkipWhitespace
200 get => this.canSkipWhitespace;
201 set => this.canSkipWhitespace = value;
214 internal char NextChar()
216 if (this.pos < this.len)
217 return this.script[this.pos++];
222 internal void UndoChar()
228 internal char PeekNextChar()
230 if (this.pos < this.len)
231 return this.script[this.pos];
236 internal string PeekNextChars(
int NrChars)
238 if (this.pos + NrChars > this.len)
239 NrChars = this.len - this.pos;
244 return this.script.Substring(this.pos, NrChars);
247 internal bool IsNextChars(
string Token)
249 int c = Token.Length;
253 if (this.pos + c > this.len)
258 for (i = 0; i < c; i++)
260 if (this.script[this.pos + i] != Token[i])
267 internal bool IsNextChars(
char ch,
int Count)
272 if (this.pos + Count > this.len)
277 for (i = 0; i < Count; i++)
279 if (this.script[this.pos + i] != ch)
286 internal void SkipChars(
int NrChars)
291 internal string NextToken()
293 this.SkipWhiteSpace();
295 if (this.pos >= this.len)
298 int Start = this.pos;
299 char ch = this.script[this.pos];
301 if (
char.IsLetter(ch))
303 while (this.pos < this.len &&
char.IsLetterOrDigit(this.script[this.pos]))
306 else if (
char.IsDigit(ch))
308 while (this.pos < this.len &&
char.IsDigit(this.script[this.pos]))
311 else if (
char.IsSymbol(ch))
313 while (this.pos < this.len &&
char.IsSymbol(this.script[this.pos]))
319 return this.script.Substring(Start, this.pos - Start);
322 internal string PeekNextToken()
325 string Token = this.NextToken();
331 internal void SkipWhiteSpace()
333 if (this.canSkipWhitespace)
337 while (this.pos < this.len)
339 ch = this.script[this.pos];
341 if (ch <=
' ' || ch == 160)
343 else if (ch ==
'/' &&
344 this.pos + 1 < this.len &&
345 ((ch2 = this.script[this.pos + 1]) ==
'/' || ch2 ==
'*'))
351 while (this.pos < this.len &&
352 (ch = this.script[this.pos]) !=
'\n' && ch !=
'\r')
359 while (this.pos < this.len &&
360 (this.script[this.pos] !=
'*' ||
361 this.pos + 1 == this.len ||
362 this.script[this.pos + 1] !=
'/'))
367 if (this.pos + 1 < this.len)
388 throw new SyntaxException(
"Right operand missing.", this.pos, this.script);
396 this.SkipWhiteSpace();
400 while (Node is
null && this.PeekNextChar() ==
';')
403 Node = this.ParseStatement(
true);
404 this.SkipWhiteSpace();
411 int Start = Node.
Start;
413 if (!(Node is
null) && this.PeekNextChar() ==
';')
417 if (!(Node2 is
null))
425 this.SkipWhiteSpace();
426 while (this.PeekNextChar() ==
';')
429 Node2 = this.ParseStatement(
true);
433 Statements.
Add(Node2);
434 this.SkipWhiteSpace();
437 Node =
new Sequence(Statements, Start, this.pos - Start,
this);
444 internal ScriptNode ParseStatement(
bool ParseLists)
446 this.SkipWhiteSpace();
448 int Start = this.pos;
450 switch (
char.ToUpper(this.PeekNextChar()))
453 if (
string.Compare(this.PeekNextToken(),
"DO",
true) == 0)
457 ScriptNode Statement = this.AssertOperandNotNull(this.ParseStatement(
false));
459 this.SkipWhiteSpace();
460 if (
string.Compare(this.PeekNextToken(),
"WHILE",
true) != 0)
465 ScriptNode Condition = this.AssertOperandNotNull(this.ParseIf());
467 return new DoWhile(Statement, Condition, Start, this.pos - Start,
this);
470 return ParseLists ? this.ParseList() : this.ParseIf();
473 if (
string.Compare(this.PeekNextToken(),
"WHILE",
true) == 0)
477 ScriptNode Condition = this.AssertOperandNotNull(this.ParseIf());
479 this.SkipWhiteSpace();
480 if (this.PeekNextChar() ==
':')
482 else if (
string.Compare(this.PeekNextToken(),
"DO",
true) == 0)
487 ScriptNode Statement = this.AssertOperandNotNull(this.ParseStatement(
false));
489 return new WhileDo(Condition, Statement, Start, this.pos - Start,
this);
492 return ParseLists ? this.ParseList() : this.ParseIf();
495 switch (this.PeekNextToken().ToUpper())
499 if (!(this.AssertOperandNotNull(this.ParseIf()) is
In In))
500 throw new SyntaxException(
"IN statement expected", this.pos, this.script);
505 this.SkipWhiteSpace();
506 if (this.PeekNextChar() ==
':')
508 else if (
string.Compare(this.PeekNextToken(),
"DO",
true) == 0)
513 ScriptNode Statement = this.AssertOperandNotNull(this.ParseStatement(
false));
519 this.SkipWhiteSpace();
521 if (
string.Compare(this.PeekNextToken(),
"EACH",
true) == 0)
524 In = this.AssertOperandNotNull(this.ParseIf()) as
In;
526 throw new
SyntaxException("IN statement expected", this.pos, this.script);
532 this.SkipWhiteSpace();
533 if (this.PeekNextChar() == ':')
535 else if (
string.Compare(this.PeekNextToken(), "DO", true) == 0)
540 Statement = this.AssertOperandNotNull(this.ParseStatement(false));
542 return new
ForEach(Ref.VariableName,
In.RightOperand, Statement, Start, this.pos - Start, this);
547 throw new SyntaxException(
"Assignment expected", this.pos, this.script);
549 this.SkipWhiteSpace();
550 if (
string.Compare(this.PeekNextToken(),
"TO",
true) != 0)
555 ScriptNode To = this.AssertOperandNotNull(this.ParseIf());
558 this.SkipWhiteSpace();
559 if (
string.Compare(this.PeekNextToken(),
"STEP",
true) == 0)
562 Step = this.AssertOperandNotNull(this.ParseIf());
567 this.SkipWhiteSpace();
568 if (this.PeekNextChar() ==
':')
570 else if (
string.Compare(this.PeekNextToken(),
"DO",
true) == 0)
575 Statement = this.AssertOperandNotNull(this.ParseStatement(
false));
581 return ParseLists ? this.ParseList() : this.ParseIf();
585 if (
string.Compare(this.PeekNextToken(),
"TRY",
true) == 0)
589 ScriptNode Statement = this.AssertOperandNotNull(this.ParseStatement(
false));
591 this.SkipWhiteSpace();
592 switch (this.PeekNextToken().ToUpper())
596 ScriptNode Finally = this.AssertOperandNotNull(this.ParseStatement(
false));
597 return new TryFinally(Statement, Finally, Start, this.pos - Start,
this);
601 ScriptNode Catch = this.AssertOperandNotNull(this.ParseStatement(
false));
603 this.SkipWhiteSpace();
604 if (
string.Compare(this.PeekNextToken(),
"FINALLY",
true) == 0)
607 Finally = this.AssertOperandNotNull(this.ParseStatement(
false));
608 return new TryCatchFinally(Statement, Catch, Finally, Start, this.pos - Start,
this);
611 return new TryCatch(Statement, Catch, Start, this.pos - Start,
this);
614 throw new SyntaxException(
"Expected CATCH or FINALLY.", this.pos, this.script);
618 return ParseLists ? this.ParseList() : this.ParseIf();
622 if (this.PeekNextChar() ==
']')
626 StringBuilder sb =
new StringBuilder();
629 while ((ch = this.NextChar()) !=
'[' || this.PeekNextChar() !=
'[')
638 this.containsImplicitPrint =
true;
639 return new ImplicitPrint(sb.ToString(), Start,
this.pos - Start,
this);
644 return ParseLists ? this.ParseList() : this.ParseIf();
648 return ParseLists ? this.ParseList() : this.ParseIf();
662 this.SkipWhiteSpace();
663 if (this.PeekNextChar() ==
',')
670 while (this.PeekNextChar() ==
',')
673 Node = this.ParseIf();
677 this.SkipWhiteSpace();
688 this.SkipWhiteSpace();
693 int Start = this.pos;
695 if (
char.ToUpper(this.PeekNextChar()) ==
'I' &&
string.Compare(this.PeekNextToken(),
"IF",
true) == 0)
698 this.SkipWhiteSpace();
700 Condition = this.AssertOperandNotNull(this.ParseAssignments());
702 this.SkipWhiteSpace();
703 if (
string.Compare(this.PeekNextToken(),
"THEN",
true) == 0)
708 IfTrue = this.AssertOperandNotNull(this.ParseStatement(
false));
710 this.SkipWhiteSpace();
711 if (
string.Compare(this.PeekNextToken(),
"ELSE",
true) == 0)
714 IfFalse = this.AssertOperandNotNull(this.ParseStatement(
false));
721 Condition = this.ParseAssignments();
722 if (Condition is
null)
725 this.SkipWhiteSpace();
726 if (this.PeekNextChar() !=
'?')
731 switch (this.PeekNextChar())
742 if (this.PeekNextChar() ==
'?')
745 IfTrue = this.AssertOperandNotNull(this.ParseStatement(
false));
746 return new TryCatch(Condition, IfTrue, Start, this.pos - Start,
this);
750 IfTrue = this.AssertOperandNotNull(this.ParseStatement(
false));
751 return new NullCheck(Condition, IfTrue, Start, this.pos - Start,
this);
755 IfTrue = this.AssertOperandNotNull(this.ParseStatement(
false));
757 this.SkipWhiteSpace();
758 if (this.PeekNextChar() ==
':')
761 IfFalse = this.AssertOperandNotNull(this.ParseStatement(
false));
770 return new If(Condition, IfTrue, IfFalse, Start, this.pos - Start,
this);
775 ScriptNode Left = this.ParseLambdaExpression();
779 int Start = Left.
Start;
782 this.SkipWhiteSpace();
784 switch (this.PeekNextChar())
788 if (this.PeekNextChar() ==
'=')
791 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
823 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
824 Argument.
Start,
this.script);
833 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
834 Argument.
Start,
this.script);
843 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
844 Argument.
Start,
this.script);
851 if (Def.Elements.Length != 1 || (Ref = Def.Elements[0] as
VariableReference) is
null)
853 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
854 Argument.
Start,
this.script);
863 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
864 Argument.
Start,
this.script);
877 return new PatternMatch(Left, Right, Start, this.pos - Start,
this);
887 if (this.PeekNextChar() ==
'=')
891 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
894 return new Operators.Assignments.WithSelf.AddToSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
906 throw new SyntaxException(
"Invalid use of the += operator.", this.pos, this.script);
916 if (this.PeekNextChar() ==
'=')
920 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
923 return new Operators.Assignments.WithSelf.SubtractFromSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
935 throw new SyntaxException(
"Invalid use of the -= operator.", this.pos, this.script);
946 if (this.PeekNextChar() ==
'=')
950 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
953 return new Operators.Assignments.WithSelf.MultiplyWithSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
965 throw new SyntaxException(
"Invalid use of the *= operator.", this.pos, this.script);
975 if (this.PeekNextChar() ==
'=')
979 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
982 return new Operators.Assignments.WithSelf.DivideFromSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
994 throw new SyntaxException(
"Invalid use of the /= operator.", this.pos, this.script);
1004 if (this.PeekNextChar() ==
'=')
1008 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1011 return new Operators.Assignments.WithSelf.PowerOfSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1023 throw new SyntaxException(
"Invalid use of the ^= operator.", this.pos, this.script);
1033 switch (this.PeekNextChar())
1038 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1041 return new Operators.Assignments.WithSelf.BinaryAndWithSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1053 throw new SyntaxException(
"Invalid use of the &= operator.", this.pos, this.script);
1057 if (this.PeekNextChar() ==
'=')
1061 Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1064 return new Operators.Assignments.WithSelf.LogicalAndWithSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1076 throw new SyntaxException(
"Invalid use of the &&= operator.", this.pos, this.script);
1091 switch (this.PeekNextChar())
1096 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1099 return new Operators.Assignments.WithSelf.BinaryOrWithSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1111 throw new SyntaxException(
"Invalid use of the |= operator.", this.pos, this.script);
1115 if (this.PeekNextChar() ==
'=')
1119 Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1122 return new Operators.Assignments.WithSelf.LogicalOrWithSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1134 throw new SyntaxException(
"Invalid use of the ||= operator.", this.pos, this.script);
1149 if (this.PeekNextChar() ==
'<')
1152 if (this.PeekNextChar() ==
'=')
1156 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1159 return new Operators.Assignments.WithSelf.ShiftSelfLeft(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1171 throw new SyntaxException(
"Invalid use of the <<= operator.", this.pos, this.script);
1187 if (this.PeekNextChar() ==
'>')
1190 if (this.PeekNextChar() ==
'=')
1194 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1197 return new Operators.Assignments.WithSelf.ShiftSelfRight(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1209 throw new SyntaxException(
"Invalid use of the >>= operator.", this.pos, this.script);
1234 this.SkipWhiteSpace();
1236 if (this.PeekNextChar() ==
'-')
1239 if (this.PeekNextChar() ==
'>')
1243 int Start = Left.
Start;
1244 string[] ArgumentNames;
1249 ArgumentNames =
new string[] { Ref.VariableName };
1250 ArgumentTypes =
new ArgumentType[] { ArgumentType.Normal };
1257 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1258 Left.
Start,
this.script);
1261 ArgumentNames =
new string[] { Ref.VariableName };
1262 ArgumentTypes =
new ArgumentType[] { ArgumentType.Vector };
1269 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1270 Left.
Start,
this.script);
1273 ArgumentNames =
new string[] { Ref.VariableName };
1274 ArgumentTypes =
new ArgumentType[] { ArgumentType.Matrix };
1281 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1282 Left.
Start,
this.script);
1285 ArgumentNames =
new string[] { Ref.VariableName };
1286 ArgumentTypes =
new ArgumentType[] { ArgumentType.Set };
1290 if (Def.Elements.Length != 1 || (Ref = Def.Elements[0] as
VariableReference) is
null)
1292 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1293 Left.
Start,
this.script);
1296 ArgumentNames =
new string[] { Ref.VariableName };
1297 ArgumentTypes =
new ArgumentType[] { ArgumentType.Scalar };
1305 ArgumentNames =
new string[c];
1308 for (i = 0; i < c; i++)
1314 else if (Argument is
ToVector ToVector2)
1319 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1320 Argument.
Start,
this.script);
1325 else if (Argument is
ToMatrix ToMatrix2)
1330 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1331 Argument.
Start,
this.script);
1336 else if (Argument is
ToSet ToSet2)
1341 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1342 Argument.
Start,
this.script);
1349 if (Def2.Elements.Length != 1 || (Ref = Def2.Elements[0] as
VariableReference) is
null)
1351 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1352 Left.
Start,
this.script);
1359 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1360 Argument.
Start,
this.script);
1363 ArgumentNames[i] = Ref.VariableName;
1369 if (!(this.ParseEquivalence() is
ScriptNode Operand))
1370 throw new SyntaxException(
"Lambda function body missing.", this.pos, this.script);
1372 return new LambdaDefinition(ArgumentNames, ArgumentTypes, Operand, Start, this.pos - Start,
this);
1387 int Start = Left.
Start;
1390 this.SkipWhiteSpace();
1392 if ((ch = this.PeekNextChar()) ==
'=')
1397 if (this.PeekNextChar() ==
'>')
1400 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseOrs());
1401 return new Implication(Left, Right, Start, this.pos - Start,
this);
1411 if (this.PeekNextChar() ==
'=')
1414 if (this.PeekNextChar() ==
'>')
1417 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseOrs());
1418 return new Equivalence(Left, Right, Start, this.pos - Start,
this);
1435 int Start = Left.
Start;
1439 this.SkipWhiteSpace();
1440 switch (
char.ToUpper(this.PeekNextChar()))
1444 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1445 Left =
new Operators.Logical.Or(Left, Right, Start, this.pos - Start,
this);
1450 switch (this.PeekNextChar())
1454 if (this.PeekNextChar() ==
'=')
1460 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1461 Left =
new Operators.Logical.Or(Left, Right, Start, this.pos - Start,
this);
1469 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1470 Left =
new Operators.Binary.Or(Left, Right, Start, this.pos - Start,
this);
1478 switch (this.PeekNextToken().ToUpper())
1482 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1483 Left =
new Operators.Dual.Or(Left, Right, Start, this.pos - Start,
this);
1488 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1489 Left =
new Operators.Dual.Xor(Left, Right, Start, this.pos - Start,
this);
1494 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1495 Left =
new Operators.Dual.Xnor(Left, Right, Start, this.pos - Start,
this);
1500 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1501 Left =
new Operators.Dual.Nor(Left, Right, Start, this.pos - Start,
this);
1521 int Start = Left.
Start;
1525 this.SkipWhiteSpace();
1526 switch (
char.ToUpper(this.PeekNextChar()))
1530 Right = this.AssertRightOperandNotNull(this.ParseMembership());
1531 Left =
new Operators.Logical.And(Left, Right, Start, this.pos - Start,
this);
1536 switch (this.PeekNextChar())
1540 if (this.PeekNextChar() ==
'=')
1546 Right = this.AssertRightOperandNotNull(this.ParseMembership());
1547 Left =
new Operators.Logical.And(Left, Right, Start, this.pos - Start,
this);
1555 Right = this.AssertRightOperandNotNull(this.ParseMembership());
1556 Left =
new Operators.Binary.And(Left, Right, Start, this.pos - Start,
this);
1563 switch (this.PeekNextToken().ToUpper())
1567 Right = this.AssertRightOperandNotNull(this.ParseMembership());
1568 Left =
new Operators.Dual.And(Left, Right, Start, this.pos - Start,
this);
1573 Right = this.AssertRightOperandNotNull(this.ParseMembership());
1574 Left =
new Operators.Dual.Nand(Left, Right, Start, this.pos - Start,
this);
1594 int Start = Left.
Start;
1598 this.SkipWhiteSpace();
1599 switch (
char.ToUpper(this.PeekNextChar()))
1607 switch (this.PeekNextToken().ToUpper())
1612 this.SkipWhiteSpace();
1613 if (
string.Compare(this.PeekNextToken(),
"NOT",
true) == 0)
1616 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1617 Left =
new IsNot(Left, Right, Start, this.pos - Start,
this);
1621 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1622 Left =
new Is(Left, Right, Start, this.pos - Start,
this);
1628 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1629 Left =
new Inherits(Left, Right, Start, this.pos - Start,
this);
1634 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1635 Left =
new As(Left, Right, Start, this.pos - Start,
this);
1640 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1641 Left =
new Matches(Left, Right, Start, this.pos - Start,
this);
1646 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1647 Left =
new In(Left, Right, Start, this.pos - Start,
this);
1652 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1653 Left =
new In(Left, Right, Start, this.pos - Start,
this);
1658 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1659 Left =
new NotIn(Left, Right, Start, this.pos - Start,
this);
1664 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1665 Left =
new NotIn(Left, Right, Start, this.pos - Start,
this);
1672 this.SkipWhiteSpace();
1673 if (
string.Compare(this.PeekNextToken(),
"IN",
true) == 0)
1676 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1677 Left =
new NotIn(Left, Right, Start, this.pos - Start,
this);
1703 int Start = Left.
Start;
1708 this.SkipWhiteSpace();
1709 switch (
char.ToUpper(this.PeekNextChar()))
1713 if ((ch = this.PeekNextChar()) ==
'=')
1717 if (this.PeekNextChar() ==
'>')
1724 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1726 Left =
new Range(LT.LeftOperand, LT.RightOperand, Right,
false,
true, LT.Start, Right.
Start + Right.
Length - LT.Start,
this);
1728 Left =
new Range(LTE.LeftOperand, LTE.RightOperand, Right,
true,
true, LTE.Start, Right.
Start + Right.
Length - LTE.Start,
this);
1736 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1737 Left =
new NotEqualTo(Left, Right, Start, this.pos - Start,
this);
1742 if (this.PeekNextChar() ==
'>')
1750 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1751 Left =
new LesserThan(Left, Right, Start, this.pos - Start,
this);
1761 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1763 Left =
new Range(LT.LeftOperand, LT.RightOperand, Right,
false,
false, LT.Start, Right.
Start + Right.
Length - LT.Start,
this);
1765 Left =
new Range(LTE.LeftOperand, LTE.RightOperand, Right,
true,
false, LTE.Start, Right.
Start + Right.
Length - LTE.Start,
this);
1767 Left =
new LesserThan(Left, Right, Start, this.pos - Start,
this);
1773 if ((ch = this.PeekNextChar()) ==
'=')
1776 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1778 Left =
new Range(Right, GT.RightOperand, GT.LeftOperand,
true,
false, GT.Start, Right.
Start + Right.
Length - GT.Start,
this);
1780 Left =
new Range(Right, GTE.RightOperand, GTE.LeftOperand,
true,
true, GTE.Start, Right.
Start + Right.
Length - GTE.Start,
this);
1791 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1793 Left =
new Range(Right, GT.RightOperand, GT.LeftOperand,
false,
false, GT.Start, Right.
Start + Right.
Length - GT.Start,
this);
1795 Left =
new Range(Right, GTE.RightOperand, GTE.LeftOperand,
false,
true, GTE.Start, Right.
Start + Right.
Length - GTE.Start,
this);
1797 Left =
new GreaterThan(Left, Right, Start, this.pos - Start,
this);
1803 if ((ch = this.PeekNextChar()) ==
'=')
1806 if (this.PeekNextChar() ==
'=')
1809 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1810 Left =
new IdenticalTo(Left, Right, Start, this.pos - Start,
this);
1814 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1815 Left =
new EqualTo(Left, Right, Start, this.pos - Start,
this);
1825 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1826 Left =
new EqualTo(Left, Right, Start, this.pos - Start,
this);
1832 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1833 Left =
new NotEqualTo(Left, Right, Start, this.pos - Start,
this);
1838 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1839 Left =
new IdenticalTo(Left, Right, Start, this.pos - Start,
this);
1844 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1847 Left =
new Range(LT.LeftOperand, LT.RightOperand, Right,
false,
true, LT.Start, Right.
Start + Right.
Length - LT.Start,
this);
1849 Left =
new Range(LTE.LeftOperand, LTE.RightOperand, Right,
true,
true, LTE.Start, Right.
Start + Right.
Length - LTE.Start,
this);
1857 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1860 Left =
new Range(Right, GT.RightOperand, GT.LeftOperand,
true,
false, GT.Start, Right.
Start + Right.
Length - GT.Start,
this);
1862 Left =
new Range(Right, GTE.RightOperand, GTE.LeftOperand,
true,
true, GTE.Start, Right.
Start + Right.
Length - GTE.Start,
this);
1870 if (this.PeekNextChar() ==
'=')
1873 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1874 Left =
new NotEqualTo(Left, Right, Start, this.pos - Start,
this);
1885 switch (this.PeekNextChar())
1889 if (this.PeekNextChar() ==
'=')
1892 if (this.PeekNextChar() ==
'=')
1895 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1900 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1906 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1913 if (this.PeekNextChar() ==
'>')
1916 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1928 if (this.PeekNextChar() ==
'=')
1931 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1949 switch (this.PeekNextToken().ToUpper())
1953 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1954 Left =
new Like(Left, Right, Start, this.pos - Start,
this);
1959 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1960 Left =
new NotLike(Left, Right, Start, this.pos - Start,
this);
1965 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1966 Left =
new NotLike(Left, Right, Start, this.pos - Start,
this);
1972 this.SkipWhiteSpace();
1973 if (
string.Compare(this.PeekNextToken(),
"LIKE",
true) == 0)
1976 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1977 Left =
new NotLike(Left, Right, Start, this.pos - Start,
this);
2003 int Start = Left.
Start;
2007 this.SkipWhiteSpace();
2008 switch (this.PeekNextChar())
2012 if (this.PeekNextChar() ==
'<')
2015 if (this.PeekNextChar() ==
'=')
2021 Right = this.AssertRightOperandNotNull(this.ParseUnions());
2022 Left =
new ShiftLeft(Left, Right, Start, this.pos - Start,
this);
2033 if (this.PeekNextChar() ==
'>')
2036 if (this.PeekNextChar() ==
'=')
2042 Right = this.AssertRightOperandNotNull(this.ParseUnions());
2043 Left =
new ShiftRight(Left, Right, Start, this.pos - Start,
this);
2065 int Start = Left.
Start;
2070 this.SkipWhiteSpace();
2071 if (
char.ToUpper(ch = this.PeekNextChar()) ==
'U')
2073 if (
string.Compare(this.PeekNextToken(),
"UNION",
true) == 0)
2076 Right = this.AssertRightOperandNotNull(this.ParseIntersections());
2077 Left =
new Union(Left, Right, Start, this.pos - Start,
this);
2085 Right = this.AssertRightOperandNotNull(this.ParseIntersections());
2086 Left =
new Union(Left, Right, Start, this.pos - Start,
this);
2100 int Start = Left.
Start;
2105 this.SkipWhiteSpace();
2106 if (
char.ToUpper(ch = this.PeekNextChar()) ==
'I')
2108 switch (this.PeekNextToken().ToUpper())
2110 case "INTERSECTION":
2112 Right = this.AssertRightOperandNotNull(this.ParseInterval());
2113 Left =
new Intersection(Left, Right, Start, this.pos - Start,
this);
2118 Right = this.AssertRightOperandNotNull(this.ParseInterval());
2119 Left =
new Intersection(Left, Right, Start, this.pos - Start,
this);
2129 Right = this.AssertRightOperandNotNull(this.ParseInterval());
2130 Left =
new Intersection(Left, Right, Start, this.pos - Start,
this);
2143 this.SkipWhiteSpace();
2144 if (this.PeekNextChar() !=
'.')
2148 if (this.PeekNextChar() !=
'.')
2155 ScriptNode To = this.AssertRightOperandNotNull(this.ParseTerms());
2156 int Start = From.
Start;
2158 this.SkipWhiteSpace();
2159 if (this.PeekNextChar() ==
'|')
2162 ScriptNode StepSize = this.AssertRightOperandNotNull(this.ParseTerms());
2163 return new Interval(From, To, StepSize, Start, this.pos - Start,
this);
2166 return new Interval(From, To, Start, this.pos - Start,
this);
2171 ScriptNode Left = this.ParseBinomialCoefficients();
2176 int Start = Left.
Start;
2181 this.SkipWhiteSpace();
2182 switch (this.PeekNextChar())
2186 ch = this.PeekNextChar();
2188 if (ch ==
'=' || ch ==
'+')
2197 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2202 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2203 Left =
new Add(Left, Right, Start, this.pos - Start,
this);
2209 if ((ch = this.PeekNextChar()) ==
'=' || ch ==
'>' || ch ==
'-')
2215 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2216 Left =
new Subtract(Left, Right, Start, this.pos - Start,
this);
2221 switch (this.PeekNextChar())
2225 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2226 Left =
new AddElementWise(Left, Right, Start, this.pos - Start,
this);
2231 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2243 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2253 internal ScriptNode ParseBinomialCoefficients()
2260 int Start = Left.
Start;
2264 this.SkipWhiteSpace();
2265 if (
char.ToUpper(this.PeekNextChar()) ==
'O' &&
string.Compare(this.PeekNextToken(),
"OVER",
true) == 0)
2268 Right = this.AssertRightOperandNotNull(this.ParseFactors());
2283 int Start = Left.
Start;
2287 this.SkipWhiteSpace();
2288 switch (
char.ToUpper(this.PeekNextChar()))
2293 if (this.PeekNextChar() ==
'=')
2299 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2300 Left =
new Multiply(Left, Right, Start, this.pos - Start,
this);
2305 if (this.PeekNextChar() ==
'=')
2311 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2312 Left =
new Divide(Left, Right, Start, this.pos - Start,
this);
2317 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2318 Left =
new LeftDivide(Left, Right, Start, this.pos - Start,
this);
2322 switch (this.PeekNextToken().ToUpper())
2326 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2327 Left =
new CrossProduct(Left, Right, Start, this.pos - Start,
this);
2332 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2341 if (
string.Compare(this.PeekNextToken(),
"DOT",
true) == 0)
2344 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2345 Left =
new DotProduct(Left, Right, Start, this.pos - Start,
this);
2352 if (
string.Compare(this.PeekNextToken(),
"MOD",
true) == 0)
2355 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2356 Left =
new Residue(Left, Right, Start, this.pos - Start,
this);
2364 switch (
char.ToUpper(this.PeekNextChar()))
2369 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2375 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2381 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2386 if (
string.Compare(this.PeekNextToken(),
"MOD",
true) == 0)
2389 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2412 ScriptNode Left = this.ParseUnaryPrefixOperator();
2417 int Start = Left.
Start;
2421 this.SkipWhiteSpace();
2422 switch (this.PeekNextChar())
2426 if (this.PeekNextChar() ==
'=')
2432 Right = this.AssertRightOperandNotNull(this.ParseUnaryPrefixOperator());
2433 Left =
new Power(Left, Right, Start, this.pos - Start,
this);
2438 Left =
new Square(Left, Start, this.pos - Start,
this);
2443 Left =
new Cube(Left, Start, this.pos - Start,
this);
2448 switch (this.PeekNextChar())
2452 Right = this.AssertRightOperandNotNull(this.ParseUnaryPrefixOperator());
2467 internal ScriptNode ParseUnaryPrefixOperator()
2469 this.SkipWhiteSpace();
2471 int Start = this.pos;
2474 switch (
char.ToUpper(this.PeekNextChar()))
2478 if ((ch = this.PeekNextChar()) ==
'-')
2482 ScriptNode Op = this.ParseUnaryPrefixOperator();
2485 return new Operators.Assignments.Pre.PreDecrement(Ref.VariableName, Start,
this.pos - Start,
this);
2497 throw new SyntaxException(
"Invalid use of the -- operator.", this.pos, this.script);
2499 else if ((ch >=
'0' && ch <=
'9') || (ch ==
'.'))
2502 return this.ParseSuffixOperator();
2507 return this.ParseSuffixOperator();
2510 return new Negate(this.AssertOperandNotNull(this.ParseFactors()), Start, this.pos - Start,
this);
2514 if ((ch = this.PeekNextChar()) ==
'+')
2518 ScriptNode Op = this.ParseUnaryPrefixOperator();
2521 return new Operators.Assignments.Pre.PreIncrement(Ref.VariableName, Start,
this.pos - Start,
this);
2533 throw new SyntaxException(
"Invalid use of the ++ operator.", this.pos, this.script);
2535 else if ((ch >=
'0' && ch <=
'9') || (ch ==
'.'))
2536 return this.ParseSuffixOperator();
2538 return this.AssertOperandNotNull(this.ParseFactors());
2542 return new Not(this.AssertOperandNotNull(this.ParseUnaryPrefixOperator()), Start, this.pos - Start,
this);
2545 if (
string.Compare(this.PeekNextToken(),
"NOT",
true) == 0)
2548 return new Not(this.AssertOperandNotNull(this.ParseUnaryPrefixOperator()), Start, this.pos - Start,
this);
2551 return this.ParseSuffixOperator();
2555 return new Complement(this.AssertOperandNotNull(this.ParseUnaryPrefixOperator()), Start, this.pos - Start,
this);
2558 return this.ParseSuffixOperator();
2569 int Start = Node.
Start;
2574 this.SkipWhiteSpace();
2575 switch (ch = this.PeekNextChar())
2581 if (this.PeekNextChar() ==
'?')
2588 ScriptNode IfNull = this.AssertOperandNotNull(this.ParseStatement(
false));
2589 Node =
new NullCheck(Node, IfNull, Start, this.pos - Start,
this);
2596 ch = this.PeekNextChar();
2616 ch = this.PeekNextChar();
2617 if (ch ==
'=' || ch ==
'+' || ch ==
'-' || ch ==
'^' || ch ==
'.' || ch ==
'*' || ch ==
'⋅' || ch ==
'/' || ch ==
'\\' || ch ==
'<' || ch ==
'!')
2623 if (
char.ToUpper(ch) ==
'M' &&
string.Compare(this.PeekNextToken(),
"MOD",
true) == 0)
2629 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseObject());
2639 bool WsBak = this.canSkipWhitespace;
2640 this.canSkipWhitespace =
true;
2642 Right = this.ParseList();
2644 this.SkipWhiteSpace();
2645 if (this.PeekNextChar() !=
')')
2648 this.canSkipWhitespace = WsBak;
2674 Node = GetFunction(Ref.VariableName, Right,
NullCheck, Start,
this.pos - Start,
this);
2679 WsBak = this.canSkipWhitespace;
2680 this.canSkipWhitespace =
true;
2682 Right = this.ParseList();
2684 this.SkipWhiteSpace();
2685 if (this.PeekNextChar() !=
']')
2688 this.canSkipWhitespace = WsBak;
2721 this.SkipWhiteSpace();
2722 if (this.PeekNextChar() ==
'}')
2725 Node =
new ToSet(Node,
NullCheck, Start, this.pos - Start,
this);
2736 if (this.PeekNextChar() ==
'+')
2743 Node =
new Operators.Assignments.Post.PostIncrement(Ref.VariableName, Start,
this.pos - Start,
this);
2762 Node =
new MinusOne(Node, Start, this.pos - Start,
this);
2766 throw new SyntaxException(
"Null-checked post increment operator not defined.", this.pos, this.script);
2778 if (this.PeekNextChar() ==
'-')
2785 Node =
new Operators.Assignments.Post.PostDecrement(Ref.VariableName, Start,
this.pos - Start,
this);
2804 Node =
new PlusOne(Node, Start, this.pos - Start,
this);
2808 throw new SyntaxException(
"Null-checked post increment operator not defined.", this.pos, this.script);
2822 throw new SyntaxException(
"Null-checked % operator not defined.", this.pos, this.script);
2824 if (this.PeekNextChar() ==
'0')
2828 if (this.PeekNextChar() ==
'0')
2831 Node =
new Perdiezmil(Node, Start, this.pos - Start,
this);
2834 Node =
new Permil(Node, Start, this.pos - Start,
this);
2837 Node =
new Percent(Node, Start, this.pos - Start,
this);
2844 throw new SyntaxException(
"Null-checked ‰ operator not defined.", this.pos, this.script);
2846 if (this.PeekNextChar() ==
'0')
2849 Node =
new Perdiezmil(Node, Start, this.pos - Start,
this);
2852 Node =
new Permil(Node, Start, this.pos - Start,
this);
2859 throw new SyntaxException(
"Null-checked ‱ operator not defined.", this.pos, this.script);
2861 Node =
new Perdiezmil(Node, Start, this.pos - Start,
this);
2868 throw new SyntaxException(
"Null-checked ° operator not defined.", this.pos, this.script);
2870 if ((ch = this.PeekNextChar()) ==
'C' || ch ==
'F')
2886 Node =
new SetUnit(Node,
Unit, Start, this.pos - Start,
this);
2890 Node =
new DegToRad(Node, Start, this.pos - Start,
this);
2894 Node =
new SetUnit(Node,
Unit, Start, this.pos - Start,
this);
2897 Node =
new DegToRad(Node, Start, this.pos - Start,
this);
2909 throw new SyntaxException(
"Null-checked differencial operators not defined.", this.pos, this.script);
2913 switch (this.PeekNextChar())
2941 ch = this.PeekNextChar();
2942 if (
char.IsLetter(ch) ||
char.IsDigit(ch))
2946 if (!this.TryParseUnit(ref Node))
2952 throw new SyntaxException(
"Null-checked T operator not defined.", this.pos, this.script);
2954 Node =
new Transpose(Node, Start, this.pos - Start,
this);
2960 ch = this.PeekNextChar();
2961 if (
char.IsLetter(ch) ||
char.IsDigit(ch))
2969 throw new SyntaxException(
"Null-checked H operator not defined.", this.pos, this.script);
2977 throw new SyntaxException(
"Null-checked † operator not defined.", this.pos, this.script);
2985 throw new SyntaxException(
"Null-checked ! operator not defined.", this.pos, this.script);
2988 switch (this.PeekNextChar())
2992 Node =
new SemiFaculty(Node, Start, this.pos - Start,
this);
3000 Node =
new Faculty(Node, Start, this.pos - Start,
this);
3007 throw new SyntaxException(
"Null-checked unit operator not defined.", this.pos, this.script);
3009 if (
char.IsLetter(ch))
3011 if (!this.TryParseUnit(ref Node))
3023 private bool TryParseUnit(ref
ScriptNode Node)
3034 int Start = Node.Start;
3046 Node =
new SetUnit(Node,
Unit, Start, this.pos - Start,
this);
3054 Node =
new SetUnit(Node,
Unit, Start, this.pos - Start,
this);
3059 internal Unit ParseUnit(
bool PermitPrefix)
3063 KeyValuePair<Prefix, UnitFactor[]> CompoundFactors;
3064 bool HasCompoundFactors;
3065 string Name, Name2, s;
3066 int Start = this.pos;
3067 int LastCompletion = Start;
3070 char ch = this.NextChar();
3071 bool LastDivision =
false;
3075 if (ch ==
'd' && this.PeekNextChar() ==
'a')
3084 ch = this.NextChar();
3094 this.pos = i = Start;
3096 ch = this.NextChar();
3100 LastDivision =
true;
3101 ch = this.NextChar();
3102 while (ch > 0 && (ch <=
' ' || ch == 160))
3103 ch = this.NextChar();
3106 while (
char.IsLetter(ch) || ch ==
'(')
3118 ch = this.NextChar();
3119 while (ch > 0 && (ch <=
' ' || ch == 160))
3120 ch = this.NextChar();
3125 ch = this.NextChar();
3126 while (ch > 0 && (ch <=
' ' || ch == 160))
3127 ch = this.NextChar();
3131 ch = this.NextChar();
3132 while (ch > 0 && (ch <=
' ' || ch == 160))
3133 ch = this.NextChar();
3135 if (ch ==
'-' ||
char.IsDigit(ch))
3140 ch = this.NextChar();
3142 while (
char.IsDigit(ch))
3143 ch = this.NextChar();
3146 s = this.script.Substring(i, this.pos - i);
3148 s = this.script.Substring(i, this.pos - i - 1);
3150 if (!
int.
TryParse(s, out Exponent))
3165 ch = this.NextChar();
3170 ch = this.NextChar();
3188 while (
char.IsLetter(ch))
3189 ch = this.NextChar();
3192 Name = this.script.Substring(i, this.pos - i);
3194 Name = this.script.Substring(i, this.pos - i - 1);
3198 if (keywords.ContainsKey(Name2 =
this.script.Substring(Start, i - Start) + Name))
3203 else if (HasCompoundFactors =
Unit.TryGetCompoundUnit(Name2, out CompoundFactors))
3205 Prefix = CompoundFactors.Key;
3208 else if (
Unit.ContainsDerivedOrBaseUnit(Name2))
3214 HasCompoundFactors =
Unit.TryGetCompoundUnit(Name, out CompoundFactors);
3217 HasCompoundFactors =
Unit.TryGetCompoundUnit(Name, out CompoundFactors);
3219 while (ch > 0 && (ch <=
' ' || ch == 160))
3220 ch = this.NextChar();
3224 ch = this.NextChar();
3225 while (ch > 0 && (ch <=
' ' || ch == 160))
3226 ch = this.NextChar();
3228 if (ch ==
'-' ||
char.IsDigit(ch))
3233 ch = this.NextChar();
3235 while (
char.IsDigit(ch))
3236 ch = this.NextChar();
3239 s = this.script.Substring(i, this.pos - i);
3241 s = this.script.Substring(i, this.pos - i - 1);
3243 if (!
int.
TryParse(s, out Exponent))
3258 ch = this.NextChar();
3263 ch = this.NextChar();
3268 if (HasCompoundFactors)
3272 foreach (
UnitFactor Segment
in CompoundFactors.Value)
3277 foreach (
UnitFactor Segment
in CompoundFactors.Value)
3290 while (ch > 0 && (ch <=
' ' || ch == 160))
3291 ch = this.NextChar();
3294 LastCompletion = this.pos;
3296 LastCompletion = this.pos - 1;
3298 if (ch ==
'*' || ch ==
'⋅')
3299 LastDivision =
false;
3301 LastDivision =
true;
3305 ch = this.NextChar();
3306 while (ch > 0 && (ch <=
' ' || ch == 160))
3307 ch = this.NextChar();
3310 PermitPrefix =
false;
3313 this.pos = LastCompletion;
3327 Dictionary<string, FunctionRef> F;
3332 if (Arguments is
null)
3337 else if (Arguments.GetType() == typeof(
ElementList))
3341 P =
new object[NrParameters + 3];
3351 P[NrParameters] = Start;
3352 P[NrParameters + 1] = Length;
3362 if (F.TryGetValue(FunctionName +
" " + NrParameters.ToString(), out FunctionRef Ref))
3368 else if (Arguments is
null)
3384 Dictionary<string, IConstant> C = constants;
3391 if (!C.TryGetValue(Name, out
IConstant Constant))
3393 ValueElement =
null;
3398 return !(ValueElement is
null);
3401 internal static IElement GetFunctionLambdaDefinition(
string FunctionName,
int Start,
int Length,
3404 Dictionary<string, FunctionRef> F;
3413 if (!F.TryGetValue(FunctionName, out FunctionRef Ref))
3417 ParameterInfo[] ConstructorParameters)
3419 int i, c = ConstructorParameters.Length - 3;
3421 object[] Arguments =
new object[c + 3];
3423 bool UseDefaultNames = DefaultNames.Length == c;
3424 string[] Names = UseDefaultNames ? DefaultNames :
new string[c];
3426 Arguments[c] = Start;
3427 Arguments[c + 1] = Length;
3430 for (i = 0; i < c; i++)
3432 if (!UseDefaultNames)
3433 Names[i] = ConstructorParameters[i].Name;
3445 return CreateLambda(Ref.MainFunction, Ref.MainConstructor, Ref.MainConstructorParameters);
3449 CreateLambda(Ref.MainFunction, Ref.MainConstructor, Ref.MainConstructorParameters)
3452 for (
int i = 0; i < Ref.NrAdditional; i++)
3454 Lambdas.
Add(CreateLambda(Ref.Additional[i], Ref.AdditionalConstructors[i],
3455 Ref.AdditionalConstructorParameters[i]));
3461 private static void Search()
3465 if (functions is
null)
3467 Dictionary<int, object[]> ParameterValuesPerNrParameters =
new Dictionary<int, object[]>();
3468 Dictionary<string, FunctionRef> Found =
new Dictionary<string, FunctionRef>(StringComparer.CurrentCultureIgnoreCase);
3469 ParameterInfo[] Parameters;
3470 ParameterInfo PInfo;
3478 void RegisterFunction(
string Name,
int NrArguments, Type T,
3479 ConstructorInfo CI, ParameterInfo[] ConstructorParameters)
3481 if (NrArguments < 0)
3484 s = Name +
" " + NrArguments.
ToString();
3486 if (Found.TryGetValue(s, out FunctionRef Prev))
3490 Prev.Multiple =
true;
3492 Prev.AdditionalConstructors =
new ConstructorInfo[] { CI };
3493 Prev.AdditionalConstructorParameters =
new ParameterInfo[][] { ConstructorParameters };
3494 Prev.NrAdditional = 1;
3498 Array.Resize(ref Prev.Additional, Prev.NrAdditional + 1);
3499 Array.Resize(ref Prev.AdditionalConstructors, Prev.NrAdditional + 1);
3500 Array.Resize(ref Prev.AdditionalConstructorParameters, Prev.NrAdditional + 1);
3501 Prev.Additional[Prev.NrAdditional] =
Function;
3502 Prev.AdditionalConstructors[Prev.NrAdditional] = CI;
3503 Prev.AdditionalConstructorParameters[Prev.NrAdditional] = ConstructorParameters;
3504 Prev.NrAdditional++;
3509 Ref =
new FunctionRef()
3511 MainConstructor = CI,
3512 MainConstructorParameters = ConstructorParameters,
3514 NrParameters = c - 3,
3517 AdditionalConstructors =
null,
3518 AdditionalConstructorParameters =
null,
3526 if (NrArguments >= 0)
3527 RegisterFunction(Name, -1, T, CI, ConstructorParameters);
3532 TI = T.GetTypeInfo();
3533 if (TI.IsAbstract || TI.IsInterface || TI.IsGenericTypeDefinition)
3536 foreach (ConstructorInfo CI
in TI.DeclaredConstructors)
3538 Parameters = CI.GetParameters();
3539 c = Parameters.Length;
3543 PInfo = Parameters[c - 1];
3544 if (PInfo.IsOut || PInfo.IsRetval || PInfo.IsOptional || PInfo.ParameterType != typeof(
Expression))
3547 PInfo = Parameters[c - 2];
3548 if (PInfo.IsOut || PInfo.IsRetval || PInfo.IsOptional || PInfo.ParameterType != typeof(
int))
3551 PInfo = Parameters[c - 3];
3552 if (PInfo.IsOut || PInfo.IsRetval || PInfo.IsOptional || PInfo.ParameterType != typeof(
int))
3555 for (i = c - 4; i >= 0; i--)
3557 PInfo = Parameters[i];
3558 if (PInfo.IsOut || PInfo.IsRetval || PInfo.IsOptional || PInfo.ParameterType != typeof(
ScriptNode))
3567 if (!ParameterValuesPerNrParameters.TryGetValue(c, out
object[] ParameterValues))
3569 ParameterValues =
new object[c];
3570 ParameterValues[c - 1] =
null;
3571 ParameterValues[c - 2] = 0;
3572 ParameterValues[c - 3] = 0;
3573 ParameterValuesPerNrParameters[c] = ParameterValues;
3583 if (!(Aliases is
null))
3585 foreach (
string Alias
in Aliases)
3586 RegisterFunction(Alias, c - 3, T, CI, Parameters);
3589 catch (Exception ex)
3593 if (ex is AggregateException ex2)
3595 foreach (Exception ex3
in ex2.InnerExceptions)
3607 if (constants is
null)
3609 Dictionary<string, IConstant> Found =
new Dictionary<string, IConstant>(StringComparer.CurrentCultureIgnoreCase);
3624 if (Found.TryGetValue(s, out
IConstant PrevConstant))
3626 if (PrevConstant.GetType() != T)
3628 Log.
Warning(
"Constant with name " + s +
" previously registered. Constant ignored.",
3629 T.FullName,
new KeyValuePair<string, object>(
"Previous", Constant.GetType().FullName));
3633 Found[s] = Constant;
3636 if (!(Aliases is
null))
3638 foreach (
string Alias
in Aliases)
3640 if (Found.TryGetValue(Alias, out PrevConstant))
3642 if (PrevConstant.GetType() != T)
3644 Log.
Warning(
"Constant with name " + Alias +
" previously registered. Constant ignored.",
3645 T.FullName,
new KeyValuePair<string, object>(
"Previous", Constant.GetType().FullName));
3649 Found[Alias] = Constant;
3653 catch (Exception ex)
3662 if (customKeyWords is
null)
3664 Dictionary<string, IKeyWord> Found =
new Dictionary<string, IKeyWord>(StringComparer.CurrentCultureIgnoreCase);
3679 if (Found.ContainsKey(s))
3681 Log.
Warning(
"Keyword with name " + s +
" previously registered. Keyword ignored.",
3682 T.FullName,
new KeyValuePair<string, object>(
"Previous", KeyWord.GetType().FullName));
3688 if (!(Aliases is
null))
3690 foreach (
string Alias
in Aliases)
3692 if (Found.ContainsKey(Alias))
3694 Log.
Warning(
"Keyword with name " + Alias +
" previously registered. Keyword ignored.",
3695 T.FullName,
new KeyValuePair<string, object>(
"Previous", KeyWord.GetType().FullName));
3698 Found[Alias] = KeyWord;
3702 catch (Exception ex)
3708 customKeyWords = Found;
3713 private class FunctionRef
3715 public ConstructorInfo MainConstructor;
3716 public ParameterInfo[] MainConstructorParameters;
3719 public ConstructorInfo[] AdditionalConstructors;
3720 public ParameterInfo[][] AdditionalConstructorParameters;
3722 public int NrParameters;
3723 public int NrAdditional;
3724 public bool Multiple;
3729 return (
Function)this.MainConstructor.Invoke(Parameters);
3734 F = (
Function)this.MainConstructor.Invoke(Parameters);
3738 for (
int i = 0; i < this.NrAdditional; i++)
3743 F = (
Function)this.AdditionalConstructors[i].Invoke(Parameters);
3746 throw new SyntaxException(
"Multiple functions with the same name recognized the same context: " + this.Name,
3755 throw new SyntaxException(
"Multiple functions registered with the name " +
3756 this.Name +
" but none recognized the current context.",
Expression.pos,
3766 this.SkipWhiteSpace();
3769 int Start = this.pos;
3770 char ch = this.PeekNextChar();
3774 bool WsBak = this.canSkipWhitespace;
3775 this.canSkipWhitespace =
true;
3777 Node = this.ParseSequence();
3779 this.SkipWhiteSpace();
3780 if (this.PeekNextChar() !=
')')
3783 this.canSkipWhitespace = WsBak;
3788 this.SkipWhiteSpace();
3789 if (this.PeekNextChar() ==
'-')
3792 if (this.PeekNextChar() ==
'>')
3796 if (!(this.ParseEquivalence() is
ScriptNode Operand))
3797 throw new SyntaxException(
"Lambda function body missing.", this.pos, this.script);
3803 throw new SyntaxException(
"Expected argument-less Lambda expression", this.pos, this.script);
3808 Node.Length = this.pos - Start;
3815 this.SkipWhiteSpace();
3816 if (this.PeekNextChar() ==
']')
3822 bool WsBak = this.canSkipWhitespace;
3823 this.canSkipWhitespace =
true;
3824 Node = this.ParseStatement(
true);
3826 this.SkipWhiteSpace();
3827 switch (this.PeekNextChar())
3831 this.canSkipWhitespace = WsBak;
3864 bool AllVectors =
true;
3868 if (!IsVectorDefinition(
Element))
3880 else if (IsVectorDefinition(Node))
3893 Conditions = List.Elements;
3905 this.SkipWhiteSpace();
3906 if (this.PeekNextChar() !=
']')
3909 this.canSkipWhitespace = WsBak;
3920 bool ObjectWildcard =
false;
3921 bool WsBak = this.canSkipWhitespace;
3924 this.canSkipWhitespace =
true;
3925 this.SkipWhiteSpace();
3927 switch (this.PeekNextChar())
3931 this.CanSkipWhitespace = WsBak;
3936 ObjectWildcard =
true;
3941 Node = this.ParseStatement(
true);
3945 this.SkipWhiteSpace();
3946 if (ObjectWildcard || (ch = this.PeekNextChar()) ==
':')
3948 bool DoubleColon =
false;
3950 if (!ObjectWildcard)
3954 if (this.PeekNextChar() ==
':')
3964 Dictionary<string, bool> MembersFound =
new Dictionary<string, bool>();
3969 if (!ObjectWildcard)
3979 throw new SyntaxException(
"Expected a variable reference or a string constant.", this.pos, this.script);
3981 MembersFound[s] =
true;
3982 Members.
Add(
new KeyValuePair<string, ScriptNode>(s, this.ParseLambdaExpression()));
3984 this.SkipWhiteSpace();
3987 while ((ch = this.PeekNextChar()) ==
',')
3990 this.SkipWhiteSpace();
3992 if (this.PeekNextChar() ==
'*')
3995 ObjectWildcard =
true;
3999 Node = this.ParseStatement(
false);
4001 this.SkipWhiteSpace();
4002 if (this.PeekNextChar() !=
':')
4006 s = VariableReference2.VariableName;
4013 throw new SyntaxException(
"Expected a variable reference or a string constant.", this.pos, this.script);
4015 if (MembersFound.ContainsKey(s))
4016 throw new SyntaxException(
"Member already defined.", this.pos, this.script);
4019 MembersFound[s] =
true;
4020 Members.
Add(
new KeyValuePair<string, ScriptNode>(s, this.ParseLambdaExpression()));
4023 this.SkipWhiteSpace();
4029 this.canSkipWhitespace = WsBak;
4031 return new ObjectExNihilo(Members, ObjectWildcard, Start, this.pos - Start,
this);
4039 Conditions = List.Elements;
4051 this.SkipWhiteSpace();
4052 if (this.PeekNextChar() !=
'}')
4055 this.canSkipWhitespace = WsBak;
4058 return new ImplicitSetDefinition(Node, SuperSet, Conditions, DoubleColon, Start, this.pos - Start,
this);
4064 this.canSkipWhitespace = WsBak;
4080 else if ((ch >=
'0' && ch <=
'9') || ch ==
'.' || ch ==
'+' || ch ==
'-')
4082 if (ch ==
'+' || ch ==
'-')
4085 ch = this.PeekNextChar();
4088 while (ch >=
'0' && ch <=
'9')
4091 ch = this.PeekNextChar();
4097 ch = this.PeekNextChar();
4099 if (ch >=
'0' && ch <=
'9')
4101 while (ch >=
'0' && ch <=
'9')
4104 ch = this.PeekNextChar();
4114 if (
char.ToUpper(ch) ==
'E')
4117 ch = this.PeekNextChar();
4119 if (ch ==
'+' || ch ==
'-')
4122 ch = this.PeekNextChar();
4125 while (ch >=
'0' && ch <=
'9')
4128 ch = this.PeekNextChar();
4132 if (!
double.
TryParse(this.script.Substring(Start,
this.pos - Start).
4133 Replace(
".", NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out
double d))
4135 throw new SyntaxException(
"Invalid double number.", this.pos, this.script);
4146 ch = this.PeekNextChar();
4152 ch = this.PeekNextChar();
4157 ch = this.PeekNextChar();
4160 ch =
char.ToLower(ch);
4161 int Start2 = this.pos;
4163 if (ch >=
'0' && ch <=
'9')
4165 else if (ch ==
'd' || ch ==
'x' || ch ==
'o' || ch ==
'b')
4168 Start2 = ++this.pos;
4171 throw new SyntaxException(
"Invalid numerical base.", this.pos, this.script);
4173 BigInteger n = BigInteger.Zero;
4178 while (this.pos < this.len && (ch = this.script[this.pos]) >=
'0' && ch <=
'9')
4181 if (Start2 == this.pos)
4184 n = BigInteger.Parse(this.script.Substring(Start2,
this.pos - Start2));
4189 while (this.pos < this.len)
4191 ch = this.script[this.pos];
4193 if (ch >=
'0' && ch <=
'9')
4195 else if (ch >=
'a' && ch <=
'f')
4196 ch -= (char)(
'a' - 10);
4197 else if (ch >=
'A' && ch <=
'F')
4198 ch -= (char)(
'A' - 10);
4209 while (this.pos < this.len && (ch = this.script[this.pos]) >=
'0' && ch <=
'7')
4218 while (this.pos < this.len && (ch = this.script[this.pos]) >=
'0' && ch <=
'1')
4227 if (Start2 == this.pos)
4235 else if (ch ==
'"' || ch ==
'\'')
4237 StringBuilder sb =
new StringBuilder();
4242 while ((ch2 = this.NextChar()) != ch)
4244 if (ch2 == 0 || ch2 ==
'\r' || ch2 ==
'\n')
4245 throw new SyntaxException(
"Expected end of string.", this.pos, this.script);
4249 ch2 = this.NextChar();
4253 throw new SyntaxException(
"Expected end of string.", this.pos, this.script);
4284 ch2 = this.NextChar();
4285 if (ch2 >=
'0' && ch2 <=
'9')
4287 else if (ch2 >=
'a' && ch2 <=
'f')
4288 ch2 -= (char)(
'a' - 10);
4289 else if (ch2 >=
'A' && ch2 <=
'F')
4290 ch2 -= (char)(
'A' - 10);
4292 throw new SyntaxException(
"Hexadecimal digit expected.", this.pos, this.script);
4294 char ch3 = this.NextChar();
4295 if (ch3 >=
'0' && ch3 <=
'9')
4297 else if (ch3 >=
'a' && ch3 <=
'f')
4298 ch3 -= (char)(
'a' - 10);
4299 else if (ch3 >=
'A' && ch3 <=
'F')
4300 ch3 -= (char)(
'A' - 10);
4302 throw new SyntaxException(
"Hexadecimal digit expected.", this.pos, this.script);
4315 else if (
char.IsLetter(ch) || ch ==
'_')
4321 while ((ch = this.PeekNextChar()) ==
'_')
4324 if (!
char.IsLetter(ch))
4325 throw new SyntaxException(
"Expected a letter.", this.pos, this.script);
4328 while (
char.IsLetter((ch = this.PeekNextChar())) ||
char.IsDigit(ch) || ch ==
'_')
4331 string s = this.script.Substring(Start, this.pos - Start);
4333 switch (s.ToUpper())
4345 Node = this.ParseCustomNode(s,
false, Start);
4370 return this.ParseCustomNode(
new string(ch, 1),
true, Start);
4374 private ScriptNode ParseCustomNode(
string KeyWord,
bool IncPosIfKeyword,
int Start)
4376 if (customKeyWords is
null)
4379 if (customKeyWords.TryGetValue(KeyWord, out
IKeyWord KeyWordParser))
4382 int PosBak = this.pos;
4384 if (IncPosIfKeyword)
4385 this.pos += KeyWord.Length;
4387 bool CanParseWhitespace = this.canSkipWhitespace;
4388 bool Result = KeyWordParser.TryParse(Parser, out
ScriptNode Node);
4390 this.canSkipWhitespace = CanParseWhitespace;
4401 private static bool IsVectorDefinition(
ScriptNode Node)
4422 [Obsolete(
"Use the EvaluateAsync method for more efficient processing of script containing asynchronous processing elements in parallel environments.")]
4429 if (this.root is
null)
4467 if (this.root is
null)
4502 return this.script.Equals(Exp.script);
4510 return this.script.GetHashCode();
4525 if (this.ContainsImplicitPrint)
4528 Dictionary<string, bool> Processed =
null;
4550 if (Processed is
null)
4551 Processed =
new Dictionary<string, bool>() { { this.script,
true } };
4553 if (Processed.ContainsKey(Exp.script))
4556 Processed[Exp.script] =
true;
4580 [Obsolete(
"Use the TransformAsync method for more efficient processing of script containing asynchronous processing elements in parallel environments.")]
4595 [Obsolete(
"Use the TransformAsync method for more efficient processing of script containing asynchronous processing elements in parallel environments.")]
4598 int i = s.IndexOf(StartDelimiter);
4602 StringBuilder Transformed =
new StringBuilder();
4607 int StartLen = StartDelimiter.Length;
4608 int StopLen = StopDelimiter.Length;
4613 j = s.IndexOf(StopDelimiter, i + StartLen);
4623 Transformed.Append(s.Substring(From, i - From));
4627 Script = s.Substring(i + StartLen, j - i - StartLen);
4633 Transformed.Append(Result.ToString());
4635 i = s.IndexOf(StartDelimiter, From);
4638 if (From < s.Length)
4639 Transformed.Append(s.Substring(From));
4641 return Transformed.ToString();
4668 int i = s.IndexOf(StartDelimiter);
4672 StringBuilder Transformed =
new StringBuilder();
4678 int StartLen = StartDelimiter.Length;
4679 int StopLen = StopDelimiter.Length;
4684 j = s.IndexOf(StopDelimiter, i + StartLen);
4694 Transformed.Append(s.Substring(From, i - From));
4698 Script = s.Substring(i + StartLen, j - i - StartLen);
4704 Transformed.Append(Printer is
null ? Result.ToString() : await Printer(Result,
Variables));
4706 i = s.IndexOf(StartDelimiter, From);
4709 if (From < s.Length)
4710 Transformed.Append(s.Substring(From));
4712 return Transformed.ToString();
4726 return IsVoid(Result.GetType());
4737 if (ResultType == typeof(
void))
4739 else if (VoidTaskResultType is
null)
4741 if (ResultType.FullName ==
"System.Threading.Tasks.VoidTaskResult")
4743 VoidTaskResultType = ResultType;
4750 return ResultType == VoidTaskResultType;
4753 private static Type VoidTaskResultType =
null;
4762 return Value.ToString(CultureInfo.InvariantCulture);
4772 return Value.ToString(CultureInfo.InvariantCulture);
4781 public static bool TryParse(
string s, out
double Value)
4783 return double.TryParse(s.Replace(
".", NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out Value);
4794 return float.TryParse(s.Replace(
".", NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out Value);
4803 public static bool TryParse(
string s, out decimal Value)
4805 return decimal.TryParse(s.Replace(
".", NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out Value);
4815 return "(" +
ToString(Value.Real) +
", " +
ToString(Value.Imaginary) +
")";
4825 return "#" + Value.ToString();
4835 return Value ?
"⊤" :
"⊥";
4845 StringBuilder sb =
null;
4847 foreach (
double d
in Value)
4850 sb =
new StringBuilder(
"[");
4862 return sb.ToString();
4873 StringBuilder sb =
null;
4875 foreach (Complex z
in Value)
4878 sb =
new StringBuilder(
"[");
4890 return sb.ToString();
4901 StringBuilder Output =
new StringBuilder();
4903 Output.Append(
"DateTime");
4905 if (Value.Kind == DateTimeKind.Utc)
4906 Output.Append(
"Utc");
4909 Output.Append(Value.Year.ToString(
"D4"));
4911 Output.Append(Value.Month.ToString(
"D2"));
4913 Output.Append(Value.Day.ToString(
"D2"));
4915 if (Value.Hour != 0 || Value.Minute != 0 || Value.Second != 0 || Value.Millisecond != 0)
4918 Output.Append(Value.Hour.ToString(
"D2"));
4920 Output.Append(Value.Minute.ToString(
"D2"));
4922 Output.Append(Value.Second.ToString(
"D2"));
4924 if (Value.Millisecond != 0)
4927 Output.Append(Value.Millisecond.ToString(
"D3"));
4933 return Output.ToString();
4943 StringBuilder Output =
new StringBuilder();
4945 Output.Append(
"TimeSpan(");
4946 Output.Append(Value.Days.ToString());
4948 Output.Append(Value.Hours.ToString(
"D2"));
4950 Output.Append(Value.Minutes.ToString(
"D2"));
4952 Output.Append(Value.Seconds.ToString(
"D2"));
4954 if (Value.Milliseconds != 0)
4957 Output.Append(Value.Milliseconds.ToString(
"D3"));
4962 return Output.ToString();
4972 StringBuilder Output =
new StringBuilder();
4974 Output.Append(Value.GetType().FullName);
4976 Output.Append(Value.ToString());
4978 return Output.ToString();
4991 StringBuilder sb =
new StringBuilder();
4992 int i = s.IndexOfAny(stringCharactersToEscape);
5005 sb.Append(s.Substring(j, i - j));
5007 k = Array.IndexOf(stringCharactersToEscape, s[i]);
5008 sb.Append(stringEscapeSequences[k]);
5010 i = s.IndexOfAny(stringCharactersToEscape, j);
5014 sb.Append(s.Substring(j));
5019 return sb.ToString();
5022 private static readonly
char[] stringCharactersToEscape =
new char[] {
'\\',
'"',
'\n',
'\r',
'\t',
'\b',
'\f',
'\a',
'\v' };
5023 private static readonly
string[] stringEscapeSequences =
new string[] {
"\\\\",
"\\\"",
"\\n",
"\\r",
"\\t",
"\\b",
"\\f",
"\\a",
"\\v" };
5030 [Obsolete(
"Use the ToExpressionString method instead.")]
5041 [Obsolete(
"Use the ToExpressionString method instead.")]
5058 Type T = Value.GetType();
5079 else if (Value is IEnumerable Enumerable)
5081 StringBuilder sb =
new StringBuilder();
5086 foreach (
object Element in Enumerable)
5098 return sb.ToString();
5101 return Value.ToString();
5112 if (Object is
double db)
5114 else if (Object is
int i)
5116 else if (Object is
bool b)
5118 else if (Object is
byte bt)
5120 else if (Object is
char ch)
5122 else if (Object is decimal dc)
5124 else if (Object is
short sh)
5126 else if (Object is
long l)
5128 else if (Object is sbyte sb)
5130 else if (Object is
float f)
5132 else if (Object is ushort us)
5134 else if (Object is uint ui)
5136 else if (Object is ulong ul)
5138 else if (Object is BigInteger i2)
5140 else if (Object is Complex z)
5142 if (z.Imaginary == 0)
5149 string s = Object.ToString();
5151 if (
double.
TryParse(s, out
double d))
5154 if (NumberFormatInfo.CurrentInfo.NumberDecimalSeparator !=
"." &&
5155 double.TryParse(s.Replace(
".", NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out d))
5171 if (Object is
double db)
5173 else if (Object is
int i)
5175 else if (Object is
bool b)
5177 else if (Object is
byte bt)
5179 else if (Object is
char ch)
5181 else if (Object is decimal dc)
5183 else if (Object is
short sh)
5185 else if (Object is
long l)
5187 else if (Object is sbyte sb)
5189 else if (Object is
float f)
5191 else if (Object is ushort us)
5193 else if (Object is uint ui)
5195 else if (Object is ulong ul)
5197 else if (Object is BigInteger i2)
5199 else if (Object is Complex z)
5201 if (z.Imaginary == 0)
5202 return (decimal)z.Real;
5208 string s = Object.ToString();
5210 if (decimal.TryParse(s, out decimal d))
5213 if (NumberFormatInfo.CurrentInfo.NumberDecimalSeparator !=
"." &&
5214 decimal.TryParse(s.Replace(
".", NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out d))
5230 if (Object is Complex z)
5233 return new Complex(
ToDouble(Object), 0);
5245 else if (Value is
double db)
5247 else if (Value is
bool b)
5249 else if (Value is
string s)
5251 else if (Value is
int i)
5253 else if (Value is
long l)
5255 else if (Value is
byte bt)
5257 else if (Value is
char ch)
5259 else if (Value is DateTime DT)
5261 else if (Value is decimal dc)
5263 else if (Value is
short sh)
5265 else if (Value is sbyte sb)
5267 else if (Value is
float f)
5269 else if (Value is ushort us)
5271 else if (Value is uint ui)
5273 else if (Value is ulong ul)
5275 else if (Value is Complex c)
5277 else if (Value is BigInteger i2)
5279 else if (Value is Type t)
5286 else if (Value is
double[] dv)
5288 else if (Value is
double[,] dm)
5291 else if (Value is Complex[] cv)
5293 else if (Value is Complex[,] cm)
5296 else if (Value is
bool[] bv)
5298 else if (Value is
bool[,] bm)
5301 else if (Value is DateTime[] dv2)
5308 else if (Value is
object[] ov)
5310 else if (Value is
object[,] om)
5330 object O1 = E1?.AssociatedObjectValue;
5331 object O2 = E2?.AssociatedObjectValue;
5332 Type T1 = O1?.GetType() ?? typeof(
object);
5333 Type T2 = O2?.GetType() ?? typeof(
object);
5341 Set1 = E1asT2.AssociatedSet;
5348 Set2 = E2asT1.AssociatedSet;
5354 if (O1 is Enum Enum1 && O2 is
double)
5356 T1 = Enum.GetUnderlyingType(Enum1.GetType());
5357 if (T1 == typeof(
int))
5364 else if (O2 is Enum Enum2 && O1 is
double)
5366 T2 = Enum.GetUnderlyingType(Enum2.GetType());
5367 if (T2 == typeof(
int))
5402 if (
TryConvert(Obj, DesiredType,
true, out
object Result))
5405 Type T = Obj.GetType();
5406 if (T == DesiredType)
5409 if (DesiredType.IsArray)
5411 Type DesiredItemType = DesiredType.GetElementType();
5416 Array
Source = (Array)Obj;
5420 Dest = (Array)Activator.CreateInstance(DesiredType, c);
5422 for (i = 0; i < c; i++)
5423 Dest.SetValue(
ConvertTo(
Source.GetValue(i), DesiredItemType, Node), i);
5427 Dest = (Array)Activator.CreateInstance(DesiredType, 1);
5428 Dest.SetValue(
ConvertTo(Obj, DesiredItemType, Node), 0);
5433 else if (DesiredType.IsEnum && Obj is
string s)
5434 return Enum.Parse(DesiredType, s);
5436 return Convert.ChangeType(Obj, DesiredType);
5445 set => this.tag = value;
5455 [Obsolete(
"Use ForAll(ScriptNodeEventHandler, object, SearchMethod) instead.")]
5472 if (!(this.root?.ForAllChildNodes(Callback, State, Order) ??
true))
5476 if (!(this.root is
null))
5478 if (!Callback(this.root, out
ScriptNode NewRoot, State))
5481 if (!(NewRoot is
null))
5482 this.root = NewRoot;
5487 if (!(this.root?.ForAllChildNodes(Callback, State, Order) ??
true))
5503 if (
TryConvert(Value, typeof(T),
true, out
object Obj))
5505 if (Obj is T Result2)
5510 else if (Value is
null && !typeof(T).IsValueType)
5531 bool AcceptInformationLoss, out
object Result)
5533 return TryConvert(Value, DesiredType, AcceptInformationLoss ? 0 : 1, out Result);
5546 double WeightThreshold, out
object Result)
5551 return !DesiredType.IsValueType;
5554 Type T = Value.GetType();
5555 TypeInfo TI = T.GetTypeInfo();
5557 if (DesiredType.IsAssignableFrom(TI))
5564 Converter.Weight >= WeightThreshold &&
5565 Converter.TryConvert(Value, out Result))
5570 if (DesiredType.IsEnum)
5572 switch (Type.GetTypeCode(Value.GetType()))
5574 case TypeCode.Empty:
5575 case TypeCode.DBNull:
5576 case TypeCode.Boolean:
5577 case TypeCode.DateTime:
5581 case TypeCode.String:
5583 string s = Value.ToString();
5584 string[] Names = Enum.GetNames(DesiredType);
5585 int i = Array.IndexOf(Names, s);
5594 Array Values = Enum.GetValues(DesiredType);
5595 Result = Values.GetValue(i);
5599 case TypeCode.Object:
5600 if (
TryConvert(Value, typeof(
string), WeightThreshold, out
object Obj) &&
5606 s = Value.ToString();
5608 Names = Enum.GetNames(DesiredType);
5609 i = Array.IndexOf(Names, s);
5618 Array Values = Enum.GetValues(DesiredType);
5619 Result = Values.GetValue(i);
5623 case TypeCode.SByte:
5624 Result = Enum.ToObject(DesiredType, (sbyte)Value);
5628 Result = Enum.ToObject(DesiredType, (
byte)Value);
5631 case TypeCode.Int16:
5632 Result = Enum.ToObject(DesiredType, (
short)Value);
5635 case TypeCode.UInt16:
5636 Result = Enum.ToObject(DesiredType, (ushort)Value);
5639 case TypeCode.Int32:
5640 Result = Enum.ToObject(DesiredType, (
int)Value);
5643 case TypeCode.UInt32:
5644 Result = Enum.ToObject(DesiredType, (uint)Value);
5647 case TypeCode.Int64:
5648 Result = Enum.ToObject(DesiredType, (
long)Value);
5651 case TypeCode.UInt64:
5652 Result = Enum.ToObject(DesiredType, (ulong)Value);
5655 case TypeCode.Single:
5656 float f = (float)Value;
5658 if (f >=
int.MinValue && f <=
int.MaxValue)
5659 Result = Enum.ToObject(DesiredType, (
int)f);
5660 else if (f >=
long.MinValue && f <=
long.MaxValue)
5661 Result = Enum.ToObject(DesiredType, (
long)f);
5662 else if (f >= ulong.MinValue && f <= ulong.MaxValue)
5663 Result = Enum.ToObject(DesiredType, (ulong)f);
5672 case TypeCode.Double:
5673 double d = (double)Value;
5675 if (d >=
int.MinValue && d <=
int.MaxValue)
5676 Result = Enum.ToObject(DesiredType, (
int)d);
5677 else if (d >=
long.MinValue && d <=
long.MaxValue)
5678 Result = Enum.ToObject(DesiredType, (
long)d);
5679 else if (d >= ulong.MinValue && d <= ulong.MaxValue)
5680 Result = Enum.ToObject(DesiredType, (ulong)d);
5689 case TypeCode.Decimal:
5690 decimal dec = (decimal)Value;
5692 if (dec >=
int.MinValue && dec <=
int.MaxValue)
5693 Result = Enum.ToObject(DesiredType, (
int)dec);
5694 else if (dec >=
long.MinValue && dec <=
long.MaxValue)
5695 Result = Enum.ToObject(DesiredType, (
long)dec);
5696 else if (dec >= ulong.MinValue && dec <= ulong.MaxValue)
5697 Result = Enum.ToObject(DesiredType, (ulong)dec);
5723 bool AcceptInformationLoss, out
IElement Result)
5725 return TryConvert(Value, DesiredType, AcceptInformationLoss ? 0 : 1, out Result);
5739 double WeightThreshold, out
IElement Result)
5745 return !DesiredType.IsValueType;
5748 Type T = Obj.GetType();
5751 Converter.Weight >= WeightThreshold &&
5752 Converter.TryConvertToElement(Obj, out Result))
5773 if (converters is
null)
5775 Dictionary<Type, Dictionary<Type, ITypeConverter>> Converters = GetTypeConverters();
5777 if (converters is
null)
5779 converters = Converters;
5780 Types.OnInvalidated += (Sender, e) => converters = GetTypeConverters();
5786 if (!converters.TryGetValue(From, out Dictionary<Type, ITypeConverter> Converters) &&
5787 (!From.IsEnum || !converters.TryGetValue(typeof(Enum), out Converters)))
5793 if (Converters.TryGetValue(To, out Converter))
5794 return !(Converter is
null);
5796 Dictionary<Type, double> Explored =
new Dictionary<Type, double>() { { From, 1.0 } };
5799 double BestWeight = 0;
5804 if (!(Converter3 is
null))
5806 Search.Add(Converter3);
5807 Explored[Converter3.
To] = Converter3.
Weight;
5811 while (Search.HasFirstItem)
5815 if (converters.TryGetValue(C.
To, out Dictionary<Type, ITypeConverter> Converters2) &&
5816 !(Converters2 is
null))
5818 if (Converters2.TryGetValue(To, out
ITypeConverter Converter2) &&
5819 !(Converter2 is
null))
5825 int c = Sequence.Converters.Length + 1;
5828 A[c - 1] = Converter2;
5837 if (!Converters.TryGetValue(To, out
ITypeConverter Converter3) ||
5838 Weight > Converter3.Weight)
5848 else if (Weight > BestWeight)
5851 BestWeight = Weight;
5857 if (!(Converter3 is
null))
5859 Weight = C.Weight * Converter3.
Weight;
5861 if (!Explored.TryGetValue(Converter3.
To, out
double Weight2) ||
5864 Search.Add(Converter3);
5865 Explored[Converter3.
To] = Weight;
5872 Converters[To] = Best;
5874 return !(Best is
null);
5878 private static Dictionary<Type, Dictionary<Type, ITypeConverter>> GetTypeConverters()
5880 Dictionary<Type, Dictionary<Type, ITypeConverter>> Converters =
new Dictionary<Type, Dictionary<Type, ITypeConverter>>();
5885 if (DefaultConstructor is
null)
5891 Type From = Converter.
From;
5892 Type To = Converter.
To;
5894 if (!Converters.TryGetValue(From, out Dictionary<Type, ITypeConverter> List))
5896 List =
new Dictionary<Type, ITypeConverter>();
5897 Converters[From] = List;
5902 Log.
Warning(
"There's already a type converter registered converting from " +
5903 From.FullName +
" to " + To.FullName, Converter2.GetType().FullName);
5906 List[To] = Converter;
5908 catch (Exception ex)
5922 [Obsolete(
"Use the EvalAsync method for more efficient processing of script containing asynchronous processing elements in parallel environments.")]
5934 [Obsolete(
"Use the EvalAsync method for more efficient processing of script containing asynchronous processing elements in parallel environments.")]
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
A chunked list is a linked list of chunks of objects of type T .
bool Contains(T Item)
Checks if an item is a member of the collection.
bool HasFirstItem
If there is a first item in the collection
void Add(T Item)
Adds an item to the collection.
T[] ToArray()
Returns an array containing all elements of the collection.
Static class that dynamically manages types and interfaces available in the runtime environment.
static object[] NoParameters
Contains an empty array of parameter values.
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
static ConstructorInfo GetDefaultConstructor(Type Type)
Gets the default constructor of a type, if one exists.
Base class for all types of elements.
Exception used to break a loop.
Exception used to continue a loop.
Base class for script exceptions.
Script runtime exception.
IElement ReturnValue
Return value.
Class managing a script expression.
static Complex ToComplex(object Object)
Converts an object to a complex value.
static bool TryGetTypeConverter(Type From, Type To, out ITypeConverter Converter)
Tries to get a type converter, converting objects from type From to objects of type To .
string Script
Original script string.
static Task< object > EvalAsync(string Script)
Evaluates script, in string format.
ScriptNode Root
Root script node.
object Evaluate(Variables Variables)
Evaluates the expression, using the variables provided in the Variables collection....
static string ToString(decimal Value)
Converts a value to a string, that can be parsed as part of an expression.
async Task< object > EvaluateAsync(Variables Variables)
Evaluates the expression, using the variables provided in the Variables collection....
Expression(string Script, object Tag)
Class managing a script expression.
static string ToString(Enum Value)
Converts a value to a string, that can be parsed as part of an expression.
Expression(string Script)
Class managing a script expression.
static string ToString(object Value)
Converts an object to a string, that can be parsed as part of an expression.
static bool IsVoid(Type ResultType)
Checks if a result object type is equal to void (i.e. its type equal to System.Threading....
static bool TryConvert(object Value, Type DesiredType, bool AcceptInformationLoss, out object Result)
Tries to convert an object Value to an object of type DesiredType .
static bool TryGetConstant(string Name, Variables Variables, out IElement ValueElement)
Tries to get a constant value, given its name.
static string ToString(TimeSpan Value)
Converts a value to a string, that can be parsed as part of an expression.
static string ToString(Complex[] Value)
Converts a value to a string, that can be parsed as part of an expression.
bool ContainsImplicitPrint
If the expression contains implicit print operations.
static string ToString(BigInteger Value)
Converts a value to a string, that can be parsed as part of an expression.
static string Transform(string s, string StartDelimiter, string StopDelimiter, Variables Variables, string Source)
Transforms a string by executing embedded script.
static string Transform(string s, string StartDelimiter, string StopDelimiter, Variables Variables)
Transforms a string by executing embedded script.
static IElement Encapsulate(object Value)
Encapsulates an object.
static bool TryParse(string s, out decimal Value)
Tries to parse a decimal-precision floating-point value.
static bool UpgradeField(ref IElement E1, ref ISet Set1, ref IElement E2, ref ISet Set2)
Upgrades elements if necessary, to a common field extension, trying to make them compatible....
static bool TryParse(string s, out double Value)
Tries to parse a double-precision floating-point value.
static object ConvertTo(IElement Value, Type DesiredType, ScriptNode Node)
Tries to conevert an element value to a desired type.
Expression(string Script, string Source)
Class managing a script expression.
static object ConvertTo(object Obj, Type DesiredType, ScriptNode Node)
Tries to conevert an object to a desired type.
static string EncodeString(string s)
Converts a string value to a parsable expression string.
static bool IsNullOrVoid(object Result)
Checks if a result object value is equal to null or void (i.e. its type equal to System....
static string ToString(DateTime Value)
Converts a value to a string, that can be parsed as part of an expression.
bool ForAll(ScriptNodeEventHandler Callback, object State, SearchMethod Order)
Calls the callback method for all script nodes defined for the expression.
static object Eval(string Script, Variables Variables)
Evaluates script, in string format.
static decimal ToDecimal(object Object)
Converts an object to a double value.
static Task< object > EvalAsync(string Script, Variables Variables)
Evaluates script, in string format.
static async Task< string > TransformAsync(string s, string StartDelimiter, string StopDelimiter, Variables Variables, string Source)
Transforms a string by executing embedded script.
static string ToString(bool Value)
Converts a value to a string, that can be parsed as part of an expression.
bool ReferencesImplicitPrint(Variables Variables)
If the expression, or any function call references, contain implicit print operations.
static string ToString(string Value)
Converts an object to a string, that can be parsed as part of an expression.
object Tag
This property allows the caller to tag the expression with an arbitrary object.
bool IsAsynchronous
If the node (or its decendants) include asynchronous evaluation. Asynchronous nodes should be evaluat...
static bool TryConvert(IElement Value, Type DesiredType, bool AcceptInformationLoss, out IElement Result)
Tries to convert an element Value to an element whose associated object is of type DesiredType .
string Source
Source of script, or null if not defined.
static bool TryConvert(IElement Value, Type DesiredType, double WeightThreshold, out IElement Result)
Tries to convert an element Value to an element whose associated object is of type DesiredType .
static bool TryParse(string s, out float Value)
Tries to parse a single-precision floating-point value.
override bool Equals(object obj)
static double ToDouble(object Object)
Converts an object to a double value.
static bool TryConvert< T >(object Value, out T Result)
Tries to convert an object Value to an object of type T .
override int GetHashCode()
static string ToString(double Value)
Converts a value to a string, that can be parsed as part of an expression.
static string ToString(double[] Value)
Converts a value to a string, that can be parsed as part of an expression.
static bool TryConvert(object Value, Type DesiredType, double WeightThreshold, out object Result)
Tries to convert an object Value to an object of type DesiredType .
bool ForAll(ScriptNodeEventHandler Callback, object State, bool DepthFirst)
Calls the callback method for all script nodes defined for the expression.
static string ToExpressionString(object Value)
Converts an object to a string, that can be parsed as part of an expression.
Expression(string Script, string Source, object Tag)
Class managing a script expression.
static string ToString(Complex Value)
Converts a value to a string, that can be parsed as part of an expression.
static Task< string > TransformAsync(string s, string StartDelimiter, string StopDelimiter, Variables Variables)
Transforms a string by executing embedded script.
static object Eval(string Script)
Evaluates script, in string format.
ScriptNode RightOperand
Right operand.
ScriptNode LeftOperand
Left operand.
Represents a constant element value.
IElement Constant
Constant value.
Base class for all funcions.
abstract string FunctionName
Name of the function
virtual bool ContextSpecific(Expression Expression)
If the function is specific to a given context, as apparent from the expression object....
abstract string[] DefaultArgumentNames
Default Argument names
virtual string[] Aliases
Optional aliases. If there are no aliases for the function, null is returned.
bool NullCheck
If null check is to be used.
string VariableName
Variable Name.
Base class for all nodes in a parsed script tree.
int Length
Length of expression covered by node.
override string ToString()
int Start
Start position in script expression.
virtual bool IsAsynchronous
If the node (or its decendants) include asynchronous evaluation. Asynchronous nodes should be evaluat...
abstract IElement Evaluate(Variables Variables)
Evaluates the node, using the variables provided in the Variables collection. This method should be ...
virtual Task< IElement > EvaluateAsync(Variables Variables)
Evaluates the node, using the variables provided in the Variables collection. This method should be ...
Script parser, for custom parsers.
ScriptNode Operand
Operand.
Represents a variable reference.
static readonly BooleanValue False
Constant false value.
static readonly BooleanValue True
Constant true value.
Pseudo-field of double numbers, as an approximation of the field of real numbers.
static readonly DoubleNumbers Instance
Instance of the set of complex numbers.
static readonly ObjectValue Null
Null value.
string Value
String value.
Element-wise Addition operator.
Degrees to radians operator.
Element-wise Division operator.
Element-wise Left-Division operator.
Element-wise Multiplication operator.
Element-wise Power operator.
Element-wise Residue operator.
Element-wise Subtraction operator.
string VariableName
Name of variable
Dynamic Index Assignment operator.
Dynamic member Assignment operator.
Function definition operator.
Matrix Column Assignment operator.
Matrix Index Assignment operator.
Matrix Row Assignment operator.
Named member Assignment operator.
Vector Index Assignment operator.
Default Differentiation operator.
Greater Than Or Equal To.
Element-Wise Identical To.
Element-Wise Not Equal To.
Binary null check operator.
Try-Catch-Finally operator.
Dynamic function call operator
Represents a list of elements.
ScriptNode[] Elements
Elements.
Represents an implicit string to be printed.
Conjugate Transpose operator.
Creates a matrix using a DO-WHILE statement.
Creates a matrix using a FOR statement.
Creates a matrix using a FOREACH statement.
Creates a matrix using a WHILE-DO statement.
string Name
Name of method.
Named method call operator.
Named function call operator
Creates an object from nothing.
Represents a sequence of statements.
Defines a set, by implicitly limiting its members to members of an optional superset,...
Creates a set using a DO-WHILE statement.
Creates a set using a FOR statement.
Creates a set using a FOREACH statement.
Creates a set using a WHILE-DO statement.
Cartesian-product operator.
Defines a vector, by implicitly limiting its members to members of an optional vector,...
Creates a vector using a DO-WHILE statement.
Creates a vector using a FOR statement.
Creates a vector using a FOREACH statement.
Creates a vector using a WHILE-DO statement.
Converts values of type String to expression strings.
string GetString(object Value)
Gets a string representing a value.
Performs a sequence of type conversions to convert an object from one type to another.
double Weight
Weight of the converter. An estimate of how well the converter performs, or how much information is r...
Static class managing units.
static bool TryParsePrefix(char ch, out Prefix Prefix)
Tries to parse a character into a prefix.
A unit factor, used to form compound units.
int Exponent
Exponent of the unit factor.
AtomicUnit Unit
Unit factor, without its exponent.
ICollection< UnitFactor > Factors
Sequence of atomic unit factors, and their corresponding exponents.
Contains information about a variable.
ValuePrinter Printer
Delegate that converts values to strings for (implicit) printing. Default is null,...
virtual bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
Basic interface for all types of elements.
object AssociatedObjectValue
Associated object value.
Basic interface for all types of sets.
Base interface for constants that integrate into the script engine.
string[] Aliases
Optional aliases. If there are no aliases for the constant, null is returned.
string ConstantName
Name of the constant
Base interface for functions that integrate into the script engine.
Interface for keywords with custom parsing.
string[] InternalKeywords
Any keywords used internally by the custom parser.
string[] Aliases
Keyword aliases, if available, null if none.
string KeyWord
Keyword associated with custom parser.
Interface for objects that can be represented as a physical quantity.
Interface for custom string output classes. Converts objects of a given type to an expression string.
Converts an object of one type to an object of another type.
Type To
Converter converts objects to this type.
double Weight
Weight of the converter. An estimate of how well the converter performs, or how much information is r...
Type From
Converter converts objects of this type.
class ContextSpecific(int Tag, Array Elements, byte[] SubSection)
A context-specific object (or set of objects).
delegate bool ScriptNodeEventHandler(ScriptNode Node, out ScriptNode NewNode, object State)
Delegate for ScriptNode callback methods.
ArgumentType
Type of parameter used in a function definition or a lambda definition.
SearchMethod
Method to traverse the expression structure
Prefix
SI prefixes. http://physics.nist.gov/cuu/Units/prefixes.html
delegate Task< string > ValuePrinter(object Value, Variables Variables)
Converts a value to a printable string.