diff options
author | Jose Antonio Marquez | 2012-05-16 15:42:37 -0700 |
---|---|---|
committer | Jose Antonio Marquez | 2012-05-16 15:42:37 -0700 |
commit | 857aafee732b6a85fa155ff4a05d1b8fde48f09d (patch) | |
tree | e06d330caee280aa05aec46391979e9abdcf974c /node_modules/montage/core/selector/language.js | |
parent | 5cc5d29736d8bf253e3a168cdd6443e839ffb23c (diff) | |
parent | fd54dabad7cbc27a0efb0957155c00d578912909 (diff) | |
download | ninja-857aafee732b6a85fa155ff4a05d1b8fde48f09d.tar.gz |
Merge branch 'refs/heads/Ninja-DOM-Architecture' into Document
Diffstat (limited to 'node_modules/montage/core/selector/language.js')
-rw-r--r-- | node_modules/montage/core/selector/language.js | 381 |
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 | |||
7 | var Montage = require("montage").Montage; | ||
8 | var AbstractLanguage = require("./abstract-language").AbstractLanguage; | ||
9 | var Semantics = require("./semantics").Semantics; | ||
10 | var PropertyLanguage = require("./property-language").PropertyLanguage; | ||
11 | |||
12 | var 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) { | ||