3using System.Reflection;
4using System.Collections;
5using System.Collections.Generic;
31using System.Threading.Tasks;
40 private readonly
static object searchSynch =
new object();
41 private static Dictionary<Type, Dictionary<Type, ITypeConverter>> converters =
null;
42 private static Dictionary<string, FunctionRef> functions =
null;
43 private static Dictionary<string, IConstant> constants =
null;
44 private static Dictionary<string, IKeyWord> customKeyWords =
null;
45 private static readonly Dictionary<Type, ICustomStringOutput> output =
new Dictionary<Type, ICustomStringOutput>();
46 internal static readonly Dictionary<string, bool> keywords = GetKeywords();
49 private readonly
string script;
50 private readonly
string source;
53 private readonly
int len;
54 private bool containsImplicitPrint =
false;
55 private bool canSkipWhitespace =
true;
76 this.len = this.script.Length;
78 this.root = this.ParseSequence();
79 if (this.pos < this.len)
80 throw new SyntaxException(
"Unexpected end of script.", this.pos, this.script);
85 Types.OnInvalidated += Types_OnInvalidated;
88 private static void Types_OnInvalidated(
object Sender, EventArgs e)
99 private static Dictionary<string, bool> GetKeywords()
101 Dictionary<string, bool> Result =
new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase)
105 {
"CARTESIAN",
true },
117 {
"INHERITS",
true },
118 {
"INTERSECT",
true },
119 {
"INTERSECTION",
true },
142 if (customKeyWords is
null)
145 foreach (
IKeyWord KeyWord
in customKeyWords.Values)
147 Result[KeyWord.
KeyWord.ToUpper()] =
true;
149 string[] Aliases = KeyWord.
Aliases;
150 if (!(Aliases is
null))
152 foreach (
string s
in Aliases)
153 Result[s.ToUpper()] =
true;
157 if (!(Aliases is
null))
159 foreach (
string s
in Aliases)
160 Result[s.ToUpper()] =
true;
167 internal int Position => this.pos;
169 internal bool EndOfScript => this.pos >= this.len;
170 internal bool InScript => this.pos < this.len;
172 internal bool CanSkipWhitespace
174 get => this.canSkipWhitespace;
175 set => this.canSkipWhitespace = value;
188 internal char NextChar()
190 if (this.pos < this.len)
191 return this.script[this.pos++];
196 internal void UndoChar()
202 internal char PeekNextChar()
204 if (this.pos < this.len)
205 return this.script[this.pos];
210 internal string PeekNextChars(
int NrChars)
212 if (this.pos + NrChars > this.len)
213 NrChars = this.len - this.pos;
218 return this.script.Substring(this.pos, NrChars);
221 internal bool IsNextChars(
string Token)
223 int c = Token.Length;
227 if (this.pos + c > this.len)
232 for (i = 0; i < c; i++)
234 if (this.script[this.pos + i] != Token[i])
241 internal bool IsNextChars(
char ch,
int Count)
246 if (this.pos + Count > this.len)
251 for (i = 0; i < Count; i++)
253 if (this.script[this.pos + i] != ch)
260 internal void SkipChars(
int NrChars)
265 internal string NextToken()
267 this.SkipWhiteSpace();
269 if (this.pos >= this.len)
272 int Start = this.pos;
273 char ch = this.script[this.pos];
275 if (
char.IsLetter(ch))
277 while (this.pos < this.len &&
char.IsLetterOrDigit(this.script[this.pos]))
280 else if (
char.IsDigit(ch))
282 while (this.pos < this.len &&
char.IsDigit(this.script[this.pos]))
285 else if (
char.IsSymbol(ch))
287 while (this.pos < this.len &&
char.IsSymbol(this.script[this.pos]))
293 return this.script.Substring(Start, this.pos - Start);
296 internal string PeekNextToken()
299 string Token = this.NextToken();
305 internal void SkipWhiteSpace()
307 if (this.canSkipWhitespace)
311 while (this.pos < this.len && ((ch = this.script[this.pos]) <=
' ' || ch == 160))
327 throw new SyntaxException(
"Right operand missing.", this.pos, this.script);
335 this.SkipWhiteSpace();
339 while (Node is
null && this.PeekNextChar() ==
';')
342 Node = this.ParseStatement(
true);
343 this.SkipWhiteSpace();
350 int Start = Node.
Start;
352 if (!(Node is
null) && this.PeekNextChar() ==
';')
356 if (!(Node2 is
null))
358 LinkedList<ScriptNode> Statements =
new LinkedList<ScriptNode>();
359 Statements.AddLast(Node);
360 Statements.AddLast(Node2);
362 this.SkipWhiteSpace();
363 while (this.PeekNextChar() ==
';')
366 Node2 = this.ParseStatement(
true);
370 Statements.AddLast(Node2);
371 this.SkipWhiteSpace();
374 Node =
new Sequence(Statements, Start, this.pos - Start,
this);
381 internal ScriptNode ParseStatement(
bool ParseLists)
383 this.SkipWhiteSpace();
385 int Start = this.pos;
387 switch (
char.ToUpper(this.PeekNextChar()))
390 if (
string.Compare(this.PeekNextToken(),
"DO",
true) == 0)
394 ScriptNode Statement = this.AssertOperandNotNull(this.ParseStatement(
false));
396 this.SkipWhiteSpace();
397 if (
string.Compare(this.PeekNextToken(),
"WHILE",
true) != 0)
402 ScriptNode Condition = this.AssertOperandNotNull(this.ParseIf());
404 return new DoWhile(Statement, Condition, Start, this.pos - Start,
this);
407 return ParseLists ? this.ParseList() : this.ParseIf();
410 if (
string.Compare(this.PeekNextToken(),
"WHILE",
true) == 0)
414 ScriptNode Condition = this.AssertOperandNotNull(this.ParseIf());
416 this.SkipWhiteSpace();
417 if (this.PeekNextChar() ==
':')
419 else if (
string.Compare(this.PeekNextToken(),
"DO",
true) == 0)
424 ScriptNode Statement = this.AssertOperandNotNull(this.ParseStatement(
false));
426 return new WhileDo(Condition, Statement, Start, this.pos - Start,
this);
429 return ParseLists ? this.ParseList() : this.ParseIf();
432 switch (this.PeekNextToken().ToUpper())
436 if (!(this.AssertOperandNotNull(this.ParseIf()) is
In In))
437 throw new SyntaxException(
"IN statement expected", this.pos, this.script);
443 this.SkipWhiteSpace();
444 if (this.PeekNextChar() ==
':')
446 else if (
string.Compare(this.PeekNextToken(),
"DO",
true) == 0)
451 ScriptNode Statement = this.AssertOperandNotNull(this.ParseStatement(
false));
457 this.SkipWhiteSpace();
459 if (
string.Compare(this.PeekNextToken(),
"EACH",
true) == 0)
462 In = this.AssertOperandNotNull(this.ParseIf()) as
In;
464 throw new
SyntaxException("IN statement expected", this.pos, this.script);
470 this.SkipWhiteSpace();
471 if (this.PeekNextChar() == ':')
473 else if (
string.Compare(this.PeekNextToken(), "DO", true) == 0)
478 Statement = this.AssertOperandNotNull(this.ParseStatement(false));
480 return new
ForEach(Ref.VariableName,
In.RightOperand, Statement, Start, this.pos - Start, this);
485 throw new SyntaxException(
"Assignment expected", this.pos, this.script);
487 this.SkipWhiteSpace();
488 if (
string.Compare(this.PeekNextToken(),
"TO",
true) != 0)
493 ScriptNode To = this.AssertOperandNotNull(this.ParseIf());
496 this.SkipWhiteSpace();
497 if (
string.Compare(this.PeekNextToken(),
"STEP",
true) == 0)
500 Step = this.AssertOperandNotNull(this.ParseIf());
505 this.SkipWhiteSpace();
506 if (this.PeekNextChar() ==
':')
508 else if (
string.Compare(this.PeekNextToken(),
"DO",
true) == 0)
513 Statement = this.AssertOperandNotNull(this.ParseStatement(
false));
519 return ParseLists ? this.ParseList() : this.ParseIf();
523 if (
string.Compare(this.PeekNextToken(),
"TRY",
true) == 0)
527 ScriptNode Statement = this.AssertOperandNotNull(this.ParseStatement(
false));
529 this.SkipWhiteSpace();
530 switch (this.PeekNextToken().ToUpper())
534 ScriptNode Finally = this.AssertOperandNotNull(this.ParseStatement(
false));
535 return new TryFinally(Statement, Finally, Start, this.pos - Start,
this);
539 ScriptNode Catch = this.AssertOperandNotNull(this.ParseStatement(
false));
541 this.SkipWhiteSpace();
542 if (
string.Compare(this.PeekNextToken(),
"FINALLY",
true) == 0)
545 Finally = this.AssertOperandNotNull(this.ParseStatement(
false));
546 return new TryCatchFinally(Statement, Catch, Finally, Start, this.pos - Start,
this);
549 return new TryCatch(Statement, Catch, Start, this.pos - Start,
this);
552 throw new SyntaxException(
"Expected CATCH or FINALLY.", this.pos, this.script);
556 return ParseLists ? this.ParseList() : this.ParseIf();
560 if (this.PeekNextChar() ==
']')
564 StringBuilder sb =
new StringBuilder();
567 while ((ch = this.NextChar()) !=
'[' || this.PeekNextChar() !=
'[')
576 this.containsImplicitPrint =
true;
577 return new ImplicitPrint(sb.ToString(), Start,
this.pos - Start,
this);
582 return ParseLists ? this.ParseList() : this.ParseIf();
586 return ParseLists ? this.ParseList() : this.ParseIf();
600 this.SkipWhiteSpace();
601 if (this.PeekNextChar() ==
',')
603 List<ScriptNode> Elements =
new List<ScriptNode>()
608 while (this.PeekNextChar() ==
',')
611 Node = this.ParseIf();
615 this.SkipWhiteSpace();
618 Node =
new ElementList(Elements.ToArray(), Start,
this.pos - Start,
this);
626 this.SkipWhiteSpace();
631 int Start = this.pos;
633 if (
char.ToUpper(this.PeekNextChar()) ==
'I' &&
string.Compare(this.PeekNextToken(),
"IF",
true) == 0)
636 this.SkipWhiteSpace();
638 Condition = this.AssertOperandNotNull(this.ParseAssignments());
640 this.SkipWhiteSpace();
641 if (
string.Compare(this.PeekNextToken(),
"THEN",
true) == 0)
646 IfTrue = this.AssertOperandNotNull(this.ParseStatement(
false));
648 this.SkipWhiteSpace();
649 if (
string.Compare(this.PeekNextToken(),
"ELSE",
true) == 0)
652 IfFalse = this.AssertOperandNotNull(this.ParseStatement(
false));
659 Condition = this.ParseAssignments();
660 if (Condition is
null)
663 this.SkipWhiteSpace();
664 if (this.PeekNextChar() !=
'?')
669 switch (this.PeekNextChar())
680 if (this.PeekNextChar() ==
'?')
683 IfTrue = this.AssertOperandNotNull(this.ParseStatement(
false));
684 return new TryCatch(Condition, IfTrue, Start, this.pos - Start,
this);
688 IfTrue = this.AssertOperandNotNull(this.ParseStatement(
false));
689 return new NullCheck(Condition, IfTrue, Start, this.pos - Start,
this);
693 IfTrue = this.AssertOperandNotNull(this.ParseStatement(
false));
695 this.SkipWhiteSpace();
696 if (this.PeekNextChar() ==
':')
699 IfFalse = this.AssertOperandNotNull(this.ParseStatement(
false));
708 return new If(Condition, IfTrue, IfFalse, Start, this.pos - Start,
this);
713 ScriptNode Left = this.ParseLambdaExpression();
717 int Start = Left.
Start;
720 this.SkipWhiteSpace();
722 switch (this.PeekNextChar())
726 if (this.PeekNextChar() ==
'=')
729 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
749 List<string> ArgumentNames =
new List<string>();
750 List<ArgumentType> ArgumentTypes =
new List<ArgumentType>();
761 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
762 Argument.
Start,
this.script);
771 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
772 Argument.
Start,
this.script);
781 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
782 Argument.
Start,
this.script);
789 if (Def.Elements.Length != 1 || (Ref = Def.Elements[0] as
VariableReference) is
null)
791 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
792 Argument.
Start,
this.script);
801 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
802 Argument.
Start,
this.script);
812 return new FunctionDefinition(f.FunctionName, ArgumentNames.ToArray(), ArgumentTypes.ToArray(), Right, Start,
this.pos - Start,
this);
815 return new PatternMatch(Left, Right, Start, this.pos - Start,
this);
825 if (this.PeekNextChar() ==
'=')
829 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
832 return new Operators.Assignments.WithSelf.AddToSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
844 throw new SyntaxException(
"Invalid use of the += operator.", this.pos, this.script);
854 if (this.PeekNextChar() ==
'=')
858 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
861 return new Operators.Assignments.WithSelf.SubtractFromSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
873 throw new SyntaxException(
"Invalid use of the -= operator.", this.pos, this.script);
884 if (this.PeekNextChar() ==
'=')
888 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
891 return new Operators.Assignments.WithSelf.MultiplyWithSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
903 throw new SyntaxException(
"Invalid use of the *= operator.", this.pos, this.script);
913 if (this.PeekNextChar() ==
'=')
917 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
920 return new Operators.Assignments.WithSelf.DivideFromSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
932 throw new SyntaxException(
"Invalid use of the /= operator.", this.pos, this.script);
942 if (this.PeekNextChar() ==
'=')
946 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
949 return new Operators.Assignments.WithSelf.PowerOfSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
961 throw new SyntaxException(
"Invalid use of the ^= operator.", this.pos, this.script);
971 switch (this.PeekNextChar())
976 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
979 return new Operators.Assignments.WithSelf.BinaryAndWithSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
991 throw new SyntaxException(
"Invalid use of the &= operator.", this.pos, this.script);
995 if (this.PeekNextChar() ==
'=')
999 Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1002 return new Operators.Assignments.WithSelf.LogicalAndWithSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1014 throw new SyntaxException(
"Invalid use of the &&= operator.", this.pos, this.script);
1029 switch (this.PeekNextChar())
1034 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1037 return new Operators.Assignments.WithSelf.BinaryOrWithSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1049 throw new SyntaxException(
"Invalid use of the |= operator.", this.pos, this.script);
1053 if (this.PeekNextChar() ==
'=')
1057 Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1060 return new Operators.Assignments.WithSelf.LogicalOrWithSelf(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1072 throw new SyntaxException(
"Invalid use of the ||= operator.", this.pos, this.script);
1087 if (this.PeekNextChar() ==
'<')
1090 if (this.PeekNextChar() ==
'=')
1094 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1097 return new Operators.Assignments.WithSelf.ShiftSelfLeft(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1109 throw new SyntaxException(
"Invalid use of the <<= operator.", this.pos, this.script);
1125 if (this.PeekNextChar() ==
'>')
1128 if (this.PeekNextChar() ==
'=')
1132 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseStatement(
false));
1135 return new Operators.Assignments.WithSelf.ShiftSelfRight(Ref.
VariableName, Right, Start,
this.pos - Start,
this);
1147 throw new SyntaxException(
"Invalid use of the >>= operator.", this.pos, this.script);
1172 this.SkipWhiteSpace();
1174 if (this.PeekNextChar() ==
'-')
1177 if (this.PeekNextChar() ==
'>')
1181 int Start = Left.
Start;
1182 string[] ArgumentNames;
1187 ArgumentNames =
new string[] { Ref.VariableName };
1188 ArgumentTypes =
new ArgumentType[] { ArgumentType.Normal };
1195 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1196 Left.
Start,
this.script);
1199 ArgumentNames =
new string[] { Ref.VariableName };
1200 ArgumentTypes =
new ArgumentType[] { ArgumentType.Vector };
1207 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1208 Left.
Start,
this.script);
1211 ArgumentNames =
new string[] { Ref.VariableName };
1212 ArgumentTypes =
new ArgumentType[] { ArgumentType.Matrix };
1219 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1220 Left.
Start,
this.script);
1223 ArgumentNames =
new string[] { Ref.VariableName };
1224 ArgumentTypes =
new ArgumentType[] { ArgumentType.Set };
1228 if (Def.Elements.Length != 1 || (Ref = Def.Elements[0] as
VariableReference) is
null)
1230 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1231 Left.
Start,
this.script);
1234 ArgumentNames =
new string[] { Ref.VariableName };
1235 ArgumentTypes =
new ArgumentType[] { ArgumentType.Scalar };
1243 ArgumentNames =
new string[c];
1246 for (i = 0; i < c; i++)
1252 else if (Argument is
ToVector ToVector2)
1257 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1258 Argument.
Start,
this.script);
1263 else if (Argument is
ToMatrix ToMatrix2)
1268 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1269 Argument.
Start,
this.script);
1274 else if (Argument is
ToSet ToSet2)
1279 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1280 Argument.
Start,
this.script);
1287 if (Def2.Elements.Length != 1 || (Ref = Def2.Elements[0] as
VariableReference) is
null)
1289 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1290 Left.
Start,
this.script);
1297 throw new SyntaxException(
"Expected variable reference, with optional scalar, vector, set or matrix attribute types.",
1298 Argument.
Start,
this.script);
1301 ArgumentNames[i] = Ref.VariableName;
1307 if (!(this.ParseEquivalence() is
ScriptNode Operand))
1308 throw new SyntaxException(
"Lambda function body missing.", this.pos, this.script);
1310 return new LambdaDefinition(ArgumentNames, ArgumentTypes, Operand, Start, this.pos - Start,
this);
1325 int Start = Left.
Start;
1328 this.SkipWhiteSpace();
1330 if ((ch = this.PeekNextChar()) ==
'=')
1335 if (this.PeekNextChar() ==
'>')
1338 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseOrs());
1339 return new Implication(Left, Right, Start, this.pos - Start,
this);
1349 if (this.PeekNextChar() ==
'=')
1352 if (this.PeekNextChar() ==
'>')
1355 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseOrs());
1356 return new Equivalence(Left, Right, Start, this.pos - Start,
this);
1373 int Start = Left.
Start;
1377 this.SkipWhiteSpace();
1378 switch (
char.ToUpper(this.PeekNextChar()))
1382 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1383 Left =
new Operators.Logical.Or(Left, Right, Start, this.pos - Start,
this);
1388 switch (this.PeekNextChar())
1392 if (this.PeekNextChar() ==
'=')
1398 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1399 Left =
new Operators.Logical.Or(Left, Right, Start, this.pos - Start,
this);
1407 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1408 Left =
new Operators.Binary.Or(Left, Right, Start, this.pos - Start,
this);
1416 switch (this.PeekNextToken().ToUpper())
1420 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1421 Left =
new Operators.Dual.Or(Left, Right, Start, this.pos - Start,
this);
1426 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1427 Left =
new Operators.Dual.Xor(Left, Right, Start, this.pos - Start,
this);
1432 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1433 Left =
new Operators.Dual.Xnor(Left, Right, Start, this.pos - Start,
this);
1438 Right = this.AssertRightOperandNotNull(this.ParseAnds());
1439 Left =
new Operators.Dual.Nor(Left, Right, Start, this.pos - Start,
this);
1459 int Start = Left.
Start;
1463 this.SkipWhiteSpace();
1464 switch (
char.ToUpper(this.PeekNextChar()))
1468 Right = this.AssertRightOperandNotNull(this.ParseMembership());
1469 Left =
new Operators.Logical.And(Left, Right, Start, this.pos - Start,
this);
1474 switch (this.PeekNextChar())
1478 if (this.PeekNextChar() ==
'=')
1484 Right = this.AssertRightOperandNotNull(this.ParseMembership());
1485 Left =
new Operators.Logical.And(Left, Right, Start, this.pos - Start,
this);
1493 Right = this.AssertRightOperandNotNull(this.ParseMembership());
1494 Left =
new Operators.Binary.And(Left, Right, Start, this.pos - Start,
this);
1501 switch (this.PeekNextToken().ToUpper())
1505 Right = this.AssertRightOperandNotNull(this.ParseMembership());
1506 Left =
new Operators.Dual.And(Left, Right, Start, this.pos - Start,
this);
1511 Right = this.AssertRightOperandNotNull(this.ParseMembership());
1512 Left =
new Operators.Dual.Nand(Left, Right, Start, this.pos - Start,
this);
1532 int Start = Left.
Start;
1536 this.SkipWhiteSpace();
1537 switch (
char.ToUpper(this.PeekNextChar()))
1545 switch (this.PeekNextToken().ToUpper())
1550 this.SkipWhiteSpace();
1551 if (
string.Compare(this.PeekNextToken(),
"NOT",
true) == 0)
1554 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1555 Left =
new IsNot(Left, Right, Start, this.pos - Start,
this);
1559 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1560 Left =
new Is(Left, Right, Start, this.pos - Start,
this);
1566 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1567 Left =
new Inherits(Left, Right, Start, this.pos - Start,
this);
1572 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1573 Left =
new As(Left, Right, Start, this.pos - Start,
this);
1578 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1579 Left =
new Matches(Left, Right, Start, this.pos - Start,
this);
1584 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1585 Left =
new In(Left, Right, Start, this.pos - Start,
this);
1590 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1591 Left =
new In(Left, Right, Start, this.pos - Start,
this);
1596 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1597 Left =
new NotIn(Left, Right, Start, this.pos - Start,
this);
1602 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1603 Left =
new NotIn(Left, Right, Start, this.pos - Start,
this);
1610 this.SkipWhiteSpace();
1611 if (
string.Compare(this.PeekNextToken(),
"IN",
true) == 0)
1614 Right = this.AssertRightOperandNotNull(this.ParseComparison());
1615 Left =
new NotIn(Left, Right, Start, this.pos - Start,
this);
1641 int Start = Left.
Start;
1646 this.SkipWhiteSpace();
1647 switch (
char.ToUpper(this.PeekNextChar()))
1651 if ((ch = this.PeekNextChar()) ==
'=')
1655 if (this.PeekNextChar() ==
'>')
1662 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1664 Left =
new Range(LT.LeftOperand, LT.RightOperand, Right,
false,
true, LT.Start, Right.
Start + Right.
Length - LT.Start,
this);
1666 Left =
new Range(LTE.LeftOperand, LTE.RightOperand, Right,
true,
true, LTE.Start, Right.
Start + Right.
Length - LTE.Start,
this);
1674 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1675 Left =
new NotEqualTo(Left, Right, Start, this.pos - Start,
this);
1680 if (this.PeekNextChar() ==
'>')
1688 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1689 Left =
new LesserThan(Left, Right, Start, this.pos - Start,
this);
1699 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1701 Left =
new Range(LT.LeftOperand, LT.RightOperand, Right,
false,
false, LT.Start, Right.
Start + Right.
Length - LT.Start,
this);
1703 Left =
new Range(LTE.LeftOperand, LTE.RightOperand, Right,
true,
false, LTE.Start, Right.
Start + Right.
Length - LTE.Start,
this);
1705 Left =
new LesserThan(Left, Right, Start, this.pos - Start,
this);
1711 if ((ch = this.PeekNextChar()) ==
'=')
1714 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1716 Left =
new Range(Right, GT.RightOperand, GT.LeftOperand,
true,
false, GT.Start, Right.
Start + Right.
Length - GT.Start,
this);
1718 Left =
new Range(Right, GTE.RightOperand, GTE.LeftOperand,
true,
true, GTE.Start, Right.
Start + Right.
Length - GTE.Start,
this);
1729 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1731 Left =
new Range(Right, GT.RightOperand, GT.LeftOperand,
false,
false, GT.Start, Right.
Start + Right.
Length - GT.Start,
this);
1733 Left =
new Range(Right, GTE.RightOperand, GTE.LeftOperand,
false,
true, GTE.Start, Right.
Start + Right.
Length - GTE.Start,
this);
1735 Left =
new GreaterThan(Left, Right, Start, this.pos - Start,
this);
1741 if ((ch = this.PeekNextChar()) ==
'=')
1744 if (this.PeekNextChar() ==
'=')
1747 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1748 Left =
new IdenticalTo(Left, Right, Start, this.pos - Start,
this);
1752 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1753 Left =
new EqualTo(Left, Right, Start, this.pos - Start,
this);
1763 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1764 Left =
new EqualTo(Left, Right, Start, this.pos - Start,
this);
1770 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1771 Left =
new NotEqualTo(Left, Right, Start, this.pos - Start,
this);
1776 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1777 Left =
new IdenticalTo(Left, Right, Start, this.pos - Start,
this);
1782 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1785 Left =
new Range(LT.LeftOperand, LT.RightOperand, Right,
false,
true, LT.Start, Right.
Start + Right.
Length - LT.Start,
this);
1787 Left =
new Range(LTE.LeftOperand, LTE.RightOperand, Right,
true,
true, LTE.Start, Right.
Start + Right.
Length - LTE.Start,
this);
1795 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1798 Left =
new Range(Right, GT.RightOperand, GT.LeftOperand,
true,
false, GT.Start, Right.
Start + Right.
Length - GT.Start,
this);
1800 Left =
new Range(Right, GTE.RightOperand, GTE.LeftOperand,
true,
true, GTE.Start, Right.
Start + Right.
Length - GTE.Start,
this);
1808 if (this.PeekNextChar() ==
'=')
1811 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1812 Left =
new NotEqualTo(Left, Right, Start, this.pos - Start,
this);
1823 switch (this.PeekNextChar())
1827 if (this.PeekNextChar() ==
'=')
1830 if (this.PeekNextChar() ==
'=')
1833 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1838 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1844 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1851 if (this.PeekNextChar() ==
'>')
1854 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1866 if (this.PeekNextChar() ==
'=')
1869 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1887 switch (this.PeekNextToken().ToUpper())
1891 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1892 Left =
new Like(Left, Right, Start, this.pos - Start,
this);
1897 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1898 Left =
new NotLike(Left, Right, Start, this.pos - Start,
this);
1903 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1904 Left =
new NotLike(Left, Right, Start, this.pos - Start,
this);
1910 this.SkipWhiteSpace();
1911 if (
string.Compare(this.PeekNextToken(),
"LIKE",
true) == 0)
1914 Right = this.AssertRightOperandNotNull(this.ParseShifts());
1915 Left =
new NotLike(Left, Right, Start, this.pos - Start,
this);
1941 int Start = Left.
Start;
1945 this.SkipWhiteSpace();
1946 switch (this.PeekNextChar())
1950 if (this.PeekNextChar() ==
'<')
1953 if (this.PeekNextChar() ==
'=')
1959 Right = this.AssertRightOperandNotNull(this.ParseUnions());
1960 Left =
new ShiftLeft(Left, Right, Start, this.pos - Start,
this);
1971 if (this.PeekNextChar() ==
'>')
1974 if (this.PeekNextChar() ==
'=')
1980 Right = this.AssertRightOperandNotNull(this.ParseUnions());
1981 Left =
new ShiftRight(Left, Right, Start, this.pos - Start,
this);
2003 int Start = Left.
Start;
2008 this.SkipWhiteSpace();
2009 if (
char.ToUpper(ch = this.PeekNextChar()) ==
'U')
2011 if (
string.Compare(this.PeekNextToken(),
"UNION",
true) == 0)
2014 Right = this.AssertRightOperandNotNull(this.ParseIntersections());
2015 Left =
new Union(Left, Right, Start, this.pos - Start,
this);
2023 Right = this.AssertRightOperandNotNull(this.ParseIntersections());
2024 Left =
new Union(Left, Right, Start, this.pos - Start,
this);
2038 int Start = Left.
Start;
2043 this.SkipWhiteSpace();
2044 if (
char.ToUpper(ch = this.PeekNextChar()) ==
'I')
2046 switch (this.PeekNextToken().ToUpper())
2048 case "INTERSECTION":
2050 Right = this.AssertRightOperandNotNull(this.ParseInterval());
2051 Left =
new Intersection(Left, Right, Start, this.pos - Start,
this);
2056 Right = this.AssertRightOperandNotNull(this.ParseInterval());
2057 Left =
new Intersection(Left, Right, Start, this.pos - Start,
this);
2067 Right = this.AssertRightOperandNotNull(this.ParseInterval());
2068 Left =
new Intersection(Left, Right, Start, this.pos - Start,
this);
2081 this.SkipWhiteSpace();
2082 if (this.PeekNextChar() !=
'.')
2086 if (this.PeekNextChar() !=
'.')
2093 ScriptNode To = this.AssertRightOperandNotNull(this.ParseTerms());
2094 int Start = From.
Start;
2096 this.SkipWhiteSpace();
2097 if (this.PeekNextChar() ==
'|')
2100 ScriptNode StepSize = this.AssertRightOperandNotNull(this.ParseTerms());
2101 return new Interval(From, To, StepSize, Start, this.pos - Start,
this);
2104 return new Interval(From, To, Start, this.pos - Start,
this);
2109 ScriptNode Left = this.ParseBinomialCoefficients();
2114 int Start = Left.
Start;
2119 this.SkipWhiteSpace();
2120 switch (this.PeekNextChar())
2124 ch = this.PeekNextChar();
2126 if (ch ==
'=' || ch ==
'+')
2135 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2140 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2141 Left =
new Add(Left, Right, Start, this.pos - Start,
this);
2147 if ((ch = this.PeekNextChar()) ==
'=' || ch ==
'>' || ch ==
'-')
2153 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2154 Left =
new Subtract(Left, Right, Start, this.pos - Start,
this);
2159 switch (this.PeekNextChar())
2163 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2164 Left =
new AddElementWise(Left, Right, Start, this.pos - Start,
this);
2169 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2181 Right = this.AssertRightOperandNotNull(this.ParseBinomialCoefficients());
2191 internal ScriptNode ParseBinomialCoefficients()
2198 int Start = Left.
Start;
2202 this.SkipWhiteSpace();
2203 if (
char.ToUpper(this.PeekNextChar()) ==
'O' &&
string.Compare(this.PeekNextToken(),
"OVER",
true) == 0)
2206 Right = this.AssertRightOperandNotNull(this.ParseFactors());
2221 int Start = Left.
Start;
2225 this.SkipWhiteSpace();
2226 switch (
char.ToUpper(this.PeekNextChar()))
2231 if (this.PeekNextChar() ==
'=')
2237 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2238 Left =
new Multiply(Left, Right, Start, this.pos - Start,
this);
2243 if (this.PeekNextChar() ==
'=')
2249 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2250 Left =
new Divide(Left, Right, Start, this.pos - Start,
this);
2255 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2256 Left =
new LeftDivide(Left, Right, Start, this.pos - Start,
this);
2260 switch (this.PeekNextToken().ToUpper())
2264 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2265 Left =
new CrossProduct(Left, Right, Start, this.pos - Start,
this);
2270 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2279 if (
string.Compare(this.PeekNextToken(),
"DOT",
true) == 0)
2282 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2283 Left =
new DotProduct(Left, Right, Start, this.pos - Start,
this);
2290 if (
string.Compare(this.PeekNextToken(),
"MOD",
true) == 0)
2293 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2294 Left =
new Residue(Left, Right, Start, this.pos - Start,
this);
2302 switch (
char.ToUpper(this.PeekNextChar()))
2307 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2313 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2319 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2324 if (
string.Compare(this.PeekNextToken(),
"MOD",
true) == 0)
2327 Right = this.AssertRightOperandNotNull(this.ParsePowers());
2350 ScriptNode Left = this.ParseUnaryPrefixOperator();
2355 int Start = Left.
Start;
2359 this.SkipWhiteSpace();
2360 switch (this.PeekNextChar())
2364 if (this.PeekNextChar() ==
'=')
2370 Right = this.AssertRightOperandNotNull(this.ParseUnaryPrefixOperator());
2371 Left =
new Power(Left, Right, Start, this.pos - Start,
this);
2376 Left =
new Square(Left, Start, this.pos - Start,
this);
2381 Left =
new Cube(Left, Start, this.pos - Start,
this);
2386 switch (this.PeekNextChar())
2390 Right = this.AssertRightOperandNotNull(this.ParseUnaryPrefixOperator());
2405 internal ScriptNode ParseUnaryPrefixOperator()
2407 this.SkipWhiteSpace();
2409 int Start = this.pos;
2412 switch (
char.ToUpper(this.PeekNextChar()))
2416 if ((ch = this.PeekNextChar()) ==
'-')
2420 ScriptNode Op = this.ParseUnaryPrefixOperator();
2423 return new Operators.Assignments.Pre.PreDecrement(Ref.VariableName, Start,
this.pos - Start,
this);
2435 throw new SyntaxException(
"Invalid use of the -- operator.", this.pos, this.script);
2437 else if ((ch >=
'0' && ch <=
'9') || (ch ==
'.'))
2440 return this.ParseSuffixOperator();
2445 return this.ParseSuffixOperator();
2448 return new Negate(this.AssertOperandNotNull(this.ParseFactors()), Start, this.pos - Start,
this);
2452 if ((ch = this.PeekNextChar()) ==
'+')
2456 ScriptNode Op = this.ParseUnaryPrefixOperator();
2459 return new Operators.Assignments.Pre.PreIncrement(Ref.VariableName, Start,
this.pos - Start,
this);
2471 throw new SyntaxException(
"Invalid use of the ++ operator.", this.pos, this.script);
2473 else if ((ch >=
'0' && ch <=
'9') || (ch ==
'.'))
2474 return this.ParseSuffixOperator();
2476 return this.AssertOperandNotNull(this.ParseFactors());
2480 return new Not(this.AssertOperandNotNull(this.ParseUnaryPrefixOperator()), Start, this.pos - Start,
this);
2483 if (
string.Compare(this.PeekNextToken(),
"NOT",
true) == 0)
2486 return new Not(this.AssertOperandNotNull(this.ParseUnaryPrefixOperator()), Start, this.pos - Start,
this);
2489 return this.ParseSuffixOperator();
2493 return new Complement(this.AssertOperandNotNull(this.ParseUnaryPrefixOperator()), Start, this.pos - Start,
this);
2496 return this.ParseSuffixOperator();
2507 int Start = Node.
Start;
2512 this.SkipWhiteSpace();
2513 switch (ch = this.PeekNextChar())
2519 if (this.PeekNextChar() ==
'?')
2526 ScriptNode IfNull = this.AssertOperandNotNull(this.ParseStatement(
false));
2527 Node =
new NullCheck(Node, IfNull, Start, this.pos - Start,
this);
2534 ch = this.PeekNextChar();
2554 ch = this.PeekNextChar();
2555 if (ch ==
'=' || ch ==
'+' || ch ==
'-' || ch ==
'^' || ch ==
'.' || ch ==
'*' || ch ==
'⋅' || ch ==
'/' || ch ==
'\\' || ch ==
'<' || ch ==
'!')
2561 if (
char.ToUpper(ch) ==
'M' &&
string.Compare(this.PeekNextToken(),
"MOD",
true) == 0)
2567 ScriptNode Right = this.AssertRightOperandNotNull(this.ParseObject());
2577 bool WsBak = this.canSkipWhitespace;
2578 this.canSkipWhitespace =
true;
2580 Right = this.ParseList();
2582 this.SkipWhiteSpace();
2583 if (this.PeekNextChar() !=
')')
2586 this.canSkipWhitespace = WsBak;
2612 Node = GetFunction(Ref.VariableName, Right,
NullCheck, Start,
this.pos - Start,
this);
2617 WsBak = this.canSkipWhitespace;
2618 this.canSkipWhitespace =
true;
2620 Right = this.ParseList();
2622 this.SkipWhiteSpace();
2623 if (this.PeekNextChar() !=
']')
2626 this.canSkipWhitespace = WsBak;
2659 this.SkipWhiteSpace();
2660 if (this.PeekNextChar() ==
'}')
2663 Node =
new ToSet(Node,
NullCheck, Start, this.pos - Start,
this);
2674 if (this.PeekNextChar() ==
'+')
2681 Node =
new Operators.Assignments.Post.PostIncrement(Ref.VariableName, Start,
this.pos - Start,
this);
2700 Node =
new MinusOne(Node, Start, this.pos - Start,
this);
2704 throw new SyntaxException(
"Null-checked post increment operator not defined.", this.pos, this.script);
2716 if (this.PeekNextChar() ==
'-')
2723 Node =
new Operators.Assignments.Post.PostDecrement(Ref.VariableName, Start,
this.pos - Start,
this);
2742 Node =
new PlusOne(Node, Start, this.pos - Start,
this);
2746 throw new SyntaxException(
"Null-checked post increment operator not defined.", this.pos, this.script);
2760 throw new SyntaxException(
"Null-checked % operator not defined.", this.pos, this.script);
2762 if (this.PeekNextChar() ==
'0')
2766 if (this.PeekNextChar() ==
'0')
2769 Node =
new Perdiezmil(Node, Start, this.pos - Start,
this);
2772 Node =
new Permil(Node, Start, this.pos - Start,
this);
2775 Node =
new Percent(Node, Start, this.pos - Start,
this);
2782 throw new SyntaxException(
"Null-checked ‰ operator not defined.", this.pos, this.script);
2784 if (this.PeekNextChar() ==
'0')
2787 Node =
new Perdiezmil(Node, Start, this.pos - Start,
this);
2790 Node =
new Permil(Node, Start, this.pos - Start,
this);
2797 throw new SyntaxException(
"Null-checked ‱ operator not defined.", this.pos, this.script);
2799 Node =
new Perdiezmil(Node, Start, this.pos - Start,
this);
2806 throw new SyntaxException(
"Null-checked ° operator not defined.", this.pos, this.script);
2808 if ((ch = this.PeekNextChar()) ==
'C' || ch ==
'F')
2824 Node =
new SetUnit(Node,
Unit, Start, this.pos - Start,
this);
2828 Node =
new DegToRad(Node, Start, this.pos - Start,
this);
2832 Node =
new SetUnit(Node,
Unit, Start, this.pos - Start,
this);
2835 Node =
new DegToRad(Node, Start, this.pos - Start,
this);
2847 throw new SyntaxException(
"Null-checked differencial operators not defined.", this.pos, this.script);
2851 switch (this.PeekNextChar())
2879 ch = this.PeekNextChar();
2880 if (
char.IsLetter(ch) ||
char.IsDigit(ch))
2888 throw new SyntaxException(
"Null-checked T operator not defined.", this.pos, this.script);
2890 Node =
new Transpose(Node, Start, this.pos - Start,
this);
2896 ch = this.PeekNextChar();
2897 if (
char.IsLetter(ch) ||
char.IsDigit(ch))
2905 throw new SyntaxException(
"Null-checked H operator not defined.", this.pos, this.script);
2913 throw new SyntaxException(
"Null-checked † operator not defined.", this.pos, this.script);
2921 throw new SyntaxException(
"Null-checked ! operator not defined.", this.pos, this.script);
2924 switch (this.PeekNextChar())
2928 Node =
new SemiFaculty(Node, Start, this.pos - Start,
this);
2936 Node =
new Faculty(Node, Start, this.pos - Start,
this);
2943 throw new SyntaxException(
"Null-checked unit operator not defined.", this.pos, this.script);
2945 if (
char.IsLetter(ch))
2966 Node =
new SetUnit(Node,
Unit, Start, this.pos - Start,
this);
2974 Node =
new SetUnit(Node,
Unit, Start, this.pos - Start,
this);
2985 internal Unit ParseUnit(
bool PermitPrefix)
2988 LinkedList<KeyValuePair<AtomicUnit, int>> Factors =
new LinkedList<KeyValuePair<AtomicUnit, int>>();
2989 KeyValuePair<Prefix, KeyValuePair<AtomicUnit, int>[]> CompoundFactors;
2990 bool HasCompoundFactors;
2991 string Name, Name2, s;
2992 int Start = this.pos;
2993 int LastCompletion = Start;
2996 char ch = this.NextChar();
2997 bool LastDivision =
false;
3001 if (ch ==
'd' && this.PeekNextChar() ==
'a')
3010 ch = this.NextChar();
3020 this.pos = i = Start;
3022 ch = this.NextChar();
3026 LastDivision =
true;
3027 ch = this.NextChar();
3028 while (ch > 0 && (ch <=
' ' || ch == 160))
3029 ch = this.NextChar();
3032 while (
char.IsLetter(ch) || ch ==
'(')
3044 ch = this.NextChar();
3045 while (ch > 0 && (ch <=
' ' || ch == 160))
3046 ch = this.NextChar();
3051 ch = this.NextChar();
3052 while (ch > 0 && (ch <=
' ' || ch == 160))
3053 ch = this.NextChar();
3057 ch = this.NextChar();
3058 while (ch > 0 && (ch <=
' ' || ch == 160))
3059 ch = this.NextChar();
3061 if (ch ==
'-' ||
char.IsDigit(ch))
3066 ch = this.NextChar();
3068 while (
char.IsDigit(ch))
3069 ch = this.NextChar();
3072 s = this.script.Substring(i, this.pos - i);
3074 s = this.script.Substring(i, this.pos - i - 1);
3076 if (!
int.
TryParse(s, out Exponent))
3091 ch = this.NextChar();
3096 ch = this.NextChar();
3103 foreach (KeyValuePair<AtomicUnit, int> Factor
in Unit.
Factors)
3104 Factors.AddLast(
new KeyValuePair<AtomicUnit, int>(Factor.Key, -Factor.Value * Exponent));
3108 foreach (KeyValuePair<AtomicUnit, int> Factor
in Unit.
Factors)
3109 Factors.AddLast(
new KeyValuePair<AtomicUnit, int>(Factor.Key, Factor.Value * Exponent));
3114 while (
char.IsLetter(ch))
3115 ch = this.NextChar();
3118 Name = this.script.Substring(i, this.pos - i);
3120 Name = this.script.Substring(i, this.pos - i - 1);
3124 if (keywords.ContainsKey(Name2 =
this.script.Substring(Start, i - Start) + Name))
3129 else if (HasCompoundFactors =
Unit.TryGetCompoundUnit(Name2, out CompoundFactors))
3131 Prefix = CompoundFactors.Key;
3134 else if (
Unit.ContainsDerivedOrBaseUnit(Name2))
3140 HasCompoundFactors =
Unit.TryGetCompoundUnit(Name, out CompoundFactors);
3143 HasCompoundFactors =
Unit.TryGetCompoundUnit(Name, out CompoundFactors);
3145 while (ch > 0 && (ch <=
' ' || ch == 160))
3146 ch = this.NextChar();
3150 ch = this.NextChar();
3151 while (ch > 0 && (ch <=
' ' || ch == 160))
3152 ch = this.NextChar();
3154 if (ch ==
'-' ||
char.IsDigit(ch))
3159 ch = this.NextChar();
3161 while (
char.IsDigit(ch))
3162 ch = this.NextChar();
3165 s = this.script.Substring(i, this.pos - i);
3167 s = this.script.Substring(i, this.pos - i - 1);
3169 if (!
int.
TryParse(s, out Exponent))
3184 ch = this.NextChar();
3189 ch = this.NextChar();
3194 if (HasCompoundFactors)
3198 foreach (KeyValuePair<AtomicUnit, int> Segment
in CompoundFactors.Value)
3199 Factors.AddLast(
new KeyValuePair<AtomicUnit, int>(Segment.Key, -Segment.Value * Exponent));
3203 foreach (KeyValuePair<AtomicUnit, int> Segment
in CompoundFactors.Value)
3204 Factors.AddLast(
new KeyValuePair<AtomicUnit, int>(Segment.Key, Segment.Value * Exponent));
3210 Factors.AddLast(
new KeyValuePair<AtomicUnit, int>(
new AtomicUnit(Name), -Exponent));
3212 Factors.AddLast(
new KeyValuePair<AtomicUnit, int>(
new AtomicUnit(Name), Exponent));
3216 while (ch > 0 && (ch <=
' ' || ch == 160))
3217 ch = this.NextChar();
3220 LastCompletion = this.pos;
3222 LastCompletion = this.pos - 1;
3224 if (ch ==
'*' || ch ==
'⋅')
3225 LastDivision =
false;
3227 LastDivision =
true;
3231 ch = this.NextChar();
3232 while (ch > 0 && (ch <=
' ' || ch == 160))
3233 ch = this.NextChar();
3236 PermitPrefix =
false;
3239 this.pos = LastCompletion;
3241 if (Factors.First is
null)
3252 Dictionary<string, FunctionRef> F;
3257 if (Arguments is
null)
3262 else if (Arguments.GetType() == typeof(
ElementList))
3266 P =
new object[NrParameters + 3];
3276 P[NrParameters] = Start;
3277 P[NrParameters + 1] = Length;
3287 if (F.TryGetValue(FunctionName +
" " + NrParameters.ToString(), out FunctionRef Ref))
3288 return (
Function)Ref.Constructor.Invoke(P);
3293 else if (Arguments is
null)
3309 Dictionary<string, IConstant> C = constants;
3316 if (!C.TryGetValue(Name, out
IConstant Constant))
3318 ValueElement =
null;
3323 return !(ValueElement is
null);
3326 internal static LambdaDefinition GetFunctionLambdaDefinition(
string FunctionName,
int Start,
int Length,
3329 Dictionary<string, FunctionRef> F;
3338 if (F.TryGetValue(FunctionName, out FunctionRef Ref))
3340 string[] ArgumentNames = Ref.Function.DefaultArgumentNames;
3341 int i, c = ArgumentNames.Length;
3343 object[] Arguments =
new object[c + 3];
3345 Arguments[c] = Start;
3346 Arguments[c + 1] = Length;
3349 for (i = 0; i < c; i++)
3355 if (Ref.Constructor.GetParameters().Length != c + 3)
3357 if (!F.TryGetValue(FunctionName +
" " + c.ToString(), out Ref))
3369 private static void Search()
3373 if (functions is
null)
3375 Dictionary<int, object[]> ParameterValuesPerNrParameters =
new Dictionary<int, object[]>();
3376 Dictionary<string, FunctionRef> Found =
new Dictionary<string, FunctionRef>(StringComparer.CurrentCultureIgnoreCase);
3377 ParameterInfo[] Parameters;
3378 ParameterInfo PInfo;
3388 TI = T.GetTypeInfo();
3389 if (TI.IsAbstract || TI.IsInterface || TI.IsGenericTypeDefinition)
3392 foreach (ConstructorInfo CI
in TI.DeclaredConstructors)
3394 Parameters = CI.GetParameters();
3399 PInfo = Parameters[c - 1];
3400 if (PInfo.IsOut || PInfo.IsRetval || PInfo.IsOptional || PInfo.ParameterType != typeof(
Expression))
3403 PInfo = Parameters[c - 2];
3404 if (PInfo.IsOut || PInfo.IsRetval || PInfo.IsOptional || PInfo.ParameterType != typeof(
int))
3407 PInfo = Parameters[c - 3];
3408 if (PInfo.IsOut || PInfo.IsRetval || PInfo.IsOptional || PInfo.ParameterType != typeof(
int))
3411 for (i = c - 4; i >= 0; i--)
3413 PInfo = Parameters[i];
3414 if (PInfo.IsOut || PInfo.IsRetval || PInfo.IsOptional || PInfo.ParameterType != typeof(
ScriptNode))
3423 if (!ParameterValuesPerNrParameters.TryGetValue(c, out
object[] ParameterValues))
3425 ParameterValues =
new object[c];
3426 ParameterValues[c - 1] =
null;
3427 ParameterValues[c - 2] = 0;
3428 ParameterValues[c - 3] = 0;
3429 ParameterValuesPerNrParameters[c] = ParameterValues;
3436 s = Function.FunctionName +
" " + (c - 3).
ToString();
3437 if (Found.ContainsKey(s))
3440 " parameters previously registered. Function ignored.",
3441 T.FullName,
new KeyValuePair<string, object>(
"Previous", Found[s].Function.GetType().FullName));
3445 Ref =
new FunctionRef()
3449 NrParameters = c - 3
3459 if (!(Aliases is
null))
3461 foreach (
string Alias
in Aliases)
3463 s = Alias +
" " + (c - 3).
ToString();
3464 if (Found.ContainsKey(s))
3467 " parameters previously registered. Function ignored.",
3468 T.FullName,
new KeyValuePair<string, object>(
"Previous", Found[s].Function.GetType().FullName));
3472 Ref =
new FunctionRef()
3476 NrParameters = c - 3
3481 if (!Found.ContainsKey(Alias))
3487 catch (Exception ex)
3491 if (ex is AggregateException ex2)
3493 foreach (Exception ex3
in ex2.InnerExceptions)
3505 if (constants is
null)
3507 Dictionary<string, IConstant> Found =
new Dictionary<string, IConstant>(StringComparer.CurrentCultureIgnoreCase);
3522 if (Found.TryGetValue(s, out
IConstant PrevConstant))
3524 if (PrevConstant.GetType() != T)
3526 Log.
Warning(
"Constant with name " + s +
" previously registered. Constant ignored.",
3527 T.FullName,
new KeyValuePair<string, object>(
"Previous", Constant.GetType().FullName));
3531 Found[s] = Constant;
3534 if (!(Aliases is
null))
3536 foreach (
string Alias
in Aliases)
3538 if (Found.TryGetValue(Alias, out PrevConstant))
3540 if (PrevConstant.GetType() != T)
3542 Log.
Warning(
"Constant with name " + Alias +
" previously registered. Constant ignored.",
3543 T.FullName,
new KeyValuePair<string, object>(
"Previous", Constant.GetType().FullName));
3547 Found[Alias] = Constant;
3551 catch (Exception ex)
3560 if (customKeyWords is
null)
3562 Dictionary<string, IKeyWord> Found =
new Dictionary<string, IKeyWord>(StringComparer.CurrentCultureIgnoreCase);
3577 if (Found.ContainsKey(s))
3579 Log.
Warning(
"Keyword with name " + s +
" previously registered. Keyword ignored.",
3580 T.FullName,
new KeyValuePair<string, object>(
"Previous", KeyWord.GetType().FullName));
3586 if (!(Aliases is
null))
3588 foreach (
string Alias
in Aliases)
3590 if (Found.ContainsKey(Alias))
3592 Log.
Warning(
"Keyword with name " + Alias +
" previously registered. Keyword ignored.",
3593 T.FullName,
new KeyValuePair<string, object>(
"Previous", KeyWord.GetType().FullName));
3596 Found[Alias] = KeyWord;
3600 catch (Exception ex)
3606 customKeyWords = Found;
3611 private class FunctionRef
3613 public ConstructorInfo Constructor;
3615 public int NrParameters;
3620 this.SkipWhiteSpace();
3623 int Start = this.pos;
3624 char ch = this.PeekNextChar();
3628 bool WsBak = this.canSkipWhitespace;
3629 this.canSkipWhitespace =
true;
3631 Node = this.ParseSequence();
3633 this.SkipWhiteSpace();
3634 if (this.PeekNextChar() !=
')')
3637 this.canSkipWhitespace = WsBak;
3642 this.SkipWhiteSpace();
3643 if (this.PeekNextChar() ==
'-')
3646 if (this.PeekNextChar() ==
'>')
3650 if (!(this.ParseEquivalence() is
ScriptNode Operand))
3651 throw new SyntaxException(
"Lambda function body missing.", this.pos, this.script);
3657 throw new SyntaxException(
"Expected argument-less Lambda expression", this.pos, this.script);
3662 Node.Length = this.pos - Start;
3669 this.SkipWhiteSpace();
3670 if (this.PeekNextChar() ==
']')
3676 bool WsBak = this.canSkipWhitespace;
3677 this.canSkipWhitespace =
true;
3678 Node = this.ParseStatement(
true);
3680 this.SkipWhiteSpace();
3681 switch (this.PeekNextChar())
3685 this.canSkipWhitespace = WsBak;
3718 bool AllVectors =
true;
3722 if (!IsVectorDefinition(
Element))
3734 else if (IsVectorDefinition(Node))
3747 Conditions = List.Elements;
3759 this.SkipWhiteSpace();
3760 if (this.PeekNextChar() !=
']')
3763 this.canSkipWhitespace = WsBak;
3775 this.SkipWhiteSpace();
3776 if (this.PeekNextChar() ==
'}')
3779 return new ObjectExNihilo(
new LinkedList<KeyValuePair<string, ScriptNode>>(), Start, this.pos - Start,
this);
3782 bool WsBak = this.canSkipWhitespace;
3783 this.canSkipWhitespace =
true;
3785 Node = this.ParseStatement(
true);
3787 this.SkipWhiteSpace();
3788 if ((ch = this.PeekNextChar()) ==
':')
3792 bool DoubleColon =
false;
3794 if (this.PeekNextChar() ==
':')
3802 LinkedList<KeyValuePair<string, ScriptNode>> Members =
new LinkedList<KeyValuePair<string, ScriptNode>>();
3803 Dictionary<string, bool> MembersFound =
new Dictionary<string, bool>();
3816 throw new SyntaxException(
"Expected a variable reference or a string constant.", this.pos, this.script);
3818 MembersFound[s] =
true;
3819 Members.AddLast(
new KeyValuePair<string, ScriptNode>(s, this.ParseLambdaExpression()));
3821 this.SkipWhiteSpace();
3822 while ((ch = this.PeekNextChar()) ==
',')
3825 Node = this.ParseStatement(
false);
3827 this.SkipWhiteSpace();
3828 if (this.PeekNextChar() !=
':')
3832 s = VariableReference2.VariableName;
3839 throw new SyntaxException(
"Expected a variable reference or a string constant.", this.pos, this.script);
3841 if (MembersFound.ContainsKey(s))
3842 throw new SyntaxException(
"Member already defined.", this.pos, this.script);
3845 MembersFound[s] =
true;
3846 Members.AddLast(
new KeyValuePair<string, ScriptNode>(s, this.ParseLambdaExpression()));
3848 this.SkipWhiteSpace();
3854 this.canSkipWhitespace = WsBak;
3856 return new ObjectExNihilo(Members, Start, this.pos - Start,
this);
3864 Conditions = List.Elements;
3876 this.SkipWhiteSpace();
3877 if (this.PeekNextChar() !=
'}')
3880 this.canSkipWhitespace = WsBak;
3883 return new ImplicitSetDefinition(Node, SuperSet, Conditions, DoubleColon, Start, this.pos - Start,
this);
3889 this.canSkipWhitespace = WsBak;
3905 else if ((ch >=
'0' && ch <=
'9') || ch ==
'.' || ch ==
'+' || ch ==
'-')
3907 if (ch ==
'+' || ch ==
'-')
3910 ch = this.PeekNextChar();
3913 while (ch >=
'0' && ch <=
'9')
3916 ch = this.PeekNextChar();
3922 ch = this.PeekNextChar();
3924 if (ch >=
'0' && ch <=
'9')
3926 while (ch >=
'0' && ch <=
'9')
3929 ch = this.PeekNextChar();
3939 if (
char.ToUpper(ch) ==
'E')
3942 ch = this.PeekNextChar();
3944 if (ch ==
'+' || ch ==
'-')
3947 ch = this.PeekNextChar();
3950 while (ch >=
'0' && ch <=
'9')
3953 ch = this.PeekNextChar();
3957 if (!
double.
TryParse(this.script.Substring(Start,
this.pos - Start).
3958 Replace(
".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out
double d))
3960 throw new SyntaxException(
"Invalid double number.", this.pos, this.script);
3971 ch = this.PeekNextChar();
3977 ch = this.PeekNextChar();
3982 ch = this.PeekNextChar();
3985 ch =
char.ToLower(ch);
3986 int Start2 = this.pos;
3988 if (ch >=
'0' && ch <=
'9')
3990 else if (ch ==
'd' || ch ==
'x' || ch ==
'o' || ch ==
'b')
3993 Start2 = ++this.pos;
3996 throw new SyntaxException(
"Invalid numberical base.", this.pos, this.script);
3998 BigInteger n = BigInteger.Zero;
4003 while (this.pos < this.len && (ch = this.script[this.pos]) >=
'0' && ch <=
'9')
4006 if (Start2 == this.pos)
4009 n = BigInteger.Parse(this.script.Substring(Start2,
this.pos - Start2));
4014 while (this.pos < this.len)
4016 ch = this.script[this.pos];
4018 if (ch >=
'0' && ch <=
'9')
4020 else if (ch >=
'a' && ch <=
'f')
4021 ch -= (char)(
'a' - 10);
4022 else if (ch >=
'A' && ch <=
'F')
4023 ch -= (char)(
'A' - 10);
4034 while (this.pos < this.len && (ch = this.script[this.pos]) >=
'0' && ch <=
'7')
4043 while (this.pos < this.len && (ch = this.script[this.pos]) >=
'0' && ch <=
'1')
4052 if (Start2 == this.pos)
4060 else if (ch ==
'"' || ch ==
'\'')
4062 StringBuilder sb =
new StringBuilder();
4067 while ((ch2 = this.NextChar()) != ch)
4069 if (ch2 == 0 || ch2 ==
'\r' || ch2 ==
'\n')
4070 throw new SyntaxException(
"Expected end of string.", this.pos, this.script);
4074 ch2 = this.NextChar();
4078 throw new SyntaxException(
"Expected end of string.", this.pos, this.script);
4109 ch2 = this.NextChar();
4110 if (ch2 >=
'0' && ch2 <=
'9')
4112 else if (ch2 >=
'a' && ch2 <=
'f')
4113 ch2 -= (char)(
'a' - 10);
4114 else if (ch2 >=
'A' && ch2 <=
'F')
4115 ch2 -= (char)(
'A' - 10);
4117 throw new SyntaxException(
"Hexadecimal digit expected.", this.pos, this.script);
4119 char ch3 = this.NextChar();
4120 if (ch3 >=
'0' && ch3 <=
'9')
4122 else if (ch3 >=
'a' && ch3 <=
'f')
4123 ch3 -= (char)(
'a' - 10);
4124 else if (ch3 >=
'A' && ch3 <=
'F')
4125 ch3 -= (char)(
'A' - 10);
4127 throw new SyntaxException(
"Hexadecimal digit expected.", this.pos, this.script);
4140 else if (
char.IsLetter(ch) || ch ==
'_')
4146 while ((ch = this.PeekNextChar()) ==
'_')
4149 if (!
char.IsLetter(ch))
4150 throw new SyntaxException(
"Expected a letter.", this.pos, this.script);
4153 while (
char.IsLetter((ch = this.PeekNextChar())) ||
char.IsDigit(ch) || ch ==
'_')
4156 string s = this.script.Substring(Start, this.pos - Start);
4158 switch (s.ToUpper())
4170 Node = this.ParseCustomNode(s,
false, Start);
4195 return this.ParseCustomNode(
new string(ch, 1),
true, Start);
4199 private ScriptNode ParseCustomNode(
string KeyWord,
bool IncPosIfKeyword,
int Start)
4201 if (customKeyWords is
null)
4204 if (customKeyWords.TryGetValue(KeyWord, out
IKeyWord KeyWordParser))
4207 int PosBak = this.pos;
4209 if (IncPosIfKeyword)
4210 this.pos += KeyWord.Length;
4212 bool CanParseWhitespace = this.canSkipWhitespace;
4213 bool Result = KeyWordParser.TryParse(Parser, out
ScriptNode Node);
4215 this.canSkipWhitespace = CanParseWhitespace;
4226 private static bool IsVectorDefinition(
ScriptNode Node)
4247 [Obsolete(
"Use the EvaluateAsync method for more efficient processing of script containing asynchronous processing elements in parallel environments.")]
4254 if (this.root is
null)
4281 if (this.root is
null)
4305 return this.script.Equals(Exp.script);
4313 return this.script.GetHashCode();
4328 if (this.ContainsImplicitPrint)
4331 Dictionary<string, bool> Processed =
null;
4353 if (Processed is
null)
4354 Processed =
new Dictionary<string, bool>() { { this.script,
true } };
4356 if (Processed.ContainsKey(Exp.script))
4359 Processed[Exp.script] =
true;
4382 [Obsolete(
"Use the TransformAsync method for more efficient processing of script containing asynchronous processing elements in parallel environments.")]
4397 [Obsolete(
"Use the TransformAsync method for more efficient processing of script containing asynchronous processing elements in parallel environments.")]
4403 int i = s.IndexOf(StartDelimiter);
4405 int StartLen = StartDelimiter.Length;
4406 int StopLen = StopDelimiter.Length;
4410 j = s.IndexOf(StopDelimiter, i + StartLen);
4414 Script = s.Substring(i + StartLen, j - i - StartLen);
4415 s = s.Remove(i, j - i + StopLen);
4420 if (!(Result is
null))
4422 s2 = Result.ToString();
4423 s = s.Insert(i, s2);
4427 i = s.IndexOf(StartDelimiter, i);
4461 int i = s.IndexOf(StartDelimiter);
4463 int StartLen = StartDelimiter.Length;
4464 int StopLen = StopDelimiter.Length;
4468 j = s.IndexOf(StopDelimiter, i + StartLen);
4472 Script = s.Substring(i + StartLen, j - i - StartLen);
4473 s = s.Remove(i, j - i + StopLen);
4478 if (!(Result is
null))
4480 s2 = Printer is
null ? Result.ToString() : await Printer(Result,
Variables);
4481 s = s.Insert(i, s2);
4485 i = s.IndexOf(StartDelimiter, i);
4498 return Value.ToString().Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator,
".");
4508 return Value.ToString().Replace(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator,
".");
4517 public static bool TryParse(
string s, out
double Value)
4519 return double.TryParse(s.Replace(
".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out Value);
4530 return float.TryParse(s.Replace(
".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out Value);
4539 public static bool TryParse(
string s, out decimal Value)
4541 return decimal.TryParse(s.Replace(
".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out Value);
4551 return "(" +
ToString(Value.Real) +
", " +
ToString(Value.Imaginary) +
")";
4561 return "#" + Value.ToString();
4571 return Value ?
"⊤" :
"⊥";
4581 StringBuilder sb =
null;
4583 foreach (
double d
in Value)
4586 sb =
new StringBuilder(
"[");
4598 return sb.ToString();
4609 StringBuilder sb =
null;
4611 foreach (Complex z
in Value)
4614 sb =
new StringBuilder(
"[");
4626 return sb.ToString();
4637 StringBuilder Output =
new StringBuilder();
4639 Output.Append(
"DateTime");
4641 if (Value.Kind == DateTimeKind.Utc)
4642 Output.Append(
"Utc");
4645 Output.Append(Value.Year.ToString(
"D4"));
4647 Output.Append(Value.Month.ToString(
"D2"));
4649 Output.Append(Value.Day.ToString(
"D2"));
4651 if (Value.Hour != 0 || Value.Minute != 0 || Value.Second != 0 || Value.Millisecond != 0)
4654 Output.Append(Value.Hour.ToString(
"D2"));
4656 Output.Append(Value.Minute.ToString(
"D2"));
4658 Output.Append(Value.Second.ToString(
"D2"));
4660 if (Value.Millisecond != 0)
4663 Output.Append(Value.Millisecond.ToString(
"D3"));
4669 return Output.ToString();
4679 StringBuilder Output =
new StringBuilder();
4681 Output.Append(
"TimeSpan(");
4682 Output.Append(Value.Days.ToString());
4684 Output.Append(Value.Hours.ToString(
"D2"));
4686 Output.Append(Value.Minutes.ToString(
"D2"));
4688 Output.Append(Value.Seconds.ToString(
"D2"));
4690 if (Value.Milliseconds != 0)
4693 Output.Append(Value.Milliseconds.ToString(
"D3"));
4698 return Output.ToString();
4708 StringBuilder Output =
new StringBuilder();
4710 Output.Append(Value.GetType().FullName);
4712 Output.Append(Value.ToString());
4714 return Output.ToString();
4727 StringBuilder sb =
new StringBuilder();
4728 int i = s.IndexOfAny(stringCharactersToEscape);
4741 sb.Append(s.Substring(j, i - j));
4743 k = Array.IndexOf(stringCharactersToEscape, s[i]);
4744 sb.Append(stringEscapeSequences[k]);
4746 i = s.IndexOfAny(stringCharactersToEscape, j);
4750 sb.Append(s.Substring(j));
4755 return sb.ToString();
4758 private static readonly
char[] stringCharactersToEscape =
new char[] {
'\\',
'"',
'\n',
'\r',
'\t',
'\b',
'\f',
'\a',
'\v' };
4759 private static readonly
string[] stringEscapeSequences =
new string[] {
"\\\\",
"\\\"",
"\\n",
"\\r",
"\\t",
"\\b",
"\\f",
"\\a",
"\\v" };
4772 Type T = Value.GetType();
4793 else if (Value is IEnumerable Enumerable)
4795 StringBuilder sb =
new StringBuilder();
4800 foreach (
object Element in Enumerable)
4812 return sb.ToString();
4815 return Value.ToString();
4826 if (Object is
double db)
4828 else if (Object is
int i)
4830 else if (Object is
bool b)
4832 else if (Object is
byte bt)
4834 else if (Object is
char ch)
4836 else if (Object is decimal dc)
4838 else if (Object is
short sh)
4840 else if (Object is
long l)
4842 else if (Object is sbyte sb)
4844 else if (Object is
float f)
4846 else if (Object is ushort us)
4848 else if (Object is uint ui)
4850 else if (Object is ulong ul)
4852 else if (Object is BigInteger i2)
4854 else if (Object is Complex z)
4856 if (z.Imaginary == 0)
4863 string s = Object.ToString();
4865 if (
double.
TryParse(s, out
double d))
4868 if (System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator !=
"." &&
4869 double.TryParse(s.Replace(
".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out d))
4885 if (Object is
double db)
4887 else if (Object is
int i)
4889 else if (Object is
bool b)
4891 else if (Object is
byte bt)
4893 else if (Object is
char ch)
4895 else if (Object is decimal dc)
4897 else if (Object is
short sh)
4899 else if (Object is
long l)
4901 else if (Object is sbyte sb)
4903 else if (Object is
float f)
4905 else if (Object is ushort us)
4907 else if (Object is uint ui)
4909 else if (Object is ulong ul)
4911 else if (Object is BigInteger i2)
4913 else if (Object is Complex z)
4915 if (z.Imaginary == 0)
4916 return (decimal)z.Real;
4922 string s = Object.ToString();
4924 if (decimal.TryParse(s, out decimal d))
4927 if (System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator !=
"." &&
4928 decimal.TryParse(s.Replace(
".", System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator), out d))
4944 if (Object is Complex z)
4947 return new Complex(
ToDouble(Object), 0);
4959 else if (Value is
double db)
4961 else if (Value is
bool b)
4963 else if (Value is
string s)
4965 else if (Value is
int i)
4967 else if (Value is
long l)
4969 else if (Value is
byte bt)
4971 else if (Value is
char ch)
4973 else if (Value is DateTime DT)
4975 else if (Value is decimal dc)
4977 else if (Value is
short sh)
4979 else if (Value is sbyte sb)
4981 else if (Value is
float f)
4983 else if (Value is ushort us)
4985 else if (Value is uint ui)
4987 else if (Value is ulong ul)
4989 else if (Value is Complex c)
4991 else if (Value is BigInteger i2)
4993 else if (Value is Type t)
5000 else if (Value is
double[] dv)
5002 else if (Value is
double[,] dm)
5005 else if (Value is Complex[] cv)
5007 else if (Value is Complex[,] cm)
5010 else if (Value is
bool[] bv)
5012 else if (Value is
bool[,] bm)
5015 else if (Value is DateTime[] dv2)
5022 else if (Value is
object[] ov)
5024 else if (Value is
object[,] om)
5044 E2 =
new StringValue(E2.AssociatedObjectValue?.ToString() ??
string.Empty);
5051 E1 =
new StringValue(E1.AssociatedObjectValue?.ToString() ??
string.Empty);
5072 object O1 = E1?.AssociatedObjectValue;
5073 object O2 = E2?.AssociatedObjectValue;
5074 Type T1 = O1?.GetType() ?? typeof(
object);
5075 Type T2 = O2?.GetType() ?? typeof(
object);
5083 Set1 = E1asT2.AssociatedSet;
5090 Set2 = E2asT1.AssociatedSet;
5096 if (O1 is Enum Enum1 && O2 is
double)
5098 T1 = Enum.GetUnderlyingType(Enum1.GetType());
5099 if (T1 == typeof(
int))
5106 else if (O2 is Enum Enum2 && O1 is
double)
5108 T2 = Enum.GetUnderlyingType(Enum2.GetType());
5109 if (T2 == typeof(
int))
5144 if (
TryConvert(Obj, DesiredType, out
object Result))
5147 Type T = Obj.GetType();
5148 if (T == DesiredType)
5151 if (DesiredType.IsArray)
5153 Type DesiredItemType = DesiredType.GetElementType();
5158 Array
Source = (Array)Obj;
5162 Dest = (Array)Activator.CreateInstance(DesiredType, c);
5164 for (i = 0; i < c; i++)
5165 Dest.SetValue(
ConvertTo(
Source.GetValue(i), DesiredItemType, Node), i);
5169 Dest = (Array)Activator.CreateInstance(DesiredType, 1);
5170 Dest.SetValue(
ConvertTo(Obj, DesiredItemType, Node), 0);
5176 return Convert.ChangeType(Obj, DesiredType);
5185 set => this.tag = value;
5195 [Obsolete(
"Use ForAll(ScriptNodeEventHandler, object, SearchMethod) instead.")]
5212 if (!(this.root?.ForAllChildNodes(Callback, State, Order) ??
true))
5216 if (!(this.root is
null))
5218 if (!Callback(this.root, out
ScriptNode NewRoot, State))
5221 if (!(NewRoot is
null))
5222 this.root = NewRoot;
5227 if (!(this.root?.ForAllChildNodes(Callback, State, Order) ??
true))
5243 if (
TryConvert(Value, typeof(T), out
object Obj))
5245 if (Obj is T Result2)
5250 else if (Value is
null && !typeof(T).GetTypeInfo().IsValueType)
5268 public static bool TryConvert(
object Value, Type DesiredType, out
object Result)
5273 return !DesiredType.GetTypeInfo().IsValueType;
5276 Type T = Value.GetType();
5277 TypeInfo TI = T.GetTypeInfo();
5279 if (DesiredType.GetTypeInfo().IsAssignableFrom(TI))
5287 Result = Converter.Convert(Value);
5288 return !(Result is
null) || (Value is
null);
5311 return !DesiredType.GetTypeInfo().IsValueType;
5314 Type T = Obj.GetType();
5318 Result = Converter.ConvertToElement(Obj);
5319 return !(Result is
null);
5338 if (converters is
null)
5340 Dictionary<Type, Dictionary<Type, ITypeConverter>> Converters = GetTypeConverters();
5342 if (converters is
null)
5344 converters = Converters;
5345 Types.OnInvalidated += (Sender, e) => converters = GetTypeConverters();
5351 if (!converters.TryGetValue(From, out Dictionary<Type, ITypeConverter> Converters) &&
5352 (!From.GetTypeInfo().IsEnum || !converters.TryGetValue(typeof(Enum), out Converters)))
5358 if (Converters.TryGetValue(To, out Converter))
5359 return !(Converter is
null);
5361 Dictionary<Type, bool> Explored =
new Dictionary<Type, bool>() { { From,
true } };
5362 LinkedList<ITypeConverter> Search =
new LinkedList<ITypeConverter>();
5366 if (!(Converter3 is
null))
5368 Search.AddLast(Converter3);
5369 Explored[Converter3.
To] =
true;
5373 while (!(Search.First is
null))
5376 Search.RemoveFirst();
5378 if (converters.TryGetValue(C.
To, out Dictionary<Type, ITypeConverter> Converters2) && !(Converters2 is
null))
5380 if (Converters2.TryGetValue(To, out
ITypeConverter Converter2) && !(Converter2 is
null))
5386 int c = Sequence.Converters.Length + 1;
5389 A[c - 1] = Converter2;
5402 if (!(Converter3 is
null))
5404 if (!Explored.ContainsKey(Converter3.
To))
5406 Search.AddLast(Converter3);
5407 Explored[Converter3.
To] =
true;
5414 Converters[To] =
null;
5420 private static Dictionary<Type, Dictionary<Type, ITypeConverter>> GetTypeConverters()
5422 Dictionary<Type, Dictionary<Type, ITypeConverter>> Converters =
new Dictionary<Type, Dictionary<Type, ITypeConverter>>();
5427 if (DefaultConstructor is
null)
5433 Type From = Converter.
From;
5434 Type To = Converter.
To;
5436 if (!Converters.TryGetValue(From, out Dictionary<Type, ITypeConverter> List))
5438 List =
new Dictionary<Type, ITypeConverter>();
5439 Converters[From] = List;
5444 Log.
Warning(
"There's already a type converter registered converting from " +
5445 From.FullName +
" to " + To.FullName, Converter2.GetType().FullName);
5448 List[To] = Converter;
5450 catch (Exception ex)
5464 [Obsolete(
"Use the EvalAsync method for more efficient processing of script containing asynchronous processing elements in parallel environments.")]
5476 [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.
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.
Base class for script exceptions.
Script runtime exception.
IElement ReturnValue
Return value.
Class managing a script expression.
static string ToString(string s)
Converts a string value to a parsable expression string.
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....
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.
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 bool UpgradeSemiGroup(ref IElement E1, ref ISet Set1, ref IElement E2, ref ISet Set2)
Upgrades elements if necessary, to a common semi-field, trying to make them compatible.
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.
static bool TryConvert(object Value, Type DesiredType, out object Result)
Tries to convert an object Value to an object of type DesiredType .
bool ReferencesImplicitPrint(Variables Variables)
If the expression, or any function call references, contain implicit print operations.
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...
string Source
Source of script, or null if not defined.
static bool TryParse(string s, out float Value)
Tries to parse a single-precision floating-point value.
override bool Equals(object obj)
static bool TryConvert(IElement Value, Type DesiredType, out IElement Result)
Tries to convert an element Value to an element whose associated object is of type DesiredType .
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.
bool ForAll(ScriptNodeEventHandler Callback, object State, bool DepthFirst)
Calls the callback method for all script nodes defined for the 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 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.
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.
Semi-group of string values.
static readonly StringValues Instance
Instance of the set of string values.
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.
Represents an atomic unit.
Static class managing units.
static bool TryParsePrefix(char ch, out Prefix Prefix)
Tries to parse a character into a prefix.
ICollection< KeyValuePair< AtomicUnit, int > > 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.
Type From
Converter converts objects of this type.
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.