diff --git a/lua-temp/doc/BYTECODE b/lua-temp/doc/BYTECODE new file mode 100644 index 0000000..d0d6571 --- /dev/null +++ b/lua-temp/doc/BYTECODE @@ -0,0 +1,35 @@ +Bytecode format +--------------- + +The bytecode file is composed of the following sections: + + * HEADER: 16-byte header + [0:3]: Magic + [4]: VM format + [rest]: Reserved for future use + * TABLE_OF_CONTENTS: list of 8 records pointing to each one of the sections + Each record (6 bytes): + - Pointer to section: 4 bytes + - Number of records in section: 2 bytes + * [0x0] Constants indexes: pointers to each of the constant locations + * Table of 4-byte constant indexes with pointer to constant + (counter start at beginning of raw constants) + * [0x1] Functions indexes: Pointer to functions within the code + [0:3]: function pointer (counter start at the beginning of executable code) + [4:5]: number of parameters + [6:7]: number of local variables + [8:b]: function size + * [0x2] Constants raw data + * [0x3] Code: executable code + * [0x4] Debugging info + ??? + +The max file size is 2 Gb. + +## Values can be encoded in the following ways: + * The type is defined by the operator. + * Encoding varies according to the type: + int: use protobuf format + float: 4-bit floating point + string: int-defined length, followed by the string proper - no null terminator + * Constant indexes and function ids are encoded as ints diff --git a/lua-temp/doc/OPCODES b/lua-temp/doc/OPCODES new file mode 100644 index 0000000..764758b --- /dev/null +++ b/lua-temp/doc/OPCODES @@ -0,0 +1,93 @@ +Operations +---------- + +Operations take either 0 or 1 parameter. The ones that take a parameter, it can be either a int8, int16 or int32. + +Instructions follow this logic: + +00 ~ 9F : no parameter +A0 ~ BF : int8 (1 byte) +C0 ~ DF : int16 (2 bytes) +E0 ~ FF : int32 (4 bytes) + +The operations of 1, 2 and 4 bytes are always interchangeable by adding/subtracting 0x20. + + ,----------- no parameter + | ,-------- int8 + | | ,----- int16 + | | | ,-- int32 +NP I8 I16 I32 Opc Instruction Description + +Stack operations: + a0 c0 e0 pushi [int] Push int + a1 c1 e1 pushc [index] Push constant + a2 c2 e2 pushf [function] Push function id +00 pushz Push zero (or false) +01 pusht Push true +02 newa Push (create) empty array +03 newt Push (create) empty table +04 pop +05 dup + +Local variables: + a3 c3 e3 pushv [int] Push n nil values into the stack (used to init local vars) + ab cb eb set [index] Set value in stack position (set local variable) + a4 c4 e4 dupv [index] Duplicate stack value (load local variable) + a5 c5 e5 setg [int] Set global variable + a6 c6 e6 getg [int] Get global variable + +Function operations: + a7 c7 e7 call [n_pars] Enter function on stack toplevel (passing n next stack values as parameters) +10 ret Leave a function (return value in stack) +11 retn Leave a function (return nil) + +Table and array operations: +16 getkv Get table's value based on key (pull 1 value, push 1 value) +17 setkv Set table's key and value (pull 2 values from stack) +18 geta Get array's position value +19 seta Set array's position value (pull 2 values from stack) +1a appnd Add value to the end of array +1b next Push the next pair into the stack (for loops) +1c smt Set value metatable +1d mt Get value metatable + +Logical/arithmetic: +20 sum Sum top 2 values in stack +21 sub Subtract top 2 values in stack +22 mul Multiply top 2 values in stack +23 div Float division +24 idiv Integer division +25 eq Equality +26 neq Inequality +27 lt Less than +28 lte Less than or equals +29 gt Greater than +2a gte Greater than or equals +2b and Bitwise AND +2c or Bitwise OR +2d xor Bitwise XOR +2e pow Power +2f shl Shift left +30 shr Shift right +31 mod Modulo + +Other value operations: +40 len Get table, array or string size +41 type Get type from value at the top of the stack + b0 cast [type] Cast type to another type +42 ver Return VM version + +External code: +48 cmpl Compile code to assembly +49 asmbl Assemble code to bytecode format +4a load Load bytecode as function (will place function on stack) + +Control flow: + a8 c8 e8 bz [pc] Branch if zero + a9 c9 e9 bnz [pc] Branch if not zero + aa ca ea jmp [pc] Unconditional jump +* Jumps can only happen within the same function. + + +Error handling: (0xa0~0xaf) + ??? diff --git a/lua-temp/doc/VM b/lua-temp/doc/VM new file mode 100644 index 0000000..733bbdd --- /dev/null +++ b/lua-temp/doc/VM @@ -0,0 +1,15 @@ +Internal handling of values +--------------------------- + +## Supported types + Nil 0 + Integer 1 + Float 2 + String 3 + Array 4 + Table 5 + Function 6 + NativePointer 7 + +## Internal format + ??? \ No newline at end of file diff --git a/lua-temp/tests.lua b/lua-temp/tests.lua new file mode 100644 index 0000000..b56215d --- /dev/null +++ b/lua-temp/tests.lua @@ -0,0 +1,74 @@ +local assemble = require('tyche-as') + +function tprint(o, indent) + indent = indent or 0 + local spacing = string.rep(" ", indent) + + if type(o) == 'table' then + local s = '{\n' + for k, v in pairs(o) do + -- Format keys: quote strings, leave numbers as is + local key = type(k) == 'string' and '["'..k..'"]' or '['..k..']' + s = s .. spacing .. " " .. key .. " = " .. tprint(v, indent + 1) .. ",\n" + end + return s .. spacing .. '}' + elseif type(o) == 'string' then + return '"' .. o .. '"' + else + return tostring(o) + end +end + +function assert_eq(found, expected, key) + assert(type(found) == type(expected), "Types not matching " .. ((key ~= nil) and ('(key: ' .. key .. ')') or '')) + if type(found) == 'table' then + assert(#found == #expected, "Tables are of different sizes " .. ((key ~= nil) and ('(key: ' .. key .. ')') or '')) + for k,v in pairs(found) do + assert_eq(v, expected[k], k) + end + for k,v in pairs(expected) do + assert_eq(v, found[k], k) + end + else + assert(found == expected, 'Assertion failed, expected "' .. tprint(expected) .. '", found "' .. tprint(found) .. '".') + end +end + +do + local source = [[ +.const + 0: 3.14 + 1: "Hello world" + +.func 0 + pushi 2 ; this is a comment + pushi 3 + sum + ret +.func 1 + pushi 5000 + ret ]] + + local expected = { + constants = { [0] = 3.14, [1] = "Hello world" }, + functions = { + [0] = { + { "pushi", 2 }, + { "pushi", 3 }, + { "sum" }, + { "ret" }, + }, + [1] = { + { "pushi", 5000 }, + { "ret" }, + } + } + } + + local found = assemble(source) + -- tprint(expected) + tprint(found) + assert_eq(found, expected) +end + +print('End.') \ No newline at end of file diff --git a/lua-temp/tyche-as.lua b/lua-temp/tyche-as.lua new file mode 100644 index 0000000..29d78e6 --- /dev/null +++ b/lua-temp/tyche-as.lua @@ -0,0 +1,62 @@ +---------------------- +-- -- +-- PARSER -- +-- -- +---------------------- + +local function assemble(source) + local proto = { + constants = {}, + functions = {}, + } + + local section = '' + local current_f_id = 0 + + for line in source:gmatch("([^\n]+)") do + local line = line:gsub("%s*;.*$", "") -- remove comments + line = line:match("^%s*(.-)%s*$") -- trim + + if #line == 1 then goto continue end + + if line == ".const" then + section = 'const' + elseif line:match("%.func%s+%d+") then + section = 'function' + local f_id = tonumber(line:match("%.func%s+(%d+)")) + proto.functions[f_id] = {} + current_f_id = f_id + elseif section == 'const' then + local k, v = line:match("^%s*(%d+)%s*:%s*(.+)$") + if v:sub(1, 1) == '"' then + proto.constants[tonumber(k)] = line:match('"(.*)"') + else + proto.constants[tonumber(k)] = tonumber(v) + end + elseif section == 'function' then + local inst, par = line:match("^%s*(%a+)%s+(%d+)%s*$") + if inst then + table.insert(proto.functions[current_f_id], { inst, tonumber(par) }) + else + local inst = line:match("^%s*(%a+)%s*$") + table.insert(proto.functions[current_f_id], { inst }) + end + end + + ::continue:: + end + + return proto +end + +---------------------- +-- -- +-- MAIN -- +-- -- +---------------------- + +if ... then + return assemble +else + error("Running assembler directly not supported yet") +end \ No newline at end of file diff --git a/lua-temp/tyche-vm.lua b/lua-temp/tyche-vm.lua new file mode 100644 index 0000000..e69de29