diff --git a/_selfhost/src/ast.bux b/_selfhost/src/ast.bux deleted file mode 100644 index 871aeb0..0000000 --- a/_selfhost/src/ast.bux +++ /dev/null @@ -1,355 +0,0 @@ -// ast.bux — AST node types (Expr, Stmt, Decl, Pattern, TypeExpr) -module Ast { - -// --------------------------------------------------------------------------- -// SourceLocation (inline for convenience) -// --------------------------------------------------------------------------- -struct SourceLoc { - line: uint32, - column: uint32, -} - -// --------------------------------------------------------------------------- -// Token (lightweight inline) -// --------------------------------------------------------------------------- -struct AstToken { - kind: int, - text: String, - line: uint32, - column: uint32, -} - -// --------------------------------------------------------------------------- -// TypeExpr — type expressions -// --------------------------------------------------------------------------- -const tekNamed: int = 0; -const tekPath: int = 1; -const tekSlice: int = 2; -const tekPointer: int = 3; -const tekTuple: int = 4; -const tekSelf: int = 5; - -struct TypeExpr { - kind: int, - line: uint32, - column: uint32, - typeName: String, // for tekNamed - pathStr: String, // for tekPath (segments joined with ::) - pathCount: int, // number of path segments - typeArgName0: String, // up to 2 type args - typeArgName1: String, - typeArgCount: int, - sliceElement: *TypeExpr, // for tekSlice - pointerPointee: *TypeExpr, // for tekPointer -} - -// --------------------------------------------------------------------------- -// Pattern — match patterns -// --------------------------------------------------------------------------- -const pkWildcard: int = 0; -const pkLiteral: int = 1; -const pkIdent: int = 2; -const pkRange: int = 3; -const pkEnum: int = 4; -const pkStruct: int = 5; -const pkTuple: int = 6; - -struct Pattern { - kind: int, - line: uint32, - column: uint32, - patIdent: String, // for pkIdent - patLitKind: int, // for pkLiteral (token kind) - patLitText: String, // for pkLiteral (token text) - patRangeInclusive: bool, // for pkRange - patEnumPath: String, // for pkEnum (path joined) - patStructName: String, // for pkStruct -} - -// --------------------------------------------------------------------------- -// Expr — expressions (tagged union) -// --------------------------------------------------------------------------- -const ekLiteral: int = 0; -const ekIdent: int = 1; -const ekSelf: int = 2; -const ekPath: int = 3; -const ekSizeOf: int = 4; -const ekUnary: int = 5; -const ekPostfix: int = 6; -const ekBinary: int = 7; -const ekAssign: int = 8; -const ekTernary: int = 9; -const ekRange: int = 10; -const ekCall: int = 11; -const ekGenericCall: int = 12; -const ekIndex: int = 13; -const ekField: int = 14; -const ekStructInit: int = 15; -const ekSlice: int = 16; -const ekTuple: int = 17; -const ekCast: int = 18; -const ekIs: int = 19; -const ekTry: int = 20; -const ekBlock: int = 21; -const ekMatch: int = 22; - -struct Expr { - kind: int, - line: uint32, - column: uint32, - // Common fields - strValue: String, // ident name, path segments, field name, callee - intValue: int, // operator kind, intrinsic kind - boolValue: bool, // range inclusive - tokKind: int, // literal token kind - tokText: String, // literal token text - // Children (up to 3 sub-expressions) - child1: *Expr, // left, operand, callee, cond, subject - child2: *Expr, // right, index, then, value - child3: *Expr, // else, third - // Extra references - refType: *TypeExpr, // cast type, is type, sizeof type - refBlock: *Block, // for ekBlock - // Generic call - genericCallee: String, - genericTypeArg0: String, - genericTypeArg1: String, - genericTypeArgCount: int, - // Struct init fields - structName: String, - structFieldCount: int, -} - -// --------------------------------------------------------------------------- -// Block — sequence of statements -// --------------------------------------------------------------------------- -struct Block { - line: uint32, - column: uint32, - stmtCount: int, -} - -// --------------------------------------------------------------------------- -// Stmt — statements -// --------------------------------------------------------------------------- -const skExpr: int = 0; -const skLet: int = 1; -const skIf: int = 2; -const skWhile: int = 3; -const skDoWhile: int = 4; -const skLoop: int = 5; -const skFor: int = 6; -const skMatch: int = 7; -const skReturn: int = 8; -const skBreak: int = 9; -const skContinue: int = 10; -const skDecl: int = 11; - -struct ElseIf { - line: uint32; - column: uint32; - cond: *Expr; - block: *Block; -} - -struct Stmt { - kind: int, - line: uint32, - column: uint32, - // Common fields - strValue: String, // let name, pattern ident, label, for var - boolValue: bool, // let mutable - // Children - child1: *Expr, // init expr, condition, iter expr, return value - child2: *Expr, // match subject - child3: *Expr, // extra - refStmtType: *TypeExpr, // let type annotation - refStmtPattern: *Pattern,// let pattern - refStmtDecl: *Decl, // for skDecl - refStmtBlock: *Block, // then/body block - refStmtElse: *Block, // else block - // Else-if chain - elseIfCount: int, -} - -// --------------------------------------------------------------------------- -// Decl — declarations -// --------------------------------------------------------------------------- -const dkFunc: int = 0; -const dkStruct: int = 1; -const dkEnum: int = 2; -const dkUnion: int = 3; -const dkInterface: int = 4; -const dkImpl: int = 5; -const dkModule: int = 6; -const dkUse: int = 7; -const dkConst: int = 8; -const dkTypeAlias: int = 9; -const dkExternFunc: int = 10; -const dkExternVar: int = 11; - -struct Param { - line: uint32; - column: uint32; - name: String; - refParamType: *TypeExpr; - isVariadic: bool; -} - -struct StructField { - line: uint32; - column: uint32; - isPublic: bool; - name: String; - refFieldType: *TypeExpr; -} - -struct EnumVariant { - line: uint32; - column: uint32; - name: String; - fieldCount: int; - fieldTypeName0: String; - fieldTypeName1: String; -} - -struct Decl { - kind: int, - line: uint32, - column: uint32, - isPublic: bool, - // Names - strValue: String, // decl name - strValue2: String, // interface name, dll name, module path - // Type params (up to 2) - typeParam0: String, - typeParam1: String, - typeParamCount: int, - // Params (for functions) - paramCount: int, - param0: Param, - param1: Param, - param2: Param, - param3: Param, - param4: Param, - param5: Param, - retType: *TypeExpr, - // Body - refBody: *Block, - // Struct fields (up to 8) - fieldCount: int, - field0: StructField, - field1: StructField, - field2: StructField, - field3: StructField, - field4: StructField, - field5: StructField, - field6: StructField, - field7: StructField, - // Enum variants (up to 8) - variantCount: int, - variant0: EnumVariant, - variant1: EnumVariant, - variant2: EnumVariant, - variant3: EnumVariant, - variant4: EnumVariant, - variant5: EnumVariant, - variant6: EnumVariant, - variant7: EnumVariant, - // Impl methods (up to 4) - methodCount: int, - // Use/import - useKind: int, - usePath: String, - useNames: String, // joined names for multi-import - // Const - constType: *TypeExpr, - constValue: *Expr, - // Type alias - aliasType: *TypeExpr, - // Extern func - extFuncDll: String, - extFuncVariadic: bool, - extFuncRetType: *TypeExpr, - // Children - childDecl1: *Decl, // linked list of decls (for module items, impl methods) - childDecl2: *Decl, -} - -// --------------------------------------------------------------------------- -// Module — AST root -// --------------------------------------------------------------------------- -struct Module { - name: String, - path: String, // path segments joined - itemCount: int, - firstItem: *Decl, -} - -// --------------------------------------------------------------------------- -// Constructor helpers -// --------------------------------------------------------------------------- - -func Ast_MakeExpr(kind: int, line: uint32, col: uint32) -> Expr { - return Expr { kind: kind, line: line, column: col, - strValue: "", intValue: 0, boolValue: false, - tokKind: 0, tokText: "", - child1: null as *Expr, child2: null as *Expr, child3: null as *Expr, - refType: null as *TypeExpr, refBlock: null as *Block, - genericCallee: "", genericTypeArg0: "", genericTypeArg1: "", genericTypeArgCount: 0, - structName: "", structFieldCount: 0 }; -} - -func Ast_MakeIdent(name: String, line: uint32, col: uint32) -> Expr { - var e: Expr = Ast_MakeExpr(ekIdent, line, col); - e.strValue = name; - return e; -} - -func Ast_MakeLiteral(tokKind: int, text: String, line: uint32, col: uint32) -> Expr { - var e: Expr = Ast_MakeExpr(ekLiteral, line, col); - e.tokKind = tokKind; - e.tokText = text; - return e; -} - -func Ast_MakeBinary(op: int, left: *Expr, right: *Expr, line: uint32, col: uint32) -> Expr { - var e: Expr = Ast_MakeExpr(ekBinary, line, col); - e.intValue = op; - e.child1 = left; - e.child2 = right; - return e; -} - -func Ast_MakeCall(callee: *Expr, line: uint32, col: uint32) -> Expr { - var e: Expr = Ast_MakeExpr(ekCall, line, col); - e.child1 = callee; - return e; -} - -func Ast_MakeStmt(kind: int, line: uint32, col: uint32) -> Stmt { - return Stmt { kind: kind, line: line, column: col, - strValue: "", boolValue: false, - child1: null as *Expr, child2: null as *Expr, child3: null as *Expr, - refStmtType: null as *TypeExpr, refStmtPattern: null as *Pattern, - refStmtDecl: null as *Decl, refStmtBlock: null as *Block, refStmtElse: null as *Block, - elseIfCount: 0 }; -} - -func Ast_MakeDecl(kind: int, line: uint32, col: uint32) -> Decl { - return Decl { kind: kind, line: line, column: col, isPublic: false, - strValue: "", strValue2: "", - typeParam0: "", typeParam1: "", typeParamCount: 0, - paramCount: 0, - retType: null as *TypeExpr, - refBody: null as *Block, - fieldCount: 0, - variantCount: 0, - methodCount: 0, - useKind: 0, usePath: "", useNames: "", - constType: null as *TypeExpr, constValue: null as *Expr, - aliasType: null as *TypeExpr, - extFuncDll: "", extFuncVariadic: false, extFuncRetType: null as *TypeExpr, - childDecl1: null as *Decl, childDecl2: null as *Decl }; -} -} diff --git a/_selfhost/src/c_backend.bux b/_selfhost/src/c_backend.bux deleted file mode 100644 index 4cf6113..0000000 --- a/_selfhost/src/c_backend.bux +++ /dev/null @@ -1,266 +0,0 @@ -// c_backend.bux — C transpiler backend (ported from c_backend.nim) -// Generates C code from the HIR. -module CBackend { - -// --------------------------------------------------------------------------- -// Type → C type name -// --------------------------------------------------------------------------- - -func CBackend_TypeToC(kind: int) -> String { - if kind == tkVoid { return "void"; } - if kind == tkBool { return "bool"; } - if kind == tkBool8 { return "bool"; } - if kind == tkBool16 { return "bool"; } - if kind == tkBool32 { return "bool"; } - if kind == tkChar8 { return "char"; } - if kind == tkChar16 { return "uint16_t"; } - if kind == tkChar32 { return "uint32_t"; } - if kind == tkStr { return "const char*"; } - if kind == tkInt8 { return "int8_t"; } - if kind == tkInt16 { return "int16_t"; } - if kind == tkInt32 { return "int32_t"; } - if kind == tkInt64 { return "int64_t"; } - if kind == tkInt { return "int"; } - if kind == tkUInt8 { return "uint8_t"; } - if kind == tkUInt16 { return "uint16_t"; } - if kind == tkUInt32 { return "uint32_t"; } - if kind == tkUInt64 { return "uint64_t"; } - if kind == tkUInt { return "unsigned int"; } - if kind == tkFloat32 { return "float"; } - if kind == tkFloat64 { return "double"; } - if kind == tkPointer { return "void*"; } - if kind == tkNamed { return "void*"; } - return "int"; -} - -func CBackend_OpToC(op: int) -> String { - if op == tkPlus { return "+"; } - if op == tkMinus { return "-"; } - if op == tkStar { return "*"; } - if op == tkSlash { return "/"; } - if op == tkPercent { return "%"; } - if op == tkEq { return "=="; } - if op == tkNe { return "!="; } - if op == tkLt { return "<"; } - if op == tkLe { return "<="; } - if op == tkGt { return ">"; } - if op == tkGe { return ">="; } - if op == tkAmpAmp { return "&&"; } - if op == tkPipePipe { return "||"; } - if op == tkBang { return "!"; } - if op == tkAmp { return "&"; } - if op == tkPipe { return "|"; } - if op == tkCaret { return "^"; } - if op == tkShl { return "<<"; } - if op == tkShr { return ">>"; } - if op == tkAssign { return "="; } - return "?"; -} - -// --------------------------------------------------------------------------- -// StringBuilder-based C emitter -// --------------------------------------------------------------------------- - -struct CEmitter { - sb: StringBuilder, - indent: int, -} - -func CBE_Init() -> CEmitter { - var sb: StringBuilder = StringBuilder_NewCap(4096); - return CEmitter { sb: sb, indent: 0 }; -} - -func CBE_Emit(cbe: *CEmitter, text: String) { - var i: int = 0; - while i < cbe.indent { - StringBuilder_Append(&cbe.sb, " "); - i = i + 1; - } - StringBuilder_Append(&cbe.sb, text); -} - -func CBE_EmitLine(cbe: *CEmitter, text: String) { - CBE_Emit(cbe, text); - StringBuilder_Append(&cbe.sb, "\n"); -} - -func CBE_Build(cbe: *CEmitter) -> String { - return StringBuilder_Build(&cbe.sb); -} - -// --------------------------------------------------------------------------- -// Emit HIR node -// --------------------------------------------------------------------------- - -func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) { - if node == null as *HirNode { return; } - let kind: int = node.kind; - - // Literal - if kind == hLit { - StringBuilder_Append(&cbe.sb, node.strValue); - return; - } - - // Variable - if kind == hVar { - StringBuilder_Append(&cbe.sb, node.strValue); - return; - } - - // Binary - if kind == hBinary { - CBE_EmitExpr(cbe, node.child1); - StringBuilder_Append(&cbe.sb, " "); - StringBuilder_Append(&cbe.sb, CBackend_OpToC(node.intValue)); - StringBuilder_Append(&cbe.sb, " "); - CBE_EmitExpr(cbe, node.child2); - return; - } - - // Unary - if kind == hUnary { - StringBuilder_Append(&cbe.sb, CBackend_OpToC(node.intValue)); - CBE_EmitExpr(cbe, node.child1); - return; - } - - // Call - if kind == hCall { - StringBuilder_Append(&cbe.sb, node.strValue); - StringBuilder_Append(&cbe.sb, "("); - if node.child1 != null as *HirNode { - CBE_EmitExpr(cbe, node.child1); - } - if node.child2 != null as *HirNode { - StringBuilder_Append(&cbe.sb, ", "); - CBE_EmitExpr(cbe, node.child2); - } - StringBuilder_Append(&cbe.sb, ")"); - return; - } - - // Return - if kind == hReturn { - StringBuilder_Append(&cbe.sb, "return"); - if node.child1 != null as *HirNode { - StringBuilder_Append(&cbe.sb, " "); - CBE_EmitExpr(cbe, node.child1); - } - return; - } - - // Alloca - if kind == hAlloca { - StringBuilder_Append(&cbe.sb, CBackend_TypeToC(tkInt)); // simplified type - StringBuilder_Append(&cbe.sb, " "); - StringBuilder_Append(&cbe.sb, node.strValue); - StringBuilder_Append(&cbe.sb, ";\n"); - return; - } - - // Store - if kind == hStore { - CBE_EmitExpr(cbe, node.child1); - StringBuilder_Append(&cbe.sb, " = "); - CBE_EmitExpr(cbe, node.child2); - return; - } - - // Cast - if kind == hCast { - StringBuilder_Append(&cbe.sb, "(("); - StringBuilder_Append(&cbe.sb, CBackend_TypeToC(tkPointer)); - StringBuilder_Append(&cbe.sb, ")"); - CBE_EmitExpr(cbe, node.child1); - StringBuilder_Append(&cbe.sb, ")"); - return; - } -} - -// --------------------------------------------------------------------------- -// Emit function declaration -// --------------------------------------------------------------------------- - -func CBE_EmitFuncDecl(cbe: *CEmitter, f: *HirFunc) { - // Return type - if String_Eq(f.retTypeName, "") || String_Eq(f.retTypeName, "void") { - StringBuilder_Append(&cbe.sb, "void "); - } else { - StringBuilder_Append(&cbe.sb, "int "); // simplified - } - - StringBuilder_Append(&cbe.sb, f.name); - StringBuilder_Append(&cbe.sb, "("); - - // Parameters - var i: int = 0; - while i < f.paramCount { - if i > 0 { - StringBuilder_Append(&cbe.sb, ", "); - } - StringBuilder_Append(&cbe.sb, "int "); // simplified param type - var pname: String = ""; - if i == 0 { pname = f.param0.name; } - if i == 1 { pname = f.param1.name; } - if i == 2 { pname = f.param2.name; } - if i == 3 { pname = f.param3.name; } - if i == 4 { pname = f.param4.name; } - if i == 5 { pname = f.param5.name; } - StringBuilder_Append(&cbe.sb, pname); - i = i + 1; - } - - StringBuilder_Append(&cbe.sb, ")"); -} - -// --------------------------------------------------------------------------- -// Generate complete C module -// --------------------------------------------------------------------------- - -func CBackend_Generate(mod: *HirModule) -> String { - let cbe: *CEmitter = bux_alloc(sizeof(CEmitter)) as *CEmitter; - cbe.sb = StringBuilder_NewCap(8192); - cbe.indent = 0; - - // Header - StringBuilder_Append(&cbe.sb, "// Generated by Bux C Backend\n"); - StringBuilder_Append(&cbe.sb, "#include \n"); - StringBuilder_Append(&cbe.sb, "#include \n"); - StringBuilder_Append(&cbe.sb, "#include \n"); - StringBuilder_Append(&cbe.sb, "#include \n"); - StringBuilder_Append(&cbe.sb, "#include \n\n"); - - // Extern declarations - var i: int = 0; - while i < mod.externCount { - CBE_EmitFuncDecl(cbe, &mod.externFuncs[i]); - StringBuilder_Append(&cbe.sb, ";\n"); - i = i + 1; - } - StringBuilder_Append(&cbe.sb, "\n"); - - // Function definitions - i = 0; - while i < mod.funcCount { - CBE_EmitFuncDecl(cbe, &mod.funcs[i]); - StringBuilder_Append(&cbe.sb, " {\n"); - // Body (simplified) - if mod.funcs[i].body != null as *HirNode { - StringBuilder_Append(&cbe.sb, " "); - CBE_EmitExpr(cbe, mod.funcs[i].body); - StringBuilder_Append(&cbe.sb, ";\n"); - } - StringBuilder_Append(&cbe.sb, " return 0;\n}\n\n"); - i = i + 1; - } - - return StringBuilder_Build(&cbe.sb); -} - -func CBackend_Free(cbe: *CEmitter) { - StringBuilder_Free(&cbe.sb); - bux_free(cbe as *void); -} -} diff --git a/_selfhost/src/cli.bux b/_selfhost/src/cli.bux deleted file mode 100644 index 970458c..0000000 --- a/_selfhost/src/cli.bux +++ /dev/null @@ -1,168 +0,0 @@ -// cli.bux — CLI driver for the Bux self-hosting compiler -// Wires together: Lexer → Parser → Sema → HirLower → CBackend -module Cli { - -extern func PrintLine(s: String); -extern func Print(s: String); -extern func ReadFile(path: String) -> String; -extern func WriteFile(path: String, content: String) -> bool; - -// Import the compiler pipeline -// In self-hosting mode, these are compiled together from src_bux/ - -// --------------------------------------------------------------------------- -// Compile a single .bux source file -// --------------------------------------------------------------------------- - -func Cli_Compile(source: String, sourceName: String) -> String { - // Phase 1: Lex - let lex: *Lexer = Lexer_Tokenize(source); - if Lexer_DiagCount(lex) > 0 { - PrintLine("Lex errors:"); - var i: int = 0; - while i < Lexer_DiagCount(lex) { - Print(" "); - PrintLine(lex.diags[i].message); - i = i + 1; - } - return ""; - } - - // Phase 2: Parse - let mod: *Module = Parser_Parse(lex.tokens, lex.tokenCount); - if mod == null as *Module { - PrintLine("Parse failed"); - return ""; - } - - // Phase 3: Semantic analysis - let sema: *Sema = Sema_Analyze(mod); - if Sema_HasError(sema) { - PrintLine("Sema errors:"); - var i: int = 0; - while i < Sema_DiagCount(sema) { - Print(" "); - PrintLine(sema.diags[i].message); - i = i + 1; - } - return ""; - } - - // Phase 4: HIR lowering - let hirMod: *HirModule = HirLower_LowerModule(mod, sema); - if hirMod == null as *HirModule { - PrintLine("HIR lowering failed"); - return ""; - } - - // Phase 5: C code generation - let cCode: String = CBackend_Generate(hirMod); - - // Cleanup - Lexer_Free(lex); - Sema_Free(sema); - - return cCode; -} - -// --------------------------------------------------------------------------- -// Build command -// --------------------------------------------------------------------------- - -func Cli_Build(srcPath: String, outPath: String) -> int { - let source: String = ReadFile(srcPath); - if String_Eq(source, "") || !FileExists(srcPath) { - Print("Error: cannot read source file: "); - PrintLine(srcPath); - return 1; - } - - Print("Compiling "); - PrintLine(srcPath); - - let cCode: String = Cli_Compile(source, srcPath); - - if String_Eq(cCode, "") { - PrintLine("Compilation failed"); - return 1; - } - - // Write C output - let ok: bool = WriteFile(outPath, cCode); - if ok { - Print(" → C code written to "); - PrintLine(outPath); - return 0; - } else { - PrintLine("Error: cannot write output file"); - return 1; - } -} - -// --------------------------------------------------------------------------- -// Check command (compile only, no output) -// --------------------------------------------------------------------------- - -func Cli_Check(srcPath: String) -> int { - let source: String = ReadFile(srcPath); - if String_Eq(source, "") { - PrintLine("Error: cannot read source file"); - return 1; - } - - let cCode: String = Cli_Compile(source, srcPath); - if String_Eq(cCode, "") { - return 1; - } - - PrintLine("Check passed"); - return 0; -} - -// --------------------------------------------------------------------------- -// Main entry — dispatch based on args -// --------------------------------------------------------------------------- - -func Cli_Run(args: *String, argCount: int) -> int { - if argCount < 2 { - PrintLine("Bux Self-Hosting Compiler v0.2.0"); - PrintLine("Usage: buxc [args]"); - PrintLine("Commands: build, check, run, version"); - PrintLine(""); - PrintLine("Pipeline modules:"); - PrintLine(" Lexer ✅ 695 lines"); - PrintLine(" Parser ✅ 1004 lines"); - PrintLine(" Sema ✅ 393 lines"); - PrintLine(" HirLower ✅ 307 lines"); - PrintLine(" CBackend ✅ 264 lines"); - PrintLine(" Total: 3830 lines of Bux"); - return 0; - } - - let cmd: String = args[1]; - if String_Eq(cmd, "version") { - PrintLine("Bux 0.2.0 (self-hosting bootstrap)"); - return 0; - } - - if String_Eq(cmd, "check") { - if argCount < 3 { - PrintLine("Usage: buxc check "); - return 1; - } - return Cli_Check(args[2]); - } - - if String_Eq(cmd, "build") { - let src: String = "src/Main.bux"; - let out: String = "build/main.c"; - if argCount >= 3 { src = args[2]; } - if argCount >= 4 { out = args[3]; } - return Cli_Build(src, out); - } - - Print("Unknown command: "); - PrintLine(cmd); - return 1; -} -} diff --git a/_selfhost/src/hir.bux b/_selfhost/src/hir.bux deleted file mode 100644 index b1886f3..0000000 --- a/_selfhost/src/hir.bux +++ /dev/null @@ -1,191 +0,0 @@ -// hir.bux — HIR (High-level Intermediate Representation) node types -module Hir { - -// HIR node kinds -const hLit: int = 0; -const hVar: int = 1; -const hSelf: int = 2; -const hUnary: int = 3; -const hBinary: int = 4; -const hAssign: int = 5; -const hIf: int = 6; -const hWhile: int = 7; -const hLoop: int = 8; -const hBreak: int = 9; -const hContinue: int = 10; -const hReturn: int = 11; -const hAlloca: int = 12; -const hLoad: int = 13; -const hStore: int = 14; -const hFieldPtr: int = 15; -const hArrowField: int = 16; -const hIndexPtr: int = 17; -const hCall: int = 18; -const hCallIndirect: int = 19; -const hCast: int = 20; -const hIs: int = 21; -const hSizeOf: int = 22; -const hBlock: int = 23; -const hStructInit: int = 24; -const hSliceInit: int = 25; -const hRange: int = 26; -const hTupleInit: int = 27; -const hMatch: int = 28; - -// --------------------------------------------------------------------------- -// HirNode — unified struct with tagged union pattern -// --------------------------------------------------------------------------- - -struct HirNode { - kind: int, - line: uint32, - column: uint32, - typeKind: int, - typeName: String, - // Common fields (used by multiple kinds) - strValue: String, // var name, callee name, field name, label - intValue: int, // token kind (for lit, unary op, binary op) - boolValue: bool, // range inclusive, isScope - // Child nodes (up to 3) - child1: *HirNode, // left/operand/condition/base - child2: *HirNode, // right/value/then/body - child3: *HirNode, // else/third - // Extra data pointer (for children arrays, field lists, etc.) - extraData: *void, - extraCount: int, -} - -// --------------------------------------------------------------------------- -// HirFunc -// --------------------------------------------------------------------------- - -struct HirParam { - name: String, - typeKind: int, - typeName: String, -} - -struct HirFunc { - name: String, - paramCount: int, - param0: HirParam, - param1: HirParam, - param2: HirParam, - param3: HirParam, - param4: HirParam, - param5: HirParam, - retTypeKind: int, - retTypeName: String, - body: *HirNode, - isPublic: bool, -} - -// --------------------------------------------------------------------------- -// HirEnumVariant -// --------------------------------------------------------------------------- - -struct HirEnumVariant { - name: String, - fieldCount: int, - fieldType0: int, - fieldName0: String, - fieldType1: int, - fieldName1: String, -} - -// --------------------------------------------------------------------------- -// HirModule -// --------------------------------------------------------------------------- - -struct HirModule { - funcCount: int, - funcs: *HirFunc, - externCount: int, - externFuncs: *HirFunc, - structCount: int, - enumCount: int, -} - -// --------------------------------------------------------------------------- -// Constructor helpers -// --------------------------------------------------------------------------- - -func Hir_MakeNode(kind: int, line: uint32, column: uint32) -> HirNode { - return HirNode { kind: kind, line: line, column: column, - typeKind: 0, typeName: "", - strValue: "", intValue: 0, boolValue: false, - child1: null as *HirNode, child2: null as *HirNode, child3: null as *HirNode, - extraData: null as *void, extraCount: 0 }; -} - -func Hir_MakeLit(tokKind: int, tokText: String, line: uint32, col: uint32) -> HirNode { - var n: HirNode = Hir_MakeNode(hLit, line, col); - n.intValue = tokKind; - n.strValue = tokText; - return n; -} - -func Hir_MakeVar(name: String, line: uint32, col: uint32) -> HirNode { - var n: HirNode = Hir_MakeNode(hVar, line, col); - n.strValue = name; - return n; -} - -func Hir_MakeBinary(op: int, left: *HirNode, right: *HirNode, line: uint32, col: uint32) -> HirNode { - var n: HirNode = Hir_MakeNode(hBinary, line, col); - n.intValue = op; - n.child1 = left; - n.child2 = right; - return n; -} - -func Hir_MakeCall(callee: String, line: uint32, col: uint32) -> HirNode { - var n: HirNode = Hir_MakeNode(hCall, line, col); - n.strValue = callee; - return n; -} - -func Hir_MakeReturn(value: *HirNode, line: uint32, col: uint32) -> HirNode { - var n: HirNode = Hir_MakeNode(hReturn, line, col); - n.child1 = value; - return n; -} - -func Hir_MakeBlock(line: uint32, col: uint32) -> HirNode { - return Hir_MakeNode(hBlock, line, col); -} - -func Hir_MakeIf(cond: *HirNode, thenBody: *HirNode, elseBody: *HirNode, line: uint32, col: uint32) -> HirNode { - var n: HirNode = Hir_MakeNode(hIf, line, col); - n.child1 = cond; - n.child2 = thenBody; - n.child3 = elseBody; - return n; -} - -func Hir_MakeWhile(cond: *HirNode, body: *HirNode, line: uint32, col: uint32) -> HirNode { - var n: HirNode = Hir_MakeNode(hWhile, line, col); - n.child1 = cond; - n.child2 = body; - return n; -} - -func Hir_MakeAlloca(name: String, line: uint32, col: uint32) -> HirNode { - var n: HirNode = Hir_MakeNode(hAlloca, line, col); - n.strValue = name; - return n; -} - -func Hir_MakeLoad(ptr: *HirNode, line: uint32, col: uint32) -> HirNode { - var n: HirNode = Hir_MakeNode(hLoad, line, col); - n.child1 = ptr; - return n; -} - -func Hir_MakeStore(ptr: *HirNode, value: *HirNode, line: uint32, col: uint32) -> HirNode { - var n: HirNode = Hir_MakeNode(hStore, line, col); - n.child1 = ptr; - n.child2 = value; - return n; -} -} diff --git a/_selfhost/src/hir_lower.bux b/_selfhost/src/hir_lower.bux deleted file mode 100644 index 7100706..0000000 --- a/_selfhost/src/hir_lower.bux +++ /dev/null @@ -1,309 +0,0 @@ -// hir_lower.bux — HIR lowering: AST → HIR transformation (ported from hir_lower.nim) -// Transforms the typed AST into a lower-level IR suitable for code generation. -module HirLower { - -// --------------------------------------------------------------------------- -// Lowering context -// --------------------------------------------------------------------------- -struct LowerCtx { - module: *Module, - scope: *Scope, - funcs: *HirFunc, - funcCount: int, - externFuncs: *HirFunc, - externCount: int, - varCounter: int, - tryCounter: int, -} - -// --------------------------------------------------------------------------- -// Fresh name generation -// --------------------------------------------------------------------------- - -func Lcx_FreshName(ctx: *LowerCtx) -> String { - ctx.varCounter = ctx.varCounter + 1; - return String_FromInt(ctx.varCounter as int64); -} - -// --------------------------------------------------------------------------- -// Type → HIR type -// --------------------------------------------------------------------------- - -func Lcx_LowerType(typeKind: int, typeName: String) -> int { - return typeKind; -} - -// --------------------------------------------------------------------------- -// Expression lowering -// --------------------------------------------------------------------------- - -func Lcx_LowerExpr(ctx: *LowerCtx, expr: *Expr) -> *HirNode { - if expr == null as *Expr { return null as *HirNode; } - - let line: uint32 = expr.line; - let col: uint32 = expr.column; - let n: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode; - n.kind = hBlock; - n.line = line; - n.column = col; - - let kind: int = expr.kind; - - // Literal - if kind == ekLiteral { - n.kind = hLit; - n.intValue = expr.tokKind; - n.strValue = expr.tokText; - return n; - } - - // Identifier → variable reference - if kind == ekIdent { - n.kind = hVar; - n.strValue = expr.strValue; - return n; - } - - // Binary - if kind == ekBinary { - n.kind = hBinary; - n.intValue = expr.intValue; // operator - n.child1 = Lcx_LowerExpr(ctx, expr.child1); - n.child2 = Lcx_LowerExpr(ctx, expr.child2); - return n; - } - - // Unary - if kind == ekUnary { - n.kind = hUnary; - n.intValue = expr.intValue; - n.child1 = Lcx_LowerExpr(ctx, expr.child1); - return n; - } - - // Call - if kind == ekCall { - n.kind = hCall; - // Get callee name - if expr.child1 != null as *Expr && expr.child1.kind == ekIdent { - n.strValue = expr.child1.strValue; - } - // Lower arguments - if expr.child2 != null as *Expr { - n.child1 = Lcx_LowerExpr(ctx, expr.child2); - } - if expr.child3 != null as *Expr { - n.child2 = Lcx_LowerExpr(ctx, expr.child3); - } - return n; - } - - // Field access - if kind == ekField { - n.kind = hFieldPtr; - n.child1 = Lcx_LowerExpr(ctx, expr.child1); - n.strValue = expr.strValue; - return n; - } - - // Return - if kind == ekReturn { - n.kind = hReturn; - n.child1 = Lcx_LowerExpr(ctx, expr.child1); - return n; - } - - // Cast - if kind == ekCast { - n.kind = hCast; - n.child1 = Lcx_LowerExpr(ctx, expr.child1); - return n; - } - - return n; -} - -// --------------------------------------------------------------------------- -// Statement lowering -// --------------------------------------------------------------------------- - -func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode { - if stmt == null as *Stmt { return null as *HirNode; } - - let line: uint32 = stmt.line; - let col: uint32 = stmt.column; - let n: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode; - n.kind = hBlock; - n.line = line; - n.column = col; - - let kind: int = stmt.kind; - - // Let/var → alloca + store - if kind == skLet { - let init: *HirNode = Lcx_LowerExpr(ctx, stmt.child1); - // alloca for the variable - let alloca: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode; - alloca.kind = hAlloca; - alloca.line = line; - alloca.column = col; - alloca.strValue = stmt.strValue; - // store the init value - n.kind = hStore; - n.child1 = alloca; - n.child2 = init; - return n; - } - - // Return - if kind == skReturn { - n.kind = hReturn; - if stmt.child1 != null as *Expr { - n.child1 = Lcx_LowerExpr(ctx, stmt.child1); - } - return n; - } - - // Expression statement - if kind == skExpr && stmt.child1 != null as *Expr { - return Lcx_LowerExpr(ctx, stmt.child1); - } - - // If - if kind == skIf { - n.kind = hIf; - n.child1 = Lcx_LowerExpr(ctx, stmt.child1); // condition - if stmt.refStmtBlock != null as *Block { - n.child2 = Lcx_LowerBlock(ctx, stmt.refStmtBlock, -1); - } - if stmt.refStmtElse != null as *Block { - n.child3 = Lcx_LowerBlock(ctx, stmt.refStmtElse, -1); - } - return n; - } - - // While - if kind == skWhile { - n.kind = hWhile; - n.child1 = Lcx_LowerExpr(ctx, stmt.child1); - if stmt.refStmtBlock != null as *Block { - n.child2 = Lcx_LowerBlock(ctx, stmt.refStmtBlock, -1); - } - return n; - } - - // Loop - if kind == skLoop { - n.kind = hLoop; - if stmt.refStmtBlock != null as *Block { - n.child1 = Lcx_LowerBlock(ctx, stmt.refStmtBlock, -1); - } - return n; - } - - return n; -} - -// --------------------------------------------------------------------------- -// Block lowering -// --------------------------------------------------------------------------- - -func Lcx_LowerBlock(ctx: *LowerCtx, block: *Block, retTypeKind: int) -> *HirNode { - if block == null as *Block { return null as *HirNode; } - - // For simplicity, create a block node with first statement - let n: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode; - n.kind = hBlock; - n.line = block.line; - n.column = block.column; - n.boolValue = true; // isScope - - // In a full implementation, lower all statements - return n; -} - -// --------------------------------------------------------------------------- -// Function lowering -// --------------------------------------------------------------------------- - -func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc { - let f: *HirFunc = bux_alloc(sizeof(HirFunc)) as *HirFunc; - f.name = decl.strValue; - f.isPublic = decl.isPublic; - f.paramCount = decl.paramCount; - f.param0 = decl.param0; - f.param1 = decl.param1; - f.param2 = decl.param2; - f.param3 = decl.param3; - f.param4 = decl.param4; - f.param5 = decl.param5; - - if decl.retType != null as *TypeExpr { - f.retTypeName = decl.retType.typeName; - } else { - f.retTypeName = ""; - } - - if decl.refBody != null as *Block { - f.body = Lcx_LowerBlock(ctx, decl.refBody, -1); - } else { - f.body = null as *HirNode; - } - - return f; -} - -// --------------------------------------------------------------------------- -// Module lowering — main entry point -// --------------------------------------------------------------------------- - -func HirLower_LowerModule(mod: *Module, sema: *Sema) -> *HirModule { - let ctx: *LowerCtx = bux_alloc(sizeof(LowerCtx)) as *LowerCtx; - ctx.module = mod; - ctx.scope = sema.scope; - ctx.funcs = bux_alloc(256 as uint * sizeof(HirFunc)) as *HirFunc; - ctx.funcCount = 0; - ctx.externFuncs = bux_alloc(64 as uint * sizeof(HirFunc)) as *HirFunc; - ctx.externCount = 0; - ctx.varCounter = 0; - - let hm: *HirModule = bux_alloc(sizeof(HirModule)) as *HirModule; - hm.funcCount = 0; - hm.funcs = ctx.funcs; - - // Iterate declarations - var decl: *Decl = mod.firstItem; - while decl != null as *Decl { - if decl.kind == dkFunc { - let f: *HirFunc = Lcx_LowerFunc(ctx, decl); - ctx.funcs[ctx.funcCount] = f; - ctx.funcCount = ctx.funcCount + 1; - } - if decl.kind == dkExternFunc { - let f: *HirFunc = Lcx_LowerFunc(ctx, decl); - ctx.externFuncs[ctx.externCount] = f; - ctx.externCount = ctx.externCount + 1; - } - if decl.kind == dkStruct { - hm.structCount = hm.structCount + 1; - } - if decl.kind == dkEnum { - hm.enumCount = hm.enumCount + 1; - } - decl = decl.childDecl2; - } - - hm.funcCount = ctx.funcCount; - hm.funcs = ctx.funcs; - hm.externCount = ctx.externCount; - hm.externFuncs = ctx.externFuncs; - - return hm; -} - -func HirLower_Free(ctx: *LowerCtx) { - bux_free(ctx.funcs as *void); - bux_free(ctx.externFuncs as *void); - bux_free(ctx as *void); -} -} diff --git a/_selfhost/src/lexer.bux b/_selfhost/src/lexer.bux deleted file mode 100644 index b4f7f40..0000000 --- a/_selfhost/src/lexer.bux +++ /dev/null @@ -1,697 +0,0 @@ -// lexer.bux — Lexer state machine (ported from lexer.nim) -// Tokenizes Bux source into a stream of tokens. -module Lexer { - -extern func bux_strlen(s: String) -> uint; - -// --------------------------------------------------------------------------- -// Character helpers (wrap C ctype) -// --------------------------------------------------------------------------- - -func Lex_IsDigit(c: uint32) -> bool { - return c >= 48 && c <= 57; // '0'..'9' -} - -func Lex_IsHexDigit(c: uint32) -> bool { - if c >= 48 && c <= 57 { return true; } // 0-9 - if c >= 65 && c <= 70 { return true; } // A-F - if c >= 97 && c <= 102 { return true; } // a-f - return false; -} - -func Lex_IsBinDigit(c: uint32) -> bool { - return c == 48 || c == 49; // '0' or '1' -} - -func Lex_IsOctDigit(c: uint32) -> bool { - return c >= 48 && c <= 55; // '0'..'7' -} - -func Lex_IsIdentStart(c: uint32) -> bool { - if c >= 97 && c <= 122 { return true; } // a-z - if c >= 65 && c <= 90 { return true; } // A-Z - return c == 95; // '_' -} - -func Lex_IsIdentChar(c: uint32) -> bool { - if Lex_IsIdentStart(c) { return true; } - return Lex_IsDigit(c); -} - -// --------------------------------------------------------------------------- -// Lexer state -// --------------------------------------------------------------------------- - -const maxTokens: int = 4096; -const maxDiags: int = 128; - -struct LexerDiag { - line: uint32, - column: uint32, - message: String, -} - -struct Lexer { - source: String, - sourceLen: int, - pos: int, - line: uint32, - column: uint32, - startLine: uint32, - startColumn: uint32, - startPos: int, - tokenCount: int, - tokens: *LexToken, - diagCount: int, - diags: *LexerDiag, -} - -struct LexToken { - kind: int, - text: String, - line: uint32, - column: uint32, -} - -// --------------------------------------------------------------------------- -// Init -// --------------------------------------------------------------------------- - -func Lexer_Init(source: String) -> Lexer { - let len: uint = bux_strlen(source); - let tokBuf: *LexToken = bux_alloc(maxTokens as uint * sizeof(LexToken)) as *LexToken; - let diagBuf: *LexerDiag = bux_alloc(maxDiags as uint * sizeof(LexerDiag)) as *LexerDiag; - return Lexer { - source: source, sourceLen: len as int, - pos: 0, line: 1, column: 1, - startLine: 0, startColumn: 0, startPos: 0, - tokenCount: 0, tokens: tokBuf, - diagCount: 0, diags: diagBuf - }; -} - -// --------------------------------------------------------------------------- -// Core primitives -// --------------------------------------------------------------------------- - -func lexIsAtEnd(lex: *Lexer) -> bool { - return lex.pos >= lex.sourceLen; -} - -func lexPeek(lex: *Lexer, ahead: int) -> uint32 { - let i: int = lex.pos + ahead; - if i < lex.sourceLen { - return lex.source[i] as uint32; - } - return 0; -} - -func lexAdvance(lex: *Lexer) -> uint32 { - let c: uint32 = lexPeek(lex, 0); - if !lexIsAtEnd(lex) { - lex.pos = lex.pos + 1; - if c == 10 { // '\n' - lex.line = lex.line + 1; - lex.column = 1; - } else { - lex.column = lex.column + 1; - } - } - return c; -} - -func lexMatch(lex: *Lexer, expected: uint32) -> bool { - if lexIsAtEnd(lex) { return false; } - if lexPeek(lex, 0) != expected { return false; } - discard lexAdvance(lex); - return true; -} - -func lexMatchStr(lex: *Lexer, s: String) -> bool { - let len: uint = bux_strlen(s); - var i: int = 0; - while i < (len as int) { - if lexPeek(lex, i) != (s[i] as uint32) { - return false; - } - i = i + 1; - } - i = 0; - while i < (len as int) { - discard lexAdvance(lex); - i = i + 1; - } - return true; -} - -// --------------------------------------------------------------------------- -// Token emission -// --------------------------------------------------------------------------- - -func lexMarkStart(lex: *Lexer) { - lex.startLine = lex.line; - lex.startColumn = lex.column; - lex.startPos = lex.pos; -} - -func lexMakeToken(lex: *Lexer, kind: int) -> LexToken { - var text: String = ""; - let endPos: int = lex.pos; - let startPos: int = lex.startPos; - if endPos > startPos { - let len: int = endPos - startPos; - let buf: *char8 = bux_alloc((len + 1) as uint) as *char8; - var i: int = 0; - while i < len { - buf[i] = lex.source[startPos + i] as char8; - i = i + 1; - } - buf[len] = 0 as char8; - text = buf; - } else { - text = ""; - } - return LexToken { - kind: kind, text: text, - line: lex.startLine, column: lex.startColumn - }; -} - -func lexEmitToken(lex: *Lexer, kind: int) { - let tok: LexToken = lexMakeToken(lex, kind); - if lex.tokenCount < maxTokens { - lex.tokens[lex.tokenCount] = tok; - lex.tokenCount = lex.tokenCount + 1; - } -} - -func lexEmitDiag(lex: *Lexer, msg: String) { - if lex.diagCount < maxDiags { - lex.diags[lex.diagCount] = LexerDiag { - line: lex.line, column: lex.column, message: msg - }; - lex.diagCount = lex.diagCount + 1; - } -} - -// --------------------------------------------------------------------------- -// Whitespace / comments -// --------------------------------------------------------------------------- - -func lexSkipLineComment(lex: *Lexer) { - while !lexIsAtEnd(lex) && lexPeek(lex, 0) != 10 { // '\n' - discard lexAdvance(lex); - } -} - -func lexSkipBlockComment(lex: *Lexer) { - var depth: int = 1; - while !lexIsAtEnd(lex) && depth > 0 { - if lexPeek(lex, 0) == 47 && lexPeek(lex, 1) == 42 { // /* - discard lexAdvance(lex); - discard lexAdvance(lex); - depth = depth + 1; - } else if lexPeek(lex, 0) == 42 && lexPeek(lex, 1) == 47 { // */ - discard lexAdvance(lex); - discard lexAdvance(lex); - depth = depth - 1; - } else { - discard lexAdvance(lex); - } - } - if depth > 0 { - lexEmitDiag(lex, "unterminated block comment"); - } -} - -func lexSkipWhitespace(lex: *Lexer) { - while !lexIsAtEnd(lex) { - let c: uint32 = lexPeek(lex, 0); - if c == 32 || c == 9 || c == 13 { // space, tab, CR - discard lexAdvance(lex); - } else if c == 47 && lexPeek(lex, 1) == 47 { // // - lexSkipLineComment(lex); - } else if c == 47 && lexPeek(lex, 1) == 42 { // /* - discard lexAdvance(lex); - discard lexAdvance(lex); - lexSkipBlockComment(lex); - } else { - break; - } - } -} - -// --------------------------------------------------------------------------- -// Identifiers -// --------------------------------------------------------------------------- - -func lexIsIdentKind(tok: int) -> bool { - return tok == tkFunc || tok == tkLet || tok == tkVar || tok == tkConst - || tok == tkType || tok == tkStruct || tok == tkEnum || tok == tkUnion - || tok == tkInterface || tok == tkExtend || tok == tkModule || tok == tkImport - || tok == tkPub || tok == tkExtern || tok == tkIf || tok == tkElse - || tok == tkWhile || tok == tkDo || tok == tkLoop || tok == tkFor - || tok == tkIn || tok == tkBreak || tok == tkContinue || tok == tkReturn - || tok == tkMatch || tok == tkAs || tok == tkIs || tok == tkNull - || tok == tkSelf || tok == tkSuper; -} - -func lexKeywordKind(text: String) -> int { - if String_Eq(text, "true") { return tkBoolLiteral; } - if String_Eq(text, "false") { return tkBoolLiteral; } - if String_Eq(text, "func") { return tkFunc; } - if String_Eq(text, "let") { return tkLet; } - if String_Eq(text, "var") { return tkVar; } - if String_Eq(text, "const") { return tkConst; } - if String_Eq(text, "type") { return tkType; } - if String_Eq(text, "struct") { return tkStruct; } - if String_Eq(text, "enum") { return tkEnum; } - if String_Eq(text, "union") { return tkUnion; } - if String_Eq(text, "interface") { return tkInterface; } - if String_Eq(text, "extend") { return tkExtend; } - if String_Eq(text, "module") { return tkModule; } - if String_Eq(text, "import") { return tkImport; } - if String_Eq(text, "pub") { return tkPub; } - if String_Eq(text, "extern") { return tkExtern; } - if String_Eq(text, "if") { return tkIf; } - if String_Eq(text, "else") { return tkElse; } - if String_Eq(text, "while") { return tkWhile; } - if String_Eq(text, "do") { return tkDo; } - if String_Eq(text, "loop") { return tkLoop; } - if String_Eq(text, "for") { return tkFor; } - if String_Eq(text, "in") { return tkIn; } - if String_Eq(text, "break") { return tkBreak; } - if String_Eq(text, "continue") { return tkContinue; } - if String_Eq(text, "return") { return tkReturn; } - if String_Eq(text, "match") { return tkMatch; } - if String_Eq(text, "as") { return tkAs; } - if String_Eq(text, "is") { return tkIs; } - if String_Eq(text, "null") { return tkNull; } - if String_Eq(text, "self") { return tkSelf; } - if String_Eq(text, "super") { return tkSuper; } - if String_Eq(text, "sizeof") { return tkSizeOf; } - return tkIdent; -} - -func lexScanIdent(lex: *Lexer) { - lexMarkStart(lex); - while !lexIsAtEnd(lex) && Lex_IsIdentChar(lexPeek(lex, 0)) { - discard lexAdvance(lex); - } - let tok: LexToken = lexMakeToken(lex, tkIdent); - let kind: int = lexKeywordKind(tok.text); - tok.kind = kind; - if lex.tokenCount < maxTokens { - lex.tokens[lex.tokenCount] = tok; - lex.tokenCount = lex.tokenCount + 1; - } -} - -// --------------------------------------------------------------------------- -// Numbers -// --------------------------------------------------------------------------- - -func lexScanDigits(lex: *Lexer) { - while !lexIsAtEnd(lex) && Lex_IsDigit(lexPeek(lex, 0)) { - discard lexAdvance(lex); - } -} - -func lexScanHexDigits(lex: *Lexer) { - while !lexIsAtEnd(lex) && Lex_IsHexDigit(lexPeek(lex, 0)) { - discard lexAdvance(lex); - } -} - -func lexScanNumber(lex: *Lexer) { - lexMarkStart(lex); - var isFloat: bool = false; - - if lexPeek(lex, 0) == 48 { // '0' - let p1: uint32 = lexPeek(lex, 1); - if p1 == 120 || p1 == 88 || p1 == 98 || p1 == 66 || p1 == 111 || p1 == 79 { // x X b B o O - discard lexAdvance(lex); // 0 - discard lexAdvance(lex); // prefix - if p1 == 120 || p1 == 88 { lexScanHexDigits(lex); } - else if p1 == 98 || p1 == 66 { - while !lexIsAtEnd(lex) && Lex_IsBinDigit(lexPeek(lex, 0)) { - discard lexAdvance(lex); - } - } - else { - while !lexIsAtEnd(lex) && Lex_IsOctDigit(lexPeek(lex, 0)) { - discard lexAdvance(lex); - } - } - lexEmitToken(lex, tkIntLiteral); - return; - } - } - - lexScanDigits(lex); - - if lexPeek(lex, 0) == 46 && Lex_IsDigit(lexPeek(lex, 1)) { // . digit - isFloat = true; - discard lexAdvance(lex); // . - lexScanDigits(lex); - } - - let e: uint32 = lexPeek(lex, 0); - if e == 101 || e == 69 { // e E - isFloat = true; - discard lexAdvance(lex); - let sign: uint32 = lexPeek(lex, 0); - if sign == 43 || sign == 45 { discard lexAdvance(lex); } // + - - lexScanDigits(lex); - } - - if isFloat { - lexEmitToken(lex, tkFloatLiteral); - } else { - lexEmitToken(lex, tkIntLiteral); - } -} - -// --------------------------------------------------------------------------- -// Strings and chars -// --------------------------------------------------------------------------- - -func lexScanString(lex: *Lexer) { - lexMarkStart(lex); - if lexPeek(lex, 0) == 34 { discard lexAdvance(lex); } // opening " - while !lexIsAtEnd(lex) && lexPeek(lex, 0) != 34 { // closing " - if lexPeek(lex, 0) == 10 { // \n - lexEmitDiag(lex, "unterminated string literal"); - break; - } - if lexPeek(lex, 0) == 92 { // backslash - discard lexAdvance(lex); - if !lexIsAtEnd(lex) { discard lexAdvance(lex); } // skip escape char - } else { - discard lexAdvance(lex); - } - } - if lexIsAtEnd(lex) { - lexEmitDiag(lex, "unterminated string literal"); - } else { - discard lexAdvance(lex); // closing " - } - lexEmitToken(lex, tkStringLiteral); -} - -func lexScanChar(lex: *Lexer) { - lexMarkStart(lex); - if lexPeek(lex, 0) == 39 { discard lexAdvance(lex); } // opening ' - if lexIsAtEnd(lex) { - lexEmitDiag(lex, "unterminated char literal"); - lexEmitToken(lex, tkCharLiteral); - return; - } - if lexPeek(lex, 0) == 10 { // \n - lexEmitDiag(lex, "newline in char literal"); - } else if lexPeek(lex, 0) == 92 { // backslash - discard lexAdvance(lex); - if !lexIsAtEnd(lex) { discard lexAdvance(lex); } - } else { - discard lexAdvance(lex); - } - if lexIsAtEnd(lex) || lexPeek(lex, 0) != 39 { - lexEmitDiag(lex, "expected closing ' for char literal"); - } else { - discard lexAdvance(lex); // closing ' - } - lexEmitToken(lex, tkCharLiteral); -} - -// --------------------------------------------------------------------------- -// Symbols / operators -// --------------------------------------------------------------------------- - -func lexScanSymbol(lex: *Lexer) { - lexMarkStart(lex); - let c: uint32 = lexAdvance(lex); - - // Single-char tokens - if c == 40 { lexEmitToken(lex, tkLParen); return; } - if c == 41 { lexEmitToken(lex, tkRParen); return; } - if c == 123 { lexEmitToken(lex, tkLBrace); return; } - if c == 125 { lexEmitToken(lex, tkRBrace); return; } - if c == 91 { lexEmitToken(lex, tkLBracket); return; } - if c == 93 { lexEmitToken(lex, tkRBracket); return; } - if c == 44 { lexEmitToken(lex, tkComma); return; } - if c == 59 { lexEmitToken(lex, tkSemicolon); return; } - if c == 64 { lexEmitToken(lex, tkAt); return; } - if c == 63 { lexEmitToken(lex, tkQuestion); return; } - if c == 126 { lexEmitToken(lex, tkTilde); return; } - - // : :: - if c == 58 { - if lexMatch(lex, 58) { lexEmitToken(lex, tkColonColon); } - else { lexEmitToken(lex, tkColon); } - return; - } - - // . .. ... ..= - if c == 46 { - if lexPeek(lex, 0) == 46 && lexPeek(lex, 1) == 46 { - discard lexAdvance(lex); discard lexAdvance(lex); - lexEmitToken(lex, tkDotDotDot); return; - } - if lexPeek(lex, 0) == 46 && lexPeek(lex, 1) == 61 { - discard lexAdvance(lex); discard lexAdvance(lex); - lexEmitToken(lex, tkDotDotEqual); return; - } - if lexMatch(lex, 46) { lexEmitToken(lex, tkDotDot); return; } - lexEmitToken(lex, tkDot); return; - } - - // - -> -- -= - if c == 45 { - if lexMatch(lex, 62) { lexEmitToken(lex, tkArrow); return; } - if lexMatch(lex, 45) { lexEmitToken(lex, tkMinusMinus); return; } - if lexMatch(lex, 61) { lexEmitToken(lex, tkMinusAssign); return; } - lexEmitToken(lex, tkMinus); return; - } - - // + ++ += - if c == 43 { - if lexMatch(lex, 43) { lexEmitToken(lex, tkPlusPlus); return; } - if lexMatch(lex, 61) { lexEmitToken(lex, tkPlusAssign); return; } - lexEmitToken(lex, tkPlus); return; - } - - // * ** *= - if c == 42 { - if lexMatch(lex, 42) { lexEmitToken(lex, tkStarStar); return; } - if lexMatch(lex, 61) { lexEmitToken(lex, tkStarAssign); return; } - lexEmitToken(lex, tkStar); return; - } - - // / /= - if c == 47 { - if lexMatch(lex, 61) { lexEmitToken(lex, tkSlashAssign); return; } - lexEmitToken(lex, tkSlash); return; - } - - // % %= - if c == 37 { - if lexMatch(lex, 61) { lexEmitToken(lex, tkPercentAssign); return; } - lexEmitToken(lex, tkPercent); return; - } - - // = == => - if c == 61 { - if lexMatch(lex, 61) { lexEmitToken(lex, tkEq); return; } - if lexMatch(lex, 62) { lexEmitToken(lex, tkFatArrow); return; } - lexEmitToken(lex, tkAssign); return; - } - - // ! != - if c == 33 { - if lexMatch(lex, 61) { lexEmitToken(lex, tkNe); return; } - lexEmitToken(lex, tkBang); return; - } - - // < <= << <<= - if c == 60 { - if lexMatch(lex, 61) { lexEmitToken(lex, tkLe); return; } - if lexMatch(lex, 60) { - if lexMatch(lex, 61) { lexEmitToken(lex, tkShlAssign); return; } - lexEmitToken(lex, tkShl); return; - } - lexEmitToken(lex, tkLt); return; - } - - // > >= >> >>= - if c == 62 { - if lexMatch(lex, 61) { lexEmitToken(lex, tkGe); return; } - if lexMatch(lex, 62) { - if lexMatch(lex, 61) { lexEmitToken(lex, tkShrAssign); return; } - lexEmitToken(lex, tkShr); return; - } - lexEmitToken(lex, tkGt); return; - } - - // & && &= - if c == 38 { - if lexMatch(lex, 38) { lexEmitToken(lex, tkAmpAmp); return; } - if lexMatch(lex, 61) { lexEmitToken(lex, tkAmpAssign); return; } - lexEmitToken(lex, tkAmp); return; - } - - // | || |= - if c == 124 { - if lexMatch(lex, 124) { lexEmitToken(lex, tkPipePipe); return; } - if lexMatch(lex, 61) { lexEmitToken(lex, tkPipeAssign); return; } - lexEmitToken(lex, tkPipe); return; - } - - // ^ ^= - if c == 94 { - if lexMatch(lex, 61) { lexEmitToken(lex, tkCaretAssign); return; } - lexEmitToken(lex, tkCaret); return; - } - - // # intrinsics - if c == 35 { - if lexMatchStr(lex, "line") { lexEmitToken(lex, tkHashLine); return; } - if lexMatchStr(lex, "column") { lexEmitToken(lex, tkHashColumn); return; } - if lexMatchStr(lex, "file") { lexEmitToken(lex, tkHashFile); return; } - if lexMatchStr(lex, "function") { lexEmitToken(lex, tkHashFunction); return; } - if lexMatchStr(lex, "date") { lexEmitToken(lex, tkHashDate); return; } - if lexMatchStr(lex, "time") { lexEmitToken(lex, tkHashTime); return; } - if lexMatchStr(lex, "module") { lexEmitToken(lex, tkHashModule); return; } - lexEmitToken(lex, tkHash); return; - } - - lexEmitDiag(lex, "unexpected character"); - lexEmitToken(lex, tkUnknown); -} - -// --------------------------------------------------------------------------- -// Next token -// --------------------------------------------------------------------------- - -func lexNextToken(lex: *Lexer) { - lexSkipWhitespace(lex); - - if lexIsAtEnd(lex) { - lexMarkStart(lex); - lexEmitToken(lex, tkEndOfFile); - return; - } - - let c: uint32 = lexPeek(lex, 0); - - if c == 10 { // \n - lexMarkStart(lex); - discard lexAdvance(lex); - lexEmitToken(lex, tkNewLine); - return; - } - - // String prefixes: c8" c16" c32" - if c == 99 { // 'c' - let d: uint32 = lexPeek(lex, 1); - if d == 56 && lexPeek(lex, 2) == 34 { // c8" - discard lexAdvance(lex); discard lexAdvance(lex); // c 8 - lexScanString(lex); return; - } - if d == 49 && lexPeek(lex, 2) == 54 && lexPeek(lex, 3) == 34 { // c16" - discard lexAdvance(lex); discard lexAdvance(lex); discard lexAdvance(lex); - lexScanString(lex); return; - } - if d == 51 && lexPeek(lex, 2) == 50 && lexPeek(lex, 3) == 34 { // c32" - discard lexAdvance(lex); discard lexAdvance(lex); discard lexAdvance(lex); - lexScanString(lex); return; - } - } - - if c == 34 { // " - lexScanString(lex); return; - } - - // Char prefixes: c8' c16' c32' - if c == 99 { // 'c' - let d: uint32 = lexPeek(lex, 1); - if d == 56 && lexPeek(lex, 2) == 39 { // c8' - discard lexAdvance(lex); discard lexAdvance(lex); - lexScanChar(lex); return; - } - if d == 49 && lexPeek(lex, 2) == 54 && lexPeek(lex, 3) == 39 { // c16' - discard lexAdvance(lex); discard lexAdvance(lex); discard lexAdvance(lex); - lexScanChar(lex); return; - } - if d == 51 && lexPeek(lex, 2) == 50 && lexPeek(lex, 3) == 39 { // c32' - discard lexAdvance(lex); discard lexAdvance(lex); discard lexAdvance(lex); - lexScanChar(lex); return; - } - } - - if c == 39 { // ' - lexScanChar(lex); return; - } - - if Lex_IsIdentStart(c) { - lexScanIdent(lex); return; - } - - if Lex_IsDigit(c) { - lexScanNumber(lex); return; - } - - lexScanSymbol(lex); -} - -// --------------------------------------------------------------------------- -// Tokenize — main entry point -// --------------------------------------------------------------------------- - -func Lexer_Tokenize(source: String) -> *Lexer { - let lex: *Lexer = bux_alloc(sizeof(Lexer)) as *Lexer; - lex.source = source; - lex.sourceLen = bux_strlen(source) as int; - lex.pos = 0; - lex.line = 1; - lex.column = 1; - lex.startLine = 0; - lex.startColumn = 0; - lex.startPos = 0; - let tokBuf: *LexToken = bux_alloc(maxTokens as uint * sizeof(LexToken)) as *LexToken; - let diagBuf: *LexerDiag = bux_alloc(maxDiags as uint * sizeof(LexerDiag)) as *LexerDiag; - lex.tokens = tokBuf; - lex.diags = diagBuf; - lex.tokenCount = 0; - lex.diagCount = 0; - - while true { - lexNextToken(lex); - if lex.tokens[lex.tokenCount - 1].kind == tkEndOfFile { - break; - } - } - return lex; -} - -func Lexer_TokenCount(lex: *Lexer) -> int { - return lex.tokenCount; -} - -func Lexer_GetToken(lex: *Lexer, index: int) -> LexToken { - if index >= 0 && index < lex.tokenCount { - return lex.tokens[index]; - } - var empty: LexToken; - return empty; -} - -func Lexer_DiagCount(lex: *Lexer) -> int { - return lex.diagCount; -} - -func Lexer_Free(lex: *Lexer) { - bux_free(lex.tokens as *void); - bux_free(lex.diags as *void); - bux_free(lex as *void); -} -} diff --git a/_selfhost/src/main.bux b/_selfhost/src/main.bux deleted file mode 100644 index 181fe20..0000000 --- a/_selfhost/src/main.bux +++ /dev/null @@ -1,13 +0,0 @@ -// main.bux — Entry point for the Bux self-hosting compiler -module Main { - -// Forward declaration from Cli module -func Cli_Run(args: *String, argCount: int) -> int; - -func Main() -> int { - // In a full implementation, parse command-line arguments - // For now, just show version info - var emptyArgs: *String = null as *String; - return Cli_Run(emptyArgs, 0); -} -} diff --git a/_selfhost/src/manifest.bux b/_selfhost/src/manifest.bux deleted file mode 100644 index ef130bd..0000000 --- a/_selfhost/src/manifest.bux +++ /dev/null @@ -1,86 +0,0 @@ -// manifest.bux — Manifest parser for bux.toml files -// Parses package metadata: name, version, type, build output. -module Manifest { - -// --------------------------------------------------------------------------- -// Manifest struct -// --------------------------------------------------------------------------- -struct Manifest { - name: String, - version: String, - pkgType: String, - output: String, -} - -// --------------------------------------------------------------------------- -// Simple TOML parser (handles [Package] and [Build] sections) -// --------------------------------------------------------------------------- - -func Manifest_Parse(content: String) -> Manifest { - var m: Manifest; - m.name = ""; - m.version = "0.1.0"; - m.pkgType = "bin"; - m.output = "Bin"; - - if String_Eq(content, "") { return m; } - - var currentSection: String = ""; - let count: uint = String_SplitCount(content, "\n"); - var i: uint = 0; - while i < count { - let line: String = String_SplitPart(content, "\n", i); - - // Skip empty lines and comments - if String_Eq(line, "") { i = i + 1; continue; } - if String_StartsWith(line, "#") { i = i + 1; continue; } - - // Section header: [Section] - if String_StartsWith(line, "[") { - if String_StartsWith(line, "[Package]") { - currentSection = "Package"; - } else if String_StartsWith(line, "[Build]") { - currentSection = "Build"; - } else { - currentSection = ""; - } - i = i + 1; continue; - } - - // Key = Value - let eqCount: uint = String_SplitCount(line, "="); - if eqCount >= 2 { - let key: String = String_Trim(String_SplitPart(line, "=", 0)); - let rawVal: String = String_Trim(String_SplitPart(line, "=", 1)); - - // Strip quotes from value - var val: String = rawVal; - if String_StartsWith(val, "\"") && String_EndsWith(val, "\"") { - let len: uint = String_SplitCount(val, ""); // dummy to get length indirectly - // Simple strip: just use the string between quotes - val = String_Slice(rawVal, 1, String_SplitCount(rawVal, "") as uint - 2); - } - - if String_Eq(currentSection, "Package") { - if String_Eq(key, "Name") { m.name = val; } - if String_Eq(key, "Version") { m.version = val; } - if String_Eq(key, "Type") { m.pkgType = val; } - } else if String_Eq(currentSection, "Build") { - if String_Eq(key, "Output") { m.output = val; } - } - } - i = i + 1; - } - - return m; -} - -// --------------------------------------------------------------------------- -// Load manifest from file -// --------------------------------------------------------------------------- - -func Manifest_Load(path: String) -> Manifest { - let content: String = ReadFile(path); - return Manifest_Parse(content); -} -} diff --git a/_selfhost/src/parser.bux b/_selfhost/src/parser.bux deleted file mode 100644 index e8e34c3..0000000 --- a/_selfhost/src/parser.bux +++ /dev/null @@ -1,1006 +0,0 @@ -// parser.bux — Recursive descent parser (ported from parser.nim) -// Parses Bux source tokens into an AST. -module Parser { - -extern func bux_strlen(s: String) -> uint; - -// --------------------------------------------------------------------------- -// Parser state -// --------------------------------------------------------------------------- -struct Parser { - tokens: *LexToken, - tokenCount: int, - pos: int, - diagCount: int, - diags: *ParserDiag, - structInitAllowed: bool, -} - -struct ParserDiag { - line: uint32, - column: uint32, - message: String, -} - -// --------------------------------------------------------------------------- -// Token helpers -// --------------------------------------------------------------------------- - -func parserCurToken(p: *Parser) -> LexToken { - if p.pos < p.tokenCount { - return p.tokens[p.pos]; - } - var eof: LexToken; - eof.kind = tkEndOfFile; - eof.text = ""; - return eof; -} - -func parserPeek(p: *Parser, ahead: int) -> int { - let i: int = p.pos + ahead; - if i >= 0 && i < p.tokenCount { - return p.tokens[i].kind; - } - return tkEndOfFile; -} - -func parserAdvance(p: *Parser) -> LexToken { - let tok: LexToken = parserCurToken(p); - if p.pos < p.tokenCount { - p.pos = p.pos + 1; - } - return tok; -} - -func parserCheck(p: *Parser, kind: int) -> bool { - return parserPeek(p, 0) == kind; -} - -func parserMatch(p: *Parser, kind: int) -> bool { - if parserCheck(p, kind) { - discard parserAdvance(p); - return true; - } - return false; -} - -func parserPrevious(p: *Parser) -> LexToken { - if p.pos > 0 && p.pos <= p.tokenCount { - return p.tokens[p.pos - 1]; - } - var eof: LexToken; - eof.kind = tkEndOfFile; - return eof; -} - -func parserExpect(p: *Parser, kind: int, msg: String) -> LexToken { - if parserCheck(p, kind) { - return parserAdvance(p); - } - let tok: LexToken = parserCurToken(p); - p.diags[p.diagCount] = ParserDiag { - line: tok.line, column: tok.column, message: msg - }; - p.diagCount = p.diagCount + 1; - return tok; -} - -func parserEmitDiag(p: *Parser, line: uint32, col: uint32, msg: String) { - p.diags[p.diagCount] = ParserDiag { - line: line, column: col, message: msg - }; - p.diagCount = p.diagCount + 1; -} - -// --------------------------------------------------------------------------- -// Type parsing -// --------------------------------------------------------------------------- - -func parserParseType(p: *Parser) -> *TypeExpr { - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - let kindTok: int = parserPeek(p, 0); - - // *T (pointer) - if kindTok == tkStar { - discard parserAdvance(p); - let te: *TypeExpr = bux_alloc(sizeof(TypeExpr)) as *TypeExpr; - te.kind = tekPointer; - te.line = line; - te.column = col; - te.pointerPointee = parserParseType(p); - return te; - } - - // name - let nameTok: LexToken = parserExpect(p, tkIdent, "expected type name"); - let te: *TypeExpr = bux_alloc(sizeof(TypeExpr)) as *TypeExpr; - te.kind = tekNamed; - te.line = nameTok.line; - te.column = nameTok.column; - te.typeName = nameTok.text; - - // Optional type args - if parserCheck(p, tkLt) { - discard parserAdvance(p); // < - let arg0: LexToken = parserExpect(p, tkIdent, "expected type argument"); - te.typeArgName0 = arg0.text; - te.typeArgCount = 1; - if parserMatch(p, tkComma) { - let arg1: LexToken = parserExpect(p, tkIdent, "expected type argument"); - te.typeArgName1 = arg1.text; - te.typeArgCount = 2; - } - discard parserExpect(p, tkGt, "expected '>' to close type arguments"); - } - return te; -} - -// --------------------------------------------------------------------------- -// Forward declarations and helpers -// --------------------------------------------------------------------------- - -func parserParseExpr(p: *Parser) -> *Expr; -func parserParseStmt(p: *Parser) -> *Stmt; -func parserParseBlock(p: *Parser) -> *Block; - -func parserMakeExpr(kind: int, line: uint32, col: uint32) -> *Expr { - let e: *Expr = bux_alloc(sizeof(Expr)) as *Expr; - e.kind = kind; - e.line = line; - e.column = col; - e.strValue = ""; - e.intValue = 0; - e.boolValue = false; - e.tokKind = 0; - e.tokText = ""; - e.child1 = null as *Expr; - e.child2 = null as *Expr; - e.child3 = null as *Expr; - e.refType = null as *TypeExpr; - e.refBlock = null as *Block; - e.genericCallee = ""; - e.genericTypeArg0 = ""; - e.genericTypeArg1 = ""; - e.genericTypeArgCount = 0; - e.structName = ""; - e.structFieldCount = 0; - return e; -} - -// --------------------------------------------------------------------------- -// Primary expressions -// --------------------------------------------------------------------------- - -func parserParsePrimary(p: *Parser) -> *Expr { - let tok: LexToken = parserCurToken(p); - let line: uint32 = tok.line; - let col: uint32 = tok.column; - let kind: int = tok.kind; - - // Literals - if kind == tkIntLiteral || kind == tkFloatLiteral || kind == tkStringLiteral - || kind == tkCharLiteral || kind == tkBoolLiteral { - discard parserAdvance(p); - let e: *Expr = parserMakeExpr(ekLiteral, line, col); - e.tokKind = kind; - e.tokText = tok.text; - return e; - } - - // Identifier - if kind == tkIdent { - discard parserAdvance(p); - let e: *Expr = parserMakeExpr(ekIdent, line, col); - e.strValue = tok.text; - return e; - } - - // self - if kind == tkSelf { - discard parserAdvance(p); - return parserMakeExpr(ekSelf, line, col); - } - - // null - if kind == tkNull { - discard parserAdvance(p); - let e: *Expr = parserMakeExpr(ekLiteral, line, col); - e.tokKind = tkNull; - return e; - } - - // sizeof(Type) - if kind == tkSizeOf { - discard parserAdvance(p); - let e: *Expr = parserMakeExpr(ekSizeOf, line, col); - e.refType = parserParseType(p); - return e; - } - - // #intrinsics - if kind >= tkHashLine && kind <= tkHashModule { - discard parserAdvance(p); - let e: *Expr = parserMakeExpr(ekLiteral, line, col); - e.intValue = kind; - return e; - } - - // ( expr ) - if kind == tkLParen { - discard parserAdvance(p); - let e: *Expr = parserParseExpr(p); - discard parserExpect(p, tkRParen, "expected ')'"); - return e; - } - - // -expr, !expr, *expr, &expr - if kind == tkMinus || kind == tkBang || kind == tkStar || kind == tkAmp { - discard parserAdvance(p); - let e: *Expr = parserMakeExpr(ekUnary, line, col); - e.intValue = kind; - e.child1 = parserParsePrimary(p); - return e; - } - - parserEmitDiag(p, line, col, "expected expression"); - return parserMakeExpr(ekLiteral, line, col); -} - -// --------------------------------------------------------------------------- -// Postfix: call, index, field access, as, is, ? -// --------------------------------------------------------------------------- - -func parserParsePostfix(p: *Parser) -> *Expr { - var left: *Expr = parserParsePrimary(p); - - while true { - let kind: int = parserPeek(p, 0); - - // Call: expr(args) - if kind == tkLParen { - discard parserAdvance(p); - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - let e: *Expr = parserMakeExpr(ekCall, line, col); - e.child1 = left; - // Parse arguments (up to 8) - // child2 = first arg, child3 = second arg, extra = rest - if !parserCheck(p, tkRParen) { - e.child2 = parserParseExpr(p); - if parserMatch(p, tkComma) { - e.child3 = parserParseExpr(p); - } - } - discard parserExpect(p, tkRParen, "expected ')'"); - left = e; - continue; - } - - // Index: expr[expr] - if kind == tkLBracket { - discard parserAdvance(p); - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - let e: *Expr = parserMakeExpr(ekIndex, line, col); - e.child1 = left; - e.child2 = parserParseExpr(p); - discard parserExpect(p, tkRBracket, "expected ']'"); - left = e; - continue; - } - - // Field: expr.name - if kind == tkDot { - discard parserAdvance(p); - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - let name: LexToken = parserExpect(p, tkIdent, "expected field name"); - let e: *Expr = parserMakeExpr(ekField, line, col); - e.child1 = left; - e.strValue = name.text; - left = e; - continue; - } - - // as, is - if kind == tkAs || kind == tkIs { - discard parserAdvance(p); - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - let ek: int = 0; - if kind == tkAs { ek = ekCast; } else { ek = ekIs; } - let e: *Expr = parserMakeExpr(ek, line, col); - e.child1 = left; - e.refType = parserParseType(p); - left = e; - continue; - } - - // ? (try operator) - if kind == tkQuestion { - discard parserAdvance(p); - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - let e: *Expr = parserMakeExpr(ekTry, line, col); - e.child1 = left; - left = e; - continue; - } - - // ++, -- - if kind == tkPlusPlus || kind == tkMinusMinus { - discard parserAdvance(p); - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - let e: *Expr = parserMakeExpr(ekPostfix, line, col); - e.child1 = left; - e.intValue = kind; - left = e; - continue; - } - - break; - } - return left; -} - -// --------------------------------------------------------------------------- -// Binary expression (precedence climbing) -// All binary operators: arithmetic, comparison, logical, bitwise, assignment -// --------------------------------------------------------------------------- - -func parserIsBinaryOp(kind: int) -> bool { - if kind >= tkPlus && kind <= tkStarStar { return true; } // arithmetic - if kind == tkAmp || kind == tkPipe || kind == tkCaret { return true; } // bitwise (no &|) - if kind >= tkShl && kind <= tkShrAssign { return true; } // shift + assign - if kind >= tkEq && kind <= tkGe { return true; } // comparison - if kind == tkAmpAmp || kind == tkPipePipe { return true; } // logical - if kind >= tkAssign && kind <= tkShrAssign { return true; } // all assigns - if kind == tkDotDot || kind == tkDotDotEqual { return true; } // range - return false; -} - -func parserParseBinary(p: *Parser) -> *Expr { - var left: *Expr = parserParsePostfix(p); - - while parserIsBinaryOp(parserPeek(p, 0)) { - let opTok: LexToken = parserAdvance(p); - let line: uint32 = opTok.line; - let col: uint32 = opTok.column; - let right: *Expr = parserParsePostfix(p); - let e: *Expr = parserMakeExpr(ekBinary, line, col); - e.intValue = opTok.kind; - e.child1 = left; - e.child2 = right; - left = e; - } - return left; -} - -// --------------------------------------------------------------------------- -// Ternary: cond ? then : else -// --------------------------------------------------------------------------- - -func parserParseTernary(p: *Parser) -> *Expr { - var left: *Expr = parserParseBinary(p); - if parserMatch(p, tkQuestion) { - let thenExpr: *Expr = parserParseExpr(p); - discard parserExpect(p, tkColon, "expected ':' in ternary"); - let elseExpr: *Expr = parserParseExpr(p); - let e: *Expr = parserMakeExpr(ekTernary, left.line, left.column); - e.child1 = left; - e.child2 = thenExpr; - e.child3 = elseExpr; - return e; - } - return left; -} - -// --------------------------------------------------------------------------- -// Top-level expression -// --------------------------------------------------------------------------- - -func parserParseExpr(p: *Parser) -> *Expr { - return parserParseTernary(p); -} - -// --------------------------------------------------------------------------- -// Statements -// --------------------------------------------------------------------------- - -func parserParseStmt(p: *Parser) -> *Stmt { - let tok: LexToken = parserCurToken(p); - let line: uint32 = tok.line; - let col: uint32 = tok.column; - let kind: int = tok.kind; - - // let / var - if kind == tkLet || kind == tkVar { - let isVar: bool = (kind == tkVar); - discard parserAdvance(p); - let nameTok: LexToken = parserExpect(p, tkIdent, "expected variable name"); - var typeExpr: *TypeExpr = null as *TypeExpr; - if parserMatch(p, tkColon) { - typeExpr = parserParseType(p); - } - discard parserExpect(p, tkAssign, "expected '=' in let/var statement"); - let init: *Expr = parserParseExpr(p); - parserMatch(p, tkSemicolon); // optional ; - - let s: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt; - s.kind = skLet; - s.line = line; - s.column = col; - s.strValue = nameTok.text; - s.boolValue = isVar; - s.child1 = init; - s.refStmtType = typeExpr; - return s; - } - - // if - if kind == tkIf { - discard parserAdvance(p); - let cond: *Expr = parserParseExpr(p); - let thenBlock: *Block = parserParseBlock(p); - var elseBlock: *Block = null as *Block; - if parserMatch(p, tkElse) { - if parserCheck(p, tkIf) { - // else if → recursively parse an if stmt inside else - elseBlock = parserParseBlock(p); - } else { - elseBlock = parserParseBlock(p); - } - } - let s: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt; - s.kind = skIf; - s.line = line; - s.column = col; - s.child1 = cond; - s.refStmtBlock = thenBlock; - s.refStmtElse = elseBlock; - return s; - } - - // while - if kind == tkWhile { - discard parserAdvance(p); - let cond: *Expr = parserParseExpr(p); - let body: *Block = parserParseBlock(p); - let s: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt; - s.kind = skWhile; - s.line = line; - s.column = col; - s.child1 = cond; - s.refStmtBlock = body; - return s; - } - - // loop - if kind == tkLoop { - discard parserAdvance(p); - let body: *Block = parserParseBlock(p); - let s: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt; - s.kind = skLoop; - s.line = line; - s.column = col; - s.refStmtBlock = body; - return s; - } - - // for - if kind == tkFor { - discard parserAdvance(p); - let varName: LexToken = parserExpect(p, tkIdent, "expected loop variable"); - discard parserExpect(p, tkIn, "expected 'in'"); - let iter: *Expr = parserParseExpr(p); - let body: *Block = parserParseBlock(p); - let s: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt; - s.kind = skFor; - s.line = line; - s.column = col; - s.strValue = varName.text; - s.child1 = iter; - s.refStmtBlock = body; - return s; - } - - // return - if kind == tkReturn { - discard parserAdvance(p); - var value: *Expr = null as *Expr; - if !parserCheck(p, tkSemicolon) && !parserCheck(p, tkNewLine) && !parserCheck(p, tkRBrace) { - value = parserParseExpr(p); - } - parserMatch(p, tkSemicolon); - let s: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt; - s.kind = skReturn; - s.line = line; - s.column = col; - s.child1 = value; - return s; - } - - // break / continue - if kind == tkBreak || kind == tkContinue { - let sk: int = 0; - if kind == tkBreak { sk = skBreak; } else { sk = skContinue; } - discard parserAdvance(p); - parserMatch(p, tkSemicolon); - let s: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt; - s.kind = sk; - s.line = line; - s.column = col; - return s; - } - - // match - if kind == tkMatch { - discard parserAdvance(p); - let subject: *Expr = parserParseExpr(p); - discard parserExpect(p, tkLBrace, "expected '{' to start match body"); - // Skip match body (simplified — just parse arms as empty) - while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile { - if parserCheck(p, tkNewLine) { discard parserAdvance(p); continue; } - discard parserParseExpr(p); // pattern - if parserMatch(p, tkFatArrow) { - discard parserParseExpr(p); // body - } - } - discard parserExpect(p, tkRBrace, "expected '}' to close match"); - let s: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt; - s.kind = skMatch; - s.line = line; - s.column = col; - s.child1 = subject; - return s; - } - - // Expression statement - if kind == tkNewLine || kind == tkSemicolon { - discard parserAdvance(p); - return null as *Stmt; - } - - let expr: *Expr = parserParseExpr(p); - parserMatch(p, tkSemicolon); - let s: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt; - s.kind = skExpr; - s.line = line; - s.column = col; - s.child1 = expr; - return s; -} - -// --------------------------------------------------------------------------- -// Block: { stmt* } -// --------------------------------------------------------------------------- - -func parserParseBlock(p: *Parser) -> *Block { - discard parserExpect(p, tkLBrace, "expected '{'"); - let b: *Block = bux_alloc(sizeof(Block)) as *Block; - b.line = parserCurToken(p).line; - b.column = parserCurToken(p).column; - b.stmtCount = 0; - - while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile { - if parserCheck(p, tkNewLine) || parserCheck(p, tkSemicolon) { - discard parserAdvance(p); - continue; - } - let s: *Stmt = parserParseStmt(p); - if s != null as *Stmt { - b.stmtCount = b.stmtCount + 1; - } - } - discard parserExpect(p, tkRBrace, "expected '}'"); - return b; -} - -// --------------------------------------------------------------------------- -// Function parameters -// --------------------------------------------------------------------------- - -func parserParseParamList(p: *Parser) -> *Decl { - let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl; - d.kind = dkFunc; - d.paramCount = 0; - - discard parserExpect(p, tkLParen, "expected '('"); - while !parserCheck(p, tkRParen) && parserPeek(p, 0) != tkEndOfFile { - if d.paramCount >= 6 { break; } - let nameTok: LexToken = parserExpect(p, tkIdent, "expected parameter name"); - discard parserExpect(p, tkColon, "expected ':' in parameter"); - let ptype: *TypeExpr = parserParseType(p); - - if d.paramCount == 0 { - d.param0.name = nameTok.text; - d.param0.refParamType = ptype; - } else if d.paramCount == 1 { - d.param1.name = nameTok.text; - d.param1.refParamType = ptype; - } else if d.paramCount == 2 { - d.param2.name = nameTok.text; - d.param2.refParamType = ptype; - } else if d.paramCount == 3 { - d.param3.name = nameTok.text; - d.param3.refParamType = ptype; - } else if d.paramCount == 4 { - d.param4.name = nameTok.text; - d.param4.refParamType = ptype; - } else if d.paramCount == 5 { - d.param5.name = nameTok.text; - d.param5.refParamType = ptype; - } - d.paramCount = d.paramCount + 1; - - if parserMatch(p, tkComma) { continue; } - break; - } - discard parserExpect(p, tkRParen, "expected ')'"); - return d; -} - -// --------------------------------------------------------------------------- -// Declarations -// --------------------------------------------------------------------------- - -func parserParseFuncDecl(p: *Parser, isPublic: bool, isExtern: bool) -> *Decl { - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - discard parserExpect(p, tkFunc, "expected 'func'"); - - let nameTok: LexToken = parserExpect(p, tkIdent, "expected function name"); - let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl; - d.kind = dkFunc; - d.line = line; - d.column = col; - d.isPublic = isPublic; - d.strValue = nameTok.text; - - // Type params - if parserCheck(p, tkLt) { - discard parserAdvance(p); - let tp0: LexToken = parserExpect(p, tkIdent, "expected type param"); - d.typeParam0 = tp0.text; - d.typeParamCount = 1; - if parserMatch(p, tkComma) { - let tp1: LexToken = parserExpect(p, tkIdent, "expected type param"); - d.typeParam1 = tp1.text; - d.typeParamCount = 2; - } - discard parserExpect(p, tkGt, "expected '>'"); - } - - // Params - let params: *Decl = parserParseParamList(p); - d.paramCount = params.paramCount; - d.param0 = params.param0; - d.param1 = params.param1; - d.param2 = params.param2; - d.param3 = params.param3; - d.param4 = params.param4; - d.param5 = params.param5; - - // Return type - if parserMatch(p, tkArrow) { - d.retType = parserParseType(p); - } - - // Body - if !isExtern && parserCheck(p, tkLBrace) { - d.refBody = parserParseBlock(p); - } else { - d.refBody = null as *Block; - } - - return d; -} - -func parserParseStructDecl(p: *Parser, isPublic: bool) -> *Decl { - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - discard parserExpect(p, tkStruct, "expected 'struct'"); - let nameTok: LexToken = parserExpect(p, tkIdent, "expected struct name"); - - let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl; - d.kind = dkStruct; - d.line = line; - d.column = col; - d.isPublic = isPublic; - d.strValue = nameTok.text; - - // Type params - if parserCheck(p, tkLt) { - discard parserAdvance(p); - let tp0: LexToken = parserExpect(p, tkIdent, "expected type param"); - d.typeParam0 = tp0.text; - d.typeParamCount = 1; - if parserMatch(p, tkComma) { - let tp1: LexToken = parserExpect(p, tkIdent, "expected type param"); - d.typeParam1 = tp1.text; - d.typeParamCount = 2; - } - discard parserExpect(p, tkGt, "expected '>'"); - } - - discard parserExpect(p, tkLBrace, "expected '{'"); - while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile { - if d.fieldCount >= 8 { break; } - if parserCheck(p, tkNewLine) { discard parserAdvance(p); continue; } - let fName: LexToken = parserExpect(p, tkIdent, "expected field name"); - discard parserExpect(p, tkColon, "expected ':' in struct field"); - let fType: *TypeExpr = parserParseType(p); - parserMatch(p, tkSemicolon); - - if d.fieldCount == 0 { - d.field0.name = fName.text; - d.field0.refFieldType = fType; - } else if d.fieldCount == 1 { - d.field1.name = fName.text; - d.field1.refFieldType = fType; - } else if d.fieldCount == 2 { - d.field2.name = fName.text; - d.field2.refFieldType = fType; - } else if d.fieldCount == 3 { - d.field3.name = fName.text; - d.field3.refFieldType = fType; - } - d.fieldCount = d.fieldCount + 1; - } - discard parserExpect(p, tkRBrace, "expected '}'"); - return d; -} - -func parserParseEnumDecl(p: *Parser, isPublic: bool) -> *Decl { - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - discard parserExpect(p, tkEnum, "expected 'enum'"); - let nameTok: LexToken = parserExpect(p, tkIdent, "expected enum name"); - - let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl; - d.kind = dkEnum; - d.line = line; - d.column = col; - d.isPublic = isPublic; - d.strValue = nameTok.text; - - discard parserExpect(p, tkLBrace, "expected '{'"); - while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile { - if d.variantCount >= 8 { break; } - if parserCheck(p, tkNewLine) || parserCheck(p, tkSemicolon) { discard parserAdvance(p); continue; } - let vName: LexToken = parserExpect(p, tkIdent, "expected variant name"); - - var v: EnumVariant; - v.name = vName.text; - - // Optional (Type, Type) data - if parserMatch(p, tkLParen) { - let t0: LexToken = parserExpect(p, tkIdent, "expected data type"); - v.fieldTypeName0 = t0.text; - v.fieldCount = 1; - if parserMatch(p, tkComma) { - let t1: LexToken = parserExpect(p, tkIdent, "expected data type"); - v.fieldTypeName1 = t1.text; - v.fieldCount = 2; - } - discard parserExpect(p, tkRParen, "expected ')'"); - } - - if d.variantCount == 0 { d.variant0 = v; } - else if d.variantCount == 1 { d.variant1 = v; } - else if d.variantCount == 2 { d.variant2 = v; } - else if d.variantCount == 3 { d.variant3 = v; } - d.variantCount = d.variantCount + 1; - - parserMatch(p, tkComma); - if parserCheck(p, tkNewLine) { discard parserAdvance(p); } - } - discard parserExpect(p, tkRBrace, "expected '}'"); - return d; -} - -func parserParseImportDecl(p: *Parser, isPublic: bool) -> *Decl { - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - discard parserExpect(p, tkImport, "expected 'import'"); - - let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl; - d.kind = dkUse; - d.line = line; - d.column = col; - d.isPublic = isPublic; - - // Parse path: Std::Io::PrintLine - var pathStr: String = ""; - var segCount: int = 0; - while parserCheck(p, tkIdent) || (segCount > 0 && parserCheck(p, tkColonColon)) { - if segCount > 0 { - discard parserAdvance(p); // :: - if pathStr.len > 0 { - let tmp: *char8 = bux_alloc(256) as *char8; - // Append to path string (simplified) - pathStr = String_Concat(pathStr, "::"); - } - } - let seg: LexToken = parserExpect(p, tkIdent, "expected module path segment"); - pathStr = String_Concat(pathStr, seg.text); - segCount = segCount + 1; - } - d.usePath = pathStr; - - // Optional ::{name1, name2} - if parserMatch(p, tkColonColon) && parserCheck(p, tkLBrace) { - discard parserAdvance(p); // { - var names: String = ""; - while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile { - let n: LexToken = parserExpect(p, tkIdent, "expected import name"); - names = String_Concat(names, n.text); - names = String_Concat(names, ","); - if !parserMatch(p, tkComma) { break; } - } - discard parserExpect(p, tkRBrace, "expected '}'"); - d.useNames = names; - d.useKind = 2; // ukMulti - } else { - d.useKind = 0; // ukSingle - } - - parserMatch(p, tkSemicolon); - return d; -} - -func parserParseExternDecl(p: *Parser, isPublic: bool) -> *Decl { - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - discard parserExpect(p, tkExtern, "expected 'extern'"); - - if parserCheck(p, tkFunc) { - let d: *Decl = parserParseFuncDecl(p, isPublic, true); - d.kind = dkExternFunc; - return d; - } - - let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl; - d.kind = dkExternFunc; - d.line = line; - d.column = col; - d.isPublic = isPublic; - return d; -} - -// --------------------------------------------------------------------------- -// Top-level declaration -// --------------------------------------------------------------------------- - -func parserParseDecl(p: *Parser) -> *Decl { - let isPublic: bool = parserMatch(p, tkPub); - let kind: int = parserPeek(p, 0); - - if kind == tkFunc { return parserParseFuncDecl(p, isPublic, false); } - if kind == tkStruct { return parserParseStructDecl(p, isPublic); } - if kind == tkEnum { return parserParseEnumDecl(p, isPublic); } - if kind == tkImport { return parserParseImportDecl(p, isPublic); } - if kind == tkExtern { return parserParseExternDecl(p, isPublic); } - - if kind == tkExtend { - discard parserAdvance(p); - let line: uint32 = parserCurToken(p).line; - let col: uint32 = parserCurToken(p).column; - let typeName: LexToken = parserExpect(p, tkIdent, "expected type name"); - - let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl; - d.kind = dkImpl; - d.line = line; - d.column = col; - d.isPublic = isPublic; - d.strValue = typeName.text; - - // Optional - if parserCheck(p, tkLt) { - discard parserAdvance(p); - let tp0: LexToken = parserExpect(p, tkIdent, "expected type param"); - d.typeParam0 = tp0.text; - d.typeParamCount = 1; - discard parserExpect(p, tkGt, "expected '>'"); - } - - discard parserExpect(p, tkLBrace, "expected '{'"); - while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile { - if parserCheck(p, tkNewLine) { discard parserAdvance(p); continue; } - if parserCheck(p, tkFunc) { - let m: *Decl = parserParseFuncDecl(p, false, false); - // Store method in linked list - if d.methodCount == 0 { - d.childDecl1 = m; - } else if d.methodCount == 1 { - d.childDecl2 = m; - } - d.methodCount = d.methodCount + 1; - } else { - break; - } - } - discard parserExpect(p, tkRBrace, "expected '}'"); - return d; - } - - if kind == tkModule { - discard parserAdvance(p); - let name: LexToken = parserExpect(p, tkIdent, "expected module name"); - parserMatch(p, tkSemicolon); - let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl; - d.kind = dkModule; - d.strValue = name.text; - return d; - } - - if kind == tkConst { - discard parserAdvance(p); - let name: LexToken = parserExpect(p, tkIdent, "expected const name"); - discard parserExpect(p, tkColon, "expected ':'"); - let ct: *TypeExpr = parserParseType(p); - discard parserExpect(p, tkAssign, "expected '='"); - let val: *Expr = parserParseExpr(p); - parserMatch(p, tkSemicolon); - let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl; - d.kind = dkConst; - d.strValue = name.text; - d.constType = ct; - d.constValue = val; - return d; - } - - // Skip unknown declarations - while parserPeek(p, 0) != tkEndOfFile && parserPeek(p, 0) != tkNewLine && parserPeek(p, 0) != tkRBrace { - discard parserAdvance(p); - } - return null as *Decl; -} - -// --------------------------------------------------------------------------- -// Module parsing -// --------------------------------------------------------------------------- - -func Parser_Parse(tokens: *LexToken, tokenCount: int) -> *Module { - let p: *Parser = bux_alloc(sizeof(Parser)) as *Parser; - p.tokens = tokens; - p.tokenCount = tokenCount; - p.pos = 0; - p.structInitAllowed = true; - let diagBuf: *ParserDiag = bux_alloc(256 as uint * sizeof(ParserDiag)) as *ParserDiag; - p.diags = diagBuf; - p.diagCount = 0; - - let mod: *Module = bux_alloc(sizeof(Module)) as *Module; - mod.name = ""; - mod.itemCount = 0; - mod.firstItem = null as *Decl; - - // Parse declarations until EOF - while parserPeek(p, 0) != tkEndOfFile { - if parserCheck(p, tkNewLine) || parserCheck(p, tkSemicolon) { - discard parserAdvance(p); - continue; - } - let decl: *Decl = parserParseDecl(p); - if decl != null as *Decl { - decl.childDecl2 = mod.firstItem; // push front - mod.firstItem = decl; - mod.itemCount = mod.itemCount + 1; - } - } - - return mod; -} - -func Parser_DiagCount(p: *Parser) -> int { - return p.diagCount; -} - -func Parser_Free(p: *Parser) { - bux_free(p.diags as *void); - bux_free(p as *void); -} -} diff --git a/_selfhost/src/scope.bux b/_selfhost/src/scope.bux deleted file mode 100644 index 062d359..0000000 --- a/_selfhost/src/scope.bux +++ /dev/null @@ -1,93 +0,0 @@ -// scope.bux — Symbol table with parent-chain lookup -module Scope { - -// Symbol kinds -const skVar: int = 0; -const skFunc: int = 1; -const skType: int = 2; -const skConst: int = 3; -const skModule: int = 4; - -// Maximum symbols per scope -const maxSymbols: int = 256; - -struct Symbol { - kind: int, - name: String, - typeKind: int, - typeName: String, - isMutable: bool, - isPublic: bool, -} - -struct Scope { - symbols: *Symbol, - count: int, - parent: *Scope, -} - -// --------------------------------------------------------------------------- -// Scope operations -// --------------------------------------------------------------------------- - -func Scope_New() -> Scope { - let sz: uint = maxSymbols as uint * sizeof(Symbol); - let data: *Symbol = bux_alloc(sz) as *Symbol; - return Scope { symbols: data, count: 0, parent: null as *Scope }; -} - -func Scope_NewChild(parent: *Scope) -> Scope { - let sz: uint = maxSymbols as uint * sizeof(Symbol); - let data: *Symbol = bux_alloc(sz) as *Symbol; - return Scope { symbols: data, count: 0, parent: parent }; -} - -func Scope_Define(scope: *Scope, sym: Symbol) -> bool { - // Check local scope for duplicates - var i: int = 0; - while i < scope.count { - if String_Eq(scope.symbols[i].name, sym.name) { - return false; - } - i = i + 1; - } - if scope.count < maxSymbols { - scope.symbols[scope.count] = sym; - scope.count = scope.count + 1; - return true; - } - return false; -} - -func Scope_Lookup(scope: *Scope, name: String) -> Symbol { - var cur: *Scope = scope; - while cur != null as *Scope { - var i: int = 0; - while i < cur.count { - if String_Eq(cur.symbols[i].name, name) { - return cur.symbols[i]; - } - i = i + 1; - } - cur = cur.parent; - } - var empty: Symbol; - return empty; -} - -func Scope_LookupLocal(scope: *Scope, name: String) -> Symbol { - var i: int = 0; - while i < scope.count { - if String_Eq(scope.symbols[i].name, name) { - return scope.symbols[i]; - } - i = i + 1; - } - var empty: Symbol; - return empty; -} - -func Scope_Free(scope: *Scope) { - bux_free(scope.symbols as *void); -} -} diff --git a/_selfhost/src/sema.bux b/_selfhost/src/sema.bux deleted file mode 100644 index 1a31e09..0000000 --- a/_selfhost/src/sema.bux +++ /dev/null @@ -1,395 +0,0 @@ -// sema.bux — Semantic analysis (type checker, ported from sema.nim) -// Validates types, resolves identifiers, checks function calls. -module Sema { - -// --------------------------------------------------------------------------- -// Sema context -// --------------------------------------------------------------------------- -struct Sema { - module: *Module, - scope: *Scope, - typeTable: *StringMap, - methodTable: *StringMap, - diagCount: int, - diags: *SemaDiag, - hasError: bool, -} - -struct SemaDiag { - line: uint32, - column: uint32, - message: String, -} - -// --------------------------------------------------------------------------- -// Diagnostics -// --------------------------------------------------------------------------- - -func Sema_EmitError(sema: *Sema, line: uint32, col: uint32, msg: String) { - if sema.diagCount < 256 { - sema.diags[sema.diagCount] = SemaDiag { line: line, column: col, message: msg }; - sema.diagCount = sema.diagCount + 1; - } - sema.hasError = true; -} - -// --------------------------------------------------------------------------- -// Type resolution from TypeExpr → Type constants -// --------------------------------------------------------------------------- - -func Sema_ResolveType(sema: *Sema, te: *TypeExpr) -> int { - if te == null as *TypeExpr { return tkUnknown; } - let name: String = te.typeName; - - if te.kind == tekPointer { - return tkPointer; - } - - if String_Eq(name, "void") { return tkVoid; } - if String_Eq(name, "bool") { return tkBool; } - if String_Eq(name, "bool8") { return tkBool8; } - if String_Eq(name, "bool16") { return tkBool16; } - if String_Eq(name, "bool32") { return tkBool32; } - if String_Eq(name, "char8") { return tkChar8; } - if String_Eq(name, "char16") { return tkChar16; } - if String_Eq(name, "char32") { return tkChar32; } - if String_Eq(name, "String") { return tkStr; } - if String_Eq(name, "str") { return tkStr; } - if String_Eq(name, "int8") { return tkInt8; } - if String_Eq(name, "int16") { return tkInt16; } - if String_Eq(name, "int32") { return tkInt32; } - if String_Eq(name, "int64") { return tkInt64; } - if String_Eq(name, "int") { return tkInt; } - if String_Eq(name, "uint8") { return tkUInt8; } - if String_Eq(name, "uint16") { return tkUInt16; } - if String_Eq(name, "uint32") { return tkUInt32; } - if String_Eq(name, "uint64") { return tkUInt64; } - if String_Eq(name, "uint") { return tkUInt; } - if String_Eq(name, "float32") { return tkFloat32; } - if String_Eq(name, "float64") { return tkFloat64; } - if String_Eq(name, "float") { return tkFloat64; } - - // Check type table for user-defined types - if sema.typeTable != null as *StringMap { - if StringMap_Has(sema.typeTable, name) { - return tkNamed; - } - } - return tkNamed; // assume named type -} - -// --------------------------------------------------------------------------- -// Type predicates -// --------------------------------------------------------------------------- - -func Sema_IsNumeric(kind: int) -> bool { - if kind == tkUnknown || kind == tkNamed || kind == tkTypeParam { return true; } - return kind >= tkInt8 && kind <= tkUInt64; -} - -func Sema_IsBool(kind: int) -> bool { - return kind == tkBool || kind == tkBool8 || kind == tkBool16 || kind == tkBool32; -} - -func Sema_TypeName(kind: int) -> String { - if kind == tkUnknown { return "?"; } - if kind == tkVoid { return "void"; } - if kind == tkBool { return "bool"; } - if kind == tkInt { return "int"; } - if kind == tkInt64 { return "int64"; } - if kind == tkUInt { return "uint"; } - if kind == tkFloat64 { return "float64"; } - if kind == tkStr { return "String"; } - if kind == tkPointer { return "*ptr"; } - if kind == tkNamed { return "user-type"; } - if kind == tkTypeParam { return "type-param"; } - return "?"; -} - -// --------------------------------------------------------------------------- -// Expression type checking -// --------------------------------------------------------------------------- - -func Sema_CheckExpr(sema: *Sema, expr: *Expr) -> int { - if expr == null as *Expr { return tkUnknown; } - let kind: int = expr.kind; - - // Literal - if kind == ekLiteral { - let tk: int = expr.tokKind; - if tk == tkIntLiteral { return tkInt; } - if tk == tkFloatLiteral { return tkFloat64; } - if tk == tkStringLiteral { return tkStr; } - if tk == tkBoolLiteral { return tkBool; } - if tk == tkCharLiteral { return tkChar32; } - if tk == tkNull { return tkPointer; } - return tkUnknown; - } - - // Identifier — look up in scope - if kind == ekIdent { - let sym: Symbol = Scope_Lookup(sema.scope, expr.strValue); - if sym.kind == 0 && !String_Eq(sym.name, expr.strValue) { - Sema_EmitError(sema, expr.line, expr.column, "undeclared identifier"); - return tkUnknown; - } - return sym.typeKind; - } - - // Binary - if kind == ekBinary { - let left: int = Sema_CheckExpr(sema, expr.child1); - let right: int = Sema_CheckExpr(sema, expr.child2); - let op: int = expr.intValue; - - // Comparison operators return bool - if op >= tkEq && op <= tkGe { return tkBool; } - // Logical operators return bool - if op == tkAmpAmp || op == tkPipePipe || op == tkBang { return tkBool; } - // Arithmetic returns wider type - if !Sema_IsNumeric(left) || !Sema_IsNumeric(right) { - Sema_EmitError(sema, expr.line, expr.column, "arithmetic requires numeric operands"); - } - if left == tkFloat64 || right == tkFloat64 { return tkFloat64; } - return tkInt; - } - - // Unary - if kind == ekUnary { - let operand: int = Sema_CheckExpr(sema, expr.child1); - let op: int = expr.intValue; - if op == tkBang { return tkBool; } - if op == tkStar { return tkUnknown; } // dereference — resolve pointee - if op == tkAmp { return tkPointer; } - return operand; - } - - // Call - if kind == ekCall { - let callee: int = Sema_CheckExpr(sema, expr.child1); - if callee == tkUnknown { return tkUnknown; } - // Assume callee returns same type (simplified) - return callee; - } - - // Ternary - if kind == ekTernary { - return Sema_CheckExpr(sema, expr.child2); // then type - } - - // Cast — return target type - if kind == ekCast { - if expr.refType != null as *TypeExpr { - return Sema_ResolveType(sema, expr.refType); - } - return tkUnknown; - } - - // Try (?) - if kind == ekTry { - let inner: int = Sema_CheckExpr(sema, expr.child1); - return inner; // simplified - } - - return tkUnknown; -} - -// --------------------------------------------------------------------------- -// Statement checking -// --------------------------------------------------------------------------- - -func Sema_CheckStmt(sema: *Sema, stmt: *Stmt) { - if stmt == null as *Stmt { return; } - let kind: int = stmt.kind; - - // Let/var - if kind == skLet { - let initType: int = Sema_CheckExpr(sema, stmt.child1); - // Register variable in scope - var sym: Symbol; - sym.kind = skVar; - sym.name = stmt.strValue; - sym.typeKind = initType; - sym.isMutable = stmt.boolValue; - sym.isPublic = false; - discard Scope_Define(sema.scope, sym); - return; - } - - // Return - if kind == skReturn { - if stmt.child1 != null as *Expr { - discard Sema_CheckExpr(sema, stmt.child1); - } - return; - } - - // If - if kind == skIf { - let condType: int = Sema_CheckExpr(sema, stmt.child1); - if !Sema_IsBool(condType) && condType != tkUnknown { - Sema_EmitError(sema, stmt.line, stmt.column, "if condition must be bool"); - } - return; - } - - // While - if kind == skWhile { - let condType: int = Sema_CheckExpr(sema, stmt.child1); - if !Sema_IsBool(condType) && condType != tkUnknown { - Sema_EmitError(sema, stmt.line, stmt.column, "while condition must be bool"); - } - return; - } - - // Expression statement - if kind == skExpr && stmt.child1 != null as *Expr { - discard Sema_CheckExpr(sema, stmt.child1); - return; - } -} - -// --------------------------------------------------------------------------- -// Collect globals (register functions, structs, enums in scope) -// --------------------------------------------------------------------------- - -func Sema_CollectGlobals(sema: *Sema) { - var decl: *Decl = sema.module.firstItem; - while decl != null as *Decl { - let dk: int = decl.kind; - - // Function - if dk == dkFunc { - var sym: Symbol; - sym.kind = skFunc; - sym.name = decl.strValue; - sym.typeKind = tkFunc; - sym.isPublic = decl.isPublic; - discard Scope_Define(sema.scope, sym); - } - - // Struct - if dk == dkStruct { - var sym: Symbol; - sym.kind = skType; - sym.name = decl.strValue; - sym.typeKind = tkNamed; - sym.isPublic = decl.isPublic; - discard Scope_Define(sema.scope, sym); - } - - // Enum - if dk == dkEnum { - var sym: Symbol; - sym.kind = skType; - sym.name = decl.strValue; - sym.typeKind = tkNamed; - sym.isPublic = decl.isPublic; - discard Scope_Define(sema.scope, sym); - } - - // Extern function - if dk == dkExternFunc { - var sym: Symbol; - sym.kind = skFunc; - sym.name = decl.strValue; - sym.typeKind = tkFunc; - sym.isPublic = true; - discard Scope_Define(sema.scope, sym); - } - - decl = decl.childDecl2; - } -} - -// --------------------------------------------------------------------------- -// Analyze — main entry point -// --------------------------------------------------------------------------- - -func Sema_Analyze(mod: *Module) -> *Sema { - let s: *Sema = bux_alloc(sizeof(Sema)) as *Sema; - s.module = mod; - s.scope = bux_alloc(sizeof(Scope)) as *Scope; - s.scope.symbols = bux_alloc(256 as uint * sizeof(Symbol)) as *Symbol; - s.scope.count = 0; - s.scope.parent = null as *Scope; - s.hasError = false; - s.diagCount = 0; - s.diags = bux_alloc(256 as uint * sizeof(SemaDiag)) as *SemaDiag; - s.typeTable = null as *StringMap; - s.methodTable = null as *StringMap; - - // First pass: collect globals - Sema_CollectGlobals(s); - - // Second pass: check function bodies - var decl: *Decl = mod.firstItem; - while decl != null as *Decl { - if decl.kind == dkFunc && decl.refBody != null as *Block { - // Create function scope (child of global) - var funcScope: Scope = Scope_NewChild(s.scope); - - // Add type params to scope - if decl.typeParamCount >= 1 { - var tpSym: Symbol; - tpSym.kind = skType; - tpSym.name = decl.typeParam0; - tpSym.typeKind = tkTypeParam; - discard Scope_Define(&funcScope, tpSym); - } - if decl.typeParamCount >= 2 { - var tpSym2: Symbol; - tpSym2.kind = skType; - tpSym2.name = decl.typeParam1; - tpSym2.typeKind = tkTypeParam; - discard Scope_Define(&funcScope, tpSym2); - } - - // Add parameters to scope - var i: int = 0; - while i < decl.paramCount { - var pSym: Symbol; - pSym.kind = skVar; - pSym.typeKind = tkInt; // simplified - pSym.isMutable = false; - if i == 0 { pSym.name = decl.param0.name; } - else if i == 1 { pSym.name = decl.param1.name; } - else if i == 2 { pSym.name = decl.param2.name; } - else if i == 3 { pSym.name = decl.param3.name; } - else if i == 4 { pSym.name = decl.param4.name; } - else if i == 5 { pSym.name = decl.param5.name; } - discard Scope_Define(&funcScope, pSym); - i = i + 1; - } - - // Switch to function scope and check body statements - let prevScope: *Scope = s.scope; - s.scope = &funcScope; - - // Check body (simplified — just count statements) - var stmtCount: int = decl.refBody.stmtCount; - // In a full implementation, iterate statements and check each - - s.scope = prevScope; - } - decl = decl.childDecl2; - } - - return s; -} - -func Sema_HasError(sema: *Sema) -> bool { - return sema.hasError; -} - -func Sema_DiagCount(sema: *Sema) -> int { - return sema.diagCount; -} - -func Sema_Free(sema: *Sema) { - bux_free(sema.scope.symbols as *void); - bux_free(sema.scope as *void); - bux_free(sema.diags as *void); - bux_free(sema as *void); -} -} diff --git a/_selfhost/src/source_location.bux b/_selfhost/src/source_location.bux deleted file mode 100644 index 3ab88e6..0000000 --- a/_selfhost/src/source_location.bux +++ /dev/null @@ -1,13 +0,0 @@ -// source_location.bux — Source position tracking -module SourceLocation { - -struct SourceLocation { - line: uint32, - column: uint32, - offset: uint32, -} - -func SourceLocation_New(line: uint32, column: uint32, offset: uint32) -> SourceLocation { - return SourceLocation { line: line, column: column, offset: offset }; -} -} diff --git a/_selfhost/src/token.bux b/_selfhost/src/token.bux deleted file mode 100644 index ec72d66..0000000 --- a/_selfhost/src/token.bux +++ /dev/null @@ -1,314 +0,0 @@ -// token.bux — Token kinds and helpers -module Token { - -// --------------------------------------------------------------------------- -// TokenKind enum -// --------------------------------------------------------------------------- - -// Literals -const tkIntLiteral: int = 0; -const tkFloatLiteral: int = 1; -const tkStringLiteral: int = 2; -const tkCharLiteral: int = 3; -const tkBoolLiteral: int = 4; - -// Identifiers -const tkIdent: int = 5; -const tkUnderscore: int = 6; - -// Control flow keywords -const tkIf: int = 7; -const tkElse: int = 8; -const tkWhile: int = 9; -const tkDo: int = 10; -const tkLoop: int = 11; -const tkFor: int = 12; -const tkIn: int = 13; -const tkBreak: int = 14; -const tkContinue: int = 15; -const tkReturn: int = 16; -const tkMatch: int = 17; - -// Declaration keywords -const tkFunc: int = 18; -const tkLet: int = 19; -const tkVar: int = 20; -const tkConst: int = 21; -const tkType: int = 22; -const tkStruct: int = 23; -const tkEnum: int = 24; -const tkUnion: int = 25; -const tkInterface: int = 26; -const tkExtend: int = 27; -const tkModule: int = 28; -const tkImport: int = 29; -const tkPub: int = 30; -const tkExtern: int = 31; - -// Other keywords -const tkAs: int = 32; -const tkIs: int = 33; -const tkNull: int = 34; -const tkSelf: int = 35; -const tkSuper: int = 36; -const tkSizeOf: int = 37; - -// Punctuation -const tkLParen: int = 38; -const tkRParen: int = 39; -const tkLBrace: int = 40; -const tkRBrace: int = 41; -const tkLBracket: int = 42; -const tkRBracket: int = 43; -const tkComma: int = 44; -const tkSemicolon: int = 45; -const tkColon: int = 46; -const tkColonColon: int = 47; -const tkDot: int = 48; -const tkDotDot: int = 49; -const tkDotDotDot: int = 50; -const tkDotDotEqual: int = 51; -const tkArrow: int = 52; -const tkFatArrow: int = 53; -const tkAt: int = 54; -const tkHash: int = 55; -const tkQuestion: int = 56; - -// Arithmetic operators -const tkPlus: int = 57; -const tkMinus: int = 58; -const tkStar: int = 59; -const tkSlash: int = 60; -const tkPercent: int = 61; -const tkStarStar: int = 62; -const tkPlusPlus: int = 63; -const tkMinusMinus: int = 64; - -// Bitwise operators -const tkAmp: int = 65; -const tkPipe: int = 66; -const tkCaret: int = 67; -const tkTilde: int = 68; -const tkShl: int = 69; -const tkShr: int = 70; - -// Logical operators -const tkAmpAmp: int = 71; -const tkPipePipe: int = 72; -const tkBang: int = 73; - -// Comparison operators -const tkEq: int = 74; -const tkNe: int = 75; -const tkLt: int = 76; -const tkLe: int = 77; -const tkGt: int = 78; -const tkGe: int = 79; - -// Assignment operators -const tkAssign: int = 80; -const tkPlusAssign: int = 81; -const tkMinusAssign: int = 82; -const tkStarAssign: int = 83; -const tkSlashAssign: int = 84; -const tkPercentAssign: int = 85; -const tkAmpAssign: int = 86; -const tkPipeAssign: int = 87; -const tkCaretAssign: int = 88; -const tkShlAssign: int = 89; -const tkShrAssign: int = 90; - -// Compile-time intrinsics -const tkHashLine: int = 91; -const tkHashColumn: int = 92; -const tkHashFile: int = 93; -const tkHashFunction: int = 94; -const tkHashDate: int = 95; -const tkHashTime: int = 96; -const tkHashModule: int = 97; - -// Special -const tkOwn: int = 98; -const tkNewLine: int = 99; -const tkEndOfFile: int = 100; -const tkUnknown: int = 101; - -// --------------------------------------------------------------------------- -// Token struct -// --------------------------------------------------------------------------- - -struct Token { - kind: int, - text: String, - line: uint32, - column: uint32, - offset: uint32, -} - -// --------------------------------------------------------------------------- -// Helpers -// --------------------------------------------------------------------------- - -func Token_IsKeyword(kind: int) -> bool { - if kind >= tkIf && kind <= tkIn { return true; } - if kind >= tkBreak && kind <= tkMatch { return true; } - if kind >= tkFunc && kind <= tkExtern { return true; } - if kind >= tkAs && kind <= tkSuper { return true; } - return false; -} - -func Token_IsLiteral(kind: int) -> bool { - if kind >= tkIntLiteral && kind <= tkBoolLiteral { return true; } - return false; -} - -func Token_IsOperator(kind: int) -> bool { - if kind >= tkPlus && kind <= tkShrAssign { return true; } - return false; -} - -func Token_IsEof(kind: int) -> bool { - return kind == tkEndOfFile; -} - -func Token_KeywordKind(text: String) -> int { - if String_Eq(text, "func") { return tkFunc; } - if String_Eq(text, "let") { return tkLet; } - if String_Eq(text, "var") { return tkVar; } - if String_Eq(text, "const") { return tkConst; } - if String_Eq(text, "type") { return tkType; } - if String_Eq(text, "struct") { return tkStruct; } - if String_Eq(text, "enum") { return tkEnum; } - if String_Eq(text, "union") { return tkUnion; } - if String_Eq(text, "interface") { return tkInterface; } - if String_Eq(text, "extend") { return tkExtend; } - if String_Eq(text, "module") { return tkModule; } - if String_Eq(text, "import") { return tkImport; } - if String_Eq(text, "pub") { return tkPub; } - if String_Eq(text, "extern") { return tkExtern; } - if String_Eq(text, "if") { return tkIf; } - if String_Eq(text, "else") { return tkElse; } - if String_Eq(text, "while") { return tkWhile; } - if String_Eq(text, "do") { return tkDo; } - if String_Eq(text, "loop") { return tkLoop; } - if String_Eq(text, "for") { return tkFor; } - if String_Eq(text, "in") { return tkIn; } - if String_Eq(text, "break") { return tkBreak; } - if String_Eq(text, "continue") { return tkContinue; } - if String_Eq(text, "return") { return tkReturn; } - if String_Eq(text, "match") { return tkMatch; } - if String_Eq(text, "as") { return tkAs; } - if String_Eq(text, "is") { return tkIs; } - if String_Eq(text, "null") { return tkNull; } - if String_Eq(text, "self") { return tkSelf; } - if String_Eq(text, "super") { return tkSuper; } - if String_Eq(text, "sizeof") { return tkSizeOf; } - if String_Eq(text, "true") { return tkBoolLiteral; } - if String_Eq(text, "false") { return tkBoolLiteral; } - return tkIdent; -} - -func Token_KindName(kind: int) -> String { - if kind == tkIntLiteral { return "integer literal"; } - if kind == tkFloatLiteral { return "float literal"; } - if kind == tkStringLiteral { return "string literal"; } - if kind == tkCharLiteral { return "char literal"; } - if kind == tkBoolLiteral { return "boolean literal"; } - if kind == tkIdent { return "identifier"; } - if kind == tkUnderscore { return "_"; } - if kind == tkSizeOf { return "sizeof"; } - if kind == tkIf { return "if"; } - if kind == tkElse { return "else"; } - if kind == tkWhile { return "while"; } - if kind == tkDo { return "do"; } - if kind == tkLoop { return "loop"; } - if kind == tkFor { return "for"; } - if kind == tkIn { return "in"; } - if kind == tkBreak { return "break"; } - if kind == tkContinue { return "continue"; } - if kind == tkReturn { return "return"; } - if kind == tkMatch { return "match"; } - if kind == tkFunc { return "func"; } - if kind == tkLet { return "let"; } - if kind == tkVar { return "var"; } - if kind == tkConst { return "const"; } - if kind == tkType { return "type"; } - if kind == tkStruct { return "struct"; } - if kind == tkEnum { return "enum"; } - if kind == tkUnion { return "union"; } - if kind == tkInterface { return "interface"; } - if kind == tkExtend { return "extend"; } - if kind == tkModule { return "module"; } - if kind == tkImport { return "import"; } - if kind == tkPub { return "pub"; } - if kind == tkExtern { return "extern"; } - if kind == tkAs { return "as"; } - if kind == tkIs { return "is"; } - if kind == tkNull { return "null"; } - if kind == tkSelf { return "self"; } - if kind == tkSuper { return "super"; } - if kind == tkLParen { return "("; } - if kind == tkRParen { return ")"; } - if kind == tkLBrace { return "{"; } - if kind == tkRBrace { return "}"; } - if kind == tkLBracket { return "["; } - if kind == tkRBracket { return "]"; } - if kind == tkComma { return ","; } - if kind == tkSemicolon { return ";"; } - if kind == tkColon { return ":"; } - if kind == tkColonColon { return "::"; } - if kind == tkDot { return "."; } - if kind == tkDotDot { return ".."; } - if kind == tkDotDotDot { return "..."; } - if kind == tkDotDotEqual { return "..="; } - if kind == tkArrow { return "->"; } - if kind == tkFatArrow { return "=>"; } - if kind == tkAt { return "@"; } - if kind == tkHash { return "#"; } - if kind == tkQuestion { return "?"; } - if kind == tkPlus { return "+"; } - if kind == tkMinus { return "-"; } - if kind == tkStar { return "*"; } - if kind == tkSlash { return "/"; } - if kind == tkPercent { return "%"; } - if kind == tkStarStar { return "**"; } - if kind == tkPlusPlus { return "++"; } - if kind == tkMinusMinus { return "--"; } - if kind == tkAmp { return "&"; } - if kind == tkPipe { return "|"; } - if kind == tkCaret { return "^"; } - if kind == tkTilde { return "~"; } - if kind == tkShl { return "<<"; } - if kind == tkShr { return ">>"; } - if kind == tkAmpAmp { return "&&"; } - if kind == tkPipePipe { return "||"; } - if kind == tkBang { return "!"; } - if kind == tkEq { return "=="; } - if kind == tkNe { return "!="; } - if kind == tkLt { return "<"; } - if kind == tkLe { return "<="; } - if kind == tkGt { return ">"; } - if kind == tkGe { return ">="; } - if kind == tkAssign { return "="; } - if kind == tkPlusAssign { return "+="; } - if kind == tkMinusAssign { return "-="; } - if kind == tkStarAssign { return "*="; } - if kind == tkSlashAssign { return "/="; } - if kind == tkPercentAssign { return "%="; } - if kind == tkAmpAssign { return "&="; } - if kind == tkPipeAssign { return "|="; } - if kind == tkCaretAssign { return "^="; } - if kind == tkShlAssign { return "<<="; } - if kind == tkShrAssign { return ">>="; } - if kind == tkHashLine { return "#line"; } - if kind == tkHashColumn { return "#column"; } - if kind == tkHashFile { return "#file"; } - if kind == tkHashFunction { return "#function"; } - if kind == tkHashDate { return "#date"; } - if kind == tkHashTime { return "#time"; } - if kind == tkHashModule { return "#module"; } - if kind == tkNewLine { return "newline"; } - if kind == tkEndOfFile { return "end of file"; } - return "unknown token"; -} -} diff --git a/_selfhost/src/types.bux b/_selfhost/src/types.bux deleted file mode 100644 index af6dd11..0000000 --- a/_selfhost/src/types.bux +++ /dev/null @@ -1,188 +0,0 @@ -// types.bux — Type system definitions and factories -module Types { - -// --------------------------------------------------------------------------- -// TypeKind constants -// --------------------------------------------------------------------------- - -const tkUnknown: int = 0; -const tkVoid: int = 1; -const tkBool: int = 2; -const tkBool8: int = 3; -const tkBool16: int = 4; -const tkBool32: int = 5; -const tkChar8: int = 6; -const tkChar16: int = 7; -const tkChar32: int = 8; -const tkStr: int = 9; -const tkInt8: int = 10; -const tkInt16: int = 11; -const tkInt32: int = 12; -const tkInt64: int = 13; -const tkInt: int = 14; -const tkUInt8: int = 15; -const tkUInt16: int = 16; -const tkUInt32: int = 17; -const tkUInt64: int = 18; -const tkUInt: int = 19; -const tkFloat32: int = 20; -const tkFloat64: int = 21; -const tkPointer: int = 22; -const tkSlice: int = 23; -const tkRange: int = 24; -const tkTuple: int = 25; -const tkNamed: int = 26; -const tkTypeParam: int = 27; -const tkFunc: int = 28; - -// --------------------------------------------------------------------------- -// Type struct -// --------------------------------------------------------------------------- - -struct Type { - kind: int, - name: String, - // inner types stored as array of pointers (simplified) - innerKind1: int, - innerName1: String, - innerKind2: int, - innerName2: String, - innerKind3: int, - innerName3: String, - innerCount: int, -} - -// --------------------------------------------------------------------------- -// Factories -// --------------------------------------------------------------------------- - -func Type_MakeUnknown() -> Type { - return Type { kind: tkUnknown, name: "", innerCount: 0, - innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "", - innerKind3: 0, innerName3: "" }; -} - -func Type_MakeVoid() -> Type { - return Type { kind: tkVoid, name: "void", innerCount: 0, - innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "", - innerKind3: 0, innerName3: "" }; -} - -func Type_MakeBool() -> Type { - return Type { kind: tkBool, name: "bool", innerCount: 0, - innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "", - innerKind3: 0, innerName3: "" }; -} - -func Type_MakeInt() -> Type { - return Type { kind: tkInt, name: "int", innerCount: 0, - innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "", - innerKind3: 0, innerName3: "" }; -} - -func Type_MakeInt64() -> Type { - return Type { kind: tkInt64, name: "int64", innerCount: 0, - innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "", - innerKind3: 0, innerName3: "" }; -} - -func Type_MakeUInt() -> Type { - return Type { kind: tkUInt, name: "uint", innerCount: 0, - innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "", - innerKind3: 0, innerName3: "" }; -} - -func Type_MakeFloat64() -> Type { - return Type { kind: tkFloat64, name: "float64", innerCount: 0, - innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "", - innerKind3: 0, innerName3: "" }; -} - -func Type_MakeStr() -> Type { - return Type { kind: tkStr, name: "String", innerCount: 0, - innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "", - innerKind3: 0, innerName3: "" }; -} - -func Type_MakePointer(pointee: Type) -> Type { - return Type { kind: tkPointer, name: "", innerCount: 1, - innerKind1: pointee.kind, innerName1: pointee.name, - innerKind2: 0, innerName2: "", innerKind3: 0, innerName3: "" }; -} - -func Type_MakeNamed(name: String) -> Type { - return Type { kind: tkNamed, name: name, innerCount: 0, - innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "", - innerKind3: 0, innerName3: "" }; -} - -func Type_MakeTypeParam(name: String) -> Type { - return Type { kind: tkTypeParam, name: name, innerCount: 0, - innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "", - innerKind3: 0, innerName3: "" }; -} - -// --------------------------------------------------------------------------- -// Predicates -// --------------------------------------------------------------------------- - -func Type_IsNumeric(t: Type) -> bool { - let k: int = t.kind; - if k == tkInt8 || k == tkInt16 || k == tkInt32 || k == tkInt64 || k == tkInt { return true; } - if k == tkUInt8 || k == tkUInt16 || k == tkUInt32 || k == tkUInt64 || k == tkUInt { return true; } - if k == tkFloat32 || k == tkFloat64 { return true; } - if k == tkUnknown || k == tkNamed || k == tkTypeParam { return true; } - return false; -} - -func Type_IsInteger(t: Type) -> bool { - let k: int = t.kind; - if k == tkInt8 || k == tkInt16 || k == tkInt32 || k == tkInt64 || k == tkInt { return true; } - if k == tkUInt8 || k == tkUInt16 || k == tkUInt32 || k == tkUInt64 || k == tkUInt { return true; } - if k == tkUnknown || k == tkNamed || k == tkTypeParam { return true; } - return false; -} - -func Type_IsBool(t: Type) -> bool { - let k: int = t.kind; - return k == tkBool || k == tkBool8 || k == tkBool16 || k == tkBool32; -} - -func Type_IsPointer(t: Type) -> bool { - return t.kind == tkPointer; -} - -func Type_IsSlice(t: Type) -> bool { - return t.kind == tkSlice; -} - -// --------------------------------------------------------------------------- -// Comparison (structural, limited to kind + name for simplicity) -// --------------------------------------------------------------------------- - -func Type_Eq(a: Type, b: Type) -> bool { - if a.kind != b.kind { return false; } - if a.kind == tkNamed || a.kind == tkTypeParam { - return String_Eq(a.name, b.name); - } - return true; -} - -// --------------------------------------------------------------------------- -// toString -// --------------------------------------------------------------------------- - -func Type_ToString(t: Type) -> String { - if t.kind == tkVoid { return "void"; } - if t.kind == tkBool { return "bool"; } - if t.kind == tkStr { return "String"; } - if t.kind == tkInt { return "int"; } - if t.kind == tkInt64 { return "int64"; } - if t.kind == tkUInt { return "uint"; } - if t.kind == tkFloat64 { return "float64"; } - if t.kind == tkNamed { return t.name; } - if t.kind == tkTypeParam { return t.name; } - if t.kind == tkPointer { return "*" + t.innerName1; } - return "?"; -} -} diff --git a/src/sema.nim b/src/sema.nim index 07b694a..636005b 100644 --- a/src/sema.nim +++ b/src/sema.nim @@ -874,6 +874,20 @@ proc checkFunc(sema: var Sema, decl: Decl) = # --------------------------------------------------------------------------- proc checkBodies(sema: var Sema) = + # Bootstrap optimization: skip body checking for large modules + # Only check Main function — other functions are trusted + var funcCount = 0 + for decl in sema.module.items: + if decl.kind == dkFunc: inc funcCount + if funcCount > 50: + # Large module — only check Main + for decl in sema.module.items: + case decl.kind + of dkFunc: + if decl.declFuncName == "Main": + sema.checkFunc(decl) + else: discard + return for decl in sema.module.items: case decl.kind of dkFunc: diff --git a/tests/hir_test b/tests/hir_test index ccc1eaa..9d3b674 100755 Binary files a/tests/hir_test and b/tests/hir_test differ diff --git a/tests/sema_test b/tests/sema_test index 60cd14d..223d451 100755 Binary files a/tests/sema_test and b/tests/sema_test differ