-
Notifications
You must be signed in to change notification settings - Fork 0
/
bytecode.js
147 lines (147 loc) · 5.44 KB
/
bytecode.js
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
"use strict";
var ConstantPrimitive = /** @class */ (function () {
function ConstantPrimitive(v, type, constID) {
this.v = v;
this.type = type;
this.constRef = (type === 'int'
? NativeOp.CONST_INT.opcode
: type === 'double'
? NativeOp.CONST_DOUBLE.opcode
: NativeOp.CONST_STRING.opcode) + constID;
}
return ConstantPrimitive;
}());
var ByteCode = /** @class */ (function () {
function ByteCode(q, constants, constID) {
this.constRef = NativeOp.CONST_QUOTE.opcode + constID;
var sb = [];
for (var i = 0; i < q.ops.length; ++i) {
sb.push(q.ops[i].compile(constants));
}
this.compiled = sb.join('');
}
return ByteCode;
}());
var CodeObject = /** @class */ (function () {
function CodeObject(q) {
this.nextBCID = 0;
this.names = [];
this.primitives = [];
this.byteCodes = [];
this.addQuote(q);
}
CodeObject.prototype.addQuote = function (q) {
var bcID = this.nextBCID++;
var bc = new ByteCode(q, this, bcID);
this.byteCodes[bcID] = bc;
return bc.constRef;
};
CodeObject.prototype.addPrimitive = function (v, typeTag) {
for (var i = 0; i < this.primitives.length; ++i) {
var p_1 = this.primitives[i];
if (p_1.type === typeTag && p_1.v === v) {
return p_1.constRef;
}
}
var p = new ConstantPrimitive(v, typeTag, this.primitives.length);
this.primitives.push(p);
return p.constRef;
};
CodeObject.prototype.addName = function (name) {
var i = this.names.indexOf(name);
if (i === -1) {
i = this.names.length;
this.names.push(name);
}
return i;
};
CodeObject.prototype.toJSON = function () {
return {
bytecode: this.byteCodes.map(function (bc) { return bc.compiled; }),
constants: this.primitives.map(function (p) { return p.v; }),
names: this.names
};
};
return CodeObject;
}());
function extractID(index, bc, startPos) {
var pos = startPos;
while (/[0-9]/.test(bc[pos]) && ++pos < bc.length)
;
if (startPos === pos) {
throw new Error('Bytecode error: expected numerical index at index ' + index + ', position ' + pos);
}
return bc.substring(startPos, pos);
}
function decompile(jsonCodeObject, index) {
if (index === void 0) { index = 0; }
var bc = jsonCodeObject.bytecode[index];
var q = new Quote();
var pos = 0;
while (pos < bc.length) {
var c = bc[pos++];
var op = NativeOp.getByOpCode(c);
if (op === null) {
throw new Error('Bytecode error: illegal opcode `' + c + '` at index ' + index + ', position ' + (pos - 1));
}
else if (op.name === null) {
var constIDstr = extractID(index, bc, pos);
pos += constIDstr.length;
var constID = parseInt(constIDstr);
if (c === NativeOp.CONST_QUOTE.opcode) {
if (constID < index) {
throw new Error('Bytecode error: backward reference in bytecode array');
}
op = new PushOp(decompile(jsonCodeObject, constID));
}
else if (c === NativeOp.CONST_INT.opcode) {
var v = jsonCodeObject.constants[constID];
if (typeof v !== 'number' || v !== (v | 0)) {
throw new Error('Bytecode error: expected int constant at index ' + index + ', id ' + constID);
}
op = new PushOp(new IntValue(v));
}
else if (c === NativeOp.CONST_DOUBLE.opcode) {
var v = jsonCodeObject.constants[constID];
if (typeof v !== 'number') {
throw new Error('Bytecode error: expected double constant at index ' + index + ', id ' + constID);
}
op = new PushOp(new DoubleValue(v));
}
else if (c === NativeOp.CONST_STRING.opcode) {
var v = jsonCodeObject.constants[constID];
if (typeof v !== 'string') {
throw new Error('Bytecode error: expected string constant at index ' + index + ', id ' + constID);
}
op = new PushOp(new StringValue(v));
}
else if (c === NativeOp.DUP.opcode) {
if (constID === 0) {
throw new Error('Bytecode error: cannot DUP 0 at index ' + index);
}
op = new DupOp(constID);
}
else {
var name_1 = jsonCodeObject.names[constID];
switch (c) {
case NativeOp.STORE.opcode:
op = new AssignOp(name_1, false);
break;
case NativeOp.STORE_QUOTE.opcode:
op = new AssignOp(name_1, true);
break;
case NativeOp.LOAD_FAST.opcode:
op = new LocalReadOp(name_1);
break;
case NativeOp.LOAD_SLOW.opcode:
op = new ReadOp(name_1);
break;
default:
throw new Error('Bytecode error: illegal opcode `' + c + '`');
}
}
}
q.ops.push(op);
}
return q;
}