opal 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/runtime/opal.js ADDED
@@ -0,0 +1,200 @@
1
+ /*
2
+ * opal.js
3
+ * opal
4
+ *
5
+ * Created by Adam Beynon.
6
+ * Copyright 2010 Adam Beynon.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+
28
+ // temp..
29
+ var nil;
30
+
31
+ /**
32
+ nodes etc
33
+ */
34
+
35
+ var NOEX_PUBLIC = 0,
36
+ NOEX_NOSUPER = 1,
37
+ NOEX_PRIVATE = 2,
38
+ NOEX_PROTECTED = 4,
39
+ NOEX_MASK = 6,
40
+ NOEX_BASIC = 8;
41
+
42
+
43
+ function require() {
44
+
45
+ };
46
+
47
+ // Boolean test. false if null, undefined, nil, or false
48
+ function RTEST(val) {
49
+ return (val != null && val != undefined && val != nil && val != false) ? true : false;
50
+ };
51
+
52
+ /**
53
+ Performs an 'or op' with lhs and rhs
54
+ */
55
+ function ORTEST(lhs, rhs) {
56
+ if (lhs == null || lhs == undefined) lhs = nil;
57
+ if (rhs == null || rhs == undefined) rhs = nil;
58
+
59
+ if (lhs == nil || lhs == false) {
60
+ return rhs;
61
+ }
62
+ return lhs;
63
+ };
64
+
65
+ /**
66
+ Performs an 'and op' with lhs and rhs
67
+ */
68
+ function ANDTEST(lhs, rhs) {
69
+ if (lhs == null || lhs == undefined) lhs = nil;
70
+ if (rhs == null || rhs == undefined) rhs = nil;
71
+
72
+ if (lhs == nil || lhs == false) {
73
+ return nil;
74
+ }
75
+ return rhs;
76
+ };
77
+
78
+ function NOTTEST(expr) {
79
+ if (expr == null || expr == undefined || expr == nil || expr == false) return true;
80
+ return false;
81
+ };
82
+
83
+ /**
84
+ Fix for browsers not having console
85
+ */
86
+ // if (typeof console === 'undefined') {
87
+ // var console = console || window.console || { };
88
+ // console.log = console.info = console.warn = console.error = function() { };
89
+ // }
90
+
91
+ function RObject(klass, type) {
92
+ this.klass = klass;
93
+ this.flags = type;
94
+ this.iv_tbl = { };
95
+ return this;
96
+ }
97
+
98
+ function RClass(klass, super_klass) {
99
+ this.klass = klass ;
100
+ this.sup = super_klass ;
101
+ this.flags = T_CLASS ;
102
+ this.m_tbl = { };
103
+ this.iv_tbl = { };
104
+ return this;
105
+ };
106
+
107
+ function RHash() {
108
+ this.klass = nil;
109
+ this.flags = nil;
110
+ this.ifnone = nil;
111
+ // ordered keys
112
+ this.keys = [];
113
+ // keys.to_s => values
114
+ this.dict = { };
115
+ return this;
116
+ }
117
+
118
+ // Types
119
+ var T_CLASS = 1,
120
+ T_MODULE = 2,
121
+ T_OBJECT = 4,
122
+ T_BOOLEAN = 8,
123
+ T_STRING = 16,
124
+ T_ARRAY = 32,
125
+ T_NUMBER = 64,
126
+ T_PROC = 128,
127
+ T_SYMBOL = 256,
128
+ T_HASH = 512,
129
+ T_ICLASS = 1024;
130
+
131
+ // Flags
132
+ var FL_SINGLETON = 2056;
133
+
134
+ function FL_TEST(x, f) {
135
+ return x.flags & f;
136
+ }
137
+
138
+ function FL_SET(x, f) {
139
+ x.flags |= f;
140
+ }
141
+
142
+ function FL_UNSET(x, f) {
143
+ x.flags &= (~f);
144
+ }
145
+
146
+ rb_class_tbl = { } ; // all classes are stored here
147
+ rb_global_tbl = { } ; // globals are stored here
148
+
149
+ function rb_gvar_get(id) {
150
+
151
+ };
152
+
153
+ function rb_gvar_set(id, val) {
154
+
155
+ };
156
+
157
+
158
+ function boot_defclass(id, super_class) {
159
+ var o = rb_class_boot(super_class);
160
+ rb_name_class(o, id);
161
+ rb_class_tbl[id] = o;
162
+ rb_const_set((rb_cObject ? rb_cObject : o), id, o);
163
+ return o;
164
+ };
165
+
166
+ boot_defmetametaclass = function(klass, metametaclass) {
167
+ klass.klass.klass = metametaclass;
168
+ };
169
+
170
+ obj_alloc = function(klass) {
171
+ // console.log('in base.js, obj_alloc ' + arguments.length);
172
+ // var obj = klass.$('allocate', []);
173
+ var obj = VN$(klass, 'allocate');
174
+ return obj;
175
+ };
176
+
177
+ class_allocate_instance = function() {
178
+ // console.log('doing VN.class_allocate_instance');
179
+ var obj = new RObject(this, T_OBJECT) ;
180
+ return obj;
181
+ };
182
+
183
+ obj_dummy = function() {
184
+ return nil ;
185
+ };
186
+
187
+ equal = function(obj) {
188
+ if (obj == this) return true ;
189
+ var result = this.$funcall('==', [obj]);
190
+ if (result) return true ;
191
+ return false ;
192
+ };
193
+
194
+ eql = function(obj) {
195
+ return this.$funcall('==', [obj]);
196
+ };
197
+
198
+ obj_equal = function(obj) {
199
+ return (obj == this) ? true : false ;
200
+ };
data/runtime/parse.js ADDED
@@ -0,0 +1,2218 @@
1
+ /*
2
+ * parse.js
3
+ * opal
4
+ *
5
+ * Created by Adam Beynon.
6
+ * Copyright 2010 Adam Beynon.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+
27
+
28
+ // lex states
29
+ var EXPR_BEG = 0, EXPR_END = 1, EXPR_ENDARG = 2, EXPR_ARG = 3,
30
+ EXPR_CMDARG = 4, EXPR_MID = 5, EXPR_FNAME = 6, EXPR_DOT = 7,
31
+ EXPR_CLASS = 8, EXPR_VALUE = 9;
32
+
33
+ // keywords
34
+ var kCLASS = 0, kMODULE = 1, kDEF = 2, kUNDEF = 3,
35
+ kBEGIN = 4, kRESCUE = 5, kENSURE = 6, kEND = 7,
36
+ kIF = 8, kUNLESS = 9, kTHEN = 10, kELSIF = 11,
37
+ kELSE = 12, kCASE = 13, kWHEN = 14, kWHILE = 15,
38
+ kUNTIL = 16, kFOR = 17, kBREAK = 18, kNEXT = 19,
39
+ kREDO = 20, kELSIF = 21, kELSE = 22, kCASE = 23,
40
+ kWHEN = 24, kWHILE = 25, kUNTIL = 26, kFOR = 27,
41
+ kBREAK = 28, kNEXT = 29, kREDO = 30, kRETRY = 31,
42
+ kIN = 32, kDO_COND = 33, kDO_BLOCK = 34, kDO_LAMBDA = 35,
43
+ kRETURN = 36, kYIELD = 37, kSUPER = 38, kSELF = 39,
44
+ kNIL = 40, kTRUE = 41, kFALSE = 42, kAND = 43,
45
+ kOR = 44, kNOT = 45, kIF_MOD = 46, kUNLESS_MOD= 47,
46
+ kWHILE_MOD = 48, kUNTIL_MOD = 49, kRESCUE_MOD = 50, kALIAS = 51,
47
+ kDEFINED = 52, klBEGIN = 53, klEND = 54, k__LINE__ = 55,
48
+ k__FILE__ = 56, kDO = 57, kDEFined = 58,
49
+ // tokens
50
+ tIDENTIFIER = 59, tFID = 60, tGVAR = 61, tIVAR = 62,
51
+ tCONSTANT = 63, tCVAR = 64, tLABEL = 65, tINTEGER = 66,
52
+ tFLOAT = 67, tSTR_CONTENT= 68, tCHAR = 69, tNTH_REF = 70,
53
+ tBACK_REF = 71, tREGEXP_END = 72, tUPLUS = 73, tUMINUS = 74,
54
+ tPOW = 75, tCMP = 76, tEQ = 77, tEQQ = 78,
55
+ tNEQ = 79, tGEQ = 80, tLEQ = 81, tANDOP = 82,
56
+ tOROP = 83, tMATCH = 84, tNMATCH = 85, tDOT2 = 86,
57
+ tDOT3 = 87, tAREF = 88, tASET = 89, tLSHFT = 90,
58
+ tRSHFT = 91, tCOLON2 = 92, tCOLON3 = 93, tOP_ASGN = 94,
59
+ tASSOC = 95, tLPAREN = 96, tLPAREN_ARG = 97, tRPAREN = 98,
60
+ tLBRACK = 99, tLBRACE = 100, tLBRACE_ARG = 101, tSTAR = 102,
61
+ tAMPER = 103, tLAMBDA = 104, tSYMBEG = 105, tSTRING_BEG= 106,
62
+ tXSTRING_BEG= 107, tREGEXP_BEG = 108, tWORDS_BEG = 109, tQWORDS_BEG= 110,
63
+ tSTRING_DBEG= 111, tSTRING_DVAR= 112, tSTRING_END = 113, tLAMBEG = 114,
64
+ tUMINUS_NUM = 115, tSTRING = 116, tXSTRING_END= 117,
65
+
66
+ tPLUS = 118, tMINUS = 119, tNL = 120, tSEMI = 121;
67
+
68
+ // special tokens (used for generator)
69
+ var tCALL = 150, tMLHS = 151, tOPT_PLUS = 152, tOPT_MINUS = 153,
70
+ tOPT_MULT = 154, tOPT_DIV = 155;
71
+
72
+ /**
73
+ Parse the given ruby code, str, with the given filename. This allows us to
74
+ dynamically set the filename, for example, with eval()'d code. This returns
75
+ an Instruction sequence, with all of its sub sequences, opcodes etc.
76
+ */
77
+ var vn_parser = function(filename, str) {
78
+
79
+ // current lex state
80
+ var lex_state = EXPR_BEG;
81
+ // last lexerparser state
82
+ var last_state;
83
+ // the scanner
84
+ var scanner; //= new vn_ruby_string_scanner(str);
85
+ // current token
86
+ var token = { type: false, value: false };
87
+ // last token
88
+ var last_token = { type: false, value: false };
89
+ //
90
+ var sym_tbl = { };
91
+ // eval string..
92
+ var eval_arr = [];
93
+ // valid types of stmt that are valid as the first cmd args (helps us identify if the
94
+ // next statemebnt should be appeneded to the current identifer as a cmd arg )
95
+ var valid_cmd_args = [tIDENTIFIER, tINTEGER, tCONSTANT, tSTRING_BEG, kDO, '{', tSYMBEG];
96
+ // start of command (not stmt), when on new line etc
97
+ var cmd_start = false;
98
+
99
+ // all contexts
100
+ var contexts = [];
101
+
102
+ // function push_context(c) {
103
+ // contexts.push(c);
104
+ // }
105
+
106
+
107
+ /**
108
+ String parsing
109
+ */
110
+ var string_parse_stack = [];
111
+
112
+ var push_string_parse = function(o) {
113
+ string_parse_stack.push(o);
114
+ };
115
+
116
+ var pop_string_parse = function() {
117
+ string_parse_stack.pop();
118
+ };
119
+
120
+ var current_string_parse = function() {
121
+ if (string_parse_stack.length == 0) {
122
+ return null;
123
+ }
124
+ return string_parse_stack[string_parse_stack.length - 1];
125
+ };
126
+
127
+
128
+ // create object dup
129
+ var object_create = function(obj) {
130
+ var targ = { };
131
+ for (var prop in obj) {
132
+ targ[prop] = obj[prop];
133
+ }
134
+
135
+ return targ;
136
+ };
137
+
138
+ var original_symbol = {
139
+ nud: function () {
140
+ return this;
141
+ },
142
+ led: function (left) {
143
+ throw 'led unimplemented';
144
+ }
145
+ };
146
+
147
+ var symbol = function(id, binding_power) {
148
+ var sym = sym_tbl[id];
149
+ binding_power = binding_power || 0;
150
+ if (sym) {
151
+ if (binding_power >= sym.lbp) {
152
+ sym.lbp = binding_power;
153
+ }
154
+ }
155
+ else {
156
+ sym = object_create(original_symbol);
157
+ sym.type = sym.value = id;
158
+ sym.lbp = binding_power;
159
+ sym_tbl[id] = sym;
160
+ }
161
+ return sym;
162
+ };
163
+
164
+ var sym_stmt = function (id, bp, block) {
165
+ if (!block) {
166
+ block = bp;
167
+ bp = 0;
168
+ }
169
+
170
+ var sym = symbol(id);
171
+ sym.std = block;
172
+ return sym;
173
+ };
174
+
175
+ var infixr = function (id, bp, led) {
176
+ var s = symbol(id, bp);
177
+ s.led = led || function (left) {
178
+ this.first = left;
179
+ this.second = expr(bp - 1);
180
+ this.arity = "binary";
181
+ return this;
182
+ };
183
+ return s;
184
+ };
185
+
186
+ // make a function for us that has a 'usual beahiour' (saves making a function
187
+ // over and over) - +/-/*// all do the same thing etc
188
+ var infix = function (id, bp, led) {
189
+ var s = symbol(id, bp);
190
+ s.led = led || function (left) {
191
+ this.$lhs = left;
192
+ this.$rhs = expr(bp);
193
+ this.type = id;
194
+ return this;
195
+ };
196
+ return s;
197
+ };
198
+
199
+ var prefix = function (id, nud) {
200
+ var s = symbol(id);
201
+ s.nud = nud || function () {
202
+ scope.reserve(this);
203
+ this.first = expression(70);
204
+ this.arity = "unary";
205
+ return this;
206
+ };
207
+ return s;
208
+ };
209
+
210
+ var assignment = function (id) {
211
+ return infixr(id, 10, function (left) {
212
+ if (left.type !== "." && left.type !== "[" && left.type !== tIDENTIFIER && left.type != tIVAR && left.type !== tMLHS && left.type !== tCONSTANT) {
213
+ throw 'bad lhs'
214
+ }
215
+ this.$lhs = left;
216
+ this.$rhs = stmt();
217
+ this.assignment = true;
218
+ // this.type = "assignment";
219
+ return this;
220
+ });
221
+ };
222
+
223
+ assignment("=");
224
+
225
+ symbol(kDO).nud = function() {
226
+ if (token.type == '|') {
227
+ var e;
228
+ this.$args = [];
229
+ // gather block params
230
+ next_token();
231
+ e = expr();
232
+ this.$args.push(e);
233
+ while (true) {
234
+ if (token.type == "|") {
235
+ next_token();
236
+ break;
237
+ }
238
+ else if (token.type == ",") {
239
+ next_token();
240
+ continue;
241
+ }
242
+ else {
243
+ this.$args.push(expr());
244
+ }
245
+ // throw "erm.."
246
+ }
247
+ }
248
+ // throw token.value
249
+ // next_token();
250
+ // throw token.type
251
+ this.$stmts = stmts([kEND]);
252
+ // read over kEND
253
+ next_token();
254
+ return this;
255
+ };
256
+
257
+ // alt block
258
+ symbol('{').nud = function() {
259
+ // read over {
260
+ this.$stmt = stmt();
261
+ // read over }
262
+ next_token('}');
263
+ return this;
264
+ };
265
+
266
+ // self... simple, just return
267
+ symbol(kSELF).nud = function() {
268
+ return this;
269
+ };
270
+
271
+ symbol(kRETURN).nud = function() {
272
+ return this;
273
+ };
274
+
275
+ symbol(kNIL).nud = function() {
276
+ return this;
277
+ };
278
+
279
+ symbol(kSUPER).nud = function() {
280
+ return this;
281
+ };
282
+
283
+ symbol(kTRUE).nud = function() {
284
+ return this;
285
+ };
286
+
287
+ symbol(kFALSE).nud = function() {
288
+ return this;
289
+ };
290
+
291
+ symbol(tSTRING_BEG).nud = function() {
292
+ // console.log('in hre..');
293
+ // these will be string_contents mixed with actual ruby parse trees
294
+ this.$parts = [];
295
+ // next_token();
296
+ // throw token.value
297
+ while (true) {
298
+ if (token.type === false) {
299
+ throw 'Parsing string error: not expecting EOF before end of string'
300
+ }
301
+ else {
302
+ // console.log(token.value);
303
+ if (token.type === tSTRING_END) {
304
+ next_token();
305
+ break;
306
+ }
307
+ else {
308
+ if (token.type === tSTR_CONTENT) {
309
+ this.$parts.push(token)
310
+ next_token();
311
+ }
312
+ else if (token.type === tSTRING_DBEG) {
313
+ var d = token;
314
+ // skip over dbeg
315
+ next_token();
316
+ d.$value = stmt();
317
+ this.$parts.push(d);
318
+ // skip over '}'
319
+ next_token();
320
+ }
321
+ // console.log('found a part');
322
+ // this.$parts.push(token);
323
+ // next_token();
324
+ }
325
+
326
+ }
327
+ }
328
+ return this;
329
+ };
330
+
331
+ // when we get identifier identifier (treat first like receiver, second like arg1)
332
+ symbol(tIDENTIFIER).nud = function() {
333
+ // we need to check last_state, as lex_state (current) is overridden when parsing current token
334
+ if ((valid_cmd_args.indexOf(token.type) != -1) && (last_state == EXPR_CMDARG)) {
335
+ // console.log("about to gather command args..");
336
+ gather_command_args(this);
337
+ this.type = tCALL;
338
+ this.$recv = null;
339
+ this.$meth = this.value;
340
+ // this.$meth = this;
341
+ }
342
+ return this;
343
+ };
344
+
345
+ symbol(tCONSTANT).nud = function() {
346
+ return this;
347
+ };
348
+
349
+ // the 'command' to apply the argumens to
350
+ // FIXME: rewrite to asume first arg is not neceserialy a arg, it could be start
351
+ // of assocs, or might be start of kDO
352
+ var gather_command_args = function(cmd) {
353
+ cmd.$call_args = {
354
+ args: []
355
+ };
356
+ // console.log('tIDENTIFIER "' + token.value + '" lex state: ' + lex_state + ' last state: ' + last_state + ' ,last token: ' + last_token.value);
357
+ if ((token.type !== kDO) && (token.type !== '{')) {
358
+ // dont add if next statement is kDO...
359
+ // console.log("getting exopr..");
360
+ cmd.$call_args.args.push(expr());
361
+ }
362
+
363
+ // collect remaining params
364
+ if (token.type === ',') {
365
+ // read over initial commar
366
+ next_token();
367
+ while (true) {
368
+ s = expr();
369
+ // s = expr(80);
370
+ // this.$args.push(stmt());
371
+ // check if tok is tASSOC.. if so, , then we
372
+ // are beginning a hash list, so dont add stmt to $args, but push it to
373
+ // the hash arg list instead
374
+ // console.log(token.type);
375
+ if (token.type === tASSOC) {
376
+ // console.log('found tassoc');
377
+ // should we check if we already have assoc list? having it more than once per cmd call
378
+ // might be an error
379
+ var a_keys = [], a_values = [];
380
+ cmd.$assocs = { '$keys': a_keys, '$values': a_values };
381
+ a_keys.push(s);
382
+ // read over tassoc
383
+ next_token();
384
+ a_values.push(expr());
385
+
386
+ while (true) {
387
+ if (token.type !== ',') {
388
+ // end of assoc list
389
+ break;
390
+ }
391
+ // read over commar
392
+ next_token(',');
393
+ a_keys.push(expr());
394
+ next_token(tASSOC);
395
+ a_values.push(expr());
396
+ }
397
+
398
+ // console.log(this);
399
+ // throw 'hash begin!'
400
+ }
401
+ else {
402
+ cmd.$call_args.args.push(s);
403
+ }
404
+ // CHECK HERE for do_block
405
+ // move this outside of loop? once we have do_block, command is over
406
+
407
+
408
+ if (token.type !== ',') {
409
+ break;
410
+ }
411
+ // any other case, add it as an arg
412
+
413
+ // console.log(token.type);
414
+ next_token(',');
415
+ // check for 'wrong' token types... a def, class, module etc are NOT valid tokens
416
+ if ([kDEF, kCLASS, kMODULE, kIF].indexOf(token.type) !== -1) {
417
+ throw 'Command Args: Not expecting token "' + token.type + '". Perhaps a trailing commar?'
418
+ }
419
+ }
420
+ }
421
+ if (token.type === kDO) {
422
+ // gather do block
423
+ cmd.$brace_block = stmt();
424
+ }
425
+ else if (token.type === '{') {
426
+ // gather rlcurly block
427
+ cmd.$brace_block = stmt();
428
+ }
429
+ };
430
+
431
+ // kDO opt_block_param compstmt kEND
432
+ var gather_do_block = function() {
433
+ var result = token;
434
+ // read over kDO
435
+ next_token();
436
+ // throw token.value
437
+ result.$stmts = stmts([kEND]);
438
+ // read over kEND
439
+ next_token();
440
+ return result;
441
+ }
442
+
443
+ symbol(tINTEGER).nud = function() {
444
+ return this;
445
+ };
446
+
447
+ symbol(tSYMBEG).nud = function() {
448
+ this.$name = stmt();
449
+ return this;
450
+ };
451
+
452
+ symbol(tIVAR).nud = function() {
453
+ return this;
454
+ };
455
+
456
+ symbol(tCVAR).nud = function() {
457
+ return this;
458
+ };
459
+
460
+ symbol(tGVAR).nud = function() {
461
+ return this;
462
+ };
463
+
464
+ // Catching block definitions in Def statements.
465
+ symbol("&").nud = function() {
466
+ this.$name = stmt();
467
+ return this;
468
+ }
469
+
470
+
471
+ infix(",", 80, function(left) {
472
+ this.type = tMLHS;
473
+ // check if already part of a mLHS chain
474
+ if (left.type == tMLHS) {
475
+ // add to current chain
476
+ throw "in here.." + token.value
477
+ }
478
+ else {
479
+ // start new chain
480
+ this.$parts = [];
481
+ this.$parts.push(left);
482
+ this.$parts.push(expr(10));
483
+ // dont get next_token. expr() gets it for us.
484
+ // next_token();
485
+ // this.$parts.push(next_token());
486
+ }
487
+ // throw token.value
488
+ // throw "in here.." + token.value
489
+
490
+
491
+ return this;
492
+ });
493
+
494
+
495
+ /**
496
+ Fixme!! this is going to break!!
497
+
498
+ Argh! not sure how we are going to do mlghs, mrhs
499
+ */
500
+ // infix(',', 80, function(left) {
501
+ // this.$lhs = left;
502
+ // if (token.type === tSYMBEG) {
503
+ // // throw 'we need to parse an assoc.'
504
+ // next_token();
505
+ // next_token();
506
+ // next_token();
507
+ // next_token();
508
+ // }
509
+ // else {
510
+ // this.$rhs = stmt();
511
+ // }
512
+ //
513
+ // return this;
514
+ // });
515
+
516
+ // Dot notation
517
+ infix(".", 80, function (left) {
518
+ // console.log('doing dot!')
519
+ this.$recv = left;
520
+ this.$meth = token;
521
+ this.type = tCALL;
522
+ // skip over dot
523
+ next_token();
524
+ if ((valid_cmd_args.indexOf(token.type) != -1) && (last_state === EXPR_CMDARG)) {
525
+ gather_command_args(this);
526
+ }
527
+ // else {
528
+ // if not, check if we just have a block...... no args, just block..
529
+ // e.g. my_array.each do ...
530
+ // could we just add kDO to the valid_cmd_args array...?
531
+ // throw token.value
532
+ // }
533
+
534
+ return this;
535
+ });
536
+
537
+ // m - method name
538
+ // b - binding power
539
+ // t is optinal type (instead of tCALL)
540
+ // used for a + a, a - a, a << a etc. (as m)
541
+ function meth_call(m, b, t) {
542
+ return infix(m, b, function(left) {
543
+ this.type = t || tCALL;
544
+ this.$recv = left;
545
+ this.$meth = this;
546
+ this.$call_args = {
547
+ args: [stmt()]
548
+ }
549
+ return this;
550
+ });
551
+ }
552
+
553
+ meth_call(tPLUS, 80, tOPT_PLUS);
554
+ meth_call(tMINUS, 80, tOPT_MINUS);
555
+ meth_call("*", 80, tOPT_MULT);
556
+ meth_call("/", 80, tOPT_DIV);
557
+
558
+
559
+ // method calls (with paranthesis)
560
+ infix("(", 80, function (left) {
561
+ var args = {
562
+ args: []
563
+ };
564
+ // valid left values
565
+ if (left.type === '.') {
566
+ // already a method call, so just set $args property
567
+ left.$call_args = args;
568
+ }
569
+ else if (left.type === tIDENTIFIER || left.type === tCONSTANT || left.type === tCALL) {
570
+ // identifier/constant - turn them into a method call, with args
571
+ // as the args (and no receiver!)
572
+ // will identifier already be a method call? unless an actual identifier
573
+ left.$call_args = args;
574
+ }
575
+ else {
576
+ throw left.value + ' is not a valid receiver'
577
+ }
578
+
579
+ if (token.type !== ')') {
580
+ while (true) {
581
+ // console.log("gaething..");
582
+ args.args.push(expr());
583
+ if (token.type !== ',') {
584
+ break;
585
+ }
586
+ next_token(',');
587
+ }
588
+ }
589
+ next_token(')');
590
+
591
+ if (token.type === kDO) {
592
+ // gather do block
593
+ left.$block = stmt();
594
+ }
595
+ else if (token.type === '{') {
596
+ // gather rlcurly block
597
+ left.$block = stmt();
598
+ }
599
+
600
+ return left;
601
+ });
602
+
603
+ // array declarations (explicit)
604
+ prefix(tLBRACK, function() {
605
+ var arr = [];
606
+ // throw token.value
607
+ if (token.type !== ']') {
608
+ while (true) {
609
+ arr.push(expr());
610
+ if (token.type !== ',') {
611
+ break;
612
+ }
613
+ next_token(',');
614
+ }
615
+ }
616
+ next_token(']');
617
+ this.$values = arr;
618
+ return this;
619
+ });
620
+
621
+ // hash literal
622
+ prefix(tLBRACE, function () {
623
+ this.$keys = [];
624
+ this.$values = [];
625
+ if (token.type !== '}') {
626
+ while (true) {
627
+ var t = token;
628
+ // check for valid key?
629
+ next_token();
630
+ // should this be a => ?? probbaly...
631
+ next_token();
632
+ this.$keys.push(t);
633
+ this.$values.push(stmt());
634
+ if (token.type !== ',') {
635
+ break;
636
+ }
637
+ next_token(',');
638
+ }
639
+ }
640
+ next_token('}');
641
+ return this;
642
+ });
643
+
644
+ prefix(kCASE, function() {
645
+ this.$expr = stmt();
646
+ this.$body = [];
647
+
648
+ if (token.type == tNL || token.type == tSEMI) next_token();
649
+
650
+ while (true) {
651
+ if (token.type == kEND) {
652
+ next_token();
653
+ break;
654
+ }
655
+ else if (token.type == kWHEN) {
656
+ var s, t = token;
657
+ t.$args = [];
658
+ next_token();
659
+ if ([tNL, tSEMI, ","].indexOf(token.type) != -1)
660
+ throw "kCASE: not expecting given token type"
661
+ while (true) {
662
+ s = stmt();
663
+ t.$args.push(s);
664
+ if (token.type == ",") next_token();
665
+ else break;
666
+ }
667
+ t.$stmts = stmts([kEND, kELSE, kWHEN]);
668
+ }
669
+ else if (token.type == kELSE) {
670
+ var t = token;
671
+ next_token();
672
+ // throw "jere"
673
+ t.$stmts = stmts([kEND]);
674
+ // throw "erm"
675
+ }
676
+ }
677
+ return this;
678
+ });
679
+
680
+ // if statment - expression, not really a statement.
681
+ prefix(kIF, function() {
682
+ this.$expr = stmt();
683
+ this.$tail = [];
684
+
685
+ if (token.type == tNL || token.type == tSEMI) {
686
+ next_token();
687
+ if (token.type == kTHEN) next_token();
688
+ }
689
+ else if (token.type == kTHEN) {
690
+ next_token();
691
+ }
692
+ else {
693
+ throw "kIF: expecting either term or kTHEN"
694
+ }
695
+
696
+ this.$stmts = stmts([kEND, kELSE, kELSIF]);
697
+
698
+ while (true) {
699
+ if (token.type == kEND) {
700
+ next_token();
701
+ break;
702
+ }
703
+ else if (token.type == kELSIF) {
704
+ var t = token;
705
+ next_token();
706
+ t.$expr = stmt();
707
+
708
+ if (token.type == tNL || token.type == tSEMI) {
709
+ next_token();
710
+ if (token.type == kTHEN) next_token();
711
+ }
712
+ else if (token.type == kTHEN) {
713
+ next_token();
714
+ }
715
+ else {
716
+ throw "kIF: expecting either term or kTHEN"
717
+ }
718
+
719
+ t.$stmts = stmts([kEND, kELSIF, kELSE]);
720
+ this.$tail.push(t);
721
+ }
722
+ else if (token.type == kELSE) {
723
+ var t = token;
724
+ next_token();
725
+ t.$stmts = stmts([kEND]);
726
+ this.$tail.push(t);
727
+ }
728
+ else {
729
+ throw "kIF: unexpected token: " + token.type + ", " + token.value
730
+ }
731
+ }
732
+
733
+ return this;
734
+ });
735
+
736
+ // method definitions
737
+ sym_stmt(kDEF, function () {
738
+
739
+ if (token.type === tIDENTIFIER || token.type === tCONSTANT || token.type === kSELF) {
740
+ this.$fname = token;
741
+ }
742
+ else {
743
+ throw 'Method Defintion: expected identifier or constant as def name.'
744
+ }
745
+ // reads over the fname
746
+ next_token();
747
+
748
+ // check if singleton definition
749
+ if (token.type === '.' || token.type === tCOLON2) {
750
+ // we have a singleton, so put old $fname as singleton name
751
+ this.$sname = this.$fname;
752
+ // stype is either '.' or tCOLON2 - might help code generation
753
+ this.$stype = token.type;
754
+ // now get real fname
755
+ next_token();
756
+ this.$fname = token;
757
+ // read over fname
758
+ next_token();
759
+ }
760
+ else {
761
+ // check we havent shot ourself in the foot
762
+ if (this.$fname.type === kSELF) {
763
+ throw "Cannot use keyword 'self' as method name"
764
+ }
765
+ }
766
+
767
+ // ignore arglist for the moment.
768
+ if (token.type === tNL || token.type === tSEMI) {
769
+ // we can ignore... nothing to do
770
+ }
771
+ else {
772
+
773
+ this.$arglist = {
774
+ arg: [],
775
+ rest_arg: [],
776
+ opt_arg: [],
777
+ opt_block_arg: null
778
+ };
779
+
780
+ if (token.type === '(') {
781
+ // params with paranthesis
782
+ this.$paran = true;
783
+ next_token();
784
+ }
785
+ while (true) {
786
+ if (token.type === ')') {
787
+ // end of params..check if we actually had start paran?
788
+ next_token();
789
+ break;
790
+ }
791
+ else {
792
+ // for now assume every stmt will be a regular arg. need to check actual types
793
+ // later
794
+ var s = stmt();
795
+ this.$arglist.arg.push(s);
796
+ if (token.type == ',') {
797
+ // read over commar
798
+ next_token();
799
+ }
800
+ else {
801
+
802
+ if (token.type === ')') continue;
803
+ else if (token.type == tNL || token.type == tSEMI) break;
804
+ else throw "Error: def, unsupported param type " + token.type
805
+ }
806
+ }
807
+ }
808
+ }
809
+
810
+ // read stmts.
811
+ this.$stmts = stmts([kEND]);
812
+ // read over kEND
813
+ next_token();
814
+ return this;
815
+ });
816
+
817
+ sym_stmt(kCLASS, function() {
818
+
819
+ if (token.type === tIDENTIFIER) {
820
+ throw 'Class defintion: cannot use tIDENTIFIER as a class name. Expected tCONSTANT'
821
+ }
822
+ else if(token.type === tCONSTANT) {
823
+ this.$kname = token;
824
+ }
825
+ else {
826
+ throw 'Class definition: expected constant as class name'
827
+ }
828
+ // read over kname
829
+ next_token();
830
+
831
+ if (token.type == '<') {
832
+ next_token();
833
+ // for now, only constant is valid superclass. we should allow other things..except new line.
834
+ if (token.type == tCONSTANT) {
835
+ this.$super = stmt();
836
+ next_token();
837
+ }
838
+ else {
839
+ throw "Class error: supername?"
840
+ }
841
+ }
842
+
843
+ this.$stmts = stmts([kEND]);
844
+ // read over kEND
845
+ next_token();
846
+ return this;
847
+ });
848
+
849
+ sym_stmt(kMODULE, function() {
850
+ if (token.type === tIDENTIFIER) {
851
+ throw "Module definition: cannot use tIDENTIFIER as a module name. Expected tCONSTANT"
852
+ }
853
+ else if (token.type === tCONSTANT) {
854
+ this.$kname = token;
855
+ }
856
+ else {
857
+ throw "Module definition: Expected tCONSTANT for module name"
858
+ }
859
+
860
+ // name
861
+ next_token();
862
+
863
+ this.$stmts = stmts([kEND]);
864
+ // kend
865
+ next_token();
866
+ return this;
867
+ });
868
+
869
+
870
+
871
+ var stmts = function(t) {
872
+ var s;
873
+ var r = [];
874
+ t = t || [];
875
+ while (true) {
876
+ if (token.type === false) {
877
+ if (t.indexOf(false) === -1) {
878
+ break;
879
+ }
880
+ else {
881
+ throw 'stmts: got to EOF before reaching end of statements'
882
+ }
883
+ }
884
+ else if (t.indexOf(token.type) != -1) {
885
+ break;
886
+ }
887
+ else {
888
+ if (token.type === tNL || token.type === tSEMI) {
889
+ next_token();
890
+ }
891
+ else {
892
+ s = stmt();
893
+ r.push(s);
894
+ }
895
+ }
896
+ }
897
+ return r;
898
+ };
899
+
900
+ var stmt = function() {
901
+ var c = token;
902
+ if (c.std) {
903
+ next_token();
904
+ return c.std();
905
+ }
906
+ var e = expr(0);
907
+ return e;
908
+ };
909
+
910
+ var expr = function(right_binding_power) {
911
+ var old = token;
912
+ next_token();
913
+ // console.log(old);
914
+ var left = old.nud();
915
+ while (right_binding_power < token.lbp) {
916
+ old = token;
917
+ next_token();
918
+ left = old.led(left);
919
+ }
920
+ return left;
921
+ };
922
+
923
+
924
+
925
+ var get_next_string_token = function() {
926
+ var str_parse = current_string_parse();
927
+
928
+ // see if we can read end of string/xstring/regexp markers
929
+ if (scanner.scan( new RegExp('^\\' + str_parse.beg))) {
930
+ pop_string_parse();
931
+ if (str_parse.beg == '"' || str_parse.beg == "'") {
932
+ lex_state = EXPR_END;
933
+ return [tSTRING_END, scanner.matched];
934
+ }
935
+ else {
936
+ // assume to be xstring
937
+ return [tXSTRING_END, scanner.matched]
938
+ }
939
+ }
940
+
941
+ // not end of string, so we must be parsing contents
942
+ var str_buffer = [];
943
+
944
+ if (scanner.scan(/^#(\$|\@)/)) {
945
+ return [tSTRING_DVAR, scanner.matched];
946
+ }
947
+ else if (scanner.scan(/^#\{/)) {
948
+ // we are into ruby code, so stop parsing content (for the moment)
949
+ str_parse.content = false;
950
+ return [tSTRING_DBEG, scanner.matched];
951
+ }
952
+ else if (scanner.scan(/^#/)) {
953
+ str_buffer.push('#');
954
+ }
955
+
956
+ // content regexp (what is valid content for strings..)
957
+ var reg_exp = (str_parse.beg == '`') ?
958
+ // xstring: CAN include new lines
959
+ new RegExp('[^\\' + str_parse.beg + '\#\0\\]+|.') :
960
+ // normal string: cannot include new lines
961
+ new RegExp('[^\\' + str_parse.beg + '\#\0\\\n]+|.');
962
+
963
+ scanner.scan(reg_exp);
964
+ str_buffer.push(scanner.matched);
965
+ return [tSTR_CONTENT, str_buffer.join('')];
966
+ };
967
+
968
+
969
+ // checks id of current token to make sure it matches, only if id is defined.
970
+ var next_token = function(id) {
971
+ // last token support
972
+ last_token = token;
973
+ // capture string stuff
974
+ if (current_string_parse() && current_string_parse().content) {
975
+ // console.log('geting str token');
976
+ var t = get_next_string_token();
977
+ // console.log('string token: (' + t[0] + ' : ' + t[1] + ') lex_state: (' + lex_state + ')');
978
+ // token = object_create(sym_tblt);
979
+ token = { };
980
+ token.type = t[0];
981
+ token.value = t[1];
982
+ return token;
983
+ }
984
+
985
+ var t = get_next_token();
986
+ if (id && (id !== token.type)) {
987
+ throw 'Unexpected value "' + token.value + '". Expecting: ' + id
988
+ }
989
+ // console.log('token: (' + t[0] + ' : ' + t[1] + ') lex_state: (' + lex_state + ')');
990
+ // token = { type: t[0], value:t[1] };
991
+ // token = {};
992
+ token = object_create(sym_tbl[t[0]]);
993
+ token.type = t[0];
994
+ token.value = t[1];
995
+ // console.log(token.value + ', ' + last_token.value);
996
+ return token;
997
+ };
998
+
999
+ // actually get the next token
1000
+ var get_next_token = function() {
1001
+ var c = '', space_seen = false;
1002
+
1003
+ last_state = lex_state;
1004
+ cmd_start = false;
1005
+
1006
+
1007
+ while (true) {
1008
+ // console.log(scanner.working_string);
1009
+ // if (scanner.scan(/\ |\t|\r/)) {
1010
+ if(scanner.scan(/^(\ |\t|\r)/)) {
1011
+ space_seen = true;
1012
+ // console.log('found space: "' + scanner.matched + '"');
1013
+ // console.log(scanner.working_string);
1014
+ continue;
1015
+ }
1016
+ else if (scanner.scan(/^(\n|#)/)) {
1017
+ // console.log('found: ' + scanner.matched);
1018
+ c = scanner.matched;
1019
+ if (c == '#') {
1020
+ scanner.scan(/^(.*\n)/);
1021
+ }
1022
+ // we can skip any more blank lines..(combine them into one..)
1023
+ scanner.scan(/^(\n+)/);
1024
+ // console.log('we scanned lots');
1025
+ // console.log(scanner.matched);
1026
+
1027
+ if (lex_state == EXPR_BEG) {
1028
+ continue;
1029
+ }
1030
+ cmd_start = true;
1031
+ lex_state = EXPR_BEG;
1032
+ return [tNL, '\n'];
1033
+ }
1034
+ else if (scanner.scan(/^[+-]/)) {
1035
+ var result = scanner.matched == '+' ? tPLUS : tMINUS;
1036
+ var sign = (result == tPLUS) ? tUPLUS : tUMINUS;
1037
+ // method name
1038
+ if (lex_state == EXPR_FNAME || lex_state == EXPR_DOT) {
1039
+ lex_state = EXPR_ARG;
1040
+ if (scanner.scan(/^@/)) {
1041
+ return [sign, result + '@'];
1042
+ }
1043
+ else {
1044
+ return [sign, result];
1045
+ }
1046
+ }
1047
+ // += or -=
1048
+ if (scanner.scan(/^\=/)) {
1049
+ lex_state = EXPR_BEG;
1050
+ return [tOP_ASGN, result];
1051
+ }
1052
+
1053
+ if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
1054
+ lex_state = EXPR_BEG;
1055
+ return [sign, result];
1056
+ }
1057
+
1058
+ lex_state = EXPR_BEG;
1059
+ return [result, scanner.matched];
1060
+ }
1061
+
1062
+
1063
+
1064
+
1065
+ else if (scanner.scan(/^\//)) {
1066
+ lex_state = EXPR_BEG;
1067
+ return ['/', scanner.matched];
1068
+ }
1069
+
1070
+ else if (scanner.scan(/^\*\*\=/)) {
1071
+ lex_state = EXPR_BEG;
1072
+ return [tOP_ASGN, "**"];
1073
+ }
1074
+ else if (scanner.scan(/^\*\*/)) {
1075
+ return [tPOW, "**"];
1076
+ }
1077
+ else if (scanner.scan(/^\*\=/)) {
1078
+ lex_state = EXPR_BEG;
1079
+ return [tOP_ASGN, "*"];
1080
+ }
1081
+ else if (scanner.scan(/^\*/)) {
1082
+ var r;
1083
+ if (lex_state == EXPR_FNAME) {
1084
+ lex_state = EXPR_BEG;
1085
+ r = "*";
1086
+ }
1087
+ else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
1088
+ r = tSTAR;
1089
+ }
1090
+ else {
1091
+ lex_state = EXPR_BEG;
1092
+ r = "*"
1093
+ }
1094
+ return [r, scanner.matched];
1095
+ }
1096
+
1097
+
1098
+
1099
+
1100
+
1101
+
1102
+ else if (scanner.scan(/^\<\=\>/)) {
1103
+ return [tCMP, scanner.matched];
1104
+ }
1105
+ else if (scanner.scan(/^\<\=/)) {
1106
+ return [tLEQ, "<="];
1107
+ }
1108
+ else if (scanner.scan(/^\<\<\=/)) {
1109
+ lex_state = EXPR_BEG;
1110
+ return [tOP_ASGN, "<<"];
1111
+ }
1112
+ else if (scanner.scan(/^\<\</)) {
1113
+ if (([EXPR_END, EXPR_DOT, EXPR_ENDARG, EXPR_CLASS].indexOf(lex_state) != -1) && space_seen) {
1114
+ return [tLSHFT, "<<"];
1115
+ }
1116
+ lex_state = EXPR_BEG;
1117
+ return [tLSHFT, "<<"];
1118
+ }
1119
+ else if (scanner.scan(/^\</)) {
1120
+ lex_state = EXPR_BEG;
1121
+ return ["<", "<"];
1122
+ }
1123
+
1124
+
1125
+
1126
+
1127
+ else if (scanner.scan(/^\&\&\=/)) {
1128
+ lex_state = EXPR_BEG;
1129
+ return [tOP_ASGN, "&&"];
1130
+ }
1131
+ else if (scanner.scan(/^\&\&/)) {
1132
+ lex_state = EXPR_BEG;
1133
+ return [tANDOP, "&&"];
1134
+ }
1135
+ else if (scanner.scan(/^\&\=/)) {
1136
+ lex_state = EXPR_BEG;
1137
+ return [tOP_ASGN, "&"];
1138
+ }
1139
+ else if (scanner.scan(/^\&/)) {
1140
+ var r;
1141
+ if (space_seen && !scanner.check(/^\s/)) {
1142
+ if (lex_state == EXPR_CMDARG) r = tAMPER;
1143
+ else r = "&";
1144
+ }
1145
+ else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
1146
+ r = tAMPER;
1147
+ }
1148
+ else {
1149
+ r = "&";
1150
+ }
1151
+ return [r, "&"];
1152
+ }
1153
+
1154
+
1155
+
1156
+
1157
+ // strings.. in order: double, single, xstring
1158
+ else if (scanner.scan(/^\"/)) {
1159
+ push_string_parse({ beg: '"', content: true });
1160
+ return [tSTRING_BEG, scanner.matched];
1161
+ }
1162
+ else if (scanner.scan(/^\'/)) {
1163
+ push_string_parse({ beg: "'", content: true });
1164
+ return [tSTRING_BEG, scanner.matched];
1165
+ }
1166
+ else if (scanner.scan(/^\`/)) {
1167
+ push_string_parse({ beg: "`", content: true });
1168
+ return [tXSTRING_BEG, scanner.matched];
1169
+ }
1170
+
1171
+ // numbers
1172
+ else if (scanner.check(/^[0-9]/)) {
1173
+ lex_state = EXPR_END;
1174
+ if (scanner.scan(/^[\d_]+\.[\d_]+\b/)) {
1175
+ return [tFLOAT, scanner.matched];
1176
+ }
1177
+ else if (scanner.scan(/^[\d_]+\b/)) {
1178
+ return [tINTEGER, scanner.matched];
1179
+ }
1180
+ else if (scanner.scan(/^0(x|X)(\d|[a-f]|[A-F])+/)) {
1181
+ return [tINTEGER, scanner.matched];
1182
+ }
1183
+ else {
1184
+ console.log('unexpected number type');
1185
+ return [false, false];
1186
+ }
1187
+ }
1188
+
1189
+
1190
+ else if (scanner.scan(/^\|\|\=/)) {
1191
+ lex_state = EXPR_BEG;
1192
+ return [tOP_ASGN, '||'];
1193
+ }
1194
+ else if (scanner.scan(/^\|\|/)) {
1195
+ lex_state = EXPR_BEG;
1196
+ return [tOROP, scanner.matched];
1197
+ }
1198
+ else if (scanner.scan(/^\|\=/)) {
1199
+ lex_state = EXPR_BEG;
1200
+ return [tOP_ASGN, '|'];
1201
+ }
1202
+ else if (scanner.scan(/^\|/)) {
1203
+ lex_state = EXPR_BEG;
1204
+ return ["|", scanner.matched];
1205
+ }
1206
+
1207
+ else if (scanner.scan(/^\:/)) {
1208
+ // console.log ("HERE " + lex_state);
1209
+ if (lex_state === EXPR_END || lex_state === EXPR_ENDARG || scanner.check(/^\s/)) {
1210
+ // FIXME: hack for tertiary statements
1211
+ if (!scanner.check(/^\w/)) {
1212
+ return [':', scanner.matched];
1213
+ }
1214
+
1215
+ lex_state = EXPR_BEG;
1216
+ return [tSYMBEG, scanner.matched];
1217
+ }
1218
+
1219
+ lex_state = EXPR_FNAME;
1220
+ return [tSYMBEG, ':'];
1221
+ }
1222
+
1223
+ else if (scanner.scan(/^\[/)) {
1224
+ result = scanner.matched;
1225
+
1226
+ if (lex_state == EXPR_FNAME || lex_state == EXPR_DOT) {
1227
+ lex_state = EXPR_ARG
1228
+ if (scanner.scan(/^\]\=/)) {
1229
+ return [tASET, '[]='];
1230
+ }
1231
+ else if (scanner.scan(/^\]/)) {
1232
+ return [tAREF, '[]'];
1233
+ }
1234
+ else {
1235
+ throw "error, unexpecrted '[]' token"
1236
+ }
1237
+ }
1238
+ // space seen allows for method calls with array as first param
1239
+ // otherwise it thinks its calling the '[]' method
1240
+ else if (lex_state == EXPR_BEG || lex_state == EXPR_MID || space_seen) {
1241
+ return [tLBRACK, scanner.matched]
1242
+ }
1243
+ // hmm?
1244
+ return ['[', scanner.matched]
1245
+ }
1246
+
1247
+ else if (scanner.scan(/^\{/)) {
1248
+ var result;
1249
+ if ([EXPR_END, EXPR_CMDARG].indexOf(lex_state) !== -1) {
1250
+ // primary block
1251
+ result = '{';
1252
+ }
1253
+ else if (lex_state == EXPR_ENDARG) {
1254
+ // expr block
1255
+ result = tLBRACE_ARG;
1256
+ }
1257
+ else {
1258
+ // hash
1259
+ result = tLBRACE;
1260
+ }
1261
+ return [result, scanner.matched];
1262
+ }
1263
+
1264
+ // ]
1265
+ else if (scanner.scan(/^\]/)) {
1266
+ lex_state = EXPR_END;
1267
+ return [']', scanner.matched];
1268
+ }
1269
+
1270
+ else if (scanner.scan(/^\;/)) {
1271
+ lex_state = EXPR_BEG;
1272
+ return [tSEMI, ';'];
1273
+ }
1274
+ // #
1275
+ else if (scanner.scan(/^\(/)) {
1276
+ var result = '(';
1277
+ if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
1278
+ result = tLPAREN;
1279
+ }
1280
+ else if (space_seen) {
1281
+ if (lex_state == EXPR_CMDARG) {
1282
+ result = tLPAREN_ARG;
1283
+ }
1284
+ else if(lex_state == EXPR_ARG) {
1285
+ // dont put space before arys
1286
+ result = tLPAREN2;
1287
+ }
1288
+ }
1289
+ lex_state = EXPR_BEG;
1290
+ return [result, scanner.matched];
1291
+ }
1292
+ // )
1293
+ else if (scanner.scan(/^\)/)) {
1294
+ lex_state = EXPR_END;
1295
+ return [')', scanner.matched];
1296
+ }
1297
+
1298
+ // }
1299
+ else if (scanner.scan(/^\}/)) {
1300
+ lex_state = EXPR_END;
1301
+ // throw 'got to end of string'
1302
+ if (current_string_parse()) {
1303
+ current_string_parse().content = true
1304
+ }
1305
+ // check if parsing string...
1306
+ return ['}', scanner.matched];
1307
+ }
1308
+
1309
+ // .
1310
+ else if (scanner.scan(/^\./)) {
1311
+ // should be EXPR_DOT in ALL cases?
1312
+ // if (lex_state == EXPR_FNAME) {
1313
+ lex_state = EXPR_DOT;
1314
+ // }
1315
+ return ['.', scanner.matched];
1316
+ }
1317
+
1318
+ // ,
1319
+ else if (scanner.scan(/^\,/)) {
1320
+ lex_state = EXPR_BEG;
1321
+ return [',', scanner.matched];
1322
+ }
1323
+
1324
+ // Class variabled
1325
+ else if (scanner.scan(/^\@\@\w*/)) {
1326
+ lex_state = EXPR_END;
1327
+ return [tCVAR, scanner.matched];
1328
+ }
1329
+ // Instance variables
1330
+ else if (scanner.scan(/^\@\w*/)) {
1331
+ lex_state = EXPR_END;
1332
+ return [tIVAR, scanner.matched];
1333
+ }
1334
+
1335
+ else if (scanner.scan(/^\=\>/)) {
1336
+ lex_state = EXPR_BEG;
1337
+ return [tASSOC, scanner.matched];
1338
+ }
1339
+
1340
+ else if (scanner.scan(/^\=/)) {
1341
+ lex_state = EXPR_BEG;
1342
+ return ['=', scanner.matched];
1343
+ }
1344
+
1345
+ else if (scanner.scan(/^\w+[\?\!]?/)) {
1346
+ switch (scanner.matched) {
1347
+ case 'def':
1348
+ lex_state = EXPR_FNAME;
1349
+ return [kDEF, scanner.matched];
1350
+ case 'end':
1351
+ lex_state = EXPR_END;
1352
+ return [kEND, scanner.matched];
1353
+ case 'class':
1354
+ // catch 'class' being used as a method name. This only works when class is used
1355
+ // like object.class .. you cannot just use 'class' to call class method on self
1356
+ // without explicitly stating self as the receiver.
1357
+ if (lex_state == EXPR_DOT) {
1358
+ return [tIDENTIFIER, scanner.matched];
1359
+ }
1360
+ lex_state = EXPR_CLASS;
1361
+ return [kCLASS, scanner.matched];
1362
+ case 'module':
1363
+ lex_state = EXPR_BEG;
1364
+ return [kMODULE, scanner.matched];
1365
+ case 'do':
1366
+ if (lex_state == EXPR_ENDARG) {
1367
+ lex_state = EXPR_BEG;
1368
+ return [kDO_BLOCK, scanner.matched];
1369
+ }
1370
+ return [kDO, scanner.matched];
1371
+ case 'if':
1372
+ if (lex_state == EXPR_BEG) {
1373
+ return [kIF, scanner.matched];
1374
+ }
1375
+ lex_state = EXPR_BEG;
1376
+ return [kIF_MOD, scanner.matched];
1377
+ case 'then':
1378
+ return [kTHEN, scanner.matched];
1379
+ case 'else':
1380
+ return [kELSE, scanner.matched];
1381
+ case 'elsif':
1382
+ return [kELSIF, scanner.matched];
1383
+ case 'unless':
1384
+ if (lex_state == EXPR_BEG) {
1385
+ return [kUNLESS, scanner.matched];
1386
+ }
1387
+ lex_state = EXPR_BEG;
1388
+ return [kUNLESS_MOD, scanner.matched];
1389
+ case 'self':
1390
+ if (lex_state != EXPR_FNAME) {
1391
+ lex_state = EXPR_END;
1392
+ }
1393
+ return [kSELF, scanner.matched];
1394
+ case 'super':
1395
+ lex_state = EXPR_ARG;
1396
+ return [kSUPER, scanner.matched];
1397
+ case 'true':
1398
+ lex_state = EXPR_END;
1399
+ return [kTRUE, scanner.matched];
1400
+ case 'false':
1401
+ lex_state = EXPR_END;
1402
+ return [kFALSE, scanner.matched];
1403
+ case 'nil':
1404
+ lex_state = EXPR_END;
1405
+ return [kNIL, scanner.matched];
1406
+ case 'return':
1407
+ lex_state = EXPR_MID;
1408
+ return [kRETURN, scanner.matched];
1409
+ case 'case':
1410
+ lex_state = EXPR_BEG;
1411
+ return [kCASE, scanner.matched];
1412
+ case 'when':
1413
+ lex_state = EXPR_BEG;
1414
+ return [kWHEN, scanner.matched];
1415
+ case 'yield':
1416
+ lex_state = EXPR_ARG;
1417
+ return [kYIELD, scanner.matched];
1418
+ }
1419
+
1420
+ var matched = scanner.matched;
1421
+
1422
+ // labels - avoid picking up a mod/class divide name
1423
+ if ((scanner.peek(2) != '::') && (scanner.scan(/^\:/))) {
1424
+ return [tLABEL, matched + scanner.matched];
1425
+ }
1426
+
1427
+ if (lex_state == EXPR_FNAME) {
1428
+ if (scanner.scan(/^=(?:(?![~>=])|(?==>))/)) {
1429
+ lex_state = EXPR_END;
1430
+ return [tIDENTIFIER, matched + scanner.matched];
1431
+ }
1432
+ }
1433
+
1434
+ // console.log('current state: ' + lex_state);
1435
+
1436
+ if ([EXPR_BEG, EXPR_DOT, EXPR_MID, EXPR_ARG, EXPR_CMDARG].indexOf(lex_state) !== -1) {
1437
+ lex_state = EXPR_CMDARG;
1438
+ }
1439
+ else {
1440
+ lex_state = EXPR_END;
1441
+ }
1442
+
1443
+ return [matched.match(/^[A-Z]/) ? tCONSTANT : tIDENTIFIER, matched];
1444
+ }
1445
+
1446
+ else {
1447
+ // false, false === end of stream
1448
+ return [false, false];
1449
+ }
1450
+ }
1451
+ };
1452
+
1453
+ var iseq_stack = [], iseq_stack_current = null;
1454
+ var iseq_locals_stack = [], iseq_locals_current = null;
1455
+ var iseq_jump_stack = [], iseq_jump_current = null;
1456
+
1457
+ function iseq_jump_idx() {
1458
+ return (iseq_jump_current++).toString();
1459
+ }
1460
+
1461
+ function iseq_stack_push(s) {
1462
+ iseq_jump_current = 0;
1463
+ iseq_jump_stack.push(iseq_jump_current);
1464
+
1465
+ iseq_locals_stack.push(iseq_locals_current = []);
1466
+ iseq_stack.push(s);
1467
+ iseq_stack_current = s;
1468
+ return s;
1469
+ }
1470
+
1471
+ function iseq_stack_pop() {
1472
+ // console.log(iseq_stack_current[7]);
1473
+ // throw "a"
1474
+ var f = iseq_stack_current[7].join("");
1475
+ console.log(f);
1476
+ var func = new Function(f);
1477
+ // console.log("here");
1478
+ // console.log(iseq_stack_current);
1479
+ iseq_stack_current[7] = func;
1480
+
1481
+
1482
+ iseq_jump_stack.pop();
1483
+ iseq_jump_current = iseq_jump_stack[iseq_jump_stack.length - 1];
1484
+
1485
+ iseq_locals_current = iseq_locals_stack[iseq_locals_stack.length - 2];
1486
+ iseq_locals_stack.pop();
1487
+
1488
+ iseq_stack_current = iseq_stack[iseq_stack.length - 2];
1489
+ return iseq_stack.pop();
1490
+ }
1491
+
1492
+ function write(str) {
1493
+ iseq_stack_current[7].push(str);
1494
+ }
1495
+
1496
+ // function iseq_opcode_push(opcode) {
1497
+ // iseq_stack_current[7].push(opcode);
1498
+ // return opcode;
1499
+ // }
1500
+
1501
+ /**
1502
+ checks the given name to see if its in the index. If the result is 0 or above,
1503
+ it is, and the idx is the index in the locals array. -1 means it is not in the
1504
+ array (so not a local)
1505
+ */
1506
+ function iseq_locals_idx(name) {
1507
+ return iseq_locals_current.indexOf(name);
1508
+ }
1509
+
1510
+ /**
1511
+ push locals name. the return value is the new index for the name
1512
+ */
1513
+ function iseq_locals_push(name) {
1514
+ var len = iseq_locals_current.length;
1515
+ iseq_locals_current.push(name);
1516
+ return len;
1517
+ }
1518
+
1519
+ function generate_tree(tree) {
1520
+ console.log("tree:");
1521
+ console.log(tree);
1522
+ var top_iseq = iseq_stack_push([0,0,"<compiled>",filename,ISEQ_TYPE_TOP,0,[],[]]);
1523
+
1524
+ var i;
1525
+ for (i = 0; i < tree.length; i++) {
1526
+ generate_stmt(tree[i], { instance: true, full_stmt: true, last_stmt:(tree.length - 1) == i, top_level: true} );
1527
+ }
1528
+ console.log(iseq_stack_pop());
1529
+
1530
+ return top_iseq;
1531
+ }
1532
+
1533
+ function generate_stmt(stmt, context) {
1534
+ switch (stmt.type) {
1535
+ case kCLASS:
1536
+ generate_class(stmt, context);
1537
+ break;
1538
+ case kMODULE:
1539
+ generate_module(stmt, context);
1540
+ break;
1541
+ case kDEF:
1542
+ generate_def(stmt, context);
1543
+ break;
1544
+ case tCALL:
1545
+ generate_call(stmt, context);
1546
+ break;
1547
+ case tSYMBEG:
1548
+ generate_symbol(stmt, context);
1549
+ break;
1550
+ case tCONSTANT:
1551
+ generate_constant(stmt, context);
1552
+ break;
1553
+ case tIDENTIFIER:
1554
+ generate_identifier(stmt, context);
1555
+ break;
1556
+ case tINTEGER:
1557
+ generate_integer(stmt, context);
1558
+ break;
1559
+ case tSTRING_BEG:
1560
+ generate_string(stmt, context);
1561
+ break;
1562
+ case kSELF:
1563
+ generate_self(stmt, context);
1564
+ break;
1565
+ case kIF:
1566
+ generate_if(stmt, context);
1567
+ break;
1568
+ case '=':
1569
+ generate_assign(stmt, context);
1570
+ break;
1571
+ case kFALSE:
1572
+ generate_false(stmt, context);
1573
+ break;
1574
+ case kTRUE:
1575
+ generate_true(stmt, context);
1576
+ break;
1577
+ case tLBRACK:
1578
+ generate_array(stmt, context);
1579
+ break;
1580
+ default:
1581
+ console.log("unknown generate_stmt type: " + stmt.type + ", " + stmt.value);
1582
+ }
1583
+ }
1584
+
1585
+ function generate_array(stmt, context) {
1586
+ write("[");
1587
+ if (stmt.$values) {
1588
+ var i;
1589
+ for (i = 0; i < stmt.$values.length; i++) {
1590
+ if (i > 0) write(",");
1591
+ generate_stmt(stmt.$values[i], {full_stmt:false, last_stmt:false});
1592
+ }
1593
+ }
1594
+ write("]");
1595
+ // iseq_opcode_push([iNEWARRAY, stmt.$values ? stmt.$values.length : 0]);
1596
+ }
1597
+
1598
+ function generate_assign(stmt, context) {
1599
+
1600
+ if (context.last_stmt && context.full_stmt) write("return ");
1601
+
1602
+
1603
+ if (stmt.$lhs.type == tIDENTIFIER) {
1604
+ var idx;
1605
+ // iseq_opcode_push([iSETLOCAL, 0]);
1606
+ if ((idx = iseq_locals_idx(stmt.$lhs.value)) == -1) {
1607
+ // doesnt exist, so we need a new local
1608
+ // iseq_opcode_push([iSETLOCAL, iseq_locals_push(stmt.$lhs.value)]);
1609
+ write('vm_setlocal(' + iseq_locals_push(stmt.$lhs.value) + ',');
1610
+ generate_stmt(stmt.$rhs, {full_stmt: false, last_stmt: false});
1611
+ write(')');
1612
+ }
1613
+ else {
1614
+ // already a local, so just get the index
1615
+ // iseq_opcode_push([iSETLOCAL, idx]);
1616
+ }
1617
+ }
1618
+ else {
1619
+ throw "unsupported lhs, for now"
1620
+ }
1621
+
1622
+ if (context.full_stmt) write(";");
1623
+ }
1624
+
1625
+ function generate_if(stmt, context) {
1626
+ // if expression..
1627
+ generate_stmt(stmt.$expr, {instance:context.instance, full_stmt:false, last_stmt:false});
1628
+ var jmp_label = iseq_jump_idx();
1629
+ iseq_opcode_push([iBRANCHUNLESS, jmp_label]);
1630
+
1631
+ // stmts
1632
+ if (stmt.$stmts) {
1633
+ var i, s = stmt.$stmts;
1634
+ for (i = 0; i < s.length; i++) {
1635
+ generate_stmt(s[i], {instance:context.instance, full_stmt:true, last_stmt:false});
1636
+ }
1637
+ }
1638
+
1639
+ iseq_opcode_push(jmp_label);
1640
+
1641
+ // if (context.last_stmt && context.full_stmt) write("return ");
1642
+ // write("(function(){");
1643
+ //
1644
+ // (stmt.type == kIF) ? write("if(RTEST(") : write("if(!RTEST(");
1645
+ //
1646
+ // // RTEST expression
1647
+ // generate_stmt(stmt.$expr, {instance:context.instance, full_stmt:false, last_stmt:false});
1648
+ // write(")){\n");
1649
+ //
1650
+ // if (stmt.$stmts) {
1651
+ // var i, s = stmt.$stmts;
1652
+ // for (i = 0; i < s.length; i++) {
1653
+ // generate_stmt(s[i], {instance:context.instance, full_stmt:true, last_stmt:(s[s.length -1] == s[i] ? true : false)});
1654
+ // }
1655
+ // }
1656
+ //
1657
+ // write("}\n");
1658
+ //
1659
+ // if (stmt.$tail) {
1660
+ // var i, t = stmt.$tail;
1661
+ // for (i = 0; i < t.length; i++) {
1662
+ // if (t[i].type == kELSIF) {
1663
+ // write("else if(RTEST(");
1664
+ // generate_stmt(t[i].$expr, {instance:context.instance, full_stmt:false, last_stmt:false});
1665
+ // write(")){\n");
1666
+ // }
1667
+ // else {
1668
+ // write("else{\n");
1669
+ // }
1670
+ //
1671
+ // if (t[i].$stmts) {
1672
+ // var j, k = t[i].$stmts;
1673
+ // for (j = 0; j < k.length; j++) {
1674
+ // // console.log("doing " + k[j].value);
1675
+ // generate_stmt(k[j], {instance:context.instance, full_stmt:true, last_stmt:(k[k.length - 1] == k[i] ? true : false)});
1676
+ // }
1677
+ // }
1678
+ //
1679
+ // write("}\n");
1680
+ // }
1681
+ // }
1682
+ //
1683
+ // write("})()");
1684
+ // if (context.full_stmt) write(";\n");
1685
+ }
1686
+
1687
+ function generate_false(stmt, context) {
1688
+ iseq_opcode_push([iPUTOBJECT, false]);
1689
+
1690
+ if (context.last_stmt && context.full_stmt) {
1691
+ iseq_opcode_push([iLEAVE]);
1692
+ }
1693
+ }
1694
+
1695
+ function generate_true(stmt, context) {
1696
+ iseq_opcode_push([iPUTOBJECT, true]);
1697
+
1698
+ if (context.last_stmt && context.full_stmt) {
1699
+ iseq_opcode_push([iLEAVE]);
1700
+ }
1701
+ }
1702
+
1703
+
1704
+ function generate_self(stmt, context) {
1705
+ if (context.last_stmt && context.full_stmt) write("return ");
1706
+ write(current_self());
1707
+ if (context.full_stmt) write(";\n");
1708
+ }
1709
+
1710
+ function generate_string(stmt, context) {
1711
+ // iseq_opcode_push([iPUTSTRING, stmt.$parts[0].value]);
1712
+
1713
+ // if (context.last_stmt && context.full_stmt) {
1714
+ // iseq_opcode_push([iLEAVE]);
1715
+ // }
1716
+
1717
+ write("'" + stmt.$parts[0].value + "'");
1718
+ }
1719
+
1720
+ function generate_integer(stmt, context) {
1721
+
1722
+ // iseq_opcode_push([iPUTOBJECT, parseInt(stmt.value)]);
1723
+ write(parseInt(stmt.value));
1724
+
1725
+ if (context.last_stmt && context.full_stmt) {
1726
+ iseq_opcode_push([iLEAVE]);
1727
+ }
1728
+ }
1729
+
1730
+ function generate_constant(stmt, context) {
1731
+ // iseq_opcode_push([iPUTNIL]);
1732
+ // iseq_opcode_push([iGETCONSTANT, stmt.value]);
1733
+ write("vm_getconstant(nil,'" + stmt.value + "')");
1734
+ }
1735
+
1736
+ function generate_identifier(identifier, context) {
1737
+ // for now, assumption is that they are all method calls. should check for local or dynamic
1738
+
1739
+ // no receiver.
1740
+ var idx;
1741
+ if ((idx = iseq_locals_idx(identifier.value)) == -1) {
1742
+ // not an identifier
1743
+ iseq_opcode_push([iPUTNIL]);
1744
+ iseq_opcode_push([iSEND, identifier.value, 0, null, 8, null]);
1745
+ }
1746
+ else {
1747
+ // its an identifier
1748
+ iseq_opcode_push([iGETLOCAL, idx]);
1749
+ }
1750
+
1751
+
1752
+ if (context.full_stmt && context.last_stmt) {
1753
+ iseq_opcode_push([iLEAVE]);
1754
+ }
1755
+ else if (context.full_stmt) {
1756
+ iseq_opcode_push([iPOP]);
1757
+ }
1758
+ }
1759
+
1760
+ function generate_symbol(sym, context) {
1761
+
1762
+ iseq_opcode_push([iPUTOBJECT, ID2SYM(sym.$name.value)]);
1763
+
1764
+ if (context.full_stmt && context.last_stmt) {
1765
+ iseq_opcode_push([iLEAVE]);
1766
+ }
1767
+ else if (context.full_stmt) {
1768
+ iseq_opcode_push([iPOP]);
1769
+ }
1770
+ }
1771
+
1772
+ function generate_call(call, context) {
1773
+
1774
+ write("vm_send(");
1775
+
1776
+ // receiver
1777
+ if (call.$recv) {
1778
+ generate_stmt(call.$recv, {instance:context.instance, full_stmt:false});
1779
+ // fix fcall bit..?
1780
+ }
1781
+ else {
1782
+ write("vm_putself()");
1783
+ }
1784
+
1785
+ // mid
1786
+ var mid = call.$meth;
1787
+ if (typeof mid === 'object') { mid = mid.value; }
1788
+ write(",'" + mid + "',");
1789
+
1790
+ // arguments (argv)
1791
+ if (call.$call_args && call.$call_args.args) {
1792
+ write("[");
1793
+ var i = 0, a = call.$call_args.args;
1794
+ for (i = 0; i < a.length; i++) {
1795
+ if (i > 0) write(",");
1796
+ generate_stmt(a[i], {instance:context.instance, full_stmt:false});
1797
+ }
1798
+ write("],");
1799
+ }
1800
+ else {
1801
+ write("[],");
1802
+ }
1803
+
1804
+ // block
1805
+ write("null");
1806
+
1807
+
1808
+ // end
1809
+ write(")");
1810
+
1811
+ if (context.full_stmt) write(";");
1812
+
1813
+
1814
+ // var mid = call.$meth;
1815
+ // if (typeof mid === 'object') {
1816
+ // mid = mid.value;
1817
+ // }
1818
+ //
1819
+ // var iseq = [iSEND, mid, 0, null, 8, null];
1820
+ //
1821
+ // // receiver
1822
+ // if (call.$recv) {
1823
+ // generate_stmt(call.$recv, {instance:context.instance, full_stmt:false});
1824
+ // // fix fcall bit
1825
+ // iseq[4] = 0;
1826
+ // }
1827
+ // else {
1828
+ // iseq_opcode_push([iPUTNIL]);
1829
+ // }
1830
+ //
1831
+ // // args..
1832
+ // if (call.$call_args && call.$call_args.args) {
1833
+ // var i, a = call.$call_args.args;
1834
+ // for (i = 0; i < a.length; i++) {
1835
+ // generate_stmt(a[i], { instance:context.instance, full_stmt:false });
1836
+ // }
1837
+ // iseq[2] = a.length;
1838
+ // }
1839
+ //
1840
+ // iseq_opcode_push(iseq);
1841
+ //
1842
+ // if (context.full_stmt && context.last_stmt) {
1843
+ // // if last stmt, we want to leave the context (with result of call on stack)
1844
+ // iseq_opcode_push([iLEAVE]);
1845
+ // }
1846
+ // else if (context.full_stmt) {
1847
+ // // if not last stmt, but a full stmt, remove result from stack. no-one wants it
1848
+ // iseq_opcode_push([iPOP]);
1849
+ // }
1850
+ //
1851
+ // // block
1852
+ // if (call.$brace_block) {
1853
+ // var b_seq = [0, 0, "block in <compiled>", filename, ISEQ_TYPE_BLOCK, 0, [], []];
1854
+ // iseq[3] = b_seq;
1855
+ //
1856
+ // if (call.$brace_block.$stmts) {
1857
+ // // generate stmts
1858
+ // iseq_stack_push(b_seq);
1859
+ //
1860
+ // var i, s = call.$brace_block.$stmts;
1861
+ // for (i = 0; i < s.length; i++) {
1862
+ // generate_stmt(s[i], {full_stmt:true, last_stmt:false});
1863
+ // }
1864
+ //
1865
+ // iseq_stack_pop();
1866
+ // }
1867
+ // }
1868
+
1869
+
1870
+
1871
+ // iseq_opcode_push([iPUTNIL]);
1872
+ // var iseq = [0, 0, definition.$fname.value, filename, ISEQ_TYPE_METHOD, 0, [], []];
1873
+ // var opcode = [iDEFINEMETHOD, definition.$fname.value, iseq, 0];
1874
+ // iseq_opcode_push(opcode);
1875
+ // iseq_stack_push(iseq);
1876
+ //
1877
+ // if (definition.$stmts) {
1878
+ // var i, s = definition.$stmts;
1879
+ // for (i = 0; i < s.length; i++) {
1880
+ // generate_stmt(s[i], {instance:(definition.$sname ? false : true), full_stmt:true, last_stmt:(s[s.length - 1] == s[i] ? true : false), name:definition.$fname});
1881
+ // }
1882
+ // }
1883
+
1884
+
1885
+
1886
+ // if (context.last_stmt && context.last_stmt) write("return ");
1887
+ //
1888
+ // if(call.value.match(/^[A-Z]/)) {
1889
+ // write(call.value);
1890
+ // write("(");
1891
+ // }
1892
+ // else {
1893
+ // // detect block..
1894
+ // if (call.$brace_block) {
1895
+ // write("rb_block_funcall(");
1896
+ // }
1897
+ // else {
1898
+ // write("rb_funcall(");
1899
+ // }
1900
+ //
1901
+ //
1902
+ // if (call.$recv) {
1903
+ // generate_stmt(call.$recv, {instance:context.instance, full_stmt:false, last_stmt:context.last_stmt, top_level:context.top_level});
1904
+ // }
1905
+ // else {
1906
+ // write(current_self());
1907
+ // }
1908
+ //
1909
+ // write(",'" + call.$meth.value + "'");
1910
+ // }
1911
+ //
1912
+ // // normal args
1913
+ // if (call.$call_args && call.$call_args.args) {
1914
+ // var i, a = call.$call_args.args;
1915
+ // for (i = 0; i < a.length; i++) {
1916
+ // write(",");
1917
+ // generate_stmt(a[i], {instance:context.instance, full_stmt:false});
1918
+ // }
1919
+ // }
1920
+ //
1921
+ // // assocs
1922
+ // if (call.$call_args && call.$call_args.assocs) {
1923
+ //
1924
+ // }
1925
+ //
1926
+ // // block
1927
+ // if (call.$brace_block) {
1928
+ //
1929
+ // }
1930
+ //
1931
+ // // sym block: &:upcase etc
1932
+ // if (call.$call_args && call.$call_args.block_arg) {
1933
+ // write(",rb_funcall(");
1934
+ // generate_stmt(call.$call_args.block_arg.arg, {instance:context.singleton, full_stmt:false, last_stmt:false, top_level:context.top_level});
1935
+ // write(",'to_proc')");
1936
+ // }
1937
+ //
1938
+ // write(")");
1939
+ // if (context.full_stmt) write(";\n");
1940
+ }
1941
+
1942
+ function generate_def(definition, context) {
1943
+ // assume not singleton for now, so define "on nil"
1944
+ iseq_opcode_push([iPUTNIL]);
1945
+ var iseq = [0, 0, definition.$fname.value, filename, ISEQ_TYPE_METHOD, 0, [], []];
1946
+ var opcode = [iDEFINEMETHOD, definition.$fname.value, iseq, 0];
1947
+ iseq_opcode_push(opcode);
1948
+ iseq_stack_push(iseq);
1949
+
1950
+ if (definition.$stmts) {
1951
+ var i, s = definition.$stmts;
1952
+ for (i = 0; i < s.length; i++) {
1953
+ generate_stmt(s[i], {instance:(definition.$sname ? false : true), full_stmt:true, last_stmt:(s[s.length - 1] == s[i] ? true : false), name:definition.$fname});
1954
+ }
1955
+ }
1956
+
1957
+
1958
+
1959
+ // if (definition.singleton) {
1960
+ // write("rb_define_singleton_method(");
1961
+ // generate_stmt(definition.singleton, {instance: context.instance, full_stmt:false, last_stmt:false});
1962
+ // write(",'" + definition.$fname + "',function(self,_cmd");
1963
+ // current_self_push("self");
1964
+ // }
1965
+ // else if (context.top_level) {
1966
+ // write("rb_define_singleton_method(rb_top_self, " + definition.$fname + "',function(self,_cmd");
1967
+ // current_self_push("self");
1968
+ // }
1969
+ // else {
1970
+ // write("rb_define_method(" + current_self() + ",'");
1971
+ // write(definition.$fname.value);
1972
+ // write("',function(self,_cmd");
1973
+ // current_self_push("self");
1974
+ // }
1975
+ //
1976
+ // // arglist
1977
+ // if (definition.$arglist && definition.$arglist.arg) {
1978
+ // var i, a = definition.$arglist.arg;
1979
+ // for (i = 0; i < a.length; i++) {
1980
+ // write(",");
1981
+ // write(a[i].value);
1982
+ // // add_to_nametable(a[i].value);
1983
+ // }
1984
+ // }
1985
+ //
1986
+ // // block arg support - every method potentialy might have a block.
1987
+ // write(",$b");
1988
+ //
1989
+ // write("){\n");
1990
+
1991
+ // block reference goes here (so if we say &block in params, map var block to $b)
1992
+ // if definition[:arglist] && definition[:arglist][:opt_block_arg]
1993
+ // write "var #{definition[:arglist][:opt_block_arg]} = $b;\n"
1994
+ // add_to_nametable definition[:arglist][:opt_block_arg]
1995
+ // end
1996
+
1997
+ // statements
1998
+ // push_string_buffer();
1999
+ // push_nametable();
2000
+
2001
+ // if (definition.$stmts) {
2002
+ // var i, s = definition.$stmts;
2003
+ // for (i = 0; i < s.length; i++) {
2004
+ // generate_stmt(s[i], {instance:(definition.$sname ? false : true), full_stmt:true, last_stmt:(s[s.length - 1] == s[i] ? true : false), name:definition.$fname});
2005
+ // }
2006
+ // }
2007
+
2008
+ // var body_contents = pop_string_buffer(), name_table = pop_nametable();
2009
+ // write each ivar statements..
2010
+ // if name_table.length > 0
2011
+ // write "var #{name_table.join(",")};\n"
2012
+ // end
2013
+
2014
+ // write(body_contents);
2015
+
2016
+ // current_self_pop();
2017
+ // pop_nametable();
2018
+ // write("});\n");
2019
+
2020
+ iseq_stack_pop();
2021
+ }
2022
+
2023
+ function generate_class(stmt, context) {
2024
+
2025
+ if (context.full_stmt && context.last_stmt) write("return ");
2026
+
2027
+ write("vm_defineclass(");
2028
+
2029
+ // base
2030
+ write("vm_putnil(),");
2031
+
2032
+ // superclass
2033
+ if (stmt.$super) {
2034
+ generate_stmt(stmt.$super, {full_stmt:false, last_stmt:false});
2035
+ }
2036
+ else {
2037
+ write("vm_putnil()");
2038
+ }
2039
+ write(",");
2040
+
2041
+ // class id
2042
+ write("'" + stmt.$kname.value + "'");
2043
+ write(",");
2044
+
2045
+ // iseq
2046
+ write("function(){},")
2047
+
2048
+ // op_flag
2049
+ write(0);
2050
+
2051
+ write(")");
2052
+
2053
+ if (context.full_stmt) write(";");
2054
+
2055
+ // base (for class << Ben; ...; end)
2056
+ // iseq_opcode_push([iPUTNIL]);
2057
+ // // superclass
2058
+ // if (stmt.$super) {
2059
+ // // console.log("super..");
2060
+ // // console.log(stmt.$super);
2061
+ // generate_stmt(stmt.$super, {full_stmt: false, last_stmt:false});
2062
+ // }
2063
+ // else {
2064
+ // iseq_opcode_push([iPUTNIL]);
2065
+ // }
2066
+ //
2067
+ // var iseq = [0, 0, "<class:" + stmt.$kname.value + ">", filename, ISEQ_TYPE_CLASS, 0, [], []];
2068
+ // var opcode = [iDEFINECLASS, stmt.$kname.value, iseq, 0];
2069
+ // iseq_opcode_push(opcode);
2070
+ // iseq_stack_push(iseq);
2071
+ //
2072
+ // // statements.
2073
+ // if (stmt.$stmts) {
2074
+ // var i, s = stmt.$stmts;
2075
+ // for (i = 0; i < s.length; i++) {
2076
+ // generate_stmt(s[i], {instance:false, full_stmt:true, last_stmt:(s[s.length - 1] == s[i] ? true : false), top_level:false});
2077
+ // }
2078
+ // }
2079
+ //
2080
+ // iseq_stack_pop();
2081
+
2082
+ // write("(function(self) {\n");
2083
+ // push_nametable();
2084
+ // current_self_push("self");
2085
+ //
2086
+ // if (stmt.$stmts) {
2087
+ // var i, m = stmt.$stmts;
2088
+ // for (i = 0; i < m.length; i++) {
2089
+ // generate_stmt(m[i], {instance: false, full_stmt: true, last_stmt: (m[m.length -1] == m[i] ? true : false), top_level: false});
2090
+ // }
2091
+ // }
2092
+ //
2093
+ // pop_nametable();
2094
+ // current_self_pop();
2095
+ //
2096
+ // write("})(");
2097
+ //
2098
+ // if (context.top_level) {
2099
+ // write("rb_define_class('")
2100
+ // write(stmt.$kname.value);
2101
+ // write("',");
2102
+ // }
2103
+ // else {
2104
+ // write("rb_define_class_under(" + current_self() + ",'");
2105
+ // write(stmt.$kname.value);
2106
+ // write("',");
2107
+ // }
2108
+ //
2109
+ // // superclass
2110
+ // if (stmt.$super) {
2111
+ // write("rb_const_get(self, '" + stmt.$super.value + "'))")
2112
+ // }
2113
+ // else {
2114
+ // write("rb_cObject)");
2115
+ // }
2116
+ //
2117
+ // write(");\n")
2118
+ }
2119
+
2120
+ function generate_module(mod, context) {
2121
+ write("(function(self) {\n");
2122
+ push_nametable();
2123
+ current_self_push("self");
2124
+
2125
+ if (mod.$stmts) {
2126
+ var i, m = mod.$stmts;
2127
+ for (i = 0; i < m.length; i++) {
2128
+ generate_stmt(m[i], {instance: false, full_stmt: false, last_stmt: (m[m.length -1] == m[i] ? true : false), nested: true});
2129
+ }
2130
+ }
2131
+
2132
+ pop_nametable();
2133
+ current_self_pop();
2134
+
2135
+ write("})(");
2136
+
2137
+ if (context.top_level) {
2138
+ write("rb_define_module('");
2139
+ write(mod.$kname.value);
2140
+ write("'));\n");
2141
+ }
2142
+ else {
2143
+ write("rb_define_module_under(" + current_self() + ",'");
2144
+ write(mod.$kname.value);
2145
+ write("'));\n")
2146
+ }
2147
+ }
2148
+
2149
+ this.parse = function(str) {
2150
+ scanner = new vn_ruby_string_scanner(str);
2151
+ next_token();
2152
+ var s = stmts();
2153
+ return generate_tree(s);
2154
+ }
2155
+
2156
+ this.contexts = function() {
2157
+ return contexts;
2158
+ }
2159
+
2160
+ // the parser - pass is the source to actually parse
2161
+ // return function(parse_text) {
2162
+ // scanner = new vn_ruby_string_scanner(parse_text);
2163
+ // next_token();
2164
+ // var s = stmts();
2165
+ // generate_tree(s);
2166
+ // return s;
2167
+ // }
2168
+ return this;
2169
+ };
2170
+
2171
+
2172
+ // String scanner
2173
+ var vn_ruby_string_scanner = function(str) {
2174
+ // whole string
2175
+ this.str = str;
2176
+ // current index
2177
+ this.at = 0;
2178
+ // last matched data
2179
+ this.matched = "";
2180
+ // working string (basically str substr'd from the 'at' index to the end)
2181
+ this.working_string = str;
2182
+ };
2183
+
2184
+ vn_ruby_string_scanner.prototype.scan = function(reg) {
2185
+ // reg = this._fix_regexp_to_match_beg(reg);
2186
+ var res = reg.exec(this.working_string);
2187
+ if (res == null) {
2188
+ return false;
2189
+ }
2190
+ else if (typeof res == "object") {
2191
+ // array.
2192
+ this.at += res[0].length;
2193
+ this.working_string = this.working_string.substr(res[0].length);
2194
+ this.matched = res[0];
2195
+ return res;
2196
+ }
2197
+ else if (typeof res == "string") {
2198
+ this.at += res.length;
2199
+ this.working_string = this.working_string.substr(res.length);
2200
+ return res;
2201
+ }
2202
+ return false;
2203
+ };
2204
+
2205
+ vn_ruby_string_scanner.prototype.check = function(reg) {
2206
+ // reg = this._fix_regexp_to_match_beg(reg);
2207
+ var res = reg.exec(this.working_string);
2208
+ return res;
2209
+ };
2210
+
2211
+ vn_ruby_string_scanner.prototype.matched = function() {
2212
+
2213
+ };
2214
+
2215
+ vn_ruby_string_scanner.prototype.peek = function(len) {
2216
+ return this.working_string.substr(0, len);
2217
+ };
2218
+