Skip to content

Commit

Permalink
reworked branch management for new merging
Browse files Browse the repository at this point in the history
  • Loading branch information
AjaniBilby committed May 20, 2024
1 parent 8689ae5 commit 79d3557
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 79 deletions.
114 changes: 114 additions & 0 deletions source/compiler/codegen/expression/flow-control.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import * as colors from "https://deno.land/[email protected]/fmt/colors.ts";

import type * as Syntax from "~/bnf/syntax.d.ts";
import { LinearType, SolidType, OperandType } from "~/compiler/codegen/expression/type.ts";
import { IntrinsicValue, VirtualType, bool } from "~/compiler/intrinsic.ts";
import { GetSolidType } from "~/compiler/codegen/expression/type.ts";
import { CompileExpr } from "~/compiler/codegen/expression/index.ts";
import { IsNamespace } from "~/compiler/file.ts";
import { Instruction } from "~/wasm/index.ts";
import { Context } from "~/compiler/codegen/context.ts";
import { Panic } from "~/compiler/helper.ts";


export function CompileIf(ctx: Context, syntax: Syntax.Term_If, expect?: SolidType): OperandType {
const cond = CompileExpr(ctx, syntax.value[0]);
if (cond instanceof LinearType && cond.type !== bool.value) Panic(
`${colors.red("Error")}: Invalid comparison type ${cond.type.getTypeName()}\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.value[0].ref }
);

const lifter = ctx.scope.stack.allocate(0, 0);

const brIf = CompileBranchBody(ctx, syntax.value[1], expect);

let typeIdx = 0x40;
if (brIf.type instanceof IntrinsicValue) typeIdx = ctx.file.getModule().makeType([], [brIf.type.type.bitcode]);
else if (brIf.type instanceof VirtualType) typeIdx = 0x40;
else if (brIf.type instanceof LinearType) {
lifter.align = brIf.type.getAlignment();
lifter.size = brIf.type.getSize();

if (!brIf.type.alloc) Panic(
`${colors.red("Error")}: Lifted struct somehow has no allocation\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.value[1].ref }
);

brIf.type.alloc.moveTo(lifter);
}

const elseSyntax = syntax.value[2].value[0];
if (elseSyntax) {
const brElse = CompileBranchBody(ctx, elseSyntax.value[0], GetSolidType(brIf.type));

if (brIf.type instanceof LinearType) {
if ( !(brElse.type instanceof LinearType) || brIf.type.type !== brElse.type.type ) Panic(
`${colors.red("Error")}: Type miss-match between if statement results, ${brIf.type.getTypeName()} != ${brElse.type.getTypeName()}\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }
);

if (!brElse.type.alloc) Panic(
`${colors.red("Error")}: Lifted struct somehow has no allocation\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: elseSyntax.value[0].ref }
);

brElse.type.alloc.moveTo(lifter);
} else if (brIf.type != brElse.type) Panic(
`${colors.red("Error")}: Type miss-match between if statement results, ${brIf.type.getTypeName()} != ${brElse.type.getTypeName()}\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }
);


ctx.block.push(Instruction.if(typeIdx, brIf.scope.block, brElse.scope?.block));

ctx.exited ||= brIf.scope.exited && brElse.scope.exited;
ctx.block.push(Instruction.unreachable());
} else {
ctx.block.push(Instruction.if(typeIdx, brIf.scope.block));
}

return brIf.type;
}


function CompileBranchBody(ctx: Context, syntax: Syntax.Term_Expr, expect?: SolidType) {
const stack = ctx.scope.stack.checkpoint();
const scope = ctx.child();

// If there is a single block, inline it
// Otherwise compile the expression inline
const type = InlineBlock(scope, syntax)
|| CompileExpr(scope, syntax, expect);

if (IsNamespace(type)) Panic(
`${colors.red("Error")}: Unsupported namespace yielded from a branch\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }
);

scope.mergeBlock();
stack.restore();

return { stack, scope, type };
}

function InlineBlock(ctx: Context, syntax: Syntax.Term_Expr) {
// Expression only has a single arg
if (syntax.value[1].value.length !== 0) return null;

const arg = syntax.value[0];

// No prefix operations
if (arg.value[0].value.length !== 0) return null;

// No postfix operations
if (arg.value[2].value.length !== 0) return null;

// Only a block argument
if (arg.value[1].value[0].type != "block") return null;

// Compile each of the block_stmt in the current context
const block = arg.value[1].value[0];
ctx.compile(block.value[0].value);

return ctx.raiseType;
}
82 changes: 4 additions & 78 deletions source/compiler/codegen/expression/operand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ 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 { IntrinsicValue, VirtualType, bool, never } from "~/compiler/intrinsic.ts";
import { ArrayBuilder, StructBuilder } from "~/compiler/codegen/expression/container.ts";
import { SolidType, OperandType } from "~/compiler/codegen/expression/type.ts";
import { AssertUnreachable } from "~/helper.ts";
import { CompilePostfixes } from "~/compiler/codegen/expression/postfix/index.ts";
import { CompileConstant } from "~/compiler/codegen/expression/constant.ts";
import { CompilePrefix } from "~/compiler/codegen/expression/prefix.ts";
import { CompileExpr } from "~/compiler/codegen/expression/index.ts";
import { IsNamespace } from "~/compiler/file.ts";
import { Instruction } from "~/wasm/index.ts";
import { CompileIf } from "~/compiler/codegen/expression/flow-control.ts";
import { Context } from "~/compiler/codegen/context.ts";
import { Panic } from "~/compiler/helper.ts";
import { never } from "~/compiler/intrinsic.ts";



export function CompileArg(ctx: Context, syntax: Syntax.Term_Expr_arg, expect?: SolidType, tailCall = false): OperandType {
Expand Down Expand Up @@ -80,81 +81,6 @@ function CompileName(ctx: Context, syntax: Syntax.Term_Name): OperandType {
return variable.type;
}

function CompileIf(ctx: Context, syntax: Syntax.Term_If, expect?: SolidType): OperandType {
const cond = CompileExpr(ctx, syntax.value[0]);
if (cond instanceof LinearType && cond.type !== bool.value) Panic(
`${colors.red("Error")}: Invalid comparison type ${cond.type.getTypeName()}\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.value[0].ref }
);

const lifter = ctx.scope.stack.allocate(0, 0);

const stackIf = ctx.scope.stack.checkpoint();
const scopeIf = ctx.child();
const typeIf = CompileExpr(scopeIf, syntax.value[1], expect);
if (IsNamespace(typeIf)) Panic(
`${colors.red("Error")}: Unsupported namespace yielded from if block\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }
);
scopeIf.mergeBlock();
stackIf.restore();

let typeIdx = 0x40;
if (typeIf instanceof IntrinsicValue) typeIdx = ctx.file.getModule().makeType([], [typeIf.type.bitcode]);
else if (typeIf instanceof VirtualType) typeIdx = 0x40;
else if (typeIf instanceof LinearType) {
lifter.align = typeIf.getAlignment();
lifter.size = typeIf.getSize();

if (!typeIf.alloc) Panic(
`${colors.red("Error")}: Lifted struct somehow has no allocation\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.value[1].ref }
);

typeIf.alloc.moveTo(lifter);
}

if (syntax.value[2].value[0]) {
const stackElse = ctx.scope.stack.checkpoint();
const scopeElse = ctx.child();
const typeElse = CompileExpr(scopeElse, syntax.value[2].value[0].value[0], expect);

if (IsNamespace(typeElse)) Panic(
`${colors.red("Error")}: Unsupported namespace yielded from else block\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }
);
scopeElse.mergeBlock();
stackElse.restore();

if (typeIf instanceof LinearType) {
if ( !(typeElse instanceof LinearType) || typeIf.type !== typeElse.type ) Panic(
`${colors.red("Error")}: Type miss-match between if statement results, ${typeIf.getTypeName()} != ${typeElse.getTypeName()}\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }
);

if (!typeElse.alloc) Panic(
`${colors.red("Error")}: Lifted struct somehow has no allocation\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.value[2].value[0].value[0].ref }
);

typeElse.alloc.moveTo(lifter);
} else if (typeIf != typeElse) Panic(
`${colors.red("Error")}: Type miss-match between if statement results, ${typeIf.getTypeName()} != ${typeElse.getTypeName()}\n`,
{ path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }
);


ctx.block.push(Instruction.if(typeIdx, scopeIf.block, scopeElse?.block));

ctx.exited ||= scopeIf.exited && scopeElse.exited;
ctx.block.push(Instruction.unreachable());
} else {
ctx.block.push(Instruction.if(typeIdx, scopeIf.block));
}

return typeIf;
}

function CompileBlock(ctx: Context, syntax: Syntax.Term_Block, expect?: SolidType): OperandType {
const child = ctx.child();
child.compile(syntax.value[0].value);
Expand Down
18 changes: 17 additions & 1 deletion source/compiler/codegen/expression/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,9 @@ export class LinearType {
return false;
}


/**
* Overwrites this linear type with another
*/
infuse(other: LinearType) {
if (!this.like(other)) throw new Error("Cannot infuse a different type");

Expand Down Expand Up @@ -302,4 +304,18 @@ export class LinearType {

return nx;
}
}




export function GetSolidType(type: OperandType): SolidType | undefined {
if (type instanceof IntrinsicValue) return type.type;
if (type instanceof VirtualType) return undefined;
if (type instanceof LinearType) return GetSolidType(type.type);

if (IsNamespace(type)) return undefined;
if (IsSolidType(type)) return type;

return type;
}

0 comments on commit 79d3557

Please sign in to comment.