aboutsummaryrefslogtreecommitdiff
path: root/node_modules/montage/core/selector/abstract-language.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/montage/core/selector/abstract-language.js')
-rw-r--r--node_modules/montage/core/selector/abstract-language.js303
1 files changed, 303 insertions, 0 deletions
diff --git a/node_modules/montage/core/selector/abstract-language.js b/node_modules/montage/core/selector/abstract-language.js
new file mode 100644
index 00000000..1ae8f616
--- /dev/null
+++ b/node_modules/montage/core/selector/abstract-language.js
@@ -0,0 +1,303 @@
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;
8
9var makeSelector = require("./abstract-selector").makeSelector;
10
11var AbstractLanguage = exports.AbstractLanguage = Montage.create(Montage, {
12
13 create: {
14 value: function (prototype, descriptor) {
15 var self = Montage.create(prototype, descriptor);
16 self.parsePrevious = null;
17 self.tokens = {};
18 self.tokenNames = [];
19 self.constantSyntax = {};
20 self.requireConstants(self.constants);
21
22 // compute inverse of aliases so we can map tokens
23 self.reverseAliases = {};
24 self.aliases = self.aliases || {};
25 Object.keys(self.aliases).forEach(function (to) {
26 var from = self.aliases[to];
27 self.reverseAliases[from] = self.reverseAliases[from] || [];
28 self.reverseAliases[from].push(to);
29 });
30
31 self.requireTokens(['eof']);
32
33 self.grammar();
34
35 self.Selector = makeSelector(self);
36
37 return self;
38 }
39 },
40
41 // shared by all instances and heirs to reduce allocations
42 tokenMemo: {
43 value: {}
44 },
45
46 requireTokens: {
47 value: function (names) {
48 var self = this;
49 return names.reduce(function (accumulated, name) {
50 if (!self.tokens[name]) {
51 self.tokens[name] =
52 self.tokenMemo[name] =
53 self.tokenMemo[name] || {type: name};
54 self.tokenNames.push(name);
55 if (self.reverseAliases[name]) {
56 return accumulated
57 .concat([name])
58 .concat(
59 self.requireTokens(self.reverseAliases[name])
60 );
61 }
62 }
63 return accumulated.concat([name]);
64 }, []);
65 }
66 },
67
68 constantSyntax: {
69 value: null
70 },
71
72 requireConstants: {
73 value: function (constants) {
74 var self = this;
75 var names = Object.keys(constants || {});
76 names.forEach(function (name) {
77 if (!self.constantSyntax[name]) {
78 self.tokens[name] =
79 self.constantSyntax[name] = {
80 type: 'literal',
81 value: self.constants[name]
82 }
83 self.tokenNames.push(name);
84 }
85 });
86 }
87 },
88
89 // parser utilities
90
91 makeSyntax: {
92 value: function (type, args, insensitive, negated) {
93 var self = this;
94
95 while (self.aliases.hasOwnProperty(type)) {
96 type = self.aliases[type];
97 }
98 var syntax = {
99 type: type,
100 args: args,
101 insensitive: insensitive || undefined
102 };
103 if (!insensitive) {
104 delete syntax.insensitive;
105 }
106 if (negated) {
107 return {
108 type: 'not',
109 args: [syntax]
110 }
111 }
112 return syntax;
113 }
114 },
115
116 parsePrevious: {
117 value: null
118 },
119
120 precedence: {
121 value: function (callback) {
122 callback = callback || identity;
123 this.parsePrevious = callback(this.parsePrevious);
124 return this.parsePrevious;
125 }
126 },
127
128 // parsers
129
130 optional: {
131 value: function (type, callback) {
132 return function (token) {
133 if (type === token.type) {
134 return callback(true, function rewind(state) {
135 return state(token);
136 });
137 } else {
138 return callback(false, function rewind(state) {
139 return state;
140 })(token);
141 }
142 };
143 }
144 },
145
146 expect: {
147 value: function (type, callback) {
148 return function (token) {
149 if (token.type !== type) {
150 throw new SyntaxError(
151 'Expected token ' + JSON.stringify(type) +
152 ' got ' + JSON.stringify(token.type));
153 } else {
154 return callback(token);
155 }
156 };
157 }
158
159 },
160
161 parseEof: {
162 value: function () {
163 var self = this;
164 return self.expect('eof', function () {
165 return function () {
166 return self.parseEof();
167 };
168 })
169 }
170 },
171
172 parseOperator: {
173 value: function (types, consequent, alternate) {
174 var self = this;
175 self.requireTokens(['insensitive', 'not']);
176 return self.optional('insensitive', function (
177 insensitive,
178 rewindInsensitive
179 ) {
180 return self.optional('not', function (
181 negated,
182 rewindNegation
183 ) {
184 return function (token) {
185 if (types.indexOf(token.type) !== -1) {
186 return consequent(
187 token.type,
188 insensitive,
189 negated
190 );
191 } else {
192 return rewindInsensitive(
193 rewindNegation(
194 alternate()
195 )
196 )(token);
197 }
198 };
199 });
200 });
201 }
202 },
203
204 parseLeftToRight: {
205 value: function (types) {
206 var self = this;
207 types = self.requireTokens(types);
208 var parseSelf = self.precedence(function (parsePrevious) {
209 return function (callback, left) {
210 if (left) {
211 return self.parseOperator(types, function (
212 type,
213 insensitive,
214 negated
215 ) {
216 return parsePrevious(function (right) {
217 var syntax = self.makeSyntax(
218 type,
219 [left, right],
220 insensitive,