1 #include <Esc/Esc.h>
2
3
4 namespace Upp {
5
6 #ifdef _MSC_VER
7 #pragma inline_depth(255)
8 #pragma optimize("t", on)
9 #endif
10
11 #define LTIMING(x) // RTIMING(x)
12
OutOfMemory()13 void Esc::OutOfMemory()
14 {
15 ThrowError("Out of memory");
16 }
17
TestLimit()18 void Esc::TestLimit()
19 {
20 LTIMING("TestLimit");
21 if(!IsNull(op_limit))
22 if(op_limit < 0)
23 ThrowError("out of operations limit - considered frozen");
24 if(EscValue::GetTotalCount() >= EscValue::GetMaxTotalCount())
25 OutOfMemory();
26 }
27
Get(const SRVal & val)28 EscValue Esc::Get(const SRVal& val)
29 {
30 LTIMING("Get");
31 if(skipexp)
32 return (int64)1;
33 EscValue v = val.lval ? *val.lval : val.rval;
34 if(val.sbs.IsArray()) {
35 const Vector<EscValue>& sbs = val.sbs.GetArray();
36 for(int i = 0; i < sbs.GetCount(); i++) {
37 const EscValue& ss = sbs[i];
38 if(v.IsMap()) //!!!! (problem with a[1, 2]
39 v = v.MapGet(ss);
40 else
41 if(v.IsArray()) {
42 int count = v.GetCount();
43 if(ss.IsArray() && ss.GetArray().GetCount() >= 2) {
44 EscValue v1 = ss.ArrayGet(0);
45 EscValue v2 = ss.ArrayGet(1);
46 int i = v1.GetInt();
47 int n = count - i;
48 if(ss.GetCount() == 2)
49 n = v2.IsInt() ? v2.GetInt() : n;
50 else {
51 if(v2.IsInt()) {
52 n = v2.GetInt();
53 if(n < 0)
54 n += count;
55 n -= i;
56 }
57 }
58 if(i >= 0 && n >= 0 && i + n <= count)
59 v = v.ArrayGet(i, n);
60 else
61 ThrowError("slice out of range");
62 }
63 else {
64 int64 i = Int(ss, "index");
65 if(i < 0)
66 i += count;
67 if(i >= 0 && i < count)
68 v = v.ArrayGet((int)i);
69 else
70 ThrowError("index out of range");
71 }
72 }
73 else
74 ThrowError("invalid indirection");
75 TestLimit();
76 }
77 }
78 return v;
79 }
80
Assign(EscValue & val,const Vector<EscValue> & sbs,int si,const EscValue & src)81 void Esc::Assign(EscValue& val, const Vector<EscValue>& sbs, int si, const EscValue& src)
82 {
83 LTIMING("Assign");
84 const EscValue& ss = sbs[si++];
85 if(val.IsVoid())
86 val.SetEmptyMap();
87 if(val.IsMap()) {
88 if(si < sbs.GetCount()) {
89 EscValue x = val.MapGet(ss);
90 val.MapSet(ss, 0.0);
91 Assign(x, sbs, si, src);
92 val.MapSet(ss, x);
93 }
94 else
95 val.MapSet(ss, src);
96 return;
97 }
98 else
99 if(val.IsArray()) {
100 if(si < sbs.GetCount()) {
101 if(ss.IsArray())
102 ThrowError("slice must be last subscript");
103 int64 i = Int(ss, "index");
104 if(i >= 0 && i < val.GetCount()) {
105 EscValue x = val.ArrayGet((int)i);
106 val.ArraySet((int)i, 0.0);
107 Assign(x, sbs, si, src);
108 if(!val.ArraySet((int)i, x))
109 OutOfMemory();
110 return;
111 }
112 }
113 else {
114 int count = val.GetCount();
115 if(ss.IsArray()) {
116 if(!src.IsArray() || ss.GetArray().GetCount() < 2)
117 ThrowError("only array can be assigned to the slice");
118 EscValue v1 = ss.ArrayGet(0);
119 EscValue v2 = ss.ArrayGet(1);
120 int i = v1.IsInt() ? v1.GetInt() : 0;
121 int n = count - i;
122 if(ss.GetCount() == 2)
123 n = v2.IsInt() ? v2.GetInt() : n;
124 else {
125 if(v2.IsInt()) {
126 n = v2.GetInt();
127 if(n < 0)
128 n += count;
129 n -= i;
130 }
131 }
132 if(i >= 0 && n >= 0 && i + n <= count) {
133 val.Replace(i, n, src);
134 return;
135 }
136 else
137 ThrowError("slice out of range");
138 }
139 else {
140 int64 i = ss.IsVoid() ? val.GetCount() : Int(ss, "index");
141 if(i < 0)
142 i = count + i;
143 if(i >= 0 && i < INT_MAX) {
144 if(!val.ArraySet((int)i, src))
145 ThrowError("out of memory");
146 return;
147 }
148 }
149 }
150 }
151 ThrowError("invalid indirection");
152 }
153
Assign(const SRVal & val,const EscValue & src)154 void Esc::Assign(const SRVal& val, const EscValue& src)
155 {
156 if(skipexp)
157 return;
158 if(!val.lval)
159 ThrowError("l-value required");
160 if(val.sbs.IsArray() && val.sbs.GetCount())
161 Assign(*val.lval, val.sbs.GetArray(), 0, src);
162 else
163 *val.lval = src;
164 }
165
ExecuteLambda(const String & id,EscValue lambda,SRVal self,Vector<SRVal> & arg)166 EscValue Esc::ExecuteLambda(const String& id, EscValue lambda, SRVal self, Vector<SRVal>& arg)
167 {
168 LTIMING("ExecuteLambda");
169 if(!lambda.IsLambda())
170 ThrowError(Format("'%s' is not a lambda", id));
171 const EscLambda& l = lambda.GetLambda();
172 if(!l.varargs && arg.GetCount() > l.arg.GetCount()
173 || arg.GetCount() < l.arg.GetCount() - l.def.GetCount())
174 ThrowError("invalid number of arguments in call to '" + id + "'");
175 Esc sub(global, l.code, op_limit, l.filename, l.line);
176 sub.self = Get(self);
177 for(int i = 0; i < l.arg.GetCount(); i++) {
178 sub.var.GetAdd(l.arg[i]) =
179 i < arg.GetCount() ? Get(arg[i])
180 : Evaluatex(l.def[i - (l.arg.GetCount() - l.def.GetCount())], global, op_limit);
181 TestLimit();
182 }
183 EscValue retval;
184 Array<EscValue> argvar;
185 if(l.escape) {
186 argvar = sub.var.PickValues();
187 for(int i = l.arg.GetCount(); i < arg.GetCount(); i++) {
188 argvar.Add(Get(arg[i]));
189 }
190 EscValue v = Get(self);
191 EscEscape e(*this, v, argvar);
192 e.id = id;
193 l.escape(e);
194 retval = e.ret_val;
195 self = e.self;
196 }
197 else {
198 if(l.varargs) {
199 EscValue& argv = sub.var.GetAdd("argv");
200 argv.SetEmptyArray();
201 for(int i = l.arg.GetCount(); i < arg.GetCount(); i++)
202 argv.ArrayAdd(Get(arg[i]));
203 }
204 sub.Run();
205 retval = sub.return_value;
206 argvar = sub.var.PickValues();
207 }
208 for(int i = 0; i < l.inout.GetCount(); i++)
209 if(l.inout[i] && i < arg.GetCount() && arg[i].lval)
210 Assign(arg[i], argvar[i]);
211 if(self.lval)
212 Assign(self, sub.self);
213 return retval;
214 }
215
Subscript(Esc::SRVal & r,Esc::SRVal _self,String id)216 void Esc::Subscript(Esc::SRVal& r, Esc::SRVal _self, String id)
217 {
218 LTIMING("Subscript");
219 for(;;) {
220 TestLimit();
221 if(Char('['))
222 if(Char(']'))
223 r.sbs.ArrayAdd(EscValue());
224 else {
225 EscValue v1, v2;
226 if(!IsChar(',') && !IsChar(':'))
227 v1 = GetExp();
228 if(Char(',')) {
229 if(!IsChar(']'))
230 v2 = GetExp();
231 EscValue x;
232 x.ArrayAdd(v1);
233 x.ArrayAdd(v2);
234 r.sbs.ArrayAdd(x);
235 }
236 else
237 if(Char(':')) {
238 if(!IsChar(']'))
239 v2 = GetExp();
240 EscValue x;
241 x.ArrayAdd(v1);
242 x.ArrayAdd(v2);
243 x.ArrayAdd(EscValue());
244 r.sbs.ArrayAdd(x);
245 }
246 else
247 r.sbs.ArrayAdd(v1);
248 PassChar(']');
249 }
250 else
251 if(Char('.')) {
252 _self = r;
253 r.sbs.ArrayAdd(id = ReadId());
254 }
255 else
256 if(Char('(')) {
257 LTIMING("call fn");
258 Vector<SRVal> arg;
259 if(!Char(')'))
260 for(;;) {
261 LTIMING("make args");
262 Exp(arg.Add());
263 if(Char(')')) break;
264 PassChar(',');
265 }
266 if(!IsChar2('!', '=') && Char('!')) {
267 Term(_self);
268 EscValue g = Get(_self);
269 if(!_self.lval || (!g.IsVoid() && !g.IsMap()))
270 ThrowError("l-value map or l-value void expected on the right side of !");
271 if(g.IsVoid()) {
272 EscValue v;
273 v.SetEmptyMap();
274 Assign(_self, v);
275 }
276 }
277 if(!skipexp)
278 try {
279 r = ExecuteLambda(id, Get(r), _self, arg);
280 }
281 catch(Exc e) {
282 throw Error(Format("%s.%s(): %s", Get(r).GetTypeName(), id, e));
283 }
284 }
285 else
286 return;
287 }
288 }
289
Subscript(Esc::SRVal & r)290 void Esc::Subscript(Esc::SRVal& r)
291 {
292 Subscript(r, SRVal(), String());
293 }
294
Term(SRVal & r)295 void Esc::Term(SRVal& r)
296 {
297 r.sbs = EscValue();
298
299 op_limit--;
300 TestLimit();
301 if(Char2('0', 'x') || Char2('0', 'X')) {
302 r = ReadNumber64(16);
303 return;
304 }
305 if(Char2('0', 'b') || Char2('0', 'B')) {
306 r = ReadNumber64(2);
307 return;
308 }
309 if(IsChar2('0', '.')) {
310 r = ReadDouble();
311 return;
312 }
313 if(Char('0')) {
314 r = IsNumber() ? ReadNumber64(8) : 0;
315 return;
316 }
317 if(IsNumber()) {
318 // TODO: int64 !
319 r = ReadDouble();
320 return;
321 }
322 if(IsString()) {
323 r = EscValue(FromUtf8(ReadString()));
324 return;
325 }
326 if(IsChar('\'')) {
327 WString s = FromUtf8(ReadString('\''));
328 if(s.GetLength() != 1)
329 ThrowError("invalid character literal");
330 r = (int64)s[0];
331 return;
332 }
333 if(Char('@')) {
334 r = ReadLambda(*this);
335 Subscript(r);
336 return;
337 }
338 if(Id("void")) {
339 r = EscValue();
340 return;
341 }
342 if(Char('{')) {
343 EscValue map;
344 map.SetEmptyMap();
345 if(!Char('}'))
346 for(;;) {
347 EscValue v = GetExp();
348 PassChar(':');
349 map.MapSet(v, GetExp());
350 if(Char('}'))
351 break;
352 PassChar(',');
353 TestLimit();
354 }
355 r = map;
356 Subscript(r);
357 return;
358 }
359 if(Char('[')) {
360 EscValue array;
361 array.SetEmptyArray();
362 if(!Char(']'))
363 for(;;) {
364 array.ArrayAdd(GetExp());
365 if(Char(']'))
366 break;
367 PassChar(',');
368 TestLimit();
369 }
370 r = array;
371 Subscript(r);
372 return;
373 }
374 if(Char('(')) {
375 Exp(r);
376 PassChar(')');
377 Subscript(r);
378 return;
379 }
380
381 SRVal _self;
382 bool _global = false;
383 if(Char('.')) {
384 if(!self.IsMap())
385 ThrowError("member-access in non-member code");
386 _self.lval = &self;
387 }
388 else
389 if(Char(':'))
390 _global = true;
391 if(IsId()) {
392 String id = ReadId();
393 EscValue method;
394 int locali = var.Find(id);
395 int ii;
396
397 if(id == "self") {
398 if(!self.IsMap())
399 ThrowError("self in non-member code");
400 _self.lval = &self;
401 r = self;
402 }
403 else
404 if(!_self.lval && !_global && locali < 0 && IsChar('(') &&
405 self.IsMap() && (method = self.MapGet(id)).IsLambda()) {
406 _self.lval = &self;
407 r = method;
408 }
409 else
410 if(!_self.lval && !_global && locali < 0 && IsChar('(') &&
411 (ii = global.Find(id)) >= 0 && global[ii].IsLambda()) {
412 r = global[ii];
413 }
414 else
415 if(_self.lval) {
416 r = _self;
417 r.sbs.ArrayAdd(id);
418 }
419 else
420 if(_global)
421 r.lval = &global.GetPut(id);
422 else
423 r.lval = &var.GetPut(id);
424
425 try {
426 Subscript(r, _self, id);
427 }
428 catch(CParser::Error e) {
429 throw CParser::Error(id + ": " + e);
430 }
431 }
432 else
433 ThrowError("invalid expression");
434 }
435
Lims(const String & s)436 String Lims(const String& s)
437 {
438 return s.GetLength() > 80 ? s.Mid(0, 80) : s;
439 }
440
Number(const EscValue & a,const char * oper)441 double Esc::Number(const EscValue& a, const char *oper)
442 {
443 if(!a.IsNumber())
444 ThrowError(String().Cat() << "number expected for '" << oper << "', encountered " << Lims(a.ToString()));
445 return a.GetNumber();
446 }
447
Int(const EscValue & a,const char * oper)448 int64 Esc::Int(const EscValue& a, const char *oper)
449 {
450 if(!a.IsNumber())
451 ThrowError(String().Cat() << "integer expected for '" << oper << "', encountered " << Lims(a.ToString()));
452 return a.GetInt64();
453 }
454
Number(const Esc::SRVal & a,const char * oper)455 double Esc::Number(const Esc::SRVal& a, const char *oper)
456 {
457 return Number(Get(a), oper);
458 }
459
Int(const Esc::SRVal & a,const char * oper)460 int64 Esc::Int(const Esc::SRVal& a, const char *oper)
461 {
462 return Int(Get(a), oper);
463 }
464
Unary(Esc::SRVal & r)465 void Esc::Unary(Esc::SRVal& r)
466 {
467 if(Char2('+', '+')) {
468 Unary(r);
469 EscValue v = Get(r);
470 if(v.IsInt64())
471 Assign(r, Int(v, "++") + 1);
472 else
473 Assign(r, Number(v, "++") + 1);
474 }
475 else
476 if(Char2('-', '-')) {
477 Unary(r);
478 EscValue v = Get(r);
479 if(v.IsInt64())
480 Assign(r, Int(v, "--") - 1);
481 else
482 Assign(r, Number(v, "--") - 1);
483 }
484 else
485 if(Char('-')) {
486 Unary(r);
487 EscValue v = Get(r);
488 if(v.IsInt64())
489 r = -Int(v, "-");
490 else
491 r = -Number(v, "-");
492 }
493 else
494 if(Char('+')) {
495 Unary(r);
496 EscValue v = Get(r);
497 if(v.IsInt64())
498 r = Int(v, "+");
499 else
500 r = Number(v, "+");
501 }
502 else
503 if(Char('!')) {
504 Unary(r);
505 r = (int64)!IsTrue(Get(r));
506 }
507 else
508 if(Char('~')) {
509 Unary(r);
510 r = ~Int(Get(r), "~");
511 }
512 else
513 Term(r);
514
515 if(Char2('+', '+')) {
516 EscValue v = Get(r);
517 if(v.IsInt64())
518 Assign(r, Int(v, "++") + 1);
519 else
520 Assign(r, Number(v, "++") + 1);
521 r = v;
522 }
523 if(Char2('-', '-')) {
524 EscValue v = Get(r);
525 if(v.IsInt64())
526 Assign(r, Int(v, "--") - 1);
527 else
528 Assign(r, Number(v, "--") - 1);
529 r = v;
530 }
531 }
532
MulArray(EscValue array,EscValue times)533 EscValue Esc::MulArray(EscValue array, EscValue times)
534 {
535 EscValue r;
536 r.SetEmptyArray();
537 for(int n = times.GetInt(); n > 0; n >>= 1) {
538 if(n & 1)
539 if(!r.Append(array))
540 OutOfMemory();
541 if(!array.Append(array))
542 OutOfMemory();
543 TestLimit();
544 }
545 return r;
546 }
547
Mul(Esc::SRVal & r)548 void Esc::Mul(Esc::SRVal& r)
549 {
550 Unary(r);
551 for(;;)
552 if(!IsChar2('*', '=') && Char('*')) {
553 EscValue x = Get(r);
554 SRVal w;
555 Unary(w);
556 EscValue y = Get(w);
557 if(x.IsArray() && y.IsInt())
558 r = MulArray(x, y);
559 else
560 if(y.IsArray() && x.IsInt())
561 r = MulArray(y, x);
562 else
563 if(x.IsInt64() && y.IsInt64())
564 r = Int(x, "*") * Int(y, "*");
565 else
566 r = Number(x, "*") * Number(y, "*");
567 }
568 else
569 if(!IsChar2('/', '=') && Char('/')) {
570 SRVal w;
571 Unary(w);
572 EscValue x = Get(r);
573 EscValue y = Get(w);
574 double b = Number(y, "/");
575 if(b == 0)
576 ThrowError("divide by zero");
577 r = Number(x, "/") / b;
578 }
579 else
580 if(!IsChar2('%', '=') && Char('%')) {
581 SRVal w;
582 Unary(w);
583 int64 b = Int(w, "%");
584 if(b == 0)
585 ThrowError("divide by zero");
586 r = Int(r, "%") % b;
587 }
588 else
589 return;
590 }
591
Add(Esc::SRVal & r)592 void Esc::Add(Esc::SRVal& r)
593 {
594 Mul(r);
595 for(;;)
596 if(!IsChar2('+', '=') && Char('+')) {
597 EscValue v = Get(r);
598 SRVal w;
599 Mul(w);
600 EscValue b = Get(w);
601 if(v.IsArray() && b.IsArray()) {
602 if(!v.Replace(v.GetCount(), 0, b))
603 OutOfMemory();
604 r = v;
605 }
606 else
607 if(!(v.IsArray() && b.IsVoid())) {
608 if(v.IsInt64() && b.IsInt64())
609 r = Int(v, "+") + Int(b, "+");
610 else
611 r = Number(v, "+") + Number(b, "+");
612 }
613 }
614 else
615 if(!IsChar2('-', '=') && Char('-')) {
616 SRVal w;
617 Mul(w);
618 EscValue v = Get(r);
619 EscValue b = Get(w);
620 if(v.IsInt64() && b.IsInt64())
621 r = Int(v, "-") - Int(b, "-");
622 else
623 r = Number(v, "-") - Number(b, "-");
624 }
625 else
626 return;
627 }
628
Shift(Esc::SRVal & r)629 void Esc::Shift(Esc::SRVal& r)
630 {
631 Add(r);
632 for(;;)
633 if(Char2('<', '<')) {
634 EscValue v = Get(r);
635 SRVal w;
636 Add(w);
637 EscValue b = Get(w);
638 if(v.IsArray() && b.IsArray()) {
639 if(!v.Replace(v.GetCount(), 0, b))
640 OutOfMemory();
641 Assign(r, v);
642 }
643 else
644 if(!(v.IsArray() && b.IsVoid()))
645 r = Int(v, "<<") << Int(b, "<<");
646 }
647 else
648 if(Char2('>', '>')) {
649 SRVal w;
650 Add(w);
651 r = Int(r, ">>") >> Int(w, ">>");
652 }
653 else
654 return;
655 }
656
DoCompare(const EscValue & a,const EscValue & b,const char * op)657 double Esc::DoCompare(const EscValue& a, const EscValue& b, const char *op)
658 {
659 LTIMING("DoCompare");
660 if(a.IsInt64() && b.IsInt64())
661 return SgnCompare(a.GetInt64(), b.GetInt64());
662 if(a.IsNumber() && b.IsNumber())
663 return SgnCompare(a.GetNumber(), b.GetNumber());
664 if(a.IsArray() && b.IsArray()) {
665 const Vector<EscValue>& x = a.GetArray();
666 const Vector<EscValue>& y = b.GetArray();
667 int i = 0;
668 for(;;) {
669 if(i >= x.GetCount())
670 return i < y.GetCount() ? -1 : 0;
671 if(i >= y.GetCount())
672 return i < x.GetCount() ? 1 : 0;
673 double q = DoCompare(x[i], y[i], op);
674 if(q) return q;
675 i++;
676 }
677 }
678 if(a.IsVoid() && b.IsVoid())
679 return 0;
680 if(!a.IsVoid() && b.IsVoid())
681 return 1;
682 if(a.IsVoid() && !b.IsVoid())
683 return -1;
684 ThrowError("invalid values for comparison " + a.GetTypeName() + ' ' + op + ' ' + b.GetTypeName());
685 return 0;
686 }
687
DoCompare(const SRVal & a,const char * op)688 double Esc::DoCompare(const SRVal& a, const char *op)
689 {
690 SRVal w;
691 Shift(w);
692 return DoCompare(Get(a), Get(w), op);
693 }
694
Compare(Esc::SRVal & r)695 void Esc::Compare(Esc::SRVal& r)
696 {
697 Shift(r);
698 for(;;)
699 if(Char2('>', '='))
700 r = DoCompare(r, ">=") >= 0;
701 else
702 if(Char2('<', '='))
703 r = DoCompare(r, "<=") <= 0;
704 else
705 if(Char('>'))
706 r = DoCompare(r, ">") > 0;
707 else
708 if(Char('<'))
709 r = DoCompare(r, "<") < 0;
710 else
711 return;
712 }
713
Equal(Esc::SRVal & r)714 void Esc::Equal(Esc::SRVal& r)
715 {
716 Compare(r);
717 for(;;)
718 if(Char2('=', '=')) {
719 SRVal w;
720 Compare(w);
721 r = Get(r) == Get(w);
722 }
723 else
724 if(Char2('!', '=')) {
725 SRVal w;
726 Compare(w);
727 r = Get(r) != Get(w);
728 }
729 else
730 return;
731 }
732
BinAnd(Esc::SRVal & r)733 void Esc::BinAnd(Esc::SRVal& r)
734 {
735 Equal(r);
736 while(!IsChar2('&', '&') && Char('&')) {
737 SRVal w;
738 Equal(w);
739 r = Int(r, "&") & Int(w, "&");
740 }
741 }
742
BinXor(Esc::SRVal & r)743 void Esc::BinXor(Esc::SRVal& r)
744 {
745 BinAnd(r);
746 while(Char('^')) {
747 SRVal w;
748 BinAnd(w);
749 r = Int(r, "^") ^ Int(w, "^");
750 }
751 }
752
BinOr(Esc::SRVal & r)753 void Esc::BinOr(Esc::SRVal& r)
754 {
755 BinXor(r);
756 while(!IsChar2('|', '|') && Char('|')) {
757 SRVal w;
758 BinXor(w);
759 r = Int(r, "|") | Int(w, "|");
760 }
761 }
762
And(Esc::SRVal & r)763 void Esc::And(Esc::SRVal& r)
764 {
765 BinOr(r);
766 if(IsChar2('&', '&')) {
767 bool b = IsTrue(Get(r));
768 while(Char2('&', '&')) {
769 SRVal w;
770 if(b) {
771 BinOr(w);
772 b = b && IsTrue(Get(w));
773 }
774 else {
775 skipexp++;
776 BinOr(w);
777 skipexp--;
778 }
779 }
780 r = b;
781 }
782 }
783
Or(Esc::SRVal & r)784 void Esc::Or(Esc::SRVal& r)
785 {
786 And(r);
787 if(IsChar2('|', '|')) {
788 bool b = IsTrue(Get(r));
789 while(Char2('|', '|')) {
790 SRVal w;
791 if(b) {
792 skipexp++;
793 And(w);
794 skipexp--;
795 }
796 else {
797 And(w);
798 b = b || IsTrue(Get(w));
799 }
800 }
801 r = b;
802 }
803 }
804
Cond(Esc::SRVal & r)805 void Esc::Cond(Esc::SRVal& r)
806 {
807 Or(r);
808 if(Char('?')) {
809 bool t = IsTrue(Get(r));
810 SRVal dummy;
811 if(t) {
812 Cond(r);
813 PassChar(':');
814 skipexp++;
815 Cond(dummy);
816 skipexp--;
817 }
818 else {
819 skipexp++;
820 Cond(dummy);
821 skipexp--;
822 PassChar(':');
823 Cond(r);
824 }
825 }
826 }
827
Assign(Esc::SRVal & r)828 void Esc::Assign(Esc::SRVal& r)
829 {
830 Cond(r);
831 if(Char('=')) {
832 SRVal w;
833 Assign(w);
834 Assign(r, Get(w));
835 }
836 else
837 if(Char2('+', '=')) {
838 EscValue v = Get(r);
839 SRVal w;
840 Cond(w);
841 EscValue b = Get(w);
842 if(v.IsArray() && b.IsArray()) {
843 if(!v.Replace(v.GetCount(), 0, b))
844 OutOfMemory();
845 Assign(r, v);
846 }
847 else
848 if(!(v.IsArray() && b.IsVoid())) {
849 if(v.IsInt64() && b.IsInt64())
850 Assign(r, Int(v, "+=") + Int(b, "+="));
851 else
852 Assign(r, Number(v, "+=") + Number(b, "+="));
853 }
854 }
855 else
856 if(Char2('-', '=')) {
857 SRVal w;
858 Cond(w);
859 EscValue v = Get(r);
860 EscValue b = Get(w);
861 if(v.IsInt64() && b.IsInt64())
862 Assign(r, Int(v, "-=") - Int(b, "-="));
863 else
864 Assign(r, Number(v, "-=") - Number(b, "-="));
865 }
866 else
867 if(Char2('*', '=')) {
868 SRVal w;
869 Cond(w);
870 EscValue x = Get(r);
871 EscValue y = Get(w);
872 if(x.IsInt64() && y.IsInt64())
873 Assign(r, Int(x, "*=") * Int(y, "*="));
874 else
875 Assign(r, Number(x, "*=") * Number(y, "*="));
876 }
877 else
878 if(Char2('/', '=')) {
879 SRVal w;
880 Cond(w);
881 EscValue v = Get(r);
882 EscValue b = Get(w);
883 double q = Number(v, "/=");
884 if(q == 0)
885 ThrowError("divide by zero");
886 Assign(r, Number(b, "/=") / q);
887 }
888 else
889 if(Char2('%', '=')) {
890 SRVal w;
891 Cond(w);
892 int64 a = Int(r, "%=");
893 int64 b = Int(w, "%=");
894 if(b == 0)
895 ThrowError("divide by zero");
896 Assign(r, a % b);
897 }
898 }
899
900 int Esc::stack_level = 50;
901
Exp(Esc::SRVal & r)902 void Esc::Exp(Esc::SRVal& r)
903 {
904 LTIMING("Exp");
905 Spaces();
906 stack_level--;
907 if(stack_level <= 0)
908 ThrowError("stack overflow");
909 Assign(r);
910 stack_level++;
911 }
912
GetExp()913 EscValue Esc::GetExp() {
914 SRVal r;
915 Exp(r);
916 return Get(r);
917 }
918
SkipTerm()919 void Esc::SkipTerm()
920 {
921 if(IsEof())
922 ThrowError("unexpected end of file");
923 CParser::SkipTerm();
924 Spaces();
925 }
926
SkipExp()927 void Esc::SkipExp()
928 {
929 int level = 0;
930 for(;;) {
931 if(IsChar(';'))
932 return;
933 if(IsChar(')') && level == 0)
934 return;
935 if(Char(')'))
936 level--;
937 else
938 if(Char('('))
939 level++;
940 else
941 SkipTerm();
942 if(IsEof())
943 ThrowError("unexpected end of file");
944 }
945 }
946
SkipBlock(CParser & p)947 void SkipBlock(CParser& p)
948 {
949 int level = 1;
950 while(level > 0 && !p.IsEof()) {
951 if(p.Char('{')) level++;
952 else
953 if(p.Char('}')) level--;
954 else
955 p.SkipTerm();
956 }
957 }
958
SkipStatement()959 void Esc::SkipStatement()
960 {
961 stack_level--;
962 if(stack_level <= 0)
963 ThrowError("stack overflow");
964 if(Id("if")) {
965 PassChar('(');
966 SkipExp();
967 PassChar(')');
968 SkipStatement();
969 if(Id("else"))
970 SkipStatement();
971 }
972 else
973 if(Id("for")) {
974 PassChar('(');
975 if(!IsChar(';'))
976 SkipExp();
977 PassChar(';');
978 if(!IsChar(';'))
979 SkipExp();
980 PassChar(';');
981 if(!IsChar(')'))
982 SkipExp();
983 PassChar(')');
984 SkipStatement();
985 }
986 else
987 if(Id("while") || Id("switch")) {
988 PassChar('(');
989 SkipExp();
990 PassChar(')');
991 SkipStatement();
992 }
993 else
994 if(Id("do")) {
995 SkipBlock(*this);
996 PassId("while");
997 PassChar('(');
998 SkipExp();
999 PassChar(')');
1000 PassChar(';');
1001 }
1002 else
1003 if(Char('{'))
1004 SkipBlock(*this);
1005 else {
1006 SkipExp();
1007 PassChar(';');
1008 }
1009 stack_level++;
1010 }
1011
PCond()1012 bool Esc::PCond()
1013 {
1014 PassChar('(');
1015 bool c = IsTrue(GetExp());
1016 PassChar(')');
1017 return c;
1018 }
1019
FinishSwitch()1020 void Esc::FinishSwitch()
1021 {
1022 while(no_break && no_return && no_continue) {
1023 if(Id("case")) {
1024 SRVal r;
1025 Exp(r);
1026 PassChar(':');
1027 }
1028 else
1029 if(Id("default"))
1030 PassChar(':');
1031 else
1032 if(Char('}'))
1033 return;
1034 DoStatement();
1035 }
1036 while(!Char('}'))
1037 SkipStatement();
1038 }
1039
DoStatement()1040 void Esc::DoStatement()
1041 {
1042 op_limit--;
1043 TestLimit();
1044 if(Id("if"))
1045 if(PCond()) {
1046 DoStatement();
1047 if(Id("else"))
1048 SkipStatement();
1049 }
1050 else {
1051 SkipStatement();
1052 if(Id("else"))
1053 DoStatement();
1054 }
1055 else
1056 if(Id("do")) {
1057 loop++;
1058 Pos pos = GetPos();
1059 do {
1060 SetPos(pos);
1061 DoStatement();
1062 PassId("while");
1063 no_continue = true;
1064 }
1065 while(PCond() && no_break && no_return);
1066 PassChar(';');
1067 no_break = true;
1068 loop--;
1069 }
1070 else
1071 if(Id("while")) {
1072 loop++;
1073 Pos pos = GetPos();
1074 for(;;) {
1075 SetPos(pos);
1076 if(!PCond() || !no_break || !no_return || !no_continue) {
1077 SkipStatement();
1078 break;
1079 }
1080 DoStatement();
1081 no_continue = true;
1082 }
1083 no_break = true;
1084 loop--;
1085 }
1086 else
1087 if(Id("for")) {
1088 loop++;
1089 PassChar('(');
1090 SRVal var;
1091 if(!IsChar(';'))
1092 Exp(var);
1093 if(Id("in") || Char(':')) {
1094 EscValue range = GetExp();
1095 PassChar(')');
1096 Pos stmt = GetPos();
1097 int i = 0;
1098 for(;;) {
1099 SetPos(stmt);
1100 if(range.IsArray()) {
1101 if(i >= range.GetCount())
1102 break;
1103 Assign(var, (int64)i);
1104 }
1105 else
1106 if(range.IsMap()) {
1107 const VectorMap<EscValue, EscValue>& map = range.GetMap();
1108 if(i >= map.GetCount())
1109 break;
1110 if(map.IsUnlinked(i)) {
1111 i++;
1112 continue;
1113 }
1114 Assign(var, map.GetKey(i));
1115 }
1116 if(!no_break || !no_return || !no_continue) {
1117 SkipStatement();
1118 break;
1119 }
1120 DoStatement();
1121 no_continue = true;
1122 i++;
1123 }
1124 SkipStatement();
1125 }
1126 else {
1127 PassChar(';');
1128 Pos cond;
1129 if(!IsChar(';')) {
1130 cond = GetPos();
1131 SkipExp();
1132 }
1133 PassChar(';');
1134 Pos after;
1135 if(!IsChar(')')) {
1136 after = GetPos();
1137 SkipExp();
1138 }
1139 PassChar(')');
1140 Pos stmt = GetPos();
1141 for(;;) {
1142 bool c = true;
1143 if(cond.ptr) {
1144 SetPos(cond);
1145 c = IsTrue(GetExp());
1146 }
1147 SetPos(stmt);
1148 if(!c || !no_break || !no_return || !no_continue) {
1149 SkipStatement();
1150 break;
1151 }
1152 DoStatement();
1153 no_continue = true;
1154 if(after.ptr) {
1155 SetPos(after);
1156 SRVal r;
1157 Exp(r);
1158 }
1159 }
1160 }
1161 no_break = true;
1162 loop--;
1163 }
1164 else
1165 if(Id("break")) {
1166 if(!loop)
1167 ThrowError("misplaced 'break'");
1168 no_break = false;
1169 PassChar(';');
1170 }
1171 else
1172 if(Id("continue")) {
1173 if(!loop)
1174 ThrowError("misplaced 'continue'");
1175 no_continue = false;
1176 PassChar(';');
1177 }
1178 else
1179 if(Id("case"))
1180 ThrowError("misplaced 'case'");
1181 else
1182 if(Id("default"))
1183 ThrowError("misplaced 'default'");
1184 else
1185 if(Id("else"))
1186 ThrowError("misplaced 'else'");
1187 else
1188 if(Id("return")) {
1189 no_return = false;
1190 if(!Char(';')) {
1191 return_value = GetExp();
1192 PassChar(';');
1193 }
1194 else
1195 return_value = EscValue();
1196 }
1197 else
1198 if(Id("switch")) {
1199 loop++;
1200 PassChar('(');
1201 EscValue a = GetExp();
1202 PassChar(')');
1203 PassChar('{');
1204 while(!Char('}')) {
1205 if(Id("case")) {
1206 EscValue b = GetExp();
1207 PassChar(':');
1208 if(a == b) {
1209 FinishSwitch();
1210 break;
1211 }
1212 }
1213 else
1214 if(Id("default")) {
1215 PassChar(':');
1216 FinishSwitch();
1217 break;
1218 }
1219 else
1220 SkipStatement();
1221 }
1222 loop--;
1223 no_break = true;
1224 }
1225 else
1226 if(Char('#')) {
1227 int type = 0;
1228 if(Char('.'))
1229 type = 1;
1230 else
1231 if(Char(':'))
1232 type = 2;
1233 String id = ReadId();
1234 EscValue l = ReadLambda(*this);
1235 if(type == 1) {
1236 if(self.IsVoid())
1237 ThrowError("no instance");
1238 self.MapSet(id, l);
1239 }
1240 else
1241 if(type == 2)
1242 global.GetAdd(id) = l;
1243 else
1244 var.GetAdd(id) = l;
1245 }
1246 else
1247 if(Char('{')) {
1248 while(!Char('}') && no_break && no_return && no_continue)
1249 DoStatement();
1250 }
1251 else
1252 if(!Char(';')) {
1253 SRVal v;
1254 Exp(v);
1255 PassChar(';');
1256 }
1257 }
1258
Run()1259 void Esc::Run()
1260 {
1261 no_return = no_break = no_continue = true;
1262 loop = 0;
1263 skipexp = 0;
1264 while(!IsEof() && no_return && no_break && no_continue)
1265 DoStatement();
1266 }
1267
1268 }
1269