Skip to content

Commit

Permalink
Support constructors for struct
Browse files Browse the repository at this point in the history
  • Loading branch information
benson1029 committed Apr 10, 2024
1 parent 3e9017d commit 0b39ba5
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 12 deletions.
48 changes: 37 additions & 11 deletions src/go/ece/loader/preprocess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class DeclarationObject {
class StructObject {
name: string;
fields: Map<string, Type>;
ordered_fields: Array<{ name: string; type: Type }>;
methods: Map<string, FunctionType | BuiltinType>;

constructor(name: string, fields: Array<{ name: string; type: Type }>) {
Expand All @@ -60,6 +61,7 @@ class StructObject {
for (let field of fields) {
this.fields.set(field.name, field.type);
}
this.ordered_fields = fields;
}

addMethod(name: string, type: FunctionType | BuiltinType) {
Expand Down Expand Up @@ -839,23 +841,47 @@ const microcode_preprocess: {
type_check: boolean
) => {
const t = toType(comp.type);
for (let arg of comp.args) {
const actual_t = preprocess(arg, scope, type_check);
if (!type_check) {
continue;
}
if (!t.isArray() && !t.isSlice()) {
throw new Error("Constructor on non-array type.");
if (!t.isArray() && !t.isSlice() && !t.isStruct()) {
throw new Error("Constructor on non-array, non-slice and non-struct type.");
}
if (t.isArray()) {
if (comp.args.length !== (t as ArrayType).len) {
throw new Error("Constructor argument length mismatch.");
}
const expected_t = (t as ArrayType).type;
if (!isEqual(actual_t.toObject(), expected_t.toObject())) {
throw new Error("Constructor argument type mismatch.");
}
if (t.isStruct()) {
const struct = scope.getType(t.tag) as StructObject;
if (comp.args.length !== struct.ordered_fields.length) {
throw new Error("Constructor argument length mismatch.");
}
}
comp.args.forEach((arg, i) => {
const actual_t = preprocess(arg, scope, type_check);
if (type_check) {
if (t.isArray() || t.isSlice()) {
const expected_t = (t as ArrayType).type;
if (!isEqual(actual_t.toObject(), expected_t.toObject())) {
throw new Error("Constructor argument type mismatch.");
}
}
if (t.isStruct()) {
const struct = scope.getType(t.tag) as StructObject;
const expected_t = struct.ordered_fields[i].type;
if (!isEqual(actual_t.toObject(), expected_t.toObject())) {
throw new Error("Constructor argument type mismatch.");
}
}
}
})
if (!type_check) {
return new NilType();
}
return t;
if (t.isArray() || t.isSlice()) {
return t;
}
if (t.isStruct()) {
return new StructType(t.tag);
}
},

make: (
Expand Down
2 changes: 1 addition & 1 deletion src/go/ece/loader/typeUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ abstract class Type {

public toObject(): any {
return {
tag: "struct-type",
tag: "struct-decl-type",
name: this.tag,
};
}
Expand Down
14 changes: 14 additions & 0 deletions src/go/ece/microcode/constructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,20 @@ function evaluate_constructor_i(cmd: number, heap: Heap, C: ContextControl, S: C
heap.free_object(slice);
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 = auto_cast(heap, UserStruct.allocate(heap, struct)) as UserStruct;
for (let i = 0; i < constructor_i_cmd.get_number_of_arguments(); i++) {
const field = struct.get_member_name(i);
const value = auto_cast(heap, S.pop());
struct_val.get_frame().get_variable_address(field.address).set_value(value);
value.free();
}
S.push(struct_val.address);
struct_val.free();
break;
}
default:
throw new Error("evaluate_constructor_i: Invalid type");
}
Expand Down
38 changes: 38 additions & 0 deletions src/go/ece/tests/struct.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,4 +171,42 @@ describe("Structs", () => {
const result = evaluateFunctions(functions);
expect(result).toBe("2\n");
})

it("supports constructor", () => {
const functions = `
type S struct {
x int32
y float32
}
func main() {
var s = S{1, 2.5}
fmt.Println(s.x)
fmt.Println(s.y)
}
`
const result = evaluateFunctions(functions);
expect(result).toBe("1\n2.5\n");
})

it("supports nested constructor", () => {
const functions = `
type S struct {
x int32
y float32
}
type T struct {
s S
}
func main() {
var t = T{S{1, 2.5}}
fmt.Println(t.s.x)
fmt.Println(t.s.y)
}
`
const result = evaluateFunctions(functions);
expect(result).toBe("1\n2.5\n");
})
})

0 comments on commit 0b39ba5

Please sign in to comment.