• Jump To … +
    asm-llvm.js bcompile.js binterp.js browsercanvas.js bytecode-table.js canvastest.js ccanvas.js crender-styles.js crender.js ctiles.js events.js eventtests.js extensions.js global-es5.js global.js html-escape.js jcompile.js json2.js nodemain.js parse.js render.js render2.js require.js stdlib.js str-escape.js tdop.js tests.js text.js tiles.js tokenize.js top-level.js ts.js write-lua-bytecode.js write-lua-ops.js write-php-bytecode.js write-php-ops.js write-rust-bytecode.js write-rust-ops.js
  • write-php-ops.js

  • ¶

    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('}');
    });