Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
SparqlParser.cs
1using System;
2using System.Collections.Generic;
3using System.Numerics;
4using System.Text;
5using Waher.Content;
32
34{
38 public class SparqlParser : IKeyWord
39 {
43 public static readonly SparqlParser RefInstance = new SparqlParser(string.Empty);
44
45 private static readonly Dictionary<string, IExtensionFunction> functionsPerUri = new Dictionary<string, IExtensionFunction>(StringComparer.CurrentCultureIgnoreCase);
46
47 static SparqlParser()
48 {
49 Types.OnInvalidated += (Sender, e) =>
50 {
51 lock (functionsPerUri)
52 {
53 functionsPerUri.Clear();
54 }
55 };
56 }
57
58 private readonly string preamble;
59 private readonly int preambleLen;
60 private readonly Dictionary<string, string> namespaces = new Dictionary<string, string>()
61 {
62 { "xsd", XmlSchema.Namespace },
63 { "rdf", Rdf.Namespace },
64 { "rdfs", RdfSchema.Namespace },
65 { "fn", "http://www.w3.org/2005/xpath-functions#" },
66 { "sfn", "http://www.w3.org/ns/sparql#" }
67 };
68 private QueryType queryType;
69 private SparqlRegularPattern currentRegularPattern = null;
70 private ISparqlPattern currentPattern = null;
71 private int preamblePos;
72 private System.Uri baseUri = null;
73 private int blankNodeIndex = 0;
74
79 public SparqlParser(string Preamble)
80 {
81 this.queryType = QueryType.Select;
82 this.preamble = Preamble;
83 this.preambleLen = Preamble?.Length ?? 0;
84 this.preamblePos = 0;
85 }
86
90 public string KeyWord => string.Empty;
91
95 public string[] Aliases => null;
96
100 public string[] InternalKeywords => new string[]
101 {
102 "DISTINCT",
103 "REDUCED",
104 "FROM",
105 "AS",
106 "NAMED",
107 "WHERE",
108 "OPTIONAL",
109 "UNION",
110 "MINUS",
111 "ORDER",
112 "BY",
113 "ASK",
114 "CONSTRUCT",
115 "ASC",
116 "DESC",
117 "VALUES",
118 "GRAPH",
119 "SERVICE",
120 "UNDEF",
121 "LIMIT",
122 "OFFSET"
123 };
124
131 public bool TryParse(ScriptParser Parser, out ScriptNode Result)
132 {
133 return this.TryParse(Parser, Parser.Start, out Result);
134 }
135
143 public bool TryParse(ScriptParser Parser, int Start, out ScriptNode Result)
144 {
145 Result = null;
146
147 ScriptNode Node;
148 string s;
149 bool Distinct = false;
150 bool Reduced = false;
151 char ch;
152
153 s = this.PeekNextToken(Parser).ToUpper();
154 if (string.IsNullOrEmpty(s))
155 return false;
156
157 while (s != "SELECT" && s != "ASK" && s != "CONSTRUCT")
158 {
159 switch (s)
160 {
161 case "BASE":
162 this.NextToken(Parser);
163 this.SkipWhiteSpace(Parser);
164 if (this.preamblePos < this.preambleLen)
165 return false;
166
167 ch = Parser.NextNonWhitespaceChar();
168 if (ch != '<')
169 throw Parser.SyntaxError("Expected <");
170
171 this.baseUri = this.ParseUri(Parser).Uri;
172
173 break;
174
175 case "PREFIX":
176 this.NextToken(Parser);
177 this.SkipWhiteSpace(Parser);
178 if (this.preamblePos < this.preambleLen)
179 return false;
180
181 Parser.SkipWhiteSpace();
182
183 s = this.ParseName(Parser);
184
185 if (Parser.NextNonWhitespaceChar() != ':')
186 throw Parser.SyntaxError("Expected :");
187
188 if (Parser.NextNonWhitespaceChar() != '<')
189 throw Parser.SyntaxError("Expected <");
190
191 this.namespaces[s] = this.ParseUri(Parser).Uri.ToString();
192 break;
193
194 default:
195 return false;
196 }
197
198 s = Parser.PeekNextToken().ToUpper();
199 if (string.IsNullOrEmpty(s))
200 return false;
201 }
202
203 List<ScriptNode> Columns = null;
204 List<ScriptNode> ColumnNames = null;
205 List<ScriptNode> GroupBy = null;
206 List<ScriptNode> GroupByNames = null;
207 List<KeyValuePair<ScriptNode, bool>> OrderBy = null;
208 SparqlRegularPattern Construct = null;
209 ISparqlPattern Where;
210 ScriptNode Having;
211 List<ScriptNode> From;
212 Dictionary<UriNode, ISemanticCube> NamedGraphs = null;
213
214 switch (s)
215 {
216 case "ASK":
217 this.queryType = QueryType.Ask;
218 this.NextToken(Parser);
219 s = this.PeekNextToken(Parser).ToUpper();
220 if (string.IsNullOrEmpty(s))
221 return false;
222 break;
223
224 case "CONSTRUCT":
225 this.queryType = QueryType.Construct;
226 this.NextToken(Parser);
227
228 s = Parser.PeekNextToken().ToUpper();
229 if (s == "WHERE")
230 Construct = null;
231 else
232 {
233 ISparqlPattern Pattern = this.ParsePattern(Parser)
234 ?? throw Parser.SyntaxError("Expected pattern.");
235
236 if (!(Pattern is SparqlRegularPattern RegularPattern))
237 throw Parser.SyntaxError("Expected regular pattern.");
238
239 Construct = RegularPattern;
240 if (!(Construct.BoundVariables is null))
241 throw Parser.SyntaxError("Bound variables not permitted in construct statement.");
242
243 if (!(Construct.Filter is null))
244 throw Parser.SyntaxError("Filters not permitted in construct statement.");
245
246 s = Parser.PeekNextToken().ToUpper();
247 }
248 break;
249
250 case "SELECT":
251 this.queryType = QueryType.Select;
252 this.NextToken(Parser);
253 s = this.PeekNextToken(Parser).ToUpper();
254 if (string.IsNullOrEmpty(s))
255 return false;
256
257 switch (s)
258 {
259 case "DISTINCT":
260 this.NextToken(Parser);
261 Distinct = true;
262
263 s = this.PeekNextToken(Parser).ToUpper();
264 break;
265
266 case "REDUCED":
267 this.NextToken(Parser);
268 Reduced = true;
269
270 s = this.PeekNextToken(Parser).ToUpper();
271 break;
272 }
273
274 if (s == "*")
275 {
276 this.NextToken(Parser);
277 s = this.PeekNextToken(Parser).ToUpper();
278
279 Columns = null;
280 ColumnNames = null;
281 }
282 else
283 {
284 Columns = new List<ScriptNode>();
285 ColumnNames = new List<ScriptNode>();
286
287 while (!string.IsNullOrEmpty(s) && s != "WHERE" && s != "FROM" && s != "{")
288 {
289 Node = this.ParseNamedExpression(Parser);
290 if (Node is NamedNode NamedNode)
291 {
292 Columns.Add(NamedNode.LeftOperand);
293 ColumnNames.Add(NamedNode.RightOperand);
294 }
295 else
296 {
297 Columns.Add(Node);
298 ColumnNames.Add(null);
299 }
300
301 s = Parser.PeekNextToken().ToUpper();
302 }
303 }
304 break;
305
306 default:
307 throw Parser.SyntaxError("Expected SELECT or ASK.");
308 }
309
310 From = null;
311
312 while (s == "FROM")
313 {
314 if (From is null)
315 From = new List<ScriptNode>();
316
317 Parser.NextToken();
318 Parser.SkipWhiteSpace();
319
320 switch (Parser.PeekNextChar())
321 {
322 case '<':
323 int Start2 = Parser.Position;
324 Parser.NextChar();
325 UriNode FromUri = this.ParseUri(Parser);
326
327 From.Add(new ConstantElement(FromUri, Start2, Parser.Position - Start2, Parser.Expression));
328 break;
329
330 case 'n':
331 case 'N':
332 if (string.Compare(Parser.PeekNextToken(), "NAMED", true) == 0)
333 {
334 Parser.NextToken();
335 if (Parser.NextNonWhitespaceChar() != '<')
336 throw Parser.SyntaxError("Expected <");
337
338 FromUri = this.ParseUri(Parser);
339
340 if (NamedGraphs is null)
341 NamedGraphs = new Dictionary<UriNode, ISemanticCube>();
342
343 NamedGraphs[FromUri] = null;
344 }
345 else
346 From.Add(Parser.ParseObject());
347 break;
348
349 default:
350 From.Add(Parser.ParseObject());
351 break;
352 }
353
354 s = Parser.PeekNextToken().ToUpper();
355 }
356
357 if (s == "WHERE")
358 {
359 Parser.NextToken();
360 Where = this.ParsePattern(Parser);
361 s = Parser.PeekNextToken().ToUpper();
362 }
363 else if (s == "{")
364 {
365 Where = this.ParsePattern(Parser);
366 s = Parser.PeekNextToken().ToUpper();
367 }
368 else
369 Where = null;
370
371 if (this.queryType == QueryType.Construct && Construct is null)
372 {
373 if (Where is SparqlRegularPattern RegularPattern)
374 Construct = RegularPattern;
375 else
376 throw Parser.SyntaxError("CONSTRUCT WHERE queries require a regular WHERE pattern.");
377 }
378
379 if (s == "VALUES")
380 {
381 Parser.NextToken();
382
383 ValuesPattern Values = this.ParseValues(Parser);
384
385 if (Where is null)
386 Where = Values;
387 else
388 Where = new IntersectionPattern(Values, Where);
389
390 s = Parser.PeekNextToken().ToUpper();
391 }
392
393 if (s == "GROUP")
394 {
395 Parser.NextToken();
396
397 if (string.Compare(Parser.NextToken(), "BY", true) != 0)
398 throw Parser.SyntaxError("Expected BY");
399
400 GroupBy = new List<ScriptNode>();
401 GroupByNames = new List<ScriptNode>();
402
403 while (!string.IsNullOrEmpty(s) && s != "HAVING" && s != "ORDER" && s != ";" && s != ")" && s != "}")
404 {
405 Node = this.ParseNamedExpression(Parser);
406 if (Node is NamedNode NamedNode)
407 {
408 GroupBy.Add(NamedNode.LeftOperand);
409 GroupByNames.Add(NamedNode.RightOperand);
410 }
411 else
412 {
413 GroupBy.Add(Node);
414 GroupByNames.Add(null);
415 }
416
417 s = Parser.PeekNextToken().ToUpper();
418 }
419
420 if (s == "HAVING")
421 {
422 Parser.NextToken();
423 Having = this.ParseExpression(Parser, false);
424 s = Parser.PeekNextToken().ToUpper();
425 }
426 else
427 Having = null;
428 }
429 else
430 Having = null;
431
432 if (s == "ORDER")
433 {
434 if (this.queryType == QueryType.Ask)
435 throw Parser.SyntaxError("ORDER BY not expected in ASK queries.");
436
437 Parser.NextToken();
438 s = Parser.NextToken().ToUpper();
439 if (s != "BY")
440 throw Parser.SyntaxError("Expected BY");
441
442 OrderBy = new List<KeyValuePair<ScriptNode, bool>>();
443
444 while (true)
445 {
446 Node = this.ParseExpression(Parser, true);
447 if (Node is null)
448 break;
449 else if (Node is Asc Asc)
450 OrderBy.Add(new KeyValuePair<ScriptNode, bool>(Asc.Argument, true));
451 else if (Node is Desc Desc)
452 OrderBy.Add(new KeyValuePair<ScriptNode, bool>(Desc.Argument, false));
453 else
454 OrderBy.Add(new KeyValuePair<ScriptNode, bool>(Node, true));
455 }
456
457 s = Parser.PeekNextToken().ToUpper();
458 }
459
460 int? Offset = null;
461 int? Limit = null;
462
463 while (true)
464 {
465 switch (s)
466 {
467 case "LIMIT":
468 Parser.NextToken();
469 Limit = this.ParsePositiveInteger(Parser);
470 break;
471
472 case "OFFSET":
473 Parser.NextToken();
474 Offset = this.ParsePositiveInteger(Parser);
475 break;
476
477 default:
478 Result = new SparqlQuery(this.queryType, Distinct, Reduced, Columns?.ToArray(),
479 ColumnNames?.ToArray(), From?.ToArray(), NamedGraphs, Where,
480 GroupBy?.ToArray(), GroupByNames?.ToArray(), Having, OrderBy?.ToArray(),
481 Limit, Offset, Construct, Start, Parser.Position - Start, Parser.Expression);
482
483 return true;
484 }
485
486 s = Parser.PeekNextToken().ToUpper();
487 }
488 }
489
490 private char PeekNextChar(ScriptParser Parser)
491 {
492 if (this.preamblePos < this.preambleLen)
493 return this.preamble[this.preamblePos];
494 else
495 return Parser.PeekNextChar();
496 }
497
498 private char NextChar(ScriptParser Parser)
499 {
500 if (this.preamblePos < this.preambleLen)
501 return this.preamble[this.preamblePos++];
502 else
503 return Parser.NextChar();
504 }
505
506 private void SkipWhiteSpace(ScriptParser Parser)
507 {
508 char ch = this.PeekNextChar(Parser);
509
510 while (ch != 0 && (ch <= ' ' || ch == 160))
511 {
512 this.NextChar(Parser);
513 ch = this.PeekNextChar(Parser);
514 }
515 }
516
517 private string NextToken(ScriptParser Parser)
518 {
519 this.SkipWhiteSpace(Parser);
520
521 if (this.preamblePos < this.preambleLen)
522 {
523 int Start = this.preamblePos;
524 char ch = this.preamble[this.preamblePos];
525
526 if (char.IsLetter(ch))
527 {
528 while (this.preamblePos < this.preambleLen && char.IsLetterOrDigit(this.preamble[this.preamblePos]))
529 this.preamblePos++;
530 }
531 else if (char.IsDigit(ch))
532 {
533 while (this.preamblePos < this.preambleLen && char.IsDigit(this.preamble[this.preamblePos]))
534 this.preamblePos++;
535 }
536 else if (char.IsSymbol(ch))
537 {
538 while (this.preamblePos < this.preambleLen && char.IsSymbol(this.preamble[this.preamblePos]))
539 this.preamblePos++;
540 }
541 else
542 this.preamblePos++;
543
544 return this.preamble.Substring(Start, this.preamblePos - Start);
545 }
546 else
547 return Parser.NextToken();
548 }
549
550 private string PeekNextToken(ScriptParser Parser)
551 {
552 this.SkipWhiteSpace(Parser);
553
554 if (this.preamblePos < this.preambleLen)
555 {
556 int Bak = this.preamblePos;
557 string Token = this.NextToken(Parser);
558 this.preamblePos = Bak;
559
560 return Token;
561 }
562 else
563 return Parser.PeekNextToken();
564 }
565
566 private ISparqlPattern ParsePattern(ScriptParser Parser)
567 {
568 if (Parser.NextNonWhitespaceChar() != '{')
569 throw Parser.SyntaxError("Expected {");
570
571 Parser.SkipWhiteSpace();
572 if (Parser.PeekNextChar() == '}')
573 {
574 Parser.NextChar();
575 return null;
576 }
577
578 SparqlRegularPattern Bak = this.currentRegularPattern;
579 ISparqlPattern Bak2 = this.currentPattern;
580
581 this.currentRegularPattern = new SparqlRegularPattern();
582 this.currentPattern = this.currentRegularPattern;
583
584 this.ParseTriples(Parser);
585
586 if (Parser.NextNonWhitespaceChar() != '}')
587 throw Parser.SyntaxError("Expected }");
588
589 ISparqlPattern Result = this.currentPattern;
590
591 this.currentRegularPattern = Bak;
592 this.currentPattern = Bak2;
593
594 return Result;
595 }
596
597 private void ParseTriples(ScriptParser Parser)
598 {
599 this.ParseTriples(Parser, null);
600 }
601
602 private void ParseTriples(ScriptParser Parser, ISemanticElement Subject)
603 {
606 int TriplePosition = Subject is null ? 0 : 1;
607 bool InBlankNode = !(Subject is null);
608
609 while (Parser.InScript)
610 {
611 if (TriplePosition == 0)
612 {
613 Parser.SkipWhiteSpace();
614
615 switch (Parser.PeekNextChar())
616 {
617 case '.':
618 if (TriplePosition == 0)
619 break;
620
621 throw Parser.SyntaxError("Unexpected .");
622
623 case '{':
624 ISparqlPattern Left = this.currentPattern;
625 ISparqlPattern Pattern = this.ParsePattern(Parser);
626
627 if (Left.IsEmpty)
628 {
629 this.currentPattern = Pattern;
630 this.currentRegularPattern = Pattern as SparqlRegularPattern;
631 }
632 else
633 {
634 this.currentRegularPattern = null;
635 this.currentPattern = new IntersectionPattern(Left, Pattern);
636 }
637
638 Parser.SkipWhiteSpace();
639 switch (Parser.PeekNextChar())
640 {
641 case '.':
642 Parser.NextChar();
643 Subject = null;
644 Predicate = null;
645 TriplePosition = 0;
646 break;
647
648 case '}':
649 return;
650 }
651 continue;
652
653 case 'o':
654 case 'O':
655 case 'u':
656 case 'U':
657 case 'm':
658 case 'M':
659 case 'v':
660 case 'V':
661 case 's':
662 case 'S':
663 case 'g':
664 case 'G':
665 if (!this.ParsePatternOperator(Parser))
666 break;
667
668 Parser.SkipWhiteSpace();
669 switch (Parser.PeekNextChar())
670 {
671 case '.':
672 Parser.NextChar();
673 Subject = null;
674 Predicate = null;
675 TriplePosition = 0;
676 break;
677
678 case '}':
679 return;
680 }
681 continue;
682 }
683 }
684
685 Object = this.ParseElement(Parser, TriplePosition);
686 if (Object is null)
687 {
688 if (Subject is null)
689 return;
690 else if (Predicate is null)
691 {
692 if (InBlankNode)
693 return;
694 else
695 throw Parser.SyntaxError("Expected predicate.");
696 }
697 else
698 throw Parser.SyntaxError("Expected object.");
699 }
700
701 if (Subject is null)
702 {
703 Subject = Object;
704 TriplePosition++;
705 }
706 else if (Predicate is null)
707 {
709 TriplePosition++;
710 }
711 else
712 {
713 if (this.currentRegularPattern is null)
714 {
715 this.currentRegularPattern = new SparqlRegularPattern();
716 this.currentPattern = new IntersectionPattern(this.currentPattern, this.currentRegularPattern);
717 }
718
719 this.currentRegularPattern.AddTriple(new SemanticQueryTriple(Subject, Predicate, Object));
720
721 switch (Parser.NextNonWhitespaceChar())
722 {
723 case '.':
724 if (InBlankNode)
725 throw Parser.SyntaxError("Expected ]");
726
727 Subject = null;
728 Predicate = null;
729 TriplePosition = 0;
730 break;
731
732 case '}':
733 if (InBlankNode)
734 throw Parser.SyntaxError("Expected ]");
735
736 Parser.UndoChar();
737 return;
738
739 case ';':
740 Predicate = null;
741 TriplePosition = 1;
742
743 Parser.SkipWhiteSpace();
744 if (Parser.PeekNextChar() == '.')
745 {
746 if (InBlankNode)
747 throw Parser.SyntaxError("Expected ]");
748
749 Parser.NextChar();
750 Subject = null;
751 TriplePosition = 0;
752 }
753 break;
754
755 case ',':
756 break;
757
758 case ']':
759 return;
760
761 case 'b':
762 case 'B':
763 if (char.ToUpper(Parser.NextChar()) != 'I' ||
764 char.ToUpper(Parser.NextChar()) != 'N' ||
765 char.ToUpper(Parser.NextChar()) != 'D')
766 {
767 throw Parser.SyntaxError("Expected BIND");
768 }
769
770 if (InBlankNode)
771 throw Parser.SyntaxError("Expected ]");
772
773 Subject = null;
774 Predicate = null;
775 TriplePosition = 0;
776
777 if (Parser.NextNonWhitespaceChar() != '(')
778 throw Parser.SyntaxError("Expected (");
779
780 ScriptNode Node = this.ParseNamedExpression(Parser);
781 if (!(Node is NamedNode NamedNode))
782 throw Parser.SyntaxError("Expected name.");
783
784 if (this.currentRegularPattern is null)
785 {
786 this.currentRegularPattern = new SparqlRegularPattern();
787 this.currentPattern = new IntersectionPattern(this.currentPattern, this.currentRegularPattern);
788 }
789
790 this.currentRegularPattern.AddVariableBinding(
792
793 if (Parser.NextNonWhitespaceChar() != ')')
794 throw Parser.SyntaxError("Expected )");
795
796 break;
797
798 case 'f':
799 case 'F':
800 if (char.ToUpper(Parser.NextChar()) != 'I' ||
801 char.ToUpper(Parser.NextChar()) != 'L' ||
802 char.ToUpper(Parser.NextChar()) != 'T' ||
803 char.ToUpper(Parser.NextChar()) != 'E' ||
804 char.ToUpper(Parser.NextChar()) != 'R')
805 {
806 throw Parser.SyntaxError("Expected FILTER");
807 }
808
809 if (InBlankNode)
810 throw Parser.SyntaxError("Expected ]");
811
812 Subject = null;
813 Predicate = null;
814 TriplePosition = 0;
815
816 Node = this.ParseUnary(Parser, false);
817
818 if (this.currentRegularPattern is null)
819 {
820 this.currentRegularPattern = new SparqlRegularPattern();
821 this.currentPattern = new IntersectionPattern(this.currentPattern, this.currentRegularPattern);
822 }
823
824 this.currentRegularPattern.AddFilter(Node);
825 break;
826
827 case 'u':
828 case 'U':
829 case 'o':
830 case 'O':
831 case 'm':
832 case 'M':
833 case 'v':
834 case 'V':
835 case 's':
836 case 'S':
837 case 'g':
838 case 'G':
839 Parser.UndoChar();
840
841 if (!this.ParsePatternOperator(Parser))
842 throw Parser.SyntaxError("Unexpected token.");
843
844 if (InBlankNode)
845 throw Parser.SyntaxError("Expected ]");
846
847 Subject = null;
848 Predicate = null;
849 TriplePosition = 0;
850 break;
851
852 default:
853 throw Parser.SyntaxError("Unexpected token.");
854 }
855 }
856 }
857 }
858
859 private bool ParsePatternOperator(ScriptParser Parser)
860 {
861 switch (Parser.PeekNextToken().ToUpper())
862 {
863 case "OPTIONAL":
864 Parser.NextToken();
865
866 ISparqlPattern Left = this.currentPattern;
867 ISparqlPattern Pattern = this.ParsePattern(Parser);
868
869 this.currentRegularPattern = null;
870 this.currentPattern = new OptionalPattern(Left, Pattern);
871 return true;
872
873 case "UNION":
874 Parser.NextToken();
875
876 Left = this.currentPattern;
877 Pattern = this.ParsePattern(Parser);
878
879 this.currentRegularPattern = null;
880 this.currentPattern = new UnionPattern(Left, Pattern);
881 return true;
882
883 case "MINUS":
884 Parser.NextToken();
885
886 Left = this.currentPattern;
887 Pattern = this.ParsePattern(Parser);
888
889 this.currentRegularPattern = null;
890 this.currentPattern = new ComplementPattern(Left, Pattern);
891 return true;
892
893 case "VALUES":
894 Parser.NextToken();
895
896 ValuesPattern Values = this.ParseValues(Parser);
897
898 this.currentRegularPattern = null;
899
900 if (this.currentPattern.IsEmpty)
901 this.currentPattern = Values;
902 else
903 this.currentPattern = new IntersectionPattern(Values, this.currentPattern);
904
905 return true;
906
907 case "SELECT":
908 SparqlParser SubParser = new SparqlParser(string.Empty);
909
910 foreach (KeyValuePair<string, string> P in this.namespaces)
911 SubParser.namespaces[P.Key] = P.Value;
912
913 if (!SubParser.TryParse(Parser, Parser.Position, out ScriptNode Node))
914 throw Parser.SyntaxError("Unable to parse subquery.");
915
916 if (!(Node is SparqlQuery SubQuery))
917 throw Parser.SyntaxError("Expected subquery.");
918
920
921 this.currentRegularPattern = null;
922
923 if (this.currentPattern.IsEmpty)
924 this.currentPattern = SubQueryPattern;
925 else
926 this.currentPattern = new IntersectionPattern(this.currentPattern, SubQueryPattern);
927
928 return true;
929
930 case "GRAPH":
931 Parser.NextToken();
932
933 ScriptNode Graph = this.ParseExpression(Parser, false);
934 Pattern = this.ParsePattern(Parser);
935
936 GraphPattern GraphPattern = new GraphPattern(Graph, Pattern);
937
938 this.currentRegularPattern = null;
939
940 if (this.currentPattern.IsEmpty)
941 this.currentPattern = GraphPattern;
942 else
943 this.currentPattern = new IntersectionPattern(this.currentPattern, GraphPattern);
944
945 return true;
946
947
948 default:
949 return false;
950 }
951 }
952
953 private ValuesPattern ParseValues(ScriptParser Parser)
954 {
955 Parser.SkipWhiteSpace();
956 switch (Parser.PeekNextChar())
957 {
958 case '?':
959 Parser.NextChar();
960
961 string s = this.ParseName(Parser);
962
963 if (Parser.NextNonWhitespaceChar() != '{')
964 throw Parser.SyntaxError("Expected {");
965
966 List<ISemanticElement> Values = new List<ISemanticElement>();
967
968 while (true)
969 {
970 Parser.SkipWhiteSpace();
971 switch (Parser.PeekNextChar())
972 {
973 case (char)0:
974 throw Parser.SyntaxError("Expected }");
975
976 case '}':
977 Parser.NextChar();
978
979 return new ValuesPattern(s, Values.ToArray());
980
981 default:
982 ISemanticElement Element = this.ParseElement(Parser, 2);
983 if (Element is UndefinedLiteral)
984 Values.Add(null);
985 else
986 Values.Add(Element);
987 break;
988 }
989 }
990
991 case '(':
992 Parser.NextChar();
993
994 List<string> Names = new List<string>();
995
996 while (true)
997 {
998 switch (Parser.NextNonWhitespaceChar())
999 {
1000 case '?':
1001 Names.Add(this.ParseName(Parser));
1002 continue;
1003
1004 case ')':
1005 break;
1006
1007 default:
1008 throw Parser.SyntaxError("Expected ? or )");
1009 }
1010
1011 break;
1012 }
1013
1014 int i, c = Names.Count;
1015 if (c == 0)
1016 throw Parser.SyntaxError("Expected variable name.");
1017
1018 if (Parser.NextNonWhitespaceChar() != '{')
1019 throw Parser.SyntaxError("Expected {");
1020
1021 List<ISemanticElement[]> Records = new List<ISemanticElement[]>();
1022
1023 while (true)
1024 {
1025 switch (Parser.NextNonWhitespaceChar())
1026 {
1027 case '(':
1028 Values = new List<ISemanticElement>();
1029
1030 for (i = 0; i < c; i++)
1031 {
1032 ISemanticElement Element = this.ParseElement(Parser, 2);
1033
1034 if (Element is UndefinedLiteral)
1035 Values.Add(null);
1036 else
1037 Values.Add(Element);
1038 }
1039
1040 if (Parser.NextNonWhitespaceChar() != ')')
1041 throw Parser.SyntaxError("Expected )");
1042
1043 Records.Add(Values.ToArray());
1044 continue;
1045
1046 case '}':
1047 return new ValuesPattern(Names.ToArray(), Records.ToArray());
1048
1049 default:
1050 throw Parser.SyntaxError("Expected ( or }");
1051 }
1052 }
1053
1054 default:
1055 throw Parser.SyntaxError("Expected ? or (");
1056 }
1057 }
1058
1059 private ScriptNode ParseNamedExpression(ScriptParser Parser)
1060 {
1061 ScriptNode Node = this.ParseExpression(Parser, false);
1062 string s = Parser.PeekNextToken().ToUpper();
1063
1064 if (s == "AS")
1065 {
1066 Parser.NextToken();
1067 ScriptNode Name = this.ParseExpression(Parser, false);
1068 Node = new NamedNode(Node, Name, Node.Start, Parser.Position - Node.Start, Parser.Expression);
1069 }
1070
1071 return Node;
1072 }
1073
1074 private ScriptNode ParseExpression(ScriptParser Parser, bool Optional)
1075 {
1076 return this.ParseOrs(Parser, Optional);
1077 }
1078
1079 private ScriptNode ParseOrs(ScriptParser Parser, bool Optional)
1080 {
1081 ScriptNode Left = this.ParseAnds(Parser, Optional);
1082 if (Left is null)
1083 return null;
1084
1085 Parser.SkipWhiteSpace();
1086 while (Parser.PeekNextChars(2) == "||")
1087 {
1088 Parser.SkipChars(2);
1089 ScriptNode Right = this.ParseAnds(Parser, false);
1090 Left = new Operators.Logical.Or(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1091 Parser.SkipWhiteSpace();
1092 }
1093
1094 return Left;
1095 }
1096
1097 private ScriptNode ParseAnds(ScriptParser Parser, bool Optional)
1098 {
1099 ScriptNode Left = this.ParseComparisons(Parser, Optional);
1100 if (Left is null)
1101 return null;
1102
1103 Parser.SkipWhiteSpace();
1104 while (Parser.PeekNextChars(2) == "&&")
1105 {
1106 Parser.SkipChars(2);
1107 ScriptNode Right = this.ParseComparisons(Parser, false);
1108 Left = new Operators.Logical.And(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1109 Parser.SkipWhiteSpace();
1110 }
1111
1112 return Left;
1113 }
1114
1115 private ScriptNode ParseComparisons(ScriptParser Parser, bool Optional)
1116 {
1117 ScriptNode Left = this.ParseTerms(Parser, Optional);
1118 if (Left is null)
1119 return null;
1120
1121 while (true)
1122 {
1123 Parser.SkipWhiteSpace();
1124
1125 switch (Parser.PeekNextChar())
1126 {
1127 case '=':
1128 Parser.NextChar();
1129 ScriptNode Right = this.ParseTerms(Parser, false);
1130 Left = new EqualTo(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1131 break;
1132
1133 case '!':
1134 Parser.NextChar();
1135 if (Parser.PeekNextChar() == '=')
1136 {
1137 Parser.NextChar();
1138 Right = this.ParseTerms(Parser, false);
1139 Left = new NotEqualTo(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1140 }
1141 else
1142 {
1143 Parser.UndoChar();
1144 return Left;
1145 }
1146 break;
1147
1148 case '<':
1149 Parser.NextChar();
1150
1151 if (Parser.PeekNextChar() == '=')
1152 {
1153 Parser.NextChar();
1154 Right = this.ParseTerms(Parser, false);
1156 }
1157 else
1158 {
1159 Right = this.ParseTerms(Parser, false);
1160 Left = new LesserThan(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1161 }
1162 break;
1163
1164 case '>':
1165 Parser.NextChar();
1166
1167 if (Parser.PeekNextChar() == '=')
1168 {
1169 Parser.NextChar();
1170 Right = this.ParseTerms(Parser, false);
1172 }
1173 else
1174 {
1175 Right = this.ParseTerms(Parser, false);
1176 Left = new GreaterThan(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1177 }
1178 break;
1179
1180 case 'i':
1181 case 'I':
1182 if (string.Compare(Parser.PeekNextToken(), "IN", true) == 0)
1183 {
1184 Parser.NextToken();
1185 Right = this.ParseTerms(Parser, false);
1186 Left = new In(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1187 }
1188 else
1189 return Left;
1190 break;
1191
1192 case 'n':
1193 case 'N':
1194 if (string.Compare(Parser.PeekNextToken(), "NOT", true) == 0)
1195 {
1196 if (string.Compare(Parser.NextToken(), "IN", true) != 0)
1197 throw Parser.SyntaxError("Expected IN");
1198
1199 Right = this.ParseTerms(Parser, false);
1200 Left = new NotIn(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1201 }
1202 else
1203 return Left;
1204 break;
1205
1206 default:
1207 return Left;
1208 }
1209 }
1210 }
1211
1212 private ScriptNode ParseTerms(ScriptParser Parser, bool Optional)
1213 {
1214 ScriptNode Left = this.ParseFactors(Parser, Optional);
1215
1216 while (true)
1217 {
1218 Parser.SkipWhiteSpace();
1219
1220 switch (Parser.PeekNextChar())
1221 {
1222 case '+':
1223 Parser.NextChar();
1224 ScriptNode Right = this.ParseFactors(Parser, false);
1225 Left = new Add(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1226 break;
1227
1228 case '-':
1229 Parser.NextChar();
1230 Right = this.ParseFactors(Parser, false);
1231 Left = new Subtract(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1232 break;
1233
1234 default:
1235 return Left;
1236 }
1237 }
1238 }
1239
1240 private ScriptNode ParseFactors(ScriptParser Parser, bool Optional)
1241 {
1242 ScriptNode Left = this.ParseUnary(Parser, Optional);
1243
1244 while (true)
1245 {
1246 Parser.SkipWhiteSpace();
1247
1248 switch (Parser.PeekNextChar())
1249 {
1250 case '*':
1251 Parser.NextChar();
1252 ScriptNode Right = this.ParseUnary(Parser, false);
1253 Left = new Multiply(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1254 break;
1255
1256 case '/':
1257 Parser.NextChar();
1258 Right = this.ParseUnary(Parser, false);
1259 Left = new Divide(Left, Right, Left.Start, Parser.Position - Left.Start, Parser.Expression);
1260 break;
1261
1262 default:
1263 return Left;
1264 }
1265 }
1266 }
1267
1268 private ScriptNode ParseUnary(ScriptParser Parser, bool Optional)
1269 {
1270 Parser.SkipWhiteSpace();
1271
1272 int Start = Parser.Position;
1273 char ch;
1274
1275 switch (ch = Parser.PeekNextChar())
1276 {
1277 case '!':
1278 Parser.NextChar();
1279 ScriptNode Node = this.ParseUnary(Parser, false);
1280 return new Not(Node, Start, Parser.Position - Start, Parser.Expression);
1281
1282 case '+':
1283 Parser.NextChar();
1284 return this.ParseUnary(Parser, false);
1285
1286 case '-':
1287 Parser.NextChar();
1288
1289 switch (Parser.PeekNextChar())
1290 {
1291 case '0':
1292 case '1':
1293 case '2':
1294 case '3':
1295 case '4':
1296 case '5':
1297 case '6':
1298 case '7':
1299 case '8':
1300 case '9':
1301 case '.':
1302 Parser.UndoChar();
1303 ISemanticElement Element2 = this.ParseElement(Parser, 2);
1304 return new ConstantElement(Element2, Start, Parser.Position - Start, Parser.Expression);
1305
1306 default:
1307 Node = this.ParseUnary(Parser, false);
1308 return new Negate(Node, Start, Parser.Position - Start, Parser.Expression);
1309 }
1310
1311 case '(':
1312 Parser.NextChar();
1313 Node = this.ParseNamedExpression(Parser);
1314 if (Parser.NextChar() != ')')
1315 throw Parser.SyntaxError("Expected )");
1316 return Node;
1317
1318 case '?':
1319 case '$':
1320 Parser.NextChar();
1321 string s = this.ParseName(Parser);
1322 return new VariableReference(s, Start, Parser.Position - Start, Parser.Expression);
1323
1324 case '\'':
1325 case '"':
1326 case '0':
1327 case '1':
1328 case '2':
1329 case '3':
1330 case '4':
1331 case '5':
1332 case '6':
1333 case '7':
1334 case '8':
1335 case '9':
1336 case '.':
1337 ISemanticElement Element = this.ParseElement(Parser, 2);
1338 return new ConstantElement(Element, Start, Parser.Position - Start, Parser.Expression);
1339
1340 case '<':
1341 Parser.NextChar();
1342 Element = this.ParseUri(Parser);
1343 return new ConstantElement(Element, Start, Parser.Position - Start, Parser.Expression);
1344
1345 case ':':
1346 Parser.NextChar();
1347 Element = this.ParsePrefixedToken(Parser, string.Empty);
1348 return new ConstantElement(Element, Start, Parser.Position - Start, Parser.Expression);
1349
1350 default:
1351 if (!char.IsLetter(ch))
1352 {
1353 if (Optional)
1354 return null;
1355
1356 throw Parser.SyntaxError("Expected value.");
1357 }
1358
1359 s = Parser.NextToken();
1360 if (Parser.PeekNextChar() == ':')
1361 {
1362 Parser.NextChar();
1363 UriNode Fqn = this.ParsePrefixedToken(Parser, s);
1364
1365 Parser.SkipWhiteSpace();
1366 if (Parser.PeekNextChar() == '(')
1367 return this.ParseExtensionFunction(Fqn.Uri.AbsoluteUri, Parser, Start);
1368 else
1369 return new ConstantElement(Fqn, Start, Parser.Position - Start, Parser.Expression);
1370 }
1371
1372 return this.ParseFunction(Parser, s, Start, Optional);
1373 }
1374 }
1375
1376 private ScriptNode ParseFunction(ScriptParser Parser, string s, int Start, bool Optional)
1377 {
1378 switch (s.ToUpper())
1379 {
1380 case "BIND":
1381 if (Parser.NextNonWhitespaceChar() != '(')
1382 throw Parser.SyntaxError("Expected (");
1383
1384 ScriptNode Node = this.ParseNamedExpression(Parser);
1385 if (!(Node is NamedNode NamedNode))
1386 throw Parser.SyntaxError("Expected name.");
1387
1388 if (this.currentRegularPattern is null)
1389 {
1390 this.currentRegularPattern = new SparqlRegularPattern();
1391 this.currentPattern = new IntersectionPattern(this.currentPattern, this.currentRegularPattern);
1392 }
1393
1394 this.currentRegularPattern.AddVariableBinding(NamedNode.LeftOperand, NamedNode.RightOperand);
1395
1396 if (Parser.NextNonWhitespaceChar() != ')')
1397 throw Parser.SyntaxError("Expected )");
1398
1399 return this.ParseUnary(Parser, Optional);
1400
1401 case "FILTER":
1402 Node = this.ParseUnary(Parser, false);
1403
1404 if (this.currentRegularPattern is null)
1405 {
1406 this.currentRegularPattern = new SparqlRegularPattern();
1407 this.currentPattern = new IntersectionPattern(this.currentPattern, this.currentRegularPattern);
1408 }
1409
1410 this.currentRegularPattern.AddFilter(Node);
1411
1412 return this.ParseUnary(Parser, Optional);
1413
1414 case "TRUE":
1415 return new ConstantElement(BooleanValue.True, Start, Parser.Position - Start, Parser.Expression);
1416
1417 case "FALSE":
1418 return new ConstantElement(BooleanValue.False, Start, Parser.Position - Start, Parser.Expression);
1419
1420 case "CONCAT":
1421 int Start2 = Parser.Position;
1422 ScriptNode[] Arguments = this.ParseArguments(Parser, 1, int.MaxValue);
1423
1424 VectorDefinition Vector = new VectorDefinition(Arguments,
1425 Start2, Parser.Position - Start2, Parser.Expression);
1426
1427 return new Concat(Vector, Start2, Parser.Position - Start2, Parser.Expression);
1428
1429 case "ASC":
1430 Node = this.ParseArgument(Parser);
1431 return new Asc(Node, Start, Parser.Position - Start, Parser.Expression);
1432
1433 case "DESC":
1434 Node = this.ParseArgument(Parser);
1435 return new Desc(Node, Start, Parser.Position - Start, Parser.Expression);
1436
1437 case "REGEX":
1438 Arguments = this.ParseArguments(Parser, 2, 3);
1439 if (Arguments.Length == 2)
1440 {
1441 return new LikeWithOptions(Arguments[0], Arguments[1], null,
1442 Start, Parser.Position - Start, Parser.Expression);
1443 }
1444 else
1445 {
1446 return new LikeWithOptions(Arguments[0], Arguments[1], Arguments[2],
1447 Start, Parser.Position - Start, Parser.Expression);
1448 }
1449
1450 case "EXISTS":
1451 return new Exists(this.ParsePattern(Parser),
1452 Start, Parser.Position - Start, Parser.Expression);
1453
1454 case "NOT": // EXISTS
1455 if (Parser.NextToken() != "EXISTS")
1456 throw Parser.SyntaxError("Expected EXISTS.");
1457
1458 return new NotExists(this.ParsePattern(Parser),
1459 Start, Parser.Position - Start, Parser.Expression);
1460
1461 case "COUNT":
1462 Node = this.ParseArgument(Parser);
1463 return new Count(Node, Start, Parser.Position - Start, Parser.Expression);
1464
1465 case "SUM":
1466 Node = this.ParseArgument(Parser);
1467 return new Sum(Node, Start, Parser.Position - Start, Parser.Expression);
1468
1469 case "MIN":
1470 Node = this.ParseArgument(Parser);
1471 return new Script.Functions.Vectors.Min(Node, Start, Parser.Position - Start, Parser.Expression);
1472
1473 case "MAX":
1474 Node = this.ParseArgument(Parser);
1475 return new Script.Functions.Vectors.Max(Node, Start, Parser.Position - Start, Parser.Expression);
1476
1477 case "AVG":
1478 Node = this.ParseArgument(Parser);
1479 return new Average(Node, Start, Parser.Position - Start, Parser.Expression);
1480
1481 case "GROUP_CONCAT":
1482 Node = this.ParseArgumentOptionalScalarVal(Parser, "separator", out ScriptNode Node2);
1483 if (Node2 is null)
1484 return new Concat(Node, Start, Parser.Position - Start, Parser.Expression);
1485 else
1486 return new Concat(Node, Node2, Start, Parser.Position - Start, Parser.Expression);
1487
1488 case "SAMPLE":
1489 Node = this.ParseArgument(Parser);
1490 return new Sample(Node, Start, Parser.Position - Start, Parser.Expression);
1491
1492 case "STR":
1493 Node = this.ParseArgument(Parser);
1494 return new Script.Functions.Scalar.String(Node, Start, Parser.Position - Start, Parser.Expression);
1495
1496 case "ABS":
1497 Node = this.ParseArgument(Parser);
1498 return new Abs(Node, Start, Parser.Position - Start, Parser.Expression);
1499
1500 case "CEIL":
1501 Node = this.ParseArgument(Parser);
1502 return new Ceiling(Node, Start, Parser.Position - Start, Parser.Expression);
1503
1504 case "FLOOR":
1505 Node = this.ParseArgument(Parser);
1506 return new Floor(Node, Start, Parser.Position - Start, Parser.Expression);
1507
1508 case "ROUND":
1509 Node = this.ParseArgument(Parser);
1510 return new Round(Node, Start, Parser.Position - Start, Parser.Expression);
1511
1512 case "STRLEN":
1513 Node = this.ParseArgument(Parser);
1514 return new Length(Node, Start, Parser.Position - Start, Parser.Expression);
1515
1516 case "UCASE":
1517 Node = this.ParseArgument(Parser);
1518 return new UpperCase(Node, Start, Parser.Position - Start, Parser.Expression);
1519
1520 case "LCASE":
1521 Node = this.ParseArgument(Parser);
1522 return new LowerCase(Node, Start, Parser.Position - Start, Parser.Expression);
1523
1524 case "CONTAINS":
1525 this.Parse2Arguments(Parser, out Node, out Node2);
1526 return new Contains(Node, Node2, Start, Parser.Position - Start, Parser.Expression);
1527
1528 case "STRSTARTS":
1529 this.Parse2Arguments(Parser, out Node, out Node2);
1530 return new StartsWith(Node, Node2, Start, Parser.Position - Start, Parser.Expression);
1531
1532 case "STRENDS":
1533 this.Parse2Arguments(Parser, out Node, out Node2);
1534 return new EndsWith(Node, Node2, Start, Parser.Position - Start, Parser.Expression);
1535
1536 case "STRBEFORE":
1537 this.Parse2Arguments(Parser, out Node, out Node2);
1538 return new Before(Node, Node2, Start, Parser.Position - Start, Parser.Expression);
1539
1540 case "STRAFTER":
1541 this.Parse2Arguments(Parser, out Node, out Node2);
1542 return new After(Node, Node2, Start, Parser.Position - Start, Parser.Expression);
1543
1544 case "SUBSTR":
1545 Arguments = this.ParseArguments(Parser, 2, 3);
1546 int NodeStart = Arguments[1].Start;
1547 int NodeLen = Arguments[1].Length;
1548
1549 Arguments[1] = new Subtract(Arguments[1],
1550 new ConstantElement(new DoubleNumber(1), NodeStart, NodeLen, Parser.Expression),
1551 NodeStart, NodeLen, Parser.Expression);
1552
1553 if (Arguments.Length == 2)
1554 {
1555 return new Mid(Arguments[0], Arguments[1], null,
1556 Start, Parser.Position - Start, Parser.Expression);
1557 }
1558 else
1559 {
1560 return new Mid(Arguments[0], Arguments[1], Arguments[2],
1561 Start, Parser.Position - Start, Parser.Expression);
1562 }
1563
1564 case "YEAR":
1565 Node = this.ParseArgument(Parser);
1566 return new Year(Node, Start, Parser.Position - Start, Parser.Expression);
1567
1568 case "MONTH":
1569 Node = this.ParseArgument(Parser);
1570 return new Month(Node, Start, Parser.Position - Start, Parser.Expression);
1571
1572 case "DAY":
1573 Node = this.ParseArgument(Parser);
1574 return new Day(Node, Start, Parser.Position - Start, Parser.Expression);
1575
1576 case "HOURS":
1577 Node = this.ParseArgument(Parser);
1578 return new Hour(Node, Start, Parser.Position - Start, Parser.Expression);
1579
1580 case "MINUTES":
1581 Node = this.ParseArgument(Parser);
1582 return new Minute(Node, Start, Parser.Position - Start, Parser.Expression);
1583
1584 case "SECONDS":
1585 Node = this.ParseArgument(Parser);
1586 return new Second(Node, Start, Parser.Position - Start, Parser.Expression);
1587
1588 case "NOW":
1589 this.Parse0Arguments(Parser);
1590 return new VariableReference("Now", Start, Parser.Position - Start, Parser.Expression);
1591
1592 case "MD5":
1593 Node = this.ParseArgument(Parser);
1594 NodeStart = Node.Start;
1595 NodeLen = Node.Length;
1596
1597 return new HexEncode(
1598 new Md5(Node, NodeStart, NodeLen, Parser.Expression),
1599 NodeStart, NodeLen, Parser.Expression);
1600
1601 case "SHA1":
1602 Node = this.ParseArgument(Parser);
1603 NodeStart = Node.Start;
1604 NodeLen = Node.Length;
1605
1606 return new HexEncode(
1607 new Sha1(Node, NodeStart, NodeLen, Parser.Expression),
1608 NodeStart, NodeLen, Parser.Expression);
1609
1610 case "SHA256":
1611 Node = this.ParseArgument(Parser);
1612 NodeStart = Node.Start;
1613 NodeLen = Node.Length;
1614
1615 return new HexEncode(
1616 new Sha2_256(Node, NodeStart, NodeLen, Parser.Expression),
1617 NodeStart, NodeLen, Parser.Expression);
1618
1619 case "SHA384":
1620 Node = this.ParseArgument(Parser);
1621 NodeStart = Node.Start;
1622 NodeLen = Node.Length;
1623
1624 return new HexEncode(
1625 new Sha2_384(Node, NodeStart, NodeLen, Parser.Expression),
1626 NodeStart, NodeLen, Parser.Expression);
1627
1628 case "SHA512":
1629 Node = this.ParseArgument(Parser);
1630 NodeStart = Node.Start;
1631 NodeLen = Node.Length;
1632
1633 return new HexEncode(
1634 new Sha2_512(Node, NodeStart, NodeLen, Parser.Expression),
1635 NodeStart, NodeLen, Parser.Expression);
1636
1637 case "RAND":
1638 this.Parse0Arguments(Parser);
1639 return new Uniform(Start, Parser.Position - Start, Parser.Expression);
1640
1641 case "ENCODE_FOR_URI":
1642 Node = this.ParseArgument(Parser);
1643 return new UrlEncode(Node, Start, Parser.Position - Start, Parser.Expression);
1644
1645 case "STRUUID":
1646 this.Parse0Arguments(Parser);
1647 NodeLen = Parser.Position - Start;
1648
1649 return new Script.Functions.Scalar.String(
1650 new NewGuid(Start, NodeLen, Parser.Expression),
1651 Start, NodeLen, Parser.Expression);
1652
1653 case "UUID":
1654 this.Parse0Arguments(Parser);
1655 NodeLen = Parser.Position - Start;
1656
1657 return new Script.Functions.Scalar.Uri(
1658 new Add(
1659 new ConstantElement(new StringValue("urn:uuid:"), Start, NodeLen, Parser.Expression),
1660 new Script.Functions.Scalar.String(
1661 new NewGuid(Start, NodeLen, Parser.Expression),
1662 Start, NodeLen, Parser.Expression),
1663 Start, NodeLen, Parser.Expression),
1664 Start, NodeLen, Parser.Expression);
1665
1666 case "IRI":
1667 case "URI":
1668 Node = this.ParseArgument(Parser);
1669 return new Script.Functions.Scalar.Uri(Node, Start, Parser.Position - Start, Parser.Expression);
1670
1671 case "IF":
1672 Arguments = this.ParseArguments(Parser, 3, 3);
1673 return new If(Arguments[0], Arguments[1], Arguments[2],
1674 Start, Parser.Position - Start, Parser.Expression);
1675
1676 case "SAMETERM":
1677 this.Parse2Arguments(Parser, out Node, out Node2);
1678 return new EqualTo(Node, Node2, Start, Parser.Position - Start, Parser.Expression);
1679
1680 case "BOUND":
1681 Node = this.ParseArgument(Parser);
1682 return new Script.Functions.Runtime.Exists(Node, Start, Parser.Position - Start, Parser.Expression);
1683
1684 case "ISIRI":
1685 case "ISURI":
1686 Node = this.ParseArgument(Parser);
1687 return new IsUri(Node, Start, Parser.Position - Start, Parser.Expression);
1688
1689 case "ISBLANK":
1690 Node = this.ParseArgument(Parser);
1691 return new IsBlank(Node, Start, Parser.Position - Start, Parser.Expression);
1692
1693 case "ISNUMERIC":
1694 Node = this.ParseArgument(Parser);
1695 return new IsNumeric(Node, Start, Parser.Position - Start, Parser.Expression);
1696
1697 case "ISLITERAL":
1698 Node = this.ParseArgument(Parser);
1699 return new IsLiteral(Node, Start, Parser.Position - Start, Parser.Expression);
1700
1701 case "LANG":
1702 Node = this.ParseArgument(Parser);
1703 return new Lang(Node, Start, Parser.Position - Start, Parser.Expression);
1704
1705 case "DATATYPE":
1706 Node = this.ParseArgument(Parser);
1707 return new DataType(Node, Start, Parser.Position - Start, Parser.Expression);
1708
1709 case "BNODE":
1710 Arguments = this.ParseArguments(Parser, 0, 1);
1711
1712 if (Arguments.Length == 0)
1713 return new BNode(Start, Parser.Position - Start, Parser.Expression);
1714 else
1715 return new BNode(Arguments[0], Start, Parser.Position - Start, Parser.Expression);
1716
1717 case "STRDT":
1718 this.Parse2Arguments(Parser, out Node, out Node2);
1719 return new StrDt(Node, Node2, Start, Parser.Position - Start, Parser.Expression);
1720
1721 case "STRLANG":
1722 this.Parse2Arguments(Parser, out Node, out Node2);
1723 return new StrLang(Node, Node2, Start, Parser.Position - Start, Parser.Expression);
1724
1725 case "LANGMATCHES":
1726 this.Parse2Arguments(Parser, out Node, out Node2);
1727 return new LangMatches(Node, Node2, Start, Parser.Position - Start, Parser.Expression);
1728
1729 case "REPLACE":
1730 Arguments = this.ParseArguments(Parser, 3, 4);
1731 if (Arguments.Length == 2)
1732 {
1733 return new Replace(Arguments[0], Arguments[1], Arguments[2], true,
1734 Start, Parser.Position - Start, Parser.Expression);
1735 }
1736 else
1737 {
1738 return new Replace(Arguments[0], Arguments[1], Arguments[2], Arguments[3],
1739 Start, Parser.Position - Start, Parser.Expression);
1740 }
1741
1742 case "TIMEZONE":
1743 Node = this.ParseArgument(Parser);
1744 return new Waher.Content.Semantic.Functions.TimeZone(Node, Start, Parser.Position - Start, Parser.Expression);
1745
1746 case "TZ":
1747 Node = this.ParseArgument(Parser);
1748 return new Tz(Node, Start, Parser.Position - Start, Parser.Expression);
1749
1750 case "COALESCE":
1751 Arguments = this.ParseArguments(Parser, 1, int.MaxValue);
1752 return new Coalesce(Arguments, Start, Parser.Position - Start, Parser.Expression);
1753
1754 case "ERROR":
1755 Node = this.ParseArgument(Parser);
1756 return new Script.Functions.Runtime.Error(Node, Start, Parser.Position - Start, Parser.Expression);
1757
1758 case "TRIPLE":
1759 Arguments = this.ParseArguments(Parser, 3, 3);
1760 return new Triple(Arguments[0], Arguments[1], Arguments[2], Start, Parser.Position - Start, Parser.Expression);
1761
1762 case "SUBJECT":
1763 Node = this.ParseArgument(Parser);
1764 return new Subject(Node, Start, Parser.Position - Start, Parser.Expression);
1765
1766 case "PREDICATE":
1767 Node = this.ParseArgument(Parser);
1768 return new Predicate(Node, Start, Parser.Position - Start, Parser.Expression);
1769
1770 case "OBJECT":
1771 Node = this.ParseArgument(Parser);
1772 return new Waher.Content.Semantic.Functions.Object(Node, Start, Parser.Position - Start, Parser.Expression);
1773
1774 case "ISTRIPLE":
1775 Node = this.ParseArgument(Parser);
1776 return new IsTriple(Node, Start, Parser.Position - Start, Parser.Expression);
1777
1778 default:
1779 if (Parser.PeekNextChar() == ':')
1780 {
1781 s = this.ParsePrefixedToken(Parser, s).Uri.AbsoluteUri;
1782 return this.ParseExtensionFunction(s, Parser, Start);
1783 }
1784
1785 if (Optional)
1786 {
1787 int i = s.Length;
1788 while (i-- > 0)
1789 Parser.UndoChar();
1790
1791 return null;
1792 }
1793
1794 throw Parser.SyntaxError("Unexpected token: " + s);
1795 }
1796 }
1797
1798 private ScriptNode ParseExtensionFunction(string FullyQualifiedName, ScriptParser Parser, int Start)
1799 {
1801
1802 lock (functionsPerUri)
1803 {
1804 if (!functionsPerUri.TryGetValue(FullyQualifiedName, out Function))
1805 {
1806 Function = Types.FindBest<IExtensionFunction, string>(FullyQualifiedName);
1807 functionsPerUri[FullyQualifiedName] = Function;
1808 }
1809 }
1810
1811 if (Function is null)
1812 throw Parser.SyntaxError("Function not found.");
1813
1814 ScriptNode[] Arguments = this.ParseArguments(Parser, Function.MinArguments, Function.MaxArguments);
1815
1816 return Function.CreateFunction(Arguments, Start, Parser.Position - Start, Parser.Expression);
1817 }
1818
1819 private void Parse0Arguments(ScriptParser Parser)
1820 {
1821 if (Parser.NextNonWhitespaceChar() != '(')
1822 throw Parser.SyntaxError("Expected (");
1823
1824 if (Parser.NextNonWhitespaceChar() != ')')
1825 throw Parser.SyntaxError("Expected )");
1826 }
1827
1828 private ScriptNode ParseArgument(ScriptParser Parser)
1829 {
1830 if (Parser.NextNonWhitespaceChar() != '(')
1831 throw Parser.SyntaxError("Expected (");
1832
1833 ScriptNode Argument = this.ParseExpression(Parser, false);
1834
1835 if (Parser.NextNonWhitespaceChar() != ')')
1836 throw Parser.SyntaxError("Expected )");
1837
1838 return Argument;
1839 }
1840
1841 private void Parse2Arguments(ScriptParser Parser, out ScriptNode Argument1, out ScriptNode Argument2)
1842 {
1843 if (Parser.NextNonWhitespaceChar() != '(')
1844 throw Parser.SyntaxError("Expected (");
1845
1846 Argument1 = this.ParseExpression(Parser, false);
1847
1848 if (Parser.NextNonWhitespaceChar() != ',')
1849 throw Parser.SyntaxError("Expected ,");
1850
1851 Argument2 = this.ParseExpression(Parser, false);
1852
1853 if (Parser.NextNonWhitespaceChar() != ')')
1854 throw Parser.SyntaxError("Expected )");
1855 }
1856
1857 private ScriptNode ParseArgumentOptionalScalarVal(ScriptParser Parser, string ExpectedScalarName, out ScriptNode ScalarVal)
1858 {
1859 if (Parser.NextNonWhitespaceChar() != '(')
1860 throw Parser.SyntaxError("Expected (");
1861
1862 ScriptNode Argument = this.ParseExpression(Parser, false);
1863
1864 switch (Parser.NextNonWhitespaceChar())
1865 {
1866 case ')':
1867 ScalarVal = null;
1868 return Argument;
1869
1870 case ';':
1871 string s = this.ParseName(Parser);
1872 if (s != ExpectedScalarName)
1873 throw Parser.SyntaxError("Expected " + ExpectedScalarName);
1874
1875 if (Parser.NextNonWhitespaceChar() != '=')
1876 throw Parser.SyntaxError("Expected =");
1877
1878 ScalarVal = this.ParseExpression(Parser, false);
1879
1880 if (Parser.NextNonWhitespaceChar() != ')')
1881 throw Parser.SyntaxError("Expected )");
1882
1883 return Argument;
1884
1885 default:
1886 throw Parser.SyntaxError("Expected ) or ;");
1887 }
1888 }
1889
1890 private ScriptNode[] ParseArguments(ScriptParser Parser, int Min, int Max)
1891 {
1892 if (Parser.NextNonWhitespaceChar() != '(')
1893 throw Parser.SyntaxError("Expected (");
1894
1895 List<ScriptNode> Arguments = new List<ScriptNode>();
1896
1897 while (true)
1898 {
1899 Arguments.Add(this.ParseExpression(Parser, false));
1900
1901 if (Parser.NextNonWhitespaceChar() != ',')
1902 {
1903 Parser.UndoChar();
1904 break;
1905 }
1906 }
1907
1908 int c = Arguments.Count;
1909 if (c < Min)
1910 throw Parser.SyntaxError("Expected at least " + Min.ToString() + " arguments.");
1911
1912 if (c > Max)
1913 throw Parser.SyntaxError("Expected at most " + Max.ToString() + " arguments.");
1914
1915 if (Parser.NextNonWhitespaceChar() != ')')
1916 throw Parser.SyntaxError("Expected )");
1917
1918 return Arguments.ToArray();
1919 }
1920
1921 private ISemanticElement ParseElement(ScriptParser Parser, int TriplePosition)
1922 {
1923 while (true)
1924 {
1925 char ch = Parser.NextNonWhitespaceChar();
1926
1927 switch (ch)
1928 {
1929 case (char)0:
1930 return null;
1931
1932 case '[':
1933 if (TriplePosition == 1)
1934 throw Parser.SyntaxError("Predicate cannot be a blank node.");
1935
1936 BlankNode Node = this.CreateBlankNode();
1937 this.ParseTriples(Parser, Node);
1938 return Node;
1939
1940 case '(':
1941 return this.ParseCollection(Parser);
1942
1943 case ']':
1944 return null;
1945
1946 case '}':
1947 Parser.UndoChar();
1948 return null;
1949
1950 case '<':
1951 return this.ParseUri(Parser);
1952
1953 case '"':
1954 if (TriplePosition != 2)
1955 throw Parser.SyntaxError("Literals can only occur in object position.");
1956
1957 string s;
1958
1959 if (Parser.IsNextChars('"', 2))
1960 {
1961 Parser.SkipChars(2);
1962 s = this.ParseString(Parser, '"', true, true);
1963 }
1964 else
1965 s = this.ParseString(Parser, '"', false, true);
1966
1967 string Language = null;
1968
1969 if (Parser.PeekNextChar() == '@')
1970 {
1971 Parser.NextChar();
1972 Language = this.ParseName(Parser);
1973 }
1974
1975 if (Parser.IsNextChars('^', 2))
1976 {
1977 Parser.SkipChars(2);
1978
1979 string DataType = this.ParseUriOrPrefixedToken(Parser).Uri.ToString();
1980
1981 return SemanticElements.Parse(s, DataType, Language);
1982 }
1983 else if (!string.IsNullOrEmpty(Language))
1984 return new StringLiteral(s, Language);
1985 else
1986 return new StringLiteral(s);
1987
1988 case ':':
1989 return this.ParsePrefixedToken(Parser, string.Empty);
1990
1991 case '?':
1992 case '$':
1993 int Start2 = Parser.Position;
1994 s = this.ParseName(Parser);
1995 return new SemanticScriptElement(new VariableReference(s, Start2, Parser.Position - Start2, Parser.Expression));
1996
1997 default:
1998 if (char.IsWhiteSpace(ch))
1999 break;
2000
2001 if (ch == '_')
2002 {
2003 if (Parser.NextNonWhitespaceChar() != ':')
2004 throw Parser.SyntaxError("Expected :");
2005
2006 return new BlankNode(this.ParseName(Parser));
2007 }
2008 else if (char.IsLetter(ch) || ch == ':')
2009 {
2010 Parser.UndoChar();
2011 Start2 = Parser.Position;
2012 s = this.ParseName(Parser);
2013
2014 if (Parser.PeekNextChar() == ':')
2015 {
2016 Parser.NextChar();
2017 return this.ParsePrefixedToken(Parser, s);
2018 }
2019
2020 switch (s)
2021 {
2022 case "a":
2023 if (TriplePosition == 1)
2024 return RdfDocument.RdfType;
2025 break;
2026
2027 case "true":
2028 if (TriplePosition == 2)
2029 return new BooleanLiteral(true);
2030 break;
2031
2032 case "false":
2033 if (TriplePosition == 2)
2034 return new BooleanLiteral(false);
2035 break;
2036 }
2037
2038 if (string.Compare(s, "UNDEF", true) == 0)
2039 {
2040 if (TriplePosition != 2)
2041 throw Parser.SyntaxError("UNDEF not permitted.");
2042
2043 return new UndefinedLiteral();
2044 }
2045
2046 ScriptNode ScriptNode = this.ParseFunction(Parser, s, Start2, true);
2047
2048 if (ScriptNode is null)
2049 {
2050 if (TriplePosition == 0)
2051 {
2052 Parser.UndoChar();
2053 return null;
2054 }
2055 else
2056 throw Parser.SyntaxError("Expected :");
2057 }
2058
2060 }
2061 else
2062 {
2063 if (TriplePosition != 2)
2064 throw Parser.SyntaxError("Literals can only occur in object position.");
2065
2066 Parser.UndoChar();
2067 return this.ParseNumber(Parser);
2068 }
2069 }
2070 }
2071 }
2072
2073 private BlankNode CreateBlankNode()
2074 {
2075 return new BlankNode("n" + (++this.blankNodeIndex).ToString());
2076 }
2077
2078 private ISemanticElement ParseCollection(ScriptParser Parser)
2079 {
2080 LinkedList<ISemanticElement> Elements = null;
2081
2082 Parser.SkipWhiteSpace();
2083
2084 while (Parser.InScript)
2085 {
2086 if (Parser.PeekNextChar() == ')')
2087 {
2088 Parser.NextChar();
2089
2090 if (Elements is null)
2091 return RdfDocument.RdfNil;
2092
2093 LinkedListNode<ISemanticElement> Loop = Elements.First;
2094 BlankNode Result = this.CreateBlankNode();
2095 BlankNode Current = Result;
2096
2097 if (this.currentRegularPattern is null)
2098 {
2099 this.currentRegularPattern = new SparqlRegularPattern();
2100 this.currentPattern = new IntersectionPattern(this.currentPattern, this.currentRegularPattern);
2101 }
2102
2103 while (!(Loop is null))
2104 {
2105 this.currentRegularPattern.AddTriple(new SemanticQueryTriple(Current, RdfDocument.RdfFirst, Loop.Value));
2106
2107 Loop = Loop.Next;
2108
2109 if (!(Loop is null))
2110 {
2111 BlankNode Next = this.CreateBlankNode();
2112 this.currentRegularPattern.AddTriple(new SemanticQueryTriple(Current, RdfDocument.RdfRest, Next));
2113 Current = Next;
2114 }
2115 }
2116
2117 this.currentRegularPattern.AddTriple(new SemanticQueryTriple(Current, RdfDocument.RdfRest, RdfDocument.RdfNil));
2118
2119 return Result;
2120 }
2121
2122 ISemanticElement Element = this.ParseElement(Parser, 2);
2123 if (Element is null)
2124 break;
2125
2126 if (Elements is null)
2127 Elements = new LinkedList<ISemanticElement>();
2128
2129 Elements.AddLast(Element);
2130 Parser.SkipWhiteSpace();
2131 }
2132
2133 throw Parser.SyntaxError("Expected )");
2134 }
2135
2136 private UriNode ParseUriOrPrefixedToken(ScriptParser Parser)
2137 {
2138 if (Parser.EndOfScript)
2139 throw Parser.SyntaxError("Expected URI or prefixed token.");
2140
2141 if (Parser.PeekNextChar() == '<')
2142 {
2143 Parser.NextChar();
2144 return this.ParseUri(Parser);
2145 }
2146
2147 string Prefix = this.ParseName(Parser);
2148
2149 if (Parser.NextChar() != ':')
2150 throw Parser.SyntaxError("Expected :");
2151
2152 return this.ParsePrefixedToken(Parser, Prefix);
2153 }
2154
2155 private UriNode ParsePrefixedToken(ScriptParser Parser, string Prefix)
2156 {
2157 if (!this.namespaces.TryGetValue(Prefix, out string Namespace))
2158 throw Parser.SyntaxError("Prefix unknown.");
2159
2160 Parser.SkipWhiteSpace();
2161
2162 string LocalName = this.ParseName(Parser);
2163
2164 return new UriNode(new System.Uri(Namespace + LocalName), Prefix + ":" + LocalName);
2165 }
2166
2167 private string ParseName(ScriptParser Parser)
2168 {
2170 return string.Empty;
2171
2172 int Start = Parser.Position;
2173 Parser.NextChar();
2174
2175 while (TurtleDocument.IsNameChar(Parser.PeekNextChar()))
2176 Parser.NextChar();
2177
2178 return Parser.Expression.Script.Substring(Start, Parser.Position - Start);
2179 }
2180
2181 private int ParsePositiveInteger(ScriptParser Parser)
2182 {
2183 Parser.SkipWhiteSpace();
2184
2185 int Start = Parser.Position;
2186
2187 while (char.IsDigit(Parser.PeekNextChar()))
2188 Parser.NextChar();
2189
2190 string s = Parser.Expression.Script.Substring(Start, Parser.Position - Start);
2191
2192 if (!int.TryParse(s, out int i))
2193 throw Parser.SyntaxError("Expected non-negative integer.");
2194
2195 return i;
2196 }
2197
2198 private SemanticLiteral ParseNumber(ScriptParser Parser)
2199 {
2200 int Start = Parser.Position;
2201 char ch = Parser.PeekNextChar();
2202 bool HasDigits = false;
2203 bool HasDecimal = false;
2204 bool HasExponent = false;
2205
2206 if (ch == '+' || ch == '-')
2207 {
2208 Parser.NextChar();
2209 ch = Parser.PeekNextChar();
2210 }
2211
2212 while (char.IsDigit(ch))
2213 {
2214 Parser.NextChar();
2215 ch = Parser.PeekNextChar();
2216 HasDigits = true;
2217 }
2218
2219 if (ch == '.')
2220 {
2221 HasDecimal = true;
2222 Parser.NextChar();
2223 ch = Parser.PeekNextChar();
2224
2225 while (char.IsDigit(ch))
2226 {
2227 Parser.NextChar();
2228 ch = Parser.PeekNextChar();
2229 }
2230 }
2231
2232 if (ch == 'e' || ch == 'E')
2233 {
2234 HasExponent = true;
2235 Parser.NextChar();
2236 ch = Parser.PeekNextChar();
2237
2238 if (ch == '+' || ch == '-')
2239 {
2240 Parser.NextChar();
2241 ch = Parser.PeekNextChar();
2242 }
2243
2244 while (char.IsDigit(ch))
2245 {
2246 Parser.NextChar();
2247 ch = Parser.PeekNextChar();
2248 }
2249 }
2250
2251 if (Parser.Position > Start)
2252 {
2253 string s = Parser.Expression.Script.Substring(Start, Parser.Position - Start);
2254
2255 if (HasExponent)
2256 {
2257 if (CommonTypes.TryParse(s, out double dbl))
2258 return new DoubleLiteral(dbl, s);
2259 else
2260 throw Parser.SyntaxError("Invalid double number.");
2261 }
2262 else if (HasDecimal)
2263 {
2264 if (CommonTypes.TryParse(s, out decimal dec))
2265 return new DecimalLiteral(dec, s);
2266 else
2267 throw Parser.SyntaxError("Invalid decimal number.");
2268 }
2269 else if (HasDigits)
2270 {
2271 if (BigInteger.TryParse(s, out BigInteger bi))
2272 return new IntegerLiteral(bi, s);
2273 else
2274 throw Parser.SyntaxError("Invalid integer number.");
2275 }
2276 }
2277
2278 throw Parser.SyntaxError("Expected value element.");
2279 }
2280
2281 private string ParseString(ScriptParser Parser, char EndChar, bool MultiLine, bool IncludeWhiteSpace)
2282 {
2283 StringBuilder sb = null;
2284 int Start = Parser.Position;
2285 char ch;
2286
2287 while ((ch = Parser.PeekNextChar()) != (char)0)
2288 {
2289 Parser.NextChar();
2290
2291 if (ch == EndChar)
2292 {
2293 if (MultiLine)
2294 {
2295 if (Parser.IsNextChars(EndChar, 2))
2296 {
2297 Parser.SkipChars(2);
2298 return sb?.ToString() ?? Parser.Expression.Script.Substring(Start, Parser.Position - Start - 3);
2299 }
2300 else
2301 sb?.Append(ch);
2302 }
2303 else
2304 return sb?.ToString() ?? Parser.Expression.Script.Substring(Start, Parser.Position - Start - 1);
2305 }
2306 else if (ch == '\\')
2307 {
2308 if (sb is null)
2309 {
2310 sb = new StringBuilder();
2311
2312 if (Parser.Position > Start + 1)
2313 sb.Append(Parser.Expression.Script.Substring(Start, Parser.Position - Start - 1));
2314 }
2315
2316 switch (ch = Parser.NextChar())
2317 {
2318 case (char)0:
2319 throw Parser.SyntaxError("Expected escape code.");
2320
2321 case 't':
2322 sb.Append('\t');
2323 break;
2324
2325 case 'n':
2326 sb.Append('\n');
2327 break;
2328
2329 case 'r':
2330 sb.Append('\r');
2331 break;
2332
2333 case 'v':
2334 sb.Append('\v');
2335 break;
2336
2337 case 'f':
2338 sb.Append('\f');
2339 break;
2340
2341 case 'b':
2342 sb.Append('\b');
2343 break;
2344
2345 case 'a':
2346 sb.Append('\a');
2347 break;
2348
2349 case 'u':
2350 if (Parser.HasCharacters(4) && int.TryParse(Parser.PeekNextChars(4), System.Globalization.NumberStyles.HexNumber, null, out int i))
2351 {
2352 sb.Append((char)i);
2353 Parser.SkipChars(4);
2354 }
2355 else
2356 throw Parser.SyntaxError("Expected 4-character hexadecimal code.");
2357 break;
2358
2359 case 'U':
2360 if (Parser.HasCharacters(8) && int.TryParse(Parser.PeekNextChars(8), System.Globalization.NumberStyles.HexNumber, null, out i))
2361 {
2362 sb.Append((char)i);
2363 Parser.SkipChars(8);
2364 }
2365 else
2366 throw Parser.SyntaxError("Expected 8-character hexadecimal code.");
2367 break;
2368
2369 default:
2370 sb.Append(ch);
2371 break;
2372 }
2373 }
2374 else if (IncludeWhiteSpace || !char.IsWhiteSpace(ch))
2375 sb?.Append(ch);
2376 }
2377
2378 throw Parser.SyntaxError("Expected " + new string(EndChar, MultiLine ? 3 : 1));
2379 }
2380
2381 private UriNode ParseUri(ScriptParser Parser)
2382 {
2383 string Short = this.ParseString(Parser, '>', false, false);
2384
2385 if (this.baseUri is null)
2386 {
2387 if (System.Uri.TryCreate(Short, UriKind.RelativeOrAbsolute, out System.Uri URI))
2388 return new UriNode(URI, Short);
2389 else
2390 throw Parser.SyntaxError("Invalid URI.");
2391 }
2392 else
2393 {
2394 if (string.IsNullOrEmpty(Short))
2395 return new UriNode(this.baseUri, Short);
2396 else if (System.Uri.TryCreate(this.baseUri, Short, out System.Uri URI))
2397 return new UriNode(URI, Short);
2398 else
2399 throw Parser.SyntaxError("Invalid URI.");
2400 }
2401 }
2402
2403 }
2404}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Definition: CommonTypes.cs:46
Coalesce(Expression, ...)
Definition: Coalesce.cs:15
LangMatches(Language,Pattern)
Definition: LangMatches.cs:13
Triple(Subject,Predicate,Object)
Definition: Triple.cs:13
Represents a blank node
Definition: BlankNode.cs:7
Represents an integer literal of undefined size.
static ISemanticElement Parse(string Value, string DataType, string Language)
Parses a string literal value.
Abstract base class for semantic literal values.
Contains semantic information stored in an RDF document.
Definition: RdfDocument.cs:21
static UriNode RdfType
rdf:type predicate
Definition: RdfDocument.cs:25
static UriNode RdfNil
Predefined reference to end of collection.
Definition: RdfDocument.cs:40
static UriNode RdfRest
Predefined reference to next element in a collection.
Definition: RdfDocument.cs:35
static UriNode RdfFirst
Predefined reference to first element in a collection.
Definition: RdfDocument.cs:30
Contains semantic information stored in a turtle document. https://www.w3.org/TR/rdf12-turtle/ https:...
static bool IsNameChar(char ch)
Checks if a character can be included in a name.
static bool IsNameStartChar(char ch)
Checks if a character is a character that can start a name.
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:14
string Script
Original script string.
Definition: Expression.cs:181
Concatenates the elements of a vector, optionally delimiting the elements with a Delimiter.
Definition: Concat.cs:12
EndsWith(String,Substring)
Definition: EndsWith.cs:11
Replace(String,From,To)
Definition: Replace.cs:13
StartsWith(String,Substring)
Definition: StartsWith.cs:11
ScriptNode RightOperand
Right operand.
ScriptNode LeftOperand
Left operand.
Represents a constant element value.
Base class for all funcions.
Definition: Function.cs:9
ScriptNode Argument
Function argument.
Base class for all nodes in a parsed script tree.
Definition: ScriptNode.cs:69
int Length
Length of expression covered by node.
Definition: ScriptNode.cs:101
override string ToString()
Definition: ScriptNode.cs:359
int Start
Start position in script expression.
Definition: ScriptNode.cs:92
Script parser, for custom parsers.
Definition: ScriptParser.cs:10
SyntaxException SyntaxError(string Message)
Returns a Syntax Error Exception object.
string PeekNextToken()
Returns the next token to be parsed, without moving the position forward. If at the end of the expres...
bool HasCharacters(int NrCharacters)
If there are a given number of characters left to parse.
bool IsNextChars(string Token)
If the next characters to be parsed is a given token.
string NextToken()
Returns the next token to be parsed, and moves the position forward correspondingly....
int Start
Start position in expression
Definition: ScriptParser.cs:28
int Position
Current parsing position.
Definition: ScriptParser.cs:38
bool InScript
If position is in script.
Expression Expression
Expression being parsed.
Definition: ScriptParser.cs:43
void UndoChar()
Undoes a character in the parsing of an expression.
Definition: ScriptParser.cs:82
string PeekNextChars(int NrChars)
Returns the next given number of characters to be parsed, without moving the position forward one cha...
Definition: ScriptParser.cs:92
void SkipChars(int NrChars)
Skips a predefined number of characters.
char PeekNextChar()
Returns the next character to be parsed, without moving the position forward one character....
bool EndOfScript
If position is at end of script.
void SkipWhiteSpace()
If current position is whitespace, moves the current position forward to the first non-whitespace cha...
char NextChar()
Returns the next character to be parsed, and moves the position forward one character....
ScriptNode ParseObject()
Parses an object ex nihilo.
char NextNonWhitespaceChar()
Returns the next non-whitespace character to be parsed, and moves the position forward accordingly....
Definition: ScriptParser.cs:66
Represents a variable reference.
Boolean-valued number.
Definition: BooleanValue.cs:12
static readonly BooleanValue False
Constant false value.
static readonly BooleanValue True
Constant true value.
Checks if a pattern has at least a match.
Definition: Exists.cs:15
Extension of the Like operator, that allows the script to set options.
Checks if a pattern has at least no matches.
Definition: NotExists.cs:15
SparqlParser(string Preamble)
Parses a SPARQL statement
Definition: SparqlParser.cs:79
bool TryParse(ScriptParser Parser, int Start, out ScriptNode Result)
Tries to parse a script node.
string[] InternalKeywords
Any keywords used internally by the custom parser.
static readonly SparqlParser RefInstance
Reference instance of SPARQL parser.
Definition: SparqlParser.cs:43
string[] Aliases
Keyword aliases, if available, null if none.
Definition: SparqlParser.cs:95
string KeyWord
Keyword associated with custom parser.
Definition: SparqlParser.cs:90
bool TryParse(ScriptParser Parser, out ScriptNode Result)
Tries to parse a script node.
Complement of a pattern (right) in another (left).
A pattern referencing a named source.
Definition: GraphPattern.cs:15
void AddFilter(ScriptNode Filter)
Adds a filter to the pattern.
void AddTriple(SemanticQueryTriple Triple)
Adds a triple to the pattern
void AddVariableBinding(ScriptNode Value, ScriptNode Variable)
Adds a variable binding to the pattern.
IEnumerable< IFilterNode > Filter
Filter, null if none.
IEnumerable< KeyValuePair< ScriptNode, ScriptNode > > BoundVariables
Bound variables, null if none.
Generates a random number using the uniform distribution.
Definition: Uniform.cs:15
Interface for semantic nodes.
Interface for keywords with custom parsing.
Definition: IKeyWord.cs:9
delegate string ToString(IElement Element)
Delegate for callback methods that convert an element value to a string.
QueryType
SPARQL query type.
Definition: SparqlQuery.cs:26
Prefix
SI prefixes. http://physics.nist.gov/cuu/Units/prefixes.html
Definition: Prefixes.cs:11
Definition: App.xaml.cs:4