diff --git a/lang/bytecode.c b/lang/bytecode.c index ed415ef..761a583 100644 --- a/lang/bytecode.c +++ b/lang/bytecode.c @@ -19,7 +19,7 @@ OP_END = 0x00, OP_RATIO1 = 0x01, OP_RET = 0x03, - OP_UNUSED1 = 0x02, // Unused, use for next op + OP_CREATE = 0x02, OP_CALL = 0x04, OP_NONE = 0x05, OP_GET = 0x06, @@ -176,6 +176,17 @@ vm_stack_push(state, obj); break; } + // OP_CREATE creates a class from a module scope + // First argument is the number in the scope's classes + case OP_CREATE: { + debug_msg("OP_CREATE %i\n", *pos_code); + int index = *pos_code++; + // Create a new module refernce for the class + object_hold(state, module); + Object obj = module_class_create(state, module, index); + vm_stack_push(state, obj); + break; + } // Unknown op, error out default: { debug_msg("Unknown OP 0x%02x\n", op); diff --git a/lang/compile.py b/lang/compile.py index b53a0a3..3b18a16 100755 --- a/lang/compile.py +++ b/lang/compile.py @@ -51,6 +51,13 @@ def __repr__(self): return '\n\t\t\t\tASTCall(subject=%s, verb="%s", args=%s)' % (self.subject, self.verb, self.args) +class ASTCreate(): + def __init__(self, class_): + self.class_ = class_ + + def __repr__(self): + return '\n\t\t\t\tASTCreate(class=%s)' % (self.class_) + class ASTJump(): def __init__(self, call): self.call = call @@ -156,9 +163,6 @@ def parse_call(line, offset): cut = line[offset-1:] - if len(cut) < 1: - print("not a call? line: %s" % (' '.join(line))) - return None subject = parse_value(cut[0]) if subject is None: print("not a subject? line: %s" % (' '.join(line))) @@ -175,11 +179,28 @@ args.append(val) return ASTCall(subject, verb, args) +def parse_create(line, offset): + cut = line[offset-1:] + if len(cut) != 2: + print("not a create? line: %s" % (' '.join(line))) + return None + return ASTCreate(cut[1]) + +def parse_call_or_create(line, offset): + cut = line[offset-1:] + if len(cut) < 1: + print("not a call or create? line: %s" % (' '.join(line))) + return None + if cut[0] == "Create": + return parse_create(line, offset) + else: + return parse_call(line, offset) + def parse_set(line): if len(line) < 4 or line[0] != "Set" or line[2] != "To": print("not a set? line: %s" % (' '.join(line))) return None - call = parse_call(line, 4) + call = parse_call_or_create(line, 4) if call is None: return None return ASTSet(line[1], call) @@ -430,6 +451,14 @@ def __repr__(self): return 'IRTailCall(name="%s", args=%i)' % (self.name, self.args) +class IRCreate(): + def __init__(self, class_, index): + self.class_ = class_ + self.index = index + + def __repr__(self): + return 'IRCreate(class="%s", index=%i)' % (self.class_, self.index) + class IRReturn(): def __repr__(self): return 'IRReturn()' @@ -537,13 +566,22 @@ final_ir = final_ir + call_ir return final_ir +def generate_ir_create(ast): + return [IRCreate(ast.class_, -1)] + +def generate_ir_call_or_create(ast): + if isinstance(ast, ASTCall): + return generate_ir_call(ast, False) + else: + return generate_ir_create(ast) + def generate_ir_jump(ast): # juggle args to arg count then cleanup stack return generate_ir_call(ast.call, True) def generate_ir_set(ast, create): command = ast.command - sub_ir = generate_ir_call(command, False) + sub_ir = generate_ir_call_or_create(command) if sub_ir is None: print("Unknown set ast node: %s" % (node)) return None @@ -731,6 +769,53 @@ ir.append(metadata) return ir +def update_creates_ir(metadata, old_ir): + index = 0 + found = False + for class_ in metadata.classes_: + if class_.name == old_ir.class_: + found = True + break + index += 1 + if not found: + return None + return IRCreate(old_ir.class_, index) + +def update_creates_function(metadata, func): + old_ir = func.statements + ir = [] + for node in old_ir: + new_ir = node + if isinstance(node, IRCreate): + new_ir = update_creates_ir(metadata, node) + if not new_ir: + print("No class to create for IR: %s" % (node)) + return None + ir.append(new_ir) + public = func.public + class_ = func.class_ + name = func.name + args = func.args + return IRFunction(public, class_, name, args, ir) + +def update_creates(old_ir): + ir = [] + metadata = None + for node in old_ir: + if isinstance(node, IRMetadata): + metadata = node + break + if metadata is None: + return None + for node in old_ir: + new_ir = node + if isinstance(node, IRFunction): + new_ir = update_creates_function(metadata, node) + if not new_ir: + return None + ir.append(new_ir) + return ir + ## Register allocation # Register allocation here is very simple: Each variable gets one stack slot @@ -887,6 +972,10 @@ bytes += (node.args + 1).to_bytes(1) bytes += node.name.encode('utf-8') bytes += b"\x00" # NULL terminator + elif isinstance(node, IRCreate): + index = int(node.index) + bytes += b"\x02" # OP_CREATE + bytes += index.to_bytes(1) elif isinstance(node, IRReturn): bytes += b"\x03" # OP_RET elif isinstance(node, IRDepthCheck): @@ -1068,7 +1157,11 @@ if ir_meta is None: print("Failed to generate metadata") return None - ir_reg = registers_allocate(module_args, ir_meta) + ir_creates = update_creates(ir_meta) + if ir_creates is None: + print("Failed to update creates indexes") + return None + ir_reg = registers_allocate(module_args, ir_creates) if ir_reg is None: print("Failed to allocate registers") return None diff --git a/lang/module.c b/lang/module.c index a20690d..e06e3a5 100644 --- a/lang/module.c +++ b/lang/module.c @@ -64,6 +64,21 @@ return object_list_get(state, data->uses, index); } +const ModuleClass *module_runtime_class_info( + VmState state, Object obj, int index) { + struct module_runtime_data *data = + (struct module_runtime_data *)object_priv( + state, obj, &module_runtime_class); + const ModuleClass *class; + for (int i = 0; i <= index; ++i) { + class = data->info->classes[index]; + if (class == NULL) + break; + } + vm_abort_if(state, !class, "Unable to find class by index!"); + return class; +} + static struct object_call module_runtime_calls[] = {{.name = NULL, /* end */}}; static struct object_class module_runtime_class = { @@ -78,14 +93,13 @@ Object module_runtime; }; -Object module_class_create( - VmState state, const ModuleClass *class, Object module_runtime) { +Object module_class_create(VmState state, Object module_runtime, int index) { size_t size = sizeof(struct module_class_data); Object obj = object_create(state, &module_class_class, size); struct module_class_data *data = (struct module_class_data *)object_priv( state, obj, &module_class_class); - data->class = class; + data->class = module_runtime_class_info(state, module_runtime, index); data->module_runtime = module_runtime; return obj; } @@ -248,10 +262,9 @@ // Assumes all dependencies already exist Object create_module( VmState state, struct module_mapping *mapping, const ModuleInfo *info) { - const ModuleClass *class = info->classes[0]; Object use_modules = create_module_use_list(state, mapping, info); Object runtime = module_runtime_create(state, info, use_modules); - Object module_class = module_class_create(state, class, runtime); + Object module_class = module_class_create(state, runtime, 0); return module_class; } diff --git a/lang/module.h b/lang/module.h index 158ee84..5d4df42 100644 --- a/lang/module.h +++ b/lang/module.h @@ -48,8 +48,13 @@ typedef struct module_info ModuleInfo; // Gets another module from a module's runtime data +// Creates a new reference for the caller Object module_runtime_use(VmState state, Object module, int index); +// Creates a class from a module +// Caller passes its module reference +Object module_class_create(VmState state, Object module, int index); + #endif #endif diff --git a/lang/modules/main.txt b/lang/modules/main.txt index 4229361..a6a333a 100644 --- a/lang/modules/main.txt +++ b/lang/modules/main.txt @@ -47,9 +47,14 @@ Jump Self CountDown 10000 EndFunction -Public Class Main Function MakeNumber +Public Class Main Function MakeNumberReal Set Halfish To Another GetHalfish 620 Set Double To Halfish Add Halfish Set Final To Double Subtract 2 Return Final EndFunction + +Public Class Main Function MakeNumber + Set NewMain To Create Main + Jump NewMain MakeNumberReal +EndFunction