TinyJS on mbed. TinyJS is very simple JavaScript engine.
TinyJS on mbed
what's this ?
TinyJS is an extremely simple (under than 2000 lines) JavaScript interpreter engine.
I ported on mbed. but it restrict any features.
TinyJS project is https://github.com/gfwilliams/tiny-js
TinyJSは2000行以下で書かれた非常に小さいJavaScriptインタプリタエンジンです。
これをmbedに移植してみました。(ただし、いろいろ制限があります)
本家はこちら。 https://github.com/gfwilliams/tiny-js
how to use
You must use on serial terminal application by mbed serial USB.
baud is 57600bps
USBシリアルとして、ターミナルソフトを接続するとコンソールが表示されます。
ボーレートは57600bpsになってます。
functions
functions for mbed.
mbed用関数
- mbed.DigitalIn(pinName, mode)
- mbed.DigitalOut(pinName, val)
- mbed.AnalogIn(pinName)
- mbed.AnalogOut(pinName, val)
- mbed.InterruptIn(pinName, edge, mode, callback)
- mbed.TimerStart()
- mbed.TimerStop()
- mbed.TimerReset()
- mbed.TimerRead()
- mbed.Timeout(callback, t)
- mbed.wait(s)
- mbed.memfree()
sample JavaScript codes
DigitalOut
mbed.DigitalOut('LED1', 1); mbed.DigitalOut('LED2', 0); mbed.DigitalOut('LED3', 1); mbed.DigitalOut('LED4', 0);
LED1 = On, LED2=Off, LED3=On, ED4=Off
LED1 = 点灯、LED2=消灯、LED3=点灯、LED4=消灯
DigitalIn
print(mbed.DigitalIn('p5', 'PullUp'));
p5 is pull up, read, and print on console.
p5をPullUpして読みプリントする。
AnalogOut
mbed.AnalogOut('p18', 0.8);
p18 is analog output, value is 0.8.
p18を 値0.8でアナログ出力する。
AnalogIn
print(mbed.AnalogIn('p20'));
p20 is read analog voltage, and print on console.
p20をアナログ入力しプリントする。
InterruptIn
var led1 = 0; mbed.InterruptIn('p5', 'fall', 'PullUp', function() {led1 = !led1; mbed.DigitalOut('LED1', led1);});
Interrupt on p5, and ON/OFF does LED1.
p5で割り込んでLED1をON/OFFする。
Timeout and wait sample code
mbed.Timeout(function() {mbed.DigitalOut('LED1', 1);mbed.wait(3);mbed.DigitalOut('LED1', 0);}, 4);
LED1=on when wait for 4 seconds. and LED1=off for 3 seconds later.
LED1を4秒待って点灯して3秒後に消灯する。
memfree
print(mbed.memfree());
This prints the number of bytes of the remainder memory on mbed where TinyJS is usable.
これはTinyJSが使えるmbed上での残りメモリのバイト数をプリントアウトする。
LED Blinker by Timeout
blinker = function() {var led = 0; mbed.Timeout(function() {led = !led; mbed.DigitalOut('LED1', led);blinker();}, 0.5);}; blinker();
LED Blinker by Timeout.
Timeoutを使ったLチカ。
restrictions
- There is very little available memory. (Less than 9kbytes on LPC1768)
- Registration of InterruptIn is 4 limit.
- The loop to 8,192 times.
- The built-in functions (general JavaScript functions) that TinyJS prepares for for securing of memory is not included.
more, more, more ....
制限事項
- 利用できるメモリは非常に少ない。(LPC1768で9kbytes以下)
- InterruptInで登録できる割り込みは4つまで。4つを超えると1つめから順番に削除される。
- ループは8192回まで。
- メモリ確保のためTinyJSが用意している組み込み関数(一般的なJavaScript関数)は含まれない。
他、多数....
sample movies
http://www.youtube.com/watch?v=ARp0DK70JGM
http://www.youtube.com/watch?v=UOZQ4eEC4xA
TinyJS.cpp@8:819934a27c2d, 2014-01-20 (annotated)
- Committer:
- ohneta
- Date:
- Mon Jan 20 00:07:35 2014 +0000
- Revision:
- 8:819934a27c2d
- Parent:
- 0:aae260bdcdd9
update InterruptIn, Timer, Timeout functons
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ohneta | 0:aae260bdcdd9 | 1 | /* |
ohneta | 0:aae260bdcdd9 | 2 | * TinyJS |
ohneta | 0:aae260bdcdd9 | 3 | * |
ohneta | 0:aae260bdcdd9 | 4 | * A single-file Javascript-alike engine |
ohneta | 0:aae260bdcdd9 | 5 | * |
ohneta | 0:aae260bdcdd9 | 6 | * Authored By Gordon Williams <gw@pur3.co.uk> |
ohneta | 0:aae260bdcdd9 | 7 | * |
ohneta | 0:aae260bdcdd9 | 8 | * Copyright (C) 2009 Pur3 Ltd |
ohneta | 0:aae260bdcdd9 | 9 | * |
ohneta | 0:aae260bdcdd9 | 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy of |
ohneta | 0:aae260bdcdd9 | 11 | * this software and associated documentation files (the "Software"), to deal in |
ohneta | 0:aae260bdcdd9 | 12 | * the Software without restriction, including without limitation the rights to |
ohneta | 0:aae260bdcdd9 | 13 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
ohneta | 0:aae260bdcdd9 | 14 | * of the Software, and to permit persons to whom the Software is furnished to do |
ohneta | 0:aae260bdcdd9 | 15 | * so, subject to the following conditions: |
ohneta | 0:aae260bdcdd9 | 16 | |
ohneta | 0:aae260bdcdd9 | 17 | * The above copyright notice and this permission notice shall be included in all |
ohneta | 0:aae260bdcdd9 | 18 | * copies or substantial portions of the Software. |
ohneta | 0:aae260bdcdd9 | 19 | |
ohneta | 0:aae260bdcdd9 | 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
ohneta | 0:aae260bdcdd9 | 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
ohneta | 0:aae260bdcdd9 | 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
ohneta | 0:aae260bdcdd9 | 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
ohneta | 0:aae260bdcdd9 | 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
ohneta | 0:aae260bdcdd9 | 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
ohneta | 0:aae260bdcdd9 | 26 | * SOFTWARE. |
ohneta | 0:aae260bdcdd9 | 27 | */ |
ohneta | 0:aae260bdcdd9 | 28 | |
ohneta | 0:aae260bdcdd9 | 29 | /* Version 0.1 : (gw) First published on Google Code |
ohneta | 0:aae260bdcdd9 | 30 | Version 0.11 : Making sure the 'root' variable never changes |
ohneta | 0:aae260bdcdd9 | 31 | 'symbol_base' added for the current base of the sybmbol table |
ohneta | 0:aae260bdcdd9 | 32 | Version 0.12 : Added findChildOrCreate, changed string passing to use references |
ohneta | 0:aae260bdcdd9 | 33 | Fixed broken string encoding in getJSString() |
ohneta | 0:aae260bdcdd9 | 34 | Removed getInitCode and added getJSON instead |
ohneta | 0:aae260bdcdd9 | 35 | Added nil |
ohneta | 0:aae260bdcdd9 | 36 | Added rough JSON parsing |
ohneta | 0:aae260bdcdd9 | 37 | Improved example app |
ohneta | 0:aae260bdcdd9 | 38 | Version 0.13 : Added tokenEnd/tokenLastEnd to lexer to avoid parsing whitespace |
ohneta | 0:aae260bdcdd9 | 39 | Ability to define functions without names |
ohneta | 0:aae260bdcdd9 | 40 | Can now do "var mine = function(a,b) { ... };" |
ohneta | 0:aae260bdcdd9 | 41 | Slightly better 'trace' function |
ohneta | 0:aae260bdcdd9 | 42 | Added findChildOrCreateByPath function |
ohneta | 0:aae260bdcdd9 | 43 | Added simple test suite |
ohneta | 0:aae260bdcdd9 | 44 | Added skipping of blocks when not executing |
ohneta | 0:aae260bdcdd9 | 45 | Version 0.14 : Added parsing of more number types |
ohneta | 0:aae260bdcdd9 | 46 | Added parsing of string defined with ' |
ohneta | 0:aae260bdcdd9 | 47 | Changed nil to null as per spec, added 'undefined' |
ohneta | 0:aae260bdcdd9 | 48 | Now set variables with the correct scope, and treat unknown |
ohneta | 0:aae260bdcdd9 | 49 | as 'undefined' rather than failing |
ohneta | 0:aae260bdcdd9 | 50 | Added proper (I hope) handling of null and undefined |
ohneta | 0:aae260bdcdd9 | 51 | Added === check |
ohneta | 0:aae260bdcdd9 | 52 | Version 0.15 : Fix for possible memory leaks |
ohneta | 0:aae260bdcdd9 | 53 | Version 0.16 : Removal of un-needed findRecursive calls |
ohneta | 0:aae260bdcdd9 | 54 | symbol_base removed and replaced with 'scopes' stack |
ohneta | 0:aae260bdcdd9 | 55 | Added reference counting a proper tree structure |
ohneta | 0:aae260bdcdd9 | 56 | (Allowing pass by reference) |
ohneta | 0:aae260bdcdd9 | 57 | Allowed JSON output to output IDs, not strings |
ohneta | 0:aae260bdcdd9 | 58 | Added get/set for array indices |
ohneta | 0:aae260bdcdd9 | 59 | Changed Callbacks to include user data pointer |
ohneta | 0:aae260bdcdd9 | 60 | Added some support for objects |
ohneta | 0:aae260bdcdd9 | 61 | Added more Java-esque builtin functions |
ohneta | 0:aae260bdcdd9 | 62 | Version 0.17 : Now we don't deepCopy the parent object of the class |
ohneta | 0:aae260bdcdd9 | 63 | Added JSON.stringify and eval() |
ohneta | 0:aae260bdcdd9 | 64 | Nicer JSON indenting |
ohneta | 0:aae260bdcdd9 | 65 | Fixed function output in JSON |
ohneta | 0:aae260bdcdd9 | 66 | Added evaluateComplex |
ohneta | 0:aae260bdcdd9 | 67 | Fixed some reentrancy issues with evaluate/execute |
ohneta | 0:aae260bdcdd9 | 68 | Version 0.18 : Fixed some issues with code being executed when it shouldn't |
ohneta | 0:aae260bdcdd9 | 69 | Version 0.19 : Added array.length |
ohneta | 0:aae260bdcdd9 | 70 | Changed '__parent' to 'prototype' to bring it more in line with javascript |
ohneta | 0:aae260bdcdd9 | 71 | Version 0.20 : Added '%' operator |
ohneta | 0:aae260bdcdd9 | 72 | Version 0.21 : Added array type |
ohneta | 0:aae260bdcdd9 | 73 | String.length() no more - now String.length |
ohneta | 0:aae260bdcdd9 | 74 | Added extra constructors to reduce confusion |
ohneta | 0:aae260bdcdd9 | 75 | Fixed checks against undefined |
ohneta | 0:aae260bdcdd9 | 76 | Version 0.22 : First part of ardi's changes: |
ohneta | 0:aae260bdcdd9 | 77 | sprintf -> sprintf_s |
ohneta | 0:aae260bdcdd9 | 78 | extra tokens parsed |
ohneta | 0:aae260bdcdd9 | 79 | array memory leak fixed |
ohneta | 0:aae260bdcdd9 | 80 | Fixed memory leak in evaluateComplex |
ohneta | 0:aae260bdcdd9 | 81 | Fixed memory leak in FOR loops |
ohneta | 0:aae260bdcdd9 | 82 | Fixed memory leak for unary minus |
ohneta | 0:aae260bdcdd9 | 83 | Version 0.23 : Allowed evaluate[Complex] to take in semi-colon separated |
ohneta | 0:aae260bdcdd9 | 84 | statements and then only return the value from the last one. |
ohneta | 0:aae260bdcdd9 | 85 | Also checks to make sure *everything* was parsed. |
ohneta | 0:aae260bdcdd9 | 86 | Ints + doubles are now stored in binary form (faster + more precise) |
ohneta | 0:aae260bdcdd9 | 87 | Version 0.24 : More useful error for maths ops |
ohneta | 0:aae260bdcdd9 | 88 | Don't dump everything on a match error. |
ohneta | 0:aae260bdcdd9 | 89 | Version 0.25 : Better string escaping |
ohneta | 0:aae260bdcdd9 | 90 | Version 0.26 : Add CScriptVar::equals |
ohneta | 0:aae260bdcdd9 | 91 | Add built-in array functions |
ohneta | 0:aae260bdcdd9 | 92 | Version 0.27 : Added OZLB's TinyJS.setVariable (with some tweaks) |
ohneta | 0:aae260bdcdd9 | 93 | Added OZLB's Maths Functions |
ohneta | 0:aae260bdcdd9 | 94 | Version 0.28 : Ternary operator |
ohneta | 0:aae260bdcdd9 | 95 | Rudimentary call stack on error |
ohneta | 0:aae260bdcdd9 | 96 | Added String Character functions |
ohneta | 0:aae260bdcdd9 | 97 | Added shift operators |
ohneta | 0:aae260bdcdd9 | 98 | Version 0.29 : Added new object via functions |
ohneta | 0:aae260bdcdd9 | 99 | Fixed getString() for double on some platforms |
ohneta | 0:aae260bdcdd9 | 100 | Version 0.30 : Rlyeh Mario's patch for Math Functions on VC++ |
ohneta | 0:aae260bdcdd9 | 101 | Version 0.31 : Add exec() to TinyJS functions |
ohneta | 0:aae260bdcdd9 | 102 | Now print quoted JSON that can be read by PHP/Python parsers |
ohneta | 0:aae260bdcdd9 | 103 | Fixed postfix increment operator |
ohneta | 0:aae260bdcdd9 | 104 | Version 0.32 : Fixed Math.randInt on 32 bit PCs, where it was broken |
ohneta | 0:aae260bdcdd9 | 105 | Version 0.33 : Fixed Memory leak + brokenness on === comparison |
ohneta | 0:aae260bdcdd9 | 106 | |
ohneta | 0:aae260bdcdd9 | 107 | NOTE: |
ohneta | 0:aae260bdcdd9 | 108 | Constructing an array with an initial length 'Array(5)' doesn't work |
ohneta | 0:aae260bdcdd9 | 109 | Recursive loops of data such as a.foo = a; fail to be garbage collected |
ohneta | 0:aae260bdcdd9 | 110 | length variable cannot be set |
ohneta | 0:aae260bdcdd9 | 111 | The postfix increment operator returns the current value, not the previous as it should. |
ohneta | 0:aae260bdcdd9 | 112 | There is no prefix increment operator |
ohneta | 0:aae260bdcdd9 | 113 | Arrays are implemented as a linked list - hence a lookup time is O(n) |
ohneta | 0:aae260bdcdd9 | 114 | |
ohneta | 0:aae260bdcdd9 | 115 | TODO: |
ohneta | 0:aae260bdcdd9 | 116 | Utility va-args style function in TinyJS for executing a function directly |
ohneta | 0:aae260bdcdd9 | 117 | Merge the parsing of expressions/statements so eval("statement") works like we'd expect. |
ohneta | 0:aae260bdcdd9 | 118 | Move 'shift' implementation into mathsOp |
ohneta | 0:aae260bdcdd9 | 119 | |
ohneta | 0:aae260bdcdd9 | 120 | */ |
ohneta | 0:aae260bdcdd9 | 121 | /* |
ohneta | 0:aae260bdcdd9 | 122 | * TinyJS for mbed. |
ohneta | 0:aae260bdcdd9 | 123 | * |
ohneta | 0:aae260bdcdd9 | 124 | * Authored by Takehisa Oneta (ohneta@gmail.com) |
ohneta | 0:aae260bdcdd9 | 125 | * 10th Jan. 2013 |
ohneta | 0:aae260bdcdd9 | 126 | */ |
ohneta | 0:aae260bdcdd9 | 127 | |
ohneta | 0:aae260bdcdd9 | 128 | #include "TinyJS.h" |
ohneta | 0:aae260bdcdd9 | 129 | #include <assert.h> |
ohneta | 0:aae260bdcdd9 | 130 | |
ohneta | 0:aae260bdcdd9 | 131 | #define ASSERT(X) assert(X) |
ohneta | 0:aae260bdcdd9 | 132 | /* Frees the given link IF it isn't owned by anything else */ |
ohneta | 0:aae260bdcdd9 | 133 | #define CLEAN(x) { CScriptVarLink *__v = x; if (__v && !__v->owned) { delete __v; } } |
ohneta | 0:aae260bdcdd9 | 134 | /* Create a LINK to point to VAR and free the old link. |
ohneta | 0:aae260bdcdd9 | 135 | * BUT this is more clever - it tries to keep the old link if it's not owned to save allocations */ |
ohneta | 0:aae260bdcdd9 | 136 | #define CREATE_LINK(LINK, VAR) { if (!LINK || LINK->owned) LINK = new CScriptVarLink(VAR); else LINK->replaceWith(VAR); } |
ohneta | 0:aae260bdcdd9 | 137 | |
ohneta | 0:aae260bdcdd9 | 138 | #include <string> |
ohneta | 0:aae260bdcdd9 | 139 | #include <string.h> |
ohneta | 0:aae260bdcdd9 | 140 | #include <sstream> |
ohneta | 0:aae260bdcdd9 | 141 | #include <cstdlib> |
ohneta | 0:aae260bdcdd9 | 142 | #include <stdio.h> |
ohneta | 0:aae260bdcdd9 | 143 | |
ohneta | 0:aae260bdcdd9 | 144 | using namespace std; |
ohneta | 0:aae260bdcdd9 | 145 | |
ohneta | 0:aae260bdcdd9 | 146 | #ifdef _WIN32 |
ohneta | 0:aae260bdcdd9 | 147 | #ifdef _DEBUG |
ohneta | 0:aae260bdcdd9 | 148 | #ifndef DBG_NEW |
ohneta | 0:aae260bdcdd9 | 149 | #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ ) |
ohneta | 0:aae260bdcdd9 | 150 | #define new DBG_NEW |
ohneta | 0:aae260bdcdd9 | 151 | #endif |
ohneta | 0:aae260bdcdd9 | 152 | #endif |
ohneta | 0:aae260bdcdd9 | 153 | #endif |
ohneta | 0:aae260bdcdd9 | 154 | |
ohneta | 0:aae260bdcdd9 | 155 | #ifdef __GNUC__ |
ohneta | 0:aae260bdcdd9 | 156 | #define vsprintf_s vsnprintf |
ohneta | 0:aae260bdcdd9 | 157 | #define sprintf_s snprintf |
ohneta | 0:aae260bdcdd9 | 158 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 159 | #define _strdup strdup |
ohneta | 0:aae260bdcdd9 | 160 | #else |
ohneta | 0:aae260bdcdd9 | 161 | char *_strdup(const char *str) |
ohneta | 0:aae260bdcdd9 | 162 | { |
ohneta | 0:aae260bdcdd9 | 163 | size_t siz; |
ohneta | 0:aae260bdcdd9 | 164 | char *copy; |
ohneta | 0:aae260bdcdd9 | 165 | |
ohneta | 0:aae260bdcdd9 | 166 | siz = strlen(str) + 1; |
ohneta | 0:aae260bdcdd9 | 167 | if ((copy = (char *)malloc(siz)) == NULL) |
ohneta | 0:aae260bdcdd9 | 168 | return(NULL); |
ohneta | 0:aae260bdcdd9 | 169 | (void)memcpy(copy, str, siz); |
ohneta | 0:aae260bdcdd9 | 170 | return(copy); |
ohneta | 0:aae260bdcdd9 | 171 | } |
ohneta | 0:aae260bdcdd9 | 172 | #endif |
ohneta | 0:aae260bdcdd9 | 173 | #endif |
ohneta | 0:aae260bdcdd9 | 174 | |
ohneta | 0:aae260bdcdd9 | 175 | #ifdef MBED |
ohneta | 0:aae260bdcdd9 | 176 | extern int mbedErrorFlag; |
ohneta | 0:aae260bdcdd9 | 177 | extern std::string mbedErrorMessage; |
ohneta | 0:aae260bdcdd9 | 178 | |
ohneta | 0:aae260bdcdd9 | 179 | #define LMATCH_VOID(c) {mbedErrorFlag = 0;l->match(c);if (mbedErrorFlag != 0) return;} |
ohneta | 0:aae260bdcdd9 | 180 | #define LMATCH(c) {mbedErrorFlag = 0;l->match(c);if (mbedErrorFlag != 0) return 0;} |
ohneta | 0:aae260bdcdd9 | 181 | //#define LMATCH_VOID(c) {l->match(c);} |
ohneta | 0:aae260bdcdd9 | 182 | //#define LMATCH(c) {l->match(c);} |
ohneta | 0:aae260bdcdd9 | 183 | #endif |
ohneta | 0:aae260bdcdd9 | 184 | |
ohneta | 0:aae260bdcdd9 | 185 | |
ohneta | 0:aae260bdcdd9 | 186 | // ----------------------------------------------------------------------------------- Memory Debug |
ohneta | 0:aae260bdcdd9 | 187 | |
ohneta | 0:aae260bdcdd9 | 188 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 189 | |
ohneta | 0:aae260bdcdd9 | 190 | vector<CScriptVar*> allocatedVars; |
ohneta | 0:aae260bdcdd9 | 191 | vector<CScriptVarLink*> allocatedLinks; |
ohneta | 0:aae260bdcdd9 | 192 | |
ohneta | 0:aae260bdcdd9 | 193 | void mark_allocated(CScriptVar *v) { |
ohneta | 0:aae260bdcdd9 | 194 | allocatedVars.push_back(v); |
ohneta | 0:aae260bdcdd9 | 195 | } |
ohneta | 0:aae260bdcdd9 | 196 | |
ohneta | 0:aae260bdcdd9 | 197 | void mark_deallocated(CScriptVar *v) { |
ohneta | 0:aae260bdcdd9 | 198 | for (size_t i=0;i<allocatedVars.size();i++) { |
ohneta | 0:aae260bdcdd9 | 199 | if (allocatedVars[i] == v) { |
ohneta | 0:aae260bdcdd9 | 200 | allocatedVars.erase(allocatedVars.begin()+i); |
ohneta | 0:aae260bdcdd9 | 201 | break; |
ohneta | 0:aae260bdcdd9 | 202 | } |
ohneta | 0:aae260bdcdd9 | 203 | } |
ohneta | 0:aae260bdcdd9 | 204 | } |
ohneta | 0:aae260bdcdd9 | 205 | |
ohneta | 0:aae260bdcdd9 | 206 | void mark_allocated(CScriptVarLink *v) { |
ohneta | 0:aae260bdcdd9 | 207 | allocatedLinks.push_back(v); |
ohneta | 0:aae260bdcdd9 | 208 | } |
ohneta | 0:aae260bdcdd9 | 209 | |
ohneta | 0:aae260bdcdd9 | 210 | void mark_deallocated(CScriptVarLink *v) { |
ohneta | 0:aae260bdcdd9 | 211 | for (size_t i=0;i<allocatedLinks.size();i++) { |
ohneta | 0:aae260bdcdd9 | 212 | if (allocatedLinks[i] == v) { |
ohneta | 0:aae260bdcdd9 | 213 | allocatedLinks.erase(allocatedLinks.begin()+i); |
ohneta | 0:aae260bdcdd9 | 214 | break; |
ohneta | 0:aae260bdcdd9 | 215 | } |
ohneta | 0:aae260bdcdd9 | 216 | } |
ohneta | 0:aae260bdcdd9 | 217 | } |
ohneta | 0:aae260bdcdd9 | 218 | |
ohneta | 0:aae260bdcdd9 | 219 | void show_allocated() { |
ohneta | 0:aae260bdcdd9 | 220 | for (size_t i=0;i<allocatedVars.size();i++) { |
ohneta | 0:aae260bdcdd9 | 221 | printf("ALLOCATED, %d refs\n", allocatedVars[i]->getRefs()); |
ohneta | 0:aae260bdcdd9 | 222 | allocatedVars[i]->trace(" "); |
ohneta | 0:aae260bdcdd9 | 223 | } |
ohneta | 0:aae260bdcdd9 | 224 | for (size_t i=0;i<allocatedLinks.size();i++) { |
ohneta | 0:aae260bdcdd9 | 225 | printf("ALLOCATED LINK %s, allocated[%d] to \n", allocatedLinks[i]->name.c_str(), allocatedLinks[i]->var->getRefs()); |
ohneta | 0:aae260bdcdd9 | 226 | allocatedLinks[i]->var->trace(" "); |
ohneta | 0:aae260bdcdd9 | 227 | } |
ohneta | 0:aae260bdcdd9 | 228 | allocatedVars.clear(); |
ohneta | 0:aae260bdcdd9 | 229 | allocatedLinks.clear(); |
ohneta | 0:aae260bdcdd9 | 230 | } |
ohneta | 0:aae260bdcdd9 | 231 | #endif |
ohneta | 0:aae260bdcdd9 | 232 | |
ohneta | 0:aae260bdcdd9 | 233 | // ----------------------------------------------------------------------------------- Utils |
ohneta | 0:aae260bdcdd9 | 234 | bool isWhitespace(char ch) { |
ohneta | 0:aae260bdcdd9 | 235 | return (ch==' ') || (ch=='\t') || (ch=='\n') || (ch=='\r'); |
ohneta | 0:aae260bdcdd9 | 236 | } |
ohneta | 0:aae260bdcdd9 | 237 | |
ohneta | 0:aae260bdcdd9 | 238 | bool isNumeric(char ch) { |
ohneta | 0:aae260bdcdd9 | 239 | return (ch>='0') && (ch<='9'); |
ohneta | 0:aae260bdcdd9 | 240 | } |
ohneta | 0:aae260bdcdd9 | 241 | bool isNumber(const string &str) { |
ohneta | 0:aae260bdcdd9 | 242 | for (size_t i=0;i<str.size();i++) |
ohneta | 0:aae260bdcdd9 | 243 | if (!isNumeric(str[i])) return false; |
ohneta | 0:aae260bdcdd9 | 244 | return true; |
ohneta | 0:aae260bdcdd9 | 245 | } |
ohneta | 0:aae260bdcdd9 | 246 | bool isHexadecimal(char ch) { |
ohneta | 0:aae260bdcdd9 | 247 | return ((ch>='0') && (ch<='9')) || |
ohneta | 0:aae260bdcdd9 | 248 | ((ch>='a') && (ch<='f')) || |
ohneta | 0:aae260bdcdd9 | 249 | ((ch>='A') && (ch<='F')); |
ohneta | 0:aae260bdcdd9 | 250 | } |
ohneta | 0:aae260bdcdd9 | 251 | bool isAlpha(char ch) { |
ohneta | 0:aae260bdcdd9 | 252 | return ((ch>='a') && (ch<='z')) || ((ch>='A') && (ch<='Z')) || ch=='_'; |
ohneta | 0:aae260bdcdd9 | 253 | } |
ohneta | 0:aae260bdcdd9 | 254 | |
ohneta | 0:aae260bdcdd9 | 255 | bool isIDString(const char *s) { |
ohneta | 0:aae260bdcdd9 | 256 | if (!isAlpha(*s)) |
ohneta | 0:aae260bdcdd9 | 257 | return false; |
ohneta | 0:aae260bdcdd9 | 258 | while (*s) { |
ohneta | 0:aae260bdcdd9 | 259 | if (!(isAlpha(*s) || isNumeric(*s))) |
ohneta | 0:aae260bdcdd9 | 260 | return false; |
ohneta | 0:aae260bdcdd9 | 261 | s++; |
ohneta | 0:aae260bdcdd9 | 262 | } |
ohneta | 0:aae260bdcdd9 | 263 | return true; |
ohneta | 0:aae260bdcdd9 | 264 | } |
ohneta | 0:aae260bdcdd9 | 265 | |
ohneta | 0:aae260bdcdd9 | 266 | void replace(string &str, char textFrom, const char *textTo) { |
ohneta | 0:aae260bdcdd9 | 267 | int sLen = strlen(textTo); |
ohneta | 0:aae260bdcdd9 | 268 | size_t p = str.find(textFrom); |
ohneta | 0:aae260bdcdd9 | 269 | while (p != string::npos) { |
ohneta | 0:aae260bdcdd9 | 270 | str = str.substr(0, p) + textTo + str.substr(p+1); |
ohneta | 0:aae260bdcdd9 | 271 | p = str.find(textFrom, p+sLen); |
ohneta | 0:aae260bdcdd9 | 272 | } |
ohneta | 0:aae260bdcdd9 | 273 | } |
ohneta | 0:aae260bdcdd9 | 274 | |
ohneta | 0:aae260bdcdd9 | 275 | /// convert the given string into a quoted string suitable for javascript |
ohneta | 0:aae260bdcdd9 | 276 | std::string getJSString(const std::string &str) { |
ohneta | 0:aae260bdcdd9 | 277 | std::string nStr = str; |
ohneta | 0:aae260bdcdd9 | 278 | for (size_t i=0;i<nStr.size();i++) { |
ohneta | 0:aae260bdcdd9 | 279 | const char *replaceWith = ""; |
ohneta | 0:aae260bdcdd9 | 280 | bool replace = true; |
ohneta | 0:aae260bdcdd9 | 281 | |
ohneta | 0:aae260bdcdd9 | 282 | switch (nStr[i]) { |
ohneta | 0:aae260bdcdd9 | 283 | case '\\': replaceWith = "\\\\"; break; |
ohneta | 0:aae260bdcdd9 | 284 | case '\n': replaceWith = "\\n"; break; |
ohneta | 0:aae260bdcdd9 | 285 | case '\r': replaceWith = "\\r"; break; |
ohneta | 0:aae260bdcdd9 | 286 | case '\a': replaceWith = "\\a"; break; |
ohneta | 0:aae260bdcdd9 | 287 | case '"': replaceWith = "\\\""; break; |
ohneta | 0:aae260bdcdd9 | 288 | default: { |
ohneta | 0:aae260bdcdd9 | 289 | int nCh = ((int)nStr[i]) &0xFF; |
ohneta | 0:aae260bdcdd9 | 290 | if (nCh<32 || nCh>127) { |
ohneta | 0:aae260bdcdd9 | 291 | char buffer[5]; |
ohneta | 0:aae260bdcdd9 | 292 | sprintf_s(buffer, 5, "\\x%02X", nCh); |
ohneta | 0:aae260bdcdd9 | 293 | replaceWith = buffer; |
ohneta | 0:aae260bdcdd9 | 294 | } else replace=false; |
ohneta | 0:aae260bdcdd9 | 295 | } |
ohneta | 0:aae260bdcdd9 | 296 | } |
ohneta | 0:aae260bdcdd9 | 297 | |
ohneta | 0:aae260bdcdd9 | 298 | if (replace) { |
ohneta | 0:aae260bdcdd9 | 299 | nStr = nStr.substr(0, i) + replaceWith + nStr.substr(i+1); |
ohneta | 0:aae260bdcdd9 | 300 | i += strlen(replaceWith)-1; |
ohneta | 0:aae260bdcdd9 | 301 | } |
ohneta | 0:aae260bdcdd9 | 302 | } |
ohneta | 0:aae260bdcdd9 | 303 | return "\"" + nStr + "\""; |
ohneta | 0:aae260bdcdd9 | 304 | } |
ohneta | 0:aae260bdcdd9 | 305 | |
ohneta | 0:aae260bdcdd9 | 306 | /** Is the string alphanumeric */ |
ohneta | 0:aae260bdcdd9 | 307 | bool isAlphaNum(const std::string &str) { |
ohneta | 0:aae260bdcdd9 | 308 | if (str.size()==0) return true; |
ohneta | 0:aae260bdcdd9 | 309 | if (!isAlpha(str[0])) return false; |
ohneta | 0:aae260bdcdd9 | 310 | for (size_t i=0;i<str.size();i++) |
ohneta | 0:aae260bdcdd9 | 311 | if (!(isAlpha(str[i]) || isNumeric(str[i]))) |
ohneta | 0:aae260bdcdd9 | 312 | return false; |
ohneta | 0:aae260bdcdd9 | 313 | return true; |
ohneta | 0:aae260bdcdd9 | 314 | } |
ohneta | 0:aae260bdcdd9 | 315 | |
ohneta | 0:aae260bdcdd9 | 316 | // ----------------------------------------------------------------------------------- CSCRIPTEXCEPTION |
ohneta | 0:aae260bdcdd9 | 317 | |
ohneta | 0:aae260bdcdd9 | 318 | CScriptException::CScriptException(const string &exceptionText) { |
ohneta | 0:aae260bdcdd9 | 319 | text = exceptionText; |
ohneta | 0:aae260bdcdd9 | 320 | } |
ohneta | 0:aae260bdcdd9 | 321 | |
ohneta | 0:aae260bdcdd9 | 322 | // ----------------------------------------------------------------------------------- CSCRIPTLEX |
ohneta | 0:aae260bdcdd9 | 323 | |
ohneta | 0:aae260bdcdd9 | 324 | CScriptLex::CScriptLex(const string &input) { |
ohneta | 0:aae260bdcdd9 | 325 | data = _strdup(input.c_str()); |
ohneta | 0:aae260bdcdd9 | 326 | dataOwned = true; |
ohneta | 0:aae260bdcdd9 | 327 | dataStart = 0; |
ohneta | 0:aae260bdcdd9 | 328 | dataEnd = strlen(data); |
ohneta | 0:aae260bdcdd9 | 329 | reset(); |
ohneta | 0:aae260bdcdd9 | 330 | } |
ohneta | 0:aae260bdcdd9 | 331 | |
ohneta | 0:aae260bdcdd9 | 332 | CScriptLex::CScriptLex(CScriptLex *owner, int startChar, int endChar) { |
ohneta | 0:aae260bdcdd9 | 333 | data = owner->data; |
ohneta | 0:aae260bdcdd9 | 334 | dataOwned = false; |
ohneta | 0:aae260bdcdd9 | 335 | dataStart = startChar; |
ohneta | 0:aae260bdcdd9 | 336 | dataEnd = endChar; |
ohneta | 0:aae260bdcdd9 | 337 | reset(); |
ohneta | 0:aae260bdcdd9 | 338 | } |
ohneta | 0:aae260bdcdd9 | 339 | |
ohneta | 0:aae260bdcdd9 | 340 | CScriptLex::~CScriptLex(void) |
ohneta | 0:aae260bdcdd9 | 341 | { |
ohneta | 0:aae260bdcdd9 | 342 | if (dataOwned) |
ohneta | 0:aae260bdcdd9 | 343 | free((void*)data); |
ohneta | 0:aae260bdcdd9 | 344 | } |
ohneta | 0:aae260bdcdd9 | 345 | |
ohneta | 0:aae260bdcdd9 | 346 | void CScriptLex::reset() { |
ohneta | 0:aae260bdcdd9 | 347 | dataPos = dataStart; |
ohneta | 0:aae260bdcdd9 | 348 | tokenStart = 0; |
ohneta | 0:aae260bdcdd9 | 349 | tokenEnd = 0; |
ohneta | 0:aae260bdcdd9 | 350 | tokenLastEnd = 0; |
ohneta | 0:aae260bdcdd9 | 351 | tk = 0; |
ohneta | 0:aae260bdcdd9 | 352 | tkStr = ""; |
ohneta | 0:aae260bdcdd9 | 353 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 354 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 355 | getNextToken(); |
ohneta | 0:aae260bdcdd9 | 356 | } |
ohneta | 0:aae260bdcdd9 | 357 | |
ohneta | 0:aae260bdcdd9 | 358 | void CScriptLex::match(int expected_tk) { |
ohneta | 0:aae260bdcdd9 | 359 | if (tk!=expected_tk) { |
ohneta | 0:aae260bdcdd9 | 360 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 361 | ostringstream errorString; |
ohneta | 0:aae260bdcdd9 | 362 | errorString << "Got " << getTokenStr(tk) << " expected " << getTokenStr(expected_tk) |
ohneta | 0:aae260bdcdd9 | 363 | << " at " << getPosition(tokenStart); |
ohneta | 0:aae260bdcdd9 | 364 | throw new CScriptException(errorString.str()); |
ohneta | 0:aae260bdcdd9 | 365 | #else |
ohneta | 0:aae260bdcdd9 | 366 | mbedErrorFlag = 1; |
ohneta | 0:aae260bdcdd9 | 367 | mbedErrorMessage = "Got "; |
ohneta | 0:aae260bdcdd9 | 368 | mbedErrorMessage += getTokenStr(tk); |
ohneta | 0:aae260bdcdd9 | 369 | mbedErrorMessage += " expected "; |
ohneta | 0:aae260bdcdd9 | 370 | mbedErrorMessage += getTokenStr(expected_tk); |
ohneta | 0:aae260bdcdd9 | 371 | mbedErrorMessage += " at "; |
ohneta | 0:aae260bdcdd9 | 372 | mbedErrorMessage += getPosition(tokenStart); |
ohneta | 0:aae260bdcdd9 | 373 | return; |
ohneta | 0:aae260bdcdd9 | 374 | #endif |
ohneta | 0:aae260bdcdd9 | 375 | } |
ohneta | 0:aae260bdcdd9 | 376 | getNextToken(); |
ohneta | 0:aae260bdcdd9 | 377 | } |
ohneta | 0:aae260bdcdd9 | 378 | |
ohneta | 0:aae260bdcdd9 | 379 | string CScriptLex::getTokenStr(int token) { |
ohneta | 0:aae260bdcdd9 | 380 | if (token>32 && token<128) { |
ohneta | 0:aae260bdcdd9 | 381 | char buf[4] = "' '"; |
ohneta | 0:aae260bdcdd9 | 382 | buf[1] = (char)token; |
ohneta | 0:aae260bdcdd9 | 383 | return buf; |
ohneta | 0:aae260bdcdd9 | 384 | } |
ohneta | 0:aae260bdcdd9 | 385 | switch (token) { |
ohneta | 0:aae260bdcdd9 | 386 | case LEX_EOF : return "EOF"; |
ohneta | 0:aae260bdcdd9 | 387 | case LEX_ID : return "ID"; |
ohneta | 0:aae260bdcdd9 | 388 | case LEX_INT : return "INT"; |
ohneta | 0:aae260bdcdd9 | 389 | case LEX_FLOAT : return "FLOAT"; |
ohneta | 0:aae260bdcdd9 | 390 | case LEX_STR : return "STRING"; |
ohneta | 0:aae260bdcdd9 | 391 | case LEX_EQUAL : return "=="; |
ohneta | 0:aae260bdcdd9 | 392 | case LEX_TYPEEQUAL : return "==="; |
ohneta | 0:aae260bdcdd9 | 393 | case LEX_NEQUAL : return "!="; |
ohneta | 0:aae260bdcdd9 | 394 | case LEX_NTYPEEQUAL : return "!=="; |
ohneta | 0:aae260bdcdd9 | 395 | case LEX_LEQUAL : return "<="; |
ohneta | 0:aae260bdcdd9 | 396 | case LEX_LSHIFT : return "<<"; |
ohneta | 0:aae260bdcdd9 | 397 | case LEX_LSHIFTEQUAL : return "<<="; |
ohneta | 0:aae260bdcdd9 | 398 | case LEX_GEQUAL : return ">="; |
ohneta | 0:aae260bdcdd9 | 399 | case LEX_RSHIFT : return ">>"; |
ohneta | 0:aae260bdcdd9 | 400 | case LEX_RSHIFTUNSIGNED : return ">>"; |
ohneta | 0:aae260bdcdd9 | 401 | case LEX_RSHIFTEQUAL : return ">>="; |
ohneta | 0:aae260bdcdd9 | 402 | case LEX_PLUSEQUAL : return "+="; |
ohneta | 0:aae260bdcdd9 | 403 | case LEX_MINUSEQUAL : return "-="; |
ohneta | 0:aae260bdcdd9 | 404 | case LEX_PLUSPLUS : return "++"; |
ohneta | 0:aae260bdcdd9 | 405 | case LEX_MINUSMINUS : return "--"; |
ohneta | 0:aae260bdcdd9 | 406 | case LEX_ANDEQUAL : return "&="; |
ohneta | 0:aae260bdcdd9 | 407 | case LEX_ANDAND : return "&&"; |
ohneta | 0:aae260bdcdd9 | 408 | case LEX_OREQUAL : return "|="; |
ohneta | 0:aae260bdcdd9 | 409 | case LEX_OROR : return "||"; |
ohneta | 0:aae260bdcdd9 | 410 | case LEX_XOREQUAL : return "^="; |
ohneta | 0:aae260bdcdd9 | 411 | // reserved words |
ohneta | 0:aae260bdcdd9 | 412 | case LEX_R_IF : return "if"; |
ohneta | 0:aae260bdcdd9 | 413 | case LEX_R_ELSE : return "else"; |
ohneta | 0:aae260bdcdd9 | 414 | case LEX_R_DO : return "do"; |
ohneta | 0:aae260bdcdd9 | 415 | case LEX_R_WHILE : return "while"; |
ohneta | 0:aae260bdcdd9 | 416 | case LEX_R_FOR : return "for"; |
ohneta | 0:aae260bdcdd9 | 417 | case LEX_R_BREAK : return "break"; |
ohneta | 0:aae260bdcdd9 | 418 | case LEX_R_CONTINUE : return "continue"; |
ohneta | 0:aae260bdcdd9 | 419 | case LEX_R_FUNCTION : return "function"; |
ohneta | 0:aae260bdcdd9 | 420 | case LEX_R_RETURN : return "return"; |
ohneta | 0:aae260bdcdd9 | 421 | case LEX_R_VAR : return "var"; |
ohneta | 0:aae260bdcdd9 | 422 | case LEX_R_TRUE : return "true"; |
ohneta | 0:aae260bdcdd9 | 423 | case LEX_R_FALSE : return "false"; |
ohneta | 0:aae260bdcdd9 | 424 | case LEX_R_NULL : return "null"; |
ohneta | 0:aae260bdcdd9 | 425 | case LEX_R_UNDEFINED : return "undefined"; |
ohneta | 0:aae260bdcdd9 | 426 | case LEX_R_NEW : return "new"; |
ohneta | 0:aae260bdcdd9 | 427 | } |
ohneta | 0:aae260bdcdd9 | 428 | |
ohneta | 0:aae260bdcdd9 | 429 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 430 | ostringstream msg; |
ohneta | 0:aae260bdcdd9 | 431 | msg << "?[" << token << "]"; |
ohneta | 0:aae260bdcdd9 | 432 | return msg.str(); |
ohneta | 0:aae260bdcdd9 | 433 | #else |
ohneta | 0:aae260bdcdd9 | 434 | string msg; |
ohneta | 0:aae260bdcdd9 | 435 | msg = "?["; |
ohneta | 0:aae260bdcdd9 | 436 | msg += token; |
ohneta | 0:aae260bdcdd9 | 437 | msg += "]"; |
ohneta | 0:aae260bdcdd9 | 438 | return msg; |
ohneta | 0:aae260bdcdd9 | 439 | #endif |
ohneta | 0:aae260bdcdd9 | 440 | } |
ohneta | 0:aae260bdcdd9 | 441 | |
ohneta | 0:aae260bdcdd9 | 442 | void CScriptLex::getNextCh() { |
ohneta | 0:aae260bdcdd9 | 443 | currCh = nextCh; |
ohneta | 0:aae260bdcdd9 | 444 | if (dataPos < dataEnd) |
ohneta | 0:aae260bdcdd9 | 445 | nextCh = data[dataPos]; |
ohneta | 0:aae260bdcdd9 | 446 | else |
ohneta | 0:aae260bdcdd9 | 447 | nextCh = 0; |
ohneta | 0:aae260bdcdd9 | 448 | dataPos++; |
ohneta | 0:aae260bdcdd9 | 449 | } |
ohneta | 0:aae260bdcdd9 | 450 | |
ohneta | 0:aae260bdcdd9 | 451 | void CScriptLex::getNextToken() { |
ohneta | 0:aae260bdcdd9 | 452 | tk = LEX_EOF; |
ohneta | 0:aae260bdcdd9 | 453 | tkStr.clear(); |
ohneta | 0:aae260bdcdd9 | 454 | while (currCh && isWhitespace(currCh)) getNextCh(); |
ohneta | 0:aae260bdcdd9 | 455 | // newline comments |
ohneta | 0:aae260bdcdd9 | 456 | if (currCh=='/' && nextCh=='/') { |
ohneta | 0:aae260bdcdd9 | 457 | while (currCh && currCh!='\n') getNextCh(); |
ohneta | 0:aae260bdcdd9 | 458 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 459 | getNextToken(); |
ohneta | 0:aae260bdcdd9 | 460 | return; |
ohneta | 0:aae260bdcdd9 | 461 | } |
ohneta | 0:aae260bdcdd9 | 462 | // block comments |
ohneta | 0:aae260bdcdd9 | 463 | if (currCh=='/' && nextCh=='*') { |
ohneta | 0:aae260bdcdd9 | 464 | while (currCh && (currCh!='*' || nextCh!='/')) getNextCh(); |
ohneta | 0:aae260bdcdd9 | 465 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 466 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 467 | getNextToken(); |
ohneta | 0:aae260bdcdd9 | 468 | return; |
ohneta | 0:aae260bdcdd9 | 469 | } |
ohneta | 0:aae260bdcdd9 | 470 | // record beginning of this token |
ohneta | 0:aae260bdcdd9 | 471 | tokenStart = dataPos-2; |
ohneta | 0:aae260bdcdd9 | 472 | // tokens |
ohneta | 0:aae260bdcdd9 | 473 | if (isAlpha(currCh)) { // IDs |
ohneta | 0:aae260bdcdd9 | 474 | while (isAlpha(currCh) || isNumeric(currCh)) { |
ohneta | 0:aae260bdcdd9 | 475 | tkStr += currCh; |
ohneta | 0:aae260bdcdd9 | 476 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 477 | } |
ohneta | 0:aae260bdcdd9 | 478 | tk = LEX_ID; |
ohneta | 0:aae260bdcdd9 | 479 | if (tkStr=="if") tk = LEX_R_IF; |
ohneta | 0:aae260bdcdd9 | 480 | else if (tkStr=="else") tk = LEX_R_ELSE; |
ohneta | 0:aae260bdcdd9 | 481 | else if (tkStr=="do") tk = LEX_R_DO; |
ohneta | 0:aae260bdcdd9 | 482 | else if (tkStr=="while") tk = LEX_R_WHILE; |
ohneta | 0:aae260bdcdd9 | 483 | else if (tkStr=="for") tk = LEX_R_FOR; |
ohneta | 0:aae260bdcdd9 | 484 | else if (tkStr=="break") tk = LEX_R_BREAK; |
ohneta | 0:aae260bdcdd9 | 485 | else if (tkStr=="continue") tk = LEX_R_CONTINUE; |
ohneta | 0:aae260bdcdd9 | 486 | else if (tkStr=="function") tk = LEX_R_FUNCTION; |
ohneta | 0:aae260bdcdd9 | 487 | else if (tkStr=="return") tk = LEX_R_RETURN; |
ohneta | 0:aae260bdcdd9 | 488 | else if (tkStr=="var") tk = LEX_R_VAR; |
ohneta | 0:aae260bdcdd9 | 489 | else if (tkStr=="true") tk = LEX_R_TRUE; |
ohneta | 0:aae260bdcdd9 | 490 | else if (tkStr=="false") tk = LEX_R_FALSE; |
ohneta | 0:aae260bdcdd9 | 491 | else if (tkStr=="null") tk = LEX_R_NULL; |
ohneta | 0:aae260bdcdd9 | 492 | else if (tkStr=="undefined") tk = LEX_R_UNDEFINED; |
ohneta | 0:aae260bdcdd9 | 493 | else if (tkStr=="new") tk = LEX_R_NEW; |
ohneta | 0:aae260bdcdd9 | 494 | } else if (isNumeric(currCh)) { // Numbers |
ohneta | 0:aae260bdcdd9 | 495 | bool isHex = false; |
ohneta | 0:aae260bdcdd9 | 496 | if (currCh=='0') { tkStr += currCh; getNextCh(); } |
ohneta | 0:aae260bdcdd9 | 497 | if (currCh=='x') { |
ohneta | 0:aae260bdcdd9 | 498 | isHex = true; |
ohneta | 0:aae260bdcdd9 | 499 | tkStr += currCh; getNextCh(); |
ohneta | 0:aae260bdcdd9 | 500 | } |
ohneta | 0:aae260bdcdd9 | 501 | tk = LEX_INT; |
ohneta | 0:aae260bdcdd9 | 502 | while (isNumeric(currCh) || (isHex && isHexadecimal(currCh))) { |
ohneta | 0:aae260bdcdd9 | 503 | tkStr += currCh; |
ohneta | 0:aae260bdcdd9 | 504 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 505 | } |
ohneta | 0:aae260bdcdd9 | 506 | if (!isHex && currCh=='.') { |
ohneta | 0:aae260bdcdd9 | 507 | tk = LEX_FLOAT; |
ohneta | 0:aae260bdcdd9 | 508 | tkStr += '.'; |
ohneta | 0:aae260bdcdd9 | 509 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 510 | while (isNumeric(currCh)) { |
ohneta | 0:aae260bdcdd9 | 511 | tkStr += currCh; |
ohneta | 0:aae260bdcdd9 | 512 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 513 | } |
ohneta | 0:aae260bdcdd9 | 514 | } |
ohneta | 0:aae260bdcdd9 | 515 | // do fancy e-style floating point |
ohneta | 0:aae260bdcdd9 | 516 | if (!isHex && (currCh=='e'||currCh=='E')) { |
ohneta | 0:aae260bdcdd9 | 517 | tk = LEX_FLOAT; |
ohneta | 0:aae260bdcdd9 | 518 | tkStr += currCh; getNextCh(); |
ohneta | 0:aae260bdcdd9 | 519 | if (currCh=='-') { tkStr += currCh; getNextCh(); } |
ohneta | 0:aae260bdcdd9 | 520 | while (isNumeric(currCh)) { |
ohneta | 0:aae260bdcdd9 | 521 | tkStr += currCh; getNextCh(); |
ohneta | 0:aae260bdcdd9 | 522 | } |
ohneta | 0:aae260bdcdd9 | 523 | } |
ohneta | 0:aae260bdcdd9 | 524 | } else if (currCh=='"') { |
ohneta | 0:aae260bdcdd9 | 525 | // strings... |
ohneta | 0:aae260bdcdd9 | 526 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 527 | while (currCh && currCh!='"') { |
ohneta | 0:aae260bdcdd9 | 528 | if (currCh == '\\') { |
ohneta | 0:aae260bdcdd9 | 529 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 530 | switch (currCh) { |
ohneta | 0:aae260bdcdd9 | 531 | case 'n' : tkStr += '\n'; break; |
ohneta | 0:aae260bdcdd9 | 532 | case '"' : tkStr += '"'; break; |
ohneta | 0:aae260bdcdd9 | 533 | case '\\' : tkStr += '\\'; break; |
ohneta | 0:aae260bdcdd9 | 534 | default: tkStr += currCh; |
ohneta | 0:aae260bdcdd9 | 535 | } |
ohneta | 0:aae260bdcdd9 | 536 | } else { |
ohneta | 0:aae260bdcdd9 | 537 | tkStr += currCh; |
ohneta | 0:aae260bdcdd9 | 538 | } |
ohneta | 0:aae260bdcdd9 | 539 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 540 | } |
ohneta | 0:aae260bdcdd9 | 541 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 542 | tk = LEX_STR; |
ohneta | 0:aae260bdcdd9 | 543 | } else if (currCh=='\'') { |
ohneta | 0:aae260bdcdd9 | 544 | // strings again... |
ohneta | 0:aae260bdcdd9 | 545 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 546 | while (currCh && currCh!='\'') { |
ohneta | 0:aae260bdcdd9 | 547 | if (currCh == '\\') { |
ohneta | 0:aae260bdcdd9 | 548 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 549 | switch (currCh) { |
ohneta | 0:aae260bdcdd9 | 550 | case 'n' : tkStr += '\n'; break; |
ohneta | 0:aae260bdcdd9 | 551 | case 'a' : tkStr += '\a'; break; |
ohneta | 0:aae260bdcdd9 | 552 | case 'r' : tkStr += '\r'; break; |
ohneta | 0:aae260bdcdd9 | 553 | case 't' : tkStr += '\t'; break; |
ohneta | 0:aae260bdcdd9 | 554 | case '\'' : tkStr += '\''; break; |
ohneta | 0:aae260bdcdd9 | 555 | case '\\' : tkStr += '\\'; break; |
ohneta | 0:aae260bdcdd9 | 556 | case 'x' : { // hex digits |
ohneta | 0:aae260bdcdd9 | 557 | char buf[3] = "??"; |
ohneta | 0:aae260bdcdd9 | 558 | getNextCh(); buf[0] = currCh; |
ohneta | 0:aae260bdcdd9 | 559 | getNextCh(); buf[1] = currCh; |
ohneta | 0:aae260bdcdd9 | 560 | tkStr += (char)strtol(buf,0,16); |
ohneta | 0:aae260bdcdd9 | 561 | } break; |
ohneta | 0:aae260bdcdd9 | 562 | default: if (currCh>='0' && currCh<='7') { |
ohneta | 0:aae260bdcdd9 | 563 | // octal digits |
ohneta | 0:aae260bdcdd9 | 564 | char buf[4] = "???"; |
ohneta | 0:aae260bdcdd9 | 565 | buf[0] = currCh; |
ohneta | 0:aae260bdcdd9 | 566 | getNextCh(); buf[1] = currCh; |
ohneta | 0:aae260bdcdd9 | 567 | getNextCh(); buf[2] = currCh; |
ohneta | 0:aae260bdcdd9 | 568 | tkStr += (char)strtol(buf,0,8); |
ohneta | 0:aae260bdcdd9 | 569 | } else |
ohneta | 0:aae260bdcdd9 | 570 | tkStr += currCh; |
ohneta | 0:aae260bdcdd9 | 571 | } |
ohneta | 0:aae260bdcdd9 | 572 | } else { |
ohneta | 0:aae260bdcdd9 | 573 | tkStr += currCh; |
ohneta | 0:aae260bdcdd9 | 574 | } |
ohneta | 0:aae260bdcdd9 | 575 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 576 | } |
ohneta | 0:aae260bdcdd9 | 577 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 578 | tk = LEX_STR; |
ohneta | 0:aae260bdcdd9 | 579 | } else { |
ohneta | 0:aae260bdcdd9 | 580 | // single chars |
ohneta | 0:aae260bdcdd9 | 581 | tk = currCh; |
ohneta | 0:aae260bdcdd9 | 582 | if (currCh) getNextCh(); |
ohneta | 0:aae260bdcdd9 | 583 | if (tk=='=' && currCh=='=') { // == |
ohneta | 0:aae260bdcdd9 | 584 | tk = LEX_EQUAL; |
ohneta | 0:aae260bdcdd9 | 585 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 586 | if (currCh=='=') { // === |
ohneta | 0:aae260bdcdd9 | 587 | tk = LEX_TYPEEQUAL; |
ohneta | 0:aae260bdcdd9 | 588 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 589 | } |
ohneta | 0:aae260bdcdd9 | 590 | } else if (tk=='!' && currCh=='=') { // != |
ohneta | 0:aae260bdcdd9 | 591 | tk = LEX_NEQUAL; |
ohneta | 0:aae260bdcdd9 | 592 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 593 | if (currCh=='=') { // !== |
ohneta | 0:aae260bdcdd9 | 594 | tk = LEX_NTYPEEQUAL; |
ohneta | 0:aae260bdcdd9 | 595 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 596 | } |
ohneta | 0:aae260bdcdd9 | 597 | } else if (tk=='<' && currCh=='=') { |
ohneta | 0:aae260bdcdd9 | 598 | tk = LEX_LEQUAL; |
ohneta | 0:aae260bdcdd9 | 599 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 600 | } else if (tk=='<' && currCh=='<') { |
ohneta | 0:aae260bdcdd9 | 601 | tk = LEX_LSHIFT; |
ohneta | 0:aae260bdcdd9 | 602 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 603 | if (currCh=='=') { // <<= |
ohneta | 0:aae260bdcdd9 | 604 | tk = LEX_LSHIFTEQUAL; |
ohneta | 0:aae260bdcdd9 | 605 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 606 | } |
ohneta | 0:aae260bdcdd9 | 607 | } else if (tk=='>' && currCh=='=') { |
ohneta | 0:aae260bdcdd9 | 608 | tk = LEX_GEQUAL; |
ohneta | 0:aae260bdcdd9 | 609 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 610 | } else if (tk=='>' && currCh=='>') { |
ohneta | 0:aae260bdcdd9 | 611 | tk = LEX_RSHIFT; |
ohneta | 0:aae260bdcdd9 | 612 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 613 | if (currCh=='=') { // >>= |
ohneta | 0:aae260bdcdd9 | 614 | tk = LEX_RSHIFTEQUAL; |
ohneta | 0:aae260bdcdd9 | 615 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 616 | } else if (currCh=='>') { // >>> |
ohneta | 0:aae260bdcdd9 | 617 | tk = LEX_RSHIFTUNSIGNED; |
ohneta | 0:aae260bdcdd9 | 618 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 619 | } |
ohneta | 0:aae260bdcdd9 | 620 | } else if (tk=='+' && currCh=='=') { |
ohneta | 0:aae260bdcdd9 | 621 | tk = LEX_PLUSEQUAL; |
ohneta | 0:aae260bdcdd9 | 622 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 623 | } else if (tk=='-' && currCh=='=') { |
ohneta | 0:aae260bdcdd9 | 624 | tk = LEX_MINUSEQUAL; |
ohneta | 0:aae260bdcdd9 | 625 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 626 | } else if (tk=='+' && currCh=='+') { |
ohneta | 0:aae260bdcdd9 | 627 | tk = LEX_PLUSPLUS; |
ohneta | 0:aae260bdcdd9 | 628 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 629 | } else if (tk=='-' && currCh=='-') { |
ohneta | 0:aae260bdcdd9 | 630 | tk = LEX_MINUSMINUS; |
ohneta | 0:aae260bdcdd9 | 631 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 632 | } else if (tk=='&' && currCh=='=') { |
ohneta | 0:aae260bdcdd9 | 633 | tk = LEX_ANDEQUAL; |
ohneta | 0:aae260bdcdd9 | 634 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 635 | } else if (tk=='&' && currCh=='&') { |
ohneta | 0:aae260bdcdd9 | 636 | tk = LEX_ANDAND; |
ohneta | 0:aae260bdcdd9 | 637 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 638 | } else if (tk=='|' && currCh=='=') { |
ohneta | 0:aae260bdcdd9 | 639 | tk = LEX_OREQUAL; |
ohneta | 0:aae260bdcdd9 | 640 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 641 | } else if (tk=='|' && currCh=='|') { |
ohneta | 0:aae260bdcdd9 | 642 | tk = LEX_OROR; |
ohneta | 0:aae260bdcdd9 | 643 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 644 | } else if (tk=='^' && currCh=='=') { |
ohneta | 0:aae260bdcdd9 | 645 | tk = LEX_XOREQUAL; |
ohneta | 0:aae260bdcdd9 | 646 | getNextCh(); |
ohneta | 0:aae260bdcdd9 | 647 | } |
ohneta | 0:aae260bdcdd9 | 648 | } |
ohneta | 0:aae260bdcdd9 | 649 | /* This isn't quite right yet */ |
ohneta | 0:aae260bdcdd9 | 650 | tokenLastEnd = tokenEnd; |
ohneta | 0:aae260bdcdd9 | 651 | tokenEnd = dataPos-3; |
ohneta | 0:aae260bdcdd9 | 652 | } |
ohneta | 0:aae260bdcdd9 | 653 | |
ohneta | 0:aae260bdcdd9 | 654 | string CScriptLex::getSubString(int lastPosition) { |
ohneta | 0:aae260bdcdd9 | 655 | int lastCharIdx = tokenLastEnd+1; |
ohneta | 0:aae260bdcdd9 | 656 | if (lastCharIdx < dataEnd) { |
ohneta | 0:aae260bdcdd9 | 657 | /* save a memory alloc by using our data array to create the |
ohneta | 0:aae260bdcdd9 | 658 | substring */ |
ohneta | 0:aae260bdcdd9 | 659 | char old = data[lastCharIdx]; |
ohneta | 0:aae260bdcdd9 | 660 | data[lastCharIdx] = 0; |
ohneta | 0:aae260bdcdd9 | 661 | std::string value = &data[lastPosition]; |
ohneta | 0:aae260bdcdd9 | 662 | data[lastCharIdx] = old; |
ohneta | 0:aae260bdcdd9 | 663 | return value; |
ohneta | 0:aae260bdcdd9 | 664 | } else { |
ohneta | 0:aae260bdcdd9 | 665 | return std::string(&data[lastPosition]); |
ohneta | 0:aae260bdcdd9 | 666 | } |
ohneta | 0:aae260bdcdd9 | 667 | } |
ohneta | 0:aae260bdcdd9 | 668 | |
ohneta | 0:aae260bdcdd9 | 669 | |
ohneta | 0:aae260bdcdd9 | 670 | CScriptLex *CScriptLex::getSubLex(int lastPosition) { |
ohneta | 0:aae260bdcdd9 | 671 | int lastCharIdx = tokenLastEnd+1; |
ohneta | 0:aae260bdcdd9 | 672 | if (lastCharIdx < dataEnd) |
ohneta | 0:aae260bdcdd9 | 673 | return new CScriptLex(this, lastPosition, lastCharIdx); |
ohneta | 0:aae260bdcdd9 | 674 | else |
ohneta | 0:aae260bdcdd9 | 675 | return new CScriptLex(this, lastPosition, dataEnd ); |
ohneta | 0:aae260bdcdd9 | 676 | } |
ohneta | 0:aae260bdcdd9 | 677 | |
ohneta | 0:aae260bdcdd9 | 678 | string CScriptLex::getPosition(int pos) { |
ohneta | 0:aae260bdcdd9 | 679 | if (pos<0) pos=tokenLastEnd; |
ohneta | 0:aae260bdcdd9 | 680 | int line = 1,col = 1; |
ohneta | 0:aae260bdcdd9 | 681 | for (int i=0;i<pos;i++) { |
ohneta | 0:aae260bdcdd9 | 682 | char ch; |
ohneta | 0:aae260bdcdd9 | 683 | if (i < dataEnd) |
ohneta | 0:aae260bdcdd9 | 684 | ch = data[i]; |
ohneta | 0:aae260bdcdd9 | 685 | else |
ohneta | 0:aae260bdcdd9 | 686 | ch = 0; |
ohneta | 0:aae260bdcdd9 | 687 | col++; |
ohneta | 0:aae260bdcdd9 | 688 | if (ch=='\n') { |
ohneta | 0:aae260bdcdd9 | 689 | line++; |
ohneta | 0:aae260bdcdd9 | 690 | col = 0; |
ohneta | 0:aae260bdcdd9 | 691 | } |
ohneta | 0:aae260bdcdd9 | 692 | } |
ohneta | 0:aae260bdcdd9 | 693 | char buf[256]; |
ohneta | 0:aae260bdcdd9 | 694 | sprintf_s(buf, 256, "(line: %d, col: %d)", line, col); |
ohneta | 0:aae260bdcdd9 | 695 | return buf; |
ohneta | 0:aae260bdcdd9 | 696 | } |
ohneta | 0:aae260bdcdd9 | 697 | |
ohneta | 0:aae260bdcdd9 | 698 | // ----------------------------------------------------------------------------------- CSCRIPTVARLINK |
ohneta | 0:aae260bdcdd9 | 699 | |
ohneta | 0:aae260bdcdd9 | 700 | CScriptVarLink::CScriptVarLink(CScriptVar *var, const std::string &name) { |
ohneta | 0:aae260bdcdd9 | 701 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 702 | mark_allocated(this); |
ohneta | 0:aae260bdcdd9 | 703 | #endif |
ohneta | 0:aae260bdcdd9 | 704 | this->name = name; |
ohneta | 0:aae260bdcdd9 | 705 | this->nextSibling = 0; |
ohneta | 0:aae260bdcdd9 | 706 | this->prevSibling = 0; |
ohneta | 0:aae260bdcdd9 | 707 | this->var = var->ref(); |
ohneta | 0:aae260bdcdd9 | 708 | this->owned = false; |
ohneta | 0:aae260bdcdd9 | 709 | } |
ohneta | 0:aae260bdcdd9 | 710 | |
ohneta | 0:aae260bdcdd9 | 711 | CScriptVarLink::CScriptVarLink(const CScriptVarLink &link) { |
ohneta | 0:aae260bdcdd9 | 712 | // Copy constructor |
ohneta | 0:aae260bdcdd9 | 713 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 714 | mark_allocated(this); |
ohneta | 0:aae260bdcdd9 | 715 | #endif |
ohneta | 0:aae260bdcdd9 | 716 | this->name = link.name; |
ohneta | 0:aae260bdcdd9 | 717 | this->nextSibling = 0; |
ohneta | 0:aae260bdcdd9 | 718 | this->prevSibling = 0; |
ohneta | 0:aae260bdcdd9 | 719 | this->var = link.var->ref(); |
ohneta | 0:aae260bdcdd9 | 720 | this->owned = false; |
ohneta | 0:aae260bdcdd9 | 721 | } |
ohneta | 0:aae260bdcdd9 | 722 | |
ohneta | 0:aae260bdcdd9 | 723 | CScriptVarLink::~CScriptVarLink() { |
ohneta | 0:aae260bdcdd9 | 724 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 725 | mark_deallocated(this); |
ohneta | 0:aae260bdcdd9 | 726 | #endif |
ohneta | 0:aae260bdcdd9 | 727 | var->unref(); |
ohneta | 0:aae260bdcdd9 | 728 | } |
ohneta | 0:aae260bdcdd9 | 729 | |
ohneta | 0:aae260bdcdd9 | 730 | void CScriptVarLink::replaceWith(CScriptVar *newVar) { |
ohneta | 0:aae260bdcdd9 | 731 | CScriptVar *oldVar = var; |
ohneta | 0:aae260bdcdd9 | 732 | var = newVar->ref(); |
ohneta | 0:aae260bdcdd9 | 733 | oldVar->unref(); |
ohneta | 0:aae260bdcdd9 | 734 | } |
ohneta | 0:aae260bdcdd9 | 735 | |
ohneta | 0:aae260bdcdd9 | 736 | void CScriptVarLink::replaceWith(CScriptVarLink *newVar) { |
ohneta | 0:aae260bdcdd9 | 737 | if (newVar) |
ohneta | 0:aae260bdcdd9 | 738 | replaceWith(newVar->var); |
ohneta | 0:aae260bdcdd9 | 739 | else |
ohneta | 0:aae260bdcdd9 | 740 | replaceWith(new CScriptVar()); |
ohneta | 0:aae260bdcdd9 | 741 | } |
ohneta | 0:aae260bdcdd9 | 742 | |
ohneta | 0:aae260bdcdd9 | 743 | int CScriptVarLink::getIntName() { |
ohneta | 0:aae260bdcdd9 | 744 | return atoi(name.c_str()); |
ohneta | 0:aae260bdcdd9 | 745 | } |
ohneta | 0:aae260bdcdd9 | 746 | void CScriptVarLink::setIntName(int n) { |
ohneta | 0:aae260bdcdd9 | 747 | char sIdx[64]; |
ohneta | 0:aae260bdcdd9 | 748 | sprintf_s(sIdx, sizeof(sIdx), "%d", n); |
ohneta | 0:aae260bdcdd9 | 749 | name = sIdx; |
ohneta | 0:aae260bdcdd9 | 750 | } |
ohneta | 0:aae260bdcdd9 | 751 | |
ohneta | 0:aae260bdcdd9 | 752 | // ----------------------------------------------------------------------------------- CSCRIPTVAR |
ohneta | 0:aae260bdcdd9 | 753 | |
ohneta | 0:aae260bdcdd9 | 754 | CScriptVar::CScriptVar() { |
ohneta | 0:aae260bdcdd9 | 755 | refs = 0; |
ohneta | 0:aae260bdcdd9 | 756 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 757 | mark_allocated(this); |
ohneta | 0:aae260bdcdd9 | 758 | #endif |
ohneta | 0:aae260bdcdd9 | 759 | init(); |
ohneta | 0:aae260bdcdd9 | 760 | flags = SCRIPTVAR_UNDEFINED; |
ohneta | 0:aae260bdcdd9 | 761 | } |
ohneta | 0:aae260bdcdd9 | 762 | |
ohneta | 0:aae260bdcdd9 | 763 | CScriptVar::CScriptVar(const string &str) { |
ohneta | 0:aae260bdcdd9 | 764 | refs = 0; |
ohneta | 0:aae260bdcdd9 | 765 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 766 | mark_allocated(this); |
ohneta | 0:aae260bdcdd9 | 767 | #endif |
ohneta | 0:aae260bdcdd9 | 768 | init(); |
ohneta | 0:aae260bdcdd9 | 769 | flags = SCRIPTVAR_STRING; |
ohneta | 0:aae260bdcdd9 | 770 | data = str; |
ohneta | 0:aae260bdcdd9 | 771 | } |
ohneta | 0:aae260bdcdd9 | 772 | |
ohneta | 0:aae260bdcdd9 | 773 | |
ohneta | 0:aae260bdcdd9 | 774 | CScriptVar::CScriptVar(const string &varData, int varFlags) { |
ohneta | 0:aae260bdcdd9 | 775 | refs = 0; |
ohneta | 0:aae260bdcdd9 | 776 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 777 | mark_allocated(this); |
ohneta | 0:aae260bdcdd9 | 778 | #endif |
ohneta | 0:aae260bdcdd9 | 779 | init(); |
ohneta | 0:aae260bdcdd9 | 780 | flags = varFlags; |
ohneta | 0:aae260bdcdd9 | 781 | if (varFlags & SCRIPTVAR_INTEGER) { |
ohneta | 0:aae260bdcdd9 | 782 | intData = strtol(varData.c_str(),0,0); |
ohneta | 0:aae260bdcdd9 | 783 | } else if (varFlags & SCRIPTVAR_DOUBLE) { |
ohneta | 0:aae260bdcdd9 | 784 | doubleData = strtod(varData.c_str(),0); |
ohneta | 0:aae260bdcdd9 | 785 | } else |
ohneta | 0:aae260bdcdd9 | 786 | data = varData; |
ohneta | 0:aae260bdcdd9 | 787 | } |
ohneta | 0:aae260bdcdd9 | 788 | |
ohneta | 0:aae260bdcdd9 | 789 | CScriptVar::CScriptVar(double val) { |
ohneta | 0:aae260bdcdd9 | 790 | refs = 0; |
ohneta | 0:aae260bdcdd9 | 791 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 792 | mark_allocated(this); |
ohneta | 0:aae260bdcdd9 | 793 | #endif |
ohneta | 0:aae260bdcdd9 | 794 | init(); |
ohneta | 0:aae260bdcdd9 | 795 | setDouble(val); |
ohneta | 0:aae260bdcdd9 | 796 | } |
ohneta | 0:aae260bdcdd9 | 797 | |
ohneta | 0:aae260bdcdd9 | 798 | CScriptVar::CScriptVar(int val) { |
ohneta | 0:aae260bdcdd9 | 799 | refs = 0; |
ohneta | 0:aae260bdcdd9 | 800 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 801 | mark_allocated(this); |
ohneta | 0:aae260bdcdd9 | 802 | #endif |
ohneta | 0:aae260bdcdd9 | 803 | init(); |
ohneta | 0:aae260bdcdd9 | 804 | setInt(val); |
ohneta | 0:aae260bdcdd9 | 805 | } |
ohneta | 0:aae260bdcdd9 | 806 | |
ohneta | 0:aae260bdcdd9 | 807 | CScriptVar::~CScriptVar(void) { |
ohneta | 0:aae260bdcdd9 | 808 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 809 | mark_deallocated(this); |
ohneta | 0:aae260bdcdd9 | 810 | #endif |
ohneta | 0:aae260bdcdd9 | 811 | removeAllChildren(); |
ohneta | 0:aae260bdcdd9 | 812 | } |
ohneta | 0:aae260bdcdd9 | 813 | |
ohneta | 0:aae260bdcdd9 | 814 | void CScriptVar::init() { |
ohneta | 0:aae260bdcdd9 | 815 | firstChild = 0; |
ohneta | 0:aae260bdcdd9 | 816 | lastChild = 0; |
ohneta | 0:aae260bdcdd9 | 817 | flags = 0; |
ohneta | 0:aae260bdcdd9 | 818 | jsCallback = 0; |
ohneta | 0:aae260bdcdd9 | 819 | jsCallbackUserData = 0; |
ohneta | 0:aae260bdcdd9 | 820 | data = TINYJS_BLANK_DATA; |
ohneta | 0:aae260bdcdd9 | 821 | intData = 0; |
ohneta | 0:aae260bdcdd9 | 822 | doubleData = 0; |
ohneta | 0:aae260bdcdd9 | 823 | } |
ohneta | 0:aae260bdcdd9 | 824 | |
ohneta | 0:aae260bdcdd9 | 825 | CScriptVar *CScriptVar::getReturnVar() { |
ohneta | 0:aae260bdcdd9 | 826 | return getParameter(TINYJS_RETURN_VAR); |
ohneta | 0:aae260bdcdd9 | 827 | } |
ohneta | 0:aae260bdcdd9 | 828 | |
ohneta | 0:aae260bdcdd9 | 829 | void CScriptVar::setReturnVar(CScriptVar *var) { |
ohneta | 0:aae260bdcdd9 | 830 | findChildOrCreate(TINYJS_RETURN_VAR)->replaceWith(var); |
ohneta | 0:aae260bdcdd9 | 831 | } |
ohneta | 0:aae260bdcdd9 | 832 | |
ohneta | 0:aae260bdcdd9 | 833 | |
ohneta | 0:aae260bdcdd9 | 834 | CScriptVar *CScriptVar::getParameter(const std::string &name) { |
ohneta | 0:aae260bdcdd9 | 835 | return findChildOrCreate(name)->var; |
ohneta | 0:aae260bdcdd9 | 836 | } |
ohneta | 0:aae260bdcdd9 | 837 | |
ohneta | 0:aae260bdcdd9 | 838 | CScriptVarLink *CScriptVar::findChild(const string &childName) { |
ohneta | 0:aae260bdcdd9 | 839 | CScriptVarLink *v = firstChild; |
ohneta | 0:aae260bdcdd9 | 840 | while (v) { |
ohneta | 0:aae260bdcdd9 | 841 | if (v->name.compare(childName)==0) |
ohneta | 0:aae260bdcdd9 | 842 | return v; |
ohneta | 0:aae260bdcdd9 | 843 | v = v->nextSibling; |
ohneta | 0:aae260bdcdd9 | 844 | } |
ohneta | 0:aae260bdcdd9 | 845 | return 0; |
ohneta | 0:aae260bdcdd9 | 846 | } |
ohneta | 0:aae260bdcdd9 | 847 | |
ohneta | 0:aae260bdcdd9 | 848 | CScriptVarLink *CScriptVar::findChildOrCreate(const string &childName, int varFlags) { |
ohneta | 0:aae260bdcdd9 | 849 | CScriptVarLink *l = findChild(childName); |
ohneta | 0:aae260bdcdd9 | 850 | if (l) return l; |
ohneta | 0:aae260bdcdd9 | 851 | |
ohneta | 0:aae260bdcdd9 | 852 | return addChild(childName, new CScriptVar(TINYJS_BLANK_DATA, varFlags)); |
ohneta | 0:aae260bdcdd9 | 853 | } |
ohneta | 0:aae260bdcdd9 | 854 | |
ohneta | 0:aae260bdcdd9 | 855 | CScriptVarLink *CScriptVar::findChildOrCreateByPath(const std::string &path) { |
ohneta | 0:aae260bdcdd9 | 856 | size_t p = path.find('.'); |
ohneta | 0:aae260bdcdd9 | 857 | if (p == string::npos) |
ohneta | 0:aae260bdcdd9 | 858 | return findChildOrCreate(path); |
ohneta | 0:aae260bdcdd9 | 859 | |
ohneta | 0:aae260bdcdd9 | 860 | return findChildOrCreate(path.substr(0,p), SCRIPTVAR_OBJECT)->var-> |
ohneta | 0:aae260bdcdd9 | 861 | findChildOrCreateByPath(path.substr(p+1)); |
ohneta | 0:aae260bdcdd9 | 862 | } |
ohneta | 0:aae260bdcdd9 | 863 | |
ohneta | 0:aae260bdcdd9 | 864 | CScriptVarLink *CScriptVar::addChild(const std::string &childName, CScriptVar *child) { |
ohneta | 0:aae260bdcdd9 | 865 | if (isUndefined()) { |
ohneta | 0:aae260bdcdd9 | 866 | flags = SCRIPTVAR_OBJECT; |
ohneta | 0:aae260bdcdd9 | 867 | } |
ohneta | 0:aae260bdcdd9 | 868 | // if no child supplied, create one |
ohneta | 0:aae260bdcdd9 | 869 | if (!child) |
ohneta | 0:aae260bdcdd9 | 870 | child = new CScriptVar(); |
ohneta | 0:aae260bdcdd9 | 871 | |
ohneta | 0:aae260bdcdd9 | 872 | CScriptVarLink *link = new CScriptVarLink(child, childName); |
ohneta | 0:aae260bdcdd9 | 873 | link->owned = true; |
ohneta | 0:aae260bdcdd9 | 874 | if (lastChild) { |
ohneta | 0:aae260bdcdd9 | 875 | lastChild->nextSibling = link; |
ohneta | 0:aae260bdcdd9 | 876 | link->prevSibling = lastChild; |
ohneta | 0:aae260bdcdd9 | 877 | lastChild = link; |
ohneta | 0:aae260bdcdd9 | 878 | } else { |
ohneta | 0:aae260bdcdd9 | 879 | firstChild = link; |
ohneta | 0:aae260bdcdd9 | 880 | lastChild = link; |
ohneta | 0:aae260bdcdd9 | 881 | } |
ohneta | 0:aae260bdcdd9 | 882 | return link; |
ohneta | 0:aae260bdcdd9 | 883 | } |
ohneta | 0:aae260bdcdd9 | 884 | |
ohneta | 0:aae260bdcdd9 | 885 | CScriptVarLink *CScriptVar::addChildNoDup(const std::string &childName, CScriptVar *child) { |
ohneta | 0:aae260bdcdd9 | 886 | // if no child supplied, create one |
ohneta | 0:aae260bdcdd9 | 887 | if (!child) |
ohneta | 0:aae260bdcdd9 | 888 | child = new CScriptVar(); |
ohneta | 0:aae260bdcdd9 | 889 | |
ohneta | 0:aae260bdcdd9 | 890 | CScriptVarLink *v = findChild(childName); |
ohneta | 0:aae260bdcdd9 | 891 | if (v) { |
ohneta | 0:aae260bdcdd9 | 892 | v->replaceWith(child); |
ohneta | 0:aae260bdcdd9 | 893 | } else { |
ohneta | 0:aae260bdcdd9 | 894 | v = addChild(childName, child); |
ohneta | 0:aae260bdcdd9 | 895 | } |
ohneta | 0:aae260bdcdd9 | 896 | |
ohneta | 0:aae260bdcdd9 | 897 | return v; |
ohneta | 0:aae260bdcdd9 | 898 | } |
ohneta | 0:aae260bdcdd9 | 899 | |
ohneta | 0:aae260bdcdd9 | 900 | void CScriptVar::removeChild(CScriptVar *child) { |
ohneta | 0:aae260bdcdd9 | 901 | CScriptVarLink *link = firstChild; |
ohneta | 0:aae260bdcdd9 | 902 | while (link) { |
ohneta | 0:aae260bdcdd9 | 903 | if (link->var == child) |
ohneta | 0:aae260bdcdd9 | 904 | break; |
ohneta | 0:aae260bdcdd9 | 905 | link = link->nextSibling; |
ohneta | 0:aae260bdcdd9 | 906 | } |
ohneta | 0:aae260bdcdd9 | 907 | ASSERT(link); |
ohneta | 0:aae260bdcdd9 | 908 | removeLink(link); |
ohneta | 0:aae260bdcdd9 | 909 | } |
ohneta | 0:aae260bdcdd9 | 910 | |
ohneta | 0:aae260bdcdd9 | 911 | void CScriptVar::removeLink(CScriptVarLink *link) { |
ohneta | 0:aae260bdcdd9 | 912 | if (!link) return; |
ohneta | 0:aae260bdcdd9 | 913 | if (link->nextSibling) |
ohneta | 0:aae260bdcdd9 | 914 | link->nextSibling->prevSibling = link->prevSibling; |
ohneta | 0:aae260bdcdd9 | 915 | if (link->prevSibling) |
ohneta | 0:aae260bdcdd9 | 916 | link->prevSibling->nextSibling = link->nextSibling; |
ohneta | 0:aae260bdcdd9 | 917 | if (lastChild == link) |
ohneta | 0:aae260bdcdd9 | 918 | lastChild = link->prevSibling; |
ohneta | 0:aae260bdcdd9 | 919 | if (firstChild == link) |
ohneta | 0:aae260bdcdd9 | 920 | firstChild = link->nextSibling; |
ohneta | 0:aae260bdcdd9 | 921 | delete link; |
ohneta | 0:aae260bdcdd9 | 922 | } |
ohneta | 0:aae260bdcdd9 | 923 | |
ohneta | 0:aae260bdcdd9 | 924 | void CScriptVar::removeAllChildren() { |
ohneta | 0:aae260bdcdd9 | 925 | CScriptVarLink *c = firstChild; |
ohneta | 0:aae260bdcdd9 | 926 | while (c) { |
ohneta | 0:aae260bdcdd9 | 927 | CScriptVarLink *t = c->nextSibling; |
ohneta | 0:aae260bdcdd9 | 928 | delete c; |
ohneta | 0:aae260bdcdd9 | 929 | c = t; |
ohneta | 0:aae260bdcdd9 | 930 | } |
ohneta | 0:aae260bdcdd9 | 931 | firstChild = 0; |
ohneta | 0:aae260bdcdd9 | 932 | lastChild = 0; |
ohneta | 0:aae260bdcdd9 | 933 | } |
ohneta | 0:aae260bdcdd9 | 934 | |
ohneta | 0:aae260bdcdd9 | 935 | CScriptVar *CScriptVar::getArrayIndex(int idx) { |
ohneta | 0:aae260bdcdd9 | 936 | char sIdx[64]; |
ohneta | 0:aae260bdcdd9 | 937 | sprintf_s(sIdx, sizeof(sIdx), "%d", idx); |
ohneta | 0:aae260bdcdd9 | 938 | CScriptVarLink *link = findChild(sIdx); |
ohneta | 0:aae260bdcdd9 | 939 | if (link) return link->var; |
ohneta | 0:aae260bdcdd9 | 940 | else return new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_NULL); // undefined |
ohneta | 0:aae260bdcdd9 | 941 | } |
ohneta | 0:aae260bdcdd9 | 942 | |
ohneta | 0:aae260bdcdd9 | 943 | void CScriptVar::setArrayIndex(int idx, CScriptVar *value) { |
ohneta | 0:aae260bdcdd9 | 944 | char sIdx[64]; |
ohneta | 0:aae260bdcdd9 | 945 | sprintf_s(sIdx, sizeof(sIdx), "%d", idx); |
ohneta | 0:aae260bdcdd9 | 946 | CScriptVarLink *link = findChild(sIdx); |
ohneta | 0:aae260bdcdd9 | 947 | |
ohneta | 0:aae260bdcdd9 | 948 | if (link) { |
ohneta | 0:aae260bdcdd9 | 949 | if (value->isUndefined()) |
ohneta | 0:aae260bdcdd9 | 950 | removeLink(link); |
ohneta | 0:aae260bdcdd9 | 951 | else |
ohneta | 0:aae260bdcdd9 | 952 | link->replaceWith(value); |
ohneta | 0:aae260bdcdd9 | 953 | } else { |
ohneta | 0:aae260bdcdd9 | 954 | if (!value->isUndefined()) |
ohneta | 0:aae260bdcdd9 | 955 | addChild(sIdx, value); |
ohneta | 0:aae260bdcdd9 | 956 | } |
ohneta | 0:aae260bdcdd9 | 957 | } |
ohneta | 0:aae260bdcdd9 | 958 | |
ohneta | 0:aae260bdcdd9 | 959 | int CScriptVar::getArrayLength() { |
ohneta | 0:aae260bdcdd9 | 960 | int highest = -1; |
ohneta | 0:aae260bdcdd9 | 961 | if (!isArray()) return 0; |
ohneta | 0:aae260bdcdd9 | 962 | |
ohneta | 0:aae260bdcdd9 | 963 | CScriptVarLink *link = firstChild; |
ohneta | 0:aae260bdcdd9 | 964 | while (link) { |
ohneta | 0:aae260bdcdd9 | 965 | if (isNumber(link->name)) { |
ohneta | 0:aae260bdcdd9 | 966 | int val = atoi(link->name.c_str()); |
ohneta | 0:aae260bdcdd9 | 967 | if (val > highest) highest = val; |
ohneta | 0:aae260bdcdd9 | 968 | } |
ohneta | 0:aae260bdcdd9 | 969 | link = link->nextSibling; |
ohneta | 0:aae260bdcdd9 | 970 | } |
ohneta | 0:aae260bdcdd9 | 971 | return highest+1; |
ohneta | 0:aae260bdcdd9 | 972 | } |
ohneta | 0:aae260bdcdd9 | 973 | |
ohneta | 0:aae260bdcdd9 | 974 | int CScriptVar::getChildren() { |
ohneta | 0:aae260bdcdd9 | 975 | int n = 0; |
ohneta | 0:aae260bdcdd9 | 976 | CScriptVarLink *link = firstChild; |
ohneta | 0:aae260bdcdd9 | 977 | while (link) { |
ohneta | 0:aae260bdcdd9 | 978 | n++; |
ohneta | 0:aae260bdcdd9 | 979 | link = link->nextSibling; |
ohneta | 0:aae260bdcdd9 | 980 | } |
ohneta | 0:aae260bdcdd9 | 981 | return n; |
ohneta | 0:aae260bdcdd9 | 982 | } |
ohneta | 0:aae260bdcdd9 | 983 | |
ohneta | 0:aae260bdcdd9 | 984 | int CScriptVar::getInt() { |
ohneta | 0:aae260bdcdd9 | 985 | /* strtol understands about hex and octal */ |
ohneta | 0:aae260bdcdd9 | 986 | if (isInt()) return intData; |
ohneta | 0:aae260bdcdd9 | 987 | if (isNull()) return 0; |
ohneta | 0:aae260bdcdd9 | 988 | if (isUndefined()) return 0; |
ohneta | 0:aae260bdcdd9 | 989 | if (isDouble()) return (int)doubleData; |
ohneta | 0:aae260bdcdd9 | 990 | return 0; |
ohneta | 0:aae260bdcdd9 | 991 | } |
ohneta | 0:aae260bdcdd9 | 992 | |
ohneta | 0:aae260bdcdd9 | 993 | double CScriptVar::getDouble() { |
ohneta | 0:aae260bdcdd9 | 994 | if (isDouble()) return doubleData; |
ohneta | 0:aae260bdcdd9 | 995 | if (isInt()) return intData; |
ohneta | 0:aae260bdcdd9 | 996 | if (isNull()) return 0; |
ohneta | 0:aae260bdcdd9 | 997 | if (isUndefined()) return 0; |
ohneta | 0:aae260bdcdd9 | 998 | return 0; /* or NaN? */ |
ohneta | 0:aae260bdcdd9 | 999 | } |
ohneta | 0:aae260bdcdd9 | 1000 | |
ohneta | 0:aae260bdcdd9 | 1001 | const string &CScriptVar::getString() { |
ohneta | 0:aae260bdcdd9 | 1002 | /* Because we can't return a string that is generated on demand. |
ohneta | 0:aae260bdcdd9 | 1003 | * I should really just use char* :) */ |
ohneta | 0:aae260bdcdd9 | 1004 | static string s_null = "null"; |
ohneta | 0:aae260bdcdd9 | 1005 | static string s_undefined = "undefined"; |
ohneta | 0:aae260bdcdd9 | 1006 | if (isInt()) { |
ohneta | 0:aae260bdcdd9 | 1007 | char buffer[32]; |
ohneta | 0:aae260bdcdd9 | 1008 | sprintf_s(buffer, sizeof(buffer), "%ld", intData); |
ohneta | 0:aae260bdcdd9 | 1009 | data = buffer; |
ohneta | 0:aae260bdcdd9 | 1010 | return data; |
ohneta | 0:aae260bdcdd9 | 1011 | } |
ohneta | 0:aae260bdcdd9 | 1012 | if (isDouble()) { |
ohneta | 0:aae260bdcdd9 | 1013 | char buffer[32]; |
ohneta | 0:aae260bdcdd9 | 1014 | sprintf_s(buffer, sizeof(buffer), "%f", doubleData); |
ohneta | 0:aae260bdcdd9 | 1015 | data = buffer; |
ohneta | 0:aae260bdcdd9 | 1016 | return data; |
ohneta | 0:aae260bdcdd9 | 1017 | } |
ohneta | 0:aae260bdcdd9 | 1018 | if (isNull()) return s_null; |
ohneta | 0:aae260bdcdd9 | 1019 | if (isUndefined()) return s_undefined; |
ohneta | 0:aae260bdcdd9 | 1020 | // are we just a string here? |
ohneta | 0:aae260bdcdd9 | 1021 | return data; |
ohneta | 0:aae260bdcdd9 | 1022 | } |
ohneta | 0:aae260bdcdd9 | 1023 | |
ohneta | 0:aae260bdcdd9 | 1024 | void CScriptVar::setInt(int val) { |
ohneta | 0:aae260bdcdd9 | 1025 | flags = (flags&~SCRIPTVAR_VARTYPEMASK) | SCRIPTVAR_INTEGER; |
ohneta | 0:aae260bdcdd9 | 1026 | intData = val; |
ohneta | 0:aae260bdcdd9 | 1027 | doubleData = 0; |
ohneta | 0:aae260bdcdd9 | 1028 | data = TINYJS_BLANK_DATA; |
ohneta | 0:aae260bdcdd9 | 1029 | } |
ohneta | 0:aae260bdcdd9 | 1030 | |
ohneta | 0:aae260bdcdd9 | 1031 | void CScriptVar::setDouble(double val) { |
ohneta | 0:aae260bdcdd9 | 1032 | flags = (flags&~SCRIPTVAR_VARTYPEMASK) | SCRIPTVAR_DOUBLE; |
ohneta | 0:aae260bdcdd9 | 1033 | doubleData = val; |
ohneta | 0:aae260bdcdd9 | 1034 | intData = 0; |
ohneta | 0:aae260bdcdd9 | 1035 | data = TINYJS_BLANK_DATA; |
ohneta | 0:aae260bdcdd9 | 1036 | } |
ohneta | 0:aae260bdcdd9 | 1037 | |
ohneta | 0:aae260bdcdd9 | 1038 | void CScriptVar::setString(const string &str) { |
ohneta | 0:aae260bdcdd9 | 1039 | // name sure it's not still a number or integer |
ohneta | 0:aae260bdcdd9 | 1040 | flags = (flags&~SCRIPTVAR_VARTYPEMASK) | SCRIPTVAR_STRING; |
ohneta | 0:aae260bdcdd9 | 1041 | data = str; |
ohneta | 0:aae260bdcdd9 | 1042 | intData = 0; |
ohneta | 0:aae260bdcdd9 | 1043 | doubleData = 0; |
ohneta | 0:aae260bdcdd9 | 1044 | } |
ohneta | 0:aae260bdcdd9 | 1045 | |
ohneta | 0:aae260bdcdd9 | 1046 | void CScriptVar::setUndefined() { |
ohneta | 0:aae260bdcdd9 | 1047 | // name sure it's not still a number or integer |
ohneta | 0:aae260bdcdd9 | 1048 | flags = (flags&~SCRIPTVAR_VARTYPEMASK) | SCRIPTVAR_UNDEFINED; |
ohneta | 0:aae260bdcdd9 | 1049 | data = TINYJS_BLANK_DATA; |
ohneta | 0:aae260bdcdd9 | 1050 | intData = 0; |
ohneta | 0:aae260bdcdd9 | 1051 | doubleData = 0; |
ohneta | 0:aae260bdcdd9 | 1052 | removeAllChildren(); |
ohneta | 0:aae260bdcdd9 | 1053 | } |
ohneta | 0:aae260bdcdd9 | 1054 | |
ohneta | 0:aae260bdcdd9 | 1055 | void CScriptVar::setArray() { |
ohneta | 0:aae260bdcdd9 | 1056 | // name sure it's not still a number or integer |
ohneta | 0:aae260bdcdd9 | 1057 | flags = (flags&~SCRIPTVAR_VARTYPEMASK) | SCRIPTVAR_ARRAY; |
ohneta | 0:aae260bdcdd9 | 1058 | data = TINYJS_BLANK_DATA; |
ohneta | 0:aae260bdcdd9 | 1059 | intData = 0; |
ohneta | 0:aae260bdcdd9 | 1060 | doubleData = 0; |
ohneta | 0:aae260bdcdd9 | 1061 | removeAllChildren(); |
ohneta | 0:aae260bdcdd9 | 1062 | } |
ohneta | 0:aae260bdcdd9 | 1063 | |
ohneta | 0:aae260bdcdd9 | 1064 | bool CScriptVar::equals(CScriptVar *v) { |
ohneta | 0:aae260bdcdd9 | 1065 | CScriptVar *resV = mathsOp(v, LEX_EQUAL); |
ohneta | 0:aae260bdcdd9 | 1066 | bool res = resV->getBool(); |
ohneta | 0:aae260bdcdd9 | 1067 | delete resV; |
ohneta | 0:aae260bdcdd9 | 1068 | return res; |
ohneta | 0:aae260bdcdd9 | 1069 | } |
ohneta | 0:aae260bdcdd9 | 1070 | |
ohneta | 0:aae260bdcdd9 | 1071 | CScriptVar *CScriptVar::mathsOp(CScriptVar *b, int op) { |
ohneta | 0:aae260bdcdd9 | 1072 | CScriptVar *a = this; |
ohneta | 0:aae260bdcdd9 | 1073 | // Type equality check |
ohneta | 0:aae260bdcdd9 | 1074 | if (op == LEX_TYPEEQUAL || op == LEX_NTYPEEQUAL) { |
ohneta | 0:aae260bdcdd9 | 1075 | // check type first, then call again to check data |
ohneta | 0:aae260bdcdd9 | 1076 | bool eql = ((a->flags & SCRIPTVAR_VARTYPEMASK) == |
ohneta | 0:aae260bdcdd9 | 1077 | (b->flags & SCRIPTVAR_VARTYPEMASK)); |
ohneta | 0:aae260bdcdd9 | 1078 | if (eql) { |
ohneta | 0:aae260bdcdd9 | 1079 | CScriptVar *contents = a->mathsOp(b, LEX_EQUAL); |
ohneta | 0:aae260bdcdd9 | 1080 | if (!contents->getBool()) eql = false; |
ohneta | 0:aae260bdcdd9 | 1081 | if (!contents->refs) delete contents; |
ohneta | 0:aae260bdcdd9 | 1082 | } |
ohneta | 0:aae260bdcdd9 | 1083 | ; |
ohneta | 0:aae260bdcdd9 | 1084 | if (op == LEX_TYPEEQUAL) |
ohneta | 0:aae260bdcdd9 | 1085 | return new CScriptVar(eql); |
ohneta | 0:aae260bdcdd9 | 1086 | else |
ohneta | 0:aae260bdcdd9 | 1087 | return new CScriptVar(!eql); |
ohneta | 0:aae260bdcdd9 | 1088 | } |
ohneta | 0:aae260bdcdd9 | 1089 | // do maths... |
ohneta | 0:aae260bdcdd9 | 1090 | if (a->isUndefined() && b->isUndefined()) { |
ohneta | 0:aae260bdcdd9 | 1091 | if (op == LEX_EQUAL) return new CScriptVar(true); |
ohneta | 0:aae260bdcdd9 | 1092 | else if (op == LEX_NEQUAL) return new CScriptVar(false); |
ohneta | 0:aae260bdcdd9 | 1093 | else return new CScriptVar(); // undefined |
ohneta | 0:aae260bdcdd9 | 1094 | } else if ((a->isNumeric() || a->isUndefined()) && |
ohneta | 0:aae260bdcdd9 | 1095 | (b->isNumeric() || b->isUndefined())) { |
ohneta | 0:aae260bdcdd9 | 1096 | if (!a->isDouble() && !b->isDouble()) { |
ohneta | 0:aae260bdcdd9 | 1097 | // use ints |
ohneta | 0:aae260bdcdd9 | 1098 | int da = a->getInt(); |
ohneta | 0:aae260bdcdd9 | 1099 | int db = b->getInt(); |
ohneta | 0:aae260bdcdd9 | 1100 | switch (op) { |
ohneta | 0:aae260bdcdd9 | 1101 | case '+': return new CScriptVar(da+db); |
ohneta | 0:aae260bdcdd9 | 1102 | case '-': return new CScriptVar(da-db); |
ohneta | 0:aae260bdcdd9 | 1103 | case '*': return new CScriptVar(da*db); |
ohneta | 0:aae260bdcdd9 | 1104 | case '/': return new CScriptVar(da/db); |
ohneta | 0:aae260bdcdd9 | 1105 | case '&': return new CScriptVar(da&db); |
ohneta | 0:aae260bdcdd9 | 1106 | case '|': return new CScriptVar(da|db); |
ohneta | 0:aae260bdcdd9 | 1107 | case '^': return new CScriptVar(da^db); |
ohneta | 0:aae260bdcdd9 | 1108 | case '%': return new CScriptVar(da%db); |
ohneta | 0:aae260bdcdd9 | 1109 | case LEX_EQUAL: return new CScriptVar(da==db); |
ohneta | 0:aae260bdcdd9 | 1110 | case LEX_NEQUAL: return new CScriptVar(da!=db); |
ohneta | 0:aae260bdcdd9 | 1111 | case '<': return new CScriptVar(da<db); |
ohneta | 0:aae260bdcdd9 | 1112 | case LEX_LEQUAL: return new CScriptVar(da<=db); |
ohneta | 0:aae260bdcdd9 | 1113 | case '>': return new CScriptVar(da>db); |
ohneta | 0:aae260bdcdd9 | 1114 | case LEX_GEQUAL: return new CScriptVar(da>=db); |
ohneta | 0:aae260bdcdd9 | 1115 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1116 | default: throw new CScriptException("Operation "+CScriptLex::getTokenStr(op)+" not supported on the Int datatype"); |
ohneta | 0:aae260bdcdd9 | 1117 | #else |
ohneta | 0:aae260bdcdd9 | 1118 | default: |
ohneta | 0:aae260bdcdd9 | 1119 | mbedErrorFlag = 1; |
ohneta | 0:aae260bdcdd9 | 1120 | mbedErrorMessage = "Operation "; |
ohneta | 0:aae260bdcdd9 | 1121 | mbedErrorMessage += CScriptLex::getTokenStr(op); |
ohneta | 0:aae260bdcdd9 | 1122 | mbedErrorMessage += " not supported on the Int datatype"; |
ohneta | 0:aae260bdcdd9 | 1123 | return 0; |
ohneta | 0:aae260bdcdd9 | 1124 | #endif |
ohneta | 0:aae260bdcdd9 | 1125 | } |
ohneta | 0:aae260bdcdd9 | 1126 | } else { |
ohneta | 0:aae260bdcdd9 | 1127 | // use doubles |
ohneta | 0:aae260bdcdd9 | 1128 | double da = a->getDouble(); |
ohneta | 0:aae260bdcdd9 | 1129 | double db = b->getDouble(); |
ohneta | 0:aae260bdcdd9 | 1130 | switch (op) { |
ohneta | 0:aae260bdcdd9 | 1131 | case '+': return new CScriptVar(da+db); |
ohneta | 0:aae260bdcdd9 | 1132 | case '-': return new CScriptVar(da-db); |
ohneta | 0:aae260bdcdd9 | 1133 | case '*': return new CScriptVar(da*db); |
ohneta | 0:aae260bdcdd9 | 1134 | case '/': return new CScriptVar(da/db); |
ohneta | 0:aae260bdcdd9 | 1135 | case LEX_EQUAL: return new CScriptVar(da==db); |
ohneta | 0:aae260bdcdd9 | 1136 | case LEX_NEQUAL: return new CScriptVar(da!=db); |
ohneta | 0:aae260bdcdd9 | 1137 | case '<': return new CScriptVar(da<db); |
ohneta | 0:aae260bdcdd9 | 1138 | case LEX_LEQUAL: return new CScriptVar(da<=db); |
ohneta | 0:aae260bdcdd9 | 1139 | case '>': return new CScriptVar(da>db); |
ohneta | 0:aae260bdcdd9 | 1140 | case LEX_GEQUAL: return new CScriptVar(da>=db); |
ohneta | 0:aae260bdcdd9 | 1141 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1142 | default: throw new CScriptException("Operation "+CScriptLex::getTokenStr(op)+" not supported on the Double datatype"); |
ohneta | 0:aae260bdcdd9 | 1143 | #else |
ohneta | 0:aae260bdcdd9 | 1144 | default: |
ohneta | 0:aae260bdcdd9 | 1145 | mbedErrorFlag = 1; |
ohneta | 0:aae260bdcdd9 | 1146 | mbedErrorMessage = "Operation "; |
ohneta | 0:aae260bdcdd9 | 1147 | mbedErrorMessage += CScriptLex::getTokenStr(op); |
ohneta | 0:aae260bdcdd9 | 1148 | mbedErrorMessage += " not supported on the Double datatype"; |
ohneta | 0:aae260bdcdd9 | 1149 | return 0; |
ohneta | 0:aae260bdcdd9 | 1150 | #endif |
ohneta | 0:aae260bdcdd9 | 1151 | } |
ohneta | 0:aae260bdcdd9 | 1152 | } |
ohneta | 0:aae260bdcdd9 | 1153 | } else if (a->isArray()) { |
ohneta | 0:aae260bdcdd9 | 1154 | /* Just check pointers */ |
ohneta | 0:aae260bdcdd9 | 1155 | switch (op) { |
ohneta | 0:aae260bdcdd9 | 1156 | case LEX_EQUAL: return new CScriptVar(a==b); |
ohneta | 0:aae260bdcdd9 | 1157 | case LEX_NEQUAL: return new CScriptVar(a!=b); |
ohneta | 0:aae260bdcdd9 | 1158 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1159 | default: throw new CScriptException("Operation "+CScriptLex::getTokenStr(op)+" not supported on the Array datatype"); |
ohneta | 0:aae260bdcdd9 | 1160 | #else |
ohneta | 0:aae260bdcdd9 | 1161 | default: |
ohneta | 0:aae260bdcdd9 | 1162 | mbedErrorFlag = 1;; |
ohneta | 0:aae260bdcdd9 | 1163 | mbedErrorMessage = "Operation "; |
ohneta | 0:aae260bdcdd9 | 1164 | mbedErrorMessage += CScriptLex::getTokenStr(op); |
ohneta | 0:aae260bdcdd9 | 1165 | mbedErrorMessage += " not supported on the Array datatype"; |
ohneta | 0:aae260bdcdd9 | 1166 | return 0; |
ohneta | 0:aae260bdcdd9 | 1167 | |
ohneta | 0:aae260bdcdd9 | 1168 | #endif |
ohneta | 0:aae260bdcdd9 | 1169 | } |
ohneta | 0:aae260bdcdd9 | 1170 | } else if (a->isObject()) { |
ohneta | 0:aae260bdcdd9 | 1171 | /* Just check pointers */ |
ohneta | 0:aae260bdcdd9 | 1172 | switch (op) { |
ohneta | 0:aae260bdcdd9 | 1173 | case LEX_EQUAL: return new CScriptVar(a==b); |
ohneta | 0:aae260bdcdd9 | 1174 | case LEX_NEQUAL: return new CScriptVar(a!=b); |
ohneta | 0:aae260bdcdd9 | 1175 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1176 | default: throw new CScriptException("Operation "+CScriptLex::getTokenStr(op)+" not supported on the Object datatype"); |
ohneta | 0:aae260bdcdd9 | 1177 | #else |
ohneta | 0:aae260bdcdd9 | 1178 | default: |
ohneta | 0:aae260bdcdd9 | 1179 | mbedErrorFlag = 1; |
ohneta | 0:aae260bdcdd9 | 1180 | mbedErrorMessage = "Operation "; |
ohneta | 0:aae260bdcdd9 | 1181 | mbedErrorMessage += CScriptLex::getTokenStr(op); |
ohneta | 0:aae260bdcdd9 | 1182 | mbedErrorMessage += " not supported on the Object datatype"; |
ohneta | 0:aae260bdcdd9 | 1183 | return 0; |
ohneta | 0:aae260bdcdd9 | 1184 | #endif |
ohneta | 0:aae260bdcdd9 | 1185 | } |
ohneta | 0:aae260bdcdd9 | 1186 | } else { |
ohneta | 0:aae260bdcdd9 | 1187 | string da = a->getString(); |
ohneta | 0:aae260bdcdd9 | 1188 | string db = b->getString(); |
ohneta | 0:aae260bdcdd9 | 1189 | // use strings |
ohneta | 0:aae260bdcdd9 | 1190 | switch (op) { |
ohneta | 0:aae260bdcdd9 | 1191 | case '+': return new CScriptVar(da+db, SCRIPTVAR_STRING); |
ohneta | 0:aae260bdcdd9 | 1192 | case LEX_EQUAL: return new CScriptVar(da==db); |
ohneta | 0:aae260bdcdd9 | 1193 | case LEX_NEQUAL: return new CScriptVar(da!=db); |
ohneta | 0:aae260bdcdd9 | 1194 | case '<': return new CScriptVar(da<db); |
ohneta | 0:aae260bdcdd9 | 1195 | case LEX_LEQUAL: return new CScriptVar(da<=db); |
ohneta | 0:aae260bdcdd9 | 1196 | case '>': return new CScriptVar(da>db); |
ohneta | 0:aae260bdcdd9 | 1197 | case LEX_GEQUAL: return new CScriptVar(da>=db); |
ohneta | 0:aae260bdcdd9 | 1198 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1199 | default: throw new CScriptException("Operation "+CScriptLex::getTokenStr(op)+" not supported on the string datatype"); |
ohneta | 0:aae260bdcdd9 | 1200 | #else |
ohneta | 0:aae260bdcdd9 | 1201 | default: |
ohneta | 0:aae260bdcdd9 | 1202 | mbedErrorFlag = 1; |
ohneta | 0:aae260bdcdd9 | 1203 | mbedErrorMessage = "Operation "; |
ohneta | 0:aae260bdcdd9 | 1204 | mbedErrorMessage += CScriptLex::getTokenStr(op); |
ohneta | 0:aae260bdcdd9 | 1205 | mbedErrorMessage += " not supported on the string datatype"; |
ohneta | 0:aae260bdcdd9 | 1206 | return 0; |
ohneta | 0:aae260bdcdd9 | 1207 | #endif |
ohneta | 0:aae260bdcdd9 | 1208 | } |
ohneta | 0:aae260bdcdd9 | 1209 | } |
ohneta | 0:aae260bdcdd9 | 1210 | ASSERT(0); |
ohneta | 0:aae260bdcdd9 | 1211 | return 0; |
ohneta | 0:aae260bdcdd9 | 1212 | } |
ohneta | 0:aae260bdcdd9 | 1213 | |
ohneta | 0:aae260bdcdd9 | 1214 | void CScriptVar::copySimpleData(CScriptVar *val) { |
ohneta | 0:aae260bdcdd9 | 1215 | data = val->data; |
ohneta | 0:aae260bdcdd9 | 1216 | intData = val->intData; |
ohneta | 0:aae260bdcdd9 | 1217 | doubleData = val->doubleData; |
ohneta | 0:aae260bdcdd9 | 1218 | flags = (flags & ~SCRIPTVAR_VARTYPEMASK) | (val->flags & SCRIPTVAR_VARTYPEMASK); |
ohneta | 0:aae260bdcdd9 | 1219 | } |
ohneta | 0:aae260bdcdd9 | 1220 | |
ohneta | 0:aae260bdcdd9 | 1221 | void CScriptVar::copyValue(CScriptVar *val) { |
ohneta | 0:aae260bdcdd9 | 1222 | if (val) { |
ohneta | 0:aae260bdcdd9 | 1223 | copySimpleData(val); |
ohneta | 0:aae260bdcdd9 | 1224 | // remove all current children |
ohneta | 0:aae260bdcdd9 | 1225 | removeAllChildren(); |
ohneta | 0:aae260bdcdd9 | 1226 | // copy children of 'val' |
ohneta | 0:aae260bdcdd9 | 1227 | CScriptVarLink *child = val->firstChild; |
ohneta | 0:aae260bdcdd9 | 1228 | while (child) { |
ohneta | 0:aae260bdcdd9 | 1229 | CScriptVar *copied; |
ohneta | 0:aae260bdcdd9 | 1230 | // don't copy the 'parent' object... |
ohneta | 0:aae260bdcdd9 | 1231 | if (child->name != TINYJS_PROTOTYPE_CLASS) |
ohneta | 0:aae260bdcdd9 | 1232 | copied = child->var->deepCopy(); |
ohneta | 0:aae260bdcdd9 | 1233 | else |
ohneta | 0:aae260bdcdd9 | 1234 | copied = child->var; |
ohneta | 0:aae260bdcdd9 | 1235 | |
ohneta | 0:aae260bdcdd9 | 1236 | addChild(child->name, copied); |
ohneta | 0:aae260bdcdd9 | 1237 | |
ohneta | 0:aae260bdcdd9 | 1238 | child = child->nextSibling; |
ohneta | 0:aae260bdcdd9 | 1239 | } |
ohneta | 0:aae260bdcdd9 | 1240 | } else { |
ohneta | 0:aae260bdcdd9 | 1241 | setUndefined(); |
ohneta | 0:aae260bdcdd9 | 1242 | } |
ohneta | 0:aae260bdcdd9 | 1243 | } |
ohneta | 0:aae260bdcdd9 | 1244 | |
ohneta | 0:aae260bdcdd9 | 1245 | CScriptVar *CScriptVar::deepCopy() { |
ohneta | 0:aae260bdcdd9 | 1246 | CScriptVar *newVar = new CScriptVar(); |
ohneta | 0:aae260bdcdd9 | 1247 | newVar->copySimpleData(this); |
ohneta | 0:aae260bdcdd9 | 1248 | // copy children |
ohneta | 0:aae260bdcdd9 | 1249 | CScriptVarLink *child = firstChild; |
ohneta | 0:aae260bdcdd9 | 1250 | while (child) { |
ohneta | 0:aae260bdcdd9 | 1251 | CScriptVar *copied; |
ohneta | 0:aae260bdcdd9 | 1252 | // don't copy the 'parent' object... |
ohneta | 0:aae260bdcdd9 | 1253 | if (child->name != TINYJS_PROTOTYPE_CLASS) |
ohneta | 0:aae260bdcdd9 | 1254 | copied = child->var->deepCopy(); |
ohneta | 0:aae260bdcdd9 | 1255 | else |
ohneta | 0:aae260bdcdd9 | 1256 | copied = child->var; |
ohneta | 0:aae260bdcdd9 | 1257 | |
ohneta | 0:aae260bdcdd9 | 1258 | newVar->addChild(child->name, copied); |
ohneta | 0:aae260bdcdd9 | 1259 | child = child->nextSibling; |
ohneta | 0:aae260bdcdd9 | 1260 | } |
ohneta | 0:aae260bdcdd9 | 1261 | return newVar; |
ohneta | 0:aae260bdcdd9 | 1262 | } |
ohneta | 0:aae260bdcdd9 | 1263 | |
ohneta | 0:aae260bdcdd9 | 1264 | void CScriptVar::trace(string indentStr, const string &name) { |
ohneta | 0:aae260bdcdd9 | 1265 | TRACE("%s'%s' = '%s' %s\n", |
ohneta | 0:aae260bdcdd9 | 1266 | indentStr.c_str(), |
ohneta | 0:aae260bdcdd9 | 1267 | name.c_str(), |
ohneta | 0:aae260bdcdd9 | 1268 | getString().c_str(), |
ohneta | 0:aae260bdcdd9 | 1269 | getFlagsAsString().c_str()); |
ohneta | 0:aae260bdcdd9 | 1270 | string indent = indentStr+" "; |
ohneta | 0:aae260bdcdd9 | 1271 | CScriptVarLink *link = firstChild; |
ohneta | 0:aae260bdcdd9 | 1272 | while (link) { |
ohneta | 0:aae260bdcdd9 | 1273 | link->var->trace(indent, link->name); |
ohneta | 0:aae260bdcdd9 | 1274 | link = link->nextSibling; |
ohneta | 0:aae260bdcdd9 | 1275 | } |
ohneta | 0:aae260bdcdd9 | 1276 | } |
ohneta | 0:aae260bdcdd9 | 1277 | |
ohneta | 0:aae260bdcdd9 | 1278 | string CScriptVar::getFlagsAsString() { |
ohneta | 0:aae260bdcdd9 | 1279 | string flagstr = ""; |
ohneta | 0:aae260bdcdd9 | 1280 | if (flags&SCRIPTVAR_FUNCTION) flagstr = flagstr + "FUNCTION "; |
ohneta | 0:aae260bdcdd9 | 1281 | if (flags&SCRIPTVAR_OBJECT) flagstr = flagstr + "OBJECT "; |
ohneta | 0:aae260bdcdd9 | 1282 | if (flags&SCRIPTVAR_ARRAY) flagstr = flagstr + "ARRAY "; |
ohneta | 0:aae260bdcdd9 | 1283 | if (flags&SCRIPTVAR_NATIVE) flagstr = flagstr + "NATIVE "; |
ohneta | 0:aae260bdcdd9 | 1284 | if (flags&SCRIPTVAR_DOUBLE) flagstr = flagstr + "DOUBLE "; |
ohneta | 0:aae260bdcdd9 | 1285 | if (flags&SCRIPTVAR_INTEGER) flagstr = flagstr + "INTEGER "; |
ohneta | 0:aae260bdcdd9 | 1286 | if (flags&SCRIPTVAR_STRING) flagstr = flagstr + "STRING "; |
ohneta | 0:aae260bdcdd9 | 1287 | return flagstr; |
ohneta | 0:aae260bdcdd9 | 1288 | } |
ohneta | 0:aae260bdcdd9 | 1289 | |
ohneta | 0:aae260bdcdd9 | 1290 | string CScriptVar::getParsableString() { |
ohneta | 0:aae260bdcdd9 | 1291 | // Numbers can just be put in directly |
ohneta | 0:aae260bdcdd9 | 1292 | if (isNumeric()) |
ohneta | 0:aae260bdcdd9 | 1293 | return getString(); |
ohneta | 0:aae260bdcdd9 | 1294 | if (isFunction()) { |
ohneta | 0:aae260bdcdd9 | 1295 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1296 | ostringstream funcStr; |
ohneta | 0:aae260bdcdd9 | 1297 | funcStr << "function ("; |
ohneta | 0:aae260bdcdd9 | 1298 | // get list of parameters |
ohneta | 0:aae260bdcdd9 | 1299 | CScriptVarLink *link = firstChild; |
ohneta | 0:aae260bdcdd9 | 1300 | while (link) { |
ohneta | 0:aae260bdcdd9 | 1301 | funcStr << link->name; |
ohneta | 0:aae260bdcdd9 | 1302 | if (link->nextSibling) funcStr << ","; |
ohneta | 0:aae260bdcdd9 | 1303 | link = link->nextSibling; |
ohneta | 0:aae260bdcdd9 | 1304 | } |
ohneta | 0:aae260bdcdd9 | 1305 | // add function body |
ohneta | 0:aae260bdcdd9 | 1306 | funcStr << ") " << getString(); |
ohneta | 0:aae260bdcdd9 | 1307 | return funcStr.str(); |
ohneta | 0:aae260bdcdd9 | 1308 | #else |
ohneta | 0:aae260bdcdd9 | 1309 | string funcStr; |
ohneta | 0:aae260bdcdd9 | 1310 | funcStr = "function ("; |
ohneta | 0:aae260bdcdd9 | 1311 | CScriptVarLink *link = firstChild; |
ohneta | 0:aae260bdcdd9 | 1312 | while (link) { |
ohneta | 0:aae260bdcdd9 | 1313 | funcStr += link->name; |
ohneta | 0:aae260bdcdd9 | 1314 | if (link->nextSibling) funcStr += ","; |
ohneta | 0:aae260bdcdd9 | 1315 | link = link->nextSibling; |
ohneta | 0:aae260bdcdd9 | 1316 | } |
ohneta | 0:aae260bdcdd9 | 1317 | // add function body |
ohneta | 0:aae260bdcdd9 | 1318 | funcStr += ") "; |
ohneta | 0:aae260bdcdd9 | 1319 | funcStr += getString(); |
ohneta | 0:aae260bdcdd9 | 1320 | return funcStr; |
ohneta | 0:aae260bdcdd9 | 1321 | #endif |
ohneta | 0:aae260bdcdd9 | 1322 | } |
ohneta | 0:aae260bdcdd9 | 1323 | // if it is a string then we quote it |
ohneta | 0:aae260bdcdd9 | 1324 | if (isString()) |
ohneta | 0:aae260bdcdd9 | 1325 | return getJSString(getString()); |
ohneta | 0:aae260bdcdd9 | 1326 | if (isNull()) |
ohneta | 0:aae260bdcdd9 | 1327 | return "null"; |
ohneta | 0:aae260bdcdd9 | 1328 | return "undefined"; |
ohneta | 0:aae260bdcdd9 | 1329 | } |
ohneta | 0:aae260bdcdd9 | 1330 | |
ohneta | 0:aae260bdcdd9 | 1331 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1332 | void CScriptVar::getJSON(ostringstream &destination, const string linePrefix) { |
ohneta | 0:aae260bdcdd9 | 1333 | if (isObject()) { |
ohneta | 0:aae260bdcdd9 | 1334 | string indentedLinePrefix = linePrefix+" "; |
ohneta | 0:aae260bdcdd9 | 1335 | // children - handle with bracketed list |
ohneta | 0:aae260bdcdd9 | 1336 | destination << "{ \n"; |
ohneta | 0:aae260bdcdd9 | 1337 | CScriptVarLink *link = firstChild; |
ohneta | 0:aae260bdcdd9 | 1338 | while (link) { |
ohneta | 0:aae260bdcdd9 | 1339 | destination << indentedLinePrefix; |
ohneta | 0:aae260bdcdd9 | 1340 | destination << getJSString(link->name); |
ohneta | 0:aae260bdcdd9 | 1341 | destination << " : "; |
ohneta | 0:aae260bdcdd9 | 1342 | link->var->getJSON(destination, indentedLinePrefix); |
ohneta | 0:aae260bdcdd9 | 1343 | link = link->nextSibling; |
ohneta | 0:aae260bdcdd9 | 1344 | if (link) { |
ohneta | 0:aae260bdcdd9 | 1345 | destination << ",\n"; |
ohneta | 0:aae260bdcdd9 | 1346 | } |
ohneta | 0:aae260bdcdd9 | 1347 | } |
ohneta | 0:aae260bdcdd9 | 1348 | destination << "\n" << linePrefix << "}"; |
ohneta | 0:aae260bdcdd9 | 1349 | } else if (isArray()) { |
ohneta | 0:aae260bdcdd9 | 1350 | string indentedLinePrefix = linePrefix+" "; |
ohneta | 0:aae260bdcdd9 | 1351 | destination << "[\n"; |
ohneta | 0:aae260bdcdd9 | 1352 | int len = getArrayLength(); |
ohneta | 0:aae260bdcdd9 | 1353 | if (len>10000) len=10000; // we don't want to get stuck here! |
ohneta | 0:aae260bdcdd9 | 1354 | |
ohneta | 0:aae260bdcdd9 | 1355 | for (int i=0;i<len;i++) { |
ohneta | 0:aae260bdcdd9 | 1356 | getArrayIndex(i)->getJSON(destination, indentedLinePrefix); |
ohneta | 0:aae260bdcdd9 | 1357 | if (i<len-1) destination << ",\n"; |
ohneta | 0:aae260bdcdd9 | 1358 | } |
ohneta | 0:aae260bdcdd9 | 1359 | |
ohneta | 0:aae260bdcdd9 | 1360 | destination << "\n" << linePrefix << "]"; |
ohneta | 0:aae260bdcdd9 | 1361 | } else { |
ohneta | 0:aae260bdcdd9 | 1362 | // no children or a function... just write value directly |
ohneta | 0:aae260bdcdd9 | 1363 | destination << getParsableString(); |
ohneta | 0:aae260bdcdd9 | 1364 | } |
ohneta | 0:aae260bdcdd9 | 1365 | } |
ohneta | 0:aae260bdcdd9 | 1366 | #else |
ohneta | 0:aae260bdcdd9 | 1367 | void CScriptVar::getJSON(string &destination, const string linePrefix) { |
ohneta | 0:aae260bdcdd9 | 1368 | if (isObject()) { |
ohneta | 0:aae260bdcdd9 | 1369 | string indentedLinePrefix = linePrefix+" "; |
ohneta | 0:aae260bdcdd9 | 1370 | // children - handle with bracketed list |
ohneta | 0:aae260bdcdd9 | 1371 | destination += "{ \n"; |
ohneta | 0:aae260bdcdd9 | 1372 | CScriptVarLink *link = firstChild; |
ohneta | 0:aae260bdcdd9 | 1373 | while (link) { |
ohneta | 0:aae260bdcdd9 | 1374 | destination += indentedLinePrefix; |
ohneta | 0:aae260bdcdd9 | 1375 | destination += getJSString(link->name); |
ohneta | 0:aae260bdcdd9 | 1376 | destination += " : "; |
ohneta | 0:aae260bdcdd9 | 1377 | link->var->getJSON(destination, indentedLinePrefix); |
ohneta | 0:aae260bdcdd9 | 1378 | link = link->nextSibling; |
ohneta | 0:aae260bdcdd9 | 1379 | if (link) { |
ohneta | 0:aae260bdcdd9 | 1380 | destination += ",\n"; |
ohneta | 0:aae260bdcdd9 | 1381 | } |
ohneta | 0:aae260bdcdd9 | 1382 | } |
ohneta | 0:aae260bdcdd9 | 1383 | destination += "\n"; |
ohneta | 0:aae260bdcdd9 | 1384 | destination += linePrefix; |
ohneta | 0:aae260bdcdd9 | 1385 | destination += "}"; |
ohneta | 0:aae260bdcdd9 | 1386 | } else if (isArray()) { |
ohneta | 0:aae260bdcdd9 | 1387 | string indentedLinePrefix = linePrefix+" "; |
ohneta | 0:aae260bdcdd9 | 1388 | destination + "[\n"; |
ohneta | 0:aae260bdcdd9 | 1389 | int len = getArrayLength(); |
ohneta | 0:aae260bdcdd9 | 1390 | if (len>10000) len=10000; // we don't want to get stuck here! |
ohneta | 0:aae260bdcdd9 | 1391 | |
ohneta | 0:aae260bdcdd9 | 1392 | for (int i=0;i<len;i++) { |
ohneta | 0:aae260bdcdd9 | 1393 | getArrayIndex(i)->getJSON(destination, indentedLinePrefix); |
ohneta | 0:aae260bdcdd9 | 1394 | if (i<len-1) { |
ohneta | 0:aae260bdcdd9 | 1395 | destination += ",\n"; |
ohneta | 0:aae260bdcdd9 | 1396 | } |
ohneta | 0:aae260bdcdd9 | 1397 | } |
ohneta | 0:aae260bdcdd9 | 1398 | |
ohneta | 0:aae260bdcdd9 | 1399 | destination += "\n"; |
ohneta | 0:aae260bdcdd9 | 1400 | destination += linePrefix; |
ohneta | 0:aae260bdcdd9 | 1401 | destination += "]"; |
ohneta | 0:aae260bdcdd9 | 1402 | } else { |
ohneta | 0:aae260bdcdd9 | 1403 | // no children or a function... just write value directly |
ohneta | 0:aae260bdcdd9 | 1404 | destination += getParsableString(); |
ohneta | 0:aae260bdcdd9 | 1405 | } |
ohneta | 0:aae260bdcdd9 | 1406 | } |
ohneta | 0:aae260bdcdd9 | 1407 | #endif |
ohneta | 0:aae260bdcdd9 | 1408 | |
ohneta | 0:aae260bdcdd9 | 1409 | void CScriptVar::setCallback(JSCallback callback, void *userdata) { |
ohneta | 0:aae260bdcdd9 | 1410 | jsCallback = callback; |
ohneta | 0:aae260bdcdd9 | 1411 | jsCallbackUserData = userdata; |
ohneta | 0:aae260bdcdd9 | 1412 | } |
ohneta | 0:aae260bdcdd9 | 1413 | |
ohneta | 0:aae260bdcdd9 | 1414 | CScriptVar *CScriptVar::ref() { |
ohneta | 0:aae260bdcdd9 | 1415 | refs++; |
ohneta | 0:aae260bdcdd9 | 1416 | return this; |
ohneta | 0:aae260bdcdd9 | 1417 | } |
ohneta | 0:aae260bdcdd9 | 1418 | |
ohneta | 0:aae260bdcdd9 | 1419 | void CScriptVar::unref() { |
ohneta | 0:aae260bdcdd9 | 1420 | if (refs<=0) printf("OMFG, we have unreffed too far!\n"); |
ohneta | 0:aae260bdcdd9 | 1421 | if ((--refs)==0) { |
ohneta | 0:aae260bdcdd9 | 1422 | delete this; |
ohneta | 0:aae260bdcdd9 | 1423 | } |
ohneta | 0:aae260bdcdd9 | 1424 | } |
ohneta | 0:aae260bdcdd9 | 1425 | |
ohneta | 0:aae260bdcdd9 | 1426 | int CScriptVar::getRefs() { |
ohneta | 0:aae260bdcdd9 | 1427 | return refs; |
ohneta | 0:aae260bdcdd9 | 1428 | } |
ohneta | 0:aae260bdcdd9 | 1429 | |
ohneta | 0:aae260bdcdd9 | 1430 | |
ohneta | 0:aae260bdcdd9 | 1431 | // ----------------------------------------------------------------------------------- CSCRIPT |
ohneta | 0:aae260bdcdd9 | 1432 | |
ohneta | 0:aae260bdcdd9 | 1433 | CTinyJS::CTinyJS() { |
ohneta | 0:aae260bdcdd9 | 1434 | l = 0; |
ohneta | 0:aae260bdcdd9 | 1435 | root = (new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT))->ref(); |
ohneta | 0:aae260bdcdd9 | 1436 | // Add built-in classes |
ohneta | 0:aae260bdcdd9 | 1437 | stringClass = (new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT))->ref(); |
ohneta | 0:aae260bdcdd9 | 1438 | arrayClass = (new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT))->ref(); |
ohneta | 0:aae260bdcdd9 | 1439 | objectClass = (new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT))->ref(); |
ohneta | 0:aae260bdcdd9 | 1440 | root->addChild("String", stringClass); |
ohneta | 0:aae260bdcdd9 | 1441 | root->addChild("Array", arrayClass); |
ohneta | 0:aae260bdcdd9 | 1442 | root->addChild("Object", objectClass); |
ohneta | 0:aae260bdcdd9 | 1443 | } |
ohneta | 0:aae260bdcdd9 | 1444 | |
ohneta | 0:aae260bdcdd9 | 1445 | CTinyJS::~CTinyJS() { |
ohneta | 0:aae260bdcdd9 | 1446 | ASSERT(!l); |
ohneta | 0:aae260bdcdd9 | 1447 | scopes.clear(); |
ohneta | 0:aae260bdcdd9 | 1448 | stringClass->unref(); |
ohneta | 0:aae260bdcdd9 | 1449 | arrayClass->unref(); |
ohneta | 0:aae260bdcdd9 | 1450 | objectClass->unref(); |
ohneta | 0:aae260bdcdd9 | 1451 | root->unref(); |
ohneta | 0:aae260bdcdd9 | 1452 | |
ohneta | 0:aae260bdcdd9 | 1453 | #if DEBUG_MEMORY |
ohneta | 0:aae260bdcdd9 | 1454 | show_allocated(); |
ohneta | 0:aae260bdcdd9 | 1455 | #endif |
ohneta | 0:aae260bdcdd9 | 1456 | } |
ohneta | 0:aae260bdcdd9 | 1457 | |
ohneta | 0:aae260bdcdd9 | 1458 | void CTinyJS::trace() { |
ohneta | 0:aae260bdcdd9 | 1459 | root->trace(); |
ohneta | 0:aae260bdcdd9 | 1460 | } |
ohneta | 0:aae260bdcdd9 | 1461 | |
ohneta | 0:aae260bdcdd9 | 1462 | void CTinyJS::execute(const string &code) { |
ohneta | 0:aae260bdcdd9 | 1463 | CScriptLex *oldLex = l; |
ohneta | 0:aae260bdcdd9 | 1464 | vector<CScriptVar*> oldScopes = scopes; |
ohneta | 0:aae260bdcdd9 | 1465 | l = new CScriptLex(code); |
ohneta | 0:aae260bdcdd9 | 1466 | #ifdef TINYJS_CALL_STACK |
ohneta | 0:aae260bdcdd9 | 1467 | call_stack.clear(); |
ohneta | 0:aae260bdcdd9 | 1468 | #endif |
ohneta | 0:aae260bdcdd9 | 1469 | scopes.clear(); |
ohneta | 0:aae260bdcdd9 | 1470 | scopes.push_back(root); |
ohneta | 0:aae260bdcdd9 | 1471 | |
ohneta | 0:aae260bdcdd9 | 1472 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1473 | try { |
ohneta | 0:aae260bdcdd9 | 1474 | bool execute = true; |
ohneta | 0:aae260bdcdd9 | 1475 | while (l->tk) statement(execute); |
ohneta | 0:aae260bdcdd9 | 1476 | } catch (CScriptException *e) { |
ohneta | 0:aae260bdcdd9 | 1477 | ostringstream msg; |
ohneta | 0:aae260bdcdd9 | 1478 | msg << "Error " << e->text; |
ohneta | 0:aae260bdcdd9 | 1479 | #ifdef TINYJS_CALL_STACK |
ohneta | 0:aae260bdcdd9 | 1480 | for (int i=(int)call_stack.size()-1;i>=0;i--) |
ohneta | 0:aae260bdcdd9 | 1481 | msg << "\n" << i << ": " << call_stack.at(i); |
ohneta | 0:aae260bdcdd9 | 1482 | #endif |
ohneta | 0:aae260bdcdd9 | 1483 | msg << " at " << l->getPosition(); |
ohneta | 0:aae260bdcdd9 | 1484 | delete l; |
ohneta | 0:aae260bdcdd9 | 1485 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 1486 | |
ohneta | 0:aae260bdcdd9 | 1487 | throw new CScriptException(msg.str()); |
ohneta | 0:aae260bdcdd9 | 1488 | } |
ohneta | 0:aae260bdcdd9 | 1489 | #else |
ohneta | 0:aae260bdcdd9 | 1490 | { |
ohneta | 0:aae260bdcdd9 | 1491 | bool execute = true; |
ohneta | 0:aae260bdcdd9 | 1492 | while (l->tk) { |
ohneta | 0:aae260bdcdd9 | 1493 | mbedErrorFlag = 0; |
ohneta | 0:aae260bdcdd9 | 1494 | statement(execute); |
ohneta | 0:aae260bdcdd9 | 1495 | if (mbedErrorFlag != 0) { |
ohneta | 0:aae260bdcdd9 | 1496 | string msg; |
ohneta | 0:aae260bdcdd9 | 1497 | msg = "Error "; |
ohneta | 0:aae260bdcdd9 | 1498 | msg += mbedErrorMessage; |
ohneta | 0:aae260bdcdd9 | 1499 | #ifdef TINYJS_CALL_STACK |
ohneta | 0:aae260bdcdd9 | 1500 | for (int i=(int)call_stack.size()-1;i>=0;i--) { |
ohneta | 0:aae260bdcdd9 | 1501 | msg += "\n"; |
ohneta | 0:aae260bdcdd9 | 1502 | msg += i; |
ohneta | 0:aae260bdcdd9 | 1503 | msg += ": "; |
ohneta | 0:aae260bdcdd9 | 1504 | msg += call_stack.at(i); |
ohneta | 0:aae260bdcdd9 | 1505 | } |
ohneta | 0:aae260bdcdd9 | 1506 | #endif |
ohneta | 0:aae260bdcdd9 | 1507 | msg += " at "; |
ohneta | 0:aae260bdcdd9 | 1508 | msg += l->getPosition(); |
ohneta | 0:aae260bdcdd9 | 1509 | |
ohneta | 0:aae260bdcdd9 | 1510 | delete l; |
ohneta | 0:aae260bdcdd9 | 1511 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 1512 | |
ohneta | 0:aae260bdcdd9 | 1513 | mbedErrorFlag = 1; |
ohneta | 0:aae260bdcdd9 | 1514 | mbedErrorMessage = msg; |
ohneta | 0:aae260bdcdd9 | 1515 | return; |
ohneta | 0:aae260bdcdd9 | 1516 | } |
ohneta | 0:aae260bdcdd9 | 1517 | } |
ohneta | 0:aae260bdcdd9 | 1518 | } |
ohneta | 0:aae260bdcdd9 | 1519 | #endif |
ohneta | 0:aae260bdcdd9 | 1520 | |
ohneta | 0:aae260bdcdd9 | 1521 | |
ohneta | 0:aae260bdcdd9 | 1522 | delete l; |
ohneta | 0:aae260bdcdd9 | 1523 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 1524 | scopes = oldScopes; |
ohneta | 0:aae260bdcdd9 | 1525 | } |
ohneta | 0:aae260bdcdd9 | 1526 | |
ohneta | 0:aae260bdcdd9 | 1527 | CScriptVarLink CTinyJS::evaluateComplex(const string &code) { |
ohneta | 0:aae260bdcdd9 | 1528 | CScriptLex *oldLex = l; |
ohneta | 0:aae260bdcdd9 | 1529 | vector<CScriptVar*> oldScopes = scopes; |
ohneta | 0:aae260bdcdd9 | 1530 | |
ohneta | 0:aae260bdcdd9 | 1531 | l = new CScriptLex(code); |
ohneta | 0:aae260bdcdd9 | 1532 | #ifdef TINYJS_CALL_STACK |
ohneta | 0:aae260bdcdd9 | 1533 | call_stack.clear(); |
ohneta | 0:aae260bdcdd9 | 1534 | #endif |
ohneta | 0:aae260bdcdd9 | 1535 | scopes.clear(); |
ohneta | 0:aae260bdcdd9 | 1536 | scopes.push_back(root); |
ohneta | 0:aae260bdcdd9 | 1537 | CScriptVarLink *v = 0; |
ohneta | 0:aae260bdcdd9 | 1538 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1539 | try { |
ohneta | 0:aae260bdcdd9 | 1540 | bool execute = true; |
ohneta | 0:aae260bdcdd9 | 1541 | do { |
ohneta | 0:aae260bdcdd9 | 1542 | CLEAN(v); |
ohneta | 0:aae260bdcdd9 | 1543 | v = base(execute); |
ohneta | 0:aae260bdcdd9 | 1544 | if (l->tk!=LEX_EOF) l->match(';'); |
ohneta | 0:aae260bdcdd9 | 1545 | } while (l->tk!=LEX_EOF); |
ohneta | 0:aae260bdcdd9 | 1546 | } catch (CScriptException *e) { |
ohneta | 0:aae260bdcdd9 | 1547 | ostringstream msg; |
ohneta | 0:aae260bdcdd9 | 1548 | msg << "Error " << e->text; |
ohneta | 0:aae260bdcdd9 | 1549 | #ifdef TINYJS_CALL_STACK |
ohneta | 0:aae260bdcdd9 | 1550 | for (int i=(int)call_stack.size()-1;i>=0;i--) |
ohneta | 0:aae260bdcdd9 | 1551 | msg << "\n" << i << ": " << call_stack.at(i); |
ohneta | 0:aae260bdcdd9 | 1552 | #endif |
ohneta | 0:aae260bdcdd9 | 1553 | msg << " at " << l->getPosition(); |
ohneta | 0:aae260bdcdd9 | 1554 | delete l; |
ohneta | 0:aae260bdcdd9 | 1555 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 1556 | |
ohneta | 0:aae260bdcdd9 | 1557 | throw new CScriptException(msg.str()); |
ohneta | 0:aae260bdcdd9 | 1558 | } |
ohneta | 0:aae260bdcdd9 | 1559 | #else |
ohneta | 0:aae260bdcdd9 | 1560 | { |
ohneta | 0:aae260bdcdd9 | 1561 | bool execute = true; |
ohneta | 0:aae260bdcdd9 | 1562 | do { |
ohneta | 0:aae260bdcdd9 | 1563 | CLEAN(v); |
ohneta | 0:aae260bdcdd9 | 1564 | mbedErrorFlag = 0; |
ohneta | 0:aae260bdcdd9 | 1565 | v = base(execute); |
ohneta | 0:aae260bdcdd9 | 1566 | if (mbedErrorFlag != 0) { |
ohneta | 0:aae260bdcdd9 | 1567 | string msg; |
ohneta | 0:aae260bdcdd9 | 1568 | msg = "Error "; |
ohneta | 0:aae260bdcdd9 | 1569 | msg += mbedErrorMessage; |
ohneta | 0:aae260bdcdd9 | 1570 | #ifdef TINYJS_CALL_STACK |
ohneta | 0:aae260bdcdd9 | 1571 | for (int i=(int)call_stack.size()-1;i>=0;i--) { |
ohneta | 0:aae260bdcdd9 | 1572 | msg += "\n"; |
ohneta | 0:aae260bdcdd9 | 1573 | msg += i; |
ohneta | 0:aae260bdcdd9 | 1574 | msg += ": "; |
ohneta | 0:aae260bdcdd9 | 1575 | msg += call_stack.at(i); |
ohneta | 0:aae260bdcdd9 | 1576 | } |
ohneta | 0:aae260bdcdd9 | 1577 | #endif |
ohneta | 0:aae260bdcdd9 | 1578 | msg += " at "; |
ohneta | 0:aae260bdcdd9 | 1579 | msg += l->getPosition(); |
ohneta | 0:aae260bdcdd9 | 1580 | delete l; |
ohneta | 0:aae260bdcdd9 | 1581 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 1582 | |
ohneta | 0:aae260bdcdd9 | 1583 | mbedErrorFlag = 1; |
ohneta | 0:aae260bdcdd9 | 1584 | mbedErrorMessage = msg; |
ohneta | 0:aae260bdcdd9 | 1585 | return 0; |
ohneta | 0:aae260bdcdd9 | 1586 | } |
ohneta | 0:aae260bdcdd9 | 1587 | |
ohneta | 0:aae260bdcdd9 | 1588 | if (l->tk!=LEX_EOF) { |
ohneta | 0:aae260bdcdd9 | 1589 | mbedErrorFlag = 0; |
ohneta | 0:aae260bdcdd9 | 1590 | l->match(';'); |
ohneta | 0:aae260bdcdd9 | 1591 | if (mbedErrorFlag != 0) return 0; |
ohneta | 0:aae260bdcdd9 | 1592 | } |
ohneta | 0:aae260bdcdd9 | 1593 | } while (l->tk!=LEX_EOF); |
ohneta | 0:aae260bdcdd9 | 1594 | } |
ohneta | 0:aae260bdcdd9 | 1595 | #endif |
ohneta | 0:aae260bdcdd9 | 1596 | delete l; |
ohneta | 0:aae260bdcdd9 | 1597 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 1598 | scopes = oldScopes; |
ohneta | 0:aae260bdcdd9 | 1599 | |
ohneta | 0:aae260bdcdd9 | 1600 | if (v) { |
ohneta | 0:aae260bdcdd9 | 1601 | CScriptVarLink r = *v; |
ohneta | 0:aae260bdcdd9 | 1602 | CLEAN(v); |
ohneta | 0:aae260bdcdd9 | 1603 | return r; |
ohneta | 0:aae260bdcdd9 | 1604 | } |
ohneta | 0:aae260bdcdd9 | 1605 | // return undefined... |
ohneta | 0:aae260bdcdd9 | 1606 | return CScriptVarLink(new CScriptVar()); |
ohneta | 0:aae260bdcdd9 | 1607 | } |
ohneta | 0:aae260bdcdd9 | 1608 | |
ohneta | 0:aae260bdcdd9 | 1609 | string CTinyJS::evaluate(const string &code) { |
ohneta | 0:aae260bdcdd9 | 1610 | return evaluateComplex(code).var->getString(); |
ohneta | 0:aae260bdcdd9 | 1611 | } |
ohneta | 0:aae260bdcdd9 | 1612 | |
ohneta | 0:aae260bdcdd9 | 1613 | void CTinyJS::parseFunctionArguments(CScriptVar *funcVar) { |
ohneta | 0:aae260bdcdd9 | 1614 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1615 | l->match('('); |
ohneta | 0:aae260bdcdd9 | 1616 | while (l->tk!=')') { |
ohneta | 0:aae260bdcdd9 | 1617 | funcVar->addChildNoDup(l->tkStr); |
ohneta | 0:aae260bdcdd9 | 1618 | l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1619 | if (l->tk!=')') l->match(','); |
ohneta | 0:aae260bdcdd9 | 1620 | } |
ohneta | 0:aae260bdcdd9 | 1621 | l->match(')'); |
ohneta | 0:aae260bdcdd9 | 1622 | #else |
ohneta | 0:aae260bdcdd9 | 1623 | LMATCH_VOID('('); |
ohneta | 0:aae260bdcdd9 | 1624 | while (l->tk!=')') { |
ohneta | 0:aae260bdcdd9 | 1625 | funcVar->addChildNoDup(l->tkStr); |
ohneta | 0:aae260bdcdd9 | 1626 | LMATCH_VOID(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1627 | if (l->tk!=')') { |
ohneta | 0:aae260bdcdd9 | 1628 | LMATCH_VOID(','); |
ohneta | 0:aae260bdcdd9 | 1629 | } |
ohneta | 0:aae260bdcdd9 | 1630 | } |
ohneta | 0:aae260bdcdd9 | 1631 | LMATCH_VOID(')'); |
ohneta | 0:aae260bdcdd9 | 1632 | #endif |
ohneta | 0:aae260bdcdd9 | 1633 | } |
ohneta | 0:aae260bdcdd9 | 1634 | |
ohneta | 0:aae260bdcdd9 | 1635 | void CTinyJS::addNative(const string &funcDesc, JSCallback ptr, void *userdata) { |
ohneta | 0:aae260bdcdd9 | 1636 | CScriptLex *oldLex = l; |
ohneta | 0:aae260bdcdd9 | 1637 | l = new CScriptLex(funcDesc); |
ohneta | 0:aae260bdcdd9 | 1638 | |
ohneta | 0:aae260bdcdd9 | 1639 | CScriptVar *base = root; |
ohneta | 0:aae260bdcdd9 | 1640 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1641 | l->match(LEX_R_FUNCTION); |
ohneta | 0:aae260bdcdd9 | 1642 | #else |
ohneta | 0:aae260bdcdd9 | 1643 | LMATCH_VOID(LEX_R_FUNCTION); |
ohneta | 0:aae260bdcdd9 | 1644 | #endif |
ohneta | 0:aae260bdcdd9 | 1645 | string funcName = l->tkStr; |
ohneta | 0:aae260bdcdd9 | 1646 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1647 | l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1648 | #else |
ohneta | 0:aae260bdcdd9 | 1649 | LMATCH_VOID(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1650 | #endif |
ohneta | 0:aae260bdcdd9 | 1651 | /* Check for dots, we might want to do something like function String.substring ... */ |
ohneta | 0:aae260bdcdd9 | 1652 | while (l->tk == '.') { |
ohneta | 0:aae260bdcdd9 | 1653 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1654 | l->match('.'); |
ohneta | 0:aae260bdcdd9 | 1655 | #else |
ohneta | 0:aae260bdcdd9 | 1656 | LMATCH_VOID('.'); |
ohneta | 0:aae260bdcdd9 | 1657 | #endif |
ohneta | 0:aae260bdcdd9 | 1658 | CScriptVarLink *link = base->findChild(funcName); |
ohneta | 0:aae260bdcdd9 | 1659 | // if it doesn't exist, make an object class |
ohneta | 0:aae260bdcdd9 | 1660 | if (!link) link = base->addChild(funcName, new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT)); |
ohneta | 0:aae260bdcdd9 | 1661 | base = link->var; |
ohneta | 0:aae260bdcdd9 | 1662 | funcName = l->tkStr; |
ohneta | 0:aae260bdcdd9 | 1663 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1664 | l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1665 | #else |
ohneta | 0:aae260bdcdd9 | 1666 | LMATCH_VOID(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1667 | #endif |
ohneta | 0:aae260bdcdd9 | 1668 | } |
ohneta | 0:aae260bdcdd9 | 1669 | |
ohneta | 0:aae260bdcdd9 | 1670 | CScriptVar *funcVar = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_FUNCTION | SCRIPTVAR_NATIVE); |
ohneta | 0:aae260bdcdd9 | 1671 | funcVar->setCallback(ptr, userdata); |
ohneta | 0:aae260bdcdd9 | 1672 | parseFunctionArguments(funcVar); |
ohneta | 0:aae260bdcdd9 | 1673 | delete l; |
ohneta | 0:aae260bdcdd9 | 1674 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 1675 | |
ohneta | 0:aae260bdcdd9 | 1676 | base->addChild(funcName, funcVar); |
ohneta | 0:aae260bdcdd9 | 1677 | } |
ohneta | 0:aae260bdcdd9 | 1678 | |
ohneta | 0:aae260bdcdd9 | 1679 | CScriptVarLink *CTinyJS::parseFunctionDefinition() { |
ohneta | 0:aae260bdcdd9 | 1680 | // actually parse a function... |
ohneta | 0:aae260bdcdd9 | 1681 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1682 | l->match(LEX_R_FUNCTION); |
ohneta | 0:aae260bdcdd9 | 1683 | #else |
ohneta | 0:aae260bdcdd9 | 1684 | LMATCH(LEX_R_FUNCTION); |
ohneta | 0:aae260bdcdd9 | 1685 | #endif |
ohneta | 0:aae260bdcdd9 | 1686 | string funcName = TINYJS_TEMP_NAME; |
ohneta | 0:aae260bdcdd9 | 1687 | /* we can have functions without names */ |
ohneta | 0:aae260bdcdd9 | 1688 | if (l->tk==LEX_ID) { |
ohneta | 0:aae260bdcdd9 | 1689 | funcName = l->tkStr; |
ohneta | 0:aae260bdcdd9 | 1690 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1691 | l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1692 | #else |
ohneta | 0:aae260bdcdd9 | 1693 | LMATCH(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1694 | #endif |
ohneta | 0:aae260bdcdd9 | 1695 | } |
ohneta | 0:aae260bdcdd9 | 1696 | CScriptVarLink *funcVar = new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_FUNCTION), funcName); |
ohneta | 0:aae260bdcdd9 | 1697 | parseFunctionArguments(funcVar->var); |
ohneta | 0:aae260bdcdd9 | 1698 | int funcBegin = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 1699 | bool noexecute = false; |
ohneta | 0:aae260bdcdd9 | 1700 | block(noexecute); |
ohneta | 0:aae260bdcdd9 | 1701 | funcVar->var->data = l->getSubString(funcBegin); |
ohneta | 0:aae260bdcdd9 | 1702 | return funcVar; |
ohneta | 0:aae260bdcdd9 | 1703 | } |
ohneta | 0:aae260bdcdd9 | 1704 | |
ohneta | 0:aae260bdcdd9 | 1705 | /** Handle a function call (assumes we've parsed the function name and we're |
ohneta | 0:aae260bdcdd9 | 1706 | * on the start bracket). 'parent' is the object that contains this method, |
ohneta | 0:aae260bdcdd9 | 1707 | * if there was one (otherwise it's just a normnal function). |
ohneta | 0:aae260bdcdd9 | 1708 | */ |
ohneta | 0:aae260bdcdd9 | 1709 | CScriptVarLink *CTinyJS::functionCall(bool &execute, CScriptVarLink *function, CScriptVar *parent) { |
ohneta | 0:aae260bdcdd9 | 1710 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 1711 | if (!function->var->isFunction()) { |
ohneta | 0:aae260bdcdd9 | 1712 | string errorMsg = "Expecting '"; |
ohneta | 0:aae260bdcdd9 | 1713 | errorMsg = errorMsg + function->name + "' to be a function"; |
ohneta | 0:aae260bdcdd9 | 1714 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1715 | throw new CScriptException(errorMsg.c_str()); |
ohneta | 0:aae260bdcdd9 | 1716 | #else |
ohneta | 0:aae260bdcdd9 | 1717 | mbedErrorFlag = 1; |
ohneta | 0:aae260bdcdd9 | 1718 | mbedErrorMessage = errorMsg; |
ohneta | 0:aae260bdcdd9 | 1719 | return 0; |
ohneta | 0:aae260bdcdd9 | 1720 | #endif |
ohneta | 0:aae260bdcdd9 | 1721 | } |
ohneta | 0:aae260bdcdd9 | 1722 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1723 | l->match('('); |
ohneta | 0:aae260bdcdd9 | 1724 | #else |
ohneta | 0:aae260bdcdd9 | 1725 | LMATCH('('); |
ohneta | 0:aae260bdcdd9 | 1726 | #endif |
ohneta | 0:aae260bdcdd9 | 1727 | // create a new symbol table entry for execution of this function |
ohneta | 0:aae260bdcdd9 | 1728 | CScriptVar *functionRoot = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_FUNCTION); |
ohneta | 0:aae260bdcdd9 | 1729 | if (parent) |
ohneta | 0:aae260bdcdd9 | 1730 | functionRoot->addChildNoDup("this", parent); |
ohneta | 0:aae260bdcdd9 | 1731 | // grab in all parameters |
ohneta | 0:aae260bdcdd9 | 1732 | CScriptVarLink *v = function->var->firstChild; |
ohneta | 0:aae260bdcdd9 | 1733 | while (v) { |
ohneta | 0:aae260bdcdd9 | 1734 | CScriptVarLink *value = base(execute); |
ohneta | 0:aae260bdcdd9 | 1735 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 1736 | if (value->var->isBasic()) { |
ohneta | 0:aae260bdcdd9 | 1737 | // pass by value |
ohneta | 0:aae260bdcdd9 | 1738 | functionRoot->addChild(v->name, value->var->deepCopy()); |
ohneta | 0:aae260bdcdd9 | 1739 | } else { |
ohneta | 0:aae260bdcdd9 | 1740 | // pass by reference |
ohneta | 0:aae260bdcdd9 | 1741 | functionRoot->addChild(v->name, value->var); |
ohneta | 0:aae260bdcdd9 | 1742 | } |
ohneta | 0:aae260bdcdd9 | 1743 | } |
ohneta | 0:aae260bdcdd9 | 1744 | CLEAN(value); |
ohneta | 0:aae260bdcdd9 | 1745 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1746 | if (l->tk!=')') l->match(','); |
ohneta | 0:aae260bdcdd9 | 1747 | #else |
ohneta | 0:aae260bdcdd9 | 1748 | if (l->tk!=')') LMATCH(','); |
ohneta | 0:aae260bdcdd9 | 1749 | #endif |
ohneta | 0:aae260bdcdd9 | 1750 | v = v->nextSibling; |
ohneta | 0:aae260bdcdd9 | 1751 | } |
ohneta | 0:aae260bdcdd9 | 1752 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1753 | l->match(')'); |
ohneta | 0:aae260bdcdd9 | 1754 | #else |
ohneta | 0:aae260bdcdd9 | 1755 | LMATCH(')'); |
ohneta | 0:aae260bdcdd9 | 1756 | #endif |
ohneta | 0:aae260bdcdd9 | 1757 | // setup a return variable |
ohneta | 0:aae260bdcdd9 | 1758 | CScriptVarLink *returnVar = NULL; |
ohneta | 0:aae260bdcdd9 | 1759 | // execute function! |
ohneta | 0:aae260bdcdd9 | 1760 | // add the function's execute space to the symbol table so we can recurse |
ohneta | 0:aae260bdcdd9 | 1761 | CScriptVarLink *returnVarLink = functionRoot->addChild(TINYJS_RETURN_VAR); |
ohneta | 0:aae260bdcdd9 | 1762 | scopes.push_back(functionRoot); |
ohneta | 0:aae260bdcdd9 | 1763 | #ifdef TINYJS_CALL_STACK |
ohneta | 0:aae260bdcdd9 | 1764 | call_stack.push_back(function->name + " from " + l->getPosition()); |
ohneta | 0:aae260bdcdd9 | 1765 | #endif |
ohneta | 0:aae260bdcdd9 | 1766 | |
ohneta | 0:aae260bdcdd9 | 1767 | if (function->var->isNative()) { |
ohneta | 0:aae260bdcdd9 | 1768 | ASSERT(function->var->jsCallback); |
ohneta | 0:aae260bdcdd9 | 1769 | function->var->jsCallback(functionRoot, function->var->jsCallbackUserData); |
ohneta | 0:aae260bdcdd9 | 1770 | } else { |
ohneta | 0:aae260bdcdd9 | 1771 | /* we just want to execute the block, but something could |
ohneta | 0:aae260bdcdd9 | 1772 | * have messed up and left us with the wrong ScriptLex, so |
ohneta | 0:aae260bdcdd9 | 1773 | * we want to be careful here... */ |
ohneta | 0:aae260bdcdd9 | 1774 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1775 | CScriptException *exception = 0; |
ohneta | 0:aae260bdcdd9 | 1776 | CScriptLex *oldLex = l; |
ohneta | 0:aae260bdcdd9 | 1777 | CScriptLex *newLex = new CScriptLex(function->var->getString()); |
ohneta | 0:aae260bdcdd9 | 1778 | l = newLex; |
ohneta | 0:aae260bdcdd9 | 1779 | |
ohneta | 0:aae260bdcdd9 | 1780 | try { |
ohneta | 0:aae260bdcdd9 | 1781 | block(execute); |
ohneta | 0:aae260bdcdd9 | 1782 | // because return will probably have called this, and set execute to false |
ohneta | 0:aae260bdcdd9 | 1783 | execute = true; |
ohneta | 0:aae260bdcdd9 | 1784 | } catch (CScriptException *e) { |
ohneta | 0:aae260bdcdd9 | 1785 | exception = e; |
ohneta | 0:aae260bdcdd9 | 1786 | } |
ohneta | 0:aae260bdcdd9 | 1787 | delete newLex; |
ohneta | 0:aae260bdcdd9 | 1788 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 1789 | |
ohneta | 0:aae260bdcdd9 | 1790 | if (exception) |
ohneta | 0:aae260bdcdd9 | 1791 | throw exception; |
ohneta | 0:aae260bdcdd9 | 1792 | #else |
ohneta | 0:aae260bdcdd9 | 1793 | CScriptLex *oldLex = l; |
ohneta | 0:aae260bdcdd9 | 1794 | CScriptLex *newLex = new CScriptLex(function->var->getString()); |
ohneta | 0:aae260bdcdd9 | 1795 | l = newLex; |
ohneta | 0:aae260bdcdd9 | 1796 | |
ohneta | 0:aae260bdcdd9 | 1797 | { |
ohneta | 0:aae260bdcdd9 | 1798 | mbedErrorFlag = 0; |
ohneta | 0:aae260bdcdd9 | 1799 | block(execute); |
ohneta | 0:aae260bdcdd9 | 1800 | if (mbedErrorFlag != 0) { |
ohneta | 0:aae260bdcdd9 | 1801 | delete newLex; |
ohneta | 0:aae260bdcdd9 | 1802 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 1803 | return 0; |
ohneta | 0:aae260bdcdd9 | 1804 | } else { |
ohneta | 0:aae260bdcdd9 | 1805 | execute = true; |
ohneta | 0:aae260bdcdd9 | 1806 | |
ohneta | 0:aae260bdcdd9 | 1807 | delete newLex; |
ohneta | 0:aae260bdcdd9 | 1808 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 1809 | } |
ohneta | 0:aae260bdcdd9 | 1810 | } |
ohneta | 0:aae260bdcdd9 | 1811 | #endif |
ohneta | 0:aae260bdcdd9 | 1812 | |
ohneta | 0:aae260bdcdd9 | 1813 | } |
ohneta | 0:aae260bdcdd9 | 1814 | #ifdef TINYJS_CALL_STACK |
ohneta | 0:aae260bdcdd9 | 1815 | if (!call_stack.empty()) call_stack.pop_back(); |
ohneta | 0:aae260bdcdd9 | 1816 | #endif |
ohneta | 0:aae260bdcdd9 | 1817 | scopes.pop_back(); |
ohneta | 0:aae260bdcdd9 | 1818 | /* get the real return var before we remove it from our function */ |
ohneta | 0:aae260bdcdd9 | 1819 | returnVar = new CScriptVarLink(returnVarLink->var); |
ohneta | 0:aae260bdcdd9 | 1820 | functionRoot->removeLink(returnVarLink); |
ohneta | 0:aae260bdcdd9 | 1821 | delete functionRoot; |
ohneta | 0:aae260bdcdd9 | 1822 | if (returnVar) |
ohneta | 0:aae260bdcdd9 | 1823 | return returnVar; |
ohneta | 0:aae260bdcdd9 | 1824 | else |
ohneta | 0:aae260bdcdd9 | 1825 | return new CScriptVarLink(new CScriptVar()); |
ohneta | 0:aae260bdcdd9 | 1826 | } else { |
ohneta | 0:aae260bdcdd9 | 1827 | // function, but not executing - just parse args and be done |
ohneta | 0:aae260bdcdd9 | 1828 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1829 | l->match('('); |
ohneta | 0:aae260bdcdd9 | 1830 | while (l->tk != ')') { |
ohneta | 0:aae260bdcdd9 | 1831 | CScriptVarLink *value = base(execute); |
ohneta | 0:aae260bdcdd9 | 1832 | CLEAN(value); |
ohneta | 0:aae260bdcdd9 | 1833 | if (l->tk!=')') l->match(','); |
ohneta | 0:aae260bdcdd9 | 1834 | } |
ohneta | 0:aae260bdcdd9 | 1835 | l->match(')'); |
ohneta | 0:aae260bdcdd9 | 1836 | #else |
ohneta | 0:aae260bdcdd9 | 1837 | LMATCH('('); |
ohneta | 0:aae260bdcdd9 | 1838 | while (l->tk != ')') { |
ohneta | 0:aae260bdcdd9 | 1839 | CScriptVarLink *value = base(execute); |
ohneta | 0:aae260bdcdd9 | 1840 | CLEAN(value); |
ohneta | 0:aae260bdcdd9 | 1841 | if (l->tk!=')') LMATCH(','); |
ohneta | 0:aae260bdcdd9 | 1842 | } |
ohneta | 0:aae260bdcdd9 | 1843 | LMATCH(')'); |
ohneta | 0:aae260bdcdd9 | 1844 | #endif |
ohneta | 0:aae260bdcdd9 | 1845 | if (l->tk == '{') { // TODO: why is this here? |
ohneta | 0:aae260bdcdd9 | 1846 | block(execute); |
ohneta | 0:aae260bdcdd9 | 1847 | } |
ohneta | 0:aae260bdcdd9 | 1848 | /* function will be a blank scriptvarlink if we're not executing, |
ohneta | 0:aae260bdcdd9 | 1849 | * so just return it rather than an alloc/free */ |
ohneta | 0:aae260bdcdd9 | 1850 | return function; |
ohneta | 0:aae260bdcdd9 | 1851 | } |
ohneta | 0:aae260bdcdd9 | 1852 | } |
ohneta | 0:aae260bdcdd9 | 1853 | |
ohneta | 0:aae260bdcdd9 | 1854 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 1855 | CScriptVarLink *CTinyJS::factor(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 1856 | if (l->tk=='(') { |
ohneta | 0:aae260bdcdd9 | 1857 | l->match('('); |
ohneta | 0:aae260bdcdd9 | 1858 | CScriptVarLink *a = base(execute); |
ohneta | 0:aae260bdcdd9 | 1859 | l->match(')'); |
ohneta | 0:aae260bdcdd9 | 1860 | return a; |
ohneta | 0:aae260bdcdd9 | 1861 | } |
ohneta | 0:aae260bdcdd9 | 1862 | if (l->tk==LEX_R_TRUE) { |
ohneta | 0:aae260bdcdd9 | 1863 | l->match(LEX_R_TRUE); |
ohneta | 0:aae260bdcdd9 | 1864 | return new CScriptVarLink(new CScriptVar(1)); |
ohneta | 0:aae260bdcdd9 | 1865 | } |
ohneta | 0:aae260bdcdd9 | 1866 | if (l->tk==LEX_R_FALSE) { |
ohneta | 0:aae260bdcdd9 | 1867 | l->match(LEX_R_FALSE); |
ohneta | 0:aae260bdcdd9 | 1868 | return new CScriptVarLink(new CScriptVar(0)); |
ohneta | 0:aae260bdcdd9 | 1869 | } |
ohneta | 0:aae260bdcdd9 | 1870 | if (l->tk==LEX_R_NULL) { |
ohneta | 0:aae260bdcdd9 | 1871 | l->match(LEX_R_NULL); |
ohneta | 0:aae260bdcdd9 | 1872 | return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_NULL)); |
ohneta | 0:aae260bdcdd9 | 1873 | } |
ohneta | 0:aae260bdcdd9 | 1874 | if (l->tk==LEX_R_UNDEFINED) { |
ohneta | 0:aae260bdcdd9 | 1875 | l->match(LEX_R_UNDEFINED); |
ohneta | 0:aae260bdcdd9 | 1876 | return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_UNDEFINED)); |
ohneta | 0:aae260bdcdd9 | 1877 | } |
ohneta | 0:aae260bdcdd9 | 1878 | if (l->tk==LEX_ID) { |
ohneta | 0:aae260bdcdd9 | 1879 | CScriptVarLink *a = execute ? findInScopes(l->tkStr) : new CScriptVarLink(new CScriptVar()); |
ohneta | 0:aae260bdcdd9 | 1880 | //printf("0x%08X for %s at %s\n", (unsigned int)a, l->tkStr.c_str(), l->getPosition().c_str()); |
ohneta | 0:aae260bdcdd9 | 1881 | /* The parent if we're executing a method call */ |
ohneta | 0:aae260bdcdd9 | 1882 | CScriptVar *parent = 0; |
ohneta | 0:aae260bdcdd9 | 1883 | |
ohneta | 0:aae260bdcdd9 | 1884 | if (execute && !a) { |
ohneta | 0:aae260bdcdd9 | 1885 | /* Variable doesn't exist! JavaScript says we should create it |
ohneta | 0:aae260bdcdd9 | 1886 | * (we won't add it here. This is done in the assignment operator)*/ |
ohneta | 0:aae260bdcdd9 | 1887 | a = new CScriptVarLink(new CScriptVar(), l->tkStr); |
ohneta | 0:aae260bdcdd9 | 1888 | } |
ohneta | 0:aae260bdcdd9 | 1889 | l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1890 | while (l->tk=='(' || l->tk=='.' || l->tk=='[') { |
ohneta | 0:aae260bdcdd9 | 1891 | if (l->tk=='(') { // ------------------------------------- Function Call |
ohneta | 0:aae260bdcdd9 | 1892 | a = functionCall(execute, a, parent); |
ohneta | 0:aae260bdcdd9 | 1893 | } else if (l->tk == '.') { // ------------------------------------- Record Access |
ohneta | 0:aae260bdcdd9 | 1894 | l->match('.'); |
ohneta | 0:aae260bdcdd9 | 1895 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 1896 | const string &name = l->tkStr; |
ohneta | 0:aae260bdcdd9 | 1897 | CScriptVarLink *child = a->var->findChild(name); |
ohneta | 0:aae260bdcdd9 | 1898 | if (!child) child = findInParentClasses(a->var, name); |
ohneta | 0:aae260bdcdd9 | 1899 | if (!child) { |
ohneta | 0:aae260bdcdd9 | 1900 | /* if we haven't found this defined yet, use the built-in |
ohneta | 0:aae260bdcdd9 | 1901 | 'length' properly */ |
ohneta | 0:aae260bdcdd9 | 1902 | if (a->var->isArray() && name == "length") { |
ohneta | 0:aae260bdcdd9 | 1903 | int l = a->var->getArrayLength(); |
ohneta | 0:aae260bdcdd9 | 1904 | child = new CScriptVarLink(new CScriptVar(l)); |
ohneta | 0:aae260bdcdd9 | 1905 | } else if (a->var->isString() && name == "length") { |
ohneta | 0:aae260bdcdd9 | 1906 | int l = a->var->getString().size(); |
ohneta | 0:aae260bdcdd9 | 1907 | child = new CScriptVarLink(new CScriptVar(l)); |
ohneta | 0:aae260bdcdd9 | 1908 | } else { |
ohneta | 0:aae260bdcdd9 | 1909 | child = a->var->addChild(name); |
ohneta | 0:aae260bdcdd9 | 1910 | } |
ohneta | 0:aae260bdcdd9 | 1911 | } |
ohneta | 0:aae260bdcdd9 | 1912 | parent = a->var; |
ohneta | 0:aae260bdcdd9 | 1913 | a = child; |
ohneta | 0:aae260bdcdd9 | 1914 | } |
ohneta | 0:aae260bdcdd9 | 1915 | l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1916 | } else if (l->tk == '[') { // ------------------------------------- Array Access |
ohneta | 0:aae260bdcdd9 | 1917 | l->match('['); |
ohneta | 0:aae260bdcdd9 | 1918 | CScriptVarLink *index = base(execute); |
ohneta | 0:aae260bdcdd9 | 1919 | l->match(']'); |
ohneta | 0:aae260bdcdd9 | 1920 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 1921 | CScriptVarLink *child = a->var->findChildOrCreate(index->var->getString()); |
ohneta | 0:aae260bdcdd9 | 1922 | parent = a->var; |
ohneta | 0:aae260bdcdd9 | 1923 | a = child; |
ohneta | 0:aae260bdcdd9 | 1924 | } |
ohneta | 0:aae260bdcdd9 | 1925 | CLEAN(index); |
ohneta | 0:aae260bdcdd9 | 1926 | } else ASSERT(0); |
ohneta | 0:aae260bdcdd9 | 1927 | } |
ohneta | 0:aae260bdcdd9 | 1928 | return a; |
ohneta | 0:aae260bdcdd9 | 1929 | } |
ohneta | 0:aae260bdcdd9 | 1930 | if (l->tk==LEX_INT || l->tk==LEX_FLOAT) { |
ohneta | 0:aae260bdcdd9 | 1931 | CScriptVar *a = new CScriptVar(l->tkStr, |
ohneta | 0:aae260bdcdd9 | 1932 | ((l->tk==LEX_INT)?SCRIPTVAR_INTEGER:SCRIPTVAR_DOUBLE)); |
ohneta | 0:aae260bdcdd9 | 1933 | l->match(l->tk); |
ohneta | 0:aae260bdcdd9 | 1934 | return new CScriptVarLink(a); |
ohneta | 0:aae260bdcdd9 | 1935 | } |
ohneta | 0:aae260bdcdd9 | 1936 | if (l->tk==LEX_STR) { |
ohneta | 0:aae260bdcdd9 | 1937 | CScriptVar *a = new CScriptVar(l->tkStr, SCRIPTVAR_STRING); |
ohneta | 0:aae260bdcdd9 | 1938 | l->match(LEX_STR); |
ohneta | 0:aae260bdcdd9 | 1939 | return new CScriptVarLink(a); |
ohneta | 0:aae260bdcdd9 | 1940 | } |
ohneta | 0:aae260bdcdd9 | 1941 | if (l->tk=='{') { |
ohneta | 0:aae260bdcdd9 | 1942 | CScriptVar *contents = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT); |
ohneta | 0:aae260bdcdd9 | 1943 | /* JSON-style object definition */ |
ohneta | 0:aae260bdcdd9 | 1944 | l->match('{'); |
ohneta | 0:aae260bdcdd9 | 1945 | while (l->tk != '}') { |
ohneta | 0:aae260bdcdd9 | 1946 | string id = l->tkStr; |
ohneta | 0:aae260bdcdd9 | 1947 | // we only allow strings or IDs on the left hand side of an initialisation |
ohneta | 0:aae260bdcdd9 | 1948 | if (l->tk==LEX_STR) l->match(LEX_STR); |
ohneta | 0:aae260bdcdd9 | 1949 | else l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 1950 | l->match(':'); |
ohneta | 0:aae260bdcdd9 | 1951 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 1952 | CScriptVarLink *a = base(execute); |
ohneta | 0:aae260bdcdd9 | 1953 | contents->addChild(id, a->var); |
ohneta | 0:aae260bdcdd9 | 1954 | CLEAN(a); |
ohneta | 0:aae260bdcdd9 | 1955 | } |
ohneta | 0:aae260bdcdd9 | 1956 | // no need to clean here, as it will definitely be used |
ohneta | 0:aae260bdcdd9 | 1957 | if (l->tk != '}') l->match(','); |
ohneta | 0:aae260bdcdd9 | 1958 | } |
ohneta | 0:aae260bdcdd9 | 1959 | |
ohneta | 0:aae260bdcdd9 | 1960 | l->match('}'); |
ohneta | 0:aae260bdcdd9 | 1961 | return new CScriptVarLink(contents); |
ohneta | 0:aae260bdcdd9 | 1962 | } |
ohneta | 0:aae260bdcdd9 | 1963 | if (l->tk=='[') { |
ohneta | 0:aae260bdcdd9 | 1964 | CScriptVar *contents = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_ARRAY); |
ohneta | 0:aae260bdcdd9 | 1965 | /* JSON-style array */ |
ohneta | 0:aae260bdcdd9 | 1966 | l->match('['); |
ohneta | 0:aae260bdcdd9 | 1967 | int idx = 0; |
ohneta | 0:aae260bdcdd9 | 1968 | while (l->tk != ']') { |
ohneta | 0:aae260bdcdd9 | 1969 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 1970 | char idx_str[16]; // big enough for 2^32 |
ohneta | 0:aae260bdcdd9 | 1971 | sprintf_s(idx_str, sizeof(idx_str), "%d",idx); |
ohneta | 0:aae260bdcdd9 | 1972 | |
ohneta | 0:aae260bdcdd9 | 1973 | CScriptVarLink *a = base(execute); |
ohneta | 0:aae260bdcdd9 | 1974 | contents->addChild(idx_str, a->var); |
ohneta | 0:aae260bdcdd9 | 1975 | CLEAN(a); |
ohneta | 0:aae260bdcdd9 | 1976 | } |
ohneta | 0:aae260bdcdd9 | 1977 | // no need to clean here, as it will definitely be used |
ohneta | 0:aae260bdcdd9 | 1978 | if (l->tk != ']') l->match(','); |
ohneta | 0:aae260bdcdd9 | 1979 | idx++; |
ohneta | 0:aae260bdcdd9 | 1980 | } |
ohneta | 0:aae260bdcdd9 | 1981 | l->match(']'); |
ohneta | 0:aae260bdcdd9 | 1982 | return new CScriptVarLink(contents); |
ohneta | 0:aae260bdcdd9 | 1983 | } |
ohneta | 0:aae260bdcdd9 | 1984 | if (l->tk==LEX_R_FUNCTION) { |
ohneta | 0:aae260bdcdd9 | 1985 | CScriptVarLink *funcVar = parseFunctionDefinition(); |
ohneta | 0:aae260bdcdd9 | 1986 | if (funcVar->name != TINYJS_TEMP_NAME) |
ohneta | 0:aae260bdcdd9 | 1987 | TRACE("Functions not defined at statement-level are not meant to have a name"); |
ohneta | 0:aae260bdcdd9 | 1988 | return funcVar; |
ohneta | 0:aae260bdcdd9 | 1989 | } |
ohneta | 0:aae260bdcdd9 | 1990 | if (l->tk==LEX_R_NEW) { |
ohneta | 0:aae260bdcdd9 | 1991 | // new -> create a new object |
ohneta | 0:aae260bdcdd9 | 1992 | l->match(LEX_R_NEW); |
ohneta | 0:aae260bdcdd9 | 1993 | const string &className = l->tkStr; |
ohneta | 0:aae260bdcdd9 | 1994 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 1995 | CScriptVarLink *objClassOrFunc = findInScopes(className); |
ohneta | 0:aae260bdcdd9 | 1996 | if (!objClassOrFunc) { |
ohneta | 0:aae260bdcdd9 | 1997 | TRACE("%s is not a valid class name", className.c_str()); |
ohneta | 0:aae260bdcdd9 | 1998 | return new CScriptVarLink(new CScriptVar()); |
ohneta | 0:aae260bdcdd9 | 1999 | } |
ohneta | 0:aae260bdcdd9 | 2000 | l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2001 | CScriptVar *obj = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT); |
ohneta | 0:aae260bdcdd9 | 2002 | CScriptVarLink *objLink = new CScriptVarLink(obj); |
ohneta | 0:aae260bdcdd9 | 2003 | if (objClassOrFunc->var->isFunction()) { |
ohneta | 0:aae260bdcdd9 | 2004 | CLEAN(functionCall(execute, objClassOrFunc, obj)); |
ohneta | 0:aae260bdcdd9 | 2005 | } else { |
ohneta | 0:aae260bdcdd9 | 2006 | obj->addChild(TINYJS_PROTOTYPE_CLASS, objClassOrFunc->var); |
ohneta | 0:aae260bdcdd9 | 2007 | if (l->tk == '(') { |
ohneta | 0:aae260bdcdd9 | 2008 | l->match('('); |
ohneta | 0:aae260bdcdd9 | 2009 | l->match(')'); |
ohneta | 0:aae260bdcdd9 | 2010 | } |
ohneta | 0:aae260bdcdd9 | 2011 | } |
ohneta | 0:aae260bdcdd9 | 2012 | return objLink; |
ohneta | 0:aae260bdcdd9 | 2013 | } else { |
ohneta | 0:aae260bdcdd9 | 2014 | l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2015 | if (l->tk == '(') { |
ohneta | 0:aae260bdcdd9 | 2016 | l->match('('); |
ohneta | 0:aae260bdcdd9 | 2017 | l->match(')'); |
ohneta | 0:aae260bdcdd9 | 2018 | } |
ohneta | 0:aae260bdcdd9 | 2019 | } |
ohneta | 0:aae260bdcdd9 | 2020 | } |
ohneta | 0:aae260bdcdd9 | 2021 | // Nothing we can do here... just hope it's the end... |
ohneta | 0:aae260bdcdd9 | 2022 | l->match(LEX_EOF); |
ohneta | 0:aae260bdcdd9 | 2023 | return 0; |
ohneta | 0:aae260bdcdd9 | 2024 | } |
ohneta | 0:aae260bdcdd9 | 2025 | #else |
ohneta | 0:aae260bdcdd9 | 2026 | CScriptVarLink *CTinyJS::factor(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2027 | if (l->tk=='(') { |
ohneta | 0:aae260bdcdd9 | 2028 | LMATCH('('); |
ohneta | 0:aae260bdcdd9 | 2029 | CScriptVarLink *a = base(execute); |
ohneta | 0:aae260bdcdd9 | 2030 | LMATCH(')'); |
ohneta | 0:aae260bdcdd9 | 2031 | return a; |
ohneta | 0:aae260bdcdd9 | 2032 | } |
ohneta | 0:aae260bdcdd9 | 2033 | if (l->tk==LEX_R_TRUE) { |
ohneta | 0:aae260bdcdd9 | 2034 | LMATCH(LEX_R_TRUE); |
ohneta | 0:aae260bdcdd9 | 2035 | return new CScriptVarLink(new CScriptVar(1)); |
ohneta | 0:aae260bdcdd9 | 2036 | } |
ohneta | 0:aae260bdcdd9 | 2037 | if (l->tk==LEX_R_FALSE) { |
ohneta | 0:aae260bdcdd9 | 2038 | LMATCH(LEX_R_FALSE); |
ohneta | 0:aae260bdcdd9 | 2039 | return new CScriptVarLink(new CScriptVar(0)); |
ohneta | 0:aae260bdcdd9 | 2040 | } |
ohneta | 0:aae260bdcdd9 | 2041 | if (l->tk==LEX_R_NULL) { |
ohneta | 0:aae260bdcdd9 | 2042 | LMATCH(LEX_R_NULL); |
ohneta | 0:aae260bdcdd9 | 2043 | return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_NULL)); |
ohneta | 0:aae260bdcdd9 | 2044 | } |
ohneta | 0:aae260bdcdd9 | 2045 | if (l->tk==LEX_R_UNDEFINED) { |
ohneta | 0:aae260bdcdd9 | 2046 | LMATCH(LEX_R_UNDEFINED); |
ohneta | 0:aae260bdcdd9 | 2047 | return new CScriptVarLink(new CScriptVar(TINYJS_BLANK_DATA,SCRIPTVAR_UNDEFINED)); |
ohneta | 0:aae260bdcdd9 | 2048 | } |
ohneta | 0:aae260bdcdd9 | 2049 | if (l->tk==LEX_ID) { |
ohneta | 0:aae260bdcdd9 | 2050 | CScriptVarLink *a = execute ? findInScopes(l->tkStr) : new CScriptVarLink(new CScriptVar()); |
ohneta | 0:aae260bdcdd9 | 2051 | //printf("0x%08X for %s at %s\n", (unsigned int)a, l->tkStr.c_str(), l->getPosition().c_str()); |
ohneta | 0:aae260bdcdd9 | 2052 | /* The parent if we're executing a method call */ |
ohneta | 0:aae260bdcdd9 | 2053 | CScriptVar *parent = 0; |
ohneta | 0:aae260bdcdd9 | 2054 | |
ohneta | 0:aae260bdcdd9 | 2055 | if (execute && !a) { |
ohneta | 0:aae260bdcdd9 | 2056 | /* Variable doesn't exist! JavaScript says we should create it |
ohneta | 0:aae260bdcdd9 | 2057 | * (we won't add it here. This is done in the assignment operator)*/ |
ohneta | 0:aae260bdcdd9 | 2058 | a = new CScriptVarLink(new CScriptVar(), l->tkStr); |
ohneta | 0:aae260bdcdd9 | 2059 | } |
ohneta | 0:aae260bdcdd9 | 2060 | LMATCH(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2061 | while (l->tk=='(' || l->tk=='.' || l->tk=='[') { |
ohneta | 0:aae260bdcdd9 | 2062 | if (l->tk=='(') { // ------------------------------------- Function Call |
ohneta | 0:aae260bdcdd9 | 2063 | a = functionCall(execute, a, parent); |
ohneta | 0:aae260bdcdd9 | 2064 | } else if (l->tk == '.') { // ------------------------------------- Record Access |
ohneta | 0:aae260bdcdd9 | 2065 | LMATCH('.'); |
ohneta | 0:aae260bdcdd9 | 2066 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2067 | const string &name = l->tkStr; |
ohneta | 0:aae260bdcdd9 | 2068 | CScriptVarLink *child = a->var->findChild(name); |
ohneta | 0:aae260bdcdd9 | 2069 | if (!child) child = findInParentClasses(a->var, name); |
ohneta | 0:aae260bdcdd9 | 2070 | if (!child) { |
ohneta | 0:aae260bdcdd9 | 2071 | /* if we haven't found this defined yet, use the built-in |
ohneta | 0:aae260bdcdd9 | 2072 | 'length' properly */ |
ohneta | 0:aae260bdcdd9 | 2073 | if (a->var->isArray() && name == "length") { |
ohneta | 0:aae260bdcdd9 | 2074 | int l = a->var->getArrayLength(); |
ohneta | 0:aae260bdcdd9 | 2075 | child = new CScriptVarLink(new CScriptVar(l)); |
ohneta | 0:aae260bdcdd9 | 2076 | } else if (a->var->isString() && name == "length") { |
ohneta | 0:aae260bdcdd9 | 2077 | int l = a->var->getString().size(); |
ohneta | 0:aae260bdcdd9 | 2078 | child = new CScriptVarLink(new CScriptVar(l)); |
ohneta | 0:aae260bdcdd9 | 2079 | } else { |
ohneta | 0:aae260bdcdd9 | 2080 | child = a->var->addChild(name); |
ohneta | 0:aae260bdcdd9 | 2081 | } |
ohneta | 0:aae260bdcdd9 | 2082 | } |
ohneta | 0:aae260bdcdd9 | 2083 | parent = a->var; |
ohneta | 0:aae260bdcdd9 | 2084 | a = child; |
ohneta | 0:aae260bdcdd9 | 2085 | } |
ohneta | 0:aae260bdcdd9 | 2086 | LMATCH(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2087 | } else if (l->tk == '[') { // ------------------------------------- Array Access |
ohneta | 0:aae260bdcdd9 | 2088 | LMATCH('['); |
ohneta | 0:aae260bdcdd9 | 2089 | CScriptVarLink *index = base(execute); |
ohneta | 0:aae260bdcdd9 | 2090 | LMATCH(']'); |
ohneta | 0:aae260bdcdd9 | 2091 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2092 | CScriptVarLink *child = a->var->findChildOrCreate(index->var->getString()); |
ohneta | 0:aae260bdcdd9 | 2093 | parent = a->var; |
ohneta | 0:aae260bdcdd9 | 2094 | a = child; |
ohneta | 0:aae260bdcdd9 | 2095 | } |
ohneta | 0:aae260bdcdd9 | 2096 | CLEAN(index); |
ohneta | 0:aae260bdcdd9 | 2097 | } else ASSERT(0); |
ohneta | 0:aae260bdcdd9 | 2098 | } |
ohneta | 0:aae260bdcdd9 | 2099 | return a; |
ohneta | 0:aae260bdcdd9 | 2100 | } |
ohneta | 0:aae260bdcdd9 | 2101 | if (l->tk==LEX_INT || l->tk==LEX_FLOAT) { |
ohneta | 0:aae260bdcdd9 | 2102 | CScriptVar *a = new CScriptVar(l->tkStr, |
ohneta | 0:aae260bdcdd9 | 2103 | ((l->tk==LEX_INT)?SCRIPTVAR_INTEGER:SCRIPTVAR_DOUBLE)); |
ohneta | 0:aae260bdcdd9 | 2104 | LMATCH(l->tk); |
ohneta | 0:aae260bdcdd9 | 2105 | return new CScriptVarLink(a); |
ohneta | 0:aae260bdcdd9 | 2106 | } |
ohneta | 0:aae260bdcdd9 | 2107 | if (l->tk==LEX_STR) { |
ohneta | 0:aae260bdcdd9 | 2108 | CScriptVar *a = new CScriptVar(l->tkStr, SCRIPTVAR_STRING); |
ohneta | 0:aae260bdcdd9 | 2109 | LMATCH(LEX_STR); |
ohneta | 0:aae260bdcdd9 | 2110 | return new CScriptVarLink(a); |
ohneta | 0:aae260bdcdd9 | 2111 | } |
ohneta | 0:aae260bdcdd9 | 2112 | if (l->tk=='{') { |
ohneta | 0:aae260bdcdd9 | 2113 | CScriptVar *contents = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT); |
ohneta | 0:aae260bdcdd9 | 2114 | /* JSON-style object definition */ |
ohneta | 0:aae260bdcdd9 | 2115 | LMATCH('{'); |
ohneta | 0:aae260bdcdd9 | 2116 | while (l->tk != '}') { |
ohneta | 0:aae260bdcdd9 | 2117 | string id = l->tkStr; |
ohneta | 0:aae260bdcdd9 | 2118 | // we only allow strings or IDs on the left hand side of an initialisation |
ohneta | 0:aae260bdcdd9 | 2119 | if (l->tk==LEX_STR) { |
ohneta | 0:aae260bdcdd9 | 2120 | LMATCH(LEX_STR); |
ohneta | 0:aae260bdcdd9 | 2121 | } else { |
ohneta | 0:aae260bdcdd9 | 2122 | LMATCH(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2123 | } |
ohneta | 0:aae260bdcdd9 | 2124 | LMATCH(':'); |
ohneta | 0:aae260bdcdd9 | 2125 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2126 | CScriptVarLink *a = base(execute); |
ohneta | 0:aae260bdcdd9 | 2127 | contents->addChild(id, a->var); |
ohneta | 0:aae260bdcdd9 | 2128 | CLEAN(a); |
ohneta | 0:aae260bdcdd9 | 2129 | } |
ohneta | 0:aae260bdcdd9 | 2130 | // no need to clean here, as it will definitely be used |
ohneta | 0:aae260bdcdd9 | 2131 | if (l->tk != '}') LMATCH(','); |
ohneta | 0:aae260bdcdd9 | 2132 | } |
ohneta | 0:aae260bdcdd9 | 2133 | |
ohneta | 0:aae260bdcdd9 | 2134 | LMATCH('}'); |
ohneta | 0:aae260bdcdd9 | 2135 | return new CScriptVarLink(contents); |
ohneta | 0:aae260bdcdd9 | 2136 | } |
ohneta | 0:aae260bdcdd9 | 2137 | if (l->tk=='[') { |
ohneta | 0:aae260bdcdd9 | 2138 | CScriptVar *contents = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_ARRAY); |
ohneta | 0:aae260bdcdd9 | 2139 | /* JSON-style array */ |
ohneta | 0:aae260bdcdd9 | 2140 | LMATCH('['); |
ohneta | 0:aae260bdcdd9 | 2141 | int idx = 0; |
ohneta | 0:aae260bdcdd9 | 2142 | while (l->tk != ']') { |
ohneta | 0:aae260bdcdd9 | 2143 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2144 | char idx_str[16]; // big enough for 2^32 |
ohneta | 0:aae260bdcdd9 | 2145 | sprintf_s(idx_str, sizeof(idx_str), "%d",idx); |
ohneta | 0:aae260bdcdd9 | 2146 | |
ohneta | 0:aae260bdcdd9 | 2147 | CScriptVarLink *a = base(execute); |
ohneta | 0:aae260bdcdd9 | 2148 | contents->addChild(idx_str, a->var); |
ohneta | 0:aae260bdcdd9 | 2149 | CLEAN(a); |
ohneta | 0:aae260bdcdd9 | 2150 | } |
ohneta | 0:aae260bdcdd9 | 2151 | // no need to clean here, as it will definitely be used |
ohneta | 0:aae260bdcdd9 | 2152 | if (l->tk != ']') LMATCH(','); |
ohneta | 0:aae260bdcdd9 | 2153 | idx++; |
ohneta | 0:aae260bdcdd9 | 2154 | } |
ohneta | 0:aae260bdcdd9 | 2155 | LMATCH(']'); |
ohneta | 0:aae260bdcdd9 | 2156 | return new CScriptVarLink(contents); |
ohneta | 0:aae260bdcdd9 | 2157 | } |
ohneta | 0:aae260bdcdd9 | 2158 | if (l->tk==LEX_R_FUNCTION) { |
ohneta | 0:aae260bdcdd9 | 2159 | CScriptVarLink *funcVar = parseFunctionDefinition(); |
ohneta | 0:aae260bdcdd9 | 2160 | if (funcVar->name != TINYJS_TEMP_NAME) |
ohneta | 0:aae260bdcdd9 | 2161 | TRACE("Functions not defined at statement-level are not meant to have a name"); |
ohneta | 0:aae260bdcdd9 | 2162 | return funcVar; |
ohneta | 0:aae260bdcdd9 | 2163 | } |
ohneta | 0:aae260bdcdd9 | 2164 | if (l->tk==LEX_R_NEW) { |
ohneta | 0:aae260bdcdd9 | 2165 | // new -> create a new object |
ohneta | 0:aae260bdcdd9 | 2166 | LMATCH(LEX_R_NEW); |
ohneta | 0:aae260bdcdd9 | 2167 | const string &className = l->tkStr; |
ohneta | 0:aae260bdcdd9 | 2168 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2169 | CScriptVarLink *objClassOrFunc = findInScopes(className); |
ohneta | 0:aae260bdcdd9 | 2170 | if (!objClassOrFunc) { |
ohneta | 0:aae260bdcdd9 | 2171 | TRACE("%s is not a valid class name", className.c_str()); |
ohneta | 0:aae260bdcdd9 | 2172 | return new CScriptVarLink(new CScriptVar()); |
ohneta | 0:aae260bdcdd9 | 2173 | } |
ohneta | 0:aae260bdcdd9 | 2174 | LMATCH(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2175 | CScriptVar *obj = new CScriptVar(TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT); |
ohneta | 0:aae260bdcdd9 | 2176 | CScriptVarLink *objLink = new CScriptVarLink(obj); |
ohneta | 0:aae260bdcdd9 | 2177 | if (objClassOrFunc->var->isFunction()) { |
ohneta | 0:aae260bdcdd9 | 2178 | CLEAN(functionCall(execute, objClassOrFunc, obj)); |
ohneta | 0:aae260bdcdd9 | 2179 | } else { |
ohneta | 0:aae260bdcdd9 | 2180 | obj->addChild(TINYJS_PROTOTYPE_CLASS, objClassOrFunc->var); |
ohneta | 0:aae260bdcdd9 | 2181 | if (l->tk == '(') { |
ohneta | 0:aae260bdcdd9 | 2182 | LMATCH('('); |
ohneta | 0:aae260bdcdd9 | 2183 | LMATCH(')'); |
ohneta | 0:aae260bdcdd9 | 2184 | } |
ohneta | 0:aae260bdcdd9 | 2185 | } |
ohneta | 0:aae260bdcdd9 | 2186 | return objLink; |
ohneta | 0:aae260bdcdd9 | 2187 | } else { |
ohneta | 0:aae260bdcdd9 | 2188 | LMATCH(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2189 | if (l->tk == '(') { |
ohneta | 0:aae260bdcdd9 | 2190 | LMATCH('('); |
ohneta | 0:aae260bdcdd9 | 2191 | LMATCH(')'); |
ohneta | 0:aae260bdcdd9 | 2192 | } |
ohneta | 0:aae260bdcdd9 | 2193 | } |
ohneta | 0:aae260bdcdd9 | 2194 | } |
ohneta | 0:aae260bdcdd9 | 2195 | // Nothing we can do here... just hope it's the end... |
ohneta | 0:aae260bdcdd9 | 2196 | LMATCH(LEX_EOF); |
ohneta | 0:aae260bdcdd9 | 2197 | return 0; |
ohneta | 0:aae260bdcdd9 | 2198 | } |
ohneta | 0:aae260bdcdd9 | 2199 | #endif |
ohneta | 0:aae260bdcdd9 | 2200 | |
ohneta | 0:aae260bdcdd9 | 2201 | CScriptVarLink *CTinyJS::unary(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2202 | CScriptVarLink *a; |
ohneta | 0:aae260bdcdd9 | 2203 | if (l->tk=='!') { |
ohneta | 0:aae260bdcdd9 | 2204 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2205 | l->match('!'); // binary not |
ohneta | 0:aae260bdcdd9 | 2206 | #else |
ohneta | 0:aae260bdcdd9 | 2207 | LMATCH('!'); // binary not |
ohneta | 0:aae260bdcdd9 | 2208 | #endif |
ohneta | 0:aae260bdcdd9 | 2209 | a = factor(execute); |
ohneta | 0:aae260bdcdd9 | 2210 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2211 | CScriptVar zero(0); |
ohneta | 0:aae260bdcdd9 | 2212 | CScriptVar *res = a->var->mathsOp(&zero, LEX_EQUAL); |
ohneta | 0:aae260bdcdd9 | 2213 | CREATE_LINK(a, res); |
ohneta | 0:aae260bdcdd9 | 2214 | } |
ohneta | 0:aae260bdcdd9 | 2215 | } else |
ohneta | 0:aae260bdcdd9 | 2216 | a = factor(execute); |
ohneta | 0:aae260bdcdd9 | 2217 | return a; |
ohneta | 0:aae260bdcdd9 | 2218 | } |
ohneta | 0:aae260bdcdd9 | 2219 | |
ohneta | 0:aae260bdcdd9 | 2220 | CScriptVarLink *CTinyJS::term(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2221 | CScriptVarLink *a = unary(execute); |
ohneta | 0:aae260bdcdd9 | 2222 | while (l->tk=='*' || l->tk=='/' || l->tk=='%') { |
ohneta | 0:aae260bdcdd9 | 2223 | int op = l->tk; |
ohneta | 0:aae260bdcdd9 | 2224 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2225 | l->match(l->tk); |
ohneta | 0:aae260bdcdd9 | 2226 | #else |
ohneta | 0:aae260bdcdd9 | 2227 | LMATCH(l->tk); |
ohneta | 0:aae260bdcdd9 | 2228 | #endif |
ohneta | 0:aae260bdcdd9 | 2229 | CScriptVarLink *b = unary(execute); |
ohneta | 0:aae260bdcdd9 | 2230 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2231 | CScriptVar *res = a->var->mathsOp(b->var, op); |
ohneta | 0:aae260bdcdd9 | 2232 | CREATE_LINK(a, res); |
ohneta | 0:aae260bdcdd9 | 2233 | } |
ohneta | 0:aae260bdcdd9 | 2234 | CLEAN(b); |
ohneta | 0:aae260bdcdd9 | 2235 | } |
ohneta | 0:aae260bdcdd9 | 2236 | return a; |
ohneta | 0:aae260bdcdd9 | 2237 | } |
ohneta | 0:aae260bdcdd9 | 2238 | |
ohneta | 0:aae260bdcdd9 | 2239 | CScriptVarLink *CTinyJS::expression(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2240 | bool negate = false; |
ohneta | 0:aae260bdcdd9 | 2241 | if (l->tk=='-') { |
ohneta | 0:aae260bdcdd9 | 2242 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2243 | l->match('-'); |
ohneta | 0:aae260bdcdd9 | 2244 | #else |
ohneta | 0:aae260bdcdd9 | 2245 | LMATCH('-'); |
ohneta | 0:aae260bdcdd9 | 2246 | #endif |
ohneta | 0:aae260bdcdd9 | 2247 | negate = true; |
ohneta | 0:aae260bdcdd9 | 2248 | } |
ohneta | 0:aae260bdcdd9 | 2249 | CScriptVarLink *a = term(execute); |
ohneta | 0:aae260bdcdd9 | 2250 | if (negate) { |
ohneta | 0:aae260bdcdd9 | 2251 | CScriptVar zero(0); |
ohneta | 0:aae260bdcdd9 | 2252 | CScriptVar *res = zero.mathsOp(a->var, '-'); |
ohneta | 0:aae260bdcdd9 | 2253 | CREATE_LINK(a, res); |
ohneta | 0:aae260bdcdd9 | 2254 | } |
ohneta | 0:aae260bdcdd9 | 2255 | |
ohneta | 0:aae260bdcdd9 | 2256 | while (l->tk=='+' || l->tk=='-' || |
ohneta | 0:aae260bdcdd9 | 2257 | l->tk==LEX_PLUSPLUS || l->tk==LEX_MINUSMINUS) { |
ohneta | 0:aae260bdcdd9 | 2258 | int op = l->tk; |
ohneta | 0:aae260bdcdd9 | 2259 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2260 | l->match(l->tk); |
ohneta | 0:aae260bdcdd9 | 2261 | #else |
ohneta | 0:aae260bdcdd9 | 2262 | LMATCH(l->tk); |
ohneta | 0:aae260bdcdd9 | 2263 | #endif |
ohneta | 0:aae260bdcdd9 | 2264 | if (op==LEX_PLUSPLUS || op==LEX_MINUSMINUS) { |
ohneta | 0:aae260bdcdd9 | 2265 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2266 | CScriptVar one(1); |
ohneta | 0:aae260bdcdd9 | 2267 | CScriptVar *res = a->var->mathsOp(&one, op==LEX_PLUSPLUS ? '+' : '-'); |
ohneta | 0:aae260bdcdd9 | 2268 | CScriptVarLink *oldValue = new CScriptVarLink(a->var); |
ohneta | 0:aae260bdcdd9 | 2269 | // in-place add/subtract |
ohneta | 0:aae260bdcdd9 | 2270 | a->replaceWith(res); |
ohneta | 0:aae260bdcdd9 | 2271 | CLEAN(a); |
ohneta | 0:aae260bdcdd9 | 2272 | a = oldValue; |
ohneta | 0:aae260bdcdd9 | 2273 | } |
ohneta | 0:aae260bdcdd9 | 2274 | } else { |
ohneta | 0:aae260bdcdd9 | 2275 | CScriptVarLink *b = term(execute); |
ohneta | 0:aae260bdcdd9 | 2276 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2277 | // not in-place, so just replace |
ohneta | 0:aae260bdcdd9 | 2278 | CScriptVar *res = a->var->mathsOp(b->var, op); |
ohneta | 0:aae260bdcdd9 | 2279 | CREATE_LINK(a, res); |
ohneta | 0:aae260bdcdd9 | 2280 | } |
ohneta | 0:aae260bdcdd9 | 2281 | CLEAN(b); |
ohneta | 0:aae260bdcdd9 | 2282 | } |
ohneta | 0:aae260bdcdd9 | 2283 | } |
ohneta | 0:aae260bdcdd9 | 2284 | return a; |
ohneta | 0:aae260bdcdd9 | 2285 | } |
ohneta | 0:aae260bdcdd9 | 2286 | |
ohneta | 0:aae260bdcdd9 | 2287 | CScriptVarLink *CTinyJS::shift(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2288 | CScriptVarLink *a = expression(execute); |
ohneta | 0:aae260bdcdd9 | 2289 | if (l->tk==LEX_LSHIFT || l->tk==LEX_RSHIFT || l->tk==LEX_RSHIFTUNSIGNED) { |
ohneta | 0:aae260bdcdd9 | 2290 | int op = l->tk; |
ohneta | 0:aae260bdcdd9 | 2291 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2292 | l->match(op); |
ohneta | 0:aae260bdcdd9 | 2293 | #else |
ohneta | 0:aae260bdcdd9 | 2294 | LMATCH(op); |
ohneta | 0:aae260bdcdd9 | 2295 | #endif |
ohneta | 0:aae260bdcdd9 | 2296 | CScriptVarLink *b = base(execute); |
ohneta | 0:aae260bdcdd9 | 2297 | int shift = execute ? b->var->getInt() : 0; |
ohneta | 0:aae260bdcdd9 | 2298 | CLEAN(b); |
ohneta | 0:aae260bdcdd9 | 2299 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2300 | if (op==LEX_LSHIFT) a->var->setInt(a->var->getInt() << shift); |
ohneta | 0:aae260bdcdd9 | 2301 | if (op==LEX_RSHIFT) a->var->setInt(a->var->getInt() >> shift); |
ohneta | 0:aae260bdcdd9 | 2302 | if (op==LEX_RSHIFTUNSIGNED) a->var->setInt(((unsigned int)a->var->getInt()) >> shift); |
ohneta | 0:aae260bdcdd9 | 2303 | } |
ohneta | 0:aae260bdcdd9 | 2304 | } |
ohneta | 0:aae260bdcdd9 | 2305 | return a; |
ohneta | 0:aae260bdcdd9 | 2306 | } |
ohneta | 0:aae260bdcdd9 | 2307 | |
ohneta | 0:aae260bdcdd9 | 2308 | CScriptVarLink *CTinyJS::condition(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2309 | CScriptVarLink *a = shift(execute); |
ohneta | 0:aae260bdcdd9 | 2310 | CScriptVarLink *b; |
ohneta | 0:aae260bdcdd9 | 2311 | while (l->tk==LEX_EQUAL || l->tk==LEX_NEQUAL || |
ohneta | 0:aae260bdcdd9 | 2312 | l->tk==LEX_TYPEEQUAL || l->tk==LEX_NTYPEEQUAL || |
ohneta | 0:aae260bdcdd9 | 2313 | l->tk==LEX_LEQUAL || l->tk==LEX_GEQUAL || |
ohneta | 0:aae260bdcdd9 | 2314 | l->tk=='<' || l->tk=='>') { |
ohneta | 0:aae260bdcdd9 | 2315 | int op = l->tk; |
ohneta | 0:aae260bdcdd9 | 2316 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2317 | l->match(l->tk); |
ohneta | 0:aae260bdcdd9 | 2318 | #else |
ohneta | 0:aae260bdcdd9 | 2319 | LMATCH(l->tk); |
ohneta | 0:aae260bdcdd9 | 2320 | #endif |
ohneta | 0:aae260bdcdd9 | 2321 | b = shift(execute); |
ohneta | 0:aae260bdcdd9 | 2322 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2323 | CScriptVar *res = a->var->mathsOp(b->var, op); |
ohneta | 0:aae260bdcdd9 | 2324 | CREATE_LINK(a,res); |
ohneta | 0:aae260bdcdd9 | 2325 | } |
ohneta | 0:aae260bdcdd9 | 2326 | CLEAN(b); |
ohneta | 0:aae260bdcdd9 | 2327 | } |
ohneta | 0:aae260bdcdd9 | 2328 | return a; |
ohneta | 0:aae260bdcdd9 | 2329 | } |
ohneta | 0:aae260bdcdd9 | 2330 | |
ohneta | 0:aae260bdcdd9 | 2331 | CScriptVarLink *CTinyJS::logic(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2332 | CScriptVarLink *a = condition(execute); |
ohneta | 0:aae260bdcdd9 | 2333 | CScriptVarLink *b; |
ohneta | 0:aae260bdcdd9 | 2334 | while (l->tk=='&' || l->tk=='|' || l->tk=='^' || l->tk==LEX_ANDAND || l->tk==LEX_OROR) { |
ohneta | 0:aae260bdcdd9 | 2335 | bool noexecute = false; |
ohneta | 0:aae260bdcdd9 | 2336 | int op = l->tk; |
ohneta | 0:aae260bdcdd9 | 2337 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2338 | l->match(l->tk); |
ohneta | 0:aae260bdcdd9 | 2339 | #else |
ohneta | 0:aae260bdcdd9 | 2340 | LMATCH(l->tk); |
ohneta | 0:aae260bdcdd9 | 2341 | #endif |
ohneta | 0:aae260bdcdd9 | 2342 | bool shortCircuit = false; |
ohneta | 0:aae260bdcdd9 | 2343 | bool boolean = false; |
ohneta | 0:aae260bdcdd9 | 2344 | // if we have short-circuit ops, then if we know the outcome |
ohneta | 0:aae260bdcdd9 | 2345 | // we don't bother to execute the other op. Even if not |
ohneta | 0:aae260bdcdd9 | 2346 | // we need to tell mathsOp it's an & or | |
ohneta | 0:aae260bdcdd9 | 2347 | if (op==LEX_ANDAND) { |
ohneta | 0:aae260bdcdd9 | 2348 | op = '&'; |
ohneta | 0:aae260bdcdd9 | 2349 | shortCircuit = !a->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2350 | boolean = true; |
ohneta | 0:aae260bdcdd9 | 2351 | } else if (op==LEX_OROR) { |
ohneta | 0:aae260bdcdd9 | 2352 | op = '|'; |
ohneta | 0:aae260bdcdd9 | 2353 | shortCircuit = a->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2354 | boolean = true; |
ohneta | 0:aae260bdcdd9 | 2355 | } |
ohneta | 0:aae260bdcdd9 | 2356 | b = condition(shortCircuit ? noexecute : execute); |
ohneta | 0:aae260bdcdd9 | 2357 | if (execute && !shortCircuit) { |
ohneta | 0:aae260bdcdd9 | 2358 | if (boolean) { |
ohneta | 0:aae260bdcdd9 | 2359 | CScriptVar *newa = new CScriptVar(a->var->getBool()); |
ohneta | 0:aae260bdcdd9 | 2360 | CScriptVar *newb = new CScriptVar(b->var->getBool()); |
ohneta | 0:aae260bdcdd9 | 2361 | CREATE_LINK(a, newa); |
ohneta | 0:aae260bdcdd9 | 2362 | CREATE_LINK(b, newb); |
ohneta | 0:aae260bdcdd9 | 2363 | } |
ohneta | 0:aae260bdcdd9 | 2364 | CScriptVar *res = a->var->mathsOp(b->var, op); |
ohneta | 0:aae260bdcdd9 | 2365 | CREATE_LINK(a, res); |
ohneta | 0:aae260bdcdd9 | 2366 | } |
ohneta | 0:aae260bdcdd9 | 2367 | CLEAN(b); |
ohneta | 0:aae260bdcdd9 | 2368 | } |
ohneta | 0:aae260bdcdd9 | 2369 | return a; |
ohneta | 0:aae260bdcdd9 | 2370 | } |
ohneta | 0:aae260bdcdd9 | 2371 | |
ohneta | 0:aae260bdcdd9 | 2372 | CScriptVarLink *CTinyJS::ternary(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2373 | CScriptVarLink *lhs = logic(execute); |
ohneta | 0:aae260bdcdd9 | 2374 | bool noexec = false; |
ohneta | 0:aae260bdcdd9 | 2375 | if (l->tk=='?') { |
ohneta | 0:aae260bdcdd9 | 2376 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2377 | l->match('?'); |
ohneta | 0:aae260bdcdd9 | 2378 | #else |
ohneta | 0:aae260bdcdd9 | 2379 | LMATCH('?'); |
ohneta | 0:aae260bdcdd9 | 2380 | #endif |
ohneta | 0:aae260bdcdd9 | 2381 | if (!execute) { |
ohneta | 0:aae260bdcdd9 | 2382 | CLEAN(lhs); |
ohneta | 0:aae260bdcdd9 | 2383 | CLEAN(base(noexec)); |
ohneta | 0:aae260bdcdd9 | 2384 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2385 | l->match(':'); |
ohneta | 0:aae260bdcdd9 | 2386 | #else |
ohneta | 0:aae260bdcdd9 | 2387 | LMATCH(':'); |
ohneta | 0:aae260bdcdd9 | 2388 | #endif |
ohneta | 0:aae260bdcdd9 | 2389 | CLEAN(base(noexec)); |
ohneta | 0:aae260bdcdd9 | 2390 | } else { |
ohneta | 0:aae260bdcdd9 | 2391 | bool first = lhs->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2392 | CLEAN(lhs); |
ohneta | 0:aae260bdcdd9 | 2393 | if (first) { |
ohneta | 0:aae260bdcdd9 | 2394 | lhs = base(execute); |
ohneta | 0:aae260bdcdd9 | 2395 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2396 | l->match(':'); |
ohneta | 0:aae260bdcdd9 | 2397 | #else |
ohneta | 0:aae260bdcdd9 | 2398 | LMATCH(':'); |
ohneta | 0:aae260bdcdd9 | 2399 | #endif |
ohneta | 0:aae260bdcdd9 | 2400 | CLEAN(base(noexec)); |
ohneta | 0:aae260bdcdd9 | 2401 | } else { |
ohneta | 0:aae260bdcdd9 | 2402 | CLEAN(base(noexec)); |
ohneta | 0:aae260bdcdd9 | 2403 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2404 | l->match(':'); |
ohneta | 0:aae260bdcdd9 | 2405 | #else |
ohneta | 0:aae260bdcdd9 | 2406 | LMATCH(':'); |
ohneta | 0:aae260bdcdd9 | 2407 | #endif |
ohneta | 0:aae260bdcdd9 | 2408 | lhs = base(execute); |
ohneta | 0:aae260bdcdd9 | 2409 | } |
ohneta | 0:aae260bdcdd9 | 2410 | } |
ohneta | 0:aae260bdcdd9 | 2411 | } |
ohneta | 0:aae260bdcdd9 | 2412 | |
ohneta | 0:aae260bdcdd9 | 2413 | return lhs; |
ohneta | 0:aae260bdcdd9 | 2414 | } |
ohneta | 0:aae260bdcdd9 | 2415 | |
ohneta | 0:aae260bdcdd9 | 2416 | CScriptVarLink *CTinyJS::base(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2417 | CScriptVarLink *lhs = ternary(execute); |
ohneta | 0:aae260bdcdd9 | 2418 | if (l->tk=='=' || l->tk==LEX_PLUSEQUAL || l->tk==LEX_MINUSEQUAL) { |
ohneta | 0:aae260bdcdd9 | 2419 | /* If we're assigning to this and we don't have a parent, |
ohneta | 0:aae260bdcdd9 | 2420 | * add it to the symbol table root as per JavaScript. */ |
ohneta | 0:aae260bdcdd9 | 2421 | if (execute && !lhs->owned) { |
ohneta | 0:aae260bdcdd9 | 2422 | if (lhs->name.length()>0) { |
ohneta | 0:aae260bdcdd9 | 2423 | CScriptVarLink *realLhs = root->addChildNoDup(lhs->name, lhs->var); |
ohneta | 0:aae260bdcdd9 | 2424 | CLEAN(lhs); |
ohneta | 0:aae260bdcdd9 | 2425 | lhs = realLhs; |
ohneta | 0:aae260bdcdd9 | 2426 | } else |
ohneta | 0:aae260bdcdd9 | 2427 | TRACE("Trying to assign to an un-named type\n"); |
ohneta | 0:aae260bdcdd9 | 2428 | } |
ohneta | 0:aae260bdcdd9 | 2429 | |
ohneta | 0:aae260bdcdd9 | 2430 | int op = l->tk; |
ohneta | 0:aae260bdcdd9 | 2431 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2432 | l->match(l->tk); |
ohneta | 0:aae260bdcdd9 | 2433 | #else |
ohneta | 0:aae260bdcdd9 | 2434 | LMATCH(l->tk); |
ohneta | 0:aae260bdcdd9 | 2435 | #endif |
ohneta | 0:aae260bdcdd9 | 2436 | CScriptVarLink *rhs = base(execute); |
ohneta | 0:aae260bdcdd9 | 2437 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2438 | if (op=='=') { |
ohneta | 0:aae260bdcdd9 | 2439 | lhs->replaceWith(rhs); |
ohneta | 0:aae260bdcdd9 | 2440 | } else if (op==LEX_PLUSEQUAL) { |
ohneta | 0:aae260bdcdd9 | 2441 | CScriptVar *res = lhs->var->mathsOp(rhs->var, '+'); |
ohneta | 0:aae260bdcdd9 | 2442 | lhs->replaceWith(res); |
ohneta | 0:aae260bdcdd9 | 2443 | } else if (op==LEX_MINUSEQUAL) { |
ohneta | 0:aae260bdcdd9 | 2444 | CScriptVar *res = lhs->var->mathsOp(rhs->var, '-'); |
ohneta | 0:aae260bdcdd9 | 2445 | lhs->replaceWith(res); |
ohneta | 0:aae260bdcdd9 | 2446 | } else ASSERT(0); |
ohneta | 0:aae260bdcdd9 | 2447 | } |
ohneta | 0:aae260bdcdd9 | 2448 | CLEAN(rhs); |
ohneta | 0:aae260bdcdd9 | 2449 | } |
ohneta | 0:aae260bdcdd9 | 2450 | return lhs; |
ohneta | 0:aae260bdcdd9 | 2451 | } |
ohneta | 0:aae260bdcdd9 | 2452 | |
ohneta | 0:aae260bdcdd9 | 2453 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2454 | void CTinyJS::block(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2455 | l->match('{'); |
ohneta | 0:aae260bdcdd9 | 2456 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2457 | while (l->tk && l->tk!='}') |
ohneta | 0:aae260bdcdd9 | 2458 | statement(execute); |
ohneta | 0:aae260bdcdd9 | 2459 | l->match('}'); |
ohneta | 0:aae260bdcdd9 | 2460 | } else { |
ohneta | 0:aae260bdcdd9 | 2461 | // fast skip of blocks |
ohneta | 0:aae260bdcdd9 | 2462 | int brackets = 1; |
ohneta | 0:aae260bdcdd9 | 2463 | while (l->tk && brackets) { |
ohneta | 0:aae260bdcdd9 | 2464 | if (l->tk == '{') brackets++; |
ohneta | 0:aae260bdcdd9 | 2465 | if (l->tk == '}') brackets--; |
ohneta | 0:aae260bdcdd9 | 2466 | l->match(l->tk); |
ohneta | 0:aae260bdcdd9 | 2467 | } |
ohneta | 0:aae260bdcdd9 | 2468 | } |
ohneta | 0:aae260bdcdd9 | 2469 | } |
ohneta | 0:aae260bdcdd9 | 2470 | #else |
ohneta | 0:aae260bdcdd9 | 2471 | void CTinyJS::block(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2472 | LMATCH_VOID('{'); |
ohneta | 0:aae260bdcdd9 | 2473 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2474 | while (l->tk && l->tk!='}') |
ohneta | 0:aae260bdcdd9 | 2475 | statement(execute); |
ohneta | 0:aae260bdcdd9 | 2476 | LMATCH_VOID('}'); |
ohneta | 0:aae260bdcdd9 | 2477 | } else { |
ohneta | 0:aae260bdcdd9 | 2478 | // fast skip of blocks |
ohneta | 0:aae260bdcdd9 | 2479 | int brackets = 1; |
ohneta | 0:aae260bdcdd9 | 2480 | while (l->tk && brackets) { |
ohneta | 0:aae260bdcdd9 | 2481 | if (l->tk == '{') brackets++; |
ohneta | 0:aae260bdcdd9 | 2482 | if (l->tk == '}') brackets--; |
ohneta | 0:aae260bdcdd9 | 2483 | LMATCH_VOID(l->tk); |
ohneta | 0:aae260bdcdd9 | 2484 | } |
ohneta | 0:aae260bdcdd9 | 2485 | } |
ohneta | 0:aae260bdcdd9 | 2486 | } |
ohneta | 0:aae260bdcdd9 | 2487 | #endif |
ohneta | 0:aae260bdcdd9 | 2488 | |
ohneta | 0:aae260bdcdd9 | 2489 | #ifndef MBED |
ohneta | 0:aae260bdcdd9 | 2490 | void CTinyJS::statement(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2491 | if (l->tk==LEX_ID || |
ohneta | 0:aae260bdcdd9 | 2492 | l->tk==LEX_INT || |
ohneta | 0:aae260bdcdd9 | 2493 | l->tk==LEX_FLOAT || |
ohneta | 0:aae260bdcdd9 | 2494 | l->tk==LEX_STR || |
ohneta | 0:aae260bdcdd9 | 2495 | l->tk=='-') { |
ohneta | 0:aae260bdcdd9 | 2496 | /* Execute a simple statement that only contains basic arithmetic... */ |
ohneta | 0:aae260bdcdd9 | 2497 | CLEAN(base(execute)); |
ohneta | 0:aae260bdcdd9 | 2498 | l->match(';'); |
ohneta | 0:aae260bdcdd9 | 2499 | } else if (l->tk=='{') { |
ohneta | 0:aae260bdcdd9 | 2500 | /* A block of code */ |
ohneta | 0:aae260bdcdd9 | 2501 | block(execute); |
ohneta | 0:aae260bdcdd9 | 2502 | } else if (l->tk==';') { |
ohneta | 0:aae260bdcdd9 | 2503 | /* Empty statement - to allow things like ;;; */ |
ohneta | 0:aae260bdcdd9 | 2504 | l->match(';'); |
ohneta | 0:aae260bdcdd9 | 2505 | } else if (l->tk==LEX_R_VAR) { |
ohneta | 0:aae260bdcdd9 | 2506 | /* variable creation. TODO - we need a better way of parsing the left |
ohneta | 0:aae260bdcdd9 | 2507 | * hand side. Maybe just have a flag called can_create_var that we |
ohneta | 0:aae260bdcdd9 | 2508 | * set and then we parse as if we're doing a normal equals.*/ |
ohneta | 0:aae260bdcdd9 | 2509 | l->match(LEX_R_VAR); |
ohneta | 0:aae260bdcdd9 | 2510 | while (l->tk != ';') { |
ohneta | 0:aae260bdcdd9 | 2511 | CScriptVarLink *a = 0; |
ohneta | 0:aae260bdcdd9 | 2512 | if (execute) |
ohneta | 0:aae260bdcdd9 | 2513 | a = scopes.back()->findChildOrCreate(l->tkStr); |
ohneta | 0:aae260bdcdd9 | 2514 | l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2515 | // now do stuff defined with dots |
ohneta | 0:aae260bdcdd9 | 2516 | while (l->tk == '.') { |
ohneta | 0:aae260bdcdd9 | 2517 | l->match('.'); |
ohneta | 0:aae260bdcdd9 | 2518 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2519 | CScriptVarLink *lastA = a; |
ohneta | 0:aae260bdcdd9 | 2520 | a = lastA->var->findChildOrCreate(l->tkStr); |
ohneta | 0:aae260bdcdd9 | 2521 | } |
ohneta | 0:aae260bdcdd9 | 2522 | l->match(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2523 | } |
ohneta | 0:aae260bdcdd9 | 2524 | // sort out initialiser |
ohneta | 0:aae260bdcdd9 | 2525 | if (l->tk == '=') { |
ohneta | 0:aae260bdcdd9 | 2526 | l->match('='); |
ohneta | 0:aae260bdcdd9 | 2527 | CScriptVarLink *var = base(execute); |
ohneta | 0:aae260bdcdd9 | 2528 | if (execute) |
ohneta | 0:aae260bdcdd9 | 2529 | a->replaceWith(var); |
ohneta | 0:aae260bdcdd9 | 2530 | CLEAN(var); |
ohneta | 0:aae260bdcdd9 | 2531 | } |
ohneta | 0:aae260bdcdd9 | 2532 | if (l->tk != ';') |
ohneta | 0:aae260bdcdd9 | 2533 | l->match(','); |
ohneta | 0:aae260bdcdd9 | 2534 | } |
ohneta | 0:aae260bdcdd9 | 2535 | l->match(';'); |
ohneta | 0:aae260bdcdd9 | 2536 | } else if (l->tk==LEX_R_IF) { |
ohneta | 0:aae260bdcdd9 | 2537 | l->match(LEX_R_IF); |
ohneta | 0:aae260bdcdd9 | 2538 | l->match('('); |
ohneta | 0:aae260bdcdd9 | 2539 | CScriptVarLink *var = base(execute); |
ohneta | 0:aae260bdcdd9 | 2540 | l->match(')'); |
ohneta | 0:aae260bdcdd9 | 2541 | bool cond = execute && var->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2542 | CLEAN(var); |
ohneta | 0:aae260bdcdd9 | 2543 | bool noexecute = false; // because we need to be abl;e to write to it |
ohneta | 0:aae260bdcdd9 | 2544 | statement(cond ? execute : noexecute); |
ohneta | 0:aae260bdcdd9 | 2545 | if (l->tk==LEX_R_ELSE) { |
ohneta | 0:aae260bdcdd9 | 2546 | l->match(LEX_R_ELSE); |
ohneta | 0:aae260bdcdd9 | 2547 | statement(cond ? noexecute : execute); |
ohneta | 0:aae260bdcdd9 | 2548 | } |
ohneta | 0:aae260bdcdd9 | 2549 | } else if (l->tk==LEX_R_WHILE) { |
ohneta | 0:aae260bdcdd9 | 2550 | // We do repetition by pulling out the string representing our statement |
ohneta | 0:aae260bdcdd9 | 2551 | // there's definitely some opportunity for optimisation here |
ohneta | 0:aae260bdcdd9 | 2552 | l->match(LEX_R_WHILE); |
ohneta | 0:aae260bdcdd9 | 2553 | l->match('('); |
ohneta | 0:aae260bdcdd9 | 2554 | int whileCondStart = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 2555 | bool noexecute = false; |
ohneta | 0:aae260bdcdd9 | 2556 | CScriptVarLink *cond = base(execute); |
ohneta | 0:aae260bdcdd9 | 2557 | bool loopCond = execute && cond->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2558 | CLEAN(cond); |
ohneta | 0:aae260bdcdd9 | 2559 | CScriptLex *whileCond = l->getSubLex(whileCondStart); |
ohneta | 0:aae260bdcdd9 | 2560 | l->match(')'); |
ohneta | 0:aae260bdcdd9 | 2561 | int whileBodyStart = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 2562 | statement(loopCond ? execute : noexecute); |
ohneta | 0:aae260bdcdd9 | 2563 | CScriptLex *whileBody = l->getSubLex(whileBodyStart); |
ohneta | 0:aae260bdcdd9 | 2564 | CScriptLex *oldLex = l; |
ohneta | 0:aae260bdcdd9 | 2565 | int loopCount = TINYJS_LOOP_MAX_ITERATIONS; |
ohneta | 0:aae260bdcdd9 | 2566 | while (loopCond && loopCount-->0) { |
ohneta | 0:aae260bdcdd9 | 2567 | whileCond->reset(); |
ohneta | 0:aae260bdcdd9 | 2568 | l = whileCond; |
ohneta | 0:aae260bdcdd9 | 2569 | cond = base(execute); |
ohneta | 0:aae260bdcdd9 | 2570 | loopCond = execute && cond->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2571 | CLEAN(cond); |
ohneta | 0:aae260bdcdd9 | 2572 | if (loopCond) { |
ohneta | 0:aae260bdcdd9 | 2573 | whileBody->reset(); |
ohneta | 0:aae260bdcdd9 | 2574 | l = whileBody; |
ohneta | 0:aae260bdcdd9 | 2575 | statement(execute); |
ohneta | 0:aae260bdcdd9 | 2576 | } |
ohneta | 0:aae260bdcdd9 | 2577 | } |
ohneta | 0:aae260bdcdd9 | 2578 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 2579 | delete whileCond; |
ohneta | 0:aae260bdcdd9 | 2580 | delete whileBody; |
ohneta | 0:aae260bdcdd9 | 2581 | |
ohneta | 0:aae260bdcdd9 | 2582 | if (loopCount<=0) { |
ohneta | 0:aae260bdcdd9 | 2583 | root->trace(); |
ohneta | 0:aae260bdcdd9 | 2584 | TRACE("WHILE Loop exceeded %d iterations at %s\n", TINYJS_LOOP_MAX_ITERATIONS, l->getPosition().c_str()); |
ohneta | 0:aae260bdcdd9 | 2585 | throw new CScriptException("LOOP_ERROR"); |
ohneta | 0:aae260bdcdd9 | 2586 | } |
ohneta | 0:aae260bdcdd9 | 2587 | } else if (l->tk==LEX_R_FOR) { |
ohneta | 0:aae260bdcdd9 | 2588 | l->match(LEX_R_FOR); |
ohneta | 0:aae260bdcdd9 | 2589 | l->match('('); |
ohneta | 0:aae260bdcdd9 | 2590 | statement(execute); // initialisation |
ohneta | 0:aae260bdcdd9 | 2591 | //l->match(';'); |
ohneta | 0:aae260bdcdd9 | 2592 | int forCondStart = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 2593 | bool noexecute = false; |
ohneta | 0:aae260bdcdd9 | 2594 | CScriptVarLink *cond = base(execute); // condition |
ohneta | 0:aae260bdcdd9 | 2595 | bool loopCond = execute && cond->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2596 | CLEAN(cond); |
ohneta | 0:aae260bdcdd9 | 2597 | CScriptLex *forCond = l->getSubLex(forCondStart); |
ohneta | 0:aae260bdcdd9 | 2598 | l->match(';'); |
ohneta | 0:aae260bdcdd9 | 2599 | int forIterStart = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 2600 | CLEAN(base(noexecute)); // iterator |
ohneta | 0:aae260bdcdd9 | 2601 | CScriptLex *forIter = l->getSubLex(forIterStart); |
ohneta | 0:aae260bdcdd9 | 2602 | l->match(')'); |
ohneta | 0:aae260bdcdd9 | 2603 | int forBodyStart = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 2604 | statement(loopCond ? execute : noexecute); |
ohneta | 0:aae260bdcdd9 | 2605 | CScriptLex *forBody = l->getSubLex(forBodyStart); |
ohneta | 0:aae260bdcdd9 | 2606 | CScriptLex *oldLex = l; |
ohneta | 0:aae260bdcdd9 | 2607 | if (loopCond) { |
ohneta | 0:aae260bdcdd9 | 2608 | forIter->reset(); |
ohneta | 0:aae260bdcdd9 | 2609 | l = forIter; |
ohneta | 0:aae260bdcdd9 | 2610 | CLEAN(base(execute)); |
ohneta | 0:aae260bdcdd9 | 2611 | } |
ohneta | 0:aae260bdcdd9 | 2612 | int loopCount = TINYJS_LOOP_MAX_ITERATIONS; |
ohneta | 0:aae260bdcdd9 | 2613 | while (execute && loopCond && loopCount-->0) { |
ohneta | 0:aae260bdcdd9 | 2614 | forCond->reset(); |
ohneta | 0:aae260bdcdd9 | 2615 | l = forCond; |
ohneta | 0:aae260bdcdd9 | 2616 | cond = base(execute); |
ohneta | 0:aae260bdcdd9 | 2617 | loopCond = cond->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2618 | CLEAN(cond); |
ohneta | 0:aae260bdcdd9 | 2619 | if (execute && loopCond) { |
ohneta | 0:aae260bdcdd9 | 2620 | forBody->reset(); |
ohneta | 0:aae260bdcdd9 | 2621 | l = forBody; |
ohneta | 0:aae260bdcdd9 | 2622 | statement(execute); |
ohneta | 0:aae260bdcdd9 | 2623 | } |
ohneta | 0:aae260bdcdd9 | 2624 | if (execute && loopCond) { |
ohneta | 0:aae260bdcdd9 | 2625 | forIter->reset(); |
ohneta | 0:aae260bdcdd9 | 2626 | l = forIter; |
ohneta | 0:aae260bdcdd9 | 2627 | CLEAN(base(execute)); |
ohneta | 0:aae260bdcdd9 | 2628 | } |
ohneta | 0:aae260bdcdd9 | 2629 | } |
ohneta | 0:aae260bdcdd9 | 2630 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 2631 | delete forCond; |
ohneta | 0:aae260bdcdd9 | 2632 | delete forIter; |
ohneta | 0:aae260bdcdd9 | 2633 | delete forBody; |
ohneta | 0:aae260bdcdd9 | 2634 | if (loopCount<=0) { |
ohneta | 0:aae260bdcdd9 | 2635 | root->trace(); |
ohneta | 0:aae260bdcdd9 | 2636 | TRACE("FOR Loop exceeded %d iterations at %s\n", TINYJS_LOOP_MAX_ITERATIONS, l->getPosition().c_str()); |
ohneta | 0:aae260bdcdd9 | 2637 | throw new CScriptException("LOOP_ERROR"); |
ohneta | 0:aae260bdcdd9 | 2638 | } |
ohneta | 0:aae260bdcdd9 | 2639 | } else if (l->tk==LEX_R_RETURN) { |
ohneta | 0:aae260bdcdd9 | 2640 | l->match(LEX_R_RETURN); |
ohneta | 0:aae260bdcdd9 | 2641 | CScriptVarLink *result = 0; |
ohneta | 0:aae260bdcdd9 | 2642 | if (l->tk != ';') |
ohneta | 0:aae260bdcdd9 | 2643 | result = base(execute); |
ohneta | 0:aae260bdcdd9 | 2644 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2645 | CScriptVarLink *resultVar = scopes.back()->findChild(TINYJS_RETURN_VAR); |
ohneta | 0:aae260bdcdd9 | 2646 | if (resultVar) |
ohneta | 0:aae260bdcdd9 | 2647 | resultVar->replaceWith(result); |
ohneta | 0:aae260bdcdd9 | 2648 | else |
ohneta | 0:aae260bdcdd9 | 2649 | TRACE("RETURN statement, but not in a function.\n"); |
ohneta | 0:aae260bdcdd9 | 2650 | execute = false; |
ohneta | 0:aae260bdcdd9 | 2651 | } |
ohneta | 0:aae260bdcdd9 | 2652 | CLEAN(result); |
ohneta | 0:aae260bdcdd9 | 2653 | l->match(';'); |
ohneta | 0:aae260bdcdd9 | 2654 | } else if (l->tk==LEX_R_FUNCTION) { |
ohneta | 0:aae260bdcdd9 | 2655 | CScriptVarLink *funcVar = parseFunctionDefinition(); |
ohneta | 0:aae260bdcdd9 | 2656 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2657 | if (funcVar->name == TINYJS_TEMP_NAME) |
ohneta | 0:aae260bdcdd9 | 2658 | TRACE("Functions defined at statement-level are meant to have a name\n"); |
ohneta | 0:aae260bdcdd9 | 2659 | else |
ohneta | 0:aae260bdcdd9 | 2660 | scopes.back()->addChildNoDup(funcVar->name, funcVar->var); |
ohneta | 0:aae260bdcdd9 | 2661 | } |
ohneta | 0:aae260bdcdd9 | 2662 | CLEAN(funcVar); |
ohneta | 0:aae260bdcdd9 | 2663 | } else l->match(LEX_EOF); |
ohneta | 0:aae260bdcdd9 | 2664 | } |
ohneta | 0:aae260bdcdd9 | 2665 | |
ohneta | 0:aae260bdcdd9 | 2666 | #else |
ohneta | 0:aae260bdcdd9 | 2667 | |
ohneta | 0:aae260bdcdd9 | 2668 | void CTinyJS::statement(bool &execute) { |
ohneta | 0:aae260bdcdd9 | 2669 | if (l->tk==LEX_ID || |
ohneta | 0:aae260bdcdd9 | 2670 | l->tk==LEX_INT || |
ohneta | 0:aae260bdcdd9 | 2671 | l->tk==LEX_FLOAT || |
ohneta | 0:aae260bdcdd9 | 2672 | l->tk==LEX_STR || |
ohneta | 0:aae260bdcdd9 | 2673 | l->tk=='-') { |
ohneta | 0:aae260bdcdd9 | 2674 | /* Execute a simple statement that only contains basic arithmetic... */ |
ohneta | 0:aae260bdcdd9 | 2675 | CLEAN(base(execute)); |
ohneta | 0:aae260bdcdd9 | 2676 | LMATCH_VOID(';'); |
ohneta | 0:aae260bdcdd9 | 2677 | } else if (l->tk=='{') { |
ohneta | 0:aae260bdcdd9 | 2678 | /* A block of code */ |
ohneta | 0:aae260bdcdd9 | 2679 | block(execute); |
ohneta | 0:aae260bdcdd9 | 2680 | } else if (l->tk==';') { |
ohneta | 0:aae260bdcdd9 | 2681 | /* Empty statement - to allow things like ;;; */ |
ohneta | 0:aae260bdcdd9 | 2682 | LMATCH_VOID(';'); |
ohneta | 0:aae260bdcdd9 | 2683 | } else if (l->tk==LEX_R_VAR) { |
ohneta | 0:aae260bdcdd9 | 2684 | /* variable creation. TODO - we need a better way of parsing the left |
ohneta | 0:aae260bdcdd9 | 2685 | * hand side. Maybe just have a flag called can_create_var that we |
ohneta | 0:aae260bdcdd9 | 2686 | * set and then we parse as if we're doing a normal equals.*/ |
ohneta | 0:aae260bdcdd9 | 2687 | LMATCH_VOID(LEX_R_VAR); |
ohneta | 0:aae260bdcdd9 | 2688 | while (l->tk != ';') { |
ohneta | 0:aae260bdcdd9 | 2689 | CScriptVarLink *a = 0; |
ohneta | 0:aae260bdcdd9 | 2690 | if (execute) |
ohneta | 0:aae260bdcdd9 | 2691 | a = scopes.back()->findChildOrCreate(l->tkStr); |
ohneta | 0:aae260bdcdd9 | 2692 | LMATCH_VOID(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2693 | // now do stuff defined with dots |
ohneta | 0:aae260bdcdd9 | 2694 | while (l->tk == '.') { |
ohneta | 0:aae260bdcdd9 | 2695 | LMATCH_VOID('.'); |
ohneta | 0:aae260bdcdd9 | 2696 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2697 | CScriptVarLink *lastA = a; |
ohneta | 0:aae260bdcdd9 | 2698 | a = lastA->var->findChildOrCreate(l->tkStr); |
ohneta | 0:aae260bdcdd9 | 2699 | } |
ohneta | 0:aae260bdcdd9 | 2700 | LMATCH_VOID(LEX_ID); |
ohneta | 0:aae260bdcdd9 | 2701 | } |
ohneta | 0:aae260bdcdd9 | 2702 | // sort out initialiser |
ohneta | 0:aae260bdcdd9 | 2703 | if (l->tk == '=') { |
ohneta | 0:aae260bdcdd9 | 2704 | LMATCH_VOID('='); |
ohneta | 0:aae260bdcdd9 | 2705 | CScriptVarLink *var = base(execute); |
ohneta | 0:aae260bdcdd9 | 2706 | if (execute) |
ohneta | 0:aae260bdcdd9 | 2707 | a->replaceWith(var); |
ohneta | 0:aae260bdcdd9 | 2708 | CLEAN(var); |
ohneta | 0:aae260bdcdd9 | 2709 | } |
ohneta | 0:aae260bdcdd9 | 2710 | if (l->tk != ';') |
ohneta | 0:aae260bdcdd9 | 2711 | LMATCH_VOID(','); |
ohneta | 0:aae260bdcdd9 | 2712 | } |
ohneta | 0:aae260bdcdd9 | 2713 | LMATCH_VOID(';'); |
ohneta | 0:aae260bdcdd9 | 2714 | } else if (l->tk==LEX_R_IF) { |
ohneta | 0:aae260bdcdd9 | 2715 | LMATCH_VOID(LEX_R_IF); |
ohneta | 0:aae260bdcdd9 | 2716 | LMATCH_VOID('('); |
ohneta | 0:aae260bdcdd9 | 2717 | CScriptVarLink *var = base(execute); |
ohneta | 0:aae260bdcdd9 | 2718 | LMATCH_VOID(')'); |
ohneta | 0:aae260bdcdd9 | 2719 | bool cond = execute && var->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2720 | CLEAN(var); |
ohneta | 0:aae260bdcdd9 | 2721 | bool noexecute = false; // because we need to be abl;e to write to it |
ohneta | 0:aae260bdcdd9 | 2722 | statement(cond ? execute : noexecute); |
ohneta | 0:aae260bdcdd9 | 2723 | if (l->tk==LEX_R_ELSE) { |
ohneta | 0:aae260bdcdd9 | 2724 | LMATCH_VOID(LEX_R_ELSE); |
ohneta | 0:aae260bdcdd9 | 2725 | statement(cond ? noexecute : execute); |
ohneta | 0:aae260bdcdd9 | 2726 | } |
ohneta | 0:aae260bdcdd9 | 2727 | } else if (l->tk==LEX_R_WHILE) { |
ohneta | 0:aae260bdcdd9 | 2728 | // We do repetition by pulling out the string representing our statement |
ohneta | 0:aae260bdcdd9 | 2729 | // there's definitely some opportunity for optimisation here |
ohneta | 0:aae260bdcdd9 | 2730 | LMATCH_VOID(LEX_R_WHILE); |
ohneta | 0:aae260bdcdd9 | 2731 | LMATCH_VOID('('); |
ohneta | 0:aae260bdcdd9 | 2732 | int whileCondStart = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 2733 | bool noexecute = false; |
ohneta | 0:aae260bdcdd9 | 2734 | CScriptVarLink *cond = base(execute); |
ohneta | 0:aae260bdcdd9 | 2735 | bool loopCond = execute && cond->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2736 | CLEAN(cond); |
ohneta | 0:aae260bdcdd9 | 2737 | CScriptLex *whileCond = l->getSubLex(whileCondStart); |
ohneta | 0:aae260bdcdd9 | 2738 | LMATCH_VOID(')'); |
ohneta | 0:aae260bdcdd9 | 2739 | int whileBodyStart = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 2740 | statement(loopCond ? execute : noexecute); |
ohneta | 0:aae260bdcdd9 | 2741 | CScriptLex *whileBody = l->getSubLex(whileBodyStart); |
ohneta | 0:aae260bdcdd9 | 2742 | CScriptLex *oldLex = l; |
ohneta | 0:aae260bdcdd9 | 2743 | int loopCount = TINYJS_LOOP_MAX_ITERATIONS; |
ohneta | 0:aae260bdcdd9 | 2744 | while (loopCond && loopCount-->0) { |
ohneta | 0:aae260bdcdd9 | 2745 | whileCond->reset(); |
ohneta | 0:aae260bdcdd9 | 2746 | l = whileCond; |
ohneta | 0:aae260bdcdd9 | 2747 | cond = base(execute); |
ohneta | 0:aae260bdcdd9 | 2748 | loopCond = execute && cond->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2749 | CLEAN(cond); |
ohneta | 0:aae260bdcdd9 | 2750 | if (loopCond) { |
ohneta | 0:aae260bdcdd9 | 2751 | whileBody->reset(); |
ohneta | 0:aae260bdcdd9 | 2752 | l = whileBody; |
ohneta | 0:aae260bdcdd9 | 2753 | statement(execute); |
ohneta | 0:aae260bdcdd9 | 2754 | } |
ohneta | 0:aae260bdcdd9 | 2755 | } |
ohneta | 0:aae260bdcdd9 | 2756 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 2757 | delete whileCond; |
ohneta | 0:aae260bdcdd9 | 2758 | delete whileBody; |
ohneta | 0:aae260bdcdd9 | 2759 | |
ohneta | 0:aae260bdcdd9 | 2760 | if (loopCount<=0) { |
ohneta | 0:aae260bdcdd9 | 2761 | root->trace(); |
ohneta | 0:aae260bdcdd9 | 2762 | TRACE("WHILE Loop exceeded %d iterations at %s\n", TINYJS_LOOP_MAX_ITERATIONS, l->getPosition().c_str()); |
ohneta | 0:aae260bdcdd9 | 2763 | mbedErrorFlag = 1; |
ohneta | 0:aae260bdcdd9 | 2764 | mbedErrorMessage = "LOOP_ERROR"; |
ohneta | 0:aae260bdcdd9 | 2765 | return; |
ohneta | 0:aae260bdcdd9 | 2766 | } |
ohneta | 0:aae260bdcdd9 | 2767 | } else if (l->tk==LEX_R_FOR) { |
ohneta | 0:aae260bdcdd9 | 2768 | LMATCH_VOID(LEX_R_FOR); |
ohneta | 0:aae260bdcdd9 | 2769 | LMATCH_VOID('('); |
ohneta | 0:aae260bdcdd9 | 2770 | statement(execute); // initialisation |
ohneta | 0:aae260bdcdd9 | 2771 | //LMATCH(';'); |
ohneta | 0:aae260bdcdd9 | 2772 | int forCondStart = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 2773 | bool noexecute = false; |
ohneta | 0:aae260bdcdd9 | 2774 | CScriptVarLink *cond = base(execute); // condition |
ohneta | 0:aae260bdcdd9 | 2775 | bool loopCond = execute && cond->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2776 | CLEAN(cond); |
ohneta | 0:aae260bdcdd9 | 2777 | CScriptLex *forCond = l->getSubLex(forCondStart); |
ohneta | 0:aae260bdcdd9 | 2778 | LMATCH_VOID(';'); |
ohneta | 0:aae260bdcdd9 | 2779 | int forIterStart = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 2780 | CLEAN(base(noexecute)); // iterator |
ohneta | 0:aae260bdcdd9 | 2781 | CScriptLex *forIter = l->getSubLex(forIterStart); |
ohneta | 0:aae260bdcdd9 | 2782 | LMATCH_VOID(')'); |
ohneta | 0:aae260bdcdd9 | 2783 | int forBodyStart = l->tokenStart; |
ohneta | 0:aae260bdcdd9 | 2784 | statement(loopCond ? execute : noexecute); |
ohneta | 0:aae260bdcdd9 | 2785 | CScriptLex *forBody = l->getSubLex(forBodyStart); |
ohneta | 0:aae260bdcdd9 | 2786 | CScriptLex *oldLex = l; |
ohneta | 0:aae260bdcdd9 | 2787 | if (loopCond) { |
ohneta | 0:aae260bdcdd9 | 2788 | forIter->reset(); |
ohneta | 0:aae260bdcdd9 | 2789 | l = forIter; |
ohneta | 0:aae260bdcdd9 | 2790 | CLEAN(base(execute)); |
ohneta | 0:aae260bdcdd9 | 2791 | } |
ohneta | 0:aae260bdcdd9 | 2792 | int loopCount = TINYJS_LOOP_MAX_ITERATIONS; |
ohneta | 0:aae260bdcdd9 | 2793 | while (execute && loopCond && loopCount-->0) { |
ohneta | 0:aae260bdcdd9 | 2794 | forCond->reset(); |
ohneta | 0:aae260bdcdd9 | 2795 | l = forCond; |
ohneta | 0:aae260bdcdd9 | 2796 | cond = base(execute); |
ohneta | 0:aae260bdcdd9 | 2797 | loopCond = cond->var->getBool(); |
ohneta | 0:aae260bdcdd9 | 2798 | CLEAN(cond); |
ohneta | 0:aae260bdcdd9 | 2799 | if (execute && loopCond) { |
ohneta | 0:aae260bdcdd9 | 2800 | forBody->reset(); |
ohneta | 0:aae260bdcdd9 | 2801 | l = forBody; |
ohneta | 0:aae260bdcdd9 | 2802 | statement(execute); |
ohneta | 0:aae260bdcdd9 | 2803 | } |
ohneta | 0:aae260bdcdd9 | 2804 | if (execute && loopCond) { |
ohneta | 0:aae260bdcdd9 | 2805 | forIter->reset(); |
ohneta | 0:aae260bdcdd9 | 2806 | l = forIter; |
ohneta | 0:aae260bdcdd9 | 2807 | CLEAN(base(execute)); |
ohneta | 0:aae260bdcdd9 | 2808 | } |
ohneta | 0:aae260bdcdd9 | 2809 | } |
ohneta | 0:aae260bdcdd9 | 2810 | l = oldLex; |
ohneta | 0:aae260bdcdd9 | 2811 | delete forCond; |
ohneta | 0:aae260bdcdd9 | 2812 | delete forIter; |
ohneta | 0:aae260bdcdd9 | 2813 | delete forBody; |
ohneta | 0:aae260bdcdd9 | 2814 | if (loopCount<=0) { |
ohneta | 0:aae260bdcdd9 | 2815 | root->trace(); |
ohneta | 0:aae260bdcdd9 | 2816 | TRACE("FOR Loop exceeded %d iterations at %s\n", TINYJS_LOOP_MAX_ITERATIONS, l->getPosition().c_str()); |
ohneta | 0:aae260bdcdd9 | 2817 | mbedErrorFlag = 1; |
ohneta | 0:aae260bdcdd9 | 2818 | mbedErrorMessage = "LOOP_ERROR"; |
ohneta | 0:aae260bdcdd9 | 2819 | return; |
ohneta | 0:aae260bdcdd9 | 2820 | } |
ohneta | 0:aae260bdcdd9 | 2821 | } else if (l->tk==LEX_R_RETURN) { |
ohneta | 0:aae260bdcdd9 | 2822 | LMATCH_VOID(LEX_R_RETURN); |
ohneta | 0:aae260bdcdd9 | 2823 | CScriptVarLink *result = 0; |
ohneta | 0:aae260bdcdd9 | 2824 | if (l->tk != ';') |
ohneta | 0:aae260bdcdd9 | 2825 | result = base(execute); |
ohneta | 0:aae260bdcdd9 | 2826 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2827 | CScriptVarLink *resultVar = scopes.back()->findChild(TINYJS_RETURN_VAR); |
ohneta | 0:aae260bdcdd9 | 2828 | if (resultVar) |
ohneta | 0:aae260bdcdd9 | 2829 | resultVar->replaceWith(result); |
ohneta | 0:aae260bdcdd9 | 2830 | else |
ohneta | 0:aae260bdcdd9 | 2831 | TRACE("RETURN statement, but not in a function.\n"); |
ohneta | 0:aae260bdcdd9 | 2832 | execute = false; |
ohneta | 0:aae260bdcdd9 | 2833 | } |
ohneta | 0:aae260bdcdd9 | 2834 | CLEAN(result); |
ohneta | 0:aae260bdcdd9 | 2835 | LMATCH_VOID(';'); |
ohneta | 0:aae260bdcdd9 | 2836 | } else if (l->tk==LEX_R_FUNCTION) { |
ohneta | 0:aae260bdcdd9 | 2837 | CScriptVarLink *funcVar = parseFunctionDefinition(); |
ohneta | 0:aae260bdcdd9 | 2838 | if (execute) { |
ohneta | 0:aae260bdcdd9 | 2839 | if (funcVar->name == TINYJS_TEMP_NAME) |
ohneta | 0:aae260bdcdd9 | 2840 | TRACE("Functions defined at statement-level are meant to have a name\n"); |
ohneta | 0:aae260bdcdd9 | 2841 | else |
ohneta | 0:aae260bdcdd9 | 2842 | scopes.back()->addChildNoDup(funcVar->name, funcVar->var); |
ohneta | 0:aae260bdcdd9 | 2843 | } |
ohneta | 0:aae260bdcdd9 | 2844 | CLEAN(funcVar); |
ohneta | 0:aae260bdcdd9 | 2845 | } else LMATCH_VOID(LEX_EOF); |
ohneta | 0:aae260bdcdd9 | 2846 | } |
ohneta | 0:aae260bdcdd9 | 2847 | #endif |
ohneta | 0:aae260bdcdd9 | 2848 | |
ohneta | 0:aae260bdcdd9 | 2849 | /// Get the given variable specified by a path (var1.var2.etc), or return 0 |
ohneta | 0:aae260bdcdd9 | 2850 | CScriptVar *CTinyJS::getScriptVariable(const string &path) { |
ohneta | 0:aae260bdcdd9 | 2851 | // traverse path |
ohneta | 0:aae260bdcdd9 | 2852 | size_t prevIdx = 0; |
ohneta | 0:aae260bdcdd9 | 2853 | size_t thisIdx = path.find('.'); |
ohneta | 0:aae260bdcdd9 | 2854 | if (thisIdx == string::npos) thisIdx = path.length(); |
ohneta | 0:aae260bdcdd9 | 2855 | CScriptVar *var = root; |
ohneta | 0:aae260bdcdd9 | 2856 | while (var && prevIdx<path.length()) { |
ohneta | 0:aae260bdcdd9 | 2857 | string el = path.substr(prevIdx, thisIdx-prevIdx); |
ohneta | 0:aae260bdcdd9 | 2858 | CScriptVarLink *varl = var->findChild(el); |
ohneta | 0:aae260bdcdd9 | 2859 | var = varl?varl->var:0; |
ohneta | 0:aae260bdcdd9 | 2860 | prevIdx = thisIdx+1; |
ohneta | 0:aae260bdcdd9 | 2861 | thisIdx = path.find('.', prevIdx); |
ohneta | 0:aae260bdcdd9 | 2862 | if (thisIdx == string::npos) thisIdx = path.length(); |
ohneta | 0:aae260bdcdd9 | 2863 | } |
ohneta | 0:aae260bdcdd9 | 2864 | return var; |
ohneta | 0:aae260bdcdd9 | 2865 | } |
ohneta | 0:aae260bdcdd9 | 2866 | |
ohneta | 0:aae260bdcdd9 | 2867 | /// Get the value of the given variable, or return 0 |
ohneta | 0:aae260bdcdd9 | 2868 | const string *CTinyJS::getVariable(const string &path) { |
ohneta | 0:aae260bdcdd9 | 2869 | CScriptVar *var = getScriptVariable(path); |
ohneta | 0:aae260bdcdd9 | 2870 | // return result |
ohneta | 0:aae260bdcdd9 | 2871 | if (var) |
ohneta | 0:aae260bdcdd9 | 2872 | return &var->getString(); |
ohneta | 0:aae260bdcdd9 | 2873 | else |
ohneta | 0:aae260bdcdd9 | 2874 | return 0; |
ohneta | 0:aae260bdcdd9 | 2875 | } |
ohneta | 0:aae260bdcdd9 | 2876 | |
ohneta | 0:aae260bdcdd9 | 2877 | /// set the value of the given variable, return trur if it exists and gets set |
ohneta | 0:aae260bdcdd9 | 2878 | bool CTinyJS::setVariable(const std::string &path, const std::string &varData) { |
ohneta | 0:aae260bdcdd9 | 2879 | CScriptVar *var = getScriptVariable(path); |
ohneta | 0:aae260bdcdd9 | 2880 | // return result |
ohneta | 0:aae260bdcdd9 | 2881 | if (var) { |
ohneta | 0:aae260bdcdd9 | 2882 | if (var->isInt()) |
ohneta | 0:aae260bdcdd9 | 2883 | var->setInt((int)strtol(varData.c_str(),0,0)); |
ohneta | 0:aae260bdcdd9 | 2884 | else if (var->isDouble()) |
ohneta | 0:aae260bdcdd9 | 2885 | var->setDouble(strtod(varData.c_str(),0)); |
ohneta | 0:aae260bdcdd9 | 2886 | else |
ohneta | 0:aae260bdcdd9 | 2887 | var->setString(varData.c_str()); |
ohneta | 0:aae260bdcdd9 | 2888 | return true; |
ohneta | 0:aae260bdcdd9 | 2889 | } |
ohneta | 0:aae260bdcdd9 | 2890 | else |
ohneta | 0:aae260bdcdd9 | 2891 | return false; |
ohneta | 0:aae260bdcdd9 | 2892 | } |
ohneta | 0:aae260bdcdd9 | 2893 | |
ohneta | 0:aae260bdcdd9 | 2894 | /// Finds a child, looking recursively up the scopes |
ohneta | 0:aae260bdcdd9 | 2895 | CScriptVarLink *CTinyJS::findInScopes(const std::string &childName) { |
ohneta | 0:aae260bdcdd9 | 2896 | for (int s=scopes.size()-1;s>=0;s--) { |
ohneta | 0:aae260bdcdd9 | 2897 | CScriptVarLink *v = scopes[s]->findChild(childName); |
ohneta | 0:aae260bdcdd9 | 2898 | if (v) return v; |
ohneta | 0:aae260bdcdd9 | 2899 | } |
ohneta | 0:aae260bdcdd9 | 2900 | return NULL; |
ohneta | 0:aae260bdcdd9 | 2901 | |
ohneta | 0:aae260bdcdd9 | 2902 | } |
ohneta | 0:aae260bdcdd9 | 2903 | |
ohneta | 0:aae260bdcdd9 | 2904 | /// Look up in any parent classes of the given object |
ohneta | 0:aae260bdcdd9 | 2905 | CScriptVarLink *CTinyJS::findInParentClasses(CScriptVar *object, const std::string &name) { |
ohneta | 0:aae260bdcdd9 | 2906 | // Look for links to actual parent classes |
ohneta | 0:aae260bdcdd9 | 2907 | CScriptVarLink *parentClass = object->findChild(TINYJS_PROTOTYPE_CLASS); |
ohneta | 0:aae260bdcdd9 | 2908 | while (parentClass) { |
ohneta | 0:aae260bdcdd9 | 2909 | CScriptVarLink *implementation = parentClass->var->findChild(name); |
ohneta | 0:aae260bdcdd9 | 2910 | if (implementation) return implementation; |
ohneta | 0:aae260bdcdd9 | 2911 | parentClass = parentClass->var->findChild(TINYJS_PROTOTYPE_CLASS); |
ohneta | 0:aae260bdcdd9 | 2912 | } |
ohneta | 0:aae260bdcdd9 | 2913 | // else fake it for strings and finally objects |
ohneta | 0:aae260bdcdd9 | 2914 | if (object->isString()) { |
ohneta | 0:aae260bdcdd9 | 2915 | CScriptVarLink *implementation = stringClass->findChild(name); |
ohneta | 0:aae260bdcdd9 | 2916 | if (implementation) return implementation; |
ohneta | 0:aae260bdcdd9 | 2917 | } |
ohneta | 0:aae260bdcdd9 | 2918 | if (object->isArray()) { |
ohneta | 0:aae260bdcdd9 | 2919 | CScriptVarLink *implementation = arrayClass->findChild(name); |
ohneta | 0:aae260bdcdd9 | 2920 | if (implementation) return implementation; |
ohneta | 0:aae260bdcdd9 | 2921 | } |
ohneta | 0:aae260bdcdd9 | 2922 | CScriptVarLink *implementation = objectClass->findChild(name); |
ohneta | 0:aae260bdcdd9 | 2923 | if (implementation) return implementation; |
ohneta | 0:aae260bdcdd9 | 2924 | |
ohneta | 0:aae260bdcdd9 | 2925 | return 0; |
ohneta | 0:aae260bdcdd9 | 2926 | } |
ohneta | 0:aae260bdcdd9 | 2927 |