aboutsummaryrefslogtreecommitdiff
path: root/node_modules/montage/core/selector/language.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/montage/core/selector/language.js')
-rw-r--r--node_modules/montage/core/selector/language.js381
1 files changed, 381 insertions, 0 deletions
diff --git a/node_modules/montage/core/selector/language.js b/node_modules/montage/core/selector/language.js
new file mode 100644
index 00000000..fa20b232
--- /dev/null
+++ b/node_modules/montage/core/selector/language.js
@@ -0,0 +1,381 @@
1/* <copyright>
2 This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
3 No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
4 (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
5 </copyright> */
6
7var Montage = require("montage").Montage;
8var AbstractLanguage = require("./abstract-language").AbstractLanguage;
9var Semantics = require("./semantics").Semantics;
10var PropertyLanguage = require("./property-language").PropertyLanguage;
11
12var Language = exports.Language = AbstractLanguage.create(AbstractLanguage, {
13
14 semantics: {
15 value: Semantics
16 },
17
18 grammar: {
19 value: function () {
20
21 // precedence
22
23 this.parsePrimary(function (callback) {
24 return parseExpression(callback);
25 });
26
27 this.parseProperties();
28 this.parseLeftToRight(['startsWith', 'endsWith']);
29 this.parseLeftToRight(['pow']);
30 this.parseLeftToRight(['mul', 'div', 'mod']);
31 this.parseLeftToRight(['add', 'sub']);
32 this.parseBinary(['lessThan', 'greaterThan', 'lessThanOrEquals', 'greaterThanOrEquals']);
33 this.parseBinary(['equals', 'notEquals']);
34 this.parseLeftToRight(['xor']);
35 this.parseLeftToRight(['and']);
36 this.parseLeftToRight(['or']);
37 this.parseConditional();
38 var parseScalar = this.precedence();
39
40 this.parseArray();
41 this.parseRightToLeft(['has', 'contains', 'every', 'some', 'one', 'only', 'filter', 'map', 'it']);
42 this.parseSorted(parseScalar);
43 this.parseSlice(parseScalar);
44 this.parseRightToLeft(['sum', 'count', 'average', 'unique', 'flatten']);
45 var parseExpression = this.precedence();
46
47 // TODO median, mode, flatten, any, all
48
49 // extra
50
51 this.parseOperator(); // to collect the needed tokens
52
53 }
54 },
55
56 aliases: {
57 value: {
58 lt: 'lessThan',
59 gt: 'greaterThan',
60 le: 'lessThanOrEquals',
61 ge: 'greaterThanOrEquals',
62 eq: 'equals',
63 ne: 'notEquals'
64 }
65 },
66
67 constants: {
68 value: {
69 'true': true,
70 'false': false
71 }
72 },
73
74 selectorExtras: {
75 value: {
76
77 // Shorthand for chained gets
78 property: {
79 value: function (path) {
80 try {
81 var self = this;
82 var syntax = PropertyLanguage.parse(path);
83 PropertyLanguage.reemit(syntax, function (token) {
84 self = self.emit(token);
85 })
86 return self;
87 } catch (exception) {
88 throw exception;
89 throw new SyntaxError(
90 "Can't parse property: " + JSON.stringify(path) + ": " +
91 exception.message
92 );
93 }
94 }
95 },
96
97 // Shorthand using object literals
98 matches: {
99 value: function (object) {
100 var Selector = this.language.Selector;
101 var selector = this.it["true"];
102 var tokens = selector.language.tokens;
103 for (var property_operator in object) {
104 var value = object[property_operator];
105 property_operator = property_operator.split('_');
106 var property = property_operator.shift();
107 selector.emit(tokens.and);
108 Selector.property(property).tokens.forEach(function (token) {
109 selector.emit(token);
110 });
111 if (property_operator.length) {
112 property_operator.forEach(function (operator) {
113 selector.emit(tokens[operator]);
114 });
115 } else {
116 selector.emit(tokens.equals);
117 }
118 selector.emit({type: 'literal', value: value});
119 }
120 return selector;
121 }
122 }
123
124 }
125 },
126
127 parseIdentifier: {
128 value: function (callback) {
129 var self = this;
130 self.requireTokens(['literal']);
131 return function (token) {
132 if (token.type === 'literal' && typeof token.value === 'string') {
133 return callback(token.value);
134 } else {
135 throw new SyntaxError('Expected identifier, got: ' + JSON.stringify(token.type));
136 }
137 };
138 }
139 },
140
141 parseUrPrimary: {
142 value: function (callback, parseExpression, negated, rewindNegation) {
143 var self = this;
144 return function (token) {
145 if (token.type === 'begin') {
146 return parseExpression(function (expression) {
147 return self.expect('end', function () {
148 return callback(expression, negated);
149 });
150 });
151 } else if (token.type === 'value') {
152 return callback(self.tokens.value, negated);
153 } else if (token.type === 'parameter') {
154 return self.parseIdentifier(function (name) {
155 var syntax = name.split(".").reduce(function (previous, name) {
156 return {
157 type: 'get',
158 args: [previous, {
159 type: 'literal',
160 value: name
161 }]
162 }
163 }, {type: 'parameters'})
164 return callback(syntax, negated);
165 })
166 } else if (token.type === 'literal') {
167 return callback(token, negated);
168 } else if (self.constants[token.type]) {
169 return callback(self.constantSyntax[token.type], negated);
170 } else {
171 return rewindNegation(
172 callback(
173 self.tokens.value,
174 false
175 )
176 )(token);
177 }
178 };
179 }
180 },
181
182 parsePrimary: {
183 value: function (parseExpression) {
184 var self = this;
185 self.requireTokens(['begin', 'end', 'value', 'literal', 'parameter', 'not']);
186 return self.precedence(function () { // first level of precedence
187 return function (callback) {
188 return self.optional('not', function (negated, rewindNegation) {
189 return self.parseUrPrimary(function (expression, stillNegated) {
190 if (stillNegated) {
191 expression = self.makeSyntax('not', [expression]);
192 }
193 return callback(expression);
194 }, parseExpression, negated, rewindNegation);
195 });
196 }
197 });
198 }
199 },
200
201 parseProperties: {
202 value: function () {
203 var self = this;
204 self.requireTokens(['get']);
205 var parseSelf = self.precedence(function (parsePrevious) {
206 return function (callback, previous) {
207 return function (token) {
208 if (token.type === 'get') {
209 return self.expect('literal', function (literal) {
210 previous = self.makeSyntax('get', [previous || self.tokens.value, literal]);
211 return parseSelf(callback, previous);
212 });
213 } else if (previous) {
214 return callback(previous)(token);
215 } else {
216 return parsePrevious(callback)(token);
217 }
218 }
219 };
220 });
221 return parseSelf;
222 }