UNPKG

7.49 kBJavaScriptView Raw
1var _ = require('underscore');
2var asyncControl = require('../asyncControl')
3
4module.exports = function (listOfTerminals) {
5 var terms = this;
6 return terms.oldTerm(function () {
7 this.isComplexExpression = true;
8 this.basicExpressions = _(listOfTerminals).map(function (terminals) {
9 return terms.basicExpression(terminals);
10 });
11
12 this.subterms('basicExpressions');
13
14 this.head = function () {
15 return this._firstExpression || (this._firstExpression = this.basicExpressions[0]);
16 };
17
18 this.tail = function () {
19 return this._tail || (this._tail = this.basicExpressions.slice(1));
20 };
21
22 this.hasTail = function () {
23 return this.tail().length > 0;
24 };
25
26 this.isAsyncCall = function () {
27 return this.head().hasAsyncArgument();
28 };
29
30 this.isFutureCall = function () {
31 return this.head().hasFutureArgument();
32 };
33
34 this.isCallbackCall = function () {
35 return this.head().hasCallbackArgument();
36 };
37
38 this.tailBlock = function () {
39 if (this._hasTailBlock) {
40 return this._tailBlock;
41 } else {
42 var tail = this.tail();
43 if (tail.length > 0) {
44 var block = tail[tail.length - 1].hashEntryBlock();
45
46 this._hasTailBlock = block;
47 return this._tailBlock = block;
48 } else {
49 this._hasTailBlock = false;
50 this._tailBlock = undefined;
51 }
52 }
53 }
54
55 this.arguments = function () {
56 if (this._arguments) {
57 return this._arguments;
58 } else {
59 var args = this.head().arguments();
60
61 var tailBlock = this.tailBlock();
62
63 if (tailBlock) {
64 return this._arguments = args.concat(tailBlock);
65 } else {
66 return this._arguments = args;
67 }
68 }
69 }
70
71 this.hasArguments = function () {
72 return this._hasArguments || (this._hasArguments =
73 this.head().hasArguments() || this.tailBlock()
74 );
75 };
76
77 this.expression = function () {
78 var head = this.head();
79
80 if (head.hasName()) {
81 if (this.hasArguments()) {
82 return this.wrap(terms.functionCall(terms.variable(head.name(), {couldBeMacro: false, location: this.location()}), this.arguments(), {options: true}));
83 } else {
84 return this.wrap(terms.variable(head.name(), {location: this.location()}));
85 }
86 } else {
87 if (!this.hasTail() && this.arguments().length === 1 && !this.head().isCall()) {
88 return this.arguments()[0];
89 } else {
90 return this.wrap(terms.functionCall(this.arguments()[0], this.arguments().slice(1), {options: true}));
91 }
92 }
93 };
94
95 this.objectOperationExpression = function (object) {
96 var head = this.head();
97
98 if (head.hasName()) {
99 if (this.hasArguments()) {
100 return this.wrap(terms.methodCall(object, head.name(), this.arguments(), {options: true}));
101 } else {
102 return this.wrap(terms.fieldReference(object, head.name()));
103 }
104 } else {
105 if (!this.hasTail() && !head.isCall() && !this.isAsyncCall()) {
106 return terms.indexer(object, this.arguments()[0]);
107 } else {
108 return this.wrap(terms.functionCall(terms.indexer(object, this.arguments()[0]), this.arguments().slice(1), {options: true}));
109 }
110 }
111 };
112
113 this.wrap = function (term) {
114 if (this.isAsyncCall()) {
115 term = terms.resolve(term);
116 }
117
118 return term;
119 };
120
121 this.parameters = function (options) {
122 return this.head().parameters(options);
123 };
124
125 this.hasParameters = function () {
126 return this._hasParameters || (this._hasParameters =
127 this.head().hasParameters()
128 );
129 };
130
131 this.hashEntry = function () {
132 if (this.hasTail()) {
133 return terms.errors.addTermsWithMessage(this.tail(), 'cannot be a hash entry');
134 }
135 return this.head().hashEntry();
136 };
137
138 this.objectOperationDefinition = function (object, source) {
139 var self = this;
140
141 return {
142 expression: function () {
143 if (self.head().hasName()) {
144 if (self.hasParameters()) {
145 var block = source.blockify(self.parameters(), {returnPromise: self.isAsyncCall(), redefinesSelf: true});
146 return terms.definition(terms.fieldReference(object, self.head().name()), block, {assignment: true});
147 } else {
148 return terms.definition(terms.fieldReference(object, self.head().name()), source.scopify(), {assignment: true});
149 }
150 } else {
151 if (!self.hasTail() && self.arguments().length === 1 && !self.isAsyncCall()) {
152 return terms.definition(terms.indexer(object, self.arguments()[0]), source.scopify(), {assignment: true});
153 } else {
154 var block = source.blockify(self.parameters({skipFirstParameter: true}), {returnPromise: self.isAsyncCall(), redefinesSelf: true});
155 return terms.definition(terms.indexer(object, self.arguments()[0]), block, {assignment: true});
156 }
157 }
158 }
159 };
160 };
161
162 this.objectOperation = function (object) {
163 var complexExpression = this;
164
165 return new function () {
166 this.operation = complexExpression;
167 this.object = object;
168
169 this.expression = function () {
170 return this.operation.objectOperationExpression(this.object);
171 };
172
173 this.definition = function (source) {
174 return this.operation.objectOperationDefinition(this.object, source);
175 };
176
177 this.hashEntry = function () {
178 return terms.errors.addTermWithMessage(this.expression(), 'cannot be a hash entry');
179 };
180 };
181 };
182
183 this.definition = function (source, options) {
184 var self = this;
185 var assignment = options && Object.hasOwnProperty.call(options, 'assignment') && options.assignment;
186
187 if (self.head().hasName()) {
188 if (self.hasParameters()) {
189 return {
190 expression: function () {
191 return terms.definition(terms.variable(self.head().name(), {location: self.location()}), source.blockify(self.parameters(), {returnPromise: self.isAsyncCall()}), {assignment: assignment});
192 },
193 hashEntry: function (isOptionalArgument) {
194 var block = source.blockify(self.parameters(), {returnPromise: self.isAsyncCall(), redefinesSelf: !isOptionalArgument});
195
196 return terms.hashEntry(self.head().name(), block);
197 }
198 };
199 } else {
200 return {
201 expression: function () {
202 return terms.definition(terms.variable(self.head().name(), {location: self.location()}), source.scopify(), {assignment: assignment});
203 },
204 hashEntry: function () {
205 return terms.hashEntry(self.head().hashKey(), source.scopify());
206 }
207 };
208 }
209 } else if (self.isAsyncCall()) {
210 return {
211 hashEntry: function () {
212 var head = self.head();
213 return terms.hashEntry(head.hashKey(), source.blockify ([], {async: true}));
214 }
215 };
216 } else {
217 return {
218 hashEntry: function () {
219 var head = self.head();
220 return terms.hashEntry(head.hashKey(), source);
221 }
222 };
223 }
224 };
225 });
226};