Added native function support
This commit is contained in:
110
src/c0ffi.js
Normal file
110
src/c0ffi.js
Normal file
@@ -0,0 +1,110 @@
|
||||
exports.NATIVE_FADD = 0
|
||||
exports.NATIVE_FDIV = 1
|
||||
exports.NATIVE_FLESS = 2
|
||||
exports.NATIVE_FMUL = 3
|
||||
exports.NATIVE_FSUB = 4
|
||||
exports.NATIVE_FTOI = 5
|
||||
exports.NATIVE_ITOF = 6
|
||||
exports.NATIVE_PRINT_FPT = 7
|
||||
exports.NATIVE_PRINT_HEX = 8
|
||||
exports.NATIVE_PRINT_INT = 9
|
||||
|
||||
/* args */
|
||||
exports.NATIVE_ARGS_FLAG = 10
|
||||
exports.NATIVE_ARGS_INT = 11
|
||||
exports.NATIVE_ARGS_PARSE = 12
|
||||
exports.NATIVE_ARGS_STRING = 13
|
||||
|
||||
/* conio */
|
||||
exports.NATIVE_EOF = 14
|
||||
exports.NATIVE_FLUSH = 15
|
||||
exports.NATIVE_PRINT = 16
|
||||
exports.NATIVE_PRINTBOOL = 17
|
||||
exports.NATIVE_PRINTCHAR = 18
|
||||
exports.NATIVE_PRINTINT = 19
|
||||
exports.NATIVE_PRINTLN = 20
|
||||
exports.NATIVE_READLINE = 21
|
||||
|
||||
/* curses */
|
||||
exports.NATIVE_C_ADDCH = 22
|
||||
exports.NATIVE_C_CBREAK = 23
|
||||
exports.NATIVE_C_CURS_SET = 24
|
||||
exports.NATIVE_C_DELCH = 25
|
||||
exports.NATIVE_C_ENDWIN = 26
|
||||
exports.NATIVE_C_ERASE = 27
|
||||
exports.NATIVE_C_GETCH = 28
|
||||
exports.NATIVE_C_INITSCR = 29
|
||||
exports.NATIVE_C_KEYPAD = 30
|
||||
exports.NATIVE_C_MOVE = 31
|
||||
exports.NATIVE_C_NOECHO = 32
|
||||
exports.NATIVE_C_REFRESH = 33
|
||||
exports.NATIVE_C_SUBWIN = 34
|
||||
exports.NATIVE_C_WADDCH = 35
|
||||
exports.NATIVE_C_WADDSTR = 36
|
||||
exports.NATIVE_C_WCLEAR = 37
|
||||
exports.NATIVE_C_WERASE = 38
|
||||
exports.NATIVE_C_WMOVE = 39
|
||||
exports.NATIVE_C_WREFRESH = 40
|
||||
exports.NATIVE_C_WSTANDEND = 41
|
||||
exports.NATIVE_C_WSTANDOUT = 42
|
||||
exports.NATIVE_CC_GETBEGX = 43
|
||||
exports.NATIVE_CC_GETBEGY = 44
|
||||
exports.NATIVE_CC_GETMAXX = 45
|
||||
exports.NATIVE_CC_GETMAXY = 46
|
||||
exports.NATIVE_CC_GETX = 47
|
||||
exports.NATIVE_CC_GETY = 48
|
||||
exports.NATIVE_CC_HIGHLIGHT = 49
|
||||
exports.NATIVE_CC_KEY_IS_BACKSPACE = 50
|
||||
exports.NATIVE_CC_KEY_IS_DOWN = 51
|
||||
exports.NATIVE_CC_KEY_IS_ENTER = 52
|
||||
exports.NATIVE_CC_KEY_IS_LEFT = 53
|
||||
exports.NATIVE_CC_KEY_IS_RIGHT = 54
|
||||
exports.NATIVE_CC_KEY_IS_UP = 55
|
||||
exports.NATIVE_CC_WBOLDOFF = 56
|
||||
exports.NATIVE_CC_WBOLDON = 57
|
||||
exports.NATIVE_CC_WDIMOFF = 58
|
||||
exports.NATIVE_CC_WDIMON = 59
|
||||
exports.NATIVE_CC_WREVERSEOFF = 60
|
||||
exports.NATIVE_CC_WREVERSEON = 61
|
||||
exports.NATIVE_CC_WUNDEROFF = 62
|
||||
exports.NATIVE_CC_WUNDERON = 63
|
||||
|
||||
/* file */
|
||||
exports.NATIVE_FILE_CLOSE = 64
|
||||
exports.NATIVE_FILE_CLOSED = 65
|
||||
exports.NATIVE_FILE_EOF = 66
|
||||
exports.NATIVE_FILE_READ = 67
|
||||
exports.NATIVE_FILE_READLINE = 68
|
||||
|
||||
/* img */
|
||||
exports.NATIVE_IMAGE_CLONE = 69
|
||||
exports.NATIVE_IMAGE_CREATE = 70
|
||||
exports.NATIVE_IMAGE_DATA = 71
|
||||
exports.NATIVE_IMAGE_DESTROY = 72
|
||||
exports.NATIVE_IMAGE_HEIGHT = 73
|
||||
exports.NATIVE_IMAGE_LOAD = 74
|
||||
exports.NATIVE_IMAGE_SAVE = 75
|
||||
exports.NATIVE_IMAGE_SUBIMAGE = 76
|
||||
exports.NATIVE_IMAGE_WIDTH = 77
|
||||
|
||||
/* parse */
|
||||
exports.NATIVE_PARSE_BOOL = 78
|
||||
exports.NATIVE_PARSE_INT = 79
|
||||
|
||||
/* string */
|
||||
exports.NATIVE_CHAR_CHR = 80
|
||||
exports.NATIVE_CHAR_ORD = 81
|
||||
exports.NATIVE_STRING_CHARAT = 82
|
||||
exports.NATIVE_STRING_COMPARE = 83
|
||||
exports.NATIVE_STRING_EQUAL = 84
|
||||
exports.NATIVE_STRING_FROM_CHARARRAY = 85
|
||||
exports.NATIVE_STRING_FROMBOOL = 86
|
||||
exports.NATIVE_STRING_FROMCHAR = 87
|
||||
exports.NATIVE_STRING_FROMINT = 88
|
||||
exports.NATIVE_STRING_JOIN = 89
|
||||
exports.NATIVE_STRING_LENGTH = 90
|
||||
exports.NATIVE_STRING_SUB = 91
|
||||
exports.NATIVE_STRING_TERMINATED = 92
|
||||
exports.NATIVE_STRING_TO_CHARARRAY = 93
|
||||
exports.NATIVE_STRING_TOLOWER = 94
|
||||
|
||||
60
src/c0vm.js
60
src/c0vm.js
@@ -9,7 +9,11 @@ function log(message) {
|
||||
}
|
||||
|
||||
function c0_assertion_failure(val) {
|
||||
throw "c0 assertion failure: " + val;
|
||||
throw ("c0 assertion failure: " + val);
|
||||
}
|
||||
|
||||
function c0_memory_error(val) {
|
||||
throw ("c0 memory error: " + val);
|
||||
}
|
||||
|
||||
var StackFrame = function(file, f) {
|
||||
@@ -23,7 +27,7 @@ var StackFrame = function(file, f) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
var ProgramState = function(parsed_file) {
|
||||
var ProgramState = function(parsed_file, callback_dict) {
|
||||
log("Creating program state with file " + parsed_file);
|
||||
var main_function = parsed_file.function_pool[0];
|
||||
|
||||
@@ -31,6 +35,19 @@ var ProgramState = function(parsed_file) {
|
||||
this.call_stack = [];
|
||||
this.file = parsed_file;
|
||||
|
||||
this.natives = {};
|
||||
|
||||
for (var i = 0; i < 95; i++) {
|
||||
try {
|
||||
this.natives[i] = callback_dict[i];
|
||||
} catch (key_not_found) {
|
||||
dict[i] = function (arg) {
|
||||
console.log("Native function " + name + " called, ran method stub.");
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Memory is just a big array of bytes, right?
|
||||
// "Allocation" is appending onto this array
|
||||
// A pointer to memory is an index into this array.
|
||||
@@ -108,7 +125,7 @@ ProgramState.prototype.step = function() {
|
||||
case op.RETURN:
|
||||
var retVal = this.pop();
|
||||
if (this.call_stack.length == 0)
|
||||
throw retVal;
|
||||
return retVal;
|
||||
|
||||
this.frame = this.call_stack.pop();
|
||||
this.push(retVal);
|
||||
@@ -183,7 +200,6 @@ ProgramState.prototype.step = function() {
|
||||
this.frame.pc++;
|
||||
var y = this.pop();
|
||||
var x = this.pop();
|
||||
console.log("y="+y+", x="+x);
|
||||
if (y < 0 || y > 31) c0_arith_error("Shifting by too many bits");
|
||||
this.push(x>>y);
|
||||
break;
|
||||
@@ -276,6 +292,30 @@ ProgramState.prototype.step = function() {
|
||||
this.frame = newFrame;
|
||||
break;
|
||||
|
||||
case op.INVOKENATIVE:
|
||||
var c1 = this.frame.program[this.frame.pc+1];
|
||||
var c2 = this.frame.program[this.frame.pc+2];
|
||||
this.frame.pc += 3;
|
||||
|
||||
var index = (c1 << 8) + c2;
|
||||
|
||||
var f = this.file.native_pool[index];
|
||||
var arg_array = [];
|
||||
for (var i = f.num_args - 1; i >= 0; i--)
|
||||
arg_array[i] = this.pop();
|
||||
|
||||
var native_function = this.natives[f.function_table_index];
|
||||
if (native_function === undefined) {
|
||||
native_function = function (ignored) {
|
||||
console.log("Could not find native function with index " +
|
||||
f.function_table_index);
|
||||
return 0;
|
||||
};
|
||||
console.log("Unknown native function index " + f.function_table_index);
|
||||
}
|
||||
this.push(native_function(arg_array));
|
||||
break;
|
||||
|
||||
// Memory allocation operations:
|
||||
|
||||
case op.NEW:
|
||||
@@ -354,7 +394,6 @@ ProgramState.prototype.step = function() {
|
||||
" (" + opcode_name + ")\n");
|
||||
throw "Error - unknown opcode";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Takes in a parsed .bc0 file and runs it
|
||||
@@ -362,18 +401,13 @@ function execute(file, callbacks, v) {
|
||||
verbose = typeof v !== 'undefined' ? v : true;
|
||||
log("Initializing with file " + file);
|
||||
|
||||
var state = new ProgramState(file);
|
||||
var state = new ProgramState(file, callbacks);
|
||||
|
||||
log("Beginning execution");
|
||||
|
||||
while (true) {
|
||||
// I'm not sure how to structure this control flow yet,
|
||||
// so if anyone has a better idea, let me know
|
||||
try {
|
||||
state.step();
|
||||
} catch (val) {
|
||||
return val;
|
||||
}
|
||||
var val = state.step();
|
||||
if (val !== undefined) return val;
|
||||
|
||||
// if (at_breakpoint) {
|
||||
// save state (maybe in a global in this file?)
|
||||
|
||||
14
src/index.js
14
src/index.js
@@ -1,5 +1,6 @@
|
||||
parser = require("./bytecode-parser");
|
||||
c0vm = require("./c0vm.js");
|
||||
c0ffi = require("./c0ffi.js");
|
||||
|
||||
// console.log("Reading in sample bytecode file:");
|
||||
// console.log(parser.getBytes("../test/test.bc0"));
|
||||
@@ -9,5 +10,14 @@ c0vm = require("./c0vm.js");
|
||||
// console.log(file);
|
||||
// console.log(file.function_pool[0].code);
|
||||
|
||||
var file = parser.parse("../test/iadd.c0.bc0");
|
||||
console.log("Result is " + c0vm.execute(file));
|
||||
callbacks = {};
|
||||
callbacks[c0ffi.NATIVE_PRINT] = function(args) {
|
||||
console.log("Print function says: " + args[0]);
|
||||
}
|
||||
callbacks["printint"] = function(args) {
|
||||
console.log("Printint function says: " + args[0]);
|
||||
}
|
||||
|
||||
var file = parser.parse("../test/sample2.5.c0.bc0");
|
||||
console.log("Result is " + c0vm.execute(file, callbacks));
|
||||
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
parser = require("../src/bytecode-parser.js")
|
||||
c0vm = require("../src/c0vm.js")
|
||||
parser = require("../src/bytecode-parser.js");
|
||||
c0vm = require("../src/c0vm.js");
|
||||
c0ffi = require("../src/c0ffi.js");
|
||||
|
||||
var callbacks = {}
|
||||
var printout = "";
|
||||
|
||||
callbacks[c0ffi.NATIVE_PRINT] = function(args) {
|
||||
printout += args[0];
|
||||
}
|
||||
|
||||
callbacks[c0ffi.NATIVE_PRINTINT] = function(args) {
|
||||
printout += args[0];
|
||||
}
|
||||
|
||||
callbacks[c0ffi.NATIVE_PRINTLN] = function(args) {
|
||||
printout += (args[0] + "\n");
|
||||
}
|
||||
|
||||
function doTest(filename, expected_result) {
|
||||
return function(test) {
|
||||
@@ -16,8 +30,10 @@ function doTest(filename, expected_result) {
|
||||
exports.testIADD = doTest("iadd.c0.bc0", -2);
|
||||
|
||||
exports.testPrint = function(test) {
|
||||
printout = "";
|
||||
var result = c0vm.execute(parser.parse("test.bc0"), callbacks, false);
|
||||
test.ok(result == 0, "test.bc0 - Did not print to screen correctly");
|
||||
test.ok(printout == "Hello, world.\nYou don't look so good.\n",
|
||||
"test.bc0 - Did not print to screen correctly: output was " + printout);
|
||||
test.done();
|
||||
}
|
||||
|
||||
@@ -29,7 +45,9 @@ exports.testMID = doTest("mid.c0.bc0", 155);
|
||||
|
||||
// This one should throw an exception because an assertion fails
|
||||
exports.testSample25 = function(test) {
|
||||
test.throws(c0vm.execute(parser.parse("sample2.5.c0.bc0"), callbacks, false));
|
||||
test.throws(function () {
|
||||
c0vm.execute(parser.parse("sample2.5.c0.bc0"), callbacks, false)
|
||||
});
|
||||
test.done();
|
||||
}
|
||||
|
||||
@@ -38,13 +56,18 @@ exports.testIF = doTest("testif.c0.bc0", 32);
|
||||
exports.testDSQUARED = doTest("dsquared.c0.bc0", 17068);
|
||||
|
||||
exports.testArrays = function(test) {
|
||||
var result = c0vm.execute(parser.parse("arrays.c0.bc0"), callbacks, false);
|
||||
test.ok(false, "test.bc0 - Did not print to screen correctly");
|
||||
test.throws(function () {
|
||||
c0vm.execute(parser.parse("arrays.c0.bc0"), callbacks, true)
|
||||
});
|
||||
test.done();
|
||||
}
|
||||
|
||||
exports.testStructs = function(test) {
|
||||
printout = "";
|
||||
var result = c0vm.execute(parser.parse("structs.c0.bc0"), callbacks, false);
|
||||
test.ok(false, "test.bc0 - Did not print to screen correctly");
|
||||
test.ok(printout == "expected result here",
|
||||
"structs.c0.bc0 - Did not print to screen correctly, result was " +
|
||||
printout);
|
||||
test.done();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user