opal 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/docs/jarv.rdoc +27 -0
- data/lib/opal.rb +29 -0
- data/runtime/array.js +153 -0
- data/runtime/class.js +469 -0
- data/runtime/compar.js +73 -0
- data/runtime/dir.js +115 -0
- data/runtime/enum.js +74 -0
- data/runtime/file.js +165 -0
- data/runtime/gem.js +241 -0
- data/runtime/hash.js +181 -0
- data/runtime/init.js +59 -0
- data/runtime/load.js +251 -0
- data/runtime/module.js +98 -0
- data/runtime/number.js +148 -0
- data/runtime/object.js +522 -0
- data/runtime/opal.js +200 -0
- data/runtime/parse.js +2218 -0
- data/runtime/range.js +56 -0
- data/runtime/re.js +91 -0
- data/runtime/string.js +199 -0
- data/runtime/variable.js +184 -0
- data/runtime/vm.js +1150 -0
- data/runtime/yaml.js +33 -0
- data/tasks/build.rb +16 -0
- metadata +90 -0
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
|
+
|