@matdata/yasqe 4.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/build/ts/grammar/tokenizer.d.ts +37 -0
  3. package/build/ts/src/CodeMirror.d.ts +21 -0
  4. package/build/ts/src/autocompleters/classes.d.ts +3 -0
  5. package/build/ts/src/autocompleters/index.d.ts +39 -0
  6. package/build/ts/src/autocompleters/prefixes.d.ts +3 -0
  7. package/build/ts/src/autocompleters/properties.d.ts +3 -0
  8. package/build/ts/src/autocompleters/variables.d.ts +3 -0
  9. package/build/ts/src/defaults.d.ts +75 -0
  10. package/build/ts/src/imgs.d.ts +7 -0
  11. package/build/ts/src/index.d.ts +303 -0
  12. package/build/ts/src/prefixFold.d.ts +8 -0
  13. package/build/ts/src/prefixUtils.d.ts +9 -0
  14. package/build/ts/src/sparql.d.ts +20 -0
  15. package/build/ts/src/tokenUtils.d.ts +4 -0
  16. package/build/ts/src/tooltip.d.ts +2 -0
  17. package/build/ts/src/trie.d.ts +13 -0
  18. package/build/yasqe.html +108 -0
  19. package/build/yasqe.min.css +2 -0
  20. package/build/yasqe.min.css.map +1 -0
  21. package/build/yasqe.min.js +3 -0
  22. package/build/yasqe.min.js.LICENSE.txt +3 -0
  23. package/build/yasqe.min.js.map +1 -0
  24. package/grammar/README.md +12 -0
  25. package/grammar/_tokenizer-table.js +4776 -0
  26. package/grammar/build.sh +2 -0
  27. package/grammar/sparql11-grammar.pl +834 -0
  28. package/grammar/sparqljs-browser-min.js +4535 -0
  29. package/grammar/tokenizer.ts +729 -0
  30. package/grammar/util/gen_ll1.pl +37 -0
  31. package/grammar/util/gen_sparql11.pl +11 -0
  32. package/grammar/util/ll1.pl +175 -0
  33. package/grammar/util/output_to_javascript.pl +75 -0
  34. package/grammar/util/prune.pl +49 -0
  35. package/grammar/util/rewrite.pl +104 -0
  36. package/package.json +40 -0
  37. package/src/CodeMirror.ts +54 -0
  38. package/src/autocompleters/classes.ts +32 -0
  39. package/src/autocompleters/index.ts +346 -0
  40. package/src/autocompleters/prefixes.ts +130 -0
  41. package/src/autocompleters/properties.ts +28 -0
  42. package/src/autocompleters/show-hint.scss +38 -0
  43. package/src/autocompleters/variables.ts +52 -0
  44. package/src/defaults.ts +149 -0
  45. package/src/imgs.ts +14 -0
  46. package/src/index.ts +1089 -0
  47. package/src/prefixFold.ts +93 -0
  48. package/src/prefixUtils.ts +65 -0
  49. package/src/scss/buttons.scss +275 -0
  50. package/src/scss/codemirrorMods.scss +36 -0
  51. package/src/scss/yasqe.scss +89 -0
  52. package/src/sparql.ts +215 -0
  53. package/src/tokenUtils.ts +121 -0
  54. package/src/tooltip.ts +31 -0
  55. package/src/trie.ts +238 -0
@@ -0,0 +1,729 @@
1
+ import CodeMirror from "codemirror";
2
+ export interface State {
3
+ tokenize: (stream: CodeMirror.StringStream, state: State) => string;
4
+ inLiteral: "SINGLE" | "DOUBLE" | undefined;
5
+ errorStartPos: number | undefined;
6
+ errorEndPos: number | undefined;
7
+ queryType:
8
+ | "SELECT"
9
+ | "CONSTRUCT"
10
+ | "ASK"
11
+ | "DESCRIBE"
12
+ | "INSERT"
13
+ | "DELETE"
14
+ | "LOAD"
15
+ | "CLEAR"
16
+ | "CREATE"
17
+ | "DROP"
18
+ | "COPY"
19
+ | "MOVE"
20
+ | "ADD"
21
+ | undefined;
22
+ inPrefixDecl: boolean;
23
+ allowVars: boolean;
24
+ allowBnodes: boolean;
25
+ storeProperty: boolean;
26
+ OK: boolean;
27
+ possibleCurrent: string[];
28
+ possibleNext: string[];
29
+ stack: any[];
30
+ variables: { [varName: string]: string };
31
+ prefixes: { [prefLabel: string]: string };
32
+ complete: boolean;
33
+ lastProperty: string;
34
+ lastPropertyIndex: number;
35
+ errorMsg: string | undefined;
36
+ lastPredicateOffset: number;
37
+ currentPnameNs: string | undefined;
38
+ possibleFullIri: boolean;
39
+ }
40
+ export interface Token {
41
+ quotePos: "end" | "start" | "content" | undefined;
42
+ cat: string;
43
+ style: string;
44
+ string: string;
45
+ start: number;
46
+ }
47
+ export default function (config: CodeMirror.EditorConfiguration): CodeMirror.Mode<State> {
48
+ const grammar = require("./_tokenizer-table.js");
49
+ const ll1_table = grammar.table;
50
+
51
+ const IRI_REF = '<[^<>"`|{}^\\\x00-\x20]*>';
52
+ const PN_CHARS_BASE =
53
+ "[A-Za-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD]";
54
+ const PN_CHARS_U = PN_CHARS_BASE + "|_";
55
+
56
+ const PN_CHARS = "(" + PN_CHARS_U + "|-|[0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040])";
57
+ const VARNAME = "(" + PN_CHARS_U + "|[0-9])" + "(" + PN_CHARS_U + "|[0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040])*";
58
+ const VAR1 = "\\?" + VARNAME;
59
+ const VAR2 = "\\$" + VARNAME;
60
+
61
+ const PN_PREFIX = "(" + PN_CHARS_BASE + ")(((" + PN_CHARS + ")|\\.)*(" + PN_CHARS + "))?";
62
+
63
+ const HEX = "[0-9A-Fa-f]";
64
+ const PERCENT = "(%" + HEX + HEX + ")";
65
+ const PN_LOCAL_ESC = "(\\\\[_~\\.\\-!\\$&'\\(\\)\\*\\+,;=/\\?#@%])";
66
+ const PLX = "(" + PERCENT + "|" + PN_LOCAL_ESC + ")";
67
+ const PN_LOCAL =
68
+ "(" + PN_CHARS_U + "|:|[0-9]|" + PLX + ")((" + PN_CHARS + "|\\.|:|" + PLX + ")*(" + PN_CHARS + "|:|" + PLX + "))?";
69
+ const BLANK_NODE_LABEL = "_:(" + PN_CHARS_U + "|[0-9])((" + PN_CHARS + "|\\.)*" + PN_CHARS + ")?";
70
+ const PNAME_NS = "(" + PN_PREFIX + ")?:";
71
+ const PNAME_LN = PNAME_NS + PN_LOCAL;
72
+ const LANGTAG = "@[a-zA-Z]+(-[a-zA-Z0-9]+)*";
73
+
74
+ const EXPONENT = "[eE][\\+-]?[0-9]+";
75
+ const INTEGER = "[0-9]+";
76
+ const DECIMAL = "[0-9]*\\.[0-9]+";
77
+ const DOUBLE = "(([0-9]+\\.[0-9]*" + EXPONENT + ")|(\\.[0-9]+" + EXPONENT + ")|([0-9]+" + EXPONENT + "))";
78
+
79
+ const INTEGER_POSITIVE = "\\+" + INTEGER;
80
+ const DECIMAL_POSITIVE = "\\+" + DECIMAL;
81
+ const DOUBLE_POSITIVE = "\\+" + DOUBLE;
82
+ const INTEGER_NEGATIVE = "-" + INTEGER;
83
+ const DECIMAL_NEGATIVE = "-" + DECIMAL;
84
+ const DOUBLE_NEGATIVE = "-" + DOUBLE;
85
+
86
+ const ECHAR = "\\\\[tbnrf\\\\\"']";
87
+
88
+ //IMPORTANT: this unicode rule is not in the official grammar.
89
+ //Reason: https://github.com/YASGUI/YASQE/issues/49
90
+ //unicode escape sequences (which the sparql spec considers part of the pre-processing of sparql queries)
91
+ //are marked as invalid. We have little choice (other than adding a layer of complixity) than to modify the grammar accordingly
92
+ //however, for now only allow these escape sequences in literals (where actually, this should be allows in e.g. prefixes as well)
93
+ const hex4 = HEX + "{4}";
94
+ const unicode = "(\\\\u" + hex4 + "|\\\\U00(10|0" + HEX + ")" + hex4 + ")";
95
+ const STRING_LITERAL1 = "'(([^\\x27\\x5C\\x0A\\x0D])|" + ECHAR + "|" + unicode + ")*'";
96
+ const STRING_LITERAL2 = '"(([^\\x22\\x5C\\x0A\\x0D])|' + ECHAR + "|" + unicode + ')*"';
97
+
98
+ const STRING_LITERAL_LONG: {
99
+ [key: string]: {
100
+ CAT: string;
101
+ QUOTES: string;
102
+ CONTENTS: string;
103
+ COMPLETE?: string;
104
+ };
105
+ } = {
106
+ SINGLE: {
107
+ CAT: "STRING_LITERAL_LONG1",
108
+ QUOTES: "'''",
109
+ CONTENTS: "(('|'')?([^'\\\\]|" + ECHAR + "|" + unicode + "))*",
110
+ },
111
+ DOUBLE: {
112
+ CAT: "STRING_LITERAL_LONG2",
113
+ QUOTES: '"""',
114
+ CONTENTS: '(("|"")?([^"\\\\]|' + ECHAR + "|" + unicode + "))*",
115
+ },
116
+ };
117
+ for (const key in STRING_LITERAL_LONG) {
118
+ STRING_LITERAL_LONG[key].COMPLETE =
119
+ STRING_LITERAL_LONG[key].QUOTES + STRING_LITERAL_LONG[key].CONTENTS + STRING_LITERAL_LONG[key].QUOTES;
120
+ }
121
+ //some regular expressions not used in regular terminals, because this is used accross lines
122
+ interface LiteralRegex {
123
+ name: string;
124
+ regex: RegExp;
125
+ style: string;
126
+ }
127
+ var stringLiteralLongRegex: {
128
+ [k: string]: {
129
+ complete: LiteralRegex;
130
+ contents: LiteralRegex;
131
+ closing: LiteralRegex;
132
+ quotes: LiteralRegex;
133
+ };
134
+ } = {};
135
+ for (const key in STRING_LITERAL_LONG) {
136
+ stringLiteralLongRegex[key] = {
137
+ complete: {
138
+ name: "STRING_LITERAL_LONG_" + key,
139
+ regex: new RegExp("^" + STRING_LITERAL_LONG[key].COMPLETE),
140
+ style: "string",
141
+ },
142
+ contents: {
143
+ name: "STRING_LITERAL_LONG_" + key,
144
+ regex: new RegExp("^" + STRING_LITERAL_LONG[key].CONTENTS),
145
+ style: "string",
146
+ },
147
+ closing: {
148
+ name: "STRING_LITERAL_LONG_" + key,
149
+ regex: new RegExp("^" + STRING_LITERAL_LONG[key].CONTENTS + STRING_LITERAL_LONG[key].QUOTES),
150
+ style: "string",
151
+ },
152
+ quotes: {
153
+ name: "STRING_LITERAL_LONG_QUOTES_" + key,
154
+ regex: new RegExp("^" + STRING_LITERAL_LONG[key].QUOTES),
155
+ style: "string",
156
+ },
157
+ };
158
+ }
159
+
160
+ const WS = "[\\x20\\x09\\x0D\\x0A]";
161
+ // Careful! Code mirror feeds one line at a time with no \n
162
+ // ... but otherwise comment is terminated by \n
163
+ const COMMENT = "#([^\\n\\r]*[\\n\\r]|[^\\n\\r]*$)";
164
+ const WS_OR_COMMENT_STAR = "(" + WS + "|(" + COMMENT + "))*";
165
+ const NIL = "\\(" + WS_OR_COMMENT_STAR + "\\)";
166
+ const ANON = "\\[" + WS_OR_COMMENT_STAR + "\\]";
167
+ const terminals = [
168
+ {
169
+ name: "WS",
170
+ regex: new RegExp("^" + WS + "+"),
171
+ style: "ws",
172
+ },
173
+
174
+ {
175
+ name: "COMMENT",
176
+ regex: new RegExp("^" + COMMENT),
177
+ style: "comment",
178
+ },
179
+
180
+ {
181
+ name: "IRI_REF",
182
+ regex: new RegExp("^" + IRI_REF),
183
+ style: "variable-3",
184
+ },
185
+
186
+ {
187
+ name: "VAR1",
188
+ regex: new RegExp("^" + VAR1),
189
+ style: "atom",
190
+ },
191
+
192
+ {
193
+ name: "VAR2",
194
+ regex: new RegExp("^" + VAR2),
195
+ style: "atom",
196
+ },
197
+
198
+ {
199
+ name: "LANGTAG",
200
+ regex: new RegExp("^" + LANGTAG),
201
+ style: "meta",
202
+ },
203
+
204
+ {
205
+ name: "DOUBLE",
206
+ regex: new RegExp("^" + DOUBLE),
207
+ style: "number",
208
+ },
209
+
210
+ {
211
+ name: "DECIMAL",
212
+ regex: new RegExp("^" + DECIMAL),
213
+ style: "number",
214
+ },
215
+
216
+ {
217
+ name: "INTEGER",
218
+ regex: new RegExp("^" + INTEGER),
219
+ style: "number",
220
+ },
221
+
222
+ {
223
+ name: "DOUBLE_POSITIVE",
224
+ regex: new RegExp("^" + DOUBLE_POSITIVE),
225
+ style: "number",
226
+ },
227
+
228
+ {
229
+ name: "DECIMAL_POSITIVE",
230
+ regex: new RegExp("^" + DECIMAL_POSITIVE),
231
+ style: "number",
232
+ },
233
+
234
+ {
235
+ name: "INTEGER_POSITIVE",
236
+ regex: new RegExp("^" + INTEGER_POSITIVE),
237
+ style: "number",
238
+ },
239
+
240
+ {
241
+ name: "DOUBLE_NEGATIVE",
242
+ regex: new RegExp("^" + DOUBLE_NEGATIVE),
243
+ style: "number",
244
+ },
245
+
246
+ {
247
+ name: "DECIMAL_NEGATIVE",
248
+ regex: new RegExp("^" + DECIMAL_NEGATIVE),
249
+ style: "number",
250
+ },
251
+
252
+ {
253
+ name: "INTEGER_NEGATIVE",
254
+ regex: new RegExp("^" + INTEGER_NEGATIVE),
255
+ style: "number",
256
+ },
257
+ // stringLiteralLongRegex.SINGLE.complete,
258
+ // stringLiteralLongRegex.DOUBLE.complete,
259
+ // stringLiteralLongRegex.SINGLE.quotes,
260
+ // stringLiteralLongRegex.DOUBLE.quotes,
261
+
262
+ {
263
+ name: "STRING_LITERAL1",
264
+ regex: new RegExp("^" + STRING_LITERAL1),
265
+ style: "string",
266
+ },
267
+
268
+ {
269
+ name: "STRING_LITERAL2",
270
+ regex: new RegExp("^" + STRING_LITERAL2),
271
+ style: "string",
272
+ },
273
+
274
+ // Enclosed comments won't be highlighted
275
+ {
276
+ name: "NIL",
277
+ regex: new RegExp("^" + NIL),
278
+ style: "punc",
279
+ },
280
+
281
+ // Enclosed comments won't be highlighted
282
+ {
283
+ name: "ANON",
284
+ regex: new RegExp("^" + ANON),
285
+ style: "punc",
286
+ },
287
+
288
+ {
289
+ name: "PNAME_LN",
290
+ regex: new RegExp("^" + PNAME_LN),
291
+ style: "string-2",
292
+ },
293
+
294
+ {
295
+ name: "PNAME_NS",
296
+ regex: new RegExp("^" + PNAME_NS),
297
+ style: "string-2",
298
+ },
299
+
300
+ {
301
+ name: "BLANK_NODE_LABEL",
302
+ regex: new RegExp("^" + BLANK_NODE_LABEL),
303
+ style: "string-2",
304
+ },
305
+ ];
306
+
307
+ function getPossibles(symbol: string) {
308
+ var possibles = [],
309
+ possiblesOb = ll1_table[symbol];
310
+ if (possiblesOb != undefined) {
311
+ for (const property in possiblesOb) {
312
+ possibles.push(property.toString());
313
+ }
314
+ } else {
315
+ possibles.push(symbol);
316
+ }
317
+ return possibles;
318
+ }
319
+
320
+ function tokenBase(stream: CodeMirror.StringStream, state: State) {
321
+ function nextToken(): Token {
322
+ let consumed: string[];
323
+ if (state.inLiteral) {
324
+ var closingQuotes = false;
325
+ //multi-line literal. try to parse contents.
326
+ consumed = stream.match(stringLiteralLongRegex[state.inLiteral].contents.regex as any, true, false) as any;
327
+ if (consumed && consumed[0].length == 0) {
328
+ //try seeing whether we can consume closing quotes, to avoid stopping
329
+ consumed = stream.match(stringLiteralLongRegex[state.inLiteral].closing.regex as any, true, false) as any;
330
+ closingQuotes = true;
331
+ }
332
+
333
+ if (consumed && consumed[0].length > 0) {
334
+ //some string content here.
335
+ const returnObj: Token = {
336
+ quotePos: closingQuotes ? "end" : "content",
337
+ cat: STRING_LITERAL_LONG[state.inLiteral].CAT,
338
+ style: stringLiteralLongRegex[state.inLiteral].complete.style,
339
+ string: consumed[0],
340
+ start: stream.start,
341
+ };
342
+ if (closingQuotes) state.inLiteral = undefined;
343
+ return returnObj;
344
+ }
345
+ }
346
+
347
+ //Multiline literals
348
+ for (const quoteType in stringLiteralLongRegex) {
349
+ consumed = stream.match(stringLiteralLongRegex[quoteType].quotes.regex as any, true, false) as any;
350
+ if (consumed) {
351
+ var quotePos: Token["quotePos"];
352
+ if (state.inLiteral) {
353
+ //end of literal. everything is fine
354
+ state.inLiteral = undefined;
355
+ quotePos = "end";
356
+ } else {
357
+ state.inLiteral = <any>quoteType;
358
+ quotePos = "start";
359
+ }
360
+ return {
361
+ cat: STRING_LITERAL_LONG[quoteType].CAT,
362
+ style: stringLiteralLongRegex[quoteType].quotes.style,
363
+ string: consumed[0],
364
+ quotePos: quotePos,
365
+ start: stream.start,
366
+ };
367
+ }
368
+ }
369
+
370
+ // Tokens defined by individual regular expressions
371
+ for (var i = 0; i < terminals.length; ++i) {
372
+ consumed = stream.match(terminals[i].regex as any, true, false) as any;
373
+ if (consumed) {
374
+ return {
375
+ cat: terminals[i].name,
376
+ style: terminals[i].style,
377
+ string: consumed[0],
378
+ start: stream.start,
379
+ quotePos: undefined,
380
+ };
381
+ }
382
+ }
383
+
384
+ // Keywords
385
+ consumed = stream.match(grammar.keywords, true, false) as any;
386
+ if (consumed)
387
+ return {
388
+ cat: stream.current().toUpperCase(),
389
+ style: "keyword",
390
+ string: consumed[0],
391
+ start: stream.start,
392
+ quotePos: undefined,
393
+ };
394
+
395
+ // Punctuation
396
+ consumed = stream.match(grammar.punct, true, false) as any;
397
+ if (consumed)
398
+ return {
399
+ cat: stream.current(),
400
+ style: "punc",
401
+ string: consumed[0],
402
+ start: stream.start,
403
+ quotePos: undefined,
404
+ };
405
+
406
+ // Token is invalid
407
+ // better consume something anyway, or else we're stuck
408
+ consumed = stream.match(/^.[A-Za-z0-9]*/ as any, true, false) as any;
409
+ return {
410
+ cat: "<invalid_token>",
411
+ style: "error",
412
+ string: consumed[0],
413
+ start: stream.start,
414
+ quotePos: undefined,
415
+ };
416
+ }
417
+
418
+ function recordFailurePos() {
419
+ // tokenOb.style= "sp-invalid";
420
+ const col = stream.column();
421
+ state.errorStartPos = col;
422
+ state.errorEndPos = col + tokenOb.string.length;
423
+ }
424
+ function setQueryType(s: string) {
425
+ if (state.queryType == null) {
426
+ switch (s) {
427
+ case "SELECT":
428
+ case "CONSTRUCT":
429
+ case "ASK":
430
+ case "DESCRIBE":
431
+ case "INSERT":
432
+ case "DELETE":
433
+ case "LOAD":
434
+ case "CLEAR":
435
+ case "CREATE":
436
+ case "DROP":
437
+ case "COPY":
438
+ case "MOVE":
439
+ case "ADD":
440
+ state.queryType = s;
441
+ }
442
+ }
443
+ }
444
+
445
+ // Some fake non-terminals are just there to have side-effect on state
446
+ // - i.e. allow or disallow variables and bnodes in certain non-nesting
447
+ // contexts
448
+ function setSideConditions(topSymbol: string) {
449
+ if (topSymbol === "prefixDecl") {
450
+ state.inPrefixDecl = true;
451
+ } else {
452
+ state.inPrefixDecl = false;
453
+ }
454
+ switch (topSymbol) {
455
+ case "disallowVars":
456
+ state.allowVars = false;
457
+ break;
458
+ case "allowVars":
459
+ state.allowVars = true;
460
+ break;
461
+ case "disallowBnodes":
462
+ state.allowBnodes = false;
463
+ break;
464
+ case "allowBnodes":
465
+ state.allowBnodes = true;
466
+ break;
467
+ case "storeProperty":
468
+ state.storeProperty = true;
469
+ break;
470
+ }
471
+ }
472
+
473
+ function checkSideConditions(topSymbol: string) {
474
+ return (
475
+ (state.allowVars || topSymbol != "var") &&
476
+ (state.allowBnodes ||
477
+ (topSymbol != "blankNode" &&
478
+ topSymbol != "blankNodePropertyList" &&
479
+ topSymbol != "blankNodePropertyListPath"))
480
+ );
481
+ }
482
+
483
+ // CodeMirror works with one line at a time,
484
+ // but newline should behave like whitespace
485
+ // - i.e. a definite break between tokens (for autocompleter)
486
+ if (stream.pos == 0) state.possibleCurrent = state.possibleNext;
487
+
488
+ const tokenOb = nextToken();
489
+
490
+ if (tokenOb.cat == "<invalid_token>") {
491
+ // set error state, and
492
+ if (state.OK == true) {
493
+ state.OK = false;
494
+ recordFailurePos();
495
+ }
496
+ state.complete = false;
497
+ // alert("Invalid:"+tokenOb.text);
498
+ return tokenOb.style;
499
+ }
500
+ if (tokenOb.cat === "WS" || tokenOb.cat === "COMMENT" || (tokenOb.quotePos && tokenOb.quotePos != "end")) {
501
+ state.possibleCurrent = state.possibleNext;
502
+ state.possibleFullIri = false;
503
+ return tokenOb.style;
504
+ }
505
+ // Otherwise, run the parser until the token is digested
506
+ // or failure
507
+ var finished = false;
508
+ var topSymbol;
509
+ const tokenCat = tokenOb.cat;
510
+ if (state.possibleFullIri && tokenOb.string === ">") {
511
+ state.possibleFullIri = false;
512
+ }
513
+ if (!state.possibleFullIri && tokenOb.string === "<") {
514
+ state.possibleFullIri = true;
515
+ }
516
+ if (!tokenOb.quotePos || tokenOb.quotePos == "end") {
517
+ // Incremental LL1 parse
518
+ while (state.stack.length > 0 && tokenCat && state.OK && !finished) {
519
+ topSymbol = state.stack.pop();
520
+ if (topSymbol === "var" && tokenOb.string) state.variables[tokenOb.string] = tokenOb.string;
521
+ if (!ll1_table[topSymbol]) {
522
+ // Top symbol is a terminal
523
+ if (topSymbol == tokenCat) {
524
+ if (state.inPrefixDecl) {
525
+ if (topSymbol === "PNAME_NS" && tokenOb.string.length > 0) {
526
+ state.currentPnameNs = tokenOb.string.slice(0, -1);
527
+ } else if (typeof state.currentPnameNs === "string" && tokenOb.string.length > 1) {
528
+ state.prefixes[state.currentPnameNs] = tokenOb.string.slice(1, -1);
529
+ //reset current pname ns
530
+ state.currentPnameNs = undefined;
531
+ }
532
+ }
533
+ // Matching terminals
534
+ // - consume token from input stream
535
+ finished = true;
536
+ setQueryType(topSymbol);
537
+ // Check whether $ (end of input token) is poss next
538
+ // for everything on stack
539
+ var allNillable = true;
540
+ for (var sp = state.stack.length; sp > 0; --sp) {
541
+ const item = ll1_table[state.stack[sp - 1]];
542
+ if (!item || !item["$"]) allNillable = false;
543
+ }
544
+
545
+ state.complete = allNillable;
546
+ if (state.storeProperty && tokenCat != "punc") {
547
+ state.lastProperty = tokenOb.string;
548
+ state.lastPropertyIndex = tokenOb.start;
549
+ state.storeProperty = false;
550
+ } else if (tokenCat === "." || tokenCat === ";") {
551
+ // the last property wont be relevant for what follows, so we reset it
552
+ state.lastProperty = "";
553
+ state.lastPropertyIndex = 0;
554
+ }
555
+
556
+ //check whether a used prefix is actually defined
557
+ if (!state.inPrefixDecl && (tokenCat === "PNAME_NS" || tokenCat === "PNAME_LN")) {
558
+ const colonIndex = tokenOb.string.indexOf(":");
559
+ if (colonIndex >= 0) {
560
+ const prefNs = tokenOb.string.slice(0, colonIndex);
561
+ if (state.prefixes[prefNs] === undefined) {
562
+ state.OK = false;
563
+ recordFailurePos();
564
+ state.errorMsg = "Prefix '" + prefNs + "' is not defined";
565
+ }
566
+ }
567
+ }
568
+ } else {
569
+ state.OK = false;
570
+ state.complete = false;
571
+ recordFailurePos();
572
+ }
573
+ } else {
574
+ // topSymbol is nonterminal
575
+ // - see if there is an entry for topSymbol
576
+ // and nextToken in table
577
+ const nextSymbols = ll1_table[topSymbol][tokenCat];
578
+ if (nextSymbols != undefined && checkSideConditions(topSymbol)) {
579
+ // Match - copy RHS of rule to stack
580
+ for (var i = nextSymbols.length - 1; i >= 0; --i) {
581
+ state.stack.push(nextSymbols[i]);
582
+ }
583
+ // Peform any non-grammatical side-effects
584
+ setSideConditions(topSymbol);
585
+ } else {
586
+ // No match in table - fail
587
+ state.OK = false;
588
+ state.complete = false;
589
+ recordFailurePos();
590
+ state.stack.push(topSymbol); // Shove topSymbol back on stack
591
+ }
592
+ }
593
+ }
594
+ }
595
+ if (!finished && state.OK) {
596
+ state.OK = false;
597
+ state.complete = false;
598
+ recordFailurePos();
599
+ }
600
+ if (state.possibleNext.indexOf("a") >= 0) {
601
+ //only store last pred offset when this prop isnt part of a property path
602
+ //see #https://github.com/TriplyDB/YASGUI.YASQE/issues/105
603
+ const line = stream.string;
604
+ for (let i = tokenOb.start; i >= 0; i--) {
605
+ if (line[i - 1] === " ") {
606
+ //continue search
607
+ continue;
608
+ }
609
+ if (line[i - 1] === "|" || line[i - 1] === "/") {
610
+ //part of property path, not setting this val
611
+ } else if (tokenOb.style === "punc") {
612
+ //we've moved past the property path, and reached punctuation. This can happens when the object is a literal
613
+ //So, simply not set this val (i.e. use value that was defined before this token)
614
+ } else {
615
+ state.lastPredicateOffset = tokenOb.start;
616
+ }
617
+ break;
618
+ }
619
+ }
620
+
621
+ state.possibleCurrent = state.possibleNext;
622
+
623
+ state.possibleNext = getPossibles(state.stack[state.stack.length - 1]);
624
+
625
+ return tokenOb.style;
626
+ }
627
+
628
+ const indentTop: { [symbol: string]: number } = {
629
+ "*[,, object]": 3,
630
+ "*[(,),object]": 3,
631
+ "*[(,),objectPath]": 3,
632
+ "*[/,pathEltOrInverse]": 2,
633
+ object: 2,
634
+ objectPath: 2,
635
+ objectList: 2,
636
+ objectListPath: 2,
637
+ storeProperty: 2,
638
+ pathMod: 2,
639
+ "?pathMod": 2,
640
+ propertyListNotEmpty: 1,
641
+ propertyList: 1,
642
+ propertyListPath: 1,
643
+ propertyListPathNotEmpty: 1,
644
+ "?[verb,objectList]": 1,
645
+ // "?[or([verbPath, verbSimple]),objectList]": 1,
646
+ };
647
+
648
+ const indentTable: { [char: string]: number } = {
649
+ "}": 1,
650
+ "]": 1,
651
+ ")": 1,
652
+ "{": -1,
653
+ "(": -1,
654
+ "[": -1,
655
+ // "*[;,?[or([verbPath,verbSimple]),objectList]]": 1,
656
+ };
657
+
658
+ function indent(state: State, textAfter: string) {
659
+ //just avoid we don't indent multi-line literals
660
+ if (state.inLiteral) return 0;
661
+ if (
662
+ state.lastPredicateOffset !== undefined &&
663
+ state.stack.length &&
664
+ state.stack[state.stack.length - 1] == "?[or([verbPath,verbSimple]),objectListPath]"
665
+ ) {
666
+ //we are after a semi-colon. I.e., nicely align this line with predicate position of previous line
667
+ return state.lastPredicateOffset;
668
+ } else {
669
+ var n = 0; // indent level
670
+ var i = state.stack.length - 1;
671
+ if (/^[\}\]\)]/.test(textAfter)) {
672
+ // Skip stack items until after matching bracket
673
+ const closeBracket = textAfter.substr(0, 1);
674
+ for (; i >= 0; --i) {
675
+ if (state.stack[i] == closeBracket) {
676
+ --i;
677
+ break;
678
+ }
679
+ }
680
+ } else {
681
+ // Consider nullable non-terminals if at top of stack
682
+ let dn = indentTop[state.stack[i]];
683
+ if (dn) {
684
+ n += dn;
685
+ --i;
686
+ }
687
+ }
688
+ for (; i >= 0; --i) {
689
+ let dn = indentTable[state.stack[i]];
690
+ if (dn) {
691
+ n += dn;
692
+ }
693
+ }
694
+ return n * (config.indentUnit ?? 2);
695
+ }
696
+ }
697
+
698
+ return {
699
+ token: tokenBase,
700
+ startState: function (): State {
701
+ return {
702
+ tokenize: tokenBase,
703
+ OK: true,
704
+ complete: grammar.acceptEmpty,
705
+ errorStartPos: undefined,
706
+ errorEndPos: undefined,
707
+ queryType: undefined,
708
+ possibleCurrent: getPossibles(grammar.startSymbol),
709
+ possibleNext: getPossibles(grammar.startSymbol),
710
+ allowVars: true,
711
+ allowBnodes: true,
712
+ storeProperty: false,
713
+ lastProperty: "",
714
+ lastPropertyIndex: 0,
715
+ inLiteral: undefined,
716
+ stack: [grammar.startSymbol],
717
+ lastPredicateOffset: config.indentUnit || 2,
718
+ prefixes: {},
719
+ variables: {},
720
+ currentPnameNs: undefined,
721
+ errorMsg: undefined,
722
+ inPrefixDecl: false,
723
+ possibleFullIri: false,
724
+ };
725
+ },
726
+ indent: indent,
727
+ electricChars: "}])",
728
+ };
729
+ }