From 68ea84cc1aecb0550bbeb6b732e2081f3459807d Mon Sep 17 00:00:00 2001 From: Ajani Bilby Date: Fri, 22 Mar 2024 17:12:06 +1100 Subject: [PATCH] Basic Structure Support (#8) --- .gitattributes | 2 +- deno.json | 2 +- docs/language/structure.md | 21 + package.json | 6 +- source/bnf/syntax.bnf | 50 ++- source/bnf/syntax.d.ts | 256 +++++++++++- source/bnf/syntax.js | 38 +- source/cli.ts | 40 +- .../codegen/{ => allocation}/registers.ts | 0 source/compiler/codegen/allocation/stack.ts | 355 ++++++++++++++++ source/compiler/codegen/context.ts | 345 +++++++++++---- .../compiler/codegen/expression/constant.ts | 42 +- .../compiler/codegen/expression/container.ts | 136 ++++++ source/compiler/codegen/expression/helper.ts | 93 +++++ source/compiler/codegen/expression/index.ts | 4 +- source/compiler/codegen/expression/infix.ts | 392 +++++++++++------- source/compiler/codegen/expression/operand.ts | 93 +++-- source/compiler/codegen/expression/postfix.ts | 81 +++- .../compiler/codegen/expression/precedence.ts | 64 +-- source/compiler/codegen/expression/prefix.ts | 54 +-- source/compiler/codegen/expression/type.ts | 287 +++++++++++++ source/compiler/codegen/scope.ts | 79 ++-- source/compiler/codegen/variable.ts | 68 +-- source/compiler/file.ts | 45 +- source/compiler/function.ts | 68 ++- source/compiler/global.ts | 4 + source/compiler/import.ts | 4 + source/compiler/intrinsic.ts | 88 +++- source/compiler/package.ts | 39 ++ source/compiler/project.ts | 44 +- source/compiler/structure.ts | 209 +++++++++- source/helper.ts | 124 +++++- source/parser.ts | 27 +- source/wasm/funcRef.ts | 1 - source/wasm/function.ts | 4 +- source/wasm/instruction/constant.ts | 27 +- source/wasm/instruction/index.ts | 21 +- source/wasm/instruction/memory.ts | 100 +++-- source/wasm/instruction/variable.ts | 4 +- source/wasm/module.ts | 15 +- source/wasm/section/global.ts | 56 ++- source/wasm/section/start.ts | 8 +- tests/compiler/fibonacci.test.ts | 50 --- tests/e2e/compiler/fibonacci.test.ts | 84 ++++ tests/{ => e2e}/compiler/numeric.test.ts | 16 +- tests/{ => e2e}/wasm/hello-world.test.ts | 3 +- tests/{ => e2e}/wasm/type.test.ts | 3 +- tests/source/codegen/allocation/stack.test.ts | 114 +++++ .../codegen/expression/precedence.test.ts | 10 + .../syntaxes/salient.tmLanguage.json | 39 +- 50 files changed, 2989 insertions(+), 726 deletions(-) create mode 100644 docs/language/structure.md rename source/compiler/codegen/{ => allocation}/registers.ts (100%) create mode 100644 source/compiler/codegen/allocation/stack.ts create mode 100644 source/compiler/codegen/expression/container.ts create mode 100644 source/compiler/codegen/expression/helper.ts create mode 100644 source/compiler/codegen/expression/type.ts create mode 100644 source/compiler/package.ts delete mode 100644 tests/compiler/fibonacci.test.ts create mode 100644 tests/e2e/compiler/fibonacci.test.ts rename tests/{ => e2e}/compiler/numeric.test.ts (83%) rename tests/{ => e2e}/wasm/hello-world.test.ts (97%) rename tests/{ => e2e}/wasm/type.test.ts (95%) create mode 100644 tests/source/codegen/allocation/stack.test.ts create mode 100644 tests/source/codegen/expression/precedence.test.ts diff --git a/.gitattributes b/.gitattributes index ee38dad..86404ce 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ -*.sa linguist-language=Salient +*.sa linguist-language=Salient eol=lf * text=auto eol=lf \ No newline at end of file diff --git a/deno.json b/deno.json index c8757ef..60ccc07 100644 --- a/deno.json +++ b/deno.json @@ -27,6 +27,6 @@ "lock": false, "nodeModulesDir": true, "test": { - "include": ["tests/*/*", "source/*/*"] + "include": ["tests/**"] } } \ No newline at end of file diff --git a/docs/language/structure.md b/docs/language/structure.md new file mode 100644 index 0000000..862b5f1 --- /dev/null +++ b/docs/language/structure.md @@ -0,0 +1,21 @@ +# Structure + +```bnf +struct ::= "struct" name struct_type? "{" struct_stmt* "}" ; + struct_type ::= %( ":" w* ) ...name %w* ; + struct_stmt ::= struct_attr | struct_spread ; + struct_attr ::= ...name ":" access ";" ; + struct_spread ::= "..." access ";" ; +``` + + +## Memory Layout + +| Struct Type | Attribute Storage Method | Gaps | Ordered | +| :-: | :- | :-: | :-: | +| Sparse | Stored in order with gaps between them to ensure each attribute is correctly aligned | Yes | Yes | +| Aligned | Stored with gaps to ensure alignment, however reorders such to minimise the required gaps | Yes | No | +| Linear | Stored in order with no gaps between attributes | No | Yes | +| Compact | Stored with no gaps in such an order as to maximise alignment | No | No | + +*Defaults to sparse* \ No newline at end of file diff --git a/package.json b/package.json index ac7e6a4..70d6eec 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,9 @@ "scripts": { "build": "run-s build:*", "build:syntax": "npx bnf-compile ./source/bnf/", - "build:compiler": "deno compile --output salient.exe --allow-read --allow-write --allow-env --allow-run --allow-sys ./source/cli.ts", + "build:compiler": "deno compile --output salient.exe -A ./source/cli.ts", "test": "deno test", - "compile": "deno run --allow-read --allow-write --allow-env --allow-run --allow-sys ./source/cli.ts" + "compile": "deno run -A ./source/cli.ts" }, "bin": { "salient": "bin/cli.js" @@ -36,7 +36,7 @@ "chalk": "^5.3.0" }, "devDependencies": { - "bnf-parser": "^4.0.7", + "bnf-parser": "^4.1.0", "npm-run-all": "^4.1.5", "typescript": "^5.2.2" } diff --git a/source/bnf/syntax.bnf b/source/bnf/syntax.bnf index 2935856..b53a0d1 100644 --- a/source/bnf/syntax.bnf +++ b/source/bnf/syntax.bnf @@ -1,7 +1,5 @@ program ::= %w* ( stmt_top %w* )* ; - stmt_top ::= - function ; - + stmt_top ::= function | structure ; #============================= @@ -14,6 +12,8 @@ digit ::= "0" -> "9" ; digit_nz ::= "1" -> "9" ; letter ::= "a" -> "z" | "A" -> "Z" ; +terminate ::= ( w* ";" w* ); + #============================= @@ -58,45 +58,63 @@ access ::= name ( %w* accessor )* ; access_comp ::= %"#[]"; declare ::= %( "let" w* ) name %w* (%":" %w* access %w*)? ( %("=" w*) expr )? %(w* ";" w*) ; -assign ::= name %( w* "=" w*) expr %( w* ";" w* ) ; +assign ::= access %( w* "=" w*) expr %terminate ; + + + +#============================= +# Storage +#============================= +structure ::= %("struct" w*) ...name %w* struct_type? %( "{" w* ) struct_stmt* %( w* "}" w* ); + struct_type ::= %( ":" w* ) ...name %w* ; + struct_stmt ::= struct_attr | struct_spread ; + struct_attr ::= ...name %( w* ":" w* ) access %terminate ; + struct_spread ::= %( "..." ) access %terminate ; +container ::= %(w* "[" w*) ( container_item ( %(w* "," w*) container_item )* %w* %","? )? %("]" w*) ; + container_item ::= container_map | container_value ; + container_map ::= %"." name %(w* ":" w*) expr ; + container_value ::= expr ; #============================= # Function #============================= function ::= func_head %w* ( block | ";" ) ; - func_head ::= %("fn" w+) ...name %( w* "(" w* ) func_args %(w* ")" w* ":" w*) access ; + 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 ; block ::= %( "{" w* ) block_stmt* %( w* "}" w* ) ; - block_stmt ::= declare | assign | return | raise | statement ; + block_stmt ::= assign | declare | return | raise | statement ; func_call ::= access func_call_body; func_call_body ::= %( w* "(" w* ) ( expr %w* ( %( "," w* ) expr %w* )* )? %( ")" w* ) ; -return ::= %"return" "_tail"? %w+ expr %( ";" w* ); -raise ::= %"raise" %w+ expr %( ";" w* ); +return ::= %"return" "_call"? %w+ expr? %( ";" w* ); +raise ::= %"raise" %w+ expr %( ";" w* ); # TODO rename to lift +# drop ::= %"drop" %w+ expr %( ";" w* ); #============================= # Expression #============================= expr ::= expr_arg %w* ( ...expr_infix %w* expr_arg %w* )* ; - expr_prefix ::= "!" | "-" | "return" ; + expr_prefix ::= "!" | "-" ; expr_infix ::= "&&" | "||" | "^" | "==" | "!=" | "<=" | ">=" | "<" | ">" | "%" | "*" | "/" | "+" | "-" | "as" | "instanceof" - | "->" ; - expr_postfix ::= expr_call | expr_get | expr_param ; - expr_param ::= %"#[" %w* arg_list %w* %"]" ; - expr_call ::= %"(" %w* arg_list %w* %")" ; - expr_get ::= %"[" %w* arg_list %w* %"]" ; - expr_arg ::= expr_prefix? %w* ( constant | expr_brackets | if | name | block ) %w* expr_postfix* ; + | "." | "->" ; + expr_postfix ::= expr_call | expr_get | expr_param | expr_loan ; + expr_param ::= %"#[" %w* arg_list %w* %"]" ; + expr_call ::= %"(" %w* arg_list %w* %")" ; + expr_get ::= %"[" %w* arg_list %w* %"]" ; + expr_loan ::= "@" | "$" ; + expr_arg ::= expr_prefix? %w* expr_val %w* expr_postfix* ; + expr_val ::= constant | expr_brackets | block | container | if | name ; expr_brackets ::= %( "(" w* ) expr %( w* ")" ) ; arg_list ::= ( expr %w* ","? %w* )* ; if ::= %("if" w*) expr %w* expr %w* ( %"else" %w* expr )? ; -statement ::= expr %(w* ";"? w*) ; \ No newline at end of file +statement ::= expr %terminate ; \ No newline at end of file diff --git a/source/bnf/syntax.d.ts b/source/bnf/syntax.d.ts index d61802a..f94c7c3 100644 --- a/source/bnf/syntax.d.ts +++ b/source/bnf/syntax.d.ts @@ -33,7 +33,7 @@ export type Term_Stmt_top = { count: number, ref: _Shared.ReferenceRange, value: [ - Term_Function + (Term_Function | Term_Structure) ] } export declare function Parse_Stmt_top (i: string, refMapping?: boolean): _Shared.ParseError | { @@ -128,6 +128,34 @@ export declare function Parse_Letter (i: string, refMapping?: boolean): _Shared. isPartial: boolean } +export type Term_Terminate = { + type: 'terminate', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + { + type: '(...)', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + { type: '(...)*', value: Array, start: number, end: number, count: number, ref: _Shared.ReferenceRange }, + _Literal & {value: "\x3b"}, + { type: '(...)*', value: Array, start: number, end: number, count: number, ref: _Shared.ReferenceRange } + ] +} + ] +} +export declare function Parse_Terminate (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Terminate, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + export type Term_Comment = { type: 'comment', start: number, @@ -512,7 +540,7 @@ export type Term_Assign = { count: number, ref: _Shared.ReferenceRange, value: [ - Term_Name, + Term_Access, Term_Expr ] } @@ -523,6 +551,182 @@ export declare function Parse_Assign (i: string, refMapping?: boolean): _Shared. isPartial: boolean } +export type Term_Structure = { + type: 'structure', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + _Literal, + { type: '(...)?', value: [] | [Term_Struct_type], start: number, end: number, count: number, ref: _Shared.ReferenceRange }, + { type: '(...)*', value: Array, start: number, end: number, count: number, ref: _Shared.ReferenceRange } + ] +} +export declare function Parse_Structure (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Structure, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + +export type Term_Struct_type = { + type: 'struct_type', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + _Literal + ] +} +export declare function Parse_Struct_type (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Struct_type, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + +export type Term_Struct_stmt = { + type: 'struct_stmt', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + (Term_Struct_attr | Term_Struct_spread) + ] +} +export declare function Parse_Struct_stmt (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Struct_stmt, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + +export type Term_Struct_attr = { + type: 'struct_attr', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + _Literal, + Term_Access + ] +} +export declare function Parse_Struct_attr (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Struct_attr, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + +export type Term_Struct_spread = { + type: 'struct_spread', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + Term_Access + ] +} +export declare function Parse_Struct_spread (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Struct_spread, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + +export type Term_Container = { + type: 'container', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + { type: '(...)?', value: [] | [{ + type: '(...)', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + Term_Container_item, + { type: '(...)*', value: Array<{ + type: '(...)', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + Term_Container_item + ] +}>, start: number, end: number, count: number, ref: _Shared.ReferenceRange } + ] +}], start: number, end: number, count: number, ref: _Shared.ReferenceRange } + ] +} +export declare function Parse_Container (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Container, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + +export type Term_Container_item = { + type: 'container_item', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + (Term_Container_map | Term_Container_value) + ] +} +export declare function Parse_Container_item (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Container_item, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + +export type Term_Container_map = { + type: 'container_map', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + Term_Name, + Term_Expr + ] +} +export declare function Parse_Container_map (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Container_map, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + +export type Term_Container_value = { + type: 'container_value', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + Term_Expr + ] +} +export declare function Parse_Container_value (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Container_value, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + export type Term_Function = { type: 'function', start: number, @@ -638,7 +842,7 @@ export type Term_Block_stmt = { count: number, ref: _Shared.ReferenceRange, value: [ - (Term_Declare | Term_Assign | Term_Return | Term_Raise | Term_Statement) + (Term_Assign | Term_Declare | Term_Return | Term_Raise | Term_Statement) ] } export declare function Parse_Block_stmt (i: string, refMapping?: boolean): _Shared.ParseError | { @@ -709,8 +913,8 @@ export type Term_Return = { count: number, ref: _Shared.ReferenceRange, value: [ - { type: '(...)?', value: [] | [_Literal & {value: "\x5ftail"}], start: number, end: number, count: number, ref: _Shared.ReferenceRange }, - Term_Expr + { type: '(...)?', value: [] | [_Literal & {value: "\x5fcall"}], start: number, end: number, count: number, ref: _Shared.ReferenceRange }, + { type: '(...)?', value: [] | [Term_Expr], start: number, end: number, count: number, ref: _Shared.ReferenceRange } ] } export declare function Parse_Return (i: string, refMapping?: boolean): _Shared.ParseError | { @@ -772,7 +976,7 @@ export type Term_Expr_prefix = { count: number, ref: _Shared.ReferenceRange, value: [ - (_Literal & {value: "\x21"} | _Literal & {value: "\x2d"} | _Literal & {value: "return"}) + (_Literal & {value: "\x21"} | _Literal & {value: "\x2d"}) ] } export declare function Parse_Expr_prefix (i: string, refMapping?: boolean): _Shared.ParseError | { @@ -789,7 +993,7 @@ export type Term_Expr_infix = { count: number, ref: _Shared.ReferenceRange, value: [ - (_Literal & {value: "\x26\x26"} | _Literal & {value: "\x7c\x7c"} | _Literal & {value: "\x5e"} | _Literal & {value: "\x3d\x3d"} | _Literal & {value: "\x21\x3d"} | _Literal & {value: "\x3c\x3d"} | _Literal & {value: "\x3e\x3d"} | _Literal & {value: "\x3c"} | _Literal & {value: "\x3e"} | _Literal & {value: "\x25"} | _Literal & {value: "\x2a"} | _Literal & {value: "\x2f"} | _Literal & {value: "\x2b"} | _Literal & {value: "\x2d"} | _Literal & {value: "as"} | _Literal & {value: "instanceof"} | _Literal & {value: "\x2d\x3e"}) + (_Literal & {value: "\x26\x26"} | _Literal & {value: "\x7c\x7c"} | _Literal & {value: "\x5e"} | _Literal & {value: "\x3d\x3d"} | _Literal & {value: "\x21\x3d"} | _Literal & {value: "\x3c\x3d"} | _Literal & {value: "\x3e\x3d"} | _Literal & {value: "\x3c"} | _Literal & {value: "\x3e"} | _Literal & {value: "\x25"} | _Literal & {value: "\x2a"} | _Literal & {value: "\x2f"} | _Literal & {value: "\x2b"} | _Literal & {value: "\x2d"} | _Literal & {value: "as"} | _Literal & {value: "instanceof"} | _Literal & {value: "\x2e"} | _Literal & {value: "\x2d\x3e"}) ] } export declare function Parse_Expr_infix (i: string, refMapping?: boolean): _Shared.ParseError | { @@ -806,7 +1010,7 @@ export type Term_Expr_postfix = { count: number, ref: _Shared.ReferenceRange, value: [ - (Term_Expr_call | Term_Expr_get | Term_Expr_param) + (Term_Expr_call | Term_Expr_get | Term_Expr_param | Term_Expr_loan) ] } export declare function Parse_Expr_postfix (i: string, refMapping?: boolean): _Shared.ParseError | { @@ -867,6 +1071,23 @@ export declare function Parse_Expr_get (i: string, refMapping?: boolean): _Share isPartial: boolean } +export type Term_Expr_loan = { + type: 'expr_loan', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + (_Literal & {value: "\x40"} | _Literal & {value: "\x24"}) + ] +} +export declare function Parse_Expr_loan (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Expr_loan, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + export type Term_Expr_arg = { type: 'expr_arg', start: number, @@ -875,7 +1096,7 @@ export type Term_Expr_arg = { ref: _Shared.ReferenceRange, value: [ { type: '(...)?', value: [] | [Term_Expr_prefix], start: number, end: number, count: number, ref: _Shared.ReferenceRange }, - (Term_Constant | Term_Expr_brackets | Term_If | Term_Name | Term_Block), + Term_Expr_val, { type: '(...)*', value: Array, start: number, end: number, count: number, ref: _Shared.ReferenceRange } ] } @@ -886,6 +1107,23 @@ export declare function Parse_Expr_arg (i: string, refMapping?: boolean): _Share isPartial: boolean } +export type Term_Expr_val = { + type: 'expr_val', + start: number, + end: number, + count: number, + ref: _Shared.ReferenceRange, + value: [ + (Term_Constant | Term_Expr_brackets | Term_Block | Term_Container | Term_If | Term_Name) + ] +} +export declare function Parse_Expr_val (i: string, refMapping?: boolean): _Shared.ParseError | { + root: _Shared.SyntaxNode & Term_Expr_val, + reachBytes: number, + reach: null | _Shared.Reference, + isPartial: boolean +} + export type Term_Expr_brackets = { type: 'expr_brackets', start: number, diff --git a/source/bnf/syntax.js b/source/bnf/syntax.js index 41f56e3..847bd51 100644 --- a/source/bnf/syntax.js +++ b/source/bnf/syntax.js @@ -1,5 +1,5 @@ import * as _Shared from "./shared.js"; -let _rawWasm = _Shared.DecodeBase64("AGFzbQEAAAABIQZgAAF/YAF/AX9gA39/fwBgA39/fwF/YAF/AGACf38BfwM4NwABAgMEBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBAEBAQoGIAZ/AEGDBAt/AUEAC38BQQALfwFBAAt/AUEAC38BQQALB8cENgZtZW1vcnkCAAVpbnB1dAMABXJlYWNoAwULaW5wdXRMZW5ndGgDAgVfaW5pdAAAB3Byb2dyYW0ABghzdG10X3RvcAAHAXcACAJubAAJBWRpZ2l0AAoIZGlnaXRfbnoACwZsZXR0ZXIADAdjb21tZW50AA0OY29tbWVudF9zaW5nbGUADg1jb21tZW50X211bHRpAA8IY29uc3RhbnQAEAZzdHJpbmcAEQtzdHJpbmdfdGV4dAASB2Jvb2xlYW4AEwR2b2lkABQHaW50ZWdlcgAVCWludGVnZXJfdQAWBHplcm8AFwVmbG9hdAAYBG5hbWUAGQZhY2Nlc3MAGghhY2Nlc3NvcgAbDWFjY2Vzc19zdGF0aWMAHA5hY2Nlc3NfZHluYW1pYwAdC2FjY2Vzc19jb21wAB4HZGVjbGFyZQAfBmFzc2lnbgAgCGZ1bmN0aW9uACEJZnVuY19oZWFkACIJZnVuY19hcmdzACMIZnVuY19hcmcAJAVibG9jawAlCmJsb2NrX3N0bXQAJglmdW5jX2NhbGwAJw5mdW5jX2NhbGxfYm9keQAoBnJldHVybgApBXJhaXNlACoEZXhwcgArC2V4cHJfcHJlZml4ACwKZXhwcl9pbmZpeAAtDGV4cHJfcG9zdGZpeAAuCmV4cHJfcGFyYW0ALwlleHByX2NhbGwAMAhleHByX2dldAAxCGV4cHJfYXJnADINZXhwcl9icmFja2V0cwAzCGFyZ19saXN0ADQCaWYANQlzdGF0ZW1lbnQANgrQxQE3GgBBACQEQQAkBSMCQYMEaiQBIwEQASQDIwMLCgAgAEEDakF8cQsjAQF/A0AgACADaiABIANqLQAAOgAAIANBAWoiAyACSA0ACwtBAQF/IABBgwRqIQNBACEAA0ACQCAAIANqLQAAIAAgAWotAABHDQAgAEEBaiIAIAJODQAjASAAIANqSg0BCwsgAAsOACAAIwVOBEAgACQFCwtYAQN/IAEhBEEBIQIDQCAAKAIABH8gAiAAKAIQaiECIABBFGoFIAEgAEEUaiAAKAIQIgMQAiABIANqIQEgACADQRRqahABCyEAIAJBAWsiAg0ACyABIARrC4QDAQd/IwMiAiMENgIIIAJBFGokAyMDIwMiACMENgIIIABBFGokAwNAEAhBAUZFBEAgAUEBaiEBDAELCyAAQRI2AgAgAEEGNgIEIAAjBDYCDCAAIAE2AhAkAwJAQQAhAEEADQAjAyIDIwQ2AgggA0EUaiQDA0AjAyIBIwQ2AgggAUEUaiQDAkAQByIAQQFGDQAjA0EAIQUjAyIAIwQ2AgggAEEUaiQDA0AQCEEBRkUEQCAFQQFqIQUMAQsLIABBEjYCACAAQQY2AgQgACMENgIMIAAgBTYCECQDQQAhAEEADQALIABBAUYEQEEBIQAgASgCCCQEIAEkAwUgAUEHNgIAIAFBBTYCBCABIwQ2AgwgAUEBNgIQCyAAQQFGRQRAIARBAWohBAwBCwsgA0ESNgIAIANBBjYCBCADIwQ2AgwgAyAENgIQQQAhAEEADQALIABBAUYEQEEBIQAgAigCCCQEIAIkAwUgAkEeNgIAIAJBBzYCBCACIwQ2AgwgAkEBNgIQCyAAC1YBAn8jAyIAIwQ2AgggAEEUaiQDAkAQISIBQQFGDQALIAFBAUYEQEEBIQEgACgCCCQEIAAkAwUgAEElNgIAIABBCDYCBCAAIwQ2AgwgAEEBNgIQCyABC8cCAQR/IwMiAiMENgIIIAJBFGokAyMDIgEjBDYCCCMEQS1BARADIQMgAyMEaiQEIwQQBAJAIANBAUcEQEEBIQAgASgCCCQEIAEkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQE2AhAgAUEUakEtQQEQAiABQRVqEAEkAwsCQCAARQ0AQQAhACMDIgEjBDYCCCMEQS5BARADIQMgAyMEaiQEIwQQBAJAIANBAUcEQEEBIQAgASgCCCQEIAEkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQE2AhAgAUEUakEuQQEQAiABQRVqEAEkAwsgAEUNABAJIgBFDQAQDSIARQ0ACwJAIABBAUYNAAsgAEEBRgRAQQEhACACKAIIJAQgAiQDBSACQS82AgAgAkEBNgIEIAIjBDYCDCACQQE2AhALIAALswIBBH8jAyICIwQ2AgggAkEUaiQDIwMiASMENgIIIwRBMEECEAMhAyADIwRqJAQjBBAEAkAgA0ECRwRAQQEhACABKAIIJAQgASQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBAjYCECABQRRqQTBBAhACIAFBFmoQASQDCwJAIABFDQBBACEAIwMiASMENgIIIwRBMkEBEAMhAyADIwRqJAQjBBAEAkAgA0EBRwRAQQEhACABKAIIJAQgASQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBATYCECABQRRqQTJBARACIAFBFWoQASQDCyAARQ0ACwJAIAANAAsgAARAQQEhACACKAIIJAQgAiQDBSACQTM2AgAgAkECNgIEIAIjBDYCDCACQQE2AhALIAAL3wEBBX8jAyIBIwQ2AgggAUEUaiQDIwMiACMENgIIAkAjBCMCTg0AIwRBgwRqLQAAIgRBMEkgBEE5S3INACACQQFqIQIjBEEBaiQECyMEEAQCQCACQQBMBEBBASEDIAAoAggkBCAAJAMMAQsgAEEANgIAIABBBzYCBCAAIwQ2AgwgACACNgIQIABBFGogACgCCEGDBGogAhACIAAgAkEUamoQASQDCwJAIAMNAAsgAwRAQQEhAyABKAIIJAQgASQDBSABQTY2AgAgAUEFNgIEIAEjBDYCDCABQQE2AhALIAML3wEBBX8jAyIBIwQ2AgggAUEUaiQDIwMiACMENgIIAkAjBCMCTg0AIwRBgwRqLQAAIgRBMUkgBEE5S3INACACQQFqIQIjBEEBaiQECyMEEAQCQCACQQBMBEBBASEDIAAoAggkBCAAJAMMAQsgAEEANgIAIABBBzYCBCAAIwQ2AgwgACACNgIQIABBFGogACgCCEGDBGogAhACIAAgAkEUamoQASQDCwJAIAMNAAsgAwRAQQEhAyABKAIIJAQgASQDBSABQTw2AgAgAUEINgIEIAEjBDYCDCABQQE2AhALIAMLigMBBX8jAyIDIwQ2AgggA0EUaiQDIwMiACMENgIIAkAjBCMCTg0AIwRBgwRqLQAAIgRB4QBJIARB+gBLcg0AIAFBAWohASMEQQFqJAQLIwQQBAJAIAFBAEwEQEEBIQIgACgCCCQEIAAkAwwBCyAAQQA2AgAgAEEHNgIEIAAjBDYCDCAAIAE2AhAgAEEUaiAAKAIIQYMEaiABEAIgACABQRRqahABJAMLAkAgAkUNAEEAIQJBACEBIwMiACMENgIIAkAjBCMCTg0AIwRBgwRqLQAAIgRBwQBJIARB2gBLcg0AIAFBAWohASMEQQFqJAQLIwQQBAJAIAFBAEwEQEEBIQIgACgCCCQEIAAkAwwBCyAAQQA2AgAgAEEHNgIEIAAjBDYCDCAAIAE2AhAgAEEUaiAAKAIIQYMEaiABEAIgACABQRRqahABJAMLIAJFDQALAkAgAg0ACyACBEBBASECIAMoAggkBCADJAMFIANBxgA2AgAgA0EGNgIEIAMjBDYCDCADQQE2AhALIAILZgECfyMDIgAjBDYCCCAAQRRqJAMCQBAOIgFFDQAQDyIBRQ0ACwJAIAFBAUYNAAsgAUEBRgRAQQEhASAAKAIIJAQgACQDBSAAQcwANgIAIABBBzYCBCAAIwQ2AgwgAEEBNgIQCyABC/YDAQV/IwMiAyMENgIIIANBFGokAyMDIgAjBDYCCCMEQdMAQQIQAyECIAIjBGokBCMEEAQCQCACQQJHBEBBASEBIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0ECNgIQIABBFGpB0wBBAhACIABBFmoQASQDCwJAIAFBAUYNAEEAIQIjAyIAIwQ2AgggACMFNgIMIABBFGokAwNAAkAjBCMCTg0AIwMiBCMENgIIIARBFGokAwJAEAkiAUEBRg0ACyABQQFGBEBBASEBIAQoAggkBCAEJAMFIARBBzYCACAEQQU2AgQgBCMENgIMIARBATYCEAsgAUUNACACQQFqIQIjBEEBaiQEDAELCyAAKAIMJAUgACgCCCACahAEIAAoAgggAmokBCAAQQA2AgAgAEEHNgIEIAAjBDYCDCAAIAI2AhAgAEEUaiAAKAIIQYMEaiACEAIgACACQRRqahABJANBACEBQQANACMDIgAjBDYCCCAAQRRqJAMDQBAJQQFHBEAgAUEBaiIBQQFHDQELCyAAQQw2AgAgAEEGNgIEIAAjBDYCDCAAIAE2AhBBACEBQQANAAsgAUEBRgRAQQEhASADKAIIJAQgAyQDBSADQdUANgIAIANBDjYCBCADIwQ2AgwgA0EDNgIQCyABC9IGAQl/IwMiAyMENgIIIANBFGokAyMDIgAjBDYCCCMEQeMAQQIQAyECIAIjBGokBCMEEAQCQCACQQJHBEBBASEBIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0ECNgIQIABBFGpB4wBBAhACIABBFmoQASQDCwJAIAENACMDIgUjBDYCCCAFQRRqJAMDQEEAIQEjAyIAIwQ2AggjBEHlAEECEAMhAiACIwRqJAQjBBAEAkAgAkECRwRAQQEhASAAKAIIJAQgACQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBAjYCECAAQRRqQeUAQQIQAiAAQRZqEAEkAwsCQCABRQ0AAn9BACECIwMiACMENgIIIAAjBTYCDCAAQRRqJAMDQAJAIwQjAk4NAEEAIQEjAyIEIwQ2AgggBEEUaiQDIwMiBiMENgIIIwRB5wBBAhADIQggCCMEaiQEIwQQBAJAIAhBAkcEQEEBIQEgBigCCCQEIAYkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQI2AhAgBkEUakHnAEECEAIgBkEWahABJAMLAkAgAQ0ACyABBEBBASEBIAQoAggkBCAEJAMFIARBBzYCACAEQQU2AgQgBCMENgIMIARBATYCEAsgAUUNACACQQFqIQIjBEEBaiQEDAELCyAAKAIMJAUgACgCCCACahAEIAJBAEwEQCAAKAIIJAQgACQDQQEMAQsgACgCCCACaiQEIABBADYCACAAQQc2AgQgACMENgIMIAAgAjYCECAAQRRqIAAoAghBgwRqIAIQAiAAIAJBFGpqEAEkA0EACyIBRQ0ACyABRQRAIAdBAWohBwwBCwsgBUESNgIAIAVBBjYCBCAFIwQ2AgwgBSAHNgIQQQAiAQ0AIwMiACMENgIIIwRB5wBBAhADIQIgAiMEaiQEIwQQBAJAIAJBAkcEQEEBIQEgACgCCCQEIAAkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQI2AhAgAEEUakHnAEECEAIgAEEWahABJAMLIAENAAsgAQRAQQEhASADKAIIJAQgAyQDBSADQekANgIAIANBDTYCBCADIwQ2AgwgA0EDNgIQCyABC3QBAn8jAyIAIwQ2AgggAEEUaiQDAkAQEyIBRQ0AEBEiAUUNABAYIgFFDQAQFSIBRQ0ACwJAIAFBAUYNAAsgAUEBRgRAQQEhASAAKAIIJAQgACQDBSAAQfYANgIAIABBCDYCBCAAIwQ2AgwgAEEBNgIQCyABC1cBAn8jAyIAIwQ2AgggAEEUaiQDAkAQEiIBQQFGDQALIAFBAUYEQEEBIQEgACgCCCQEIAAkAwUgAEH+ADYCACAAQQY2AgQgACMENgIMIABBATYCEAsgAQvGCAEJfyMDIgQjBDYCCCAEQRRqJAMjAyMDIgAjBDYCCCMEQYQBQQEQAyEBIAEjBGokBCMEEAQCQCABQQFHBEBBASECIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0EBNgIQIABBFGpBhAFBARACIABBFWoQASQDCyQDAkAgAg0AIwMiBSMENgIIIAVBFGokAwNAQQAhAiMDIgMjBDYCCCADQRRqJAMjAyIAIwQ2AggjBEGFAUEBEAMhASABIwRqJAQjBBAEAkAgAUEBRwRAQQEhAiAAKAIIJAQgACQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBATYCECAAQRRqQYUBQQEQAiAAQRVqEAEkAwsCQCACDQACfyMDIgAjBDYCCCAAIwU2AgwgAEEUaiQDAn9BACIBIwQjAk4NABojBEEBaiQEIAFBAWoLIQEgACgCDCQFIAAoAgggAWoQBCABQQBMBEAgACgCCCQEIAAkA0EBDAELIAAoAgggAWokBCAAQQA2AgAgAEEHNgIEIAAjBDYCDCAAIAE2AhAgAEEUaiAAKAIIQYMEaiABEAIgACABQRRqahABJANBAAsiAg0ACyACBEBBASECIAMoAggkBCADJAMFIANBBzYCACADQQU2AgQgAyMENgIMIANBAjYCEAsCQCACRQ0AAn9BACEBIwMiACMENgIIIAAjBTYCDCAAQRRqJAMCQCMEIwJODQBBACECIwMiAyMENgIIIANBFGokAyMDIgYjBDYCCCMEQYQBQQEQAyEIIAgjBGokBCMEEAQCQCAIQQFHBEBBASECIAYoAggkBCAGJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0EBNgIQIAZBFGpBhAFBARACIAZBFWoQASQDCwJAIAINAAsgAgRAQQEhAiADKAIIJAQgAyQDBSADQQc2AgAgA0EFNgIEIAMjBDYCDCADQQE2AhALIAJFDQAgAUEBaiEBIwRBAWokBAsgACgCDCQFIAAoAgggAWoQBCABQQBMBEAgACgCCCQEIAAkA0EBDAELIAAoAgggAWokBCAAQQA2AgAgAEEHNgIEIAAjBDYCDCAAIAE2AhAgAEEUaiAAKAIIQYMEaiABEAIgACABQRRqahABJANBAAsiAkUNAAsgAkUEQCAHQQFqIQcMAQsLIAVBEjYCACAFQQY2AgQgBSMENgIMIAUgBzYCEEEAIgINACMDIwMiACMENgIIIwRBhAFBARADIQEgASMEaiQEIwQQBAJAIAFBAUcEQEEBIQIgACgCCCQEIAAkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQE2AhAgAEEUakGEAUEBEAIgAEEVahABJAMLJAMgAg0ACyACBEBBASECIAQoAggkBCAEJAMFIARBhgE2AgAgBEELNgIEIAQjBDYCDCAEQQE2AhALIAILuAIBBH8jAyICIwQ2AgggAkEUaiQDIwMiASMENgIIIwRBkQFBBBADIQMgAyMEaiQEIwQQBAJAIANBBEcEQEEBIQAgASgCCCQEIAEkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQQ2AhAgAUEUakGRAUEEEAIgAUEYahABJAMLAkAgAEUNAEEAIQAjAyIBIwQ2AggjBEGVAUEFEAMhAyADIwRqJAQjBBAEAkAgA0EFRwRAQQEhACABKAIIJAQgASQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBBTYCECABQRRqQZUBQQUQAiABQRlqEAEkAwsgAEUNAAsCQCAADQALIAAEQEEBIQAgAigCCCQEIAIkAwUgAkGaATYCACACQQc2AgQgAiMENgIMIAJBATYCEAsgAAu7AQEEfyMDIgAjBDYCCCAAQRRqJAMjAyICIwQ2AggjBEGhAUEEEAMhAyADIwRqJAQjBBAEAkAgA0EERwRAQQEhASACKAIIJAQgAiQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBBDYCECACQRRqQaEBQQQQAiACQRhqEAEkAwsCQCABDQALIAEEQEEBIQEgACgCCCQEIAAkAwUgAEGhATYCACAAQQQ2AgQgACMENgIMIABBATYCEAsgAQuTAQEDfyMDIgEjBDYCCCABQRRqJAMjAyEAEBYiAkEBRgRAIAAkAwUgACAAIABBFGoQBTYCECAAQQA2AgAgAEEHNgIEIAAgACgCEEEUamoQASQDCwJAIAJBAUYNAAsgAkEBRgRAQQEhAiABKAIIJAQgASQDBSABQaUBNgIAIAFBBzYCBCABIwQ2AgwgAUEBNgIQCyACC/0BAQR/IwMiASMENgIIIAFBFGokAyMDIgIjBDYCCCACQRRqJAMCQBALIgBBAUYNACMDIgAjBDYCCCAAQRRqJAMDQBAKQQFGRQRAIANBAWohAwwBCwsgAEESNgIAIABBBjYCBCAAIwQ2AgwgACADNgIQQQAhAEEADQALIABBAUYEQEEBIQAgAigCCCQEIAIkAwUgAkEHNgIAIAJBBTYCBCACIwQ2AgwgAkECNgIQCwJAIABFDQAQFyIARQ0ACwJAIABBAUYNAAsgAEEBRgRAQQEhACABKAIIJAQgASQDBSABQawBNgIAIAFBCTYCBCABIwQ2AgwgAUEBNgIQCyAAC7kBAQR/IwMiACMENgIIIABBFGokAyMDIgIjBDYCCCMEQTVBARADIQMgAyMEaiQEIwQQBAJAIANBAUcEQEEBIQEgAigCCCQEIAIkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQE2AhAgAkEUakE1QQEQAiACQRVqEAEkAwsCQCABDQALIAEEQEEBIQEgACgCCCQEIAAkAwUgAEG1ATYCACAAQQQ2AgQgACMENgIMIABBATYCEAsgAQvtBAEJfyMDIgQjBDYCCCAEQRRqJAMjAyECIwMiBSMENgIIIAVBFGokAwJAEBUiAEEBRg0AIwMiASMENgIIIwRBuQFBARADIQMgAyMEaiQEIwQQBAJAIANBAUcEQEEBIQAgASgCCCQEIAEkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQE2AhAgAUEUakG5AUEBEAIgAUEVahABJAMLIABBAUYNABAWIgBBAUYNACMDIgMjBDYCCCADQRRqJAMDQAJAIwMiASMENgIIIAFBFGokAyMDIgYjBDYCCCMEQboBQQEQAyEIIAgjBGokBCMEEAQCQCAIQQFHBEBBASEAIAYoAggkBCAGJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0EBNgIQIAZBFGpBugFBARACIAZBFWoQASQDCwJAIABBAUYNABAVIgBBAUYNAAsgAEEBRgRAQQEhACABKAIIJAQgASQDBSABQQc2AgAgAUEFNgIEIAEjBDYCDCABQQI2AhALIABBAUYNACAHQQFqIgdBAUcNAQsLIANBDDYCACADQQY2AgQgAyMENgIMIAMgBzYCEEEAIQBBAA0ACyAAQQFGBEBBASEAIAUoAggkBCAFJAMFIAVBBzYCACAFQQU2AgQgBSMENgIMIAVBBDYCEAsgAEEBRgRAIAIkAwUgAiACIAJBFGoQBTYCECACQQA2AgAgAkEHNgIEIAIgAigCEEEUamoQASQDCwJAIABBAUYNAAsgAEEBRgRAQQEhACAEKAIIJAQgBCQDBSAEQbsBNgIAIARBBTYCBCAEIwQ2AgwgBEEBNgIQCyAAC44FAQh/IwMiBSMENgIIIAVBFGokAyMDIQMjAyIGIwQ2AgggBkEUaiQDAkACfyMDIgEjBDYCCCABQRRqJAMDQAJAEAwiAEUNAEEAIQAjAyIEIwQ2AggjBEHAAUEBEAMhByAHIwRqJAQjBBAEAkAgB0EBRwRAQQEhACAEKAIIJAQgBCQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBATYCECAEQRRqQcABQQEQAiAEQRVqEAEkAwsgAEUNAAsgAEEBRkUEQCACQQFqIQIMAQsLIAJBAEwEQCABKAIIJAQgASQDQQEMAQsgAUEYNgIAIAFBBjYCBCABIwQ2AgwgASACNgIQQQALIgBBAUYNAEEAIQQjAyIBIwQ2AgggAUEUaiQDA0ACQBAMIgBFDQAQCiIARQ0AQQAhACMDIgIjBDYCCCMEQcABQQEQAyEHIAcjBGokBCMEEAQCQCAHQQFHBEBBASEAIAIoAggkBCACJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0EBNgIQIAJBFGpBwAFBARACIAJBFWoQASQDCyAARQ0ACyAAQQFGRQRAIARBAWohBAwBCwsgAUESNgIAIAFBBjYCBCABIwQ2AgwgASAENgIQQQAhAEEADQALIABBAUYEQEEBIQAgBigCCCQEIAYkAwUgBkEHNgIAIAZBBTYCBCAGIwQ2AgwgBkECNgIQCyAAQQFGBEAgAyQDBSADIAMgA0EUahAFNgIQIANBADYCACADQQc2AgQgAyADKAIQQRRqahABJAMLAkAgAEEBRg0ACyAAQQFGBEBBASEAIAUoAggkBCAFJAMFIAVBwQE2AgAgBUEENgIEIAUjBDYCDCAFQQE2AhALIAALwQIBB38jAyIBIwQ2AgggAUEUaiQDAkAQGSIAQQFGDQAjAyIDIwQ2AgggA0EUaiQDA0AjAyICIwQ2AgggAkEUaiQDIwNBACEFIwMiACMENgIIIABBFGokAwNAEAhBAUZFBEAgBUEBaiEFDAELCyAAQRI2AgAgAEEGNgIEIAAjBDYCDCAAIAU2AhAkAwJAQQAhAEEADQAQGyIAQQFGDQALIABBAUYEQEEBIQAgAigCCCQEIAIkAwUgAkEHNgIAIAJBBTYCBCACIwQ2AgwgAkEBNgIQCyAAQQFGRQRAIARBAWohBAwBCwsgA0ESNgIAIANBBjYCBCADIwQ2AgwgAyAENgIQQQAhAEEADQALIABBAUYEQEEBIQAgASgCCCQEIAEkAwUgAUHFATYCACABQQY2AgQgASMENgIMIAFBAjYCEAsgAAttAQJ/IwMiACMENgIIIABBFGokAwJAEBwiAUUNABAdIgFFDQAQHiIBRQ0ACwJAIAFBAUYNAAsgAUEBRgRAQQEhASAAKAIIJAQgACQDBSAAQcsBNgIAIABBCDYCBCAAIwQ2AgwgAEEBNgIQCyABC4oCAQV/IwMiAiMENgIIIAJBFGokAyMDIwMiACMENgIIIwRBuQFBARADIQMgAyMEaiQEIwQQBAJAIANBAUcEQEEBIQEgACgCCCQEIAAkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQE2AhAgAEEUakG5AUEBEAIgAEEVahABJAMLJAMCQCABQQFGDQAjAyEAEBkiAUEBRgRAIAAkAwUgACAAIABBFGoQBTYCECAAQQA2AgAgAEEHNgIEIAAgACgCEEEUamoQASQDCyABQQFGDQALIAFBAUYEQEEBIQEgAigCCCQEIAIkAwUgAkHTATYCACACQQ02AgQgAiMENgIMIAJBATYCEAsgAQu/AQEFfyMDIgAjBDYCCCAAQRRqJAMjAyMDIgIjBDYCCCMEQeABQQIQAyEDIAMjBGokBCMEEAQCQCADQQJHBEBBASEBIAIoAggkBCACJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0ECNgIQIAJBFGpB4AFBAhACIAJBFmoQASQDCyQDAkAgAQ0ACyABBEBBASEBIAAoAggkBCAAJAMFIABB4gE2AgAgAEEONgIEIAAjBDYCDCAAQQA2AhALIAELvwEBBX8jAyIAIwQ2AgggAEEUaiQDIwMjAyICIwQ2AggjBEHwAUEDEAMhAyADIwRqJAQjBBAEAkAgA0EDRwRAQQEhASACKAIIJAQgAiQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBAzYCECACQRRqQfABQQMQAiACQRdqEAEkAwskAwJAIAENAAsgAQRAQQEhASAAKAIIJAQgACQDBSAAQfMBNgIAIABBCzYCBCAAIwQ2AgwgAEEANgIQCyABC4YNAQl/IwMiBiMENgIIIAZBFGokAyMDIwMiAiMENgIIIAJBFGokAyMDIgEjBDYCCCMEQf4BQQMQAyEDIAMjBGokBCMEEAQCQCADQQNHBEBBASEAIAEoAggkBCABJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0EDNgIQIAFBFGpB/gFBAxACIAFBF2oQASQDCwJAIABBAUYNAEEAIQEjAyIAIwQ2AgggAEEUaiQDA0AQCEEBRkUEQCABQQFqIQEMAQsLIABBEjYCACAAQQY2AgQgACMENgIMIAAgATYCEEEAIQBBAA0ACyAAQQFGBEBBASEAIAIoAggkBCACJAMFIAJBBzYCACACQQU2AgQgAiMENgIMIAJBAjYCEAskAwJAIABBAUYNABAZIgBBAUYNACMDQQAhAiMDIgAjBDYCCCAAQRRqJAMDQBAIQQFGRQRAIAJBAWohAgwBCwsgAEESNgIAIABBBjYCBCAAIwQ2AgwgACACNgIQJANBACEAQQANAEEAIQQjAyIBIwQ2AgggAUEUaiQDA0ACQCMDIgIjBDYCCCACQRRqJAMjAyMDIgMjBDYCCCMEQYECQQEQAyEFIAUjBGokBCMEEAQCQCAFQQFHBEBBASEAIAMoAggkBCADJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0EBNgIQIANBFGpBgQJBARACIANBFWoQASQDCyQDAkAgAEEBRg0AIwNBACEDIwMiACMENgIIIABBFGokAwNAEAhBAUZFBEAgA0EBaiEDDAELCyAAQRI2AgAgAEEGNgIEIAAjBDYCDCAAIAM2AhAkA0EAIQBBAA0AEBoiAEEBRg0AIwNBACEDIwMiACMENgIIIABBFGokAwNAEAhBAUZFBEAgA0EBaiEDDAELCyAAQRI2AgAgAEEGNgIEIAAjBDYCDCAAIAM2AhAkA0EAIQBBAA0ACyAAQQFGBEBBASEAIAIoAggkBCACJAMFIAJBBzYCACACQQU2AgQgAiMENgIMIAJBATYCEAsgAEEBRg0AIARBAWoiBEEBRw0BCwsgAUEMNgIAIAFBBjYCBCABIwQ2AgwgASAENgIQQQAhAEEADQBBACEFIwMiAyMENgIIIANBFGokAwNAAkAjAyICIwQ2AgggAkEUaiQDIwMjAyIBIwQ2AgggAUEUaiQDIwMiBCMENgIIIwRBggJBARADIQcgByMEaiQEIwQQBAJAIAdBAUcEQEEBIQAgBCgCCCQEIAQkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQE2AhAgBEEUakGCAkEBEAIgBEEVahABJAMLAkAgAEEBRg0AQQAhBCMDIgAjBDYCCCAAQRRqJAMDQBAIQQFGRQRAIARBAWohBAwBCwsgAEESNgIAIABBBjYCBCAAIwQ2AgwgACAENgIQQQAhAEEADQALIABBAUYEQEEBIQAgASgCCCQEIAEkAwUgAUEHNgIAIAFBBTYCBCABIwQ2AgwgAUECNgIQCyQDAkAgAEEBRg0AECsiAEEBRg0ACyAAQQFGBEBBASEAIAIoAggkBCACJAMFIAJBBzYCACACQQU2AgQgAiMENgIMIAJBATYCEAsgAEEBRg0AIAVBAWoiBUEBRw0BCwsgA0EMNgIAIANBBjYCBCADIwQ2AgwgAyAFNgIQQQAhAEEADQAjAyMDIgIjBDYCCCACQRRqJANBACEBIwMiACMENgIIIABBFGokAwNAEAhBAUZFBEAgAUEBaiEBDAELCyAAQRI2AgAgAEEGNgIEIAAjBDYCDCAAIAE2AhACQEEAIQBBAA0AIwMiASMENgIIIwRBgwJBARADIQMgAyMEaiQEIwQQBAJAIANBAUcEQEEBIQAgASgCCCQEIAEkAwwBCyMDQQA2AgAjA0EHNgIEIwMjBDYCDCMDQQE2AhAgAUEUakGDAkEBEAIgAUEVahABJAMLIABBAUYNAEEAIQEjAyIAIwQ2AgggAEEUaiQDA0AQCEEBRkUEQCABQQFqIQEMAQsLIABBEjYCACAAQQY2AgQgACMENgIMIAAgATYCEEEAIQBBAA0ACyAAQQFGBEBBASEAIAIoAggkBCACJAMFIAJBBzYCACACQQU2AgQgAiMENgIMIAJBAzYCEAskAyAAQQFGDQALIABBAUYEQEEBIQAgBigCCCQEIAYkAwUgBkGE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AwsgAUUNAEEAIQEjAyIAIwQ2AggjBEGIA0ECEAMhAiACIwRqJAQjBBAEAkAgAkECRwRAQQEhASAAKAIIJAQgACQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBAjYCECAAQRRqQYgDQQIQAiAAQRZqEAEkAwsgAUUNAEEAIQEjAyIAIwQ2AggjBEGKA0ECEAMhAiACIwRqJAQjBBAEAkAgAkECRwRAQQEhASAAKAIIJAQgACQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBAjYCECAAQRRqQYoDQQIQAiAAQRZqEAEkAwsgAUUNAEEAIQEjAyIAIwQ2AggjBEGMA0ECEAMhAiACIwRqJAQjBBAEAkAgAkECRwRAQQEhASAAKAIIJAQgACQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBAjYCECAAQRRqQYwDQQIQAiAAQRZqEAEkAwsgAUUNAEEAIQEjAyIAIwQ2AggjBEGOA0EBEAMhAiACIwRqJAQjBBAEAkAgAkEBRwRAQQEhASAAKAIIJAQgACQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBATYCECAAQRRqQY4DQQEQAiAAQRVqEAEkAwsgAUUNAEEAIQEjAyIAIwQ2AggjBEGPA0EBEAMhAiACIwRqJAQjBBAEAkAgAkEBRwRAQQEhASAAKAIIJAQgACQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBATYCECAAQRRqQY8DQQEQAiAAQRVqEAEkAwsgAUUNAEEAIQEjAyIAIwQ2AggjBEGQA0EBEAMhAiACIwRqJAQjBBAEAkAgAkEBRwRAQQEhASAAKAIIJAQgACQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBATYCECAAQRRqQZADQQEQAiAAQRVqEAEkAwsgAUUNAEEAIQEjAyIAIwQ2AggjBEGRA0EBEAMhAiACIwRqJAQjBBAEAkAgAkEBRwRAQQEhASAAKAIIJAQgACQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBATYCECAAQRRqQZEDQQEQAiAAQRVqEAEkAwsgAUUNAEEAIQEjAyIAIwQ2AggjBEGSA0EBEAMhAiACIwRqJAQjBBAEAkAgAkEBRwRAQQEhASAAKAIIJAQgACQDDAELIwNBADYCACMDQQc2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JQsIc3RtdF90b3AAQS0LASAAQS4LAQkAQS8LAXcAQTALAg0KAEEyCwEKAEEzCwJubABBNQsBMABBNgsFZGlnaXQAQTsLATEAQTwLCGRpZ2l0X256AEHEAAsBYQBBxQALAUEAQcYACwZsZXR0ZXIAQcwACwdjb21tZW50AEHTAAsCLy8AQdUACw5jb21tZW50X3NpbmdsZQBB4wALAi8qAEHlAAsCXCoAQecACwIqLwBB6QALDWNvbW1lbnRfbXVsdGkAQfYACwhjb25zdGFudABB/gALBnN0cmluZwBBhAELAScAQYUBCwFcAEGGAQsLc3RyaW5nX3RleHQAQZEBCwR0cnVlAEGVAQsFZmFsc2UAQZoBCwdib29sZWFuAEGhAQsEdm9pZABBpQELB2ludGVnZXIAQawBCwlpbnRlZ2VyX3UAQbUBCwR6ZXJvAEG5AQsBLgBBugELAWUAQbsBCwVmbG9hdABBwAELAV8AQcEBCwRuYW1lAEHFAQsGYWNjZXNzAEHLAQsIYWNjZXNzb3IAQdMBCw1hY2Nlc3Nfc3RhdGljAEHgAQsCW10AQeIBCw5hY2Nlc3NfZHluYW1pYwBB8AELAyNbXQBB8wELC2FjY2Vzc19jb21wAEH+AQsDbGV0AEGBAgsBOgBBggILAT0AQYMCCwE7AEGEAgsHZGVjbGFyZQBBiwILBmFzc2lnbgBBkQILCGZ1bmN0aW9uAEGZAgsCZm4AQZsCCwEoAEGcAgsBKQBBnQILCWZ1bmNfaGVhZABBpgILASwAQacCCwlmdW5jX2FyZ3MAQbACCwhmdW5jX2FyZwBBuAILAXsAQbkCCwF9AEG6AgsFYmxvY2sAQb8CCwpibG9ja19zdG10AEHJAgsJZnVuY19jYWxsAEHSAgsOZnVuY19jYWxsX2JvZHkAQeACCwZyZXR1cm4AQeYCCwVfdGFpbABB6wILBXJhaXNlAEHwAgsEZXhwcgBB9AILASEAQfUCCwEtAEH2AgsLZXhwcl9wcmVmaXgAQYEDCwImJgBBgwMLAnx8AEGFAwsBXgBBhgMLAj09AEGIAwsCIT0AQYoDCwI8PQBBjAMLAj49AEGOAwsBPABBjwMLAT4AQZADCwElAEGRAwsBKgBBkgMLAS8AQZMDCwErAEGUAwsCYXMAQZYDCwppbnN0YW5jZW9mAEGgAwsCLT4AQaIDCwpleHByX2luZml4AEGsAwsMZXhwcl9wb3N0Zml4AEG4AwsCI1sAQboDCwFdAEG7AwsKZXhwcl9wYXJhbQBBxQMLCWV4cHJfY2FsbABBzgMLAVsAQc8DCwhleHByX2dldABB1wMLCGV4cHJfYXJnAEHfAwsNZXhwcl9icmFja2V0cwBB7AMLCGFyZ19saXN0AEH0AwsCaWYAQfYDCwRlbHNlAEH6AwsJc3RhdGVtZW50"); +let _rawWasm = _Shared.DecodeBase64("AGFzbQEAAAABIQZgAAF/YAF/AGABfwF/YAN/f38AYAN/f38Bf2ACf38BfwIQAQJqcwlwcmludF9pMzIAAQNEQwACAwQBBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBAEBAQoGIAZ/AEGSBQt/AUEAC38BQQALfwFBAAt/AUEAC38BQQALB+8FQgZtZW1vcnkCAAVpbnB1dAMABXJlYWNoAwULaW5wdXRMZW5ndGgDAgVfaW5pdAABB3Byb2dyYW0ABwhzdG10X3RvcAAIAXcACQJubAAKBWRpZ2l0AAsIZGlnaXRfbnoADAZsZXR0ZXIADQl0ZXJtaW5hdGUADgdjb21tZW50AA8OY29tbWVudF9zaW5nbGUAEA1jb21tZW50X211bHRpABEIY29uc3RhbnQAEgZzdHJpbmcAEwtzdHJpbmdfdGV4dAAUB2Jvb2xlYW4AFQR2b2lkABYHaW50ZWdlcgAXCWludGVnZXJfdQAYBHplcm8AGQVmbG9hdAAaBG5hbWUAGwZhY2Nlc3MAHAhhY2Nlc3NvcgAdDWFjY2Vzc19zdGF0aWMAHg5hY2Nlc3NfZHluYW1pYwAfC2FjY2Vzc19jb21wACAHZGVjbGFyZQAhBmFzc2lnbgAiCXN0cnVjdHVyZQAjC3N0cnVjdF90eXBlACQLc3RydWN0X3N0bXQAJQtzdHJ1Y3RfYXR0cgAmDXN0cnVjdF9zcHJlYWQAJwljb250YWluZXIAKA5jb250YWluZXJfaXRlbQApDWNvbnRhaW5lcl9tYXAAKg9jb250YWluZXJfdmFsdWUAKwhmdW5jdGlvbgAsCWZ1bmNfaGVhZAAtCWZ1bmNfYXJncwAuCGZ1bmNfYXJnAC8FYmxvY2sAMApibG9ja19zdG10ADEJZnVuY19jYWxsADIOZnVuY19jYWxsX2JvZHkAMwZyZXR1cm4ANAVyYWlzZQA1BGV4cHIANgtleHByX3ByZWZpeAA3CmV4cHJfaW5maXgAOAxleHByX3Bvc3RmaXgAOQpleHByX3BhcmFtADoJZXhwcl9jYWxsADsIZXhwcl9nZXQAPAlleHByX2xvYW4APQhleHByX2FyZwA+CGV4cHJfdmFsAD8NZXhwcl9icmFja2V0cwBACGFy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AyQDDAELIwNBADYCACMDQQc2AgQjAyMENgIMIwNBATYCECADQRRqQYsCQQEQAyADQRVqEAIkAwskAwJAIABBAUYNACMDQQAhAyMDIgAjBDYCCCAAQRRqJAMDQBAJQQFGRQRAIANBAWohAwwBCwsgAEESNgIAIABBBjYCBCAAIwQ2AgwgACADNgIQJANBACEAQQANABAcIgBBAUYNACMDQQAhAyMDIgAjBDYCCCAAQRRqJAMDQBAJQQFGRQRAIANBAWohAwwBCwsgAEESNgIAIABBBjYCBCAAIwQ2AgwgACADNgIQJANBACEAQQANAAsgAEEBRgRAQQEhACACKAIIJAQgAiQDBSACQQc2AgAgAkEFNgIEIAIjBDYCDCACQQE2AhALIABBAUYNACAEQQFqIgRBAUcNAQsLIAFBDDYCACABQQY2AgQgASMENgIMIAEgBDYCEEEAIQBBAA0AQQAhBSMDIgMjBDYCCCADQRRqJAMDQAJAIwMiAiMENgIIIAJBFGokAyMDIwMiASMENgIIIAFBFGokAyMDIgQjBDYCCCMEQYwCQQEQBCEHIAcjBGokBCMEEAUCQCAHQQFHBEBBASEAIAQoAggkBCAEJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0EBNgIQIARBFGpBjAJBARADIARBFWoQAiQDCwJAIABBAUYNAEEAIQQjAyIAIwQ2AgggAEEUaiQDA0AQCUEBRkUEQCAEQQFqIQQMAQsLIABBEjYCACAAQQY2AgQgACMENgIMIAAgBDYCEEEAIQBBAA0ACyAAQQFGBEBBASEAIAEoAggkBCABJAMFIAFBBzYCACABQQU2AgQgASMENgIMIAFBAjYCEAskAwJAIABBAUYNABA2IgBBAUYNAAsgAEEBRgRAQQEhACACKAIIJAQgAiQDBSACQQc2AgAgAkEFNgIEIAIjBDYCDCACQQE2AhALIABBAUYNACAFQQFqIgVBAUcNAQsLIANBDDYCACADQQY2AgQgAyMENgIMIAMgBTYCEEEAIQBBAA0AIwMjAyICIwQ2AgggAkEUaiQDQQAhASMDIgAjBDYCCCAAQRRqJAMDQBAJQQFGRQRAIAFBAWohAQwBCwsgAEESNgIAIABBBjYCBCAAIwQ2AgwgACABNgIQAkBBACEAQQANACMDIgEjBDYCCCMEQcwAQQEQBCED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ASMDIgAjBDYCCCMEQYQEQQIQBCECIAIjBGokBCMEEAUCQCACQQJHBEBBASEBIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0ECNgIQIABBFGpBhARBAhADIABBFmoQAiQDCyABRQ0AQQAhASMDIgAjBDYCCCMEQYYEQQIQBCECIAIjBGokBCMEEAUCQCACQQJHBEBBASEBIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0ECNgIQIABBFGpBhgRBAhADIABBFmoQAiQDCyABRQ0AQQAhASMDIgAjBDYCCCMEQYgEQQIQBCECIAIjBGokBCMEEAUCQCACQQJHBEBBASEBIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0ECNgIQIABBFGpBiARBAhADIABBFmoQAiQDCyABRQ0AQQAhASMDIgAjBDYCCCMEQYoEQQIQBCECIAIjBGokBCMEEAUCQCACQQJHBEBBASEBIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0ECNgIQIABBFGpBigRBAhADIABBFmoQAiQDCyABRQ0AQQAhASMDIgAjBDYCCCMEQYwEQQEQBCECIAIjBGokBCMEEAUCQCACQQFHBEBBASEBIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0EBNgIQIABBFGpBjARBARADIABBFWoQAiQDCyABRQ0AQQAhASMDIgAjBDYCCCMEQY0EQQEQBCECIAIjBGokBCMEEAUCQCACQQFHBEBBASEBIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0EBNgIQIABBFGpBjQRBARADIABBFWoQAiQDCyABRQ0AQQAhASMDIgAjBDYCCCMEQY4EQQEQBCECIAIjBGokBCMEEAUCQCACQQFHBEBBASEBIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2AgwjA0EBNgIQIABBFGpBjgRBARADIABBFWoQAiQDCyABRQ0AQQAhASMDIgAjBDYCCCMEQY8EQQEQBCECIAIjBGokBCMEEAUCQCACQQFHBEBBASEBIAAoAggkBCAAJAMMAQsjA0EANgIAIwNBBzYCBCMDIwQ2Agwj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"); let _ctx = null; if (typeof window === 'undefined') { _ctx = new WebAssembly.Instance( @@ -42,6 +42,9 @@ export function Parse_Digit_nz (data, refMapping = true) { export function Parse_Letter (data, refMapping = true) { return _Shared.Parse(_ctx, data, refMapping, "letter"); } +export function Parse_Terminate (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "terminate"); +} export function Parse_Comment (data, refMapping = true) { return _Shared.Parse(_ctx, data, refMapping, "comment"); } @@ -102,6 +105,33 @@ export function Parse_Declare (data, refMapping = true) { export function Parse_Assign (data, refMapping = true) { return _Shared.Parse(_ctx, data, refMapping, "assign"); } +export function Parse_Structure (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "structure"); +} +export function Parse_Struct_type (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "struct_type"); +} +export function Parse_Struct_stmt (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "struct_stmt"); +} +export function Parse_Struct_attr (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "struct_attr"); +} +export function Parse_Struct_spread (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "struct_spread"); +} +export function Parse_Container (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "container"); +} +export function Parse_Container_item (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "container_item"); +} +export function Parse_Container_map (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "container_map"); +} +export function Parse_Container_value (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "container_value"); +} export function Parse_Function (data, refMapping = true) { return _Shared.Parse(_ctx, data, refMapping, "function"); } @@ -153,9 +183,15 @@ export function Parse_Expr_call (data, refMapping = true) { export function Parse_Expr_get (data, refMapping = true) { return _Shared.Parse(_ctx, data, refMapping, "expr_get"); } +export function Parse_Expr_loan (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "expr_loan"); +} export function Parse_Expr_arg (data, refMapping = true) { return _Shared.Parse(_ctx, data, refMapping, "expr_arg"); } +export function Parse_Expr_val (data, refMapping = true) { + return _Shared.Parse(_ctx, data, refMapping, "expr_val"); +} export function Parse_Expr_brackets (data, refMapping = true) { return _Shared.Parse(_ctx, data, refMapping, "expr_brackets"); } diff --git a/source/cli.ts b/source/cli.ts index 3fcc745..14fd007 100644 --- a/source/cli.ts +++ b/source/cli.ts @@ -5,7 +5,9 @@ import { existsSync } from "https://deno.land/std@0.201.0/fs/mod.ts"; import * as colors from "https://deno.land/std@0.201.0/fmt/colors.ts"; import Function from "~/compiler/function.ts"; +import Package from "~/compiler/package.ts"; import Project from "~/compiler/project.ts"; +import { DisplayTimers, TimerStart, TimerEnd } from "~/helper.ts"; import { Panic } from "~/helper.ts"; if (Deno.args.includes("--version")) { @@ -24,29 +26,35 @@ if (!existsSync(root)) { Panic(`${colors.red("Error")}: Cannot find entry ${colors.cyan(relative(cwd, root))}`); } -const project = new Project(root); -if (project.failed) { - Panic(`Compilation ${colors.red("Failed")}`); -} +const project = new Project(); +const mainPck = new Package(project, root); +if (project.failed) Panic(`Compilation ${colors.red("Failed")}`); -const mainFile = project.import(root); +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(); +TimerEnd("compilation"); +if (project.failed) Panic(`Compilation ${colors.red("Failed")}`); +if (!mainFunc.ref) Panic(`Main function not compiled correctly`); +project.module.exportFunction("_start", mainFunc.ref); +project.module.exportFunction("main", mainFunc.ref); +project.module.startFunction(mainFunc.ref); + +TimerStart("serialize"); await Deno.writeFile("out.wasm", project.module.toBinary()); -console.log(` out: ${"out.wasm"}`); +TimerEnd("serialize"); +TimerStart("wasm2wat"); const command = new Deno.Command( "wasm2wat", - { - args: ["-v", "out.wasm", "-o", "out.wat"] - } + { args: ["-v", "out.wasm", "-o", "out.wat"] } ); const { code, stdout, stderr } = await command.output(); if (code !== 0) { @@ -54,3 +62,9 @@ if (code !== 0) { console.error(new TextDecoder().decode(stderr)); Deno.exit(1); } +TimerEnd("wasm2wat"); +console.log(new TextDecoder().decode(stdout)); + +console.log(` out: ${"out.wasm"}\n`); + +if (Deno.args.includes("--time")) DisplayTimers(); diff --git a/source/compiler/codegen/registers.ts b/source/compiler/codegen/allocation/registers.ts similarity index 100% rename from source/compiler/codegen/registers.ts rename to source/compiler/codegen/allocation/registers.ts diff --git a/source/compiler/codegen/allocation/stack.ts b/source/compiler/codegen/allocation/stack.ts new file mode 100644 index 0000000..41a9ec7 --- /dev/null +++ b/source/compiler/codegen/allocation/stack.ts @@ -0,0 +1,355 @@ +import { AssertUnreachable, AlignUpInteger, AlignDownInteger, LatentValue } from "~/helper.ts"; + +/** + * Used for calculating the relative stack location of variables within a function stack + * + * Before branching behaviour a stack.checkpoint must be formed + * After a branch ends you checkpoint.rewind + * Then once all branches have been resolved you checkpoint.restore + * + * This will boil up any stack values which are originally spawned in a branch, but then continue existing into the parent's stack + * This will error if any non primary branch has remaining allocations on rewind which have not been aliased to an allocation in the primary stack + */ + +class Region { + head: number; + tail: number; + + constructor(start: number, end: number) { + this.head = start; + this.tail = end; + } +} + +enum StackEventType { allocation, free }; +class StackEvent { + type: StackEventType; + entity: StackAllocation | StackCheckpoint; + ignore: boolean; + + constructor(born: StackEventType, entity: StackAllocation | StackCheckpoint) { + this.type = born; + this.entity = entity; + this.ignore = false; + } +} + + +class StackCheckpoint { + private owner: StackAllocator; + readonly previous?: StackCheckpoint; + + private timeline: StackEvent[]; + private local: StackAllocation[]; + private firstRewind: boolean; + + constructor(owner: StackAllocator, prev?: StackCheckpoint) { + this.owner = owner; + this.previous = prev; + this.firstRewind = true; + this.timeline = []; + this.local = []; + } + + allocate(size: number, align: number) { + const alloc = new StackAllocation(this, size, align); + this.timeline.push(new StackEvent(StackEventType.allocation, alloc)); + this.local.push(alloc); + + return alloc; + } + + free(alloc: StackAllocation) { + const index = this.local.findIndex(l => l === alloc); + + this.timeline.push(new StackEvent(StackEventType.free, alloc)); + + if (index === -1) console.warn(`Warn: Attempting to free${alloc?.tag ? ` tag[${alloc?.tag}]` : ""} non-local allocation`); + else this.local.splice(index, 1); + } + + private bind(alloc: StackAllocation) { + this.timeline.push(new StackEvent(StackEventType.allocation, alloc)); + this.local.push(alloc); + alloc._move(this); + } + + hasAllocations() { + return this.local.length > 0; + } + + getAllocationCount() { + return this.local.length; + } + + getAllocations() { + return this.local.map(x => x.tag || ".unknown"); + } + + rewind() { + if (!this.previous) throw new Error("Cannot rewind root StackCheckpoint"); + + if (this.firstRewind) { + for (const alloc of this.local) { + if (alloc.isAlias()) continue; + + this.previous.bind(alloc); + + // Ignore the allocation of this in the timeline + // As it's been pushed up + for (let i=this.timeline.length-1; 0 <= i; i--) { + if (this.timeline[i].entity === alloc) { + this.timeline[i].ignore = true; + break; + } + } + } + this.local.length = 0; + } else { + for (const alloc of this.local) { + if (!alloc.isAlias()) throw new Error("Branching allocations not resolved by prior aliasing"); + } + this.local.length = 0; + } + } + + restore() { + if (this.local.length !== 0) throw new Error("Must run rewind before restore"); + + // Merge up timelines + if (this.previous) { + for (const evt of this.timeline) { + if (evt.ignore) continue; + this.previous.timeline.push(evt); + } + } + + this.owner.restore(this); + } + + events() { + return this.timeline.values(); + } +} + +export class StackAllocator { + private checkpointRef: StackCheckpoint; + private latentSize: LatentValue; // Final size of the stack + + constructor() { + this.checkpointRef = new StackCheckpoint(this); + this.latentSize = new LatentValue(); + } + + allocate(size: number, align = 1) { + if (!this.checkpointRef) throw new Error(`StackAllocator state error`); + return this.checkpointRef.allocate(size, align); + } + + checkpoint() { + this.checkpointRef = new StackCheckpoint(this, this.checkpointRef); + return this.checkpointRef; + } + + restore(checkpoint: StackCheckpoint) { + if (this.checkpointRef != checkpoint) throw new Error(`In correct stack checkpoint restore order`); + if (!checkpoint.previous) throw new Error(`Cannot restore from a root checkpoint`); + this.checkpointRef = checkpoint.previous; + } + + getSize() { + this.resolve(); + return this.latentSize.get(); + } + + getLatentSize() { + return this.latentSize; + } + + getAllocationCount() { + return this.checkpointRef.getAllocationCount(); + } + + resolve() { + if (this.checkpointRef.hasAllocations()) throw new Error( + `Stack leak: ${this.checkpointRef.getAllocationCount()} stack values are still allocated after stack frame end ` + + this.checkpointRef.getAllocations() + ); + + const table: Region[] = []; + let offset = 0; + let size = 0; + + function allocate(alloc: StackAllocation): void { + // Already allocated, likely due to stack promotion + if (alloc.inUse) throw new Error("Double allocation on stack allocation"); + if (alloc.isAlias()) return; + + alloc.inUse = true; + + // short circuit + if (alloc.size == 0) return alloc.getOffset().resolve(offset); + + // Look for the first available region + for (let i=0; i chunkSize) continue; + + let start, end: number; + let placed = false; + if (paddingFront <= paddingBack) { + start = head; + end = start + alloc.size + + if (paddingFront == 0) { + region.head += alloc.size; + placed = true; + } + } else { + end = tail; + start = end - alloc.size; + + if (paddingBack == 0) { + region.tail -= alloc.size; + placed = true; + } + } + + if (!placed) { + table.splice(i+1, 0, new Region(end, region.tail)); + region.tail = start; + } + + alloc.getOffset().resolve(start); + return; + } + + // Extend the stack to fit the new allocation + const head = AlignUpInteger(offset, alloc.align); + const padding = head-offset; + if (padding > 0) table.push(new Region(offset, head)); + + alloc.getOffset().resolve(head); + offset += alloc.size + padding; + size = Math.max(size, offset); + + } + + function free(alloc: StackAllocation): void { + if (!alloc.inUse) { + console.warn("Warn: Double free on stack allocation"); + return + } + if (alloc.isAlias()) return; + + alloc.inUse = false; + if (alloc.size == 0) return; + + const head = alloc.getOffset().get(); + const tail = head + alloc.size; + + if (table.length === 0) { + table.push(new Region(head, tail)); + return; + } + + let chunkI = table.findIndex(chunk => chunk.head >= head); + if (chunkI == -1) chunkI = table.length-1; + + const prev = table[chunkI]; + const next = table[chunkI+1]; + let found = false; + if (prev.tail === head) { + prev.tail = tail; + found = true; + return; + } + + if (next && tail === next.head) { + next.head = head; + found = true; + } + + if (found) { // attempt defrag + if (next && prev.tail == next.head) { + prev.tail = next.tail; + table.splice(chunkI+1, 1); + } + } else { // make new frag + table.splice(chunkI+1, 0, new Region(head, tail)); + } + } + + for (const event of this.checkpointRef.events()) { + if (!(event.entity instanceof StackAllocation)) continue; + switch (event.type) { + case StackEventType.allocation: allocate(event.entity); break; + case StackEventType.free: free(event.entity); break; + default: AssertUnreachable(event.type); + } + } + + this.latentSize.resolve(size); + } +} + +export class StackAllocation { + private alias?: StackAllocation; + private owner: StackCheckpoint; + + private latent: LatentValue; + readonly align: number; + readonly size: number; + inUse: boolean; + + // for debug purposes + tag?: string; + + constructor(owner: StackCheckpoint, size: number, align: number = 1) { + this.latent = new LatentValue(); + this.owner = owner; + this.inUse = true; + this.alias = undefined; + this.align = align; + this.size = size; + } + + isAlias() { + return !!this.alias; + } + + getOffset() { + return this.alias + ? this.alias.latent + : this.latent; + } + + _move(to: StackCheckpoint) { + this.owner = to; + } + free(): void { + if (this.alias) throw new Error("Cannot free an aliased allocation, please free the primary"); + + this.inUse = false; + this.owner.free(this); + } + + makeAlias(of: StackAllocation) { + // Get to the root + while (of.alias) of = of.alias; + this.alias = of; + + if (this.alias.size != this.size) throw new Error("Cannot alias a stack allocation of a different size"); + this.inUse = false; + } +} \ No newline at end of file diff --git a/source/compiler/codegen/context.ts b/source/compiler/codegen/context.ts index 758a80c..87ebe6d 100644 --- a/source/compiler/codegen/context.ts +++ b/source/compiler/codegen/context.ts @@ -1,20 +1,25 @@ import * as colors from "https://deno.land/std@0.201.0/fmt/colors.ts"; import type * as Syntax from "~/bnf/syntax.d.ts"; -import type { File, Namespace } from "~/compiler/file.ts"; -import type { Scope } from "./scope.ts"; +import type { Scope } from "~/compiler/codegen/scope.ts"; +import type { File } from "~/compiler/file.ts"; import * as banned from "~/compiler/codegen/banned.ts"; -import { Intrinsic, i16, i8, u16, u8 } from "~/compiler/intrinsic.ts"; +import Structure from "~/compiler/structure.ts"; +import Function from "~/compiler/function.ts"; +import { BasePointerType, LinearType, OperandType, SolidType, IsRuntimeType, IsSolidType } from "~/compiler/codegen/expression/type.ts"; +import { IntrinsicType, IntrinsicValue, none, never } 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"; -import { OperandType } from "~/compiler/codegen/expression/operand.ts"; +import { ReferenceRange } from "~/parser.ts"; import { CompileExpr } from "~/compiler/codegen/expression/index.ts"; -import { none, never } from "~/compiler/intrinsic.ts"; +import { Variable } from "~/compiler/codegen/variable.ts"; import { Block } from "~/wasm/instruction/control-flow.ts"; export class Context { file: File; + function: Function; scope: Scope; done: boolean; @@ -22,7 +27,8 @@ export class Context { block: AnyInstruction[]; - constructor(file: File, scope: Scope, block: AnyInstruction[]) { + constructor(file: File, func: Function, scope: Scope, block: AnyInstruction[]) { + this.function = func; this.raiseType = none; this.scope = scope; this.block = block; @@ -59,7 +65,7 @@ export class Context { } child() { - return new Context(this.file, this.scope.child(), []); + return new Context(this.file, this.function, this.scope.child(), []); } cleanup() { @@ -74,103 +80,193 @@ function CompileDeclare(ctx: Context, syntax: Syntax.Term_Declare) { const type = syntax.value[1].value[0]; const expr = syntax.value[2].value[0]; - if (banned.namespaces.includes(name)) - Panic(`${colors.red("Error")}: You're not allowed to call a variable ${name}\n`, { - path: ctx.file.path, - name: ctx.file.name, - ref: syntax.value[0].value[0].ref - }) - let typeRef: Namespace | null = null; + + if (banned.namespaces.includes(name)) Panic( + `${colors.red("Error")}: You're not allowed to call a variable ${name}\n`, + { path: ctx.file.path, name: ctx.file.name, ref: syntax.value[0].value[0].ref } + ) + + if (ctx.scope.hasVariable(name)) Panic( + `${colors.red("Error")}: Variable ${name} is already declared\n`, + { path: ctx.file.path, name: ctx.file.name, ref: syntax.ref } + ); + + + // Init variable when type given + let expectType: SolidType | undefined = undefined; + let variable: Variable | undefined = undefined; if (type) { - typeRef = ctx.file.get(type.value[0]); - - if (typeRef === null || !(typeRef instanceof Intrinsic)) - Panic(`${colors.red("Error")}: Cannot find type\n`, { - path: ctx.file.path, - name: ctx.file.name, - ref: type.ref - }) - - if (typeRef === i8 || typeRef === u8 || typeRef === i16 || typeRef === u16) - Panic(`${colors.red("Error")}: Cannot explicitly use virtual integer types\n`, { - path: ctx.file.path, - name: ctx.file.name, - ref: type.ref - }) + const namespace = ctx.file.get(type.value[0]); + + if (namespace === null) Panic( + `${colors.red("Error")}: Cannot find type\n`, + { path: ctx.file.path, name: ctx.file.name, ref: type.ref } + ) + + 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 } + ); + + let linear: LinearType; + if (namespace instanceof IntrinsicType) { + const alloc = ctx.scope.stack.allocate(namespace.size, namespace.align); + linear = LinearType.make(namespace.value, alloc, ctx.file.owner.project.stackBase); + } else if (namespace instanceof Structure) { + namespace.link(); + const alloc = ctx.scope.stack.allocate(namespace.size, namespace.align); + linear = LinearType.make(namespace, alloc, ctx.file.owner.project.stackBase); + } else AssertUnreachable(namespace); + + variable = ctx.scope.registerVariable(name, linear, type.ref); + linear.markConsumed(syntax.ref); // uninited + linear.pin(); + + expectType = namespace; } - if (!expr) { - if (!typeRef) - Panic(`${colors.red("Error")}: Declared variables must have an explicit or an inferred type\n`, { - path: ctx.file.path, - name: ctx.file.name, - ref: syntax.ref - }) - - const variable = ctx.scope.registerVariable(name, typeRef, syntax.ref); - if (!variable) - Panic(`${colors.red("Error")}: Variable ${name} is already declared\n`, { - path: ctx.file.path, - name: ctx.file.name, - ref: syntax.ref - }); + // No assigned value on declaration + if (!expr){ + if (!variable) Panic( + `${colors.red("Error")}: Declared variables must have an explicit or an inferred type\n`, + { path: ctx.file.path, name: ctx.file.name, ref: syntax.ref } + ) return; } const value = expr.value[0]; - const resolveType = CompileExpr(ctx, value, typeRef || undefined); - if (!typeRef && !resolveType) Panic( - `${colors.red("Error")}: Unable to determine type\n`, - { path: ctx.file.path, name: ctx.file.name, ref: syntax.ref } + const resolveType = CompileExpr(ctx, value, expectType); + + if (!IsRuntimeType(resolveType)) Panic( + `${colors.red("Error")}: Cannot assign to a non solid type\n`, + { path: ctx.file.path, name: ctx.file.name, ref: value.ref } ); - if (typeRef && resolveType !== typeRef) Panic( - `${colors.red("Error")}: type ${typeRef.name} != type ${resolveType.name}\n`, - { path: ctx.file.path, name: ctx.file.name, ref: type?.ref || syntax.ref } - ) - if (!(resolveType instanceof Intrinsic)) Panic( - `${colors.red("Error")}: Cannot assign variable to non-intrinsic type\n`, - { path: ctx.file.path, name: ctx.file.name, ref: type?.ref || syntax.ref } - ) - const variable = ctx.scope.registerVariable(name, typeRef || resolveType, syntax.ref); - if (!variable) - Panic(`${colors.red("Error")}: Variable ${name} is already declared\n`, { - path: ctx.file.path, - name: ctx.file.name, - ref: syntax.ref - }); - variable.markDefined(); + // Post init variable, when derived from expression + if (!variable) { + let linear: LinearType; + if (resolveType instanceof IntrinsicValue) { + const alloc = ctx.scope.stack.allocate(resolveType.type.size, resolveType.type.align); + linear = LinearType.make(resolveType.type.value, alloc, ctx.file.owner.project.stackBase); + } else if (resolveType instanceof LinearType) { + linear = resolveType; + } else AssertUnreachable(resolveType); + + variable = ctx.scope.registerVariable(name, linear, syntax.ref); + linear.markConsumed(syntax.ref); // uninited + linear.pin(); + } + - ctx.block.push(Instruction.local.set(variable.register.ref)); + Assign(ctx, variable.type, resolveType, syntax.ref); } function CompileAssign(ctx: Context, syntax: Syntax.Term_Assign) { - const name = syntax.value[0].value[0].value; + const accessors = syntax.value[0].value[1]; + const name = syntax.value[0].value[0].value[0].value; const value = syntax.value[1]; const variable = ctx.scope.getVariable(name, false); - if (!variable) - Panic(`${colors.red("Error")}: Undeclared variable ${name}\n`, { - path: ctx.file.path, - name: ctx.file.name, - ref: syntax.ref - }); - - const resolveType = CompileExpr(ctx, value, variable.type); - if (resolveType !== variable.type) Panic( - `${colors.red("Error")}: type ${variable.name} != type ${resolveType.name}\n`, + if (!variable) Panic( + `${colors.red("Error")}: Undeclared variable ${name}\n`, { path: ctx.file.path, name: ctx.file.name, ref: syntax.ref } ); - if (!(resolveType instanceof Intrinsic)) Panic( - `${colors.red("Error")}: Cannot assign variable to non-intrinsic type\n`, - { path: ctx.file.path, name: ctx.file.name, ref: syntax.ref } + let target = variable.type; + for (const syn of accessors.value) { + const access = syn.value[0].value[0]; + + switch (access.type) { + case "access_static": { + const name = access.value[0].value; + const attr = target.get(name); + if (!attr) Panic( + `${colors.red("Error")}: Unknown attribute ${name} on ${target.getTypeName()}\n`, + { path: ctx.file.path, name: ctx.file.name, ref: access.ref } + ); + + target = attr; + break; + } + default: Panic( + `${colors.red("Error")}: Access type currently not supported\n`, + { path: ctx.file.path, name: ctx.file.name, ref: access.ref } + ) + } + } + + if (target.type instanceof IntrinsicValue) { + 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); + } + } + + const expr = CompileExpr(ctx, value, target.getBaseType()); + Assign(ctx, target, expr, syntax.ref); +} + + +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 } ) - ctx.block.push(Instruction.local.set(variable.register.ref)); - variable.markDefined(); + const error = () => Panic( + `${colors.red("Error")}: ${target.type.getTypeName()} != ${expr.getTypeName()}\n`, + { path: ctx.file.path, name: ctx.file.name, ref: ref } + ); + + 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; + } + + if (!(expr instanceof LinearType)) AssertUnreachable(expr); + + if (target.type != expr.type) error(); + + // TODO: drop previous value + + // Destination address + ResolveLinearType(ctx, target, ref, false); + // Source address + ResolveLinearType(ctx, expr, ref, false); + + // Transfer + ctx.block.push(Instruction.const.i32(target.getSize())); + ctx.block.push(Instruction.copy(0, 0)); + + // Duplicate the struct's linear state over + target.infuse(expr); + + // Clean up the expr generated struct + expr.dispose(); + + return; + } @@ -184,22 +280,89 @@ function CompileStatement(ctx: Context, syntax: Syntax.Term_Statement) { +function CompileReturn(ctx: Context, syntax: Syntax.Term_Return): typeof never { + const maybe_expr = syntax.value[1].value[0]; + const isTail = syntax.value[0].value.length > 0; + const ref = syntax.ref; + if (isTail) Panic( + `${colors.red("Error")}: Unimplemented tail call return\n`, + { path: ctx.file.path, name: ctx.file.name, ref } + ); -function CompileReturn(ctx: Context, syntax: Syntax.Term_Return) { - const isTail = syntax.value[0].value.length > 0; - const value = syntax.value[1]; + // Guard: return none + if (ctx.function.returns.length === 0) { + if (maybe_expr) Panic( + `${colors.red("Error")}: This function should have no return value\n`, + { path: ctx.file.path, name: ctx.file.name, ref } + ); + + ctx.scope.cleanup(true); + ctx.block.push(Instruction.return()); + ctx.done = true; + return never; + } - if (isTail) Panic(`${colors.red("Error")}: Unimplemented tail call return\n`, { - path: ctx.file.path, - name: ctx.file.name, - ref: syntax.ref - }); + if (!maybe_expr) Panic( + `${colors.red("Error")}: Missing return expression\n`, + { path: ctx.file.path, name: ctx.file.name, ref } + ); - CompileExpr(ctx, value); - ctx.scope.cleanup(); + if (ctx.function.returns.length !== 1) Panic( + `${colors.red("Error")}: Multi value return is currently not supported\n`, + { path: ctx.file.path, name: ctx.file.name, ref } + ); + + const goal = ctx.function.returns[0]; + const expr = CompileExpr(ctx, maybe_expr, goal.type || none); + if (!IsRuntimeType(expr)) Panic( + `${colors.red("Error")}: You can only return a runtime type, not ${colors.cyan(expr.getTypeName())}\n`, + { path: ctx.file.path, name: ctx.file.name, ref } + ); + + // Guard: simple intrinsic return + if (goal.type instanceof IntrinsicType) { + if (!goal.type.like(expr)) Panic( + `${colors.red("Error")}: Return type miss-match, expected ${colors.cyan(goal.type.getTypeName())} got ${colors.cyan(expr.getTypeName())}\n`, + { path: ctx.file.path, name: ctx.file.name, ref } + ); + + if (expr instanceof LinearType) { + ResolveLinearType(ctx, expr, ref, true); + expr.dispose(); + }; + + ctx.scope.cleanup(true); + ctx.block.push(Instruction.return()); + ctx.done = true; + return never; + } + + if (expr instanceof IntrinsicValue || !expr.like(goal.type)) Panic( + `${colors.red("Error")}: Return type miss-match, expected ${colors.cyan(goal.type.getTypeName())} got ${colors.cyan(expr.getTypeName())}\n`, + { path: ctx.file.path, name: ctx.file.name, ref } + ); + + const target = ctx.scope.getVariable("return", true); + if (!target) throw new Error("Missing return variable"); + + // Destination address + ResolveLinearType(ctx, target.type, maybe_expr.ref, false); + + // Source Address + ResolveLinearType(ctx, expr, maybe_expr.ref, true); + + // Transfer + ctx.block.push(Instruction.const.i32(goal.type.size)); + ctx.block.push(Instruction.copy(0, 0)); + + expr.dispose(); + + ctx.scope.cleanup(true); ctx.block.push(Instruction.return()); ctx.done = true; + + return never; } function CompileRaise(ctx: Context, syntax: Syntax.Term_Raise) { diff --git a/source/compiler/codegen/expression/constant.ts b/source/compiler/codegen/expression/constant.ts index eb10348..bcf3afb 100644 --- a/source/compiler/codegen/expression/constant.ts +++ b/source/compiler/codegen/expression/constant.ts @@ -1,12 +1,15 @@ import * as colors from "https://deno.land/std@0.201.0/fmt/colors.ts"; import type * as Syntax from "~/bnf/syntax.d.ts"; -import { Intrinsic, bool, u8, i8, u16, i16, u32, i32, u64, i64, f32, f64 } from "~/compiler/intrinsic.ts"; +import { IntrinsicType, bool, u8, i8, u16, i16, u32, i32, u64, i64, f32, f64 } from "~/compiler/intrinsic.ts"; import { AssertUnreachable, Panic } from "~/helper.ts"; +import { IntrinsicValue } from "~/compiler/intrinsic.ts"; import { Instruction } from "~/wasm/index.ts"; +import { SolidType } from "~/compiler/codegen/expression/type.ts"; import { Context } from "~/compiler/codegen/context.ts"; -export function CompileConstant(ctx: Context, syntax: Syntax.Term_Constant, expect?: Intrinsic) { +export function CompileConstant(ctx: Context, syntax: Syntax.Term_Constant, expect?: SolidType): IntrinsicValue { + if (!(expect instanceof IntrinsicType)) expect = undefined; const val = syntax.value[0]; switch (val.type) { case "boolean": return CompileBool(ctx, val); @@ -26,10 +29,10 @@ export function CompileBool(ctx: Context, syntax: Syntax.Term_Boolean) { } ctx.block.push(Instruction.const.i32(num)); - return bool; + return bool.value; } -function CompileInt(ctx: Context, syntax: Syntax.Term_Integer, expect?: Intrinsic) { +function CompileInt(ctx: Context, syntax: Syntax.Term_Integer, expect?: IntrinsicType) { const num = Number(syntax.value[0].value); if (isNaN(num)) @@ -52,7 +55,7 @@ function CompileInt(ctx: Context, syntax: Syntax.Term_Integer, expect?: Intrinsi path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }); - return u64 + return u64.value; } if (num > 2**63) Panic(`${colors.red("Error")}: Value too big for size\n`, { @@ -63,7 +66,7 @@ function CompileInt(ctx: Context, syntax: Syntax.Term_Integer, expect?: Intrinsi path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }); - return i64; + return i64.value; } if (size === 2) { @@ -73,7 +76,7 @@ function CompileInt(ctx: Context, syntax: Syntax.Term_Integer, expect?: Intrinsi path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }); - return u16 + return u16.value; } if (num > 2**15) Panic(`${colors.red("Error")}: Value too big for size\n`, { @@ -84,7 +87,7 @@ function CompileInt(ctx: Context, syntax: Syntax.Term_Integer, expect?: Intrinsi path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }); - return i16; + return i16.value; } if (size === 1) { @@ -94,7 +97,7 @@ function CompileInt(ctx: Context, syntax: Syntax.Term_Integer, expect?: Intrinsi path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }); - return u8 + return u8.value; } if (num > 2**7) Panic(`${colors.red("Error")}: Value too big for size\n`, { @@ -105,7 +108,7 @@ function CompileInt(ctx: Context, syntax: Syntax.Term_Integer, expect?: Intrinsi path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }); - return i8; + return i8.value; } ctx.block.push(Instruction.const.i32(num)); @@ -114,7 +117,7 @@ function CompileInt(ctx: Context, syntax: Syntax.Term_Integer, expect?: Intrinsi path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }); - return u32 + return u32.value; } if (num > 2**31) Panic(`${colors.red("Error")}: Value too big for size\n`, { @@ -124,22 +127,23 @@ function CompileInt(ctx: Context, syntax: Syntax.Term_Integer, expect?: Intrinsi if (num < -(2**31)) Panic(`${colors.red("Error")}: Value too small for size\n`, { path: ctx.file.path, name: ctx.file.name, ref: syntax.ref }); - return i32; + + return i32.value; } -function CompileFloat(ctx: Context, syntax: Syntax.Term_Float, expect?: Intrinsic) { +function CompileFloat(ctx: Context, syntax: Syntax.Term_Float, expect?: IntrinsicType) { const num = Number(syntax.value[0].value); - if (isNaN(num)) - Panic(`${colors.red("Error")}: Invalid number ${syntax.value[0].value}\n`, { - path: ctx.file.path, name: ctx.file.name, ref: syntax.ref - }); + if (isNaN(num)) Panic(`${colors.red("Error")}: Invalid number ${syntax.value[0].value}\n`, { + path: ctx.file.path, name: ctx.file.name, ref: syntax.ref + }); if (expect === f64) { ctx.block.push(Instruction.const.f64(num)); - return f64; + return f64.value; } ctx.block.push(Instruction.const.f32(num)); - return f32; + + return f32.value; } \ No newline at end of file diff --git a/source/compiler/codegen/expression/container.ts b/source/compiler/codegen/expression/container.ts new file mode 100644 index 0000000..af2f2d0 --- /dev/null +++ b/source/compiler/codegen/expression/container.ts @@ -0,0 +1,136 @@ +import * as colors from "https://deno.land/std@0.201.0/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 { MaybeSingularExprArg } from "~/compiler/codegen/expression/helper.ts"; +import { ResolveLinearType } from "~/compiler/codegen/expression/helper.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 { 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( + `${colors.red("Error")}: Unable to infer struct type\n`, { + path: ctx.file.path, name: ctx.file.name, ref: syntax.ref + }); + if (expect instanceof Structure) expect.link(); + + 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(skipLast = false) { + const base = syntax.value[0].value[0]; + if (!base) return; + + // Skipping the last is the first in this case + if (skipLast && base.value[1].value.length === 0) return; + + yield base.value[0]; // first + + const length = base.value[1].value.length - ( skipLast ? 1 : 0 ); + for (let i=0; i SourceView(ctx.file.path, ctx.file.name, x, true)).join("") + + SourceView(ctx.file.path, ctx.file.name, ref, false) + ); + + ctx.file.markFailure(); + } + } + + 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); + } + + // Auto load intrinsic value from a linear type + if (baseType instanceof IntrinsicType) { + Load(ctx, baseType, type.offset); + return baseType.value; + } + + // Push the complete pointer to the stack + if (type.alloc) { + ctx.block.push(Instruction.const.i32(type.offset)); + ctx.block.push(Instruction.i32.add()); + } + + if (type.offset !== 0) ctx.block.push(Instruction.const.i32(type.offset)); + return type; +} \ No newline at end of file diff --git a/source/compiler/codegen/expression/index.ts b/source/compiler/codegen/expression/index.ts index fa52f9e..00a02fe 100644 --- a/source/compiler/codegen/expression/index.ts +++ b/source/compiler/codegen/expression/index.ts @@ -1,11 +1,11 @@ import type * as Syntax from "~/bnf/syntax.d.ts"; +import { OperandType, SolidType } from "~/compiler/codegen/expression/type.ts"; import { ApplyPrecedence } from "~/compiler/codegen/expression/precedence.ts"; import { CompileInfix } from "~/compiler/codegen/expression/infix.ts"; import { CompileArg } from "~/compiler/codegen/expression/operand.ts"; -import { Intrinsic } from "~/compiler/intrinsic.ts"; import { Context } from "~/compiler/codegen/context.ts"; -export function CompileExpr(ctx: Context, syntax: Syntax.Term_Expr, expect?: Intrinsic) { +export function CompileExpr(ctx: Context, syntax: Syntax.Term_Expr, expect?: SolidType): OperandType { const elm = ApplyPrecedence(syntax); if (elm.type === "expr_arg") return CompileArg(ctx, elm, expect); diff --git a/source/compiler/codegen/expression/infix.ts b/source/compiler/codegen/expression/infix.ts index 09634b3..edd31ff 100644 --- a/source/compiler/codegen/expression/infix.ts +++ b/source/compiler/codegen/expression/infix.ts @@ -1,24 +1,33 @@ import * as colors from "https://deno.land/std@0.201.0/fmt/colors.ts"; -import { Intrinsic, bool, u8, i8, u16, i16, u32, i32, u64, i64, f32, f64 } from "~/compiler/intrinsic.ts"; -import { OperandType, CompileArg } from "~/compiler/codegen/expression/operand.ts"; +import Structure from "~/compiler/structure.ts"; +import { IntrinsicValue, bool, u8, i8, u16, i16, u32, i32, u64, i64, f32, f64 } from "~/compiler/intrinsic.ts"; +import { OperandType, SolidType, IsSolidType, LinearType } from "~/compiler/codegen/expression/type.ts"; +import { ResolveLinearType } from "~/compiler/codegen/expression/helper.ts"; import { PrecedenceTree } from "~/compiler/codegen/expression/precedence.ts"; import { ReferenceRange } from "~/parser.ts"; import { Instruction } from "~/wasm/index.ts"; +import { CompileArg } from "~/compiler/codegen/expression/operand.ts"; import { Context } from "~/compiler/codegen/context.ts"; import { Panic } from "~/helper.ts"; -export function CompileInfix(ctx: Context, lhs: PrecedenceTree, op: string, rhs: PrecedenceTree, ref: ReferenceRange, expect?: Intrinsic) { - const a = CompilePrecedence(ctx, lhs, expect); - if (!(a instanceof Intrinsic)) Panic( - `${colors.red("Error")}: Cannot apply infix operation to non-variable\n`, { +export function CompileInfix(ctx: Context, lhs: PrecedenceTree, op: string, rhs: PrecedenceTree, ref: ReferenceRange, expect?: SolidType): OperandType { + if (op === "as") return CompileAs(ctx, lhs, rhs); + if (op === ".") return CompileStaticAccess(ctx, lhs, rhs, expect); + + let a = CompilePrecedence(ctx, lhs, expect); + if (a instanceof LinearType && a.type instanceof IntrinsicValue) a = ResolveLinearType(ctx, a, rhs.ref); + + if (!(a instanceof IntrinsicValue)) Panic( + `${colors.red("Error")}: Cannot apply arithmetic infix operation to non-intrinsics ${colors.cyan(a.getTypeName())}\n`, { path: ctx.file.path, name: ctx.file.name, ref: lhs.ref }); - const b = CompilePrecedence(ctx, rhs, a); - if (!(b instanceof Intrinsic)) Panic( - `${colors.red("Error")}: Cannot apply infix operation to non-variable\n`, { + let b = CompilePrecedence(ctx, rhs, a.type); + if (b instanceof LinearType && b.type instanceof IntrinsicValue) b = ResolveLinearType(ctx, b, rhs.ref); + if (!(b instanceof IntrinsicValue)) Panic( + `${colors.red("Error")}: Cannot apply arithmetic infix operation to non-intrinsics ${colors.cyan(b.getTypeName())}\n`, { path: ctx.file.path, name: ctx.file.name, ref: rhs.ref }); @@ -47,69 +56,132 @@ export function CompileInfix(ctx: Context, lhs: PrecedenceTree, op: string, rhs: } } -function CompilePrecedence(ctx: Context, elm: PrecedenceTree, expect?: Intrinsic): OperandType { +function CompilePrecedence(ctx: Context, elm: PrecedenceTree, expect?: SolidType): OperandType { if (elm.type === "expr_arg") return CompileArg(ctx, elm, expect); return CompileInfix(ctx, elm.lhs, elm.op, elm.rhs, elm.ref, expect); } -function CompileAdd(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot add unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileAs(ctx: Context, lhs: PrecedenceTree, rhs: PrecedenceTree): OperandType { + const goal = CompilePrecedence(ctx, rhs); + if (!IsSolidType(goal)) Panic( + `${colors.red("Error")}: Cannot type coerce to non-solid type\n`, { + path: ctx.file.path, name: ctx.file.name, ref: rhs.ref + }); + + const a = CompilePrecedence(ctx, lhs, goal); + if (a !== goal) Panic( + `${colors.red("Error")}: Type coerce is currently unimplemented\n`, { + path: ctx.file.path, name: ctx.file.name, ref: lhs.ref + }); + + return a; +} + + +function CompileStaticAccess(ctx: Context, lhs: PrecedenceTree, rhs: PrecedenceTree, expect?: SolidType): OperandType { + const a = CompilePrecedence(ctx, lhs, expect); + if (!(a instanceof LinearType)) Panic( + `${colors.red("Error")}: Cannot static access into a non-struct value\n`, { + path: ctx.file.path, name: ctx.file.name, ref: lhs.ref + }); + if (!(a.type instanceof Structure)) Panic( + `${colors.red("Error")}: Cannot static access off an intrinsic value\n`, { + path: ctx.file.path, name: ctx.file.name, ref: lhs.ref + }); + + if (rhs.type !== "expr_arg") Panic( + `${colors.red("Error")}: Expected an expression argument for a static access\n`, { + path: ctx.file.path, name: ctx.file.name, ref: rhs.ref + }); + + const prefix = rhs.value[0].value[0]; + if (prefix) Panic( + `${colors.red("Error")}: Prefix values are not supported here\n`, { + path: ctx.file.path, name: ctx.file.name, ref: prefix.ref + }); + + const postfix = rhs.value[2].value; + if (postfix.length > 0) Panic( + `${colors.red("Error")}: Postfix values are not supported here\n`, { + path: ctx.file.path, name: ctx.file.name, ref: rhs.value[2].ref + }); + + const inner = rhs.value[1].value[0]; + if (inner.type !== "name") Panic( + `${colors.red("Error")}: A name must be given for static access, not this\n`, { + path: ctx.file.path, name: ctx.file.name, ref: rhs.ref + }); + + const name = inner.value[0].value; + const attr = a.get(name); + if (!attr) Panic( + `${colors.red("Error")}: Unknown attribute ${name} on ${a.getTypeName()}\n`, { + path: ctx.file.path, name: ctx.file.name, ref: rhs.ref + }); + + return attr; +} + + + +function CompileAdd(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot add unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32 || lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value || lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.add()); return lhs; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.add()); return lhs; } - if (lhs === f32) { + if (lhs === f32.value) { ctx.block.push(Instruction.f32.add()); return lhs; } - if (lhs === f64) { + if (lhs === f64.value) { ctx.block.push(Instruction.f64.add()); return lhs; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } -function CompileSub(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot subtract unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileSub(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot subtract unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32 || lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value || lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.sub()); return lhs; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.sub()); return lhs; } - if (lhs === f32) { + if (lhs === f32.value) { ctx.block.push(Instruction.f32.sub()); return lhs; } - if (lhs === f64) { + if (lhs === f64.value) { ctx.block.push(Instruction.f64.sub()); return lhs; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } @@ -117,99 +189,99 @@ function CompileSub(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: Reference -function CompileMul(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot multiply unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileMul(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot multiply unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32 || lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value || lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.mul()); return lhs; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.mul()); return lhs; } - if (lhs === f32) { + if (lhs === f32.value) { ctx.block.push(Instruction.f32.mul()); return lhs; } - if (lhs === f64) { + if (lhs === f64.value) { ctx.block.push(Instruction.f64.mul()); return lhs; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } -function CompileDiv(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot divide unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileDiv(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot divide unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.div_s()); return lhs; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.div_u()); return lhs; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.div_s()); return lhs; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.div_u()); return lhs; } - if (lhs === f32) { + if (lhs === f32.value) { ctx.block.push(Instruction.f32.div()); return lhs; } - if (lhs === f64) { + if (lhs === f64.value) { ctx.block.push(Instruction.f64.div()); return lhs; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } -function CompileRem(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot remainder unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileRem(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot remainder unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.rem_s()); return lhs; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.rem_u()); return lhs; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.rem_s()); return lhs; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.rem_u()); return lhs; } - if (lhs === f32) { + if (lhs === f32.value) { const regA = ctx.scope.register.allocate(f32.bitcode, false); const regB = ctx.scope.register.allocate(f32.bitcode, false); ctx.block.push(Instruction.local.set(regB.ref)); @@ -232,7 +304,7 @@ function CompileRem(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: Reference return lhs; } - if (lhs === f64) { + if (lhs === f64.value) { const regA = ctx.scope.register.allocate(f64.bitcode, false); const regB = ctx.scope.register.allocate(f64.bitcode, false); ctx.block.push(Instruction.local.set(regA.ref)); @@ -254,7 +326,7 @@ function CompileRem(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: Reference return lhs; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } @@ -263,88 +335,88 @@ function CompileRem(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: Reference -function CompileAnd(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot && unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileAnd(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot && unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.and()); return lhs; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.and()); return lhs; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.and()); return lhs; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.and()); return lhs; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } -function CompileOr(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot || unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileOr(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot || unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.or()); return lhs; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.or()); return lhs; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.or()); return lhs; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.or()); return lhs; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } -function CompileXor(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot ^ unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileXor(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot ^ unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.xor()); return lhs; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.xor()); return lhs; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.xor()); return lhs; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.xor()); return lhs; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } @@ -353,230 +425,230 @@ function CompileXor(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: Reference -function CompileEq(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot == unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileEq(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot == unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.eq()); - return bool; + return bool.value; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.eq()); - return bool; + return bool.value; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.eq()); - return bool; + return bool.value; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.eq()); - return bool; + return bool.value; } - if (lhs === f32) { + if (lhs === f32.value) { ctx.block.push(Instruction.f32.eq()); - return bool; + return bool.value; } - if (lhs === f64) { + if (lhs === f64.value) { ctx.block.push(Instruction.f64.eq()); - return bool; + return bool.value; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } -function CompileNeq(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot != unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileNeq(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot != unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.ne()); - return bool; + return bool.value; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.ne()); - return bool; + return bool.value; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.ne()); - return bool; + return bool.value; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.ne()); - return bool; + return bool.value; } - if (lhs === f32) { + if (lhs === f32.value) { ctx.block.push(Instruction.f32.ne()); - return bool; + return bool.value; } - if (lhs === f64) { + if (lhs === f64.value) { ctx.block.push(Instruction.f64.ne()); - return bool; + return bool.value; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } -function CompileLt(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot < unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileLt(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot < unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.lt_s()); - return bool; + return bool.value; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.lt_u()); - return bool; + return bool.value; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.lt_s()); - return bool; + return bool.value; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.lt_u()); - return bool; + return bool.value; } - if (lhs === f32) { + if (lhs === f32.value) { ctx.block.push(Instruction.f32.lt()); - return bool; + return bool.value; } - if (lhs === f64) { + if (lhs === f64.value) { ctx.block.push(Instruction.f64.lt()); - return bool; + return bool.value; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } -function CompileLe(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot <= unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileLe(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot <= unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.le_s()); - return bool; + return bool.value; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.le_u()); - return bool; + return bool.value; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.le_s()); - return bool; + return bool.value; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.le_u()); - return bool; + return bool.value; } - if (lhs === f32) { + if (lhs === f32.value) { ctx.block.push(Instruction.f32.le()); - return bool; + return bool.value; } - if (lhs === f64) { + if (lhs === f64.value) { ctx.block.push(Instruction.f64.le()); - return bool; + return bool.value; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } -function CompileGt(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot > unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileGt(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot > unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.gt_s()); - return bool; + return bool.value; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.gt_u()); - return bool; + return bool.value; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.gt_s()); - return bool; + return bool.value; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.gt_u()); - return bool; + return bool.value; } - if (lhs === f32) { + if (lhs === f32.value) { ctx.block.push(Instruction.f32.gt()); - return bool; + return bool.value; } - if (lhs === f64) { + if (lhs === f64.value) { ctx.block.push(Instruction.f64.gt()); - return bool; + return bool.value; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } -function CompileGe(ctx: Context, lhs: Intrinsic, rhs: Intrinsic, ref: ReferenceRange) { - if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot >= unmatched types ${lhs.name} != ${rhs.name}\n`, { +function CompileGe(ctx: Context, lhs: IntrinsicValue, rhs: IntrinsicValue, ref: ReferenceRange) { + if (lhs !== rhs) Panic(`${colors.red("Error")}: Cannot >= unmatched types ${lhs.type.name} != ${rhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); - if (lhs === i8 || lhs === i16 || lhs === i32) { + if (lhs === i8.value || lhs === i16.value || lhs === i32.value) { ctx.block.push(Instruction.i32.ge_s()); - return bool; + return bool.value; } - if (lhs === u8 || lhs === u16 || lhs === u32) { + if (lhs === u8.value || lhs === u16.value || lhs === u32.value) { ctx.block.push(Instruction.i32.ge_u()); - return bool; + return bool.value; } - if (lhs === i64 || lhs === u64) { + if (lhs === i64.value || lhs === u64.value) { ctx.block.push(Instruction.i64.ge_s()); - return bool; + return bool.value; } - if (lhs === i64) { + if (lhs === i64.value) { ctx.block.push(Instruction.i64.ge_u()); - return bool; + return bool.value; } - if (lhs === f32) { + if (lhs === f32.value) { ctx.block.push(Instruction.f32.ge()); - return bool; + return bool.value; } - if (lhs === f64) { + if (lhs === f64.value) { ctx.block.push(Instruction.f64.ge()); - return bool; + return bool.value; } - Panic(`${colors.red("Error")}: Unhandled type ${lhs.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled type ${lhs.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref }); } diff --git a/source/compiler/codegen/expression/operand.ts b/source/compiler/codegen/expression/operand.ts index c6b0637..15473e6 100644 --- a/source/compiler/codegen/expression/operand.ts +++ b/source/compiler/codegen/expression/operand.ts @@ -1,46 +1,62 @@ import * as colors from "https://deno.land/std@0.201.0/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 { ArrayBuilder, StructBuilder } from "~/compiler/codegen/expression/container.ts"; import { AssertUnreachable, Panic } from "~/helper.ts"; import { CompilePostfixes } from "~/compiler/codegen/expression/postfix.ts"; -import { Intrinsic, bool } from "~/compiler/intrinsic.ts"; import { CompileConstant } from "~/compiler/codegen/expression/constant.ts"; import { CompilePrefix } from "~/compiler/codegen/expression/prefix.ts"; -import { Instruction } from "~/wasm/index.ts"; import { CompileExpr } from "~/compiler/codegen/expression/index.ts"; -import { VirtualType } from "~/compiler/intrinsic.ts"; -import { Namespace } from "~/compiler/file.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 type OperandType = Intrinsic | Namespace | VirtualType; - - -export function CompileArg(ctx: Context, syntax: Syntax.Term_Expr_arg, expect?: Intrinsic): OperandType { - const prefix = syntax.value[0].value[0]; - const postfix = syntax.value[2].value; - const val = syntax.value[1]; +export function CompileArg(ctx: Context, syntax: Syntax.Term_Expr_arg, expect?: SolidType): OperandType { + const val = syntax.value[1].value[0]; let res: OperandType; switch (val.type) { - case "constant": res = CompileConstant(ctx, val, expect); break; - case "expr_brackets": res = CompileBrackets(ctx, val, expect); break; - case "block": res = CompileBlock(ctx, val, expect); break; - case "name": res = CompileName(ctx, val, expect); break; - case "if": res = CompileIf(ctx, val, expect); break; + case "container": res = CompileContainer(ctx, val, expect); break; + case "constant": res = CompileConstant(ctx, val, expect); break; + case "expr_brackets": res = CompileBrackets(ctx, val, expect); break; + case "block": res = CompileBlock(ctx, val, expect); break; + case "name": res = CompileName(ctx, val); break; + case "if": res = CompileIf(ctx, val, expect); break; default: AssertUnreachable(val); } - if (prefix) res = CompilePrefix(ctx, prefix, res, expect); + const postfix = syntax.value[2].value; if (postfix.length > 0) res = CompilePostfixes(ctx, postfix, res, expect); + const prefix = syntax.value[0].value[0]; + if (prefix) res = CompilePrefix(ctx, prefix, res, expect); + return res; } -function CompileBrackets(ctx: Context, syntax: Syntax.Term_Expr_brackets, expect?: Intrinsic) { +function CompileContainer(ctx: Context, syntax: Syntax.Term_Container, expect?: SolidType): OperandType { + if (expect instanceof Structure) return StructBuilder(ctx, syntax, expect); + + switch (syntax.value[0].value[0]?.value[0].value[0].type) { + case "container_map": return StructBuilder(ctx, syntax, expect); + case "container_value": return ArrayBuilder(ctx, syntax, expect); + } + + Panic( + `Unable to determine container type\n`, { + path: ctx.file.path, name: ctx.file.name, ref: syntax.ref + }) +} + +function CompileBrackets(ctx: Context, syntax: Syntax.Term_Expr_brackets, expect?: SolidType) { return CompileExpr(ctx, syntax.value[0], expect); } -function CompileName(ctx: Context, syntax: Syntax.Term_Name, expect?: Intrinsic) { +function CompileName(ctx: Context, syntax: Syntax.Term_Name) { const name = syntax.value[0].value; const variable = ctx.scope.getVariable(name, true); if (!variable) { @@ -52,23 +68,22 @@ function CompileName(ctx: Context, syntax: Syntax.Term_Name, expect?: Intrinsic) return found; } - if (!variable.isDefined) Panic(`${colors.red("Error")}: Variable ${name} has no value assigned to it\n`, { - path: ctx.file.path, name: ctx.file.name, ref: syntax.ref - }); - - ctx.block.push(Instruction.local.get(variable.register.ref)); return variable.type; } -function CompileIf(ctx: Context, syntax: Syntax.Term_If, expect?: Intrinsic) { +function CompileIf(ctx: Context, syntax: Syntax.Term_If, expect?: SolidType) { const cond = CompileExpr(ctx, syntax.value[0]); - if (cond !== bool) Panic( - `${colors.red("Error")}: Invalid comparison type ${cond.name}\n`, + 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 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(); let typeElse: OperandType | null = null; @@ -76,32 +91,40 @@ function CompileIf(ctx: Context, syntax: Syntax.Term_If, expect?: Intrinsic) { if (syntax.value[2].value[0]) { scopeElse = ctx.child(); 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(); if (typeIf != typeElse) Panic( - `${colors.red("Error")}: Type miss-match between if statement results, ${typeIf.name} != ${typeElse.name}\n`, + `${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 (scopeIf.done && scopeElse.done) ctx.done = true; } - if (!(typeIf instanceof Intrinsic || typeIf instanceof VirtualType)) Panic( - `${colors.red("Error")}: Invalid output type from if expression ${typeIf.name}\n`, + 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) Panic( + `${colors.red("Error")}: Unsupported structure raising\n`, { path: ctx.file.path, name: ctx.file.name, ref: syntax.ref } ); - const typeIdx = typeIf instanceof VirtualType - ? 0x40 - : ctx.file.owner.module.makeType([], [typeIf.bitcode]); - ctx.block.push(Instruction.if(typeIdx, scopeIf.block, scopeElse?.block)); return typeIf; } -function CompileBlock(ctx: Context, syntax: Syntax.Term_Block, expect?: Intrinsic): OperandType { +function CompileBlock(ctx: Context, syntax: Syntax.Term_Block, expect?: SolidType): OperandType { const child = ctx.child(); child.compile(syntax.value[0].value); child.cleanup(); + if (child.done) ctx.done = true; + ctx.block.push(Instruction.block(0x40, child.block)); return child.raiseType; } \ No newline at end of file diff --git a/source/compiler/codegen/expression/postfix.ts b/source/compiler/codegen/expression/postfix.ts index a662949..baff977 100644 --- a/source/compiler/codegen/expression/postfix.ts +++ b/source/compiler/codegen/expression/postfix.ts @@ -3,10 +3,18 @@ import * as colors from "https://deno.land/std@0.201.0/fmt/colors.ts"; import type * as Syntax from "~/bnf/syntax.d.ts"; import Function from "~/compiler/function.ts"; import { AssertUnreachable, Panic } from "~/helper.ts"; -import { OperandType } from "~/compiler/codegen/expression/operand.ts"; +import { IntrinsicType, i32 } from "~/compiler/intrinsic.ts"; +import { ResolveLinearType } from "~/compiler/codegen/expression/helper.ts"; +import { IntrinsicValue } from "~/compiler/intrinsic.ts"; +import { OperandType } 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 { VirtualType } from "~/compiler/intrinsic.ts"; +import { LinearType } from "~/compiler/codegen/expression/type.ts"; import { Context } from "~/compiler/codegen/context.ts"; +import { none } from "~/compiler/intrinsic.ts"; + export function CompilePostfixes(ctx: Context, syntax: Syntax.Term_Expr_postfix[], type: OperandType, expect?: OperandType): OperandType { @@ -16,14 +24,12 @@ export function CompilePostfixes(ctx: Context, syntax: Syntax.Term_Expr_postfix[ switch (act.type) { case "expr_call": res = CompileCall(ctx, act, res); break; - case "expr_get": Panic( - `${colors.red("Error")}: Unimplemented postfix operation ${act.type}\n`, - { path: ctx.file.path, name: ctx.file.name, ref: act.ref } - ); break; - case "expr_param": Panic( - `${colors.red("Error")}: Unimplemented postfix operation ${act.type}\n`, - { path: ctx.file.path, name: ctx.file.name, ref: act.ref } - ); break; + + case "expr_get": case "expr_loan": case "expr_param": + Panic( + `${colors.red("Error")}: Unimplemented postfix operation ${act.type}\n`, + { path: ctx.file.path, name: ctx.file.name, ref: act.ref } + ); break; default: AssertUnreachable(act); } } @@ -40,13 +46,30 @@ function CompileCall(ctx: Context, syntax: Syntax.Term_Expr_call, operand: Opera operand.compile(); // check the function is compiled - if (operand.returns.length != 1) Panic( - `${colors.red("Error")}: Cannot currently handle functions which don't return a single value\n`, + if (!operand.ref) throw new Error("A function somehow compiled with no reference generated"); + + const stackReg = ctx.file.owner.project.stackReg.ref; + let returnType: VirtualType | IntrinsicValue | LinearType = none; + + if (operand.returns.length == 1) { + const primary = operand.returns[0]; + if (primary.type instanceof IntrinsicType) { + returnType = primary.type.value; + } else { + const alloc = ctx.scope.stack.allocate(primary.type.size, primary.type.align); + const forward = primary.type instanceof IntrinsicType + ? primary.type.value + : primary.type; + returnType = LinearType.make(forward, alloc, ctx.file.owner.project.stackBase); + + ctx.block.push(Instruction.global.get(stackReg)); + ctx.block.push(Instruction.const.i32(alloc.getOffset())); + } + } else Panic( + `${colors.red("Error")}: Multi-return is currently unsupported\n`, { path: ctx.file.path, name: ctx.file.name, ref: syntax.ref } ); - if (!operand.ref) throw new Error("A function somehow compiled with a reference generated"); - const args = LineariseArgList(syntax.value[0]); if (args.length != operand.arguments.length) Panic( `${colors.red("Error")}: Miss matched argument count\n`, @@ -55,22 +78,42 @@ function CompileCall(ctx: Context, syntax: Syntax.Term_Expr_call, operand: Opera for (let i=0; i x.value[0]); diff --git a/source/compiler/codegen/expression/precedence.ts b/source/compiler/codegen/expression/precedence.ts index 9ca2b75..43f36f7 100644 --- a/source/compiler/codegen/expression/precedence.ts +++ b/source/compiler/codegen/expression/precedence.ts @@ -1,12 +1,10 @@ -/// -import { assertEquals } from "https://deno.land/std@0.201.0/assert/mod.ts"; - import type { Term_Expr, Term_Expr_arg, _Literal } from "~/bnf/syntax.d.ts"; import { ReferenceRange } from "~/parser.ts"; +import { Panic } from "~/helper.ts"; const precedence = { - "->": 1, + ".": 1, "->": 1, "*" : 3, "/" : 3, "%" : 3, "+" : 4, "-" : 4, "<<": 5, ">>": 5, @@ -21,20 +19,15 @@ const precedence = { "||": 12, } as { [key: string]: number }; -function GetPrecedence (a: string, b: string) { +export function GetPrecedence (a: string, b: string) { const A = precedence[a]; const B = precedence[b]; - if (A == undefined && B == undefined) { - return 0; - } else if (A == B) { - return 0; - } else if (B == undefined) { - return 1; - } else if (A == undefined) { - return -1; - } else { - return Math.min(1, Math.max(-1, A-B)); - } + if (!A) Panic(`Unknown infix operation ${a}`); + if (!B) Panic(`Unknown infix operation ${a}`); + + return A !== B + ? Math.min(1, Math.max(-1, A-B)) + : 0; } export type PrecedenceTree = Term_Expr_arg | { @@ -49,11 +42,11 @@ export function ApplyPrecedence(syntax: Term_Expr) { let root: PrecedenceTree = syntax.value[0] as PrecedenceTree; for (const action of syntax.value[1].value) { - const op = action.value[0].value; - const arg = action.value[1] + const op = action.value[0].value; + const arg = action.value[1] // First action - if (!Array.isArray(root)) { + if (root.type !== "infix") { root = { type: "infix", lhs: root, @@ -64,7 +57,7 @@ export function ApplyPrecedence(syntax: Term_Expr) { continue; } - const p = GetPrecedence(root[1], op); + const p = GetPrecedence(root.op, op); if (p > 0) { // Transform stealing previous operand // (1 + 2) * 3 -> (2 * 3) + 1 @@ -72,38 +65,25 @@ export function ApplyPrecedence(syntax: Term_Expr) { type: "infix", lhs: { type: "infix", - lhs: root[2], + lhs: root.rhs, op, rhs: arg, - ref: ReferenceRange.union(root[2].ref, arg.ref) + ref: ReferenceRange.union(root.ref, arg.ref) }, - op: root[1], - rhs: root[0], + op: root.op, + rhs: root.lhs, ref: ReferenceRange.union(arg.ref, arg.ref) } - } else { root = { type: "infix", - lhs: root[0], - op: root[1], - rhs: { - type: "infix", - lhs: root[2], - op, - rhs: arg, - ref: ReferenceRange.union(root[2].ref, arg.ref) - }, - ref: ReferenceRange.union(root[0].ref, arg.ref) + lhs: root, + op: op, + rhs: arg, + ref: ReferenceRange.union(root.ref, arg.ref) } } } return root; -} - -Deno.test("Check precedence of two operators", () => { - assertEquals(GetPrecedence("+", "*"), 1); - assertEquals(GetPrecedence("+", "-"), 0); - assertEquals(GetPrecedence("*", "+"), -1); -}); \ No newline at end of file +} \ No newline at end of file diff --git a/source/compiler/codegen/expression/prefix.ts b/source/compiler/codegen/expression/prefix.ts index 73f100e..fc6ea53 100644 --- a/source/compiler/codegen/expression/prefix.ts +++ b/source/compiler/codegen/expression/prefix.ts @@ -1,70 +1,56 @@ import * as colors from "https://deno.land/std@0.201.0/fmt/colors.ts"; import type * as Syntax from "~/bnf/syntax.d.ts"; -import { Intrinsic, f32, f64, i16, i32, i64, i8, u16, u32, u64, u8 } from "~/compiler/intrinsic.ts"; +import { IntrinsicValue, f32, f64, i16, i32, i64, i8, u16, u32, u64, u8 } from "~/compiler/intrinsic.ts"; import { AssertUnreachable, Panic } from "~/helper.ts"; +import { OperandType, SolidType } from "~/compiler/codegen/expression/type.ts"; import { Instruction } from "~/wasm/index.ts"; -import { OperandType } from "~/compiler/codegen/expression/operand.ts"; import { Context } from "~/compiler/codegen/context.ts"; -import { never } from "~/compiler/intrinsic.ts"; -export function CompilePrefix(ctx: Context, prefix: Syntax.Term_Expr_prefix, type: OperandType, expect?: Intrinsic) { - if (!(type instanceof Intrinsic)) Panic( - `${colors.red("Error")}: Cannot apply prefix operation to non-variable\n`, { - path: ctx.file.path, name: ctx.file.name, ref: prefix.ref - }); - +export function CompilePrefix(ctx: Context, prefix: Syntax.Term_Expr_prefix, type: OperandType, expect?: SolidType) { const op = prefix.value[0].value; switch (op) { case "!": Panic( `${colors.red("Error")}: Unimplemented negation prefix operation\n`, { path: ctx.file.path, name: ctx.file.name, ref: prefix.ref - }); - break; - case "-": return CompileInverse(ctx, type, prefix); - case "return": return CompileReturn(ctx, type, prefix); + }); break; + case "-": return CompileInverse(ctx, type, prefix); default: AssertUnreachable(op); } } -function CompileInverse(ctx: Context, type: Intrinsic, prefix: Syntax.Term_Expr_prefix) { - if (type === u8 || type === u16 || type === u32 || type === u64) - Panic(`${colors.red("Error")}: Cannot invert an unsigned integer\n`, { - path: ctx.file.path, name: ctx.file.name, ref: prefix.ref - }); +function CompileInverse(ctx: Context, type: OperandType, prefix: Syntax.Term_Expr_prefix) { + if (!(type instanceof IntrinsicValue)) Panic( + `${colors.red("Error")}: Cannot apply prefix operation to non-variable\n`, { + path: ctx.file.path, name: ctx.file.name, ref: prefix.ref + }); + + if (type === u8.value || type === u16.value || type === u32.value || type === u64.value) Panic( + `${colors.red("Error")}: Cannot invert an unsigned integer\n`, + { path: ctx.file.path, name: ctx.file.name, ref: prefix.ref } + ); - if (type === i8 || type === i16 || type === i32) { + if (type === i8.value || type === i16.value || type === i32.value) { ctx.block.push(Instruction.const.i32(-1)); ctx.block.push(Instruction.i32.mul()); return type; - } else if (type === i64) { + } else if (type === i64.value) { ctx.block.push(Instruction.const.i64(-1)); ctx.block.push(Instruction.i64.mul()); return type; - } else if (type === f32) { + } else if (type === f32.value) { ctx.block.push(Instruction.const.f32(-1)); ctx.block.push(Instruction.f32.mul()); return type; - } else if (type === f64) { + } else if (type === f64.value) { ctx.block.push(Instruction.const.f64(-1)); ctx.block.push(Instruction.f64.mul()); return type; } - Panic(`${colors.red("Error")}: Unhandled arithmetic prefix inversion for type ${type.name}\n`, { + Panic(`${colors.red("Error")}: Unhandled arithmetic prefix inversion for type ${type.type.name}\n`, { path: ctx.file.path, name: ctx.file.name, ref: prefix.ref }); -} - - - - - -function CompileReturn(ctx: Context, type: Intrinsic, prefix: Syntax.Term_Expr_prefix) { - ctx.scope.cleanup(); - ctx.block.push(Instruction.return()); - ctx.done = true; - return never; } \ No newline at end of file diff --git a/source/compiler/codegen/expression/type.ts b/source/compiler/codegen/expression/type.ts new file mode 100644 index 0000000..28fccf3 --- /dev/null +++ b/source/compiler/codegen/expression/type.ts @@ -0,0 +1,287 @@ +import { assert } from "https://deno.land/std@0.201.0/assert/assert.ts"; + +import Structure from "~/compiler/structure.ts"; +import { IntrinsicValue, IntrinsicType, VirtualType } from "~/compiler/intrinsic.ts"; +import { StackAllocation } from "~/compiler/codegen/allocation/stack.ts"; +import { ReferenceRange } from "~/parser.ts"; +import { LatentOffset } from "~/helper.ts"; +import { IsNamespace } from "~/compiler/file.ts"; +import { Namespace } from "~/compiler/file.ts"; +import { LocalRef } from "~/wasm/funcRef.ts"; + + +export type OperandType = RuntimeType | Namespace | SolidType | VirtualType; +export type RuntimeType = LinearType | IntrinsicValue; +export type SolidType = IntrinsicType | Structure; + +// deno-lint-ignore no-explicit-any +export function IsSolidType(a: any): a is SolidType { + if (a instanceof IntrinsicType) return true; + if (a instanceof Structure) return true; + + return false; +} + +// deno-lint-ignore no-explicit-any +export function IsRuntimeType(a: any): a is RuntimeType { + if (a instanceof IntrinsicValue) return true; + if (a instanceof LinearType) return true; + + return false; +} + +// deno-lint-ignore no-explicit-any +export function IsContainerType(a: any): boolean { + if (a instanceof Structure) return true; + + return false; +} + + + + +export enum BasePointerType { global, local }; +export class BasePointer { + locality: BasePointerType; + ref: LocalRef; + + constructor(locality: BasePointerType, ref: LocalRef) { + this.locality = locality; + this.ref = ref; + } + + get () { + return this.ref.get(); + } +} + +export enum Ownership { + owner, + loanRead, + loanWrite +} + +export class LinearType { + private composable: boolean; + private parent?: LinearType; + ownership: Ownership; + + private consumedAt?: ReferenceRange; + + // Is this a structure made in an expression, not tied to a variable + // So after use the whole structure needs to be disposed? + private retain: boolean; + + private attributes: Map; + readonly type: Structure | IntrinsicValue; + + readonly base: BasePointer; + readonly alloc: StackAllocation | null; + /*readonly*/ offset: number | LatentOffset; // edited by clone + + // constructor(type: LinearType['type'], alloc: LinearType['alloc'], base: BasePointer) + // constructor(type: LinearType['type'], parent: LinearType, offset: LatentOffset) + constructor(a: LinearType['type'], b: LinearType['alloc'] | LinearType, c: BasePointer | number) { + if (b instanceof LinearType) { + assert(typeof c === "number", "should be number"); + + this.composable = true; + this.retain = false; + this.type = a; + + this.ownership = b.ownership; + this.parent = b; + this.base = b.base; + this.alloc = b.alloc; + this.offset = (this.parent.offset instanceof LatentOffset) + ? new LatentOffset(this.parent.offset, c) + : this.parent.offset + c; + + this.consumedAt = b.consumedAt; + } else { + assert(c instanceof BasePointer, "should be base pointer"); + + this.ownership = Ownership.owner; + this.consumedAt = undefined; + this.composable = true; + this.retain = false; + + this.alloc = b; + this.type = a; + this.base = c; + this.offset = this.alloc + ? new LatentOffset(this.alloc.getOffset(), 0) + : 0; + } + + this.attributes = new Map(); + } + + static make(type: LinearType['type'], alloc: LinearType['alloc'], base: BasePointer) { + return new LinearType(type, alloc, base); + } + + static from(parent: LinearType, type: LinearType['type'], offset: number) { + return new LinearType(type, parent, offset); + } + + private cascadeCompose() { + // was already composed, so cascading will make no change + if (this.composable) return; + + if (this.type instanceof Structure) { + + // Not all attributes are present + if (this.attributes.size < this.type.attributes.length) return; + + // check all children are composable + this.composable = true; + for (const [_, child] of this.attributes) { + if (!child.composable) { + this.composable = false; + return; // stop cascade + } + } + } + + // this item is now composable, cascade up + this.parent?.cascadeCompose(); + } + + private cascadeDecompose() { + if (this.composable) this.parent?.cascadeDecompose(); + } + + getCompositionErrors(reasons: ReferenceRange[] = []) { + if (this.composable) return null; + + if (this.consumedAt) { + const reasonGiven = reasons.findIndex(x => x.start.index === this.consumedAt?.start.index) !== -1; + + // You've been consumed, you have no children + if (reasonGiven) return; + reasons.push(this.consumedAt) + return reasons; + }; + + for (const [_, child] of this.attributes) { + child.getCompositionErrors(reasons); + } + + if (reasons.length === 0) return null; + + return reasons; + } + + markDefined() { + this.attributes.clear(); + this.consumedAt = undefined; + this.composable = true; + + this.parent?.cascadeCompose(); + } + + markConsumed(ref: ReferenceRange) { + this.consumedAt = ref; + this.composable = false; + this.attributes.clear(); + + this.parent?.cascadeDecompose(); + } + + shouldDispose(): boolean { + return !this.retain; + } + dispose() { + if (this.retain) return; + if (!this.alloc) return; + this.alloc.free(); + } + + // This value is not stored in a variable, and parents should retain existence after child's consumption + pin() { + this.retain = true; + } + + get(name: string) { + if (!(this.type instanceof Structure)) throw new Error(`Cannot access linear type on a non-structure`); + + const exist = this.attributes.get(name); + if (exist) return exist; + + const member = this.type.get(name); + if (!member) return null; + + const next = LinearType.from( + this, + member.type instanceof IntrinsicType ? member.type.value : member.type, + member.offset + ); + this.attributes.set(name, next); + return next; + } + + getSize() { + if (this.type instanceof IntrinsicValue) return this.type.type.size; + + this.type.link(); + return this.type.size; + } + + getTypeName() { + if (this.type instanceof Structure) return this.type.name; + + return this.type.getTypeName(); + } + + getBaseType() { + if (this.type instanceof Structure) return this.type; + return this.type.type; + } + + like(other: OperandType): boolean { + if (other instanceof LinearType) return this.type === other.type; + if (other instanceof IntrinsicValue) return this.type === other; + if (other instanceof IntrinsicType) return this.type === other.value; + if (IsNamespace(other)) return this.type === other; + + return false; + } + + + infuse(other: LinearType) { + if (!this.like(other)) throw new Error("Cannot infuse a different type"); + + this.composable = other.composable; + this.consumedAt = other.consumedAt; + + for (const key in this.attributes) { + if (other.attributes.has(key)) continue; + this.attributes.delete(key); + } + + for (const [ key, otherChild ] of other.attributes) { + this.get(key)?.infuse(otherChild); + } + } + + + clone(): LinearType { + const nx = new LinearType(this.type, this.alloc, 0); + nx.composable = this.composable; + nx.consumedAt = this.consumedAt; + nx.parent = this.parent; + nx.offset = this.offset; + nx.retain = this.retain; + + for (const [key, value] of this.attributes) { + if (value instanceof IntrinsicValue) { + nx.attributes.set(key, value); + } else { + nx.attributes.set(key, value.clone()); + } + } + + return nx; + } +} \ No newline at end of file diff --git a/source/compiler/codegen/scope.ts b/source/compiler/codegen/scope.ts index d4b265e..05041c2 100644 --- a/source/compiler/codegen/scope.ts +++ b/source/compiler/codegen/scope.ts @@ -1,14 +1,20 @@ -import { TypeSystem, Variable } from "~/compiler/codegen/variable.ts" -import { RegisterAllocator } from "~/compiler/codegen/registers.ts"; +import Structure from "~/compiler/structure.ts"; +import { SolidType, LinearType, BasePointer, BasePointerType } from "~/compiler/codegen/expression/type.ts"; +import { AssertUnreachable } from "~/helper.ts"; +import { RegisterAllocator } from "~/compiler/codegen/allocation/registers.ts"; +import { StackAllocator } from "~/compiler/codegen/allocation/stack.ts"; import { ReferenceRange } from "~/parser.ts"; -import { Intrinsic } from "~/compiler/intrinsic.ts"; +import { IntrinsicType } from "~/compiler/intrinsic.ts"; +import { Instruction } from "~/wasm/index.ts"; +import { Variable } from "~/compiler/codegen/variable.ts"; import { Function } from "~/wasm/function.ts"; import { Context } from "~/compiler/codegen/context.ts"; +import { Store } from "~/compiler/codegen/expression/helper.ts"; export class Scope { _parent: Scope | null; - _localRegs: number; register: RegisterAllocator; + stack: StackAllocator; vars: { [key: string]: Variable }; constructor(ctx: Function | Scope) { @@ -16,36 +22,54 @@ export class Scope { if (ctx instanceof Scope) { this.register = ctx.register; - this._localRegs = this.register._regs.length; this._parent = ctx; + this.stack = ctx.stack; } else { this.register = new RegisterAllocator(ctx); + this.stack = new StackAllocator(); } this.vars = {}; - this._localRegs = 0; } - registerArgument(name: string, type: Intrinsic, ref: ReferenceRange) { - this.vars[name] = new Variable( - name, type, - this.register.allocate(type.bitcode, true), - ref); + registerArgument(ctx: Context, name: string, type: SolidType, ref: ReferenceRange) { + if (this.vars[name]) throw new Error(`Attempting to rebind variable ${name}`); - this.vars[name].markArgument(); - this._localRegs = this.register._regs.length; + if (type instanceof IntrinsicType) { + const reg = this.register.allocate(type.bitcode, true); + const alloc = this.stack.allocate(type.size, type.align); + alloc.tag = name; + + const linear = LinearType.make(type.value, alloc, ctx.file.owner.project.stackBase); + this.vars[name] = new Variable(name, linear); + this.vars[name].markDefined(); + + // address + ctx.block.push(Instruction.global.get(ctx.file.owner.project.stackReg.ref)); + // value + ctx.block.push(Instruction.local.get(reg.ref)); + Store(ctx, type, linear.offset); + + this.vars[name] = new Variable(name, linear); + reg.free(); + } else if (type instanceof Structure) { + const reg = this.register.allocate(type.getBitcode(), true); + + const linear = LinearType.make(type, null, new BasePointer(BasePointerType.local, reg.ref)); + this.vars[name] = new Variable(name, linear); + } else AssertUnreachable(type); + + this.vars[name].markDefined(); + this.vars[name].type.pin(); return this.vars[name]; } - registerVariable(name: string, type: Intrinsic, ref: ReferenceRange) { - if (this.vars[name]) return null; - - this.vars[name] = new Variable( - name, type, - this.register.allocate(type.bitcode), - ref); + registerVariable(name: string, type: LinearType, ref: ReferenceRange) { + if (this.vars[name]) throw new Error(`Attempting to rebind variable ${name}`); + this.vars[name] = new Variable(name, type); + this.vars[name].type.pin(); return this.vars[name]; } @@ -59,7 +83,7 @@ export class Scope { if (readOnly) return inherited; // Don't both cloning if the value can't be consumed in this scope - if (inherited.storage === TypeSystem.Normal) return inherited; + if (inherited instanceof LinearType) return inherited; this.vars[name] = inherited.clone(); } @@ -67,16 +91,19 @@ export class Scope { return null; } + hasVariable(name: string) { + return !!this.vars[name]; + } + child() { return new Scope(this); } - - cleanup() { + cleanup(recursive: boolean = false) { for (const name in this.vars) { - if (!this.vars[name].isLocal) continue; - - this.vars[name].register.free(); + this.vars[name].cleanup(); } + + if (recursive) this._parent?.cleanup(recursive); } } \ No newline at end of file diff --git a/source/compiler/codegen/variable.ts b/source/compiler/codegen/variable.ts index 2e66d5c..0160d1e 100644 --- a/source/compiler/codegen/variable.ts +++ b/source/compiler/codegen/variable.ts @@ -1,76 +1,46 @@ import { ReferenceRange } from "~/parser.ts"; -import { Intrinsic } from "~/compiler/intrinsic.ts"; -import { Register } from "~/compiler/codegen/registers.ts"; - -export enum TypeSystem { - Affine, - Normal -} +import { LinearType } from "~/compiler/codegen/expression/type.ts"; export class Variable { - name: string; - type: Intrinsic; - storage: TypeSystem; - register: Register; - - lastDefined: ReferenceRange | null; + readonly name: string; + readonly type: LinearType; - isDefined: boolean; - isGlobal: boolean; isClone: boolean; - isLocal: boolean; - modifiedAt: ReferenceRange; - - constructor(name: string, type: Intrinsic, register: Register, ref: ReferenceRange) { + constructor(name: string, type: LinearType) { this.name = name; this.type = type; - this.storage = (type instanceof Intrinsic) ? TypeSystem.Normal : TypeSystem.Affine; - this.register = register; - this.modifiedAt = ref; - this.isDefined = false; - this.isGlobal = false; - this.isLocal = true; - this.isClone = false; + this.isClone = false; + } - this.lastDefined = ref; + getBaseType() { + return this.type.getBaseType(); } markDefined() { - this.lastDefined = null; - this.isDefined = true; + this.type.markDefined(); } markUndefined(ref: ReferenceRange) { - this.lastDefined = ref; - this.isDefined = false; - } - - markGlobal() { - this.isGlobal = true; - this.isLocal = false; - this.isClone = false; - this.markDefined(); + this.type.markConsumed(ref); } markArgument() { - this.isGlobal = false; - this.isLocal = false; - this.isClone = false; this.markDefined(); } clone() { - const clone = new Variable(this.name, this.type, this.register, this.modifiedAt); - clone.lastDefined = this.lastDefined; - clone.isDefined = this.isDefined; - clone.isGlobal = this.isGlobal; - clone.isLocal = false; - clone.isClone = true; + const clone = new Variable(this.name, this.type.clone()); + clone.isClone = true; return clone; } - toBinary() { - return this.type.bitcode; + cleanup() { + if (this.isClone) return; + if (this.type.alloc) this.type.alloc.free(); } + + // toBinary() { + // return this.register.type; + // } } \ No newline at end of file diff --git a/source/compiler/file.ts b/source/compiler/file.ts index a69ccbc..df36873 100644 --- a/source/compiler/file.ts +++ b/source/compiler/file.ts @@ -1,27 +1,37 @@ /// -import type { Term_Access, Term_Function, Term_Program } from "~/bnf/syntax.d.ts"; -import type Project from "./project.ts"; +import type Package from "./package.ts"; +import type { Term_Access, Term_Function, Term_Program, Term_Structure } from "~/bnf/syntax.d.ts"; -import { Intrinsic, bool, u8, i8, u16, i16, i32, i64, u32, u64, f32, f64 } from "~/compiler/intrinsic.ts"; -import { FlatAccess, FlattenAccess } from "~/helper.ts"; -import { AssertUnreachable } from "~/bnf/shared.js"; +import { IntrinsicType, bool, u8, i8, u16, i16, i32, i64, u32, u64, f32, f64 } from "~/compiler/intrinsic.ts"; +import { AssertUnreachable, FlatAccess, FlattenAccess } from "~/helper.ts"; import { Parse } from "~/parser.ts"; import Structure from "~/compiler/structure.ts"; import Function from "~/compiler/function.ts"; import Global from "~/compiler/global.ts"; import Import from "~/compiler/import.ts"; -export type Namespace = Function | Import | Global | Structure | Intrinsic ; +export type Namespace = Function | Import | Global | Structure | IntrinsicType ; + +// deno-lint-ignore no-explicit-any +export function IsNamespace(val: any): val is Namespace { + if (val instanceof Function) return true; + if (val instanceof Global) return true; + if (val instanceof Import) return true; + if (val instanceof IntrinsicType) return true; + if (val instanceof Structure) return true; + + return false; +} export class File { - owner: Project; + owner: Package; name: string; path: string; namespace: { [key: string]: Namespace }; - constructor(owner: Project, path: string, name: string, data: string) { + constructor(owner: Package, path: string, name: string, data: string) { this.owner = owner; this.name = name; this.path = path; @@ -57,6 +67,10 @@ export class File { return this.namespace[target.value[0].value]; } + getModule() { + return this.owner.project.module; + } + access(name: string): Namespace | null { return this.namespace[name] || null; } @@ -70,7 +84,8 @@ function Ingest(file: File, syntax: Term_Program) { switch (inner.type) { case "function": IngestFunction(file, inner); break; - default: AssertUnreachable(inner.type); + case "structure": IngestStructure(file, inner); break; + default: AssertUnreachable(inner); } } } @@ -90,4 +105,16 @@ function IngestFunction(file: File, syntax: Term_Function) { } throw new Error(`Cannot merge a function with a non-function ${func.name}`); +} + +function IngestStructure(file: File, syntax: Term_Structure) { + const struct = new Structure(file, syntax); + + const existing = file.namespace[struct.name]; + if (!existing) { + file.namespace[struct.name] = struct; + return; + } + + throw new Error(`Structures cannot share a namespace`); } \ No newline at end of file diff --git a/source/compiler/function.ts b/source/compiler/function.ts index e58bf09..17ef469 100644 --- a/source/compiler/function.ts +++ b/source/compiler/function.ts @@ -4,7 +4,8 @@ import type { Term_Access, Term_Function } from "~/bnf/syntax.d.ts"; import type { File, Namespace } from "./file.ts"; import { ReferenceRange, SourceView } from "~/parser.ts"; -import { Intrinsic } from "~/compiler/intrinsic.ts"; +import { IsSolidType, SolidType } from "~/compiler/codegen/expression/type.ts"; +import { IntrinsicType } from "~/compiler/intrinsic.ts"; import { Context } from "~/compiler/codegen/context.ts"; import { FuncRef } from "~/wasm/funcRef.ts"; import { Scope } from "~/compiler/codegen/scope.ts"; @@ -13,10 +14,10 @@ import { Panic } from "~/helper.ts"; class Argument { name: string; - type: Intrinsic; + type: SolidType; ref: ReferenceRange; - constructor(name: string, type: Intrinsic, ref: ReferenceRange) { + constructor(name: string, type: SolidType, ref: ReferenceRange) { this.name = name; this.type = type; this.ref = ref; @@ -35,7 +36,7 @@ export default class Function { isLinked: boolean; arguments: Argument[]; - returns: Intrinsic[]; + returns: Argument[]; constructor(owner: File, ast: Term_Function) { this.owner = owner; @@ -55,6 +56,10 @@ export default class Function { return this.owner; } + getTypeName() { + return "function"; + } + declarationView(): string { return SourceView(this.owner.path, this.owner.name, this.ast.value[0].ref); } @@ -90,15 +95,19 @@ export default class Function { raw_args[i].value[0].value, types[i], raw_args[i].ref - )) + )); } - const rets = LinkTypes(this.getFile(), + const returnTypes = LinkTypes(this.getFile(), [head.value[2]] ); - if (rets === null) return; - this.returns = rets; + if (returnTypes === null) return; + this.returns.push(new Argument( + "return", + returnTypes[0], + head.value[2].ref + )); this.isLinked = true; } @@ -110,24 +119,38 @@ export default class Function { if (!this.isLinked) return; // Failed to link this.isCompiled = true; - const project = this.getFile().owner; - + const project = this.getFile().owner.project; const func = project.module.makeFunction( - this.arguments.map(x => x.type.bitcode), - this.returns.map(x => x.bitcode) + [ + ...this.returns + .filter(x => !(x.type instanceof IntrinsicType)) + .map(x => x.type.getBitcode()), + ...this.arguments + .map(x => x.type.getBitcode()) + ], + this.returns + .filter(x => x.type instanceof IntrinsicType) + .map(x => x.type.getBitcode()), ); this.ref = func.ref; const scope = new Scope(func); + const ctx = new Context(this.getFile(), this, scope, func.code); + + for (const ret of this.returns) { + if (ret.type instanceof IntrinsicType) continue; + scope.registerArgument(ctx, ret.name, ret.type, ret.ref); + } + for (const arg of this.arguments) { - scope.registerArgument(arg.name, arg.type, arg.ref) + scope.registerArgument(ctx, arg.name, arg.type, arg.ref) } - const ctx = new Context(this.getFile(), scope, func.code); const body = this.ast.value[1]; if (body.type === "literal") throw new Error("Missing function body"); 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 @@ -139,15 +162,24 @@ export default class Function { function LinkTypes(scope: File, syntax: Term_Access[]) { - const out: Intrinsic[] = []; + const out: SolidType[] = []; let failed = false; for (const arg of syntax) { const res = scope.get(arg); - if (res === null || !(res instanceof Intrinsic)) { - // Not Panic-ing, because we may want to display multiple failures at once + + // Not Panicking on error + // Because we may want to display multiple failures at once + if (res === null) { + console.error( + `${colors.red("Error")}: Cannot find namespace\n` + + SourceView(scope.path, scope.name, arg.ref) + ) + failed = true; + continue; + } else if (!IsSolidType(res)) { console.error( - `${colors.red("Error")}: Cannot find type\n` + `${colors.red("Error")}: Function parameters must be a solid type\n` + SourceView(scope.path, scope.name, arg.ref) ) failed = true; diff --git a/source/compiler/global.ts b/source/compiler/global.ts index 8fe67d6..9c300a3 100644 --- a/source/compiler/global.ts +++ b/source/compiler/global.ts @@ -18,6 +18,10 @@ export default class Global { return SourceView(this.owner.path, this.owner.name, ReferenceRange.blank()); } + getTypeName() { + return "[global]"; + } + merge(other: Namespace) { console.error( `${colors.red("Error")}: Cannot share a name space between these two\n` diff --git a/source/compiler/import.ts b/source/compiler/import.ts index a8855a3..bfd82a4 100644 --- a/source/compiler/import.ts +++ b/source/compiler/import.ts @@ -18,6 +18,10 @@ export default class Import { return SourceView(this.owner.path, this.owner.name, ReferenceRange.blank()); } + getTypeName() { + return "[comptime import]"; + } + merge(other: Namespace) { console.error( `${colors.red("Error")}: Cannot share a name space between these two\n` diff --git a/source/compiler/intrinsic.ts b/source/compiler/intrinsic.ts index fa261b7..32747cf 100644 --- a/source/compiler/intrinsic.ts +++ b/source/compiler/intrinsic.ts @@ -1,19 +1,66 @@ import * as Types from "~/wasm/type.ts"; +import { OperandType } from "~/compiler/codegen/expression/type.ts"; +import { LinearType } from "~/compiler/codegen/expression/type.ts"; -export class Intrinsic { - bitcode: number; - name: string; - size: number; +export class IntrinsicType { + readonly bitcode: number; + readonly name: string; + readonly align: number; + readonly size: number; + + // Used to differentiate i8 the type, and i8 the value + readonly value: IntrinsicValue; constructor(name: string, bitcode: number, size: number) { this.name = name; this.bitcode = bitcode; + this.align = size; this.size = size; + + this.value = new IntrinsicValue(this); } declarationView() { return "0 | Native Intrinsic"; } + + getTypeName() { + return "type " + this.name; + } + + like (other: OperandType) { + if (other instanceof LinearType) return other.like(this); + if (other instanceof IntrinsicType) return this === other; + if (other instanceof IntrinsicValue) return this.value === other; + if (other instanceof VirtualType) return false; + + return false; + } + + getBitcode() { + return this.bitcode; + } +} + +export class IntrinsicValue { + type: IntrinsicType; + + constructor(type: IntrinsicType) { + this.type = type; + } + + getTypeName() { + return this.type.name; + } + + like (other: OperandType) { + if (other instanceof LinearType) return other.like(this); + if (other instanceof IntrinsicType) return this.type === other; + if (other instanceof IntrinsicValue) return this === other; + if (other instanceof VirtualType) return false; + + return false; + } } export class VirtualType { @@ -23,24 +70,35 @@ export class VirtualType { this.name = name; } + getTypeName() { + return this.name; + } + declarationView() { return "0 | Virtual Type"; } + + like (other: OperandType) { + if (other instanceof LinearType) return other.like(this); + if (other instanceof VirtualType) return false; + + return false; + } } -export const bool = new Intrinsic("bool", Types.Intrinsic.i32, 1); +export const bool = new IntrinsicType("bool", Types.Intrinsic.i32, 1); -export const u8 = new Intrinsic( "u8", Types.Intrinsic.i32, 1); -export const i8 = new Intrinsic( "i8", Types.Intrinsic.i32, 1); -export const i16 = new Intrinsic("i16", Types.Intrinsic.i32, 2); -export const u16 = new Intrinsic("u16", Types.Intrinsic.i32, 2); -export const i32 = new Intrinsic("i32", Types.Intrinsic.i32, 4); -export const u32 = new Intrinsic("u32", Types.Intrinsic.i32, 4); -export const i64 = new Intrinsic("i64", Types.Intrinsic.i64, 8); -export const u64 = new Intrinsic("u64", Types.Intrinsic.i64, 8); -export const f32 = new Intrinsic("f32", Types.Intrinsic.f32, 4); -export const f64 = new Intrinsic("f64", Types.Intrinsic.f64, 8); +export const u8 = new IntrinsicType( "u8", Types.Intrinsic.i32, 1); +export const i8 = new IntrinsicType( "i8", Types.Intrinsic.i32, 1); +export const i16 = new IntrinsicType("i16", Types.Intrinsic.i32, 2); +export const u16 = new IntrinsicType("u16", Types.Intrinsic.i32, 2); +export const i32 = new IntrinsicType("i32", Types.Intrinsic.i32, 4); +export const u32 = new IntrinsicType("u32", Types.Intrinsic.i32, 4); +export const i64 = new IntrinsicType("i64", Types.Intrinsic.i64, 8); +export const u64 = new IntrinsicType("u64", Types.Intrinsic.i64, 8); +export const f32 = new IntrinsicType("f32", Types.Intrinsic.f32, 4); +export const f64 = new IntrinsicType("f64", Types.Intrinsic.f64, 8); export const never = new VirtualType("never"); export const none = new VirtualType("none"); \ No newline at end of file diff --git a/source/compiler/package.ts b/source/compiler/package.ts new file mode 100644 index 0000000..7261fc2 --- /dev/null +++ b/source/compiler/package.ts @@ -0,0 +1,39 @@ +import { dirname, relative } from "https://deno.land/std@0.201.0/path/mod.ts"; + +import type Project from "~/compiler/project.ts"; +import { File } from "~/compiler/file.ts" + +export default class Package { + project: Project; + files: File[]; + cwd: string; + + failed: boolean; + + constructor(project: Project, base: string) { + this.project = project; + this.failed = false; + this.files = []; + this.cwd = dirname(base); + } + + import(filePath: string) { + const name = relative(this.cwd, filePath); + const data = Deno.readTextFileSync(filePath); + const file = new File(this, filePath, name, data); + this.files.push(file); + + return file; + } + + importRaw(data: string) { + const file = new File(this, "./", "[buffer]", data); + this.files.push(file); + + return file; + } + + markFailure() { + this.project.markFailure(); + } +} \ No newline at end of file diff --git a/source/compiler/project.ts b/source/compiler/project.ts index f435985..eda86f3 100644 --- a/source/compiler/project.ts +++ b/source/compiler/project.ts @@ -1,38 +1,32 @@ -import { dirname, relative } from "https://deno.land/std@0.201.0/path/mod.ts"; - +import Package from "~/compiler/package.ts"; import Module from "~/wasm/module.ts"; -import { File } from "~/compiler/file.ts" +import { BasePointer, BasePointerType } from "~/compiler/codegen/expression/type.ts"; +import { GlobalRegister } from "~/wasm/section/global.ts"; +import { Instruction } from "~/wasm/index.ts"; +import { Intrinsic } from "~/wasm/type.ts"; export default class Project { - files: File[]; - cwd: string; - module: Module; + packages: Package[]; - failed: boolean; + stackReg: GlobalRegister; + stackBase: BasePointer; - constructor(base: string) { - this.failed = false; - this.files = []; - this.cwd = dirname(base); + failed: boolean; + constructor() { this.module = new Module(); - } - - import(filePath: string) { - const name = relative(this.cwd, filePath); - const data = Deno.readTextFileSync(filePath); - const file = new File(this, filePath, name, data); - this.files.push(file); - - return file; - } + this.packages = []; + this.failed = false; - importRaw(data: string) { - const file = new File(this, "./", "[buffer]", data); - this.files.push(file); + this.stackReg = this.module.registerGlobal( + Intrinsic.i32, + true, + Instruction.const.i32(0) + ); + this.stackBase = new BasePointer(BasePointerType.global, this.stackReg.ref); - return file; + this.module.addMemory(1, 1); } markFailure() { diff --git a/source/compiler/structure.ts b/source/compiler/structure.ts index 3c53b9f..a7d972e 100644 --- a/source/compiler/structure.ts +++ b/source/compiler/structure.ts @@ -1,21 +1,210 @@ import * as colors from "https://deno.land/std@0.201.0/fmt/colors.ts"; -import type { File, Namespace } from "./file.ts"; -import { ReferenceRange, SourceView } from "~/parser.ts"; +import type { Term_Structure } from "~/bnf/syntax.d.ts"; +import type { File, Namespace } from "~/compiler/file.ts"; +import { AssertUnreachable, Panic } from "~/helper.ts"; +import { IsSolidType, SolidType } from "~/compiler/codegen/expression/type.ts"; +import { ReferenceRange } from "~/bnf/shared.d.ts"; +import { SourceView } from "~/parser.ts"; +import { i32 } from "~/compiler/intrinsic.ts"; export default class Structure { owner: File; name: string; + ast: Term_Structure; + ref: ReferenceRange; - constructor(owner: File) { + storage: "sparse" | "aligned" | "linear" | "compact"; + + attributes: Array<{ + offset: number, + name: string, + type: SolidType, + }>; + linked: boolean; + align: number; + size: number; + + constructor(owner: File, ast: Term_Structure) { this.owner = owner; - this.name = "UNKNOWN"; - // this.name = ast.value[0].value[0].value; - // this.ast = ast; + this.name = ast.value[0].value; + this.ast = ast; + this.ref = ast.ref; + + this.attributes = []; + this.linked = false; + this.align = 0; + this.size = 0; + + const declaredStorage = ast.value[1].value[0]?.value[0].value; + switch (declaredStorage) { + case undefined: + this.storage = "sparse"; + break; + case "sparse": case "aligned": case "linear": case "compact": + this.storage = declaredStorage; + break; + default: + Panic( + `${colors.red("Error")}: Invalid structure layout ${declaredStorage}\n` + + this.declarationView() + ); + } + } + + link(chain: Structure[] = []) { + if (this.linked) return; + if (chain.includes(this)) Panic( + `${colors.red("Error")}: This structure is attempting to compose itself\n` + + chain.map(x => `${x.name}${x.ref.start.toString()}`).join(' -> ') + + ` -> ${this.name}${this.ref.start.toString()}` + ); + chain.push(this); + + const attrs = Array<{ + name: string, + type: SolidType + ref: ReferenceRange + }>(); + + for (const stmt of this.ast.value[2].value) { + const line = stmt.value[0]; + switch (line.type) { + case "struct_attr": { + const name = line.value[0].value; + const existing = attrs.find(x => x.name === name); + if (existing) { + console.error( + `${colors.red("Error")}: Duplicate attribute name found in struct\n` + + SourceView(this.owner.path, this.owner.name, existing.ref) + + SourceView(this.owner.path, this.owner.name, line.value[0].ref) + ); + this.owner.markFailure(); + continue; + } + + const scope = this.owner; + const type = scope.get(line.value[1]); + if (!type) { + console.error( + `${colors.red("Error")}: Unable to resolve type\n` + + SourceView(this.owner.path, this.owner.name, line.value[1].ref) + ); + this.owner.markFailure(); + continue; + } + + if (!IsSolidType(type)) { + console.error( + `${colors.red("Error")}: Expected a solid type\n` + + SourceView(this.owner.path, this.owner.name, line.value[1].ref) + ); + console.error(type); + this.owner.markFailure(); + continue; + } + + if (type instanceof Structure) type.link(chain); + + attrs.push({ name, type, ref: line.ref }); + } break; + case "struct_spread": { + const other = this.owner.get(line.value[0]); + if (other === null) { + console.error( + `${colors.red("Error")}: Unable to resolve type\n` + + SourceView(this.owner.path, this.owner.name, line.value[0].ref) + ); + this.owner.markFailure(); + continue; + } + + if (!(other instanceof Structure)) { + console.error( + `${colors.red("Error")}: Resolved type must be another structure\n` + + SourceView(this.owner.path, this.owner.name, line.value[0].ref) + ); + this.owner.markFailure(); + continue; + } + + // Ensure this is linked + other.link(chain); + } break; + default: AssertUnreachable(line); + } + } + + const ordered = this.storage === "sparse" || this.storage === "linear"; + const padded = this.storage === "aligned" || this.storage === "sparse"; + let offset = 0; + if (ordered) { + for (const attr of attrs) { + if (padded) { + const gap = offset % attr.type.align; + if (gap !== 0) offset += attr.type.align - gap; + } + + this.attributes.push({ + offset, + name: attr.name, + type: attr.type + }); + offset += attr.type.size; + } + } else { + while (attrs.length > 0) { + let aligned = false; + let bestIdx = 0; + for (let i=1; i x.type.align)) + : 1; + this.size = offset; + + this.linked = true; + } + + get(name: string) { + this.link(); // ensure struct is linked + const out = this.attributes.find(x => x.name == name); + return out; + } + + getTypeName() { + return "type " + this.name; } declarationView(): string { - return SourceView(this.owner.path, this.owner.name, ReferenceRange.blank()); + return SourceView(this.owner.path, this.owner.name, this.ast.ref); } merge(other: Namespace) { @@ -25,6 +214,10 @@ export default class Structure { + other.declarationView() ); - // this.owner.markFailure(); + this.owner.markFailure(); + } + + getBitcode() { + return i32.bitcode; } } \ No newline at end of file diff --git a/source/helper.ts b/source/helper.ts index ab874f5..8a3447e 100644 --- a/source/helper.ts +++ b/source/helper.ts @@ -1,8 +1,10 @@ +import { assert } from "https://deno.land/std@0.201.0/assert/mod.ts"; + import type { Term_Access, Term_Access_comp, Term_Access_dynamic, Term_Access_static, Term_Name } from "~/bnf/syntax.d.ts"; import type { ReferenceRange } from "~/bnf/shared.d.ts"; import { SourceView } from "~/parser.ts"; -export type FlatAccess = (Term_Name | Term_Access_static | Term_Access_dynamic | Term_Access_comp)[]; +export type FlatAccess = (Term_Name | Term_Access_static | Term_Access_dynamic | Term_Access_comp)[]; export function FlattenAccess(syntax: Term_Access): FlatAccess { return [ @@ -31,7 +33,7 @@ export function isByte(value: number): value is Byte { export function AssertUnreachable(x: never): never { - throw new Error("Unreachable code path reachable"); + throw new Error("Unreachable code path reached"); } @@ -42,37 +44,125 @@ export type SourceMap = { } export function Panic(x: string, source?: SourceMap): never { - if (source) { - console.error(x + SourceView(source.path, source.name, source.ref)); - } else { - console.error(x); - } + if (source) console.error(x + SourceView(source.path, source.name, source.ref)); + else console.error(x); Deno.exit(1); } export class LatentValue { - _value: T | null; + private value: T | null; constructor() { - this._value = null; + this.value = null; } - get () { - if (this._value === null) - throw new Error("Attempting to read latent value before it's been resolved"); + get (): T { + if (this.value === null) throw new Error("Attempting to read latent value before it's been resolved"); - return this._value; + return this.value; } clear() { - this._value === null; + this.value === null; } - resolve(val: T, force: boolean = false) { - if (this._value !== null && !force) + resolve(val: T, force = false) { + if (this.value !== null && !force) throw new Error("Attempt to re-resolve already resolved latent value"); - this._value = val; + this.value = val; + } +} + +export type LatentLike = LatentValue | T; + + +export function ReadLatentLike(v: LatentLike) { + if (v instanceof LatentValue) return v.get(); + return v; +} + +export class LatentOffset { + private base: LatentValue; + private offset: number; + private value: number | null; + + constructor(base: LatentValue | LatentOffset, offset: number) { + if (base instanceof LatentOffset) { + this.offset = base.offset + offset; + this.base = base.base; + this.value = null; + } else { + this.offset = offset; + this.base = base; + this.value = null; + } } + + get (): number { + if (this.value === null) { + this.value = this.base.get() + this.offset; + } + + return this.value; + } +} + + + + + +export function AlignUpInteger(x: number, multiple: number) { + assert(multiple !== 0, "Cannot align by zero"); + + const remainder = x % multiple; + return remainder !== 0 + ? x + (multiple - remainder) + : x; +} + +export function AlignDownInteger(x: number, multiple: number) { + assert(multiple !== 0, "Cannot align by zero"); + + const remainder = x % multiple; + return remainder !== 0 + ? x - remainder + : x; +} + + + + +const _timer: { [key: string]: { start: number, end: number } } = {}; +export function TimerStart(key: string) { + const now = Date.now(); + _timer[key] = { start: now, end: now-1 }; +} + +export function TimerEnd(key: string) { + const now = Date.now(); + if (!_timer[key]) return; + _timer[key].end = now; +} + +export function DisplayTimers() { + const lines: string[][] = []; + const max = [0, 0]; + for (const key in _timer) { + const entry = _timer[key]; + const line = [key, (entry.end - entry.start)+"ms"]; + + max[0] = Math.max(max[0], line[0].length); + max[1] = Math.max(max[1], line[1].length); + + lines.push(line); + } + + let str = "Timers:"; + for (const line of lines) { + str += `\n ${line[0].padEnd(max[0])} ${line[1].padStart(max[1])}`; + } + + console.info(str); } \ No newline at end of file diff --git a/source/parser.ts b/source/parser.ts index 7934114..4a30c52 100644 --- a/source/parser.ts +++ b/source/parser.ts @@ -1,8 +1,8 @@ import * as colors from "https://deno.land/std@0.201.0/fmt/colors.ts"; -import { ParseError, ReferenceRange, Reference } from "~/bnf/shared.js"; import * as Instance from "~/bnf/syntax.js"; import * as Syntax from "~/bnf/syntax.d.ts"; +import { ParseError, ReferenceRange, Reference, SyntaxNode } from "~/bnf/shared.js"; import { Panic } from "~/helper.ts"; await Instance.ready; @@ -22,10 +22,31 @@ export function Parse(data: string, path: string, name: string): Syntax.Term_Pro } ); + // Fix changes which are too long due to `omit`ed syntax + RemapRefRange(res.root); + return res.root as Syntax.Term_Program; } -export function SourceView(path: string, name: string, range: ReferenceRange) { +function RemapRefRange(syntax: SyntaxNode) { + if (!Array.isArray(syntax.value)) return; + + const lastI = syntax.value.length - 1; + if (lastI < 0) return; + + for (const child of syntax.value) { + RemapRefRange(child); + } + + syntax.ref.end = syntax.value[lastI].ref.end; + + return; +} + + + + +export function SourceView(path: string, name: string, range: ReferenceRange, compact?: boolean) { const source = ReadByteRange(path, range.start.index-200, range.end.index+200); if (source === null) return `${name}: ${range.toString()}\n`; @@ -53,7 +74,7 @@ export function SourceView(path: string, name: string, range: ReferenceRange) { + eLine + " | " + finish; } - body += `\n ${name}: ${range.toString()}\n`; + body += compact ? "\n" : `\n ${name}: ${range.toString()}\n`; return body; } diff --git a/source/wasm/funcRef.ts b/source/wasm/funcRef.ts index 2e270e7..e107684 100644 --- a/source/wasm/funcRef.ts +++ b/source/wasm/funcRef.ts @@ -1,5 +1,4 @@ import { LatentValue, type Byte } from "~/helper.ts"; - import { EncodeU32, Intrinsic } from "~/wasm/type.ts"; export class FuncRef extends LatentValue { diff --git a/source/wasm/function.ts b/source/wasm/function.ts index 8536bf2..91dd118 100644 --- a/source/wasm/function.ts +++ b/source/wasm/function.ts @@ -30,7 +30,7 @@ export class Function { return ref; } - resolve(idx: number, override: boolean = false) { + resolve(idx: number, override = false) { this.ref.resolve(idx, override); } clear() { @@ -65,7 +65,7 @@ export class Function { } // Resolve local variable refs - let offsets = new Map(); + const offsets = new Map(); for (const ref of this.locals) { const key = ref.type; const offset = offsets.get(key) || types.get(key) || 0; diff --git a/source/wasm/instruction/constant.ts b/source/wasm/instruction/constant.ts index 06ca402..77987b2 100644 --- a/source/wasm/instruction/constant.ts +++ b/source/wasm/instruction/constant.ts @@ -1,6 +1,6 @@ // https://webassembly.github.io/spec/core/binary/instructions.html#numeric-instructions import { EncodeF32, EncodeF64, EncodeI32, EncodeI64 } from "~/wasm/type.ts"; -import { Byte } from "~/helper.ts"; +import { LatentOffset, LatentValue, Byte } from "~/helper.ts"; export enum Type { @@ -12,30 +12,35 @@ export enum Type { export class Constant { type: Type; - x : number; + x : number | LatentValue | LatentOffset; - constructor(type: number, idx: number) { + constructor(type: number, idx: number | LatentValue | LatentOffset) { this.type = type; this.x = idx; } + private read() { + return typeof this.x === "number" ? this.x + : this.x.get(); + } + toBinary(): Byte[] { switch (this.type) { case Type.i32: return [ this.type, - ...EncodeI32(this.x) + ...EncodeI32(this.read()) ]; case Type.i64: return [ this.type, - ...EncodeI64(this.x) + ...EncodeI64(this.read()) ]; case Type.f32: return [ this.type, - ...EncodeF32(this.x) + ...EncodeF32(this.read()) ]; case Type.f64: return [ this.type, - ...EncodeF64(this.x) + ...EncodeF64(this.read()) ]; } @@ -44,9 +49,9 @@ export class Constant { } const wrapper = { - i32: (x: number) => new Constant(Type.i32, x), - i64: (x: number) => new Constant(Type.i64, x), - f32: (x: number) => new Constant(Type.f32, x), - f64: (x: number) => new Constant(Type.f64, x), + i32: (x: number | LatentValue | LatentOffset) => new Constant(Type.i32, x), + i64: (x: number | LatentValue) => new Constant(Type.i64, x), + f32: (x: number | LatentValue) => new Constant(Type.f32, x), + f64: (x: number | LatentValue) => new Constant(Type.f64, x), } export default wrapper; \ No newline at end of file diff --git a/source/wasm/instruction/index.ts b/source/wasm/instruction/index.ts index 821f37d..d43bc60 100644 --- a/source/wasm/instruction/index.ts +++ b/source/wasm/instruction/index.ts @@ -50,14 +50,31 @@ const shared_NoOp = new NoOp(); const wrapper = { const: constFuncs, ...varFuncs, - ...memFuncs, - ...numFuncs, + i32: { + ...memFuncs.i32, + ...numFuncs.i32, + }, + i64: { + ...memFuncs.i64, + ...numFuncs.i32, + }, + f32: { + ...numFuncs.f32, + ...memFuncs.f32, + }, + f64: { + ...numFuncs.f64, + ...memFuncs.f64, + }, unreachable: () => shared_Unreachable, return : () => shared_Return, drop : () => shared_Drop, noop : () => shared_NoOp, + copy: memFuncs.copy, + fill: memFuncs.fill, + block: (typeIdx: number, n?: Any[]) => new Block(typeIdx, n), if : (typeIdx: number, t?: Any[], f?: Any[]) => new IfBlock(typeIdx, t, f), loop : (typeIdx: number, n?: Any[]) => new Loop(typeIdx, n), diff --git a/source/wasm/instruction/memory.ts b/source/wasm/instruction/memory.ts index ab8570d..443d1ed 100644 --- a/source/wasm/instruction/memory.ts +++ b/source/wasm/instruction/memory.ts @@ -1,4 +1,5 @@ // https://webassembly.github.io/spec/core/binary/instructions.html#numeric-instructions +import { LatentOffset } from "~/helper.ts"; import { EncodeU32 } from "~/wasm/type.ts"; import { Byte } from "~/helper.ts"; @@ -34,10 +35,10 @@ export enum Type { export class MemoryRegister { type : Type; - offset : number; + offset : number | LatentOffset; align : number; - constructor(type: Type, offset: number, align: number) { + constructor(type: Type, offset: number | LatentOffset, align: number) { this.type = type; this.offset = offset; this.align = align; @@ -47,38 +48,89 @@ export class MemoryRegister { return [ this.type, ...EncodeU32(this.align), - ...EncodeU32(this.offset), + ...EncodeU32( + this.offset instanceof LatentOffset + ? this.offset.get() + : this.offset + ), ]; } } +export class MemoryCopy { + fromIdx: number; + toIdx: number; + + constructor(fromIdx: Byte, toIdx: Byte) { + this.fromIdx = fromIdx; + this.toIdx = toIdx; + } + + toBinary(): Byte[] { + return [ + 0xFC, + ...EncodeU32(10), + this.fromIdx, + this.toIdx + ] + } +} + +export class MemoryFill { + memoryIdx: number; + + constructor(memoryIdx: Byte) { + this.memoryIdx = memoryIdx; + } + + toBinary(): Byte[] { + return [ + 0xFC, + ...EncodeU32(11), + this.memoryIdx, + ] + } +} + const wrapper = { i32: { - load : (offset: number, align: number) => new MemoryRegister(Type.i32Load, offset, align), - store : (offset: number, align: number) => new MemoryRegister(Type.i32Store, offset, align), + load : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i32Load, offset, align), + store : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i32Store, offset, align), - load8_u : (offset: number, align: number) => new MemoryRegister(Type.i32Load8u, offset, align), - load8_s : (offset: number, align: number) => new MemoryRegister(Type.i32Load8s, offset, align), - load16_u : (offset: number, align: number) => new MemoryRegister(Type.i32Load16u, offset, align), - load16_s : (offset: number, align: number) => new MemoryRegister(Type.i32Load16s, offset, align), + load8_u : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i32Load8u, offset, align), + load8_s : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i32Load8s, offset, align), + load16_u : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i32Load16u, offset, align), + load16_s : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i32Load16s, offset, align), - store8 : (offset: number, align: number) => new MemoryRegister(Type.i32Store8, offset, align), - store16 : (offset: number, align: number) => new MemoryRegister(Type.i32Store16, offset, align), + store8 : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i32Store8, offset, align), + store16 : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i32Store16, offset, align), }, i64: { - load : (offset: number, align: number) => new MemoryRegister(Type.i64Load, offset, align), - store : (offset: number, align: number) => new MemoryRegister(Type.i64Store, offset, align), - - load8_u : (offset: number, align: number) => new MemoryRegister(Type.i64Load8u, offset, align), - load8_s : (offset: number, align: number) => new MemoryRegister(Type.i64Load8s, offset, align), - load16_u : (offset: number, align: number) => new MemoryRegister(Type.i64Load16u, offset, align), - load16_s : (offset: number, align: number) => new MemoryRegister(Type.i64Load16s, offset, align), - load32_u : (offset: number, align: number) => new MemoryRegister(Type.i64Load32u, offset, align), - load32_s : (offset: number, align: number) => new MemoryRegister(Type.i64Load32s, offset, align), - - store8 : (offset: number, align: number) => new MemoryRegister(Type.i64Store8, offset, align), - store16 : (offset: number, align: number) => new MemoryRegister(Type.i64Store16, offset, align), - store32 : (offset: number, align: number) => new MemoryRegister(Type.i64Store32, offset, align), + load : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Load, offset, align), + store : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Store, offset, align), + + load8_u : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Load8u, offset, align), + load8_s : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Load8s, offset, align), + load16_u : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Load16u, offset, align), + load16_s : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Load16s, offset, align), + load32_u : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Load32u, offset, align), + load32_s : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Load32s, offset, align), + + store8 : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Store8, offset, align), + store16 : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Store16, offset, align), + store32 : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.i64Store32, offset, align), + }, + + f32: { + load : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.f32Load, offset, align), + store : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.f32Store, offset, align), }, + f64: { + load : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.f64Load, offset, align), + store : (offset: number | LatentOffset, align: number) => new MemoryRegister(Type.f64Store, offset, align), + }, + + copy: (fromMemoryIdx = 0, toMemoryIdx = 0) => new MemoryCopy(fromMemoryIdx, toMemoryIdx), + fill: (memoryIdx = 0) => new MemoryFill(memoryIdx), } export default wrapper; \ No newline at end of file diff --git a/source/wasm/instruction/variable.ts b/source/wasm/instruction/variable.ts index b9c2f7b..3b79ac0 100644 --- a/source/wasm/instruction/variable.ts +++ b/source/wasm/instruction/variable.ts @@ -34,8 +34,8 @@ export class Variable { const wrapper = { global: { - get: (x: number) => new Variable(Type.globalGet, x), - set: (x: number) => new Variable(Type.globalSet, x) + get: (x: LocalRef | number) => new Variable(Type.globalGet, x), + set: (x: LocalRef | number) => new Variable(Type.globalSet, x) }, local: { get: (x: LocalRef | number) => new Variable(Type.localGet, x), diff --git a/source/wasm/module.ts b/source/wasm/module.ts index 7b85eb2..a921c4f 100644 --- a/source/wasm/module.ts +++ b/source/wasm/module.ts @@ -3,6 +3,7 @@ import * as Section from "~/wasm/section/index.ts"; import { MemoryRef } from "~/wasm/memoryRef.ts"; import { Intrinsic } from "~/wasm/type.ts"; +import { Constant } from "~/wasm/instruction/constant.ts"; import { Function } from "~/wasm/function.ts"; import { FuncRef } from "~/wasm/funcRef.ts"; import { Byte } from "~/helper.ts"; @@ -14,7 +15,9 @@ export default class Module { typeSect : Section.Type; importSect : Section.Import; memorySect : Section.Memory; + globalSect : Section.Global; exportSect : Section.Export; + startSect : Section.Start; dataSect : Section.Data; entryFunc : null | FuncRef; @@ -25,7 +28,9 @@ export default class Module { this.typeSect = new Section.Type(); this.importSect = new Section.Import(); this.memorySect = new Section.Memory(); + this.globalSect = new Section.Global(); this.exportSect = new Section.Export(); + this.startSect = new Section.Start(); this.dataSect = new Section.Data(); this.entryFunc = null; this.funcs = []; @@ -44,6 +49,10 @@ export default class Module { return this.exportSect.bind(name, func); } + startFunction(func: FuncRef) { + return this.startSect.ref = func; + } + exportMemory(name: string, mem: MemoryRef) { return this.exportSect.bind(name, mem); } @@ -67,6 +76,10 @@ export default class Module { return func; } + registerGlobal(type: Intrinsic, mut: boolean, expr: Constant) { + return this.globalSect.bind(type, mut, expr); + } + bindFunction(func: Function) { if (this.funcs.includes(func)) return; @@ -103,7 +116,7 @@ export default class Module { ); // table* : tablesec buffer.push(...this.memorySect.toBinary(0)) // mem* : memsec - // global* : globalsec + buffer.push(...this.globalSect.toBinary()) // global* : globalsec buffer.push(...this.exportSect.toBinary()) // export* : exportsec if (this.entryFunc) { diff --git a/source/wasm/section/global.ts b/source/wasm/section/global.ts index 2f0d651..0fb8165 100644 --- a/source/wasm/section/global.ts +++ b/source/wasm/section/global.ts @@ -1,14 +1,60 @@ +import { Intrinsic } from "~/wasm/type.ts"; import { EncodeU32 } from "~/wasm/type.ts"; +import { Constant } from "~/wasm/instruction/constant.ts"; +import { LocalRef } from "~/wasm/funcRef.ts"; +import { Byte } from "~/helper.ts"; +export class GlobalRegister { + mutable: boolean; + expr: Constant; + ref: LocalRef; -export default class GlobalSection { + constructor(type: Intrinsic, mutable: boolean, expr: Constant, index: number) { + this.ref = new LocalRef(type); + this.mutable = mutable; + this.expr = expr; + } - constructor() {} + toBinary(): Byte[] { + return [ + this.ref.type, + this.mutable ? 0x01 : 0x00, - toBinary () { - const size = 0; - return [GlobalSection.typeID, ...EncodeU32(size)]; + ...this.expr.toBinary(), + 0x0B // expr end + ]; } +} +export default class GlobalSection { static typeID = 6; + + private bindings: GlobalRegister[]; + + constructor() { + this.bindings = []; + } + + bind(type: Intrinsic, mut: boolean, expr: Constant) { + const idx = this.bindings.length; + + const n = new GlobalRegister(type, mut, expr, idx); + n.ref.resolve(idx); + + this.bindings.push(n); + return n; + } + + toBinary () { + const buf = EncodeU32(this.bindings.length); + for (const bind of this.bindings) { + buf.push(...bind.toBinary()); + } + + return [ + GlobalSection.typeID, + ...EncodeU32(buf.length), + ...buf + ]; + } } \ No newline at end of file diff --git a/source/wasm/section/start.ts b/source/wasm/section/start.ts index f8585ea..07b8592 100644 --- a/source/wasm/section/start.ts +++ b/source/wasm/section/start.ts @@ -3,6 +3,12 @@ import { FuncRef } from "~/wasm/funcRef.ts"; export default class StartSection { + static typeID = 8; + ref: null | FuncRef; + + constructor () { + this.ref = null; + } static toBinary (ref: null | FuncRef) { const buf = []; @@ -20,6 +26,4 @@ export default class StartSection { ...buf ]; } - - static typeID = 8; } \ No newline at end of file diff --git a/tests/compiler/fibonacci.test.ts b/tests/compiler/fibonacci.test.ts deleted file mode 100644 index ef4789c..0000000 --- a/tests/compiler/fibonacci.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/// -import { fail, assertNotEquals, assert, assertEquals } from "https://deno.land/std@0.201.0/assert/mod.ts"; -import * as CompilerFunc from "../../source/compiler/function.ts"; -import Project from "../../source/compiler/project.ts"; -import { FuncRef } from "../../source/wasm/funcRef.ts"; - -Deno.test(`Signed integer Fibonacci test`, async () => { - const project = new Project("./"); - const mainFile = project.importRaw(` - fn fibonacci(n: i32): i32 { - return fibonacci_tail(n, 0, 1); - } - - fn fibonacci_tail(n: i32, a: i32, b: i32): i32 { - return if n <= 0 a else fibonacci_tail(n - 1, b, a + b); - }` - ); - - const mainFunc = mainFile.namespace["fibonacci"]; - assert(mainFunc instanceof CompilerFunc.default, "Missing main function"); - mainFunc.compile(); - assertNotEquals(mainFunc.ref, null, "Main function hasn't compiled"); - project.module.exportFunction("fibonacci", mainFunc.ref as FuncRef); - - // Load the wasm module - const wasmModule = new WebAssembly.Module(project.module.toBinary()); - - try { - // Instantiate the wasm module - const instance = await WebAssembly.instantiate(wasmModule, {}); - const exports = instance.exports; - - // Call the _start function - if (typeof exports.fibonacci === "function") { - const fibonacci = exports.fibonacci as Function; - assertEquals(fibonacci(3), 2); - assertEquals(fibonacci(4), 3); - assertEquals(fibonacci(5), 5); - assertEquals(fibonacci(6), 8); - assertEquals(fibonacci(24), 46368); - assertEquals(fibonacci(46), 1836311903); - } else { - fail(`Expected fibonacci to be a function`); - } - - } catch (err) { - // If there's an error, the test will fail - fail(`Failed to run wasm module: ${err}`); - } -}); \ No newline at end of file diff --git a/tests/e2e/compiler/fibonacci.test.ts b/tests/e2e/compiler/fibonacci.test.ts new file mode 100644 index 0000000..3e4ada9 --- /dev/null +++ b/tests/e2e/compiler/fibonacci.test.ts @@ -0,0 +1,84 @@ +/// +import { fail, assertNotEquals, assert, assertEquals } from "https://deno.land/std@0.201.0/assert/mod.ts"; + +import * as CompilerFunc from "~/compiler/function.ts"; +import Package from "~/compiler/package.ts"; +import Project from "~/compiler/project.ts"; +import { FuncRef } from "~/wasm/funcRef.ts"; + +Deno.test(`Signed integer Fibonacci test`, async () => { + const project = new Project(); + const mainPck = new Package(project, "./"); + const mainFile = mainPck.importRaw(` + fn fib_recur(n: i32): i32 { + if n <= 1 { return n; }; + return fib_recur(n - 1) + fib_recur(n - 2); + } + + fn fib_tail(n: i32, a: i32, b: i32): i32 { + if n <= 0 { + return a; + } else { + return fib_tail(n - 1, b, a + b); + }; + }` + ); + + { + const func = mainFile.namespace["fib_tail"]; + assert(func instanceof CompilerFunc.default, "Missing fib_tail function"); + func.compile(); + assertNotEquals(func.ref, null, "Main function hasn't compiled"); + project.module.exportFunction("fib_tail", func.ref as FuncRef); + } + + { + const func = mainFile.namespace["fib_recur"]; + assert(func instanceof CompilerFunc.default, "Missing recursive fibonacci function"); + func.compile(); + assertNotEquals(func.ref, null, "Main function hasn't compiled"); + project.module.exportFunction("fib_recur", func.ref as FuncRef); + } + + // Load the wasm module + const wasmModule = new WebAssembly.Module(project.module.toBinary()); + + try { + // Instantiate the wasm module + const instance = await WebAssembly.instantiate(wasmModule, {}); + const exports = instance.exports; + + if (typeof exports.fib_recur === "function") { + const fib_recur = exports.fib_recur as Function; + console.time("Recursive fibonacci"); + assertEquals(fib_recur(3), 2); + assertEquals(fib_recur(4), 3); + assertEquals(fib_recur(5), 5); + assertEquals(fib_recur(6), 8); + assertEquals(fib_recur(24), 46368); + assertEquals(fib_recur(38), 39088169); // stack overflow past this + console.timeEnd("Recursive fibonacci"); + } else { + fail(`Expected fib_recur to be a function`); + } + + if (typeof exports.fib_tail === "function") { + const fib_tail = exports.fib_tail as Function; + console.time("Tail call fibonacci"); + assertEquals(fib_tail(3, 0, 1), 2); + assertEquals(fib_tail(4, 0, 1), 3); + assertEquals(fib_tail(5, 0, 1), 5); + assertEquals(fib_tail(6, 0, 1), 8); + assertEquals(fib_tail(24, 0, 1), 46368); + assertEquals(fib_tail(38, 0, 1), 39088169); + console.timeEnd("Tail call fibonacci"); + assertEquals(fib_tail(46, 0, 1), 1836311903); // integer overflow past this + } else { + fail(`Expected fib_tail to be a function`); + } + + } catch (err) { + // If there's an error, the test will fail + fail(`Failed to run wasm module: ${err}`); + } +}); \ No newline at end of file diff --git a/tests/compiler/numeric.test.ts b/tests/e2e/compiler/numeric.test.ts similarity index 83% rename from tests/compiler/numeric.test.ts rename to tests/e2e/compiler/numeric.test.ts index f83b8aa..9311509 100644 --- a/tests/compiler/numeric.test.ts +++ b/tests/e2e/compiler/numeric.test.ts @@ -1,8 +1,10 @@ /// import { fail, assertEquals, assertNotEquals, assert } from "https://deno.land/std@0.201.0/assert/mod.ts"; -import * as CompilerFunc from "../../source/compiler/function.ts"; -import Project from "../../source/compiler/project.ts"; -import { FuncRef } from "../../source/wasm/funcRef.ts"; + +import * as CompilerFunc from "~/compiler/function.ts"; +import Package from "~/compiler/package.ts"; +import Project from "~/compiler/project.ts"; +import { FuncRef } from "~/wasm/funcRef.ts"; const decoder = new TextDecoder(); @@ -14,8 +16,9 @@ fn main(): f32 { }`; Deno.test(`Numeric logic test`, async () => { - const project = new Project("./"); - const mainFile = project.importRaw(source); + const project = new Project(); + const mainPck = new Package(project, "./"); + const mainFile = mainPck.importRaw(source); const mainFunc = mainFile.namespace["main"]; @@ -25,7 +28,6 @@ Deno.test(`Numeric logic test`, async () => { project.module.exportFunction("_start", mainFunc.ref as FuncRef); let stdout = ""; - let memory: WebAssembly.Memory; const imports = { @@ -56,7 +58,7 @@ Deno.test(`Numeric logic test`, async () => { // Call the _start function if (typeof exports._start === "function") { - const out = (exports._start as Function)() as any; + (exports._start as Function)() as any; } else { fail(`Expected _start to be a function`); } diff --git a/tests/wasm/hello-world.test.ts b/tests/e2e/wasm/hello-world.test.ts similarity index 97% rename from tests/wasm/hello-world.test.ts rename to tests/e2e/wasm/hello-world.test.ts index c62e370..c15e448 100644 --- a/tests/wasm/hello-world.test.ts +++ b/tests/e2e/wasm/hello-world.test.ts @@ -1,6 +1,7 @@ /// import { fail, assertEquals } from "https://deno.land/std@0.201.0/assert/mod.ts"; -import { Module, Instruction, Type } from "../../source/wasm/index.ts"; + +import { Module, Instruction, Type } from "~/wasm/index.ts"; const decoder = new TextDecoder(); diff --git a/tests/wasm/type.test.ts b/tests/e2e/wasm/type.test.ts similarity index 95% rename from tests/wasm/type.test.ts rename to tests/e2e/wasm/type.test.ts index 4b5ec78..012923e 100644 --- a/tests/wasm/type.test.ts +++ b/tests/e2e/wasm/type.test.ts @@ -1,6 +1,7 @@ /// import { assertEquals, assertThrows } from "https://deno.land/std@0.201.0/assert/mod.ts"; -import { EncodeSignedLEB, EncodeUnsignedLEB } from "../../source/wasm/type.ts"; + +import { EncodeSignedLEB, EncodeUnsignedLEB } from "~/wasm/type.ts"; function toHex(arr: number[]): string { return arr.map(x => x.toString(16).padStart(2, "0")).join(""); diff --git a/tests/source/codegen/allocation/stack.test.ts b/tests/source/codegen/allocation/stack.test.ts new file mode 100644 index 0000000..b19020c --- /dev/null +++ b/tests/source/codegen/allocation/stack.test.ts @@ -0,0 +1,114 @@ +/// +import { assert } from "https://deno.land/std@0.201.0/assert/mod.ts"; + +import { StackAllocator } from "~/compiler/codegen/allocation/stack.ts" + + +Deno.test(`Simple Stack Allocation`, () => { + const stack = new StackAllocator(); + + const a = stack.allocate(1, 1); a.tag = "A"; + const b = stack.allocate(4, 1); b.tag = "B"; + const c = stack.allocate(2, 1); c.tag = "C"; + + a.free(); + b.free(); + c.free(); + + stack.resolve(); + + const ptrA = a.getOffset().get(); + const ptrB = b.getOffset().get(); + const ptrC = c.getOffset().get(); + assert(ptrA < ptrB); + assert(ptrA < ptrC); + assert(ptrB < ptrC); +}); + +Deno.test(`Region Reuse`, () => { + const stack = new StackAllocator(); + + const a = stack.allocate(1, 1); a.tag = "A"; + + const b = stack.allocate(4, 1); b.tag = "B"; + const c = stack.allocate(4, 1); c.tag = "C"; + b.free(); + + const d = stack.allocate(2, 1); d.tag = "D"; + a.free(); + c.free(); + d.free(); + + stack.resolve(); + + const ptrA = a.getOffset().get(); + const ptrB = b.getOffset().get(); + const ptrC = c.getOffset().get(); + const ptrD = d.getOffset().get(); + assert(ptrA < ptrB); + assert(ptrB < ptrC); + assert(ptrB == ptrD); +}); + +Deno.test(`Nested Stack Allocation`, () => { + const stack = new StackAllocator(); + + const a = stack.allocate(1, 1); a.tag = "A"; + + const check = stack.checkpoint(); + const b = stack.allocate(4, 1); b.tag = "B"; + b.free(); + check.rewind(); + check.restore(); + + const c = stack.allocate(2, 1); c.tag = "C"; + a.free(); + c.free(); + + stack.resolve(); + + const ptrA = a.getOffset().get(); + const ptrB = b.getOffset().get(); + const ptrC = c.getOffset().get(); + assert(ptrA < ptrB); + assert(ptrA < ptrC); + assert(ptrB == ptrC); +}); + +Deno.test(`Branch Merging`, () => { + const stack = new StackAllocator(); + + const a = stack.allocate(1, 1); a.tag = "A"; + + // if { + const check = stack.checkpoint(); + const b = stack.allocate(4, 1); b.tag = "B"; + const c = stack.allocate(4, 1); c.tag = "C"; + b.free(); + check.rewind(); + // } else { + const d = stack.allocate(4, 1); d.tag = "D"; + d.makeAlias(c); + check.rewind(); + // } + check.restore(); + + const e = stack.allocate(2, 1); e.tag = "E"; + a.free(); + e.free(); + c.free(); + + stack.resolve(); + + const ptrA = a.getOffset().get(); + const ptrB = b.getOffset().get(); + const ptrC = c.getOffset().get(); + const ptrD = d.getOffset().get(); + const ptrE = e.getOffset().get(); + + assert(ptrA < ptrB); + assert(ptrB > ptrC); + assert(ptrC == ptrD); + assert(ptrC < ptrE); + assert(ptrA < ptrE); +}); \ No newline at end of file diff --git a/tests/source/codegen/expression/precedence.test.ts b/tests/source/codegen/expression/precedence.test.ts new file mode 100644 index 0000000..c3ba070 --- /dev/null +++ b/tests/source/codegen/expression/precedence.test.ts @@ -0,0 +1,10 @@ +/// +import { assertEquals } from "https://deno.land/std@0.201.0/assert/mod.ts"; + +import { GetPrecedence } from "~/compiler/codegen/expression/precedence.ts"; + +Deno.test("Check precedence of two operators", () => { + assertEquals(GetPrecedence("+", "*"), 1); + assertEquals(GetPrecedence("+", "-"), 0); + assertEquals(GetPrecedence("*", "+"), -1); +}); \ No newline at end of file diff --git a/tools/vscode-extension/syntaxes/salient.tmLanguage.json b/tools/vscode-extension/syntaxes/salient.tmLanguage.json index 67610d0..cba5d02 100644 --- a/tools/vscode-extension/syntaxes/salient.tmLanguage.json +++ b/tools/vscode-extension/syntaxes/salient.tmLanguage.json @@ -4,6 +4,7 @@ "patterns": [ {"include": "#comment"}, {"include": "#function"}, + {"include": "#structure"}, {"include": "#block"} ], "repository": { @@ -214,11 +215,47 @@ ] }, + "structure": { + "name": "meta.body.struct.sa", + "begin": "\\b(struct)\\s+(\\w+)\\s*(:\\s*(\\w+)\\s*)?\\{", + "beginCaptures": { + "1": { "name": "storage.type.struct.sa" }, + "2": { "name": "entity.name.type.struct.sa" }, + "4": { "name": "storage.type.sa" }, + "5": { "name": "punctuation.section.block.begin.bracket.curly.struct" } + }, + "end": "\\}", + "endCaptures": { + "0": { "name": "punctuation.section.block.end.bracket.curly.struct.sa" } + }, + "patterns": [ + { "include": "#comment" }, + { + "name": "declare.sa", + "match": "\\b(\\w+)(:)\\s*(\\w+)\\s*(;)", + "captures": { + "1": { "name": "variable.sa" }, + "2": { "name": "keyword.operator.sa" }, + "3": { "name": "storage.type.sa" }, + "4": { "name": "punctuation.terminator.statement.sa" } + } + }, + { + "name": "spreat.sa", + "match": "(\\.\\.\\.)(\\w+)(;)", + "captures": { + "1": { "name": "keyword.operator.sa" }, + "2": { "name": "variable.sa" } + } + } + ] + }, + "declare": { "patterns": [ { "name": "declare.sa", - "begin": "\\b(let)\\s+(\\w+)((:)\\s*(\\w+))?\\s*(=)", + "begin": "\\b(let)\\s+(\\w+)\\s*((:)\\s*(\\w+))?\\s*(=)", "beginCaptures": { "1": { "name": "storage.type.sa" }, "2": { "name": "variable.sa" },