-
Notifications
You must be signed in to change notification settings - Fork 0
/
nullish.xxl
88 lines (75 loc) · 2.17 KB
/
nullish.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
// -*-js-*-
var __doc = """
Implement JavaScript "Nullish coalescing operator" `??`,
"Logical nullish assignment" `??=`, and
"Optional chaining" `?.` operators
in XXL.
""";
const _classes = __xxl.import("classes");
_classes.Object.is_nullish = false;
_classes.Null.is_nullish = _classes.Undefined.is_nullish = true;
var __extend_parser = function (p) {
var push_thunk = function (vmcode, node) {
"""
create a thunk (closure) to evaluate node; push on stack
"""
var nodecode = p.VMCode.new();
// create scope???
node.gen(nodecode);
vmcode.emit_close(nodecode.finish(node), node); // create closure
vmcode.emit_push(node); // push closure
};
////////////////
// "Nullish coalescing operator" `??`
// a "special form" a binop that passes a closure for RHS
// (only evaluates RHS if LHS is nullish)
p.Nullish = Class.new({
name: "Nullish",
supers: [p.InfixR],
methods: {
gen: function (this, vmcode) {
push_thunk(vmcode, this.second);
this.first.gen(vmcode);
vmcode.emit_binop("??", this);
}
}
});
p.Nullish.lbp = p.PLOR;
p.add_symbol_class("??", p.Nullish);
// a special form: passes thunk for RHS!!
_classes.Object.__binops["??"] = function (l, rfun) {
return(l.is_nullish ? rfun() : l);
};
////////////////
// "Logical nullish assignment" `??=`
// NOTE! Always performs assignment.
p.NullishAssign = Class.new({
name: "NullishAssign",
supers: [p.Assign],
methods: {
gen: function (this, vmcode) {
// XXX eval children of LHS once?
push_thunk(vmcode, this.second); // RHS thunk !!!
this.first.gen(vmcode); // LHS value
vmcode.emit_binop("??", this);
this.first.gen_lhs(vmcode); // store in LHS
}
}
});
p.add_symbol_class("??=", p.NullishAssign);
////////////////
// "Optional chaining" `?.` operator
p.NullishDot = Class.new({
name: "NullishDot",
supers: [p.Dot]
});
p.NullishDot.lvalue = false;
p.add_symbol_class("?.", p.NullishDot);
_classes.Object.__binops["?."] = function (l, r) {
"""
like `l.r`, but guards against nullish values
and returns `undefined`.
"""
return(l.is_nullish ? undefined : l.getprop(r));
};
}; // __extend_parser