Skip to content

Commit

Permalink
basic function importing
Browse files Browse the repository at this point in the history
  • Loading branch information
AjaniBilby committed Mar 23, 2024
1 parent b7671eb commit 537cf4e
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 33 deletions.
22 changes: 17 additions & 5 deletions source/bnf/syntax.bnf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
program ::= %w* ( stmt_top %w* )* ;
stmt_top ::= function | structure ;
stmt_top ::= function | structure | external ;


#=============================
Expand Down Expand Up @@ -32,8 +32,9 @@ constant ::= boolean
| string
| float | integer ;

string ::= string_text ;
string_text ::= %"\'" ( ( "\\" !"" ) | !( "\'" ) )* %"\'" ;
string ::= string_ascii | string_utf8 ;
string_ascii ::= %"\'" ( ( "\\" !"" ) | !( "\'" ) )* %"\'" ;
string_utf8 ::= %"\"" ( ( "\\" !"" ) | !( "\"" ) )* %"\"" ;

boolean ::= "true" | "false" ;

Expand Down Expand Up @@ -80,7 +81,7 @@ container ::= %(w* "[" w*) ( container_item ( %(w* "," w*) container_item )* %w*
#=============================
# Function
#=============================
function ::= func_head %w* ( block | ";" ) ;
function ::= func_head %w* ( block | ";" ) %w* ;
func_head ::= %("fn" w+) ...name %( w* "(" w* ) func_args %(w* ")" w*) %(":" w*) access ;
func_args ::= ( func_arg %w* ( %( "," w* ) func_arg )* )? ;
func_arg ::= ...name %( w* ":" w* ) access ;
Expand All @@ -95,6 +96,7 @@ return ::= %"return" "_call"? ( %w+ expr)? %( w* ";" w* );
raise ::= %"raise" %w+ expr %( ";" w* ); # TODO rename to lift
# drop ::= %"drop" %w+ expr %( ";" w* );


#=============================
# Expression
#=============================
Expand All @@ -117,4 +119,14 @@ arg_list ::= ( expr %w* ","? %w* )* ;

if ::= %("if" w*) expr %w* expr %w* ( %"else" %w* expr )? ;

statement ::= expr %terminate ;
statement ::= expr %terminate ;


#=============================
# External
#=============================
external ::= %( "external" w+ ) ( ext_import | ext_export ) ;
ext_import ::= %( "import" w* "{" w* ) ext_imports* %( w* "}" w* "from" w*) string %(w* ";" w*) ;
ext_imports ::= function | ext_import_var ;
ext_import_var ::= %( "let" w* ) name %( w* ":" w* ) access %(w* ";" w*);
ext_export ::= "export" ;
126 changes: 120 additions & 6 deletions source/bnf/syntax.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type Term_Stmt_top = {
count: number,
ref: _Shared.ReferenceRange,
value: [
(Term_Function | Term_Structure)
(Term_Function | Term_Structure | Term_External)
]
}
export declare function Parse_Stmt_top (i: string, refMapping?: boolean): _Shared.ParseError | {
Expand Down Expand Up @@ -235,7 +235,7 @@ export type Term_String = {
count: number,
ref: _Shared.ReferenceRange,
value: [
Term_String_text
(Term_String_ascii | Term_String_utf8)
]
}
export declare function Parse_String (i: string, refMapping?: boolean): _Shared.ParseError | {
Expand All @@ -245,8 +245,8 @@ export declare function Parse_String (i: string, refMapping?: boolean): _Shared.
isPartial: boolean
}

export type Term_String_text = {
type: 'string_text',
export type Term_String_ascii = {
type: 'string_ascii',
start: number,
end: number,
count: number,
Expand All @@ -265,8 +265,35 @@ export type Term_String_text = {
} | _Literal)>, start: number, end: number, count: number, ref: _Shared.ReferenceRange }
]
}
export declare function Parse_String_text (i: string, refMapping?: boolean): _Shared.ParseError | {
root: _Shared.SyntaxNode & Term_String_text,
export declare function Parse_String_ascii (i: string, refMapping?: boolean): _Shared.ParseError | {
root: _Shared.SyntaxNode & Term_String_ascii,
reachBytes: number,
reach: null | _Shared.Reference,
isPartial: boolean
}

export type Term_String_utf8 = {
type: 'string_utf8',
start: number,
end: number,
count: number,
ref: _Shared.ReferenceRange,
value: [
{ type: '(...)*', value: Array<({
type: '(...)',
start: number,
end: number,
count: number,
ref: _Shared.ReferenceRange,
value: [
_Literal & {value: "\x5c"},
_Literal
]
} | _Literal)>, start: number, end: number, count: number, ref: _Shared.ReferenceRange }
]
}
export declare function Parse_String_utf8 (i: string, refMapping?: boolean): _Shared.ParseError | {
root: _Shared.SyntaxNode & Term_String_utf8,
reachBytes: number,
reach: null | _Shared.Reference,
isPartial: boolean
Expand Down Expand Up @@ -1221,3 +1248,90 @@ export declare function Parse_Statement (i: string, refMapping?: boolean): _Shar
reach: null | _Shared.Reference,
isPartial: boolean
}

export type Term_External = {
type: 'external',
start: number,
end: number,
count: number,
ref: _Shared.ReferenceRange,
value: [
(Term_Ext_import | Term_Ext_export)
]
}
export declare function Parse_External (i: string, refMapping?: boolean): _Shared.ParseError | {
root: _Shared.SyntaxNode & Term_External,
reachBytes: number,
reach: null | _Shared.Reference,
isPartial: boolean
}

export type Term_Ext_import = {
type: 'ext_import',
start: number,
end: number,
count: number,
ref: _Shared.ReferenceRange,
value: [
{ type: '(...)*', value: Array<Term_Ext_imports>, start: number, end: number, count: number, ref: _Shared.ReferenceRange },
Term_String
]
}
export declare function Parse_Ext_import (i: string, refMapping?: boolean): _Shared.ParseError | {
root: _Shared.SyntaxNode & Term_Ext_import,
reachBytes: number,
reach: null | _Shared.Reference,
isPartial: boolean
}

export type Term_Ext_imports = {
type: 'ext_imports',
start: number,
end: number,
count: number,
ref: _Shared.ReferenceRange,
value: [
(Term_Function | Term_Ext_import_var)
]
}
export declare function Parse_Ext_imports (i: string, refMapping?: boolean): _Shared.ParseError | {
root: _Shared.SyntaxNode & Term_Ext_imports,
reachBytes: number,
reach: null | _Shared.Reference,
isPartial: boolean
}

export type Term_Ext_import_var = {
type: 'ext_import_var',
start: number,
end: number,
count: number,
ref: _Shared.ReferenceRange,
value: [
Term_Name,
Term_Access
]
}
export declare function Parse_Ext_import_var (i: string, refMapping?: boolean): _Shared.ParseError | {
root: _Shared.SyntaxNode & Term_Ext_import_var,
reachBytes: number,
reach: null | _Shared.Reference,
isPartial: boolean
}

export type Term_Ext_export = {
type: 'ext_export',
start: number,
end: number,
count: number,
ref: _Shared.ReferenceRange,
value: [
_Literal & {value: "export"}
]
}
export declare function Parse_Ext_export (i: string, refMapping?: boolean): _Shared.ParseError | {
root: _Shared.SyntaxNode & Term_Ext_export,
reachBytes: number,
reach: null | _Shared.Reference,
isPartial: boolean
}
24 changes: 21 additions & 3 deletions source/bnf/syntax.js

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions source/compiler/codegen/expression/operand.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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 } from "~/compiler/intrinsic.ts";
import { ArrayBuilder, StructBuilder } from "~/compiler/codegen/expression/container.ts";
Expand All @@ -12,8 +13,6 @@ 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 Structure from "~/compiler/structure.ts";
import { ResolveLinearType } from "~/compiler/codegen/expression/helper.ts";


export function CompileArg(ctx: Context, syntax: Syntax.Term_Expr_arg, expect?: SolidType): OperandType {
Expand Down
47 changes: 38 additions & 9 deletions source/compiler/file.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// <reference lib="deno.ns" />

import type Package from "./package.ts";
import type { Term_Access, Term_Function, Term_Program, Term_Structure } from "~/bnf/syntax.d.ts";
import type { Term_Access, Term_External, Term_Function, Term_Program, Term_Structure } from "~/bnf/syntax.d.ts";

import { IntrinsicType, bool, u8, i8, u16, i16, i32, i64, u32, u64, f32, f64, none, never } from "~/compiler/intrinsic.ts";
import { AssertUnreachable, FlatAccess, FlattenAccess } from "~/helper.ts";
Expand Down Expand Up @@ -85,27 +85,23 @@ function Ingest(file: File, syntax: Term_Program) {
const inner = stmt_top.value[0];

switch (inner.type) {
case "function": IngestFunction(file, inner); break;
case "function": IngestFunction(file, inner); break;
case "structure": IngestStructure(file, inner); break;
case "external": IngestExternal(file, inner); break;
default: AssertUnreachable(inner);
}
}
}

function IngestFunction(file: File, syntax: Term_Function) {
const func = new Function(file, syntax);
function IngestFunction(file: File, syntax: Term_Function, external?: string) {
const func = new Function(file, syntax, external);

const existing = file.namespace[func.name];
if (!existing) {
file.namespace[func.name] = func;
return;
}

if (existing instanceof Function) {
existing.merge(func);
return;
}

throw new Error(`Cannot merge a function with a non-function ${func.name}`);
}

Expand All @@ -119,4 +115,37 @@ function IngestStructure(file: File, syntax: Term_Structure) {
}

throw new Error(`Structures cannot share a namespace`);
}



function IngestExternal(file: File, syntax: Term_External) {
if (syntax.value[0].type !== "ext_import") throw new Error(`Unsupported external export`);

for (const inner of syntax.value[0].value[0].value) {
const line = inner.value[0];
const type = line.type;
switch (type) {
case "function": {
IngestFunction(file, line, "ext");
} break;
case "ext_import_var": throw new Error(`Import global unimplemented`);
default: AssertUnreachable(type);
}
}

// const func = new Function(file, syntax);

// const existing = file.namespace[func.name];
// if (!existing) {
// file.namespace[func.name] = func;
// return;
// }

// if (existing instanceof Function) {
// existing.merge(func);
// return;
// }

// throw new Error(`Cannot merge a function with a non-function ${func.name}`);
}
53 changes: 45 additions & 8 deletions source/compiler/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,17 @@ export default class Function {
name: string;
ref: FuncRef | null;

external?: string;

isCompiled: boolean;
isLinking: boolean;
isLinked: boolean;

arguments: Argument[];
returns: Argument[] | VirtualType;

constructor(owner: File, ast: Term_Function) {
constructor(owner: File, ast: Term_Function, external?: string) {
this.external = external;
this.owner = owner;
this.name = ast.value[0].value[0].value;
this.ast = ast;
Expand Down Expand Up @@ -151,11 +154,37 @@ export default class Function {
}

const project = this.getFile().owner.project;
const func = project.module.makeFunction( args, rets );
this.ref = func.ref;

const body = this.ast.value[1];
if (this.external) {
const file = this.getFile();
if (body.type !== "literal") {
console.error(`${colors.red("Error")}: External imports must have no body\n`+
SourceView(file.path, file.name, body.ref)
);
file.markFailure();
return;
}

const mod = file.owner.project.module;
const typeIdx = mod.makeType(args, rets);
const ref = mod.importFunction(this.external, this.name, typeIdx);
if (ref === null) {
console.error(`${colors.red("Error")}: Import name conflict\n`+
SourceView(file.path, file.name, this.ast.ref)
);
file.markFailure();
return;
}

this.ref = ref;

return;
}


const func = project.module.makeFunction( args, rets );
this.ref = func.ref;

const scope = new Scope(func);
const ctx = new Context(this.getFile(), this, scope, func.code);
Expand All @@ -168,15 +197,23 @@ export default class Function {
scope.registerArgument(ctx, arg.name, arg.type, arg.ref)
}

const body = this.ast.value[1];
if (body.type === "literal") throw new Error("Missing function body");
if (body.type === "literal") {
console.error(`${colors.red("Error")}: Missing function body\n`+
SourceView(ctx.file.path, ctx.file.name, body.ref)
);
ctx.file.markFailure();
return;
}

ctx.compile(body.value[0].value);
scope.stack.resolve();

if (!ctx.done) Panic(`${colors.red("Error")}: Function ${colors.brightBlue(this.name)} does not return\n`, {
path: ctx.file.path, name: ctx.file.name, ref: body.ref
})
if (!ctx.done) {
console.error(`${colors.red("Error")}: Function ${colors.brightBlue(this.name)} does not return\n`+
SourceView(ctx.file.path, ctx.file.name, body.ref)
);
ctx.file.markFailure();
}
}
}

Expand Down

0 comments on commit 537cf4e

Please sign in to comment.