Skip to content

Commit

Permalink
Add struct implementation in ECE (ref count still failing)
Browse files Browse the repository at this point in the history
  • Loading branch information
benson1029 committed Apr 3, 2024
1 parent f1ee2f3 commit 64c52fb
Show file tree
Hide file tree
Showing 20 changed files with 1,072 additions and 29 deletions.
19 changes: 16 additions & 3 deletions src/go/ece/loader/globalSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,15 @@ function sort_global_declarations(program: any, imports: any[], default_imports:
if (stmt.tag === "struct-method" && ignore_structs) continue;
if (stmt.tag === "struct") {
for (let ref of stmt.fields) {
if (ref.type.tag === "struct-decl-type") {
back_edges[get_name(stmt)].push(ref.type.name);
edges[ref.type.name].push(get_name(stmt));
let dfs = (type: any) => {
if (type.tag === "struct-decl-type") {
back_edges[get_name(stmt)].push(type.name);
edges[type.name].push(get_name(stmt));
} else if (type.tag === "array-type") {
dfs(type.type);
}
}
dfs(ref.type);
}
continue;
}
Expand Down Expand Up @@ -230,6 +235,14 @@ function sort_global_declarations(program: any, imports: any[], default_imports:
}
return 0;
});

// Remove the METHOD. captures.
for (let stmt of program.body) {
if (stmt.tag === "struct") continue;
stmt.captures = stmt.captures.filter((ref: any) => {
return !ref.name.startsWith("METHOD.");
});
}
}

export { sort_global_declarations };
56 changes: 43 additions & 13 deletions src/go/ece/loader/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ function load(
preprocess_program(program, imports, default_imports, true);
sort_global_declarations(program, imports, default_imports, false);

tag_struct_methods(program);

// // Stub for loading the main function directly:
// let main = program.body.filter((x: any) => x.tag === "function" && x.name === "main")[0];
// const _main_addr = heap.allocate_any(main.body.body);
Expand All @@ -38,20 +40,27 @@ function load(
for (let phase = 0; phase < 2; phase++) {
for (let i = program.body.length - 1; i >= 0; i--) {
if (phase === 0) {
const addr =
program.body[i].tag === "function"
? heap.allocate_any({
tag: "assign",
name: {
tag: "name-address",
name: program.body[i].name
},
value: program.body[i],
})
: heap.allocate_any(program.body[i]);
C.push(addr);
heap.free_object(addr);
if (program.body[i].tag !== "struct") {
const addr =
program.body[i].tag === "function"
? heap.allocate_any({
tag: "assign",
name: {
tag: "name-address",
name: program.body[i].name
},
value: program.body[i],
})
: heap.allocate_any(program.body[i]);
C.push(addr);
heap.free_object(addr);
}
} else {
if (program.body[i].tag === "struct") {
const addr = heap.allocate_any(program.body[i]);
C.push(addr);
heap.free_object(addr);
}
if (program.body[i].tag === "function") {
const addr = heap.allocate_any({
tag: "var",
Expand All @@ -78,4 +87,25 @@ function load(
}
}

function tag_struct_methods(program: any) {
let struct_methods = {};
for (let stmt of program.body) {
if (stmt.tag === "struct-method") {
struct_methods[stmt.struct.name] = struct_methods[stmt.struct.name] || [];
struct_methods[stmt.struct.name].push(stmt);
}
}
for (let stmt of program.body) {
if (stmt.tag === "struct") {
if (!struct_methods[stmt.name]) continue;
for (let method of struct_methods[stmt.name]) {
stmt.fields.push({
name: method.name,
type: { tag: "method-type" }
})
}
}
}
}

export { load };
3 changes: 3 additions & 0 deletions src/go/ece/loader/preprocess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ const microcode_preprocess: {
member: (
comp: {
tag: string;
struct: any | null;
object: any;
member: string;
},
Expand All @@ -268,6 +269,8 @@ const microcode_preprocess: {
} catch (e) {
return obj_t.getField(comp.member);
}
comp.tag = "method-member";
comp.struct = { tag: "name", name: obj_t.name };
if (scope.current_declaration != null) {
scope.current_declaration.captures.push({ name: "METHOD." + obj_t.name + "." + comp.member, type: method });
}
Expand Down
12 changes: 11 additions & 1 deletion src/go/ece/microcode/constructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import { ContextStash } from '../../heap/types/context/stash';
import { Heap } from '../../heap';
import { ControlMake } from '../../heap/types/control/make';
import { auto_cast } from '../../heap/types/auto_cast';
import { TAG_USER_type_array, TAG_USER_type_function } from '../../heap/types/tags';
import { TAG_USER_type_array, TAG_USER_type_function, TAG_USER_type_struct_decl } from '../../heap/types/tags';
import { ComplexArray } from '../../heap/types/complex/array';
import { UserTypeArray } from '../../heap/types/user/type/array';
import { UserVariable } from '../../heap/types/user/variable';
import { ControlConstructor } from '../../heap/types/control/constructor';
import { UserTypeStructDecl } from '../../heap/types/user/type/struct_decl';
import { UserTypeStruct } from '../../heap/types/user/type/struct';
import { UserStruct } from '../../heap/types/user/struct';

function evaluate_make(cmd: number, heap: Heap, C: ContextControl, S: ContextStash, E: ContextEnv): void {
const make_cmd = auto_cast(heap, cmd) as ControlMake;
Expand All @@ -33,6 +36,13 @@ function evaluate_make(cmd: number, heap: Heap, C: ContextControl, S: ContextSta
S.push(nil_address);
heap.free_object(nil_address);
break;
case TAG_USER_type_struct_decl:
const struct_decl = type as UserTypeStructDecl;
const struct = E.get_struct_frame().get_variable_address(struct_decl.get_name().address).get_value() as UserTypeStruct;
const struct_val = UserStruct.allocate(heap, struct);
S.push(struct_val);
heap.free_object(struct_val);
break;
default:
throw new Error("evaluate_make: Invalid type");
}
Expand Down
25 changes: 24 additions & 1 deletion src/go/ece/microcode/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import { ComplexFunction } from '../../heap/types/complex/function';
import { auto_cast } from '../../heap/types/auto_cast';
import { ControlCall } from '../../heap/types/control/call';
import { ControlCallI } from '../../heap/types/control/call_i';
import { TAG_COMPLEX_builtin, TAG_COMPLEX_function, TAG_CONTROL_exit_scope_i, TAG_CONTROL_restore_env_i, TAG_PRIMITIVE_nil } from '../../heap/types/tags';
import { TAG_COMPLEX_builtin, TAG_COMPLEX_function, TAG_COMPLEX_method, TAG_CONTROL_exit_scope_i, TAG_CONTROL_restore_env_i, TAG_PRIMITIVE_nil } from '../../heap/types/tags';
import { ControlReturn } from '../../heap/types/control/return';
import { ControlReturnI } from '../../heap/types/control/return_i';
import { ControlRestoreEnvI } from '../../heap/types/control/restore_env_i';
import { evaluate_builtin } from './builtin';
import { ComplexBuiltin } from '../../heap/types/complex/builtin';
import { ControlCallStmt } from '../../heap/types/control/call_stmt';
import { ControlPushI } from '../../heap/types/control/push_i';
import { UserStruct } from '../../heap/types/user/struct';
import { ComplexMethod } from '../../heap/types/complex/method';

function evaluate_function(cmd: number, heap: Heap, C: ContextControl, S: ContextStash, E: ContextEnv): void {
const cmd_object = auto_cast(heap, cmd) as ControlFunction;
Expand Down Expand Up @@ -64,6 +67,11 @@ function evaluate_call_i(cmd: number, heap: Heap, C: ContextControl, S: ContextS
}
} else if (function_object.get_tag() === TAG_COMPLEX_builtin) {
// Do nothing
} else if (function_object.get_tag() === TAG_COMPLEX_method) {
if (function_object.get_number_of_params() !== cmd_object.get_number_of_args()) {
deferred_free();
throw new Error("Number of parameters does not match");
}
} else {
deferred_free();
throw new Error("Object is not callable");
Expand Down Expand Up @@ -98,6 +106,15 @@ function evaluate_call_i(cmd: number, heap: Heap, C: ContextControl, S: ContextS
variable.set_value(auto_cast(heap, args[i]));
}

// Handle self parameter in struct
if (function_object.get_tag() === TAG_COMPLEX_method) {
const self = auto_cast(heap, S.pop()) as UserStruct;
const self_name = (function_object as ComplexMethod).get_self_name_address();
E.get_frame().insert_new_variable(self_name.address);
const variable = E.get_frame().get_variable_address(self_name.address);
variable.set_value(self);
}

// Push the body
C.push(function_object.get_body_address().address);

Expand Down Expand Up @@ -156,6 +173,11 @@ function evaluate_pop_i(cmd: number, heap: Heap, C: ContextControl, S: ContextSt
obj.free();
}

function evaluate_push_i(cmd: number, heap: Heap, C: ContextControl, S: ContextStash, E: ContextEnv): void {
const cmd_object = auto_cast(heap, cmd) as ControlPushI;
S.push(cmd_object.get_object_address());
}

export {
evaluate_function,
evaluate_call,
Expand All @@ -165,4 +187,5 @@ export {
evaluate_restore_env_i,
evaluate_call_stmt,
evaluate_pop_i,
evaluate_push_i,
};
12 changes: 12 additions & 0 deletions src/go/ece/microcode/lookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ function lookup_microcode_sequential(tag: number): Function {
return constructor.evaluate_constructor;
case tags.TAG_CONTROL_constructor_i:
return constructor.evaluate_constructor_i;
case tags.TAG_CONTROL_struct:
return struct.evaluate_struct;
case tags.TAG_CONTROL_member_address:
return struct.evaluate_member_address;
case tags.TAG_CONTROL_member_address_i:
return struct.evaluate_member_address_i;
case tags.TAG_CONTROL_method:
return struct.evaluate_method;
case tags.TAG_CONTROL_method_member:
return struct.evaluate_method_member;
case tags.TAG_CONTROL_push_i:
return control_function.evaluate_push_i;
case tags.TAG_PRIMITIVE_nil:
return (...args: any[]) => {};
default:
Expand Down
110 changes: 110 additions & 0 deletions src/go/ece/microcode/struct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,72 @@ import { ControlMember } from '../../heap/types/control/member';
import { UserStruct } from '../../heap/types/user/struct';
import { auto_cast } from '../../heap/types/auto_cast';
import { ControlMemberI } from '../../heap/types/control/member_i';
import { ControlStruct } from '../../heap/types/control/struct';
import { UserTypeStruct } from '../../heap/types/user/type/struct';
import { UserType } from '../../heap/types/user/type';
import { ControlMemberAddress } from '../../heap/types/control/member_address';
import { ControlMemberAddressI } from '../../heap/types/control/member_address_i';
import { UserVariable } from '../../heap/types/user/variable';
import { TAG_USER_type_array, TAG_USER_type_struct_decl } from '../../heap/types/tags';
import { UserTypeStructDecl } from '../../heap/types/user/type/struct_decl';
import { UserTypeArray } from '../../heap/types/user/type/array';
import { ControlMethod } from '../../heap/types/control/method';
import { ComplexMethod } from '../../heap/types/complex/method';
import { ComplexString } from '../../heap/types/complex/string';
import { ControlMethodMember } from '../../heap/types/control/method_member';

function resolveType(heap: Heap, E: ContextEnv, type: UserType): UserType {
switch (type.get_tag()) {
case TAG_USER_type_struct_decl:
return E.get_struct_frame().get_variable_address(
(type as UserTypeStructDecl).get_name().address
).get_value() as UserTypeStruct;
case TAG_USER_type_array:
return auto_cast(heap, UserTypeArray.reallocate(
heap,
(type as UserTypeArray).get_length(),
resolveType(heap, E, (type as UserTypeArray).get_inner_type())
)) as UserTypeArray;
default:
return type;
}
}

function evaluate_struct(cmd: number, heap: Heap, C: ContextControl, S: ContextStash, E: ContextEnv): void {
const struct_cmd = new ControlStruct(heap, cmd);
const name = struct_cmd.get_name();
let members = [];
for (let i = 0; i < struct_cmd.get_number_of_fields(); i++) {
const member_name = struct_cmd.get_field_name(i);
const member_type = resolveType(heap, E, struct_cmd.get_field_type(i));
members.push({ name: member_name, type: member_type });
}
const type = auto_cast(heap, UserTypeStruct.allocate(
heap,
name,
members
)) as UserTypeStruct
E.get_struct_frame().insert_new_variable(name.address);
const variable = E.get_struct_frame().get_variable_address(name.address);
variable.set_value(type);
type.free();
}

function evaluate_method(cmd: number, heap: Heap, C: ContextControl, S: ContextStash, E: ContextEnv): void {
const method_cmd = new ControlMethod(heap, cmd);
const method_name = auto_cast(heap, ComplexString.allocate(
heap,
"METHOD." + method_cmd.get_struct_name_address().get_string()
+ "." + method_cmd.get_name_address().get_string()
)) as ComplexString;
const method_object = auto_cast(
heap,
ComplexMethod.allocate(heap, method_cmd.address, E.get_frame().address)
) as ComplexMethod;
E.get_struct_frame().insert_new_variable(method_name.address);
const variable = E.get_struct_frame().get_variable_address(method_name.address);
variable.set_value(method_object);
}

function evaluate_member(cmd: number, heap: Heap, C: ContextControl, S: ContextStash, E: ContextEnv): void {
const member_cmd = new ControlMember(heap, cmd);
Expand All @@ -26,7 +92,51 @@ function evaluate_member_i(cmd: number, heap: Heap, C: ContextControl, S: Contex
object.free();
}

function evaluate_member_address(cmd: number, heap: Heap, C: ContextControl, S: ContextStash, E: ContextEnv): void {
const member_address_cmd = new ControlMemberAddress(heap, cmd);
const value = member_address_cmd.get_object();
const member_address_i_addr = heap.allocate_any({ tag: "member_address_i", member: member_address_cmd.get_member_name_address() });
C.push(member_address_i_addr);
C.push(value.address);
heap.free_object(member_address_i_addr);
}

function evaluate_member_address_i(cmd: number, heap: Heap, C: ContextControl, S: ContextStash, E: ContextEnv): void {
const member_address_i_cmd = new ControlMemberAddressI(heap, cmd);
const member_name = member_address_i_cmd.get_member_name_address();
const variable_object = auto_cast(heap, S.pop()) as unknown as UserVariable;
const object = variable_object.get_value() as UserStruct;
const member = object.get_frame().get_variable_address(member_name.address);
S.push(member.address);
variable_object.free();
}

function evaluate_method_member(cmd: number, heap: Heap, C: ContextControl, S: ContextStash, E: ContextEnv): void {
const method_member_cmd = new ControlMethodMember(heap, cmd);
const value = method_member_cmd.get_object();
const method_name = auto_cast(
heap,
ComplexString.allocate(
heap,
"METHOD." + method_member_cmd.get_struct_name()
+ "." + method_member_cmd.get_member_name()
)
) as ComplexString;
const method = E.get_struct_frame().get_variable_address(method_name.address)
.get_value() as ComplexMethod;
const push_i_addr = heap.allocate_any({ tag: "push_i", object: method });
C.push(push_i_addr);
C.push(value.address);
method_name.free();
heap.free_object(push_i_addr);
}

export {
evaluate_struct,
evaluate_method,
evaluate_member,
evaluate_member_i,
evaluate_member_address,
evaluate_member_address_i,
evaluate_method_member,
};
Loading

0 comments on commit 64c52fb

Please sign in to comment.