aboutsummaryrefslogtreecommitdiff
path: root/node_modules/montage/core/selector/property-language.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/montage/core/selector/property-language.js')
-rw-r--r--node_modules/montage/core/selector/property-language.js346
1 files changed, 346 insertions, 0 deletions
diff --git a/node_modules/montage/core/selector/property-language.js b/node_modules/montage/core/selector/property-language.js
new file mode 100644
index 00000000..8269572c
--- /dev/null
+++ b/node_modules/montage/core/selector/property-language.js
@@ -0,0 +1,346 @@
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 AbstractLanguage = require('./abstract-language').AbstractLanguage;
8var Parser = require('./parser').Parser;
9var Semantics = require('./semantics').Semantics;
10var LANGUAGE = require('./language'); // late bound for dependency cycle
11
12var VALUE = 'value';
13var LITERAL = 'literal';
14var GET = 'get';
15var BEGIN = 'begin';
16var END = 'end';
17var MAP = 'map';
18var COMMA = 'comma';
19var IT = 'it';
20var DOT = '.';
21var ARRAY = 'array';
22var SORTED = 'sorted';
23
24var PropertyLanguage = exports.PropertyLanguage = AbstractLanguage.create(AbstractLanguage, {
25
26 semantics: {
27 value: Semantics
28 },
29
30 stringToToken: {
31 value: {
32 '(': {type: BEGIN},
33 ')': {type: END},
34 '*': {type: MAP},
35 ',': {type: COMMA}
36 }
37 },
38
39 tokenRe: {
40 value: /\(|\)|\d+|\w[\w\d]*|,|\*|\.|./g
41 },
42
43 termStartRe: {
44 value: /[\(\w\d\*]/
45 },
46
47 separatorsRe: {
48 value: /[\(\)\.,]/
49 },
50
51 tokenize: {
52 value: function (string, emit) {
53 var tokens;
54 if (!emit) {
55 tokens = [];
56 emit = function (token) {
57 tokens.push(token);
58 }
59 }
60 var self = this;
61 var expectSeparator = false;
62 var expectTermStart = true;
63 var soFar = '';
64 string.replace(self.tokenRe, function (token) {
65 if (expectSeparator) {
66 if (!self.separatorsRe.test(token)) {
67 throw new Error(
68 'Expected punctuation after: ' +
69 JSON.stringify(soFar) + ", got: " +
70 JSON.stringify(string.slice(soFar.length))
71 );
72 }
73 expectSeparator = false;
74 }
75 if (expectTermStart) {
76 if (!self.termStartRe.test(token)) {
77 throw new Error(
78 'Expected term after: ' + JSON.stringify(soFar) + ", got: " +
79 JSON.stringify(string.slice(soFar.length))
80 );
81 }
82 }
83 if (token === DOT) {
84 // ignore, used only for delimiting tokens, like a space
85 expectTermStart = true;
86 } else if (self.stringToToken[token]) {
87 emit(self.stringToToken[token]);
88 expectTermStart = false;
89 } else if (/^\d+$/.test(token)) {
90 emit({
91 type: LITERAL,
92 value: +token
93 });
94 expectSeparator = true;
95 expectTermStart = false;
96 } else if (/^\w[\w\d]*$/.test(token)) {
97 emit({
98 type: LITERAL,
99 value: token
100 });
101 expectSeparator = true;
102 expectTermStart = false;
103 } else {
104 throw new Error('Unexpected character: ' + JSON.stringify(token));
105 }
106 soFar += token;
107 })
108 return tokens;
109 }
110 },
111
112 parse: {
113 value: function (string) {
114 var self = this;
115 var syntax;
116 var parser = Parser.newWithLanguage(self, function (_syntax) {
117 syntax = _syntax;
118 });
119 self.tokenize(string, function (token) {
120 parser.emit(token);
121 })
122 parser.emit(LANGUAGE.Language.tokens.eof);
123 return syntax;
124 }
125 },
126
127 grammar: {
128 value: function () {
129 var self = this;
130
131 self.primary = self.parsePrimary(function (callback) {
132 return self.parseExpression(callback);
133 });
134
135 var parseTuple = self.parseTuple();
136
137 self.parseExpression = self.precedence();
138
139 }
140 },
141
142 parseTerm: {
143 value: function (consequent, alternate) {
144 var self = this;
145 return function (token) {
146 if (token.type === LITERAL) {
147 return self.optional(BEGIN, function (begin) {
148 if (begin) {
149 return self.primary(function (expression) {
150 return self.expect(END, function () {
151 return consequent({
152 call: true,
153 type: token.value,
154 arg: expression
155 });
156 });
157 });
158 } else {
159 return consequent({
160 type: GET,
161 arg: token
162 });
163 }
164 });
165 } else if (token.type === MAP) {
166 return self.parseTerm(function (map) {
167 return consequent({
168 type: MAP,
169 arg: {
170 type: map.type,
171 args: [
172 {type: VALUE},
173 map.arg
174 ]
175 }
176 })
177 }, function () {
178 return consequent({
179 type: IT,
180 arg: {type: VALUE}
181 })
182 });
183 } else if (token.type === BEGIN) {
184 return self.parseExpression(function (expression) {
185 return self.expect(END, function () {
186 return consequent({
187 type: IT,
188 arg: expression
189 });
190 });
191 });
192 } else {
193 return alternate()(token);
194 }
195 };
196 }
197 },
198
199 parsePrimary: {
200 value: function (parseExpression) {
201 var self = this;
202 var parseSelf = self.precedence(function (parsePrevious) {
203 return function (callback, previous) {
204 previous = previous || {type: VALUE};
205 return self.parseTerm(function (term) {
206 var syntax;
207 if (term.call) {
208 if (term.arg.type !== VALUE) {
209 previous = {
210 type: MAP,
211 args: [
212 previous,
213 term.arg
214 ]
215 };
216 }
217 syntax = {
218 type: term.type,