0
|
1 var SparqlParser = Editor.Parser = (function() {
|
|
2 function wordRegexp(words) {
|
|
3 return new RegExp("^(?:" + words.join("|") + ")$", "i");
|
|
4 }
|
|
5 var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri",
|
|
6 "isblank", "isliteral", "union", "a"]);
|
|
7 var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe",
|
|
8 "ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional",
|
|
9 "graph", "by", "asc", "desc"]);
|
|
10 var operatorChars = /[*+\-<>=&|]/;
|
|
11
|
|
12 var tokenizeSparql = (function() {
|
|
13 function normal(source, setState) {
|
|
14 var ch = source.next();
|
|
15 if (ch == "$" || ch == "?") {
|
|
16 source.nextWhileMatches(/[\w\d]/);
|
|
17 return "sp-var";
|
|
18 }
|
|
19 else if (ch == "<" && !source.matches(/[\s\u00a0=]/)) {
|
|
20 source.nextWhileMatches(/[^\s\u00a0>]/);
|
|
21 if (source.equals(">")) source.next();
|
|
22 return "sp-uri";
|
|
23 }
|
|
24 else if (ch == "\"" || ch == "'") {
|
|
25 setState(inLiteral(ch));
|
|
26 return null;
|
|
27 }
|
|
28 else if (/[{}\(\),\.;\[\]]/.test(ch)) {
|
|
29 return "sp-punc";
|
|
30 }
|
|
31 else if (ch == "#") {
|
|
32 while (!source.endOfLine()) source.next();
|
|
33 return "sp-comment";
|
|
34 }
|
|
35 else if (operatorChars.test(ch)) {
|
|
36 source.nextWhileMatches(operatorChars);
|
|
37 return "sp-operator";
|
|
38 }
|
|
39 else if (ch == ":") {
|
|
40 source.nextWhileMatches(/[\w\d\._\-]/);
|
|
41 return "sp-prefixed";
|
|
42 }
|
|
43 else {
|
|
44 source.nextWhileMatches(/[_\w\d]/);
|
|
45 if (source.equals(":")) {
|
|
46 source.next();
|
|
47 source.nextWhileMatches(/[\w\d_\-]/);
|
|
48 return "sp-prefixed";
|
|
49 }
|
|
50 var word = source.get(), type;
|
|
51 if (ops.test(word))
|
|
52 type = "sp-operator";
|
|
53 else if (keywords.test(word))
|
|
54 type = "sp-keyword";
|
|
55 else
|
|
56 type = "sp-word";
|
|
57 return {style: type, content: word};
|
|
58 }
|
|
59 }
|
|
60
|
|
61 function inLiteral(quote) {
|
|
62 return function(source, setState) {
|
|
63 var escaped = false;
|
|
64 while (!source.endOfLine()) {
|
|
65 var ch = source.next();
|
|
66 if (ch == quote && !escaped) {
|
|
67 setState(normal);
|
|
68 break;
|
|
69 }
|
|
70 escaped = !escaped && ch == "\\";
|
|
71 }
|
|
72 return "sp-literal";
|
|
73 };
|
|
74 }
|
|
75
|
|
76 return function(source, startState) {
|
|
77 return tokenizer(source, startState || normal);
|
|
78 };
|
|
79 })();
|
|
80
|
|
81 function indentSparql(context) {
|
|
82 return function(nextChars) {
|
|
83 var firstChar = nextChars && nextChars.charAt(0);
|
|
84 if (/[\]\}]/.test(firstChar))
|
|
85 while (context && context.type == "pattern") context = context.prev;
|
|
86
|
|
87 var closing = context && firstChar == matching[context.type];
|
|
88 if (!context)
|
|
89 return 0;
|
|
90 else if (context.type == "pattern")
|
|
91 return context.col;
|
|
92 else if (context.align)
|
|
93 return context.col - (closing ? context.width : 0);
|
|
94 else
|
|
95 return context.indent + (closing ? 0 : indentUnit);
|
|
96 }
|
|
97 }
|
|
98
|
|
99 function parseSparql(source) {
|
|
100 var tokens = tokenizeSparql(source);
|
|
101 var context = null, indent = 0, col = 0;
|
|
102 function pushContext(type, width) {
|
|
103 context = {prev: context, indent: indent, col: col, type: type, width: width};
|
|
104 }
|
|
105 function popContext() {
|
|
106 context = context.prev;
|
|
107 }
|
|
108
|
|
109 var iter = {
|
|
110 next: function() {
|
|
111 var token = tokens.next(), type = token.style, content = token.content, width = token.value.length;
|
|
112
|
|
113 if (content == "\n") {
|
|
114 token.indentation = indentSparql(context);
|
|
115 indent = col = 0;
|
|
116 if (context && context.align == null) context.align = false;
|
|
117 }
|
|
118 else if (type == "whitespace" && col == 0) {
|
|
119 indent = width;
|
|
120 }
|
|
121 else if (type != "sp-comment" && context && context.align == null) {
|
|
122 context.align = true;
|
|
123 }
|
|
124
|
|
125 if (content != "\n") col += width;
|
|
126
|
|
127 if (/[\[\{\(]/.test(content)) {
|
|
128 pushContext(content, width);
|
|
129 }
|
|
130 else if (/[\]\}\)]/.test(content)) {
|
|
131 while (context && context.type == "pattern")
|
|
132 popContext();
|
|
133 if (context && content == matching[context.type])
|
|
134 popContext();
|
|
135 }
|
|
136 else if (content == "." && context && context.type == "pattern") {
|
|
137 popContext();
|
|
138 }
|
|
139 else if ((type == "sp-word" || type == "sp-prefixed" || type == "sp-uri" || type == "sp-var" || type == "sp-literal") &&
|
|
140 context && /[\{\[]/.test(context.type)) {
|
|
141 pushContext("pattern", width);
|
|
142 }
|
|
143
|
|
144 return token;
|
|
145 },
|
|
146
|
|
147 copy: function() {
|
|
148 var _context = context, _indent = indent, _col = col, _tokenState = tokens.state;
|
|
149 return function(source) {
|
|
150 tokens = tokenizeSparql(source, _tokenState);
|
|
151 context = _context;
|
|
152 indent = _indent;
|
|
153 col = _col;
|
|
154 return iter;
|
|
155 };
|
|
156 }
|
|
157 };
|
|
158 return iter;
|
|
159 }
|
|
160
|
|
161 return {make: parseSparql, electricChars: "}]"};
|
|
162 })();
|