aboutsummaryrefslogtreecommitdiff
path: root/imports/codemirror/mode/xquery/xquery.js
diff options
context:
space:
mode:
Diffstat (limited to 'imports/codemirror/mode/xquery/xquery.js')
-rw-r--r--imports/codemirror/mode/xquery/xquery.js448
1 files changed, 448 insertions, 0 deletions
diff --git a/imports/codemirror/mode/xquery/xquery.js b/imports/codemirror/mode/xquery/xquery.js
new file mode 100644
index 00000000..78916dae
--- /dev/null
+++ b/imports/codemirror/mode/xquery/xquery.js
@@ -0,0 +1,448 @@
1/*
2Copyright (C) 2011 by MarkLogic Corporation
3Author: Mike Brevoort <mike@brevoort.com>
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
22*/
23CodeMirror.defineMode("xquery", function(config, parserConfig) {
24
25 // The keywords object is set to the result of this self executing
26 // function. Each keyword is a property of the keywords object whose
27 // value is {type: atype, style: astyle}
28 var keywords = function(){
29 // conveinence functions used to build keywords object
30 function kw(type) {return {type: type, style: "keyword"};}
31 var A = kw("keyword a")
32 , B = kw("keyword b")
33 , C = kw("keyword c")
34 , operator = kw("operator")
35 , atom = {type: "atom", style: "atom"}
36 , punctuation = {type: "punctuation", style: ""}
37 , qualifier = {type: "axis_specifier", style: "qualifier"};
38
39 // kwObj is what is return from this function at the end
40 var kwObj = {
41 'if': A, 'switch': A, 'while': A, 'for': A,
42 'else': B, 'then': B, 'try': B, 'finally': B, 'catch': B,
43 'element': C, 'attribute': C, 'let': C, 'implements': C, 'import': C, 'module': C, 'namespace': C,
44 'return': C, 'super': C, 'this': C, 'throws': C, 'where': C, 'private': C,
45 ',': punctuation,
46 'null': atom, 'fn:false()': atom, 'fn:true()': atom
47 };
48
49 // a list of 'basic' keywords. For each add a property to kwObj with the value of
50 // {type: basic[i], style: "keyword"} e.g. 'after' --> {type: "after", style: "keyword"}
51 var basic = ['after','ancestor','ancestor-or-self','and','as','ascending','assert','attribute','before',
52 'by','case','cast','child','comment','declare','default','define','descendant','descendant-or-self',
53 'descending','document','document-node','element','else','eq','every','except','external','following',
54 'following-sibling','follows','for','function','if','import','in','instance','intersect','item',
55 'let','module','namespace','node','node','of','only','or','order','parent','precedes','preceding',
56 'preceding-sibling','processing-instruction','ref','return','returns','satisfies','schema','schema-element',
57 'self','some','sortby','stable','text','then','to','treat','typeswitch','union','variable','version','where',
58 'xquery', 'empty-sequence'];
59 for(var i=0, l=basic.length; i < l; i++) { kwObj[basic[i]] = kw(basic[i])};
60
61 // a list of types. For each add a property to kwObj with the value of
62 // {type: "atom", style: "atom"}
63 var types = ['xs:string', 'xs:float', 'xs:decimal', 'xs:double', 'xs:integer', 'xs:boolean', 'xs:date', 'xs:dateTime',
64 'xs:time', 'xs:duration', 'xs:dayTimeDuration', 'xs:time', 'xs:yearMonthDuration', 'numeric', 'xs:hexBinary',
65 'xs:base64Binary', 'xs:anyURI', 'xs:QName', 'xs:byte','xs:boolean','xs:anyURI','xf:yearMonthDuration'];
66 for(var i=0, l=types.length; i < l; i++) { kwObj[types[i]] = atom;};
67
68 // each operator will add a property to kwObj with value of {type: "operator", style: "keyword"}
69 var operators = ['eq', 'ne', 'lt', 'le', 'gt', 'ge', ':=', '=', '>', '>=', '<', '<=', '.', '|', '?', 'and', 'or', 'div', 'idiv', 'mod', '*', '/', '+', '-'];
70 for(var i=0, l=operators.length; i < l; i++) { kwObj[operators[i]] = operator;};
71
72 // each axis_specifiers will add a property to kwObj with value of {type: "axis_specifier", style: "qualifier"}
73 var axis_specifiers = ["self::", "attribute::", "child::", "descendant::", "descendant-or-self::", "parent::",
74 "ancestor::", "ancestor-or-self::", "following::", "preceding::", "following-sibling::", "preceding-sibling::"];
75 for(var i=0, l=axis_specifiers.length; i < l; i++) { kwObj[axis_specifiers[i]] = qualifier; };
76
77 return kwObj;
78 }();
79
80 // Used as scratch variables to communicate multiple values without
81 // consing up tons of objects.
82 var type, content;
83
84 function ret(tp, style, cont) {
85 type = tp; content = cont;
86 return style;
87 }
88
89 function chain(stream, state, f) {
90 state.tokenize = f;
91 return f(stream, state);
92 }
93
94 // the primary mode tokenizer
95 function tokenBase(stream, state) {
96 var ch = stream.next(),
97 mightBeFunction = false,
98 isEQName = isEQNameAhead(stream);
99
100 // an XML tag (if not in some sub, chained tokenizer)
101 if (ch == "<") {
102 if(stream.match("!--", true))
103 return chain(stream, state, tokenXMLComment);
104
105 if(stream.match("![CDATA", false)) {
106 state.tokenize = tokenCDATA;
107 return ret("tag", "tag");
108 }
109
110 if(stream.match("?", false)) {
111 return chain(stream, state, tokenPreProcessing);
112 }
113
114 var isclose = stream.eat("/");
115 stream.eatSpace();
116 var tagName = "", c;
117 while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
118
119 return chain(stream, state, tokenTag(tagName, isclose));
120 }
121 // start code block
122 else if(ch == "{") {
123 pushStateStack(state,{ type: "codeblock"});
124 return ret("", "");
125 }
126 // end code block
127 else if(ch == "}") {
128 popStateStack(state);
129 return ret("", "");
130 }
131 // if we're in an XML block
132 else if(isInXmlBlock(state)) {
133 if(ch == ">")
134 return ret("tag", "tag");
135 else if(ch == "/" && stream.eat(">")) {
136 popStateStack(state);
137 return ret("tag", "tag");
138 }
139 else
140 return ret("word", "word");
141 }
142 // if a number
143 else if (/\d/.test(ch)) {
144 stream.match(/^\d*(?:\.\d*)?(?:E[+\-]?\d+)?/);
145 return ret("number", "atom");
146 }
147 // comment start
148 else if (ch === "(" && stream.eat(":")) {
149 pushStateStack(state, { type: "comment"});
150 return chain(stream, state, tokenComment);
151 }
152 // quoted string
153 else if ( !isEQName && (ch === '"' || ch === "'"))
154 return chain(stream, state, tokenString(ch));
155 // variable
156 else if(ch === "$") {
157 return chain(stream, state, tokenVariable);
158 }
159 // assignment
160 else if(ch ===":" && stream.eat("=")) {
161 return ret("operator", "keyword");
162 }
163 // open paren
164 else if(ch === "(") {
165 pushStateStack(state, { type: "paren"});
166 return ret("", "");
167 }
168 // close paren
169 else if(ch === ")") {
170 popStateStack(state);
171 return ret("", "");
172 }
173 // open paren
174 else if(ch === "[") {
175 pushStateStack(state, { type: "bracket"});
176 return ret("", "");
177 }
178 // close paren
179 else if(ch === "]") {
180 popStateStack(state);
181 return ret("", "");
182 }
183 else {
184 var known = keywords.propertyIsEnumerable(ch) && keywords[ch];
185
186 // if there's a EQName ahead, consume the rest of the string portion, it's likely a function
187 if(isEQName && ch === '\"') while(stream.next() !== '"'){}
188 if(isEQName && ch === '\'') while(stream.next() !== '\''){}
189
190 // gobble up a word if the character is not known
191 if(!known) stream.eatWhile(/[\w\$_-]/);
192
193 // gobble a colon in the case that is a lib func type call fn:doc
194 var foundColon = stream.eat(":")
195
196 // if there's not a second colon, gobble another word. Otherwise, it's probably an axis specifier
197 // which should get matched as a keyword
198 if(!stream.eat(":") && foundColon) {
199 stream.eatWhile(/[\w\$_-]/);
200 }
201 // if the next non whitespace character is an open paren, this is probably a function (if not a keyword of other sort)
202 if(stream.match(/^[ \t]*\(/, false)) {
203 mightBeFunction = true;
204 }
205 // is the word a keyword?
206 var word = stream.current();
207 known = keywords.propertyIsEnumerable(word) && keywords[word];
208
209 // if we think it's a function call but not yet known,
210 // set style to variable for now for lack of something better
211 if(mightBeFunction && !known) known = {type: "function_call", style: "variable def"};
212
213 // if the previous word was element, attribute, axis specifier, this word should be the name of that
214 if(isInXmlConstructor(state)) {
215 popStateStack(state);
216 return ret("word", "word", word);
217 }
218 // as previously checked, if the word is element,attribute, axis specifier, call it an "xmlconstructor" and
219 // push the stack so we know to look for it on the next word
220 if(word == "element" || word == "attribute" || known.type == "axis_specifier") pushStateStack(state, {type: "xmlconstructor"});
221