-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathswitch.xxl
109 lines (99 loc) · 2.59 KB
/
switch.xxl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// -*-js-*-
var __doc = """
EXTENSION: switch statement
""";
// *BEWARE*! uses Symbol.default, Symbol.case properties
// which will not be dumped!!
var __extend_parser = function (p) {
const CASEVAR = '-*-case-*-';
var Switch = Class.new({
name: "Do",
supers: [p.Stmt],
methods: {
std: function (this) { // parse as statement
p.advance("(");
this.first = p.expression(0);
var slist = [];
p.advance(")");
p.advance("{");
var prev_default;
while (!p.check("}")) {
var tok = p.ctoken();
if (p.check("case")) {
p.reserve(tok);
p.advance();
tok.first = p.expression(0);
tok.case = true; // XXX not visible in AST dump
// XXX set tok.arity?
p.advance(":");
}
else if (p.check("default")) {
p.reserve(tok);
if (prev_default) {
tok.error("previous default label at " +
prev_default.where);
}
prev_default = tok;
tok.default = true; // XXX not visible in AST dump
// XXX set tok.arity?
p.advance();
p.advance(":");
}
else {
tok = p.statement();
}
slist.append(tok);
}
p.advance("}");
this.second = slist;
this.arity = "statement";
return(this);
},
gen: function (this, vmcode) { // gen
var swcode = p.VMCode.new(); // switch VMcode block
swcode.emit_scope(null, this); // scope for switch
swcode.emit_var(CASEVAR, this); // create variable for value
this.first.gen(swcode); // evaluate switch expr
swcode.emit_store(CASEVAR, this); // store in variable
// XXX should "hoist" emit_var (but not init) to top of block?!
// emit tests/branches
this.second.for_each(
function (item) {
if (item.case) {
swcode.gen_push(item.first);
swcode.emit_load(CASEVAR, item);
swcode.emit_binop("==", item);
item.label = swcode.def_fwd_label();
swcode.emit_iftrue(item.label, item);
}
} // function (item)
); // for_each
// end of tests, go to default
var default_label = swcode.def_fwd_label();
swcode.emit_jrst(default_label, this);
// run thru stmts, dropping labels or code
this.second.for_each(
function (item) {
if (item.case) {
swcode.drop_fwd_label(item.label);
}
else if (item.default) {
swcode.drop_fwd_label(default_label);
default_label = null;
}
else {
item.gen(swcode);
}
}
);
// if no default label seen, drop at end of block.
if (default_label !== null) {
swcode.drop_fwd_label(default_label);
}
// create block closure & invoke
vmcode.emit_bclose_call(swcode, this);
} // gen
}
});
p.add_symbol_class("switch", Switch);
};