From 088b1d301a051a7f5977c40dd114cf58d94a9b24 Mon Sep 17 00:00:00 2001 From: Drew Youngwerth Date: Sat, 31 Aug 2024 15:08:18 -0700 Subject: [PATCH] Support nominal object initialization --- src/semantics/init-entities.ts | 42 ++++++++++++++++++++------- src/semantics/init-primitive-types.ts | 2 ++ src/syntax-objects/list.ts | 7 +++++ src/syntax-objects/types.ts | 9 +++--- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/semantics/init-entities.ts b/src/semantics/init-entities.ts index f8794e4c..6d1dc7de 100644 --- a/src/semantics/init-entities.ts +++ b/src/semantics/init-entities.ts @@ -40,10 +40,16 @@ export const initEntities: SemanticProcessor = (expr) => { return initTypeAlias(expr); } + // Object literal if (expr.calls("object")) { return initObjectLiteral(expr); } + // Nominal object definition + if (expr.calls("obj")) { + return initNominalObjectType(expr); + } + return initCall(expr); }; @@ -228,22 +234,36 @@ const initTypeExprEntities = (type?: Expr): Expr | undefined => { throw new Error("Invalid type entity"); }; +const initNominalObjectType = (obj: List) => { + const hasExtension = obj.optionalIdentifierAt(2)?.is("extends"); + return new ObjectType({ + ...obj.metadata, + name: obj.identifierAt(1), + parentObjExpr: hasExtension ? obj.at(3) : undefined, + value: extractObjectFields(hasExtension ? obj.listAt(4) : obj.listAt(2)), + }); +}; + const initObjectType = (obj: List) => { return new ObjectType({ ...obj.metadata, name: obj.syntaxId.toString(), - value: obj.sliceAsArray(1).map((v) => { - if (!v.isList()) { - throw new Error("Invalid object field"); - } - const name = v.identifierAt(1); - const typeExpr = initTypeExprEntities(v.at(2)); + value: extractObjectFields(obj), + }); +}; - if (!name || !typeExpr) { - throw new Error("Invalid object field"); - } +const extractObjectFields = (obj: List) => { + return obj.sliceAsArray(1).map((v) => { + if (!v.isList()) { + throw new Error("Invalid object field"); + } + const name = v.identifierAt(1); + const typeExpr = initTypeExprEntities(v.at(2)); - return { name: name.value, typeExpr }; - }), + if (!name || !typeExpr) { + throw new Error("Invalid object field"); + } + + return { name: name.value, typeExpr }; }); }; diff --git a/src/semantics/init-primitive-types.ts b/src/semantics/init-primitive-types.ts index 4f56815f..a12ca346 100644 --- a/src/semantics/init-primitive-types.ts +++ b/src/semantics/init-primitive-types.ts @@ -1,4 +1,5 @@ import { i32, f32, i64, f64, bool, dVoid } from "../syntax-objects/types.js"; +import { voidBaseObject } from "../syntax-objects/types.js"; import { SemanticProcessor } from "./types.js"; export const initPrimitiveTypes: SemanticProcessor = (expr) => { @@ -8,5 +9,6 @@ export const initPrimitiveTypes: SemanticProcessor = (expr) => { expr.registerEntity(f64); expr.registerEntity(bool); expr.registerEntity(dVoid); + expr.registerEntity(voidBaseObject); return expr; }; diff --git a/src/syntax-objects/list.ts b/src/syntax-objects/list.ts index f093dae6..639c8191 100644 --- a/src/syntax-objects/list.ts +++ b/src/syntax-objects/list.ts @@ -57,6 +57,13 @@ export class List extends Syntax { return id; } + optionalIdentifierAt(index: number): Identifier | undefined { + const id = this.at(index); + if (id?.isIdentifier()) { + return id; + } + } + listAt(index: number): List { const id = this.at(index); if (!id?.isList()) { diff --git a/src/syntax-objects/types.ts b/src/syntax-objects/types.ts index d7257540..651acea6 100644 --- a/src/syntax-objects/types.ts +++ b/src/syntax-objects/types.ts @@ -163,6 +163,7 @@ export type ObjectField = { name: string; typeExpr: Expr; type?: Type }; export class ObjectType extends BaseType { readonly kindOfType = "object"; fields: ObjectField[]; + parentObjExpr?: Expr; parentObj?: ObjectType; /** Type used for locals, globals, function return type */ binaryenType?: number; @@ -170,13 +171,14 @@ export class ObjectType extends BaseType { constructor( opts: NamedEntityOpts & { value: ObjectField[]; - parentObj?: ObjectType | null; + parentObjExpr?: Expr; + parentObj?: ObjectType; } ) { super(opts); this.fields = opts.value; - this.parentObj = - opts.parentObj !== null ? opts.parentObj ?? voidBaseObject : undefined; + this.parentObj = opts.parentObj; + this.parentObjExpr = opts.parentObjExpr; } get size() { @@ -293,6 +295,5 @@ export const dVoid = PrimitiveType.from("void"); export const voidBaseObject = new ObjectType({ name: "Object", value: [], - parentObj: null, }); export const CDT_ADDRESS_TYPE = i32;