-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwrite-php-ops.js
111 lines (103 loc) · 3.91 KB
/
write-php-ops.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
// Utility to write out the opcode mapping from `bytecode-table.js`
// as a PHP file.
//
// Run it under `node` with the CLI in `bin/write-php-ops.js`
define(['./bytecode-table'], function(bytecode_table) {
var bops = [];
while(true) {
var bc = bytecode_table.for_num(bops.length);
if (!bc) { break; }
bops.push(bc);
}
var comma = function(i) { return (i < (bops.length-1)) ? ',' : ''; };
var phpName = function(bc) {
var name = bc.name.toUpperCase();
if (name==='2DUP') { return 'DUP2'; }
return name;
};
console.log('<?php');
console.log('// generated by TurtleScript write-php-ops.js');
console.log('');
console.log('namespace Wikimedia\\PhpTurtle;');
console.log('');
console.log('class Op {');
// ## Emit `Op` enumeration.
bops.forEach(function(bc, i) {
console.log('\tpublic const ' + phpName(bc) + ' = ' + i + ';');
});
console.log('');
var buildSwitch = function(fn) {
console.log('\t\tswitch ( $op ) {');
var group = [];
bops.forEach(function(bc) {
var val = fn(bc);
if (typeof val === 'function') {
console.log('\t\tcase self::' + phpName(bc) + ':');
console.log('\t\t\treturn ' + val() + ';');
} else {
if (group[val]===undefined) { group[val] = []; }
group[val].push(bc);
}
});
var i = 1;
while (i < group.length) {
if (group[i] !== undefined && group[i].length > 0) {
group[i].forEach(function(bc) {
console.log('\t\tcase self::' + phpName(bc) + ':');
});
console.log('\t\t\treturn ' + i + ';');
}
i+=1;
}
if (group[0] !== undefined && group[0].length > 0) {
console.log('\t\tdefault:');
console.log('\t\t\treturn 0;');
}
console.log('\t\t}');
};
// ## Emit `Op` functions.
console.log('\t/**');
console.log('\t * Return the number of arguments used for the given opcode.');
console.log('\t * @param int $op The opcode');
console.log('\t * @return int The number of arguments required');
console.log('\t */');
console.log('\tpublic static function args( int $op ): int {');
buildSwitch(function(bc) { return bc.args; });
console.log('\t}');
console.log('');
console.log('\t/**');
console.log('\t * Return the number of stack slots pushed by the given opcode.');
console.log('\t * @param int $op The opcode');
console.log('\t * @return int The number of stack slots pushed');
console.log('\t */');
console.log('\tpublic static function stackpush( int $op ): int {');
buildSwitch(function(bc) { return bc.stackpush(); });
console.log('\t}');
console.log('');
console.log('\t/**');
console.log('\t * Return the number of stack slots popped by the given opcode.');
console.log('\t * @param int $op The opcode');
console.log('\t * @param array $args The arguments to that opcode');
console.log('\t * @return int The number of stack slots popped');
console.log('\t */');
console.log('\tpublic static function stackpop( int $op, array $args ): int {');
buildSwitch(function(bc) {
if (bc.name === 'invoke') {
return (function() { return '$args[0] + 2'; });
}
return bc.stackpop();
});
console.log('\t}');
console.log('');
console.log('\t/**');
console.log('\t * Return the human-readable name for the given opcode.');
console.log('\t * @param int $op The opcode');
console.log('\t * @return string The name of the opcode');
console.log('\t */');
console.log('\tpublic static function name( int $op ): string {');
buildSwitch(function(bc) { return (function() {
return '"' + bc.name + '"';
}); });
console.log('\t}');
console.log('}');
});