fix: multi-arg calls, uninitialized symbols, param limit; add banner img; update docs
- Fix segfault from uninitialized Symbol structs in scope/hir_lower/sema - Fix null ReadFile crash in Cli_MergeFileInto (missing stdlib files) - Extend function params from 6 to 9 (bux_str_format needs 9 args) - Add ExprList/HirArgList linked lists for >2 call arguments - Add banner image to README - Update docs: C backend is now primary (not QBE)
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
# Bux Programming Language
|
# Bux Programming Language
|
||||||
|
|
||||||
> **Status:** Self-hosting phase — `buxc2` compiles `.bux` → QBE SSA → native binary. Bootstrap (`buxc`, Nim) maintains backward compatibility via C transpiler.
|

|
||||||
|
|
||||||
Bux is a fast, compiled, strongly-typed systems programming language. Features a QBE backend for native code generation, raw multi-line strings, gradual ownership, async/await, generics, algebraic enums, and a package manager.
|
> **Status:** Self-hosting phase — `buxc2` compiles `.bux` → C → native binary. Bootstrap (`buxc`, Nim) builds the self-hosted compiler.
|
||||||
|
|
||||||
|
Bux is a fast, compiled, strongly-typed systems programming language. Features a C backend for native code generation, raw multi-line strings, gradual ownership, async/await, generics, algebraic enums, and a package manager.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -148,7 +150,7 @@ func Main() -> int {
|
|||||||
| **Interfaces** | `interface` + `extend` for trait-like behavior |
|
| **Interfaces** | `interface` + `extend` for trait-like behavior |
|
||||||
| **Error Handling** | `Result<T,E>`, `Option<T>`, and the `?` operator |
|
| **Error Handling** | `Result<T,E>`, `Option<T>`, and the `?` operator |
|
||||||
| **Standard Library** | `Io`, `Array`, `String`, `Map`, `Fs`, `Mem`, `Set`, `Path`, `Math`, `Task`, `Channel` |
|
| **Standard Library** | `Io`, `Array`, `String`, `Map`, `Fs`, `Mem`, `Set`, `Path`, `Math`, `Task`, `Channel` |
|
||||||
| **Backend** | QBE native codegen (self-hosting), C transpiler (bootstrap) |
|
| **Backend** | C transpiler (self-hosting + bootstrap) |
|
||||||
| **Strings** | Raw multi-line backtick strings (`...`), C-string interop |
|
| **Strings** | Raw multi-line backtick strings (`...`), C-string interop |
|
||||||
| **Gradual Ownership** | `@[Checked]` + `&T`/`&mut T` borrow checking |
|
| **Gradual Ownership** | `@[Checked]` + `&T`/`&mut T` borrow checking |
|
||||||
| **Async/Await** | `async func`, `spawn`, `.await` with stackful coroutines |
|
| **Async/Await** | `async func`, `spawn`, `.await` with stackful coroutines |
|
||||||
@@ -189,7 +191,7 @@ bux/
|
|||||||
# Build bootstrap compiler (Nim → C)
|
# Build bootstrap compiler (Nim → C)
|
||||||
make build
|
make build
|
||||||
|
|
||||||
# Build self-hosted compiler (Bux → QBE SSA → native)
|
# Build self-hosted compiler (Bux → C → native)
|
||||||
make selfhost
|
make selfhost
|
||||||
|
|
||||||
# Run all tests
|
# Run all tests
|
||||||
|
|||||||
+13
-1
@@ -96,6 +96,11 @@ const ekMatch: int = 22;
|
|||||||
const ekSpawn: int = 24;
|
const ekSpawn: int = 24;
|
||||||
const ekAwait: int = 25;
|
const ekAwait: int = 25;
|
||||||
|
|
||||||
|
struct ExprList {
|
||||||
|
expr: *Expr,
|
||||||
|
next: *ExprList,
|
||||||
|
}
|
||||||
|
|
||||||
struct Expr {
|
struct Expr {
|
||||||
kind: int,
|
kind: int,
|
||||||
line: uint32,
|
line: uint32,
|
||||||
@@ -121,6 +126,9 @@ struct Expr {
|
|||||||
// Struct init fields
|
// Struct init fields
|
||||||
structName: String,
|
structName: String,
|
||||||
structFieldCount: int,
|
structFieldCount: int,
|
||||||
|
// Call arguments (linked list for multi-arg support)
|
||||||
|
callArgs: *ExprList,
|
||||||
|
callArgCount: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -241,6 +249,9 @@ struct Decl {
|
|||||||
param3: Param,
|
param3: Param,
|
||||||
param4: Param,
|
param4: Param,
|
||||||
param5: Param,
|
param5: Param,
|
||||||
|
param6: Param,
|
||||||
|
param7: Param,
|
||||||
|
param8: Param,
|
||||||
retType: *TypeExpr,
|
retType: *TypeExpr,
|
||||||
// Body
|
// Body
|
||||||
refBody: *Block,
|
refBody: *Block,
|
||||||
@@ -361,7 +372,8 @@ func Ast_MakeExpr(kind: int, line: uint32, col: uint32) -> Expr {
|
|||||||
child1: null as *Expr, child2: null as *Expr, child3: null as *Expr,
|
child1: null as *Expr, child2: null as *Expr, child3: null as *Expr,
|
||||||
refType: null as *TypeExpr, refBlock: null as *Block,
|
refType: null as *TypeExpr, refBlock: null as *Block,
|
||||||
genericCallee: "", genericTypeArg0: "", genericTypeArg1: "", genericTypeArgCount: 0,
|
genericCallee: "", genericTypeArg0: "", genericTypeArg1: "", genericTypeArgCount: 0,
|
||||||
structName: "", structFieldCount: 0 };
|
structName: "", structFieldCount: 0,
|
||||||
|
callArgs: null as *ExprList, callArgCount: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
func Ast_MakeIdent(name: String, line: uint32, col: uint32) -> Expr {
|
func Ast_MakeIdent(name: String, line: uint32, col: uint32) -> Expr {
|
||||||
|
|||||||
@@ -134,12 +134,29 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) {
|
|||||||
if kind == hCall {
|
if kind == hCall {
|
||||||
StringBuilder_Append(&cbe.sb, node.strValue);
|
StringBuilder_Append(&cbe.sb, node.strValue);
|
||||||
StringBuilder_Append(&cbe.sb, "(");
|
StringBuilder_Append(&cbe.sb, "(");
|
||||||
|
var needsComma: bool = false;
|
||||||
if node.child1 != null as *HirNode {
|
if node.child1 != null as *HirNode {
|
||||||
CBE_EmitExpr(cbe, node.child1);
|
CBE_EmitExpr(cbe, node.child1);
|
||||||
|
needsComma = true;
|
||||||
}
|
}
|
||||||
if node.child2 != null as *HirNode {
|
if node.child2 != null as *HirNode {
|
||||||
|
if needsComma {
|
||||||
StringBuilder_Append(&cbe.sb, ", ");
|
StringBuilder_Append(&cbe.sb, ", ");
|
||||||
|
}
|
||||||
CBE_EmitExpr(cbe, node.child2);
|
CBE_EmitExpr(cbe, node.child2);
|
||||||
|
needsComma = true;
|
||||||
|
}
|
||||||
|
// Emit extra args from linked list
|
||||||
|
var ai: int = 0;
|
||||||
|
var curExtra: *HirArgList = node.extraData as *HirArgList;
|
||||||
|
while ai < node.extraCount {
|
||||||
|
if needsComma {
|
||||||
|
StringBuilder_Append(&cbe.sb, ", ");
|
||||||
|
}
|
||||||
|
CBE_EmitExpr(cbe, curExtra.node);
|
||||||
|
needsComma = true;
|
||||||
|
curExtra = curExtra.next;
|
||||||
|
ai = ai + 1;
|
||||||
}
|
}
|
||||||
StringBuilder_Append(&cbe.sb, ")");
|
StringBuilder_Append(&cbe.sb, ")");
|
||||||
return;
|
return;
|
||||||
@@ -414,6 +431,9 @@ func CBE_EmitFuncDecl(cbe: *CEmitter, f: *HirFunc) {
|
|||||||
if i == 3 { pname = f.param3.name; ptype = f.param3.typeName; }
|
if i == 3 { pname = f.param3.name; ptype = f.param3.typeName; }
|
||||||
if i == 4 { pname = f.param4.name; ptype = f.param4.typeName; }
|
if i == 4 { pname = f.param4.name; ptype = f.param4.typeName; }
|
||||||
if i == 5 { pname = f.param5.name; ptype = f.param5.typeName; }
|
if i == 5 { pname = f.param5.name; ptype = f.param5.typeName; }
|
||||||
|
if i == 6 { pname = f.param6.name; ptype = f.param6.typeName; }
|
||||||
|
if i == 7 { pname = f.param7.name; ptype = f.param7.typeName; }
|
||||||
|
if i == 8 { pname = f.param8.name; ptype = f.param8.typeName; }
|
||||||
// Emit type
|
// Emit type
|
||||||
if String_Eq(ptype, "String") || String_Eq(ptype, "str") {
|
if String_Eq(ptype, "String") || String_Eq(ptype, "str") {
|
||||||
StringBuilder_Append(&cbe.sb, "String ");
|
StringBuilder_Append(&cbe.sb, "String ");
|
||||||
@@ -474,6 +494,9 @@ func CBE_FuncHasGeneric(f: *HirFunc) -> bool {
|
|||||||
if pi == 3 { ptype = f.param3.typeName; }
|
if pi == 3 { ptype = f.param3.typeName; }
|
||||||
if pi == 4 { ptype = f.param4.typeName; }
|
if pi == 4 { ptype = f.param4.typeName; }
|
||||||
if pi == 5 { ptype = f.param5.typeName; }
|
if pi == 5 { ptype = f.param5.typeName; }
|
||||||
|
if pi == 6 { ptype = f.param6.typeName; }
|
||||||
|
if pi == 7 { ptype = f.param7.typeName; }
|
||||||
|
if pi == 8 { ptype = f.param8.typeName; }
|
||||||
if CBE_IsGenericTypeName(ptype) { return true; }
|
if CBE_IsGenericTypeName(ptype) { return true; }
|
||||||
pi = pi + 1;
|
pi = pi + 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -400,8 +400,13 @@ func Cli_CollectStdlibImports(mod: *Module, outPaths: *String, maxCount: int, st
|
|||||||
func Cli_MergeFileInto(target: *Module, path: String, skipNames: *String, skipCount: int) -> int {
|
func Cli_MergeFileInto(target: *Module, path: String, skipNames: *String, skipCount: int) -> int {
|
||||||
Print("DEBUG: MergeFileInto ");
|
Print("DEBUG: MergeFileInto ");
|
||||||
PrintLine(path);
|
PrintLine(path);
|
||||||
|
if !FileExists(path) {
|
||||||
|
Print("Error: stdlib file not found: ");
|
||||||
|
PrintLine(path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
let source: String = ReadFile(path);
|
let source: String = ReadFile(path);
|
||||||
if String_Eq(source, "") { return 0; }
|
if source == null as String || String_Eq(source, "") { return 0; }
|
||||||
let lex: *Lexer = Lexer_Tokenize(source);
|
let lex: *Lexer = Lexer_Tokenize(source);
|
||||||
if Lexer_DiagCount(lex) > 0 { return 0; }
|
if Lexer_DiagCount(lex) > 0 { return 0; }
|
||||||
let mod: *Module = Parser_Parse(lex.tokens, lex.tokenCount);
|
let mod: *Module = Parser_Parse(lex.tokens, lex.tokenCount);
|
||||||
|
|||||||
@@ -34,6 +34,15 @@ const hMatch: int = 28;
|
|||||||
const hSpawn: int = 29;
|
const hSpawn: int = 29;
|
||||||
const hAwait: int = 30;
|
const hAwait: int = 30;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// HirArgList — linked list for call arguments beyond 2
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct HirArgList {
|
||||||
|
node: *HirNode,
|
||||||
|
next: *HirArgList,
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// HirNode — unified struct with tagged union pattern
|
// HirNode — unified struct with tagged union pattern
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -76,6 +85,9 @@ struct HirFunc {
|
|||||||
param3: HirParam;
|
param3: HirParam;
|
||||||
param4: HirParam;
|
param4: HirParam;
|
||||||
param5: HirParam;
|
param5: HirParam;
|
||||||
|
param6: HirParam;
|
||||||
|
param7: HirParam;
|
||||||
|
param8: HirParam;
|
||||||
retTypeKind: int;
|
retTypeKind: int;
|
||||||
retTypeName: String;
|
retTypeName: String;
|
||||||
body: *HirNode;
|
body: *HirNode;
|
||||||
|
|||||||
+69
-10
@@ -180,11 +180,34 @@ func Lcx_LowerExpr(ctx: *LowerCtx, expr: *Expr) -> *HirNode {
|
|||||||
// Lower receiver as first argument
|
// Lower receiver as first argument
|
||||||
let recv: *HirNode = Lcx_LowerExpr(ctx, expr.child1.child1);
|
let recv: *HirNode = Lcx_LowerExpr(ctx, expr.child1.child1);
|
||||||
n.child1 = recv;
|
n.child1 = recv;
|
||||||
// Lower remaining arguments
|
// Lower remaining arguments from linked list
|
||||||
if expr.child2 != null as *Expr {
|
var arg: *ExprList = expr.callArgs;
|
||||||
let extra: *HirNode = Lcx_LowerExpr(ctx, expr.child2);
|
var argIdx: int = 0;
|
||||||
// Chain extra args after receiver via child2/child3
|
while arg != null as *ExprList {
|
||||||
n.child2 = extra;
|
let lowered: *HirNode = Lcx_LowerExpr(ctx, arg.expr);
|
||||||
|
if argIdx == 0 {
|
||||||
|
n.child2 = lowered;
|
||||||
|
} else if argIdx == 1 {
|
||||||
|
// Third argument — start linked list
|
||||||
|
let firstExtra: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
|
||||||
|
firstExtra.node = lowered;
|
||||||
|
firstExtra.next = null as *HirArgList;
|
||||||
|
n.extraData = firstExtra as *void;
|
||||||
|
n.extraCount = 1;
|
||||||
|
} else {
|
||||||
|
// Additional args — append to linked list
|
||||||
|
var cur: *HirArgList = n.extraData as *HirArgList;
|
||||||
|
while cur.next != null as *HirArgList {
|
||||||
|
cur = cur.next;
|
||||||
|
}
|
||||||
|
let newNode: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
|
||||||
|
newNode.node = lowered;
|
||||||
|
newNode.next = null as *HirArgList;
|
||||||
|
cur.next = newNode;
|
||||||
|
n.extraCount = n.extraCount + 1;
|
||||||
|
}
|
||||||
|
arg = arg.next;
|
||||||
|
argIdx = argIdx + 1;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -192,12 +215,36 @@ func Lcx_LowerExpr(ctx: *LowerCtx, expr: *Expr) -> *HirNode {
|
|||||||
if expr.child1 != null as *Expr && expr.child1.kind == ekIdent {
|
if expr.child1 != null as *Expr && expr.child1.kind == ekIdent {
|
||||||
n.strValue = expr.child1.strValue;
|
n.strValue = expr.child1.strValue;
|
||||||
}
|
}
|
||||||
// Lower arguments
|
// Lower arguments from linked list
|
||||||
if expr.child2 != null as *Expr {
|
var arg: *ExprList = expr.callArgs;
|
||||||
n.child1 = Lcx_LowerExpr(ctx, expr.child2);
|
var argIdx: int = 0;
|
||||||
|
while arg != null as *ExprList {
|
||||||
|
let lowered: *HirNode = Lcx_LowerExpr(ctx, arg.expr);
|
||||||
|
if argIdx == 0 {
|
||||||
|
n.child1 = lowered;
|
||||||
|
} else if argIdx == 1 {
|
||||||
|
n.child2 = lowered;
|
||||||
|
} else if argIdx == 2 {
|
||||||
|
// Third argument — start linked list
|
||||||
|
let firstExtra: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
|
||||||
|
firstExtra.node = lowered;
|
||||||
|
firstExtra.next = null as *HirArgList;
|
||||||
|
n.extraData = firstExtra as *void;
|
||||||
|
n.extraCount = 1;
|
||||||
|
} else {
|
||||||
|
// Additional args — append to linked list
|
||||||
|
var cur: *HirArgList = n.extraData as *HirArgList;
|
||||||
|
while cur.next != null as *HirArgList {
|
||||||
|
cur = cur.next;
|
||||||
}
|
}
|
||||||
if expr.child3 != null as *Expr {
|
let newNode: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
|
||||||
n.child2 = Lcx_LowerExpr(ctx, expr.child3);
|
newNode.node = lowered;
|
||||||
|
newNode.next = null as *HirArgList;
|
||||||
|
cur.next = newNode;
|
||||||
|
n.extraCount = n.extraCount + 1;
|
||||||
|
}
|
||||||
|
arg = arg.next;
|
||||||
|
argIdx = argIdx + 1;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -359,6 +406,9 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
|
|||||||
sym.name = stmt.strValue;
|
sym.name = stmt.strValue;
|
||||||
sym.typeKind = alloca.typeKind;
|
sym.typeKind = alloca.typeKind;
|
||||||
sym.typeName = alloca.typeName;
|
sym.typeName = alloca.typeName;
|
||||||
|
sym.isMutable = false;
|
||||||
|
sym.isPublic = false;
|
||||||
|
sym.decl = null as *Decl;
|
||||||
discard Scope_Define(ctx.scope, sym);
|
discard Scope_Define(ctx.scope, sym);
|
||||||
// store the init value
|
// store the init value
|
||||||
n.kind = hStore;
|
n.kind = hStore;
|
||||||
@@ -495,6 +545,9 @@ func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc {
|
|||||||
Lcx_LowerParam(&f.param3, &decl.param3);
|
Lcx_LowerParam(&f.param3, &decl.param3);
|
||||||
Lcx_LowerParam(&f.param4, &decl.param4);
|
Lcx_LowerParam(&f.param4, &decl.param4);
|
||||||
Lcx_LowerParam(&f.param5, &decl.param5);
|
Lcx_LowerParam(&f.param5, &decl.param5);
|
||||||
|
Lcx_LowerParam(&f.param6, &decl.param6);
|
||||||
|
Lcx_LowerParam(&f.param7, &decl.param7);
|
||||||
|
Lcx_LowerParam(&f.param8, &decl.param8);
|
||||||
|
|
||||||
if decl.retType != null as *TypeExpr {
|
if decl.retType != null as *TypeExpr {
|
||||||
f.retTypeName = decl.retType.typeName;
|
f.retTypeName = decl.retType.typeName;
|
||||||
@@ -514,12 +567,18 @@ func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc {
|
|||||||
else if pi == 3 { p = &decl.param3; }
|
else if pi == 3 { p = &decl.param3; }
|
||||||
else if pi == 4 { p = &decl.param4; }
|
else if pi == 4 { p = &decl.param4; }
|
||||||
else if pi == 5 { p = &decl.param5; }
|
else if pi == 5 { p = &decl.param5; }
|
||||||
|
else if pi == 6 { p = &decl.param6; }
|
||||||
|
else if pi == 7 { p = &decl.param7; }
|
||||||
|
else if pi == 8 { p = &decl.param8; }
|
||||||
if p != null as *Param && p.refParamType != null as *TypeExpr {
|
if p != null as *Param && p.refParamType != null as *TypeExpr {
|
||||||
var sym: Symbol;
|
var sym: Symbol;
|
||||||
sym.kind = skVar;
|
sym.kind = skVar;
|
||||||
sym.name = p.name;
|
sym.name = p.name;
|
||||||
sym.typeKind = Lcx_ResolveTypeKind(p.refParamType);
|
sym.typeKind = Lcx_ResolveTypeKind(p.refParamType);
|
||||||
sym.typeName = p.refParamType.typeName;
|
sym.typeName = p.refParamType.typeName;
|
||||||
|
sym.isMutable = false;
|
||||||
|
sym.isPublic = false;
|
||||||
|
sym.decl = null as *Decl;
|
||||||
discard Scope_Define(ctx.scope, sym);
|
discard Scope_Define(ctx.scope, sym);
|
||||||
}
|
}
|
||||||
pi = pi + 1;
|
pi = pi + 1;
|
||||||
|
|||||||
@@ -711,7 +711,7 @@ func Lexer_GetToken(lex: *Lexer, index: int) -> LexToken {
|
|||||||
if index >= 0 && index < lex.tokenCount {
|
if index >= 0 && index < lex.tokenCount {
|
||||||
return lex.tokens[index];
|
return lex.tokens[index];
|
||||||
}
|
}
|
||||||
var empty: LexToken;
|
var empty: LexToken = LexToken { kind: tkEndOfFile, text: "", line: 0, column: 0 };
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-11
@@ -214,6 +214,8 @@ func parserMakeExpr(kind: int, line: uint32, col: uint32) -> *Expr {
|
|||||||
e.genericTypeArgCount = 0;
|
e.genericTypeArgCount = 0;
|
||||||
e.structName = "";
|
e.structName = "";
|
||||||
e.structFieldCount = 0;
|
e.structFieldCount = 0;
|
||||||
|
e.callArgs = null as *ExprList;
|
||||||
|
e.callArgCount = 0;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,18 +339,27 @@ func parserParsePostfix(p: *Parser) -> *Expr {
|
|||||||
let col: uint32 = parserCurToken(p).column;
|
let col: uint32 = parserCurToken(p).column;
|
||||||
let e: *Expr = parserMakeExpr(ekCall, line, col);
|
let e: *Expr = parserMakeExpr(ekCall, line, col);
|
||||||
e.child1 = left;
|
e.child1 = left;
|
||||||
// Parse arguments (up to 8)
|
// Parse all arguments into linked list
|
||||||
// child2 = first arg, child3 = second arg, extra = rest
|
var argCount: int = 0;
|
||||||
if !parserCheck(p, tkRParen) {
|
var firstArg: *ExprList = null as *ExprList;
|
||||||
e.child2 = parserParseExpr(p);
|
var lastArg: *ExprList = null as *ExprList;
|
||||||
if parserMatch(p, tkComma) {
|
while !parserCheck(p, tkRParen) {
|
||||||
e.child3 = parserParseExpr(p);
|
let argExpr: *Expr = parserParseExpr(p);
|
||||||
// Consume any remaining arguments (we only store 2)
|
let argNode: *ExprList = bux_alloc(sizeof(ExprList)) as *ExprList;
|
||||||
while parserMatch(p, tkComma) {
|
argNode.expr = argExpr;
|
||||||
discard parserParseExpr(p);
|
argNode.next = null as *ExprList;
|
||||||
}
|
if firstArg == null as *ExprList {
|
||||||
|
firstArg = argNode;
|
||||||
|
lastArg = argNode;
|
||||||
|
} else {
|
||||||
|
lastArg.next = argNode;
|
||||||
|
lastArg = argNode;
|
||||||
}
|
}
|
||||||
|
argCount = argCount + 1;
|
||||||
|
if !parserMatch(p, tkComma) { break; }
|
||||||
}
|
}
|
||||||
|
e.callArgs = firstArg;
|
||||||
|
e.callArgCount = argCount;
|
||||||
discard parserExpect(p, tkRParen, "expected ')'");
|
discard parserExpect(p, tkRParen, "expected ')'");
|
||||||
left = e;
|
left = e;
|
||||||
continue;
|
continue;
|
||||||
@@ -842,7 +853,7 @@ func parserParseParamList(p: *Parser) -> *Decl {
|
|||||||
|
|
||||||
discard parserExpect(p, tkLParen, "expected '('");
|
discard parserExpect(p, tkLParen, "expected '('");
|
||||||
while !parserCheck(p, tkRParen) && parserPeek(p, 0) != tkEndOfFile {
|
while !parserCheck(p, tkRParen) && parserPeek(p, 0) != tkEndOfFile {
|
||||||
if d.paramCount >= 6 { break; }
|
if d.paramCount >= 9 { break; }
|
||||||
let nameTok: LexToken = parserExpectIdentOrKeyword(p, "expected parameter name");
|
let nameTok: LexToken = parserExpectIdentOrKeyword(p, "expected parameter name");
|
||||||
discard parserExpect(p, tkColon, "expected ':' in parameter");
|
discard parserExpect(p, tkColon, "expected ':' in parameter");
|
||||||
let ptype: *TypeExpr = parserParseType(p);
|
let ptype: *TypeExpr = parserParseType(p);
|
||||||
@@ -865,6 +876,15 @@ func parserParseParamList(p: *Parser) -> *Decl {
|
|||||||
} else if d.paramCount == 5 {
|
} else if d.paramCount == 5 {
|
||||||
d.param5.name = nameTok.text;
|
d.param5.name = nameTok.text;
|
||||||
d.param5.refParamType = ptype;
|
d.param5.refParamType = ptype;
|
||||||
|
} else if d.paramCount == 6 {
|
||||||
|
d.param6.name = nameTok.text;
|
||||||
|
d.param6.refParamType = ptype;
|
||||||
|
} else if d.paramCount == 7 {
|
||||||
|
d.param7.name = nameTok.text;
|
||||||
|
d.param7.refParamType = ptype;
|
||||||
|
} else if d.paramCount == 8 {
|
||||||
|
d.param8.name = nameTok.text;
|
||||||
|
d.param8.refParamType = ptype;
|
||||||
}
|
}
|
||||||
d.paramCount = d.paramCount + 1;
|
d.paramCount = d.paramCount + 1;
|
||||||
|
|
||||||
@@ -916,6 +936,9 @@ func parserParseFuncDecl(p: *Parser, isPublic: bool, isExtern: bool, isAsync: bo
|
|||||||
d.param3 = params.param3;
|
d.param3 = params.param3;
|
||||||
d.param4 = params.param4;
|
d.param4 = params.param4;
|
||||||
d.param5 = params.param5;
|
d.param5 = params.param5;
|
||||||
|
d.param6 = params.param6;
|
||||||
|
d.param7 = params.param7;
|
||||||
|
d.param8 = params.param8;
|
||||||
|
|
||||||
// Return type
|
// Return type
|
||||||
if parserMatch(p, tkArrow) {
|
if parserMatch(p, tkArrow) {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func Scope_Lookup(scope: *Scope, name: String) -> Symbol {
|
|||||||
}
|
}
|
||||||
cur = cur.parent;
|
cur = cur.parent;
|
||||||
}
|
}
|
||||||
var empty: Symbol;
|
var empty: Symbol = Symbol { kind: 0, name: "", typeKind: 0, typeName: "", isMutable: false, isPublic: false, decl: null as *Decl };
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ func Scope_LookupLocal(scope: *Scope, name: String) -> Symbol {
|
|||||||
}
|
}
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
}
|
}
|
||||||
var empty: Symbol;
|
var empty: Symbol = Symbol { kind: 0, name: "", typeKind: 0, typeName: "", isMutable: false, isPublic: false, decl: null as *Decl };
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-5
@@ -231,11 +231,10 @@ func Sema_CheckExpr(sema: *Sema, expr: *Expr) -> int {
|
|||||||
// Call
|
// Call
|
||||||
if kind == ekCall {
|
if kind == ekCall {
|
||||||
discard Sema_CheckExpr(sema, expr.child1);
|
discard Sema_CheckExpr(sema, expr.child1);
|
||||||
if expr.child2 != null as *Expr {
|
var arg: *ExprList = expr.callArgs;
|
||||||
discard Sema_CheckExpr(sema, expr.child2);
|
while arg != null as *ExprList {
|
||||||
}
|
discard Sema_CheckExpr(sema, arg.expr);
|
||||||
if expr.child3 != null as *Expr {
|
arg = arg.next;
|
||||||
discard Sema_CheckExpr(sema, expr.child3);
|
|
||||||
}
|
}
|
||||||
// Try to resolve return type from function declaration
|
// Try to resolve return type from function declaration
|
||||||
if expr.child1.kind == ekIdent {
|
if expr.child1.kind == ekIdent {
|
||||||
@@ -635,6 +634,7 @@ func Sema_Analyze(mod: *Module) -> *Sema {
|
|||||||
// Add type params to scope
|
// Add type params to scope
|
||||||
if decl.typeParamCount >= 1 {
|
if decl.typeParamCount >= 1 {
|
||||||
var tpSym: Symbol;
|
var tpSym: Symbol;
|
||||||
|
Sema_ZeroInitSymbol(&tpSym);
|
||||||
tpSym.kind = skType;
|
tpSym.kind = skType;
|
||||||
tpSym.name = decl.typeParam0;
|
tpSym.name = decl.typeParam0;
|
||||||
tpSym.typeKind = tyTypeParam;
|
tpSym.typeKind = tyTypeParam;
|
||||||
@@ -643,6 +643,7 @@ func Sema_Analyze(mod: *Module) -> *Sema {
|
|||||||
}
|
}
|
||||||
if decl.typeParamCount >= 2 {
|
if decl.typeParamCount >= 2 {
|
||||||
var tpSym2: Symbol;
|
var tpSym2: Symbol;
|
||||||
|
Sema_ZeroInitSymbol(&tpSym2);
|
||||||
tpSym2.kind = skType;
|
tpSym2.kind = skType;
|
||||||
tpSym2.name = decl.typeParam1;
|
tpSym2.name = decl.typeParam1;
|
||||||
tpSym2.typeKind = tyTypeParam;
|
tpSym2.typeKind = tyTypeParam;
|
||||||
@@ -660,6 +661,9 @@ func Sema_Analyze(mod: *Module) -> *Sema {
|
|||||||
else if i == 3 { p = &decl.param3; }
|
else if i == 3 { p = &decl.param3; }
|
||||||
else if i == 4 { p = &decl.param4; }
|
else if i == 4 { p = &decl.param4; }
|
||||||
else if i == 5 { p = &decl.param5; }
|
else if i == 5 { p = &decl.param5; }
|
||||||
|
else if i == 6 { p = &decl.param6; }
|
||||||
|
else if i == 7 { p = &decl.param7; }
|
||||||
|
else if i == 8 { p = &decl.param8; }
|
||||||
var pSym: Symbol;
|
var pSym: Symbol;
|
||||||
Sema_ZeroInitSymbol(&pSym);
|
Sema_ZeroInitSymbol(&pSym);
|
||||||
pSym.kind = skVar;
|
pSym.kind = skVar;
|
||||||
@@ -679,6 +683,9 @@ func Sema_Analyze(mod: *Module) -> *Sema {
|
|||||||
else if i == 3 { pSym.name = decl.param3.name; }
|
else if i == 3 { pSym.name = decl.param3.name; }
|
||||||
else if i == 4 { pSym.name = decl.param4.name; }
|
else if i == 4 { pSym.name = decl.param4.name; }
|
||||||
else if i == 5 { pSym.name = decl.param5.name; }
|
else if i == 5 { pSym.name = decl.param5.name; }
|
||||||
|
else if i == 6 { pSym.name = decl.param6.name; }
|
||||||
|
else if i == 7 { pSym.name = decl.param7.name; }
|
||||||
|
else if i == 8 { pSym.name = decl.param8.name; }
|
||||||
discard Scope_Define(&funcScope, pSym);
|
discard Scope_Define(&funcScope, pSym);
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 215 KiB |
+14
-2
@@ -32,7 +32,13 @@ make build
|
|||||||
make dev
|
make dev
|
||||||
```
|
```
|
||||||
|
|
||||||
The output is a single binary: `buxc`.
|
The output is a single binary: `buxc` (bootstrap compiler in Nim).
|
||||||
|
|
||||||
|
The self-hosted compiler `buxc2` is built from `src_bux/*.bux` sources via:
|
||||||
|
```bash
|
||||||
|
make selfhost
|
||||||
|
```
|
||||||
|
This compiles `buxc2` using the bootstrap compiler. The self-hosted compiler generates C code and invokes `cc` to produce native binaries.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -164,12 +170,18 @@ bux/
|
|||||||
./buxc build -v
|
./buxc build -v
|
||||||
```
|
```
|
||||||
|
|
||||||
### Inspecting Generated C
|
### Inspecting Generated C (bootstrap)
|
||||||
```bash
|
```bash
|
||||||
./buxc build
|
./buxc build
|
||||||
cat build/main.c
|
cat build/main.c
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Inspecting Generated C (self-hosted)
|
||||||
|
```bash
|
||||||
|
cd _selfhost && ../buxc build
|
||||||
|
cat build/main.c
|
||||||
|
```
|
||||||
|
|
||||||
### Common Errors
|
### Common Errors
|
||||||
|
|
||||||
| Error | Cause | Fix |
|
| Error | Cause | Fix |
|
||||||
|
|||||||
+13
-1
@@ -96,6 +96,11 @@ const ekMatch: int = 22;
|
|||||||
const ekSpawn: int = 24;
|
const ekSpawn: int = 24;
|
||||||
const ekAwait: int = 25;
|
const ekAwait: int = 25;
|
||||||
|
|
||||||
|
struct ExprList {
|
||||||
|
expr: *Expr,
|
||||||
|
next: *ExprList,
|
||||||
|
}
|
||||||
|
|
||||||
struct Expr {
|
struct Expr {
|
||||||
kind: int,
|
kind: int,
|
||||||
line: uint32,
|
line: uint32,
|
||||||
@@ -121,6 +126,9 @@ struct Expr {
|
|||||||
// Struct init fields
|
// Struct init fields
|
||||||
structName: String,
|
structName: String,
|
||||||
structFieldCount: int,
|
structFieldCount: int,
|
||||||
|
// Call arguments (linked list for multi-arg support)
|
||||||
|
callArgs: *ExprList,
|
||||||
|
callArgCount: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -241,6 +249,9 @@ struct Decl {
|
|||||||
param3: Param,
|
param3: Param,
|
||||||
param4: Param,
|
param4: Param,
|
||||||
param5: Param,
|
param5: Param,
|
||||||
|
param6: Param,
|
||||||
|
param7: Param,
|
||||||
|
param8: Param,
|
||||||
retType: *TypeExpr,
|
retType: *TypeExpr,
|
||||||
// Body
|
// Body
|
||||||
refBody: *Block,
|
refBody: *Block,
|
||||||
@@ -361,7 +372,8 @@ func Ast_MakeExpr(kind: int, line: uint32, col: uint32) -> Expr {
|
|||||||
child1: null as *Expr, child2: null as *Expr, child3: null as *Expr,
|
child1: null as *Expr, child2: null as *Expr, child3: null as *Expr,
|
||||||
refType: null as *TypeExpr, refBlock: null as *Block,
|
refType: null as *TypeExpr, refBlock: null as *Block,
|
||||||
genericCallee: "", genericTypeArg0: "", genericTypeArg1: "", genericTypeArgCount: 0,
|
genericCallee: "", genericTypeArg0: "", genericTypeArg1: "", genericTypeArgCount: 0,
|
||||||
structName: "", structFieldCount: 0 };
|
structName: "", structFieldCount: 0,
|
||||||
|
callArgs: null as *ExprList, callArgCount: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
func Ast_MakeIdent(name: String, line: uint32, col: uint32) -> Expr {
|
func Ast_MakeIdent(name: String, line: uint32, col: uint32) -> Expr {
|
||||||
|
|||||||
@@ -134,12 +134,29 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) {
|
|||||||
if kind == hCall {
|
if kind == hCall {
|
||||||
StringBuilder_Append(&cbe.sb, node.strValue);
|
StringBuilder_Append(&cbe.sb, node.strValue);
|
||||||
StringBuilder_Append(&cbe.sb, "(");
|
StringBuilder_Append(&cbe.sb, "(");
|
||||||
|
var needsComma: bool = false;
|
||||||
if node.child1 != null as *HirNode {
|
if node.child1 != null as *HirNode {
|
||||||
CBE_EmitExpr(cbe, node.child1);
|
CBE_EmitExpr(cbe, node.child1);
|
||||||
|
needsComma = true;
|
||||||
}
|
}
|
||||||
if node.child2 != null as *HirNode {
|
if node.child2 != null as *HirNode {
|
||||||
|
if needsComma {
|
||||||
StringBuilder_Append(&cbe.sb, ", ");
|
StringBuilder_Append(&cbe.sb, ", ");
|
||||||
|
}
|
||||||
CBE_EmitExpr(cbe, node.child2);
|
CBE_EmitExpr(cbe, node.child2);
|
||||||
|
needsComma = true;
|
||||||
|
}
|
||||||
|
// Emit extra args from linked list
|
||||||
|
var ai: int = 0;
|
||||||
|
var curExtra: *HirArgList = node.extraData as *HirArgList;
|
||||||
|
while ai < node.extraCount {
|
||||||
|
if needsComma {
|
||||||
|
StringBuilder_Append(&cbe.sb, ", ");
|
||||||
|
}
|
||||||
|
CBE_EmitExpr(cbe, curExtra.node);
|
||||||
|
needsComma = true;
|
||||||
|
curExtra = curExtra.next;
|
||||||
|
ai = ai + 1;
|
||||||
}
|
}
|
||||||
StringBuilder_Append(&cbe.sb, ")");
|
StringBuilder_Append(&cbe.sb, ")");
|
||||||
return;
|
return;
|
||||||
@@ -414,6 +431,9 @@ func CBE_EmitFuncDecl(cbe: *CEmitter, f: *HirFunc) {
|
|||||||
if i == 3 { pname = f.param3.name; ptype = f.param3.typeName; }
|
if i == 3 { pname = f.param3.name; ptype = f.param3.typeName; }
|
||||||
if i == 4 { pname = f.param4.name; ptype = f.param4.typeName; }
|
if i == 4 { pname = f.param4.name; ptype = f.param4.typeName; }
|
||||||
if i == 5 { pname = f.param5.name; ptype = f.param5.typeName; }
|
if i == 5 { pname = f.param5.name; ptype = f.param5.typeName; }
|
||||||
|
if i == 6 { pname = f.param6.name; ptype = f.param6.typeName; }
|
||||||
|
if i == 7 { pname = f.param7.name; ptype = f.param7.typeName; }
|
||||||
|
if i == 8 { pname = f.param8.name; ptype = f.param8.typeName; }
|
||||||
// Emit type
|
// Emit type
|
||||||
if String_Eq(ptype, "String") || String_Eq(ptype, "str") {
|
if String_Eq(ptype, "String") || String_Eq(ptype, "str") {
|
||||||
StringBuilder_Append(&cbe.sb, "String ");
|
StringBuilder_Append(&cbe.sb, "String ");
|
||||||
@@ -474,6 +494,9 @@ func CBE_FuncHasGeneric(f: *HirFunc) -> bool {
|
|||||||
if pi == 3 { ptype = f.param3.typeName; }
|
if pi == 3 { ptype = f.param3.typeName; }
|
||||||
if pi == 4 { ptype = f.param4.typeName; }
|
if pi == 4 { ptype = f.param4.typeName; }
|
||||||
if pi == 5 { ptype = f.param5.typeName; }
|
if pi == 5 { ptype = f.param5.typeName; }
|
||||||
|
if pi == 6 { ptype = f.param6.typeName; }
|
||||||
|
if pi == 7 { ptype = f.param7.typeName; }
|
||||||
|
if pi == 8 { ptype = f.param8.typeName; }
|
||||||
if CBE_IsGenericTypeName(ptype) { return true; }
|
if CBE_IsGenericTypeName(ptype) { return true; }
|
||||||
pi = pi + 1;
|
pi = pi + 1;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -400,8 +400,13 @@ func Cli_CollectStdlibImports(mod: *Module, outPaths: *String, maxCount: int, st
|
|||||||
func Cli_MergeFileInto(target: *Module, path: String, skipNames: *String, skipCount: int) -> int {
|
func Cli_MergeFileInto(target: *Module, path: String, skipNames: *String, skipCount: int) -> int {
|
||||||
Print("DEBUG: MergeFileInto ");
|
Print("DEBUG: MergeFileInto ");
|
||||||
PrintLine(path);
|
PrintLine(path);
|
||||||
|
if !FileExists(path) {
|
||||||
|
Print("Error: stdlib file not found: ");
|
||||||
|
PrintLine(path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
let source: String = ReadFile(path);
|
let source: String = ReadFile(path);
|
||||||
if String_Eq(source, "") { return 0; }
|
if source == null as String || String_Eq(source, "") { return 0; }
|
||||||
let lex: *Lexer = Lexer_Tokenize(source);
|
let lex: *Lexer = Lexer_Tokenize(source);
|
||||||
if Lexer_DiagCount(lex) > 0 { return 0; }
|
if Lexer_DiagCount(lex) > 0 { return 0; }
|
||||||
let mod: *Module = Parser_Parse(lex.tokens, lex.tokenCount);
|
let mod: *Module = Parser_Parse(lex.tokens, lex.tokenCount);
|
||||||
|
|||||||
@@ -34,6 +34,15 @@ const hMatch: int = 28;
|
|||||||
const hSpawn: int = 29;
|
const hSpawn: int = 29;
|
||||||
const hAwait: int = 30;
|
const hAwait: int = 30;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// HirArgList — linked list for call arguments beyond 2
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct HirArgList {
|
||||||
|
node: *HirNode,
|
||||||
|
next: *HirArgList,
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// HirNode — unified struct with tagged union pattern
|
// HirNode — unified struct with tagged union pattern
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -76,6 +85,9 @@ struct HirFunc {
|
|||||||
param3: HirParam;
|
param3: HirParam;
|
||||||
param4: HirParam;
|
param4: HirParam;
|
||||||
param5: HirParam;
|
param5: HirParam;
|
||||||
|
param6: HirParam;
|
||||||
|
param7: HirParam;
|
||||||
|
param8: HirParam;
|
||||||
retTypeKind: int;
|
retTypeKind: int;
|
||||||
retTypeName: String;
|
retTypeName: String;
|
||||||
body: *HirNode;
|
body: *HirNode;
|
||||||
|
|||||||
+69
-10
@@ -180,11 +180,34 @@ func Lcx_LowerExpr(ctx: *LowerCtx, expr: *Expr) -> *HirNode {
|
|||||||
// Lower receiver as first argument
|
// Lower receiver as first argument
|
||||||
let recv: *HirNode = Lcx_LowerExpr(ctx, expr.child1.child1);
|
let recv: *HirNode = Lcx_LowerExpr(ctx, expr.child1.child1);
|
||||||
n.child1 = recv;
|
n.child1 = recv;
|
||||||
// Lower remaining arguments
|
// Lower remaining arguments from linked list
|
||||||
if expr.child2 != null as *Expr {
|
var arg: *ExprList = expr.callArgs;
|
||||||
let extra: *HirNode = Lcx_LowerExpr(ctx, expr.child2);
|
var argIdx: int = 0;
|
||||||
// Chain extra args after receiver via child2/child3
|
while arg != null as *ExprList {
|
||||||
n.child2 = extra;
|
let lowered: *HirNode = Lcx_LowerExpr(ctx, arg.expr);
|
||||||
|
if argIdx == 0 {
|
||||||
|
n.child2 = lowered;
|
||||||
|
} else if argIdx == 1 {
|
||||||
|
// Third argument — start linked list
|
||||||
|
let firstExtra: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
|
||||||
|
firstExtra.node = lowered;
|
||||||
|
firstExtra.next = null as *HirArgList;
|
||||||
|
n.extraData = firstExtra as *void;
|
||||||
|
n.extraCount = 1;
|
||||||
|
} else {
|
||||||
|
// Additional args — append to linked list
|
||||||
|
var cur: *HirArgList = n.extraData as *HirArgList;
|
||||||
|
while cur.next != null as *HirArgList {
|
||||||
|
cur = cur.next;
|
||||||
|
}
|
||||||
|
let newNode: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
|
||||||
|
newNode.node = lowered;
|
||||||
|
newNode.next = null as *HirArgList;
|
||||||
|
cur.next = newNode;
|
||||||
|
n.extraCount = n.extraCount + 1;
|
||||||
|
}
|
||||||
|
arg = arg.next;
|
||||||
|
argIdx = argIdx + 1;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -192,12 +215,36 @@ func Lcx_LowerExpr(ctx: *LowerCtx, expr: *Expr) -> *HirNode {
|
|||||||
if expr.child1 != null as *Expr && expr.child1.kind == ekIdent {
|
if expr.child1 != null as *Expr && expr.child1.kind == ekIdent {
|
||||||
n.strValue = expr.child1.strValue;
|
n.strValue = expr.child1.strValue;
|
||||||
}
|
}
|
||||||
// Lower arguments
|
// Lower arguments from linked list
|
||||||
if expr.child2 != null as *Expr {
|
var arg: *ExprList = expr.callArgs;
|
||||||
n.child1 = Lcx_LowerExpr(ctx, expr.child2);
|
var argIdx: int = 0;
|
||||||
|
while arg != null as *ExprList {
|
||||||
|
let lowered: *HirNode = Lcx_LowerExpr(ctx, arg.expr);
|
||||||
|
if argIdx == 0 {
|
||||||
|
n.child1 = lowered;
|
||||||
|
} else if argIdx == 1 {
|
||||||
|
n.child2 = lowered;
|
||||||
|
} else if argIdx == 2 {
|
||||||
|
// Third argument — start linked list
|
||||||
|
let firstExtra: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
|
||||||
|
firstExtra.node = lowered;
|
||||||
|
firstExtra.next = null as *HirArgList;
|
||||||
|
n.extraData = firstExtra as *void;
|
||||||
|
n.extraCount = 1;
|
||||||
|
} else {
|
||||||
|
// Additional args — append to linked list
|
||||||
|
var cur: *HirArgList = n.extraData as *HirArgList;
|
||||||
|
while cur.next != null as *HirArgList {
|
||||||
|
cur = cur.next;
|
||||||
}
|
}
|
||||||
if expr.child3 != null as *Expr {
|
let newNode: *HirArgList = bux_alloc(sizeof(HirArgList)) as *HirArgList;
|
||||||
n.child2 = Lcx_LowerExpr(ctx, expr.child3);
|
newNode.node = lowered;
|
||||||
|
newNode.next = null as *HirArgList;
|
||||||
|
cur.next = newNode;
|
||||||
|
n.extraCount = n.extraCount + 1;
|
||||||
|
}
|
||||||
|
arg = arg.next;
|
||||||
|
argIdx = argIdx + 1;
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -359,6 +406,9 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
|
|||||||
sym.name = stmt.strValue;
|
sym.name = stmt.strValue;
|
||||||
sym.typeKind = alloca.typeKind;
|
sym.typeKind = alloca.typeKind;
|
||||||
sym.typeName = alloca.typeName;
|
sym.typeName = alloca.typeName;
|
||||||
|
sym.isMutable = false;
|
||||||
|
sym.isPublic = false;
|
||||||
|
sym.decl = null as *Decl;
|
||||||
discard Scope_Define(ctx.scope, sym);
|
discard Scope_Define(ctx.scope, sym);
|
||||||
// store the init value
|
// store the init value
|
||||||
n.kind = hStore;
|
n.kind = hStore;
|
||||||
@@ -495,6 +545,9 @@ func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc {
|
|||||||
Lcx_LowerParam(&f.param3, &decl.param3);
|
Lcx_LowerParam(&f.param3, &decl.param3);
|
||||||
Lcx_LowerParam(&f.param4, &decl.param4);
|
Lcx_LowerParam(&f.param4, &decl.param4);
|
||||||
Lcx_LowerParam(&f.param5, &decl.param5);
|
Lcx_LowerParam(&f.param5, &decl.param5);
|
||||||
|
Lcx_LowerParam(&f.param6, &decl.param6);
|
||||||
|
Lcx_LowerParam(&f.param7, &decl.param7);
|
||||||
|
Lcx_LowerParam(&f.param8, &decl.param8);
|
||||||
|
|
||||||
if decl.retType != null as *TypeExpr {
|
if decl.retType != null as *TypeExpr {
|
||||||
f.retTypeName = decl.retType.typeName;
|
f.retTypeName = decl.retType.typeName;
|
||||||
@@ -514,12 +567,18 @@ func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc {
|
|||||||
else if pi == 3 { p = &decl.param3; }
|
else if pi == 3 { p = &decl.param3; }
|
||||||
else if pi == 4 { p = &decl.param4; }
|
else if pi == 4 { p = &decl.param4; }
|
||||||
else if pi == 5 { p = &decl.param5; }
|
else if pi == 5 { p = &decl.param5; }
|
||||||
|
else if pi == 6 { p = &decl.param6; }
|
||||||
|
else if pi == 7 { p = &decl.param7; }
|
||||||
|
else if pi == 8 { p = &decl.param8; }
|
||||||
if p != null as *Param && p.refParamType != null as *TypeExpr {
|
if p != null as *Param && p.refParamType != null as *TypeExpr {
|
||||||
var sym: Symbol;
|
var sym: Symbol;
|
||||||
sym.kind = skVar;
|
sym.kind = skVar;
|
||||||
sym.name = p.name;
|
sym.name = p.name;
|
||||||
sym.typeKind = Lcx_ResolveTypeKind(p.refParamType);
|
sym.typeKind = Lcx_ResolveTypeKind(p.refParamType);
|
||||||
sym.typeName = p.refParamType.typeName;
|
sym.typeName = p.refParamType.typeName;
|
||||||
|
sym.isMutable = false;
|
||||||
|
sym.isPublic = false;
|
||||||
|
sym.decl = null as *Decl;
|
||||||
discard Scope_Define(ctx.scope, sym);
|
discard Scope_Define(ctx.scope, sym);
|
||||||
}
|
}
|
||||||
pi = pi + 1;
|
pi = pi + 1;
|
||||||
|
|||||||
+1
-1
@@ -711,7 +711,7 @@ func Lexer_GetToken(lex: *Lexer, index: int) -> LexToken {
|
|||||||
if index >= 0 && index < lex.tokenCount {
|
if index >= 0 && index < lex.tokenCount {
|
||||||
return lex.tokens[index];
|
return lex.tokens[index];
|
||||||
}
|
}
|
||||||
var empty: LexToken;
|
var empty: LexToken = LexToken { kind: tkEndOfFile, text: "", line: 0, column: 0 };
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+34
-11
@@ -214,6 +214,8 @@ func parserMakeExpr(kind: int, line: uint32, col: uint32) -> *Expr {
|
|||||||
e.genericTypeArgCount = 0;
|
e.genericTypeArgCount = 0;
|
||||||
e.structName = "";
|
e.structName = "";
|
||||||
e.structFieldCount = 0;
|
e.structFieldCount = 0;
|
||||||
|
e.callArgs = null as *ExprList;
|
||||||
|
e.callArgCount = 0;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,18 +339,27 @@ func parserParsePostfix(p: *Parser) -> *Expr {
|
|||||||
let col: uint32 = parserCurToken(p).column;
|
let col: uint32 = parserCurToken(p).column;
|
||||||
let e: *Expr = parserMakeExpr(ekCall, line, col);
|
let e: *Expr = parserMakeExpr(ekCall, line, col);
|
||||||
e.child1 = left;
|
e.child1 = left;
|
||||||
// Parse arguments (up to 8)
|
// Parse all arguments into linked list
|
||||||
// child2 = first arg, child3 = second arg, extra = rest
|
var argCount: int = 0;
|
||||||
if !parserCheck(p, tkRParen) {
|
var firstArg: *ExprList = null as *ExprList;
|
||||||
e.child2 = parserParseExpr(p);
|
var lastArg: *ExprList = null as *ExprList;
|
||||||
if parserMatch(p, tkComma) {
|
while !parserCheck(p, tkRParen) {
|
||||||
e.child3 = parserParseExpr(p);
|
let argExpr: *Expr = parserParseExpr(p);
|
||||||
// Consume any remaining arguments (we only store 2)
|
let argNode: *ExprList = bux_alloc(sizeof(ExprList)) as *ExprList;
|
||||||
while parserMatch(p, tkComma) {
|
argNode.expr = argExpr;
|
||||||
discard parserParseExpr(p);
|
argNode.next = null as *ExprList;
|
||||||
}
|
if firstArg == null as *ExprList {
|
||||||
|
firstArg = argNode;
|
||||||
|
lastArg = argNode;
|
||||||
|
} else {
|
||||||
|
lastArg.next = argNode;
|
||||||
|
lastArg = argNode;
|
||||||
}
|
}
|
||||||
|
argCount = argCount + 1;
|
||||||
|
if !parserMatch(p, tkComma) { break; }
|
||||||
}
|
}
|
||||||
|
e.callArgs = firstArg;
|
||||||
|
e.callArgCount = argCount;
|
||||||
discard parserExpect(p, tkRParen, "expected ')'");
|
discard parserExpect(p, tkRParen, "expected ')'");
|
||||||
left = e;
|
left = e;
|
||||||
continue;
|
continue;
|
||||||
@@ -842,7 +853,7 @@ func parserParseParamList(p: *Parser) -> *Decl {
|
|||||||
|
|
||||||
discard parserExpect(p, tkLParen, "expected '('");
|
discard parserExpect(p, tkLParen, "expected '('");
|
||||||
while !parserCheck(p, tkRParen) && parserPeek(p, 0) != tkEndOfFile {
|
while !parserCheck(p, tkRParen) && parserPeek(p, 0) != tkEndOfFile {
|
||||||
if d.paramCount >= 6 { break; }
|
if d.paramCount >= 9 { break; }
|
||||||
let nameTok: LexToken = parserExpectIdentOrKeyword(p, "expected parameter name");
|
let nameTok: LexToken = parserExpectIdentOrKeyword(p, "expected parameter name");
|
||||||
discard parserExpect(p, tkColon, "expected ':' in parameter");
|
discard parserExpect(p, tkColon, "expected ':' in parameter");
|
||||||
let ptype: *TypeExpr = parserParseType(p);
|
let ptype: *TypeExpr = parserParseType(p);
|
||||||
@@ -865,6 +876,15 @@ func parserParseParamList(p: *Parser) -> *Decl {
|
|||||||
} else if d.paramCount == 5 {
|
} else if d.paramCount == 5 {
|
||||||
d.param5.name = nameTok.text;
|
d.param5.name = nameTok.text;
|
||||||
d.param5.refParamType = ptype;
|
d.param5.refParamType = ptype;
|
||||||
|
} else if d.paramCount == 6 {
|
||||||
|
d.param6.name = nameTok.text;
|
||||||
|
d.param6.refParamType = ptype;
|
||||||
|
} else if d.paramCount == 7 {
|
||||||
|
d.param7.name = nameTok.text;
|
||||||
|
d.param7.refParamType = ptype;
|
||||||
|
} else if d.paramCount == 8 {
|
||||||
|
d.param8.name = nameTok.text;
|
||||||
|
d.param8.refParamType = ptype;
|
||||||
}
|
}
|
||||||
d.paramCount = d.paramCount + 1;
|
d.paramCount = d.paramCount + 1;
|
||||||
|
|
||||||
@@ -916,6 +936,9 @@ func parserParseFuncDecl(p: *Parser, isPublic: bool, isExtern: bool, isAsync: bo
|
|||||||
d.param3 = params.param3;
|
d.param3 = params.param3;
|
||||||
d.param4 = params.param4;
|
d.param4 = params.param4;
|
||||||
d.param5 = params.param5;
|
d.param5 = params.param5;
|
||||||
|
d.param6 = params.param6;
|
||||||
|
d.param7 = params.param7;
|
||||||
|
d.param8 = params.param8;
|
||||||
|
|
||||||
// Return type
|
// Return type
|
||||||
if parserMatch(p, tkArrow) {
|
if parserMatch(p, tkArrow) {
|
||||||
|
|||||||
+2
-2
@@ -72,7 +72,7 @@ func Scope_Lookup(scope: *Scope, name: String) -> Symbol {
|
|||||||
}
|
}
|
||||||
cur = cur.parent;
|
cur = cur.parent;
|
||||||
}
|
}
|
||||||
var empty: Symbol;
|
var empty: Symbol = Symbol { kind: 0, name: "", typeKind: 0, typeName: "", isMutable: false, isPublic: false, decl: null as *Decl };
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ func Scope_LookupLocal(scope: *Scope, name: String) -> Symbol {
|
|||||||
}
|
}
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
}
|
}
|
||||||
var empty: Symbol;
|
var empty: Symbol = Symbol { kind: 0, name: "", typeKind: 0, typeName: "", isMutable: false, isPublic: false, decl: null as *Decl };
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-5
@@ -231,11 +231,10 @@ func Sema_CheckExpr(sema: *Sema, expr: *Expr) -> int {
|
|||||||
// Call
|
// Call
|
||||||
if kind == ekCall {
|
if kind == ekCall {
|
||||||
discard Sema_CheckExpr(sema, expr.child1);
|
discard Sema_CheckExpr(sema, expr.child1);
|
||||||
if expr.child2 != null as *Expr {
|
var arg: *ExprList = expr.callArgs;
|
||||||
discard Sema_CheckExpr(sema, expr.child2);
|
while arg != null as *ExprList {
|
||||||
}
|
discard Sema_CheckExpr(sema, arg.expr);
|
||||||
if expr.child3 != null as *Expr {
|
arg = arg.next;
|
||||||
discard Sema_CheckExpr(sema, expr.child3);
|
|
||||||
}
|
}
|
||||||
// Try to resolve return type from function declaration
|
// Try to resolve return type from function declaration
|
||||||
if expr.child1.kind == ekIdent {
|
if expr.child1.kind == ekIdent {
|
||||||
@@ -635,6 +634,7 @@ func Sema_Analyze(mod: *Module) -> *Sema {
|
|||||||
// Add type params to scope
|
// Add type params to scope
|
||||||
if decl.typeParamCount >= 1 {
|
if decl.typeParamCount >= 1 {
|
||||||
var tpSym: Symbol;
|
var tpSym: Symbol;
|
||||||
|
Sema_ZeroInitSymbol(&tpSym);
|
||||||
tpSym.kind = skType;
|
tpSym.kind = skType;
|
||||||
tpSym.name = decl.typeParam0;
|
tpSym.name = decl.typeParam0;
|
||||||
tpSym.typeKind = tyTypeParam;
|
tpSym.typeKind = tyTypeParam;
|
||||||
@@ -643,6 +643,7 @@ func Sema_Analyze(mod: *Module) -> *Sema {
|
|||||||
}
|
}
|
||||||
if decl.typeParamCount >= 2 {
|
if decl.typeParamCount >= 2 {
|
||||||
var tpSym2: Symbol;
|
var tpSym2: Symbol;
|
||||||
|
Sema_ZeroInitSymbol(&tpSym2);
|
||||||
tpSym2.kind = skType;
|
tpSym2.kind = skType;
|
||||||
tpSym2.name = decl.typeParam1;
|
tpSym2.name = decl.typeParam1;
|
||||||
tpSym2.typeKind = tyTypeParam;
|
tpSym2.typeKind = tyTypeParam;
|
||||||
@@ -660,6 +661,9 @@ func Sema_Analyze(mod: *Module) -> *Sema {
|
|||||||
else if i == 3 { p = &decl.param3; }
|
else if i == 3 { p = &decl.param3; }
|
||||||
else if i == 4 { p = &decl.param4; }
|
else if i == 4 { p = &decl.param4; }
|
||||||
else if i == 5 { p = &decl.param5; }
|
else if i == 5 { p = &decl.param5; }
|
||||||
|
else if i == 6 { p = &decl.param6; }
|
||||||
|
else if i == 7 { p = &decl.param7; }
|
||||||
|
else if i == 8 { p = &decl.param8; }
|
||||||
var pSym: Symbol;
|
var pSym: Symbol;
|
||||||
Sema_ZeroInitSymbol(&pSym);
|
Sema_ZeroInitSymbol(&pSym);
|
||||||
pSym.kind = skVar;
|
pSym.kind = skVar;
|
||||||
@@ -679,6 +683,9 @@ func Sema_Analyze(mod: *Module) -> *Sema {
|
|||||||
else if i == 3 { pSym.name = decl.param3.name; }
|
else if i == 3 { pSym.name = decl.param3.name; }
|
||||||
else if i == 4 { pSym.name = decl.param4.name; }
|
else if i == 4 { pSym.name = decl.param4.name; }
|
||||||
else if i == 5 { pSym.name = decl.param5.name; }
|
else if i == 5 { pSym.name = decl.param5.name; }
|
||||||
|
else if i == 6 { pSym.name = decl.param6.name; }
|
||||||
|
else if i == 7 { pSym.name = decl.param7.name; }
|
||||||
|
else if i == 8 { pSym.name = decl.param8.name; }
|
||||||
discard Scope_Define(&funcScope, pSym);
|
discard Scope_Define(&funcScope, pSym);
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user