diff --git a/lang/bytecode.c b/lang/bytecode.c index b3b2d15..9b74196 100644 --- a/lang/bytecode.c +++ b/lang/bytecode.c @@ -28,9 +28,11 @@ OP_JUMP_FALSE = 0x0C, OP_JUMP_ALWAYS = 0x0D, OP_TAIL_CALL = 0x0E, + OP_GET_ARG = 0x0F, }; -void bytecode_run(VmState state, Object obj, const unsigned char *bytecode) { +void bytecode_run(VmState state, Object obj, const unsigned char *bytecode, + struct object_list *args) { const unsigned char *pos_code = &bytecode[0]; unsigned char op = OP_END; while ((op = *pos_code++) != OP_END) { @@ -163,6 +165,17 @@ debug_msg("OP_RET\n"); return; } + // OP_GET_ARG pushes an argument on the stack + case OP_GET_ARG: { + debug_msg("OP_GET_ARG %i\n", *pos_code); + int index = *pos_code++; + vm_abort_if(state, args->length <= index, + "argument out of range"); + Object obj = args->elems[index]; + object_hold(state, obj); + vm_stack_push(state, obj); + break; + } // Unknown op, error out default: { debug_msg("Unknown OP 0x%02x\n", op); diff --git a/lang/bytecode.h b/lang/bytecode.h index f921472..4ea1b60 100644 --- a/lang/bytecode.h +++ b/lang/bytecode.h @@ -4,9 +4,13 @@ #ifndef BYTECODE_H #define BYTECODE_H +#include "object.h" #include "types.h" // Runs bytecode -void bytecode_run(VmState state, Object obj, const unsigned char *bytecode); +// obj is used for OP_SELF +// args is used for OP_GET_ARG +void bytecode_run(VmState state, Object obj, const unsigned char *bytecode, + struct object_list *args); #endif diff --git a/lang/compile.py b/lang/compile.py index b1c21ec..f48f7eb 100755 --- a/lang/compile.py +++ b/lang/compile.py @@ -380,6 +380,14 @@ def __repr__(self): return 'IRLoad(variable=%s, pos=%i)' % (self.variable, self.pos) +class IRLoadArg(): + def __init__(self, arg, index): + self.arg = arg + self.index = index + + def __repr__(self): + return 'IRLoadArg(arg=%s, index=%i)' % (self.arg, self.index) + class IRStore(): def __init__(self, variable, pos, create): self.variable = variable @@ -610,8 +618,22 @@ # Register allocation here is very simple: Each variable gets one stack slot # No further analysis is done to optimize use of the stack -def find_variables(ir): +def find_module_args(ast): + metadata = None + for node in ast: + if isinstance(node, ASTMetadata): + metadata = node + if metadata is None: + print("Unable to find AST metadata") + return None + # Ordered list of arguments: First ones are module uses + args = metadata.uses + return args + +def find_variables(module_args, ir): vars = {'Return': 0} + for index, arg in enumerate(module_args): + vars[arg] = -1 - index var_count = 0 for arg in ir.args: var_count += 1 @@ -619,6 +641,9 @@ for node in ir.statements: if isinstance(node, IRStore): var = node.variable + if var in module_args: + print("Setting module arg: %s" % (var)) + return None if var not in vars and node.create: var_count += 1 vars[var] = var_count @@ -641,7 +666,10 @@ for node in ir.statements: if isinstance(node, IRLoad): reg = variables[node.variable] - new_ir.append(IRLoad(node.variable, reg)) + if reg < 0: + new_ir.append(IRLoadArg(node.variable, -reg - 1)) + else: + new_ir.append(IRLoad(node.variable, reg)) elif isinstance(node, IRStore): reg = variables[node.variable] new_ir.append(IRStore(node.variable, reg, node.create)) @@ -659,8 +687,8 @@ new_ir.append(node) return new_ir -def registers_allocate_func(ir): - registers = find_variables(ir) +def registers_allocate_func(module_args, ir): + registers = find_variables(module_args, ir) if registers is None: return None new_ir = replace_variables(ir, registers) @@ -668,12 +696,12 @@ args = ir.args return IRFunction(name, args, new_ir) -def registers_allocate(ir): +def registers_allocate(module_args, ir): new_ir = [] for node in ir: sub_ir = None if isinstance(node, IRFunction): - sub_ir = registers_allocate_func(node) + sub_ir = registers_allocate_func(module_args, node) else: sub_ir = node new_ir.append(sub_ir) @@ -721,6 +749,10 @@ index = int(node.pos) bytes += b"\x06" # OP_GET bytes += index.to_bytes(1) + elif isinstance(node, IRLoadArg): + index = int(node.index) + bytes += b"\x0F" # OP_GET_ARG + bytes += index.to_bytes(1) elif isinstance(node, IRStore): index = int(node.pos) bytes += b"\x07" # OP_SET @@ -799,22 +831,46 @@ ] for i in includes: header += "#include %s\n" % i - header += """ -static struct object_class module_class; + header += "static struct object_class module_class;\n\n" + return header +def generate_module_args(module_args): + return """ +static struct object_list *create_args(VmState state, struct object_list *use_modules) { + (void)state; (void)use_modules; + int args_count = %i; + struct object_list *list = object_list_create(args_count); + vm_abort_if(state, use_modules->length < args_count, "create_args: Not enough use_modules"); + for(int i = 0; i < args_count; ++i) + list->elems[i] = use_modules->elems[i]; + return list; +} + +static void free_args(VmState state, struct object_list **args) { + for(int i = 0; i < (*args)->length; ++i) + object_drop(state, &(*args)->elems[i]); + object_list_free(args); +} +""" % (len(module_args)) + +def generate_callbacks(): + return """ static Object module_create(VmState state, struct object_list *use_modules) { - for(int i = 0; i < use_modules->length; ++i) - object_drop(state, &use_modules->elems[i]); - Object obj = object_create(state, &module_class, 1); + Object obj = object_create(state, &module_class, sizeof(struct object_list *)); + struct object_list **args = (struct object_list **)object_priv(state, obj, &module_class); + *args = create_args(state, use_modules); return obj; } -static void module_cleanup(VmState state, Object obj) { (void)state; (void)obj; } +static void module_cleanup(VmState state, Object obj) { + struct object_list **args = (struct object_list **)object_priv(state, obj, &module_class); + free_args(state, args); +} static void module_call(VmState state, Object obj, void *priv) { - bytecode_run(state, obj, (const unsigned char *)priv); + struct object_list **args = (struct object_list **)object_priv(state, obj, &module_class); + bytecode_run(state, obj, (const unsigned char *)priv, *args); }\n\n""" - return header def generate_footer(verbs): footer = """static struct object_call calls[] = {\n""" @@ -857,8 +913,10 @@ output += "};\n\n" return output -def generate_c_file(ir, source): +def generate_c_file(module_args, ir, source): output = generate_header(ir, source) + output += generate_module_args(module_args) + output += generate_callbacks() verbs = [] for node in ir: next = None @@ -889,15 +947,19 @@ if ast is None: print("Failed to parse file") return None + module_args = find_module_args(ast) + if module_args is None: + print("Failed to find module arguments") + return None ir = generate_ir(ast) if ir is None: print("Failed to generate IR") return None - ir_reg = registers_allocate(ir) + ir_reg = registers_allocate(module_args, ir) if ir_reg is None: print("Failed to allocate registers") return None - c_code = generate_c_file(ir_reg, code) + c_code = generate_c_file(module_args, ir_reg, code) if c_code is None: print("Failed to generate C file") return None diff --git a/lang/modules/another.txt b/lang/modules/another.txt index ef12f47..e69c3e7 100644 --- a/lang/modules/another.txt +++ b/lang/modules/another.txt @@ -1,5 +1,7 @@ Module Another +Use B -Function DoAnotherThing - Return 42 +Function GetHalfish Args Num + Set FinalNum To Num Subtract 2 + Return FinalNum EndFunction diff --git a/lang/modules/main.txt b/lang/modules/main.txt index 031c7fa..a07a3cf 100644 --- a/lang/modules/main.txt +++ b/lang/modules/main.txt @@ -1,6 +1,5 @@ Module Main Use Another -Use B Function BoolTest Set A To True @@ -48,13 +47,8 @@ Jump Self CountDown 10000 EndFunction -Function GetHalfish Args Num - Set FinalNum To Num Subtract 2 - Return FinalNum -EndFunction - Function MakeNumber - Set Halfish To Self GetHalfish 620 + Set Halfish To Another GetHalfish 620 Set Double To Halfish Add Halfish Set Final To Double Subtract 2 Return Final