Skip to content

Commit

Permalink
inlined nested struct container expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
AjaniBilby committed Mar 20, 2024
1 parent 07075ba commit bd653f5
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 58 deletions.
6 changes: 3 additions & 3 deletions source/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ if (project.failed) Panic(`Compilation ${colors.red("Failed")}`);

const mainFile = mainPck.import(root);
const mainFunc = mainFile.namespace["main"];
if (!(mainFunc instanceof Function)) {
Panic(`Main namespace is not a function: ${mainFunc.constructor.name}`);
}
if (!(mainFunc instanceof Function)) Panic(
`Main namespace is not a function: ${colors.cyan(mainFunc.constructor.name)}`
);

TimerStart("compilation");
mainFunc.compile();
Expand Down
28 changes: 16 additions & 12 deletions source/compiler/codegen/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import type { File } from "~/compiler/file.ts";

import * as banned from "~/compiler/codegen/banned.ts";
import Structure from "~/compiler/structure.ts";
import { BasePointerType, LinearType, OperandType, SolidType, IsRuntimeType } from "~/compiler/codegen/expression/type.ts";
import { IntrinsicType, IntrinsicValue, none, never } from "~/compiler/intrinsic.ts";
import { BasePointerType, LinearType, OperandType, SolidType, IsRuntimeType, IsSolidType } from "~/compiler/codegen/expression/type.ts";
import { IntrinsicType, IntrinsicValue, none, never, i32 } from "~/compiler/intrinsic.ts";
import { Instruction, AnyInstruction } from "~/wasm/index.ts";
import { ResolveLinearType, Store } from "~/compiler/codegen/expression/helper.ts"
import { AssertUnreachable, Panic } from "~/helper.ts";
Expand Down Expand Up @@ -101,8 +101,8 @@ function CompileDeclare(ctx: Context, syntax: Syntax.Term_Declare) {
{ path: ctx.file.path, name: ctx.file.name, ref: type.ref }
)

if (!IsRuntimeType(namespace)) Panic(
`${colors.red("Error")}: Cannot declare variable with non-runtime type ${namespace.getTypeName()}\n`,
if (!IsSolidType(namespace)) Panic(
`${colors.red("Error")}: Cannot declare variable with non-solid type ${colors.cyan(namespace.getTypeName())}\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: type.ref }
);

Expand All @@ -114,10 +114,7 @@ function CompileDeclare(ctx: Context, syntax: Syntax.Term_Declare) {
namespace.link();
const alloc = ctx.scope.stack.allocate(namespace.size, namespace.align);
linear = LinearType.make(namespace, alloc, ctx.file.owner.project.stackBase);
} else Panic(
`${colors.red("Error")}: Invalid runtime-type ${namespace.getTypeName()}\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: type.ref }
)
} else AssertUnreachable(namespace);

variable = ctx.scope.registerVariable(name, linear, type.ref);
linear.markConsumed(syntax.ref); // uninited
Expand Down Expand Up @@ -211,7 +208,7 @@ function CompileAssign(ctx: Context, syntax: Syntax.Term_Assign) {
}


function Assign(ctx: Context, target: LinearType, expr: OperandType, ref: ReferenceRange) {
export function Assign(ctx: Context, target: LinearType, expr: OperandType, ref: ReferenceRange) {
if (!IsRuntimeType(expr)) Panic(
`${colors.red("Error")}: Cannot assign to a non solid type\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: ref }
Expand All @@ -225,13 +222,21 @@ function Assign(ctx: Context, target: LinearType, expr: OperandType, ref: Refere
if (expr instanceof IntrinsicValue) {
if (target.type != expr) error();

// Start stack swap
const reg = ctx.scope.register.allocate(expr.type.bitcode);
ctx.block.push(Instruction.local.set(reg.ref));

// target address
switch (target.base.locality) {
case BasePointerType.global: ctx.block.push(Instruction.global.get(target.base.ref)); break;
case BasePointerType.local: ctx.block.push(Instruction.local.get(target.base.ref)); break;
default: AssertUnreachable(target.base.locality);
}

// End stack swap
ctx.block.push(Instruction.local.get(reg.ref));
reg.free();

Store(ctx, expr.type, target.offset);
target.markDefined();
return;
Expand All @@ -242,12 +247,11 @@ function Assign(ctx: Context, target: LinearType, expr: OperandType, ref: Refere
if (target.type != expr.type) error();

// TODO: drop previous value
console.warn(`Warn: Unimplemented struct re-assign causing unsafe no-op`);

// // Destination address
// Destination address
ResolveLinearType(ctx, target, ref, false);
// Source address
ResolveLinearType(ctx, expr, ref, true);
ResolveLinearType(ctx, expr, ref, false);
// Bytes
ctx.block.push(Instruction.const.i32(target.getSize()));
ctx.block.push(Instruction.copy(0, 0));
Expand Down
77 changes: 38 additions & 39 deletions source/compiler/codegen/expression/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@ import * as colors from "https://deno.land/[email protected]/fmt/colors.ts";
import type * as Syntax from "~/bnf/syntax.d.ts";
import Structure from "~/compiler/structure.ts";
import { LinearType, SolidType, OperandType } from "~/compiler/codegen/expression/type.ts";
import { Panic, LatentOffset } from "~/helper.ts";
import { IntrinsicValue } from "~/compiler/intrinsic.ts";
import { CompileExpr } from "~/compiler/codegen/expression/index.ts";
import { Instruction } from "~/wasm/index.ts";
import { SourceView } from "~/parser.ts";
import { Context } from "~/compiler/codegen/context.ts";
import { Store } from "~/compiler/codegen/expression/helper.ts";
import { ResolveLinearType } from "~/compiler/codegen/expression/helper.ts";
import { Assign } from "~/compiler/codegen/context.ts";
import { Panic } from "~/helper.ts";

export function StructBuilder(ctx: Context, syntax: Syntax.Term_Container, expect?: SolidType): OperandType {
if (!(expect instanceof Structure)) Panic(
Expand All @@ -21,7 +18,14 @@ export function StructBuilder(ctx: Context, syntax: Syntax.Term_Container, expec

const alloc = ctx.scope.stack.allocate(expect.size, expect.align);
const linear = LinearType.make(expect, alloc, ctx.file.owner.project.stackBase);
linear.markConsumed(syntax.ref);

NestedStructBuilder(ctx, linear, syntax);

return linear;
}

function NestedStructBuilder(ctx: Context, linear: LinearType, syntax: Syntax.Term_Container) {
function* iterator() {
const base = syntax.value[0].value[0];
if (!base) return;
Expand All @@ -32,10 +36,9 @@ export function StructBuilder(ctx: Context, syntax: Syntax.Term_Container, expec
return;
}

const seen: string[] = [];
for (const item of iterator()) {
const elm = item.value[0];
if (elm.type === "container_value") {
if (elm.type !== "container_map") {
console.error(
`${colors.red("Error")}: Unexpected array value as struct member\n`
+ SourceView(ctx.file.path, ctx.file.name, elm.ref)
Expand All @@ -45,51 +48,47 @@ export function StructBuilder(ctx: Context, syntax: Syntax.Term_Container, expec
}

const name = elm.value[0].value[0].value;
const attr = expect.get(name);
if (!attr) Panic(
`${colors.red("Error")}: Unknown attribute ${name} in struct ${expect.name}\n`, {
const target = linear.get(name);
if (!target) Panic(
`${colors.red("Error")}: Unknown attribute ${name} in struct ${linear.getBaseType().name}\n`, {
path: ctx.file.path, name: ctx.file.name, ref: elm.ref
});
const value = elm.value[1];

if (seen.includes(name)) Panic(
`${colors.red("Error")}: Duplicate ${name} attribute initialization\n`, {
path: ctx.file.path, name: ctx.file.name, ref: elm.ref
});
seen.push(name);

ctx.block.push(Instruction.global.get(ctx.file.owner.project.stackBase.ref));
let expr = CompileExpr(ctx, elm.value[1], attr.type);
if (expr instanceof LinearType) {
if (expr.type instanceof IntrinsicValue) {
ResolveLinearType(ctx, expr, elm.value[1].ref);
expr = expr.type;
} else {
Panic(`${colors.red("Error")}: Only intrinsics are currently supported\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: elm.value[1].ref }
);
}
}

if (expr instanceof IntrinsicValue) {
Store(ctx, expr.type, new LatentOffset(alloc.getOffset(), attr.offset) );
// short circuit: directly write inner container inside self
const innerContainer = MaybeNestedContainer(value);
if (innerContainer) {
NestedStructBuilder(ctx, target, innerContainer);
continue;
}

Panic(`${colors.red("Error")}: Unexpected namespace ${expr.getTypeName()}\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: elm.value[1].ref }
);
}

for (const attr of expect.attributes) {
if (seen.includes(attr.name)) continue;

const blank = linear.get(attr.name);
blank?.markConsumed(syntax.ref);
const expr = CompileExpr(ctx, value, target.getBaseType());
Assign(ctx, target, expr, elm.ref);
}

return linear;
}

function MaybeNestedContainer(syntax: Syntax.Term_Expr) {
const noInfix = syntax.value[1].value.length == 0;
if (!noInfix) return null;

const expr_arg = syntax.value[0];
const expr_val = expr_arg.value[1];
if (expr_val.value[0].type != "container") return null;

const hasPrefix = expr_arg.value[0].value.length != 0;
if (hasPrefix) return null;

const hasPostfix = expr_arg.value[2].value.length != 0;
if (hasPostfix) return null;

return expr_val.value[0];
}


export function ArrayBuilder(ctx: Context, syntax: Syntax.Term_Container, expect?: SolidType): OperandType {
// TODO: Update CompileContainer to derive container type when possible

Expand Down
10 changes: 6 additions & 4 deletions source/compiler/codegen/expression/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,22 @@ export function ResolveLinearType(ctx: Context, type: LinearType, ref: Reference
}
}

const base = type.type;
const baseType = type.getBaseType();
switch (type.base.locality) {
case BasePointerType.global: ctx.block.push(Instruction.global.get(type.base.ref)); break;
case BasePointerType.local: ctx.block.push(Instruction.local.get(type.base.ref)); break;
default: AssertUnreachable(type.base.locality);
}

if (base instanceof IntrinsicValue) {
Load(ctx, base.type, type.offset);
// Auto load intrinsic value from a linear type
if (baseType instanceof IntrinsicType) {
Load(ctx, baseType, type.offset);
return;
}

// Push the complete pointer to the stack
if (type.alloc) {
ctx.block.push(Instruction.const.i32(type.alloc.getOffset()));
ctx.block.push(Instruction.const.i32(type.offset));
ctx.block.push(Instruction.i32.add());
}

Expand Down
1 change: 1 addition & 0 deletions source/compiler/codegen/expression/prefix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ function CompileReturn(ctx: Context, type: OperandType, prefix: Syntax.Term_Expr
type = type.type;
}

// TODO: Typecheck returns

ctx.scope.cleanup();
ctx.block.push(Instruction.return());
Expand Down

0 comments on commit bd653f5

Please sign in to comment.