feat: lifetime elision, tooling CI, registry, and LSP locals
Ship the QUALITY_PLAN stretch from ownership through ecosystem: C.1 lifetime elision (bootstrap + selfhost), bux fmt/test/doc CI hooks, stdlib goldens, package registry (bux search/add), and LSP 0.4 position-sensitive locals with inferred let types. Full-tree format pass plus Map/Set remove double-free fix.
This commit is contained in:
+16
-16
@@ -1,23 +1,23 @@
|
||||
// main.bux — Entry point for the Bux self-hosting compiler
|
||||
module Main {
|
||||
|
||||
// C runtime for command-line args
|
||||
extern func bux_argc() -> int;
|
||||
extern func bux_argv(index: int) -> String;
|
||||
extern func bux_alloc(size: uint) -> *void;
|
||||
// C runtime for command-line args
|
||||
extern func bux_argc() -> int;
|
||||
extern func bux_argv(index: int) -> String;
|
||||
extern func bux_alloc(size: uint) -> *void;
|
||||
|
||||
// Forward declaration from Cli module
|
||||
func Cli_Run(args: *String, argCount: int) -> int;
|
||||
// Forward declaration from Cli module
|
||||
func Cli_Run(args: *String, argCount: int) -> int;
|
||||
|
||||
func Main() -> int {
|
||||
let count: int = bux_argc();
|
||||
// Allocate array of String pointers
|
||||
let args: *String = bux_alloc(count as uint * 8) as *String;
|
||||
var i: int = 0;
|
||||
while i < count {
|
||||
args[i] = bux_argv(i);
|
||||
i = i + 1;
|
||||
func Main() -> int {
|
||||
let count: int = bux_argc();
|
||||
// Allocate array of String pointers
|
||||
let args: *String = bux_alloc(count as uint * 8) as *String;
|
||||
var i: int = 0;
|
||||
while i < count {
|
||||
args[i] = bux_argv(i);
|
||||
i = i + 1;
|
||||
}
|
||||
return Cli_Run(args, count);
|
||||
}
|
||||
return Cli_Run(args, count);
|
||||
}
|
||||
}
|
||||
|
||||
+434
-433
@@ -1,437 +1,438 @@
|
||||
// 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 tekRef: int = 7; // &T — shared reference
|
||||
const tekMutRef: int = 8; // &mut T — mutable reference
|
||||
const tekTuple: int = 4;
|
||||
const tekSelf: int = 5;
|
||||
const tekFunc: int = 6;
|
||||
|
||||
struct TypeExprList {
|
||||
te: *TypeExpr,
|
||||
next: *TypeExprList,
|
||||
}
|
||||
|
||||
struct TypeExpr {
|
||||
kind: int,
|
||||
line: uint32,
|
||||
column: uint32,
|
||||
typeName: String, // for tekNamed / diagnostic name for tekFunc
|
||||
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
|
||||
funcParams: *TypeExprList, // for tekFunc
|
||||
funcRet: *TypeExpr, // for tekFunc
|
||||
funcParamCount: int, // for tekFunc
|
||||
tupleElems: *TypeExprList, // for tekTuple
|
||||
tupleCount: int, // for tekTuple
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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;
|
||||
const pkGuarded: int = 7; // `p if cond` — patChild1 = inner, patGuardExpr = condition
|
||||
|
||||
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: "Enum::Variant"
|
||||
patStructName: String, // for pkStruct (type name)
|
||||
patFieldName: String, // for struct field entry: field name in Point { x: a }
|
||||
patChild1: *Pattern, // range lo / nested / guarded inner
|
||||
patChild2: *Pattern, // range hi / nested
|
||||
patArgs: *Pattern, // pkEnum/pkTuple/pkStruct field list (head)
|
||||
patNext: *Pattern, // next sibling in patArgs list
|
||||
patGuardExpr: *Expr, // for pkGuarded: the `if` condition
|
||||
}
|
||||
|
||||
// Match arm: pattern => body
|
||||
struct MatchArm {
|
||||
line: uint32,
|
||||
column: uint32,
|
||||
pattern: *Pattern,
|
||||
body: *Expr,
|
||||
next: *MatchArm,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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 ekUnwrap: int = 23;
|
||||
const ekBlock: int = 21;
|
||||
const ekMatch: int = 22;
|
||||
const ekSpawn: int = 24;
|
||||
const ekAwait: int = 25;
|
||||
const ekStringInterp: int = 26;
|
||||
const ekClosure: int = 27;
|
||||
|
||||
struct ExprList {
|
||||
expr: *Expr,
|
||||
next: *ExprList,
|
||||
argName: String,
|
||||
}
|
||||
|
||||
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,
|
||||
// Closure params (for ekClosure)
|
||||
closureParams: *Decl,
|
||||
// Captures (for ekClosure)
|
||||
captureCount: int,
|
||||
captureName0: String,
|
||||
captureName1: String,
|
||||
captureName2: String,
|
||||
captureName3: String,
|
||||
captureName4: String,
|
||||
captureName5: String,
|
||||
captureName6: String,
|
||||
captureName7: String,
|
||||
captureType0: int,
|
||||
captureType1: int,
|
||||
captureType2: int,
|
||||
captureType3: int,
|
||||
captureType4: int,
|
||||
captureType5: int,
|
||||
captureType6: int,
|
||||
captureType7: int,
|
||||
// Call arguments (linked list for multi-arg support)
|
||||
callArgs: *ExprList,
|
||||
callArgCount: int,
|
||||
// Match arms (for ekMatch)
|
||||
matchArms: *MatchArm,
|
||||
matchArmCount: int,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Block — sequence of statements
|
||||
// ---------------------------------------------------------------------------
|
||||
struct Block {
|
||||
line: uint32,
|
||||
column: uint32,
|
||||
stmtCount: int,
|
||||
firstStmt: *Stmt,
|
||||
lastStmt: *Stmt,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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;
|
||||
const skDefer: int = 12;
|
||||
const skSwitch: int = 13;
|
||||
|
||||
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,
|
||||
// Linked list
|
||||
nextStmt: *Stmt,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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;
|
||||
defaultExpr: *Expr;
|
||||
}
|
||||
|
||||
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 {
|
||||
fieldCount: int,
|
||||
fields: *StructField,
|
||||
kind: int,
|
||||
line: uint32,
|
||||
column: uint32,
|
||||
isPublic: bool,
|
||||
isAsync: bool,
|
||||
isChecked: int, // @[Checked] attribute (0/1)
|
||||
isDrop: int, // @[Drop] attribute (0/1)
|
||||
isRelease: int, // @[Release] attribute (0/1)
|
||||
isConst: int, // const func (0/1)
|
||||
// Names
|
||||
strValue: String, // decl name
|
||||
strValue2: String, // interface name, dll name, module path
|
||||
// Type params (up to 2)
|
||||
typeParam0: String,
|
||||
typeParam1: String,
|
||||
typeParamCount: int,
|
||||
// Trait bounds for type params (e.g. <T: Comparable>)
|
||||
typeParam0Bound: String,
|
||||
typeParam1Bound: String,
|
||||
// Params (for functions)
|
||||
paramCount: int,
|
||||
param0: Param,
|
||||
param1: Param,
|
||||
param2: Param,
|
||||
param3: Param,
|
||||
param4: Param,
|
||||
param5: Param,
|
||||
param6: Param,
|
||||
param7: Param,
|
||||
param8: Param,
|
||||
retType: *TypeExpr,
|
||||
// Body
|
||||
refBody: *Block,
|
||||
// Enum variants (up to 8)
|
||||
variantCount: int,
|
||||
variant0: EnumVariant,
|
||||
variant1: EnumVariant,
|
||||
variant2: EnumVariant,
|
||||
variant3: EnumVariant,
|
||||
variant4: EnumVariant,
|
||||
variant5: EnumVariant,
|
||||
variant6: EnumVariant,
|
||||
variant7: EnumVariant,
|
||||
variant8: 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,
|
||||
// Struct fields (up to 256)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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,
|
||||
callArgs: null as *ExprList, callArgCount: 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,
|
||||
isAsync: false, isChecked: 0, isDrop: 0, isRelease: 0, isConst: 0,
|
||||
strValue: "", strValue2: "",
|
||||
typeParam0: "", typeParam1: "", typeParamCount: 0,
|
||||
typeParam0Bound: "", typeParam1Bound: ""
|
||||
,
|
||||
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 };
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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 tekRef: int = 7; // &T — shared reference
|
||||
const tekMutRef: int = 8; // &mut T — mutable reference
|
||||
const tekTuple: int = 4;
|
||||
const tekSelf: int = 5;
|
||||
const tekFunc: int = 6;
|
||||
|
||||
struct TypeExprList {
|
||||
te: *TypeExpr,
|
||||
next: *TypeExprList,
|
||||
}
|
||||
|
||||
struct TypeExpr {
|
||||
kind: int,
|
||||
line: uint32,
|
||||
column: uint32,
|
||||
typeName: String, // for tekNamed / diagnostic name for tekFunc
|
||||
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 / tekRef / tekMutRef
|
||||
refLifetime: String, // for tekRef / tekMutRef: "'a" or "" (elided)
|
||||
funcParams: *TypeExprList, // for tekFunc
|
||||
funcRet: *TypeExpr, // for tekFunc
|
||||
funcParamCount: int, // for tekFunc
|
||||
tupleElems: *TypeExprList, // for tekTuple
|
||||
tupleCount: int, // for tekTuple
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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;
|
||||
const pkGuarded: int = 7; // `p if cond` — patChild1 = inner, patGuardExpr = condition
|
||||
|
||||
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: "Enum::Variant"
|
||||
patStructName: String, // for pkStruct (type name)
|
||||
patFieldName: String, // for struct field entry: field name in Point { x: a }
|
||||
patChild1: *Pattern, // range lo / nested / guarded inner
|
||||
patChild2: *Pattern, // range hi / nested
|
||||
patArgs: *Pattern, // pkEnum/pkTuple/pkStruct field list (head)
|
||||
patNext: *Pattern, // next sibling in patArgs list
|
||||
patGuardExpr: *Expr, // for pkGuarded: the `if` condition
|
||||
}
|
||||
|
||||
// Match arm: pattern => body
|
||||
struct MatchArm {
|
||||
line: uint32,
|
||||
column: uint32,
|
||||
pattern: *Pattern,
|
||||
body: *Expr,
|
||||
next: *MatchArm,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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 ekUnwrap: int = 23;
|
||||
const ekBlock: int = 21;
|
||||
const ekMatch: int = 22;
|
||||
const ekSpawn: int = 24;
|
||||
const ekAwait: int = 25;
|
||||
const ekStringInterp: int = 26;
|
||||
const ekClosure: int = 27;
|
||||
|
||||
struct ExprList {
|
||||
expr: *Expr,
|
||||
next: *ExprList,
|
||||
argName: String,
|
||||
}
|
||||
|
||||
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,
|
||||
// Closure params (for ekClosure)
|
||||
closureParams: *Decl,
|
||||
// Captures (for ekClosure)
|
||||
captureCount: int,
|
||||
captureName0: String,
|
||||
captureName1: String,
|
||||
captureName2: String,
|
||||
captureName3: String,
|
||||
captureName4: String,
|
||||
captureName5: String,
|
||||
captureName6: String,
|
||||
captureName7: String,
|
||||
captureType0: int,
|
||||
captureType1: int,
|
||||
captureType2: int,
|
||||
captureType3: int,
|
||||
captureType4: int,
|
||||
captureType5: int,
|
||||
captureType6: int,
|
||||
captureType7: int,
|
||||
// Call arguments (linked list for multi-arg support)
|
||||
callArgs: *ExprList,
|
||||
callArgCount: int,
|
||||
// Match arms (for ekMatch)
|
||||
matchArms: *MatchArm,
|
||||
matchArmCount: int,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Block — sequence of statements
|
||||
// ---------------------------------------------------------------------------
|
||||
struct Block {
|
||||
line: uint32,
|
||||
column: uint32,
|
||||
stmtCount: int,
|
||||
firstStmt: *Stmt,
|
||||
lastStmt: *Stmt,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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;
|
||||
const skDefer: int = 12;
|
||||
const skSwitch: int = 13;
|
||||
|
||||
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,
|
||||
// Linked list
|
||||
nextStmt: *Stmt,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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;
|
||||
defaultExpr: *Expr;
|
||||
}
|
||||
|
||||
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 {
|
||||
fieldCount: int,
|
||||
fields: *StructField,
|
||||
kind: int,
|
||||
line: uint32,
|
||||
column: uint32,
|
||||
isPublic: bool,
|
||||
isAsync: bool,
|
||||
isChecked: int, // @[Checked] attribute (0/1)
|
||||
isDrop: int, // @[Drop] attribute (0/1)
|
||||
isRelease: int, // @[Release] attribute (0/1)
|
||||
isConst: int, // const func (0/1)
|
||||
// Names
|
||||
strValue: String, // decl name
|
||||
strValue2: String, // interface name, dll name, module path
|
||||
// Type params (up to 2)
|
||||
typeParam0: String,
|
||||
typeParam1: String,
|
||||
typeParamCount: int,
|
||||
// Trait bounds for type params (e.g. <T: Comparable>)
|
||||
typeParam0Bound: String,
|
||||
typeParam1Bound: String,
|
||||
// Params (for functions)
|
||||
paramCount: int,
|
||||
param0: Param,
|
||||
param1: Param,
|
||||
param2: Param,
|
||||
param3: Param,
|
||||
param4: Param,
|
||||
param5: Param,
|
||||
param6: Param,
|
||||
param7: Param,
|
||||
param8: Param,
|
||||
retType: *TypeExpr,
|
||||
// Body
|
||||
refBody: *Block,
|
||||
// Enum variants (up to 8)
|
||||
variantCount: int,
|
||||
variant0: EnumVariant,
|
||||
variant1: EnumVariant,
|
||||
variant2: EnumVariant,
|
||||
variant3: EnumVariant,
|
||||
variant4: EnumVariant,
|
||||
variant5: EnumVariant,
|
||||
variant6: EnumVariant,
|
||||
variant7: EnumVariant,
|
||||
variant8: 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,
|
||||
// Struct fields (up to 256)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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,
|
||||
callArgs: null as *ExprList, callArgCount: 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,
|
||||
isAsync: false, isChecked: 0, isDrop: 0, isRelease: 0, isConst: 0,
|
||||
strValue: "", strValue2: "",
|
||||
typeParam0: "", typeParam1: "", typeParamCount: 0,
|
||||
typeParam0Bound: "", typeParam1Bound: ""
|
||||
,
|
||||
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 };
|
||||
}
|
||||
}
|
||||
|
||||
+1534
-1534
File diff suppressed because it is too large
Load Diff
+463
-186
@@ -2,144 +2,144 @@
|
||||
// Wires together: Lexer → Parser → Sema → HirLower → CBackend
|
||||
module Cli {
|
||||
|
||||
extern func PrintLine(s: String);
|
||||
extern func Print(s: String);
|
||||
extern func bux_read_file(path: String) -> String;
|
||||
extern func bux_write_file(path: String, content: String) -> bool;
|
||||
extern func bux_file_exists(path: String) -> int;
|
||||
extern func bux_dir_exists(path: String) -> int;
|
||||
extern func bux_getcwd() -> String;
|
||||
extern func bux_path_join(a: String, b: String) -> String;
|
||||
extern func bux_path_parent(path: String) -> String;
|
||||
extern func bux_mkdir_if_needed(path: String) -> int;
|
||||
extern func bux_run_nim(nim_file: String, out_bin: String) -> int;
|
||||
extern func bux_list_dir(dir: String, ext: String, out_count: *int) -> *String;
|
||||
extern func bux_system(cmd: String) -> int;
|
||||
extern func bux_getenv(name: String) -> String;
|
||||
extern func bux_setenv(name: String, value: String) -> int;
|
||||
extern func bux_strlen(s: String) -> uint;
|
||||
extern func bux_str_slice(s: String, start: uint, len: uint) -> String;
|
||||
extern func PrintLine(s: String);
|
||||
extern func Print(s: String);
|
||||
extern func bux_read_file(path: String) -> String;
|
||||
extern func bux_write_file(path: String, content: String) -> bool;
|
||||
extern func bux_file_exists(path: String) -> int;
|
||||
extern func bux_dir_exists(path: String) -> int;
|
||||
extern func bux_getcwd() -> String;
|
||||
extern func bux_path_join(a: String, b: String) -> String;
|
||||
extern func bux_path_parent(path: String) -> String;
|
||||
extern func bux_mkdir_if_needed(path: String) -> int;
|
||||
extern func bux_run_nim(nim_file: String, out_bin: String) -> int;
|
||||
extern func bux_list_dir(dir: String, ext: String, out_count: *int) -> *String;
|
||||
extern func bux_system(cmd: String) -> int;
|
||||
extern func bux_getenv(name: String) -> String;
|
||||
extern func bux_setenv(name: String, value: String) -> int;
|
||||
extern func bux_strlen(s: String) -> uint;
|
||||
extern func bux_str_slice(s: String, start: uint, len: uint) -> String;
|
||||
|
||||
func ReadFile(path: String) -> String {
|
||||
return bux_read_file(path);
|
||||
}
|
||||
|
||||
func WriteFile(path: String, content: String) -> bool {
|
||||
return bux_write_file(path, content);
|
||||
}
|
||||
|
||||
func FileExists(path: String) -> bool {
|
||||
return bux_file_exists(path) != 0;
|
||||
}
|
||||
|
||||
func DirExists(path: String) -> bool {
|
||||
return bux_dir_exists(path) != 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Diagnostic formatting (Rust-style errors with snippets)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct Diagnostic {
|
||||
message: String;
|
||||
line: uint32;
|
||||
column: uint32;
|
||||
severity: int;
|
||||
}
|
||||
|
||||
/* Read a single line from a file (1-based). Returns "" on error or EOF. */
|
||||
func Diagnostic_GetLine(path: String, lineNum: uint32) -> String {
|
||||
let content: String = bux_read_file(path);
|
||||
if String_Eq(content, "") { return ""; }
|
||||
/* bux_str_split_part uses 0-based index */
|
||||
return bux_str_split_part(content, "\n", lineNum - 1);
|
||||
}
|
||||
|
||||
/* Simple substring check for help hints */
|
||||
func Diagnostic_MsgContains(msg: String, needle: String) -> bool {
|
||||
return bux_str_contains(msg, needle) != 0;
|
||||
}
|
||||
|
||||
/* Actionable help for common error messages */
|
||||
func Diagnostic_Hint(msg: String) -> String {
|
||||
if Diagnostic_MsgContains(msg, "cannot assign") {
|
||||
return "ensure the right-hand side type matches the left-hand side";
|
||||
func ReadFile(path: String) -> String {
|
||||
return bux_read_file(path);
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "undeclared identifier") {
|
||||
return "check the spelling, or import the symbol from the right module";
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "too few arguments") {
|
||||
return "compare the call with the function's parameter list";
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "too many arguments") {
|
||||
return "compare the call with the function's parameter list";
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "use of moved value") {
|
||||
return "the value was moved; clone it or restructure ownership";
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "expected expression") {
|
||||
return "the previous statement may be incomplete (missing value or ';')";
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "duplicate symbol") {
|
||||
return "rename one of the definitions or remove the duplicate";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Print a diagnostic in Rust-style format:
|
||||
* error: <message>
|
||||
* --> <path>:<line>:<col>
|
||||
* |
|
||||
* 42 | <source_line>
|
||||
* | <spaces>^
|
||||
* = help: <hint>
|
||||
*/
|
||||
func Diagnostic_Print(diag: *Diagnostic, sourcePath: String) {
|
||||
/* Severity prefix */
|
||||
if diag.severity == 0 {
|
||||
Print("error: ");
|
||||
} else if diag.severity == 1 {
|
||||
Print("warning: ");
|
||||
} else {
|
||||
Print("note: ");
|
||||
func WriteFile(path: String, content: String) -> bool {
|
||||
return bux_write_file(path, content);
|
||||
}
|
||||
PrintLine(diag.message);
|
||||
|
||||
/* Location header */
|
||||
Print(" --> ");
|
||||
Print(sourcePath);
|
||||
Print(":");
|
||||
PrintInt(diag.line as int64);
|
||||
Print(":");
|
||||
PrintInt(diag.column as int64);
|
||||
PrintLine("");
|
||||
func FileExists(path: String) -> bool {
|
||||
return bux_file_exists(path) != 0;
|
||||
}
|
||||
|
||||
/* Source snippet */
|
||||
let lineText: String = Diagnostic_GetLine(sourcePath, diag.line);
|
||||
if !String_Eq(lineText, "") {
|
||||
let lineNumStr: String = String_FromInt(diag.line as int64);
|
||||
func DirExists(path: String) -> bool {
|
||||
return bux_dir_exists(path) != 0;
|
||||
}
|
||||
|
||||
Print(" |");
|
||||
PrintLine("");
|
||||
Print(" ");
|
||||
Print(lineNumStr);
|
||||
Print(" | ");
|
||||
PrintLine(lineText);
|
||||
// ---------------------------------------------------------------------------
|
||||
// Diagnostic formatting (Rust-style errors with snippets)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* Underline (multi-char for identifiers/string tokens) */
|
||||
Print(" | ");
|
||||
var i: uint32 = 0;
|
||||
while i < diag.column - 1 && i < 120 {
|
||||
Print(" ");
|
||||
i = i + 1;
|
||||
struct Diagnostic {
|
||||
message: String;
|
||||
line: uint32;
|
||||
column: uint32;
|
||||
severity: int;
|
||||
}
|
||||
|
||||
/* Read a single line from a file (1-based). Returns "" on error or EOF. */
|
||||
func Diagnostic_GetLine(path: String, lineNum: uint32) -> String {
|
||||
let content: String = bux_read_file(path);
|
||||
if String_Eq(content, "") { return ""; }
|
||||
/* bux_str_split_part uses 0-based index */
|
||||
return bux_str_split_part(content, "\n", lineNum - 1);
|
||||
}
|
||||
|
||||
/* Simple substring check for help hints */
|
||||
func Diagnostic_MsgContains(msg: String, needle: String) -> bool {
|
||||
return bux_str_contains(msg, needle) != 0;
|
||||
}
|
||||
|
||||
/* Actionable help for common error messages */
|
||||
func Diagnostic_Hint(msg: String) -> String {
|
||||
if Diagnostic_MsgContains(msg, "cannot assign") {
|
||||
return "ensure the right-hand side type matches the left-hand side";
|
||||
}
|
||||
/* Estimate token length from the source line */
|
||||
var ulen: uint = 1;
|
||||
let col0: uint = diag.column - 1;
|
||||
let lineLen: uint = String_Len(lineText);
|
||||
if col0 < lineLen {
|
||||
let first: String = String_Chars(lineText, col0);
|
||||
if String_Eq(first, "\"") || String_Eq(first, "`") || String_Eq(first, "'") {
|
||||
if Diagnostic_MsgContains(msg, "undeclared identifier") {
|
||||
return "check the spelling, or import the symbol from the right module";
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "too few arguments") {
|
||||
return "compare the call with the function's parameter list";
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "too many arguments") {
|
||||
return "compare the call with the function's parameter list";
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "use of moved value") {
|
||||
return "the value was moved; clone it or restructure ownership";
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "expected expression") {
|
||||
return "the previous statement may be incomplete (missing value or ';')";
|
||||
}
|
||||
if Diagnostic_MsgContains(msg, "duplicate symbol") {
|
||||
return "rename one of the definitions or remove the duplicate";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Print a diagnostic in Rust-style format:
|
||||
* error: <message>
|
||||
* --> <path>:<line>:<col>
|
||||
* |
|
||||
* 42 | <source_line>
|
||||
* | <spaces>^
|
||||
* = help: <hint>
|
||||
*/
|
||||
func Diagnostic_Print(diag: *Diagnostic, sourcePath: String) {
|
||||
/* Severity prefix */
|
||||
if diag.severity == 0 {
|
||||
Print("error: ");
|
||||
} else if diag.severity == 1 {
|
||||
Print("warning: ");
|
||||
} else {
|
||||
Print("note: ");
|
||||
}
|
||||
PrintLine(diag.message);
|
||||
|
||||
/* Location header */
|
||||
Print(" --> ");
|
||||
Print(sourcePath);
|
||||
Print(":");
|
||||
PrintInt(diag.line as int64);
|
||||
Print(":");
|
||||
PrintInt(diag.column as int64);
|
||||
PrintLine("");
|
||||
|
||||
/* Source snippet */
|
||||
let lineText: String = Diagnostic_GetLine(sourcePath, diag.line);
|
||||
if !String_Eq(lineText, "") {
|
||||
let lineNumStr: String = String_FromInt(diag.line as int64);
|
||||
|
||||
Print(" |");
|
||||
PrintLine("");
|
||||
Print(" ");
|
||||
Print(lineNumStr);
|
||||
Print(" | ");
|
||||
PrintLine(lineText);
|
||||
|
||||
/* Underline (multi-char for identifiers/string tokens) */
|
||||
Print(" | ");
|
||||
var i: uint32 = 0;
|
||||
while i < diag.column - 1 && i < 120 {
|
||||
Print(" ");
|
||||
i = i + 1;
|
||||
}
|
||||
/* Estimate token length from the source line */
|
||||
var ulen: uint = 1;
|
||||
let col0: uint = diag.column - 1;
|
||||
let lineLen: uint = String_Len(lineText);
|
||||
if col0 < lineLen {
|
||||
let first: String = String_Chars(lineText, col0);
|
||||
if String_Eq(first, "\"") || String_Eq(first, "`") || String_Eq(first, "'") {
|
||||
var j: uint = col0 + 1;
|
||||
while j < lineLen {
|
||||
let cj: String = String_Chars(lineText, j);
|
||||
@@ -922,12 +922,184 @@ func Cli_Fetch() -> int {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Fmt command — format source files
|
||||
// Doc command — Markdown from /// comments (D.4)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Cli_Fmt(dir: String) -> int {
|
||||
// If dir is a file, format just that file
|
||||
func Cli_DocIsDeclStart(line: String) -> bool {
|
||||
if String_StartsWith(line, "func ") { return true; }
|
||||
if String_StartsWith(line, "pub func ") { return true; }
|
||||
if String_StartsWith(line, "extern func ") { return true; }
|
||||
if String_StartsWith(line, "const func ") { return true; }
|
||||
if String_StartsWith(line, "async func ") { return true; }
|
||||
if String_StartsWith(line, "struct ") { return true; }
|
||||
if String_StartsWith(line, "pub struct ") { return true; }
|
||||
if String_StartsWith(line, "enum ") { return true; }
|
||||
if String_StartsWith(line, "interface ") { return true; }
|
||||
if String_StartsWith(line, "module ") { return true; }
|
||||
if String_StartsWith(line, "type ") { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
func Cli_DocExtractName(line: String) -> String {
|
||||
// Skip leading keywords
|
||||
var s: String = line;
|
||||
if String_StartsWith(s, "pub ") { s = bux_str_slice(s, 4, bux_strlen(s) - 4); }
|
||||
if String_StartsWith(s, "extern ") { s = bux_str_slice(s, 7, bux_strlen(s) - 7); }
|
||||
if String_StartsWith(s, "const ") { s = bux_str_slice(s, 6, bux_strlen(s) - 6); }
|
||||
if String_StartsWith(s, "async ") { s = bux_str_slice(s, 6, bux_strlen(s) - 6); }
|
||||
if String_StartsWith(s, "func ") { s = bux_str_slice(s, 5, bux_strlen(s) - 5); }
|
||||
else if String_StartsWith(s, "struct ") { s = bux_str_slice(s, 7, bux_strlen(s) - 7); }
|
||||
else if String_StartsWith(s, "enum ") { s = bux_str_slice(s, 5, bux_strlen(s) - 5); }
|
||||
else if String_StartsWith(s, "interface ") { s = bux_str_slice(s, 10, bux_strlen(s) - 10); }
|
||||
else if String_StartsWith(s, "module ") { s = bux_str_slice(s, 7, bux_strlen(s) - 7); }
|
||||
else if String_StartsWith(s, "type ") { s = bux_str_slice(s, 5, bux_strlen(s) - 5); }
|
||||
// Take until space, <, (, {, :, ;
|
||||
var i: uint = 0;
|
||||
let n: uint = bux_strlen(s);
|
||||
while i < n {
|
||||
let ch: String = bux_str_slice(s, i, 1);
|
||||
if String_Eq(ch, " ") || String_Eq(ch, "<") || String_Eq(ch, "(") ||
|
||||
String_Eq(ch, "{") || String_Eq(ch, ":") || String_Eq(ch, ";") {
|
||||
break;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
if i == 0 { return s; }
|
||||
return bux_str_slice(s, 0, i);
|
||||
}
|
||||
|
||||
func Cli_DocProcessFile(path: String, outSb: *StringBuilder) -> int {
|
||||
let source: String = ReadFile(path);
|
||||
if source == null as String || String_Eq(source, "") { return 0; }
|
||||
var itemCount: int = 0;
|
||||
var pending: String = "";
|
||||
var hasPending: bool = false;
|
||||
let lineCount: uint = bux_str_split_count(source, "\n");
|
||||
// Drop trailing empty split artifact
|
||||
var nLines: uint = lineCount;
|
||||
if nLines > 0 {
|
||||
let last: String = bux_str_split_part(source, "\n", nLines - 1);
|
||||
if String_Eq(last, "") { nLines = nLines - 1; }
|
||||
}
|
||||
var li: uint = 0;
|
||||
var wroteHeader: bool = false;
|
||||
while li < nLines {
|
||||
let raw: String = bux_str_split_part(source, "\n", li);
|
||||
let line: String = String_Trim(raw);
|
||||
if String_StartsWith(line, "///") {
|
||||
var body: String = bux_str_slice(line, 3, bux_strlen(line) - 3);
|
||||
if String_StartsWith(body, " ") {
|
||||
body = bux_str_slice(body, 1, bux_strlen(body) - 1);
|
||||
}
|
||||
if hasPending {
|
||||
pending = String_Concat(pending, String_Concat("\n", body));
|
||||
} else {
|
||||
pending = body;
|
||||
hasPending = true;
|
||||
}
|
||||
li = li + 1;
|
||||
continue;
|
||||
}
|
||||
if String_Eq(line, "") || String_StartsWith(line, "@[") {
|
||||
li = li + 1;
|
||||
continue;
|
||||
}
|
||||
if hasPending && Cli_DocIsDeclStart(line) {
|
||||
if !wroteHeader {
|
||||
StringBuilder_Append(outSb, "## `");
|
||||
StringBuilder_Append(outSb, Cli_FileNameFromPath(path));
|
||||
StringBuilder_Append(outSb, "`\n\n");
|
||||
StringBuilder_Append(outSb, "_Source: `");
|
||||
StringBuilder_Append(outSb, path);
|
||||
StringBuilder_Append(outSb, "`_\n\n");
|
||||
wroteHeader = true;
|
||||
}
|
||||
let name: String = Cli_DocExtractName(line);
|
||||
StringBuilder_Append(outSb, "### `");
|
||||
StringBuilder_Append(outSb, name);
|
||||
StringBuilder_Append(outSb, "`\n\n");
|
||||
StringBuilder_Append(outSb, "```bux\n");
|
||||
StringBuilder_Append(outSb, line);
|
||||
StringBuilder_Append(outSb, "\n```\n\n");
|
||||
StringBuilder_Append(outSb, pending);
|
||||
StringBuilder_Append(outSb, "\n\n");
|
||||
itemCount = itemCount + 1;
|
||||
hasPending = false;
|
||||
pending = "";
|
||||
li = li + 1;
|
||||
continue;
|
||||
}
|
||||
if String_StartsWith(line, "//") {
|
||||
li = li + 1;
|
||||
continue;
|
||||
}
|
||||
// Other code clears pending
|
||||
hasPending = false;
|
||||
pending = "";
|
||||
li = li + 1;
|
||||
}
|
||||
return itemCount;
|
||||
}
|
||||
|
||||
func Cli_Doc(dir: String, outPath: String) -> int {
|
||||
var sb: StringBuilder = StringBuilder_NewCap(16384);
|
||||
StringBuilder_Append(&sb, "# API Reference\n\n");
|
||||
StringBuilder_Append(&sb, "Generated by `bux doc` from `///` documentation comments.\n\n");
|
||||
var total: int = 0;
|
||||
if FileExists(dir) {
|
||||
total = total + Cli_DocProcessFile(dir, &sb);
|
||||
} else if DirExists(dir) {
|
||||
var fileCount: int = 0;
|
||||
let files: *String = bux_list_dir(dir, ".bux", &fileCount);
|
||||
var i: int = 0;
|
||||
while i < fileCount {
|
||||
total = total + Cli_DocProcessFile(files[i], &sb);
|
||||
i = i + 1;
|
||||
}
|
||||
} else {
|
||||
Print("Error: path not found: ");
|
||||
PrintLine(dir);
|
||||
StringBuilder_Free(&sb);
|
||||
return 1;
|
||||
}
|
||||
let md: String = StringBuilder_Build(&sb);
|
||||
StringBuilder_Free(&sb);
|
||||
if String_Eq(outPath, "") {
|
||||
Print(md);
|
||||
} else {
|
||||
if !WriteFile(outPath, md) {
|
||||
Print("Error: cannot write ");
|
||||
PrintLine(outPath);
|
||||
return 1;
|
||||
}
|
||||
Print("Wrote ");
|
||||
PrintInt(total as int64);
|
||||
Print(" documented items → ");
|
||||
PrintLine(outPath);
|
||||
}
|
||||
if total == 0 {
|
||||
PrintLine("warning: no /// documented declarations found");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Fmt command — format source files (write or --check for CI)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Cli_Fmt(dir: String, checkOnly: bool) -> int {
|
||||
// If dir is a file, format/check just that file
|
||||
if FileExists(dir) {
|
||||
if checkOnly {
|
||||
if Fmt_CheckFile(dir) == 0 {
|
||||
Print(" ok ");
|
||||
PrintLine(dir);
|
||||
return 0;
|
||||
}
|
||||
Print(" would reformat ");
|
||||
PrintLine(dir);
|
||||
return 1;
|
||||
}
|
||||
Print("Formatting ");
|
||||
PrintLine(dir);
|
||||
if Fmt_FormatFile(dir) {
|
||||
@@ -936,8 +1108,12 @@ func Cli_Fmt(dir: String) -> int {
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// Otherwise format all .bux files in directory
|
||||
Print("Formatting ");
|
||||
// Otherwise format/check all .bux files in directory
|
||||
if checkOnly {
|
||||
Print("Checking format in ");
|
||||
} else {
|
||||
Print("Formatting ");
|
||||
}
|
||||
PrintLine(dir);
|
||||
var fileCount: int = 0;
|
||||
let files: *String = bux_list_dir(dir, ".bux", &fileCount);
|
||||
@@ -947,14 +1123,34 @@ func Cli_Fmt(dir: String) -> int {
|
||||
}
|
||||
var i: int = 0;
|
||||
var okCount: int = 0;
|
||||
var changeCount: int = 0;
|
||||
while i < fileCount {
|
||||
Print(" ");
|
||||
PrintLine(files[i]);
|
||||
if Fmt_FormatFile(files[i]) {
|
||||
okCount = okCount + 1;
|
||||
if checkOnly {
|
||||
if Fmt_CheckFile(files[i]) == 0 {
|
||||
okCount = okCount + 1;
|
||||
} else {
|
||||
Print(" would reformat ");
|
||||
PrintLine(files[i]);
|
||||
changeCount = changeCount + 1;
|
||||
}
|
||||
} else {
|
||||
Print(" ");
|
||||
PrintLine(files[i]);
|
||||
if Fmt_FormatFile(files[i]) {
|
||||
okCount = okCount + 1;
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
if checkOnly {
|
||||
Print("fmt --check: ");
|
||||
PrintInt(changeCount as int64);
|
||||
Print(" would reformat, ");
|
||||
PrintInt(okCount as int64);
|
||||
PrintLine(" ok");
|
||||
if changeCount > 0 { return 1; }
|
||||
return 0;
|
||||
}
|
||||
Print("Formatted "); PrintInt(okCount as int64); Print("/"); PrintInt(fileCount as int64); PrintLine(" files");
|
||||
return 0;
|
||||
}
|
||||
@@ -985,32 +1181,40 @@ func Cli_StripExtension(name: String) -> String {
|
||||
return name;
|
||||
}
|
||||
|
||||
func Cli_Test(projectDir: String) -> int {
|
||||
func Cli_Test(projectDir: String, filter: String) -> int {
|
||||
Print("Testing project: ");
|
||||
PrintLine(projectDir);
|
||||
// Build and run the project's own Main first
|
||||
let mainRc: int = Cli_BuildProject(projectDir, "", false);
|
||||
if mainRc != 0 {
|
||||
PrintLine("Main test build failed");
|
||||
return mainRc;
|
||||
if !String_Eq(filter, "") {
|
||||
Print("Filter: ");
|
||||
PrintLine(filter);
|
||||
}
|
||||
let man: Manifest = Manifest_Load(bux_path_join(projectDir, "bux.toml"));
|
||||
var mainName: String = man.name;
|
||||
if String_Eq(mainName, "") { mainName = "bux_out"; }
|
||||
let mainBin: String = bux_path_join(bux_path_join(projectDir, "build"), mainName);
|
||||
if !FileExists(mainBin) {
|
||||
Print("Error: test binary not found: ");
|
||||
PrintLine(mainBin);
|
||||
return 1;
|
||||
|
||||
// Without --filter, build and run the project's own Main first.
|
||||
// With --filter, only run matching tests/*.bux files.
|
||||
if String_Eq(filter, "") {
|
||||
let mainRc: int = Cli_BuildProject(projectDir, "", false);
|
||||
if mainRc != 0 {
|
||||
PrintLine("Main test build failed");
|
||||
return mainRc;
|
||||
}
|
||||
let man: Manifest = Manifest_Load(bux_path_join(projectDir, "bux.toml"));
|
||||
var mainName: String = man.name;
|
||||
if String_Eq(mainName, "") { mainName = "bux_out"; }
|
||||
let mainBin: String = bux_path_join(bux_path_join(projectDir, "build"), mainName);
|
||||
if !FileExists(mainBin) {
|
||||
Print("Error: test binary not found: ");
|
||||
PrintLine(mainBin);
|
||||
return 1;
|
||||
}
|
||||
let mainResult: int = bux_system(mainBin);
|
||||
if mainResult != 0 {
|
||||
Print("Main tests failed (exit code ");
|
||||
PrintInt(mainResult as int64);
|
||||
PrintLine(")");
|
||||
return mainResult;
|
||||
}
|
||||
PrintLine("Main tests passed");
|
||||
}
|
||||
let mainResult: int = bux_system(mainBin);
|
||||
if mainResult != 0 {
|
||||
Print("Main tests failed (exit code ");
|
||||
PrintInt(mainResult as int64);
|
||||
PrintLine(")");
|
||||
return mainResult;
|
||||
}
|
||||
PrintLine("Main tests passed");
|
||||
|
||||
// Propagate the project's stdlib to temp test packages.
|
||||
let stdlibDir: String = Cli_FindStdlibDir(projectDir);
|
||||
@@ -1031,15 +1235,31 @@ func Cli_Test(projectDir: String) -> int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PrintLine("┌──────────────────────────────┬────────┐");
|
||||
PrintLine("│ Test │ Status │");
|
||||
PrintLine("├──────────────────────────────┼────────┤");
|
||||
|
||||
var passed: int = 0;
|
||||
var failed: int = 0;
|
||||
var skipped: int = 0;
|
||||
var i: int = 0;
|
||||
while i < testCount {
|
||||
let testPath: String = testFiles[i];
|
||||
let fileName: String = Cli_FileNameFromPath(testPath);
|
||||
let testName: String = Cli_StripExtension(fileName);
|
||||
Print(" Test: ");
|
||||
|
||||
// --filter: only run tests whose name contains the filter substring
|
||||
if !String_Eq(filter, "") {
|
||||
if !String_Contains(testName, filter) {
|
||||
skipped = skipped + 1;
|
||||
i = i + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Print("│ ");
|
||||
Print(testName);
|
||||
// Pad status column roughly (name may be long)
|
||||
Print(" ... ");
|
||||
|
||||
// Create temp package for this test file
|
||||
@@ -1050,14 +1270,14 @@ func Cli_Test(projectDir: String) -> int {
|
||||
|
||||
let source: String = ReadFile(testPath);
|
||||
if String_Eq(source, "") {
|
||||
PrintLine("FAIL (cannot read test file)");
|
||||
PrintLine("FAIL │");
|
||||
failed = failed + 1;
|
||||
i = i + 1;
|
||||
continue;
|
||||
}
|
||||
let tmpMain: String = bux_path_join(tmpSrc, "Main.bux");
|
||||
if !WriteFile(tmpMain, source) {
|
||||
PrintLine("FAIL (cannot write temp Main.bux)");
|
||||
PrintLine("FAIL │");
|
||||
failed = failed + 1;
|
||||
i = i + 1;
|
||||
continue;
|
||||
@@ -1066,7 +1286,7 @@ func Cli_Test(projectDir: String) -> int {
|
||||
let tmpToml: String = bux_path_join(tmpDir, "bux.toml");
|
||||
var tomlContent: String = "[Package]\nName = \"_test_tmp\"\nVersion = \"0.1.0\"\nType = \"bin\"\n\n[Build]\nOutput = \"Bin\"\n";
|
||||
if !WriteFile(tmpToml, tomlContent) {
|
||||
PrintLine("FAIL (cannot write temp bux.toml)");
|
||||
PrintLine("FAIL │");
|
||||
failed = failed + 1;
|
||||
i = i + 1;
|
||||
continue;
|
||||
@@ -1091,36 +1311,48 @@ func Cli_Test(projectDir: String) -> int {
|
||||
|
||||
let buildRc: int = Cli_BuildProject(tmpDir, "", false);
|
||||
if buildRc != 0 {
|
||||
PrintLine("FAIL (build error)");
|
||||
PrintLine("FAIL │");
|
||||
failed = failed + 1;
|
||||
i = i + 1;
|
||||
continue;
|
||||
}
|
||||
let testBin: String = bux_path_join(bux_path_join(tmpDir, "build"), "_test_tmp");
|
||||
if !FileExists(testBin) {
|
||||
PrintLine("FAIL (test binary not found)");
|
||||
PrintLine("FAIL │");
|
||||
failed = failed + 1;
|
||||
i = i + 1;
|
||||
continue;
|
||||
}
|
||||
let runRc: int = bux_system(testBin);
|
||||
if runRc == 0 {
|
||||
PrintLine("PASS");
|
||||
PrintLine("PASS │");
|
||||
passed = passed + 1;
|
||||
} else {
|
||||
Print("FAIL (exit ");
|
||||
PrintInt(runRc as int64);
|
||||
PrintLine(")");
|
||||
Print("FAIL │");
|
||||
PrintLine("");
|
||||
failed = failed + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
Print("Tests: ");
|
||||
PrintLine("└──────────────────────────────┴────────┘");
|
||||
Print("Results: ");
|
||||
PrintInt(passed as int64);
|
||||
Print(" passed, ");
|
||||
PrintInt(failed as int64);
|
||||
PrintLine(" failed");
|
||||
Print(" failed");
|
||||
if skipped > 0 {
|
||||
Print(", ");
|
||||
PrintInt(skipped as int64);
|
||||
Print(" skipped");
|
||||
}
|
||||
PrintLine("");
|
||||
if !String_Eq(filter, "") && passed == 0 && failed == 0 {
|
||||
Print("No tests matching filter '");
|
||||
Print(filter);
|
||||
PrintLine("'");
|
||||
return 1;
|
||||
}
|
||||
if failed > 0 { return 1; }
|
||||
return 0;
|
||||
}
|
||||
@@ -1493,7 +1725,10 @@ func Cli_Run(args: *String, argCount: int) -> int {
|
||||
if argCount < 2 {
|
||||
PrintLine("Bux Self-Hosting Compiler v0.2.0");
|
||||
PrintLine("Usage: buxc <command> [args]");
|
||||
PrintLine("Commands: build, check, new, init, add, remove, fetch, fmt, test, run, project, help, version");
|
||||
PrintLine("Commands: build, check, new, init, add, remove, fetch, fmt, doc, test, run, project, help, version");
|
||||
PrintLine(" test --filter <name> Only run tests/*.bux whose name contains <name>");
|
||||
PrintLine(" fmt --check [path] Exit 1 if any file would be reformatted (CI)");
|
||||
PrintLine(" doc --out file.md [path] API docs from /// comments");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1506,14 +1741,16 @@ func Cli_Run(args: *String, argCount: int) -> int {
|
||||
if String_Eq(cmd, "help") || String_Eq(cmd, "--help") || String_Eq(cmd, "-h") {
|
||||
PrintLine("Bux Self-Hosting Compiler v0.2.0");
|
||||
PrintLine("Usage: buxc <command> [args]");
|
||||
PrintLine("Commands: build, check, new, init, add, remove, fetch, fmt, test, run, project, help, version");
|
||||
PrintLine("Commands: build, check, new, init, add, remove, fetch, fmt, doc, test, run, project, help, version");
|
||||
PrintLine(" test --filter <name> Only run tests/*.bux whose name contains <name>");
|
||||
PrintLine(" fmt --check [path] Exit 1 if any file would be reformatted (CI)");
|
||||
PrintLine(" doc --out file.md [path] API docs from /// comments");
|
||||
PrintLine("Pipeline modules:");
|
||||
PrintLine(" Lexer ✅ 695 lines");
|
||||
PrintLine(" Parser ✅ 1004 lines");
|
||||
PrintLine(" Sema ✅ 393 lines");
|
||||
PrintLine(" HirLower ✅ 307 lines");
|
||||
PrintLine(" CBackend ✅ 585 lines");
|
||||
PrintLine(" Total: 3830 lines of Bux");
|
||||
PrintLine(" Lexer ✅");
|
||||
PrintLine(" Parser ✅");
|
||||
PrintLine(" Sema ✅");
|
||||
PrintLine(" HirLower ✅");
|
||||
PrintLine(" CBackend ✅");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1550,9 +1787,36 @@ func Cli_Run(args: *String, argCount: int) -> int {
|
||||
}
|
||||
|
||||
if String_Eq(cmd, "fmt") {
|
||||
let dir: String = ".";
|
||||
if argCount >= 3 { dir = args[2]; }
|
||||
return Cli_Fmt(dir);
|
||||
var dir: String = ".";
|
||||
var checkOnly: bool = false;
|
||||
var fi: int = 2;
|
||||
while fi < argCount {
|
||||
if String_Eq(args[fi], "--check") {
|
||||
checkOnly = true;
|
||||
} else {
|
||||
dir = args[fi];
|
||||
}
|
||||
fi = fi + 1;
|
||||
}
|
||||
return Cli_Fmt(dir, checkOnly);
|
||||
}
|
||||
|
||||
if String_Eq(cmd, "doc") {
|
||||
var dir: String = "lib";
|
||||
var outPath: String = "";
|
||||
var di: int = 2;
|
||||
while di < argCount {
|
||||
if String_Eq(args[di], "--out") && di + 1 < argCount {
|
||||
outPath = args[di + 1];
|
||||
di = di + 1;
|
||||
} else if String_StartsWith(args[di], "--out=") {
|
||||
outPath = bux_str_slice(args[di], 6, bux_strlen(args[di]) - 6);
|
||||
} else if !String_StartsWith(args[di], "-") {
|
||||
dir = args[di];
|
||||
}
|
||||
di = di + 1;
|
||||
}
|
||||
return Cli_Doc(dir, outPath);
|
||||
}
|
||||
|
||||
if String_Eq(cmd, "check") {
|
||||
@@ -1578,9 +1842,22 @@ func Cli_Run(args: *String, argCount: int) -> int {
|
||||
}
|
||||
|
||||
if String_Eq(cmd, "test") {
|
||||
let dir: String = ".";
|
||||
if argCount >= 3 { dir = args[2]; }
|
||||
return Cli_Test(dir);
|
||||
var dir: String = ".";
|
||||
var filter: String = "";
|
||||
var ti: int = 2;
|
||||
while ti < argCount {
|
||||
if String_Eq(args[ti], "--filter") && ti + 1 < argCount {
|
||||
filter = args[ti + 1];
|
||||
ti = ti + 1;
|
||||
} else if String_StartsWith(args[ti], "--filter=") {
|
||||
// --filter=name form
|
||||
filter = bux_str_slice(args[ti], 9, bux_strlen(args[ti]) - 9);
|
||||
} else if !String_StartsWith(args[ti], "-") {
|
||||
dir = args[ti];
|
||||
}
|
||||
ti = ti + 1;
|
||||
}
|
||||
return Cli_Test(dir, filter);
|
||||
}
|
||||
|
||||
if String_Eq(cmd, "run") {
|
||||
|
||||
+153
-123
@@ -1,138 +1,168 @@
|
||||
// fmt.bux — Bux source code formatter (indentation-based, preserves line structure)
|
||||
module Fmt {
|
||||
|
||||
extern func bux_read_file(path: String) -> String;
|
||||
extern func bux_write_file(path: String, content: String) -> bool;
|
||||
extern func bux_strlen(s: String) -> uint;
|
||||
extern func bux_read_file(path: String) -> String;
|
||||
extern func bux_write_file(path: String, content: String) -> bool;
|
||||
extern func bux_strlen(s: String) -> uint;
|
||||
|
||||
// Count leading spaces on a line
|
||||
func Fmt_CountLeadingSpaces(line: String) -> int {
|
||||
var count: int = 0;
|
||||
while count < 256 {
|
||||
let c: int = line[count] as int;
|
||||
if c == 0 { break; }
|
||||
if c != 32 { break; } // space
|
||||
count = count + 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Skip whitespace from start of line, return rest
|
||||
func Fmt_TrimLeft(line: String) -> String {
|
||||
var i: int = 0;
|
||||
while i < 256 {
|
||||
let c: int = line[i] as int;
|
||||
if c == 0 { break; }
|
||||
if c != 32 && c != 9 { break; }
|
||||
i = i + 1;
|
||||
}
|
||||
if i == 0 { return line; }
|
||||
// Extract substring from i
|
||||
var len: int = 0;
|
||||
while len < 256 {
|
||||
let c: int = line[len] as int;
|
||||
if c == 0 { break; }
|
||||
len = len + 1;
|
||||
}
|
||||
if i >= len { return ""; }
|
||||
return bux_str_slice(line, i as uint, (len - i) as uint);
|
||||
}
|
||||
|
||||
// Check if char at position is inside a string or comment (simplified)
|
||||
func Fmt_IsInStringOrComment(line: String, pos: int) -> bool {
|
||||
var inString: bool = false;
|
||||
var inChar: bool = false;
|
||||
var inComment: bool = false;
|
||||
var i: int = 0;
|
||||
while i < pos {
|
||||
let c: int = line[i] as int;
|
||||
let n: int = 0;
|
||||
if i + 1 < 256 { n = line[i + 1] as int; }
|
||||
if inComment { i = i + 1; continue; }
|
||||
if c == 47 && n == 47 { inComment = true; i = i + 1; continue; } // //
|
||||
if c == 34 && !inChar { inString = !inString; }
|
||||
if c == 39 && !inString { inChar = !inChar; }
|
||||
i = i + 1;
|
||||
}
|
||||
return inString || inChar || inComment;
|
||||
}
|
||||
|
||||
// Count brace depth change on a line, skipping strings/comments
|
||||
func Fmt_CountBraceDelta(line: String) -> int {
|
||||
var delta: int = 0;
|
||||
var i: int = 0;
|
||||
while i < 256 {
|
||||
let c: int = line[i] as int;
|
||||
if c == 0 { break; }
|
||||
if !Fmt_IsInStringOrComment(line, i) {
|
||||
if c == 123 { delta = delta + 1; } // {
|
||||
if c == 125 { delta = delta - 1; } // }
|
||||
// Count leading spaces on a line
|
||||
func Fmt_CountLeadingSpaces(line: String) -> int {
|
||||
var count: int = 0;
|
||||
while count < 256 {
|
||||
let c: int = line[count] as int;
|
||||
if c == 0 { break; }
|
||||
if c != 32 { break; } // space
|
||||
count = count + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
return count;
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
func Fmt_FormatSource(source: String) -> String {
|
||||
let sb: StringBuilder = StringBuilder_NewCap(8192);
|
||||
var indent: int = 0;
|
||||
var i: uint = 0;
|
||||
let lineCount: uint = bux_str_split_count(source, "\n");
|
||||
|
||||
while i < lineCount {
|
||||
let line: String = bux_str_split_part(source, "\n", i);
|
||||
let trimmed: String = Fmt_TrimLeft(line);
|
||||
|
||||
// Skip empty lines
|
||||
if String_Eq(trimmed, "") {
|
||||
StringBuilder_Append(&sb, "\n");
|
||||
// Skip whitespace from start of line, return rest
|
||||
func Fmt_TrimLeft(line: String) -> String {
|
||||
var i: int = 0;
|
||||
while i < 256 {
|
||||
let c: int = line[i] as int;
|
||||
if c == 0 { break; }
|
||||
if c != 32 && c != 9 { break; }
|
||||
i = i + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Adjust indent for closing braces on this line
|
||||
let delta: int = Fmt_CountBraceDelta(trimmed);
|
||||
// If line starts with }, decrease indent before emitting
|
||||
let firstChar: int = trimmed[0] as int;
|
||||
if firstChar == 125 { // }
|
||||
indent = indent - 1;
|
||||
if indent < 0 { indent = 0; }
|
||||
if i == 0 { return line; }
|
||||
// Extract substring from i
|
||||
var len: int = 0;
|
||||
while len < 256 {
|
||||
let c: int = line[len] as int;
|
||||
if c == 0 { break; }
|
||||
len = len + 1;
|
||||
}
|
||||
|
||||
// Emit indentation
|
||||
var si: int = 0;
|
||||
while si < indent {
|
||||
StringBuilder_Append(&sb, " ");
|
||||
si = si + 1;
|
||||
}
|
||||
|
||||
// Emit the trimmed line
|
||||
StringBuilder_Append(&sb, trimmed);
|
||||
StringBuilder_Append(&sb, "\n");
|
||||
|
||||
// Adjust indent for opening braces
|
||||
if firstChar != 125 {
|
||||
indent = indent + delta;
|
||||
} else {
|
||||
// For lines starting with }, apply the net delta after the initial decrease
|
||||
indent = indent + delta + 1;
|
||||
if indent < 0 { indent = 0; }
|
||||
}
|
||||
|
||||
i = i + 1;
|
||||
if i >= len { return ""; }
|
||||
return bux_str_slice(line, i as uint, (len - i) as uint);
|
||||
}
|
||||
|
||||
let result: String = StringBuilder_Build(&sb);
|
||||
StringBuilder_Free(&sb);
|
||||
return result;
|
||||
}
|
||||
// Check if char at position is inside a string or comment (simplified)
|
||||
func Fmt_IsInStringOrComment(line: String, pos: int) -> bool {
|
||||
var inString: bool = false;
|
||||
var inChar: bool = false;
|
||||
var inComment: bool = false;
|
||||
var i: int = 0;
|
||||
while i < pos {
|
||||
let c: int = line[i] as int;
|
||||
let n: int = 0;
|
||||
if i + 1 < 256 { n = line[i + 1] as int; }
|
||||
if inComment { i = i + 1; continue; }
|
||||
if c == 47 && n == 47 { inComment = true; i = i + 1; continue; } // //
|
||||
if c == 34 && !inChar { inString = !inString; }
|
||||
if c == 39 && !inString { inChar = !inChar; }
|
||||
i = i + 1;
|
||||
}
|
||||
return inString || inChar || inComment;
|
||||
}
|
||||
|
||||
func Fmt_FormatFile(path: String) -> bool {
|
||||
let source: String = bux_read_file(path);
|
||||
if source == null as String || String_Eq(source, "") { return false; }
|
||||
let formatted: String = Fmt_FormatSource(source);
|
||||
if String_Eq(formatted, "") { return false; }
|
||||
return bux_write_file(path, formatted);
|
||||
}
|
||||
// Count brace depth change on a line, skipping strings/comments
|
||||
func Fmt_CountBraceDelta(line: String) -> int {
|
||||
var delta: int = 0;
|
||||
var i: int = 0;
|
||||
while i < 256 {
|
||||
let c: int = line[i] as int;
|
||||
if c == 0 { break; }
|
||||
if !Fmt_IsInStringOrComment(line, i) {
|
||||
if c == 123 { delta = delta + 1; } // {
|
||||
if c == 125 { delta = delta - 1; } // }
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
|
||||
func Fmt_FormatSource(source: String) -> String {
|
||||
let sb: StringBuilder = StringBuilder_NewCap(8192);
|
||||
var indent: int = 0;
|
||||
var i: uint = 0;
|
||||
var lineCount: uint = bux_str_split_count(source, "\n");
|
||||
|
||||
// Trailing "\n" yields a final empty part (split artifact). Drop it so
|
||||
// re-formatting is idempotent and does not accumulate blank lines.
|
||||
if lineCount > 0 {
|
||||
let last: String = bux_str_split_part(source, "\n", lineCount - 1);
|
||||
if String_Eq(last, "") {
|
||||
lineCount = lineCount - 1;
|
||||
}
|
||||
}
|
||||
|
||||
while i < lineCount {
|
||||
let line: String = bux_str_split_part(source, "\n", i);
|
||||
let trimmed: String = Fmt_TrimLeft(line);
|
||||
|
||||
// Empty line (intentional blank) — keep a single newline
|
||||
if String_Eq(trimmed, "") {
|
||||
StringBuilder_Append(&sb, "\n");
|
||||
i = i + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Adjust indent for closing braces on this line
|
||||
let delta: int = Fmt_CountBraceDelta(trimmed);
|
||||
// If line starts with }, decrease indent before emitting
|
||||
let firstChar: int = trimmed[0] as int;
|
||||
if firstChar == 125 { // }
|
||||
indent = indent - 1;
|
||||
if indent < 0 { indent = 0; }
|
||||
}
|
||||
|
||||
// Emit indentation
|
||||
var si: int = 0;
|
||||
while si < indent {
|
||||
StringBuilder_Append(&sb, " ");
|
||||
si = si + 1;
|
||||
}
|
||||
|
||||
// Emit the trimmed line
|
||||
StringBuilder_Append(&sb, trimmed);
|
||||
StringBuilder_Append(&sb, "\n");
|
||||
|
||||
// Adjust indent for opening braces
|
||||
if firstChar != 125 {
|
||||
indent = indent + delta;
|
||||
} else {
|
||||
// For lines starting with }, apply the net delta after the initial decrease
|
||||
indent = indent + delta + 1;
|
||||
if indent < 0 { indent = 0; }
|
||||
}
|
||||
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
let result: String = StringBuilder_Build(&sb);
|
||||
StringBuilder_Free(&sb);
|
||||
return result;
|
||||
}
|
||||
|
||||
func Fmt_FormatFile(path: String) -> bool {
|
||||
let source: String = bux_read_file(path);
|
||||
if source == null as String || String_Eq(source, "") { return false; }
|
||||
let formatted: String = Fmt_FormatSource(source);
|
||||
if String_Eq(formatted, "") { return false; }
|
||||
return bux_write_file(path, formatted);
|
||||
}
|
||||
|
||||
// Returns true if formatting would change the file (CI --check).
|
||||
func Fmt_WouldChange(path: String) -> bool {
|
||||
let source: String = bux_read_file(path);
|
||||
if source == null as String { return false; }
|
||||
let formatted: String = Fmt_FormatSource(source);
|
||||
return !String_Eq(formatted, source);
|
||||
}
|
||||
|
||||
// Check a file without writing. Returns 0 if clean, 1 if would reformat / error.
|
||||
func Fmt_CheckFile(path: String) -> int {
|
||||
let source: String = bux_read_file(path);
|
||||
if source == null as String {
|
||||
return 1;
|
||||
}
|
||||
let formatted: String = Fmt_FormatSource(source);
|
||||
if String_Eq(formatted, source) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+250
-250
@@ -1,256 +1,256 @@
|
||||
// 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 hFieldAccess: int = 16;
|
||||
const hArrowField: int = 17;
|
||||
const hIndexPtr: int = 18;
|
||||
const hCall: int = 32;
|
||||
const hCallIndirect: int = 33;
|
||||
const hCast: int = 34;
|
||||
const hIs: int = 35;
|
||||
const hSizeOf: int = 36;
|
||||
const hBlock: int = 37;
|
||||
const hStructInit: int = 38;
|
||||
const hSliceInit: int = 39;
|
||||
const hRange: int = 40;
|
||||
const hTupleInit: int = 41;
|
||||
const hMatch: int = 42;
|
||||
const hSpawn: int = 43;
|
||||
const hAwait: int = 44;
|
||||
const hDefer: int = 45;
|
||||
// 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 hFieldAccess: int = 16;
|
||||
const hArrowField: int = 17;
|
||||
const hIndexPtr: int = 18;
|
||||
const hCall: int = 32;
|
||||
const hCallIndirect: int = 33;
|
||||
const hCast: int = 34;
|
||||
const hIs: int = 35;
|
||||
const hSizeOf: int = 36;
|
||||
const hBlock: int = 37;
|
||||
const hStructInit: int = 38;
|
||||
const hSliceInit: int = 39;
|
||||
const hRange: int = 40;
|
||||
const hTupleInit: int = 41;
|
||||
const hMatch: int = 42;
|
||||
const hSpawn: int = 43;
|
||||
const hAwait: int = 44;
|
||||
const hDefer: int = 45;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HirArgList — linked list for call arguments beyond 2
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// HirArgList — linked list for call arguments beyond 2
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct HirArgList {
|
||||
node: *HirNode,
|
||||
next: *HirArgList,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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;
|
||||
param6: *HirParam;
|
||||
param7: *HirParam;
|
||||
param8: *HirParam;
|
||||
retTypeKind: int;
|
||||
retTypeName: String;
|
||||
body: *HirNode;
|
||||
isPublic: bool;
|
||||
// Closure capture metadata
|
||||
captureCount: int;
|
||||
captureName0: String;
|
||||
captureName1: String;
|
||||
captureName2: String;
|
||||
captureName3: String;
|
||||
captureName4: String;
|
||||
captureName5: String;
|
||||
captureName6: String;
|
||||
captureName7: String;
|
||||
captureType0: int;
|
||||
captureType1: int;
|
||||
captureType2: int;
|
||||
captureType3: int;
|
||||
captureType4: int;
|
||||
captureType5: int;
|
||||
captureType6: int;
|
||||
captureType7: int;
|
||||
envStructName: String;
|
||||
envInstanceName: String;
|
||||
checkedFunc: bool;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HirEnumVariant
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct HirEnumVariant {
|
||||
name: String;
|
||||
fieldCount: int;
|
||||
fieldType0: int;
|
||||
fieldName0: String;
|
||||
fieldTypeName0: String; // C type name (e.g. "int", "Tuple_int_int")
|
||||
fieldType1: int;
|
||||
fieldName1: String;
|
||||
fieldTypeName1: String;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HirModule
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct HirStructField {
|
||||
name: String;
|
||||
typeName: String;
|
||||
}
|
||||
|
||||
struct HirStruct {
|
||||
name: String;
|
||||
fieldCount: int;
|
||||
fields: *HirStructField;
|
||||
}
|
||||
|
||||
struct HirConst {
|
||||
name: String;
|
||||
value: int;
|
||||
}
|
||||
|
||||
struct HirEnum {
|
||||
name: String;
|
||||
variantCount: int;
|
||||
variants: *HirEnumVariant;
|
||||
}
|
||||
|
||||
struct HirModule {
|
||||
funcCount: int;
|
||||
funcs: *HirFunc;
|
||||
externCount: int;
|
||||
externFuncs: *HirFunc;
|
||||
structCount: int;
|
||||
structs: *HirStruct;
|
||||
enumCount: int;
|
||||
enums: *HirEnum;
|
||||
constCount: int;
|
||||
consts: *HirConst;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
struct HirArgList {
|
||||
node: *HirNode,
|
||||
next: *HirArgList,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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;
|
||||
param6: *HirParam;
|
||||
param7: *HirParam;
|
||||
param8: *HirParam;
|
||||
retTypeKind: int;
|
||||
retTypeName: String;
|
||||
body: *HirNode;
|
||||
isPublic: bool;
|
||||
// Closure capture metadata
|
||||
captureCount: int;
|
||||
captureName0: String;
|
||||
captureName1: String;
|
||||
captureName2: String;
|
||||
captureName3: String;
|
||||
captureName4: String;
|
||||
captureName5: String;
|
||||
captureName6: String;
|
||||
captureName7: String;
|
||||
captureType0: int;
|
||||
captureType1: int;
|
||||
captureType2: int;
|
||||
captureType3: int;
|
||||
captureType4: int;
|
||||
captureType5: int;
|
||||
captureType6: int;
|
||||
captureType7: int;
|
||||
envStructName: String;
|
||||
envInstanceName: String;
|
||||
checkedFunc: bool;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HirEnumVariant
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct HirEnumVariant {
|
||||
name: String;
|
||||
fieldCount: int;
|
||||
fieldType0: int;
|
||||
fieldName0: String;
|
||||
fieldTypeName0: String; // C type name (e.g. "int", "Tuple_int_int")
|
||||
fieldType1: int;
|
||||
fieldName1: String;
|
||||
fieldTypeName1: String;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HirModule
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct HirStructField {
|
||||
name: String;
|
||||
typeName: String;
|
||||
}
|
||||
|
||||
struct HirStruct {
|
||||
name: String;
|
||||
fieldCount: int;
|
||||
fields: *HirStructField;
|
||||
}
|
||||
|
||||
struct HirConst {
|
||||
name: String;
|
||||
value: int;
|
||||
}
|
||||
|
||||
struct HirEnum {
|
||||
name: String;
|
||||
variantCount: int;
|
||||
variants: *HirEnumVariant;
|
||||
}
|
||||
|
||||
struct HirModule {
|
||||
funcCount: int;
|
||||
funcs: *HirFunc;
|
||||
externCount: int;
|
||||
externFuncs: *HirFunc;
|
||||
structCount: int;
|
||||
structs: *HirStruct;
|
||||
enumCount: int;
|
||||
enums: *HirEnum;
|
||||
constCount: int;
|
||||
consts: *HirConst;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
+3960
-3960
File diff suppressed because it is too large
Load Diff
+725
-712
File diff suppressed because it is too large
Load Diff
+213
-213
@@ -2,224 +2,137 @@
|
||||
// Parses package metadata: name, version, type, build output.
|
||||
module Manifest {
|
||||
|
||||
extern func bux_strlen(s: String) -> uint;
|
||||
extern func bux_strlen(s: String) -> uint;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Manifest struct
|
||||
// ---------------------------------------------------------------------------
|
||||
struct Manifest {
|
||||
name: String;
|
||||
version: String;
|
||||
pkgType: String;
|
||||
output: String;
|
||||
depCount: int;
|
||||
depName0: String;
|
||||
depUrl0: String;
|
||||
depName1: String;
|
||||
depUrl1: String;
|
||||
depName2: String;
|
||||
depUrl2: String;
|
||||
depName3: String;
|
||||
depUrl3: String;
|
||||
depName4: String;
|
||||
depUrl4: String;
|
||||
depName5: String;
|
||||
depUrl5: String;
|
||||
depName6: String;
|
||||
depUrl6: String;
|
||||
depName7: String;
|
||||
depUrl7: String;
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
// Manifest struct
|
||||
// ---------------------------------------------------------------------------
|
||||
struct Manifest {
|
||||
name: String;
|
||||
version: String;
|
||||
pkgType: String;
|
||||
output: String;
|
||||
depCount: int;
|
||||
depName0: String;
|
||||
depUrl0: String;
|
||||
depName1: String;
|
||||
depUrl1: String;
|
||||
depName2: String;
|
||||
depUrl2: String;
|
||||
depName3: String;
|
||||
depUrl3: String;
|
||||
depName4: String;
|
||||
depUrl4: String;
|
||||
depName5: String;
|
||||
depUrl5: String;
|
||||
depName6: String;
|
||||
depUrl6: String;
|
||||
depName7: String;
|
||||
depUrl7: String;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Simple TOML parser (handles [Package] and [Build] sections)
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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";
|
||||
m.depCount = 0;
|
||||
func Manifest_Parse(content: String) -> Manifest {
|
||||
var m: Manifest;
|
||||
m.name = "";
|
||||
m.version = "0.1.0";
|
||||
m.pkgType = "bin";
|
||||
m.output = "Bin";
|
||||
m.depCount = 0;
|
||||
|
||||
if String_Eq(content, "") { return m; }
|
||||
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);
|
||||
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; }
|
||||
// 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 if String_StartsWith(line, "[dependencies]") {
|
||||
currentSection = "dependencies";
|
||||
} else {
|
||||
currentSection = "";
|
||||
// Section header: [Section]
|
||||
if String_StartsWith(line, "[") {
|
||||
if String_StartsWith(line, "[Package]") {
|
||||
currentSection = "Package";
|
||||
} else if String_StartsWith(line, "[Build]") {
|
||||
currentSection = "Build";
|
||||
} else if String_StartsWith(line, "[dependencies]") {
|
||||
currentSection = "dependencies";
|
||||
} else {
|
||||
currentSection = "";
|
||||
}
|
||||
i = i + 1; continue;
|
||||
}
|
||||
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));
|
||||
// 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 vlen: uint = bux_strlen(val);
|
||||
if vlen >= 2 {
|
||||
val = String_Slice(val, 1, vlen - 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; }
|
||||
} else if String_Eq(currentSection, "dependencies") {
|
||||
if m.depCount < 8 {
|
||||
if m.depCount == 0 { m.depName0 = key; m.depUrl0 = val; }
|
||||
else if m.depCount == 1 { m.depName1 = key; m.depUrl1 = val; }
|
||||
else if m.depCount == 2 { m.depName2 = key; m.depUrl2 = val; }
|
||||
else if m.depCount == 3 { m.depName3 = key; m.depUrl3 = val; }
|
||||
else if m.depCount == 4 { m.depName4 = key; m.depUrl4 = val; }
|
||||
else if m.depCount == 5 { m.depName5 = key; m.depUrl5 = val; }
|
||||
else if m.depCount == 6 { m.depName6 = key; m.depUrl6 = val; }
|
||||
else if m.depCount == 7 { m.depName7 = key; m.depUrl7 = val; }
|
||||
m.depCount = m.depCount + 1;
|
||||
// Strip quotes from value
|
||||
var val: String = rawVal;
|
||||
if String_StartsWith(val, "\"") && String_EndsWith(val, "\"") {
|
||||
let vlen: uint = bux_strlen(val);
|
||||
if vlen >= 2 {
|
||||
val = String_Slice(val, 1, vlen - 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; }
|
||||
} else if String_Eq(currentSection, "dependencies") {
|
||||
if m.depCount < 8 {
|
||||
if m.depCount == 0 { m.depName0 = key; m.depUrl0 = val; }
|
||||
else if m.depCount == 1 { m.depName1 = key; m.depUrl1 = val; }
|
||||
else if m.depCount == 2 { m.depName2 = key; m.depUrl2 = val; }
|
||||
else if m.depCount == 3 { m.depName3 = key; m.depUrl3 = val; }
|
||||
else if m.depCount == 4 { m.depName4 = key; m.depUrl4 = val; }
|
||||
else if m.depCount == 5 { m.depName5 = key; m.depUrl5 = val; }
|
||||
else if m.depCount == 6 { m.depName6 = key; m.depUrl6 = val; }
|
||||
else if m.depCount == 7 { m.depName7 = key; m.depUrl7 = val; }
|
||||
m.depCount = m.depCount + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
i = i + 1;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
// Dependency helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Dependency helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Manifest_HasDep(m: Manifest, name: String) -> bool {
|
||||
var i: int = 0;
|
||||
while i < m.depCount {
|
||||
var depName: String = "";
|
||||
if i == 0 { depName = m.depName0; }
|
||||
else if i == 1 { depName = m.depName1; }
|
||||
else if i == 2 { depName = m.depName2; }
|
||||
else if i == 3 { depName = m.depName3; }
|
||||
else if i == 4 { depName = m.depName4; }
|
||||
else if i == 5 { depName = m.depName5; }
|
||||
else if i == 6 { depName = m.depName6; }
|
||||
else if i == 7 { depName = m.depName7; }
|
||||
if String_Eq(depName, name) { return true; }
|
||||
i = i + 1;
|
||||
func Manifest_HasDep(m: Manifest, name: String) -> bool {
|
||||
var i: int = 0;
|
||||
while i < m.depCount {
|
||||
var depName: String = "";
|
||||
if i == 0 { depName = m.depName0; }
|
||||
else if i == 1 { depName = m.depName1; }
|
||||
else if i == 2 { depName = m.depName2; }
|
||||
else if i == 3 { depName = m.depName3; }
|
||||
else if i == 4 { depName = m.depName4; }
|
||||
else if i == 5 { depName = m.depName5; }
|
||||
else if i == 6 { depName = m.depName6; }
|
||||
else if i == 7 { depName = m.depName7; }
|
||||
if String_Eq(depName, name) { return true; }
|
||||
i = i + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func Manifest_GetDepUrl(m: Manifest, name: String) -> String {
|
||||
var i: int = 0;
|
||||
while i < m.depCount {
|
||||
var depName: String = "";
|
||||
var depUrl: String = "";
|
||||
if i == 0 { depName = m.depName0; depUrl = m.depUrl0; }
|
||||
else if i == 1 { depName = m.depName1; depUrl = m.depUrl1; }
|
||||
else if i == 2 { depName = m.depName2; depUrl = m.depUrl2; }
|
||||
else if i == 3 { depName = m.depName3; depUrl = m.depUrl3; }
|
||||
else if i == 4 { depName = m.depName4; depUrl = m.depUrl4; }
|
||||
else if i == 5 { depName = m.depName5; depUrl = m.depUrl5; }
|
||||
else if i == 6 { depName = m.depName6; depUrl = m.depUrl6; }
|
||||
else if i == 7 { depName = m.depName7; depUrl = m.depUrl7; }
|
||||
if String_Eq(depName, name) { return depUrl; }
|
||||
i = i + 1;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
func Manifest_AddDep(m: *Manifest, name: String, url: String) -> bool {
|
||||
if Manifest_HasDep(*m, name) { return false; }
|
||||
if m.depCount >= 8 { return false; }
|
||||
if m.depCount == 0 { m.depName0 = name; m.depUrl0 = url; }
|
||||
else if m.depCount == 1 { m.depName1 = name; m.depUrl1 = url; }
|
||||
else if m.depCount == 2 { m.depName2 = name; m.depUrl2 = url; }
|
||||
else if m.depCount == 3 { m.depName3 = name; m.depUrl3 = url; }
|
||||
else if m.depCount == 4 { m.depName4 = name; m.depUrl4 = url; }
|
||||
else if m.depCount == 5 { m.depName5 = name; m.depUrl5 = url; }
|
||||
else if m.depCount == 6 { m.depName6 = name; m.depUrl6 = url; }
|
||||
else if m.depCount == 7 { m.depName7 = name; m.depUrl7 = url; }
|
||||
m.depCount = m.depCount + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
func Manifest_RemoveDep(m: *Manifest, name: String) -> bool {
|
||||
var found: int = -1;
|
||||
var i: int = 0;
|
||||
while i < m.depCount {
|
||||
var depName: String = "";
|
||||
if i == 0 { depName = m.depName0; }
|
||||
else if i == 1 { depName = m.depName1; }
|
||||
else if i == 2 { depName = m.depName2; }
|
||||
else if i == 3 { depName = m.depName3; }
|
||||
else if i == 4 { depName = m.depName4; }
|
||||
else if i == 5 { depName = m.depName5; }
|
||||
else if i == 6 { depName = m.depName6; }
|
||||
else if i == 7 { depName = m.depName7; }
|
||||
if String_Eq(depName, name) { found = i; break; }
|
||||
i = i + 1;
|
||||
}
|
||||
if found < 0 { return false; }
|
||||
i = found;
|
||||
while i < m.depCount - 1 {
|
||||
if i == 0 { m.depName0 = m.depName1; m.depUrl0 = m.depUrl1; }
|
||||
else if i == 1 { m.depName1 = m.depName2; m.depUrl1 = m.depUrl2; }
|
||||
else if i == 2 { m.depName2 = m.depName3; m.depUrl2 = m.depUrl3; }
|
||||
else if i == 3 { m.depName3 = m.depName4; m.depUrl3 = m.depUrl4; }
|
||||
else if i == 4 { m.depName4 = m.depName5; m.depUrl4 = m.depUrl5; }
|
||||
else if i == 5 { m.depName5 = m.depName6; m.depUrl5 = m.depUrl6; }
|
||||
else if i == 6 { m.depName6 = m.depName7; m.depUrl6 = m.depUrl7; }
|
||||
i = i + 1;
|
||||
}
|
||||
m.depCount = m.depCount - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Serialize manifest back to TOML
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Manifest_ToString(m: Manifest) -> String {
|
||||
let sb: StringBuilder = StringBuilder_New();
|
||||
StringBuilder_Append(&sb, "[Package]\n");
|
||||
StringBuilder_Append(&sb, "Name = \"");
|
||||
StringBuilder_Append(&sb, m.name);
|
||||
StringBuilder_Append(&sb, "\"\n");
|
||||
StringBuilder_Append(&sb, "Version = \"");
|
||||
StringBuilder_Append(&sb, m.version);
|
||||
StringBuilder_Append(&sb, "\"\n");
|
||||
StringBuilder_Append(&sb, "Type = \"");
|
||||
StringBuilder_Append(&sb, m.pkgType);
|
||||
StringBuilder_Append(&sb, "\"\n\n");
|
||||
StringBuilder_Append(&sb, "[Build]\n");
|
||||
StringBuilder_Append(&sb, "Output = \"");
|
||||
StringBuilder_Append(&sb, m.output);
|
||||
StringBuilder_Append(&sb, "\"\n");
|
||||
if m.depCount > 0 {
|
||||
StringBuilder_Append(&sb, "\n[dependencies]\n");
|
||||
func Manifest_GetDepUrl(m: Manifest, name: String) -> String {
|
||||
var i: int = 0;
|
||||
while i < m.depCount {
|
||||
var depName: String = "";
|
||||
@@ -232,22 +145,109 @@ func Manifest_ToString(m: Manifest) -> String {
|
||||
else if i == 5 { depName = m.depName5; depUrl = m.depUrl5; }
|
||||
else if i == 6 { depName = m.depName6; depUrl = m.depUrl6; }
|
||||
else if i == 7 { depName = m.depName7; depUrl = m.depUrl7; }
|
||||
StringBuilder_Append(&sb, depName);
|
||||
StringBuilder_Append(&sb, " = \"");
|
||||
StringBuilder_Append(&sb, depUrl);
|
||||
StringBuilder_Append(&sb, "\"\n");
|
||||
if String_Eq(depName, name) { return depUrl; }
|
||||
i = i + 1;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
return StringBuilder_Build(&sb);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Load manifest from file
|
||||
// ---------------------------------------------------------------------------
|
||||
func Manifest_AddDep(m: *Manifest, name: String, url: String) -> bool {
|
||||
if Manifest_HasDep(*m, name) { return false; }
|
||||
if m.depCount >= 8 { return false; }
|
||||
if m.depCount == 0 { m.depName0 = name; m.depUrl0 = url; }
|
||||
else if m.depCount == 1 { m.depName1 = name; m.depUrl1 = url; }
|
||||
else if m.depCount == 2 { m.depName2 = name; m.depUrl2 = url; }
|
||||
else if m.depCount == 3 { m.depName3 = name; m.depUrl3 = url; }
|
||||
else if m.depCount == 4 { m.depName4 = name; m.depUrl4 = url; }
|
||||
else if m.depCount == 5 { m.depName5 = name; m.depUrl5 = url; }
|
||||
else if m.depCount == 6 { m.depName6 = name; m.depUrl6 = url; }
|
||||
else if m.depCount == 7 { m.depName7 = name; m.depUrl7 = url; }
|
||||
m.depCount = m.depCount + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
func Manifest_Load(path: String) -> Manifest {
|
||||
let content: String = ReadFile(path);
|
||||
return Manifest_Parse(content);
|
||||
}
|
||||
func Manifest_RemoveDep(m: *Manifest, name: String) -> bool {
|
||||
var found: int = -1;
|
||||
var i: int = 0;
|
||||
while i < m.depCount {
|
||||
var depName: String = "";
|
||||
if i == 0 { depName = m.depName0; }
|
||||
else if i == 1 { depName = m.depName1; }
|
||||
else if i == 2 { depName = m.depName2; }
|
||||
else if i == 3 { depName = m.depName3; }
|
||||
else if i == 4 { depName = m.depName4; }
|
||||
else if i == 5 { depName = m.depName5; }
|
||||
else if i == 6 { depName = m.depName6; }
|
||||
else if i == 7 { depName = m.depName7; }
|
||||
if String_Eq(depName, name) { found = i; break; }
|
||||
i = i + 1;
|
||||
}
|
||||
if found < 0 { return false; }
|
||||
i = found;
|
||||
while i < m.depCount - 1 {
|
||||
if i == 0 { m.depName0 = m.depName1; m.depUrl0 = m.depUrl1; }
|
||||
else if i == 1 { m.depName1 = m.depName2; m.depUrl1 = m.depUrl2; }
|
||||
else if i == 2 { m.depName2 = m.depName3; m.depUrl2 = m.depUrl3; }
|
||||
else if i == 3 { m.depName3 = m.depName4; m.depUrl3 = m.depUrl4; }
|
||||
else if i == 4 { m.depName4 = m.depName5; m.depUrl4 = m.depUrl5; }
|
||||
else if i == 5 { m.depName5 = m.depName6; m.depUrl5 = m.depUrl6; }
|
||||
else if i == 6 { m.depName6 = m.depName7; m.depUrl6 = m.depUrl7; }
|
||||
i = i + 1;
|
||||
}
|
||||
m.depCount = m.depCount - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Serialize manifest back to TOML
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Manifest_ToString(m: Manifest) -> String {
|
||||
let sb: StringBuilder = StringBuilder_New();
|
||||
StringBuilder_Append(&sb, "[Package]\n");
|
||||
StringBuilder_Append(&sb, "Name = \"");
|
||||
StringBuilder_Append(&sb, m.name);
|
||||
StringBuilder_Append(&sb, "\"\n");
|
||||
StringBuilder_Append(&sb, "Version = \"");
|
||||
StringBuilder_Append(&sb, m.version);
|
||||
StringBuilder_Append(&sb, "\"\n");
|
||||
StringBuilder_Append(&sb, "Type = \"");
|
||||
StringBuilder_Append(&sb, m.pkgType);
|
||||
StringBuilder_Append(&sb, "\"\n\n");
|
||||
StringBuilder_Append(&sb, "[Build]\n");
|
||||
StringBuilder_Append(&sb, "Output = \"");
|
||||
StringBuilder_Append(&sb, m.output);
|
||||
StringBuilder_Append(&sb, "\"\n");
|
||||
if m.depCount > 0 {
|
||||
StringBuilder_Append(&sb, "\n[dependencies]\n");
|
||||
var i: int = 0;
|
||||
while i < m.depCount {
|
||||
var depName: String = "";
|
||||
var depUrl: String = "";
|
||||
if i == 0 { depName = m.depName0; depUrl = m.depUrl0; }
|
||||
else if i == 1 { depName = m.depName1; depUrl = m.depUrl1; }
|
||||
else if i == 2 { depName = m.depName2; depUrl = m.depUrl2; }
|
||||
else if i == 3 { depName = m.depName3; depUrl = m.depUrl3; }
|
||||
else if i == 4 { depName = m.depName4; depUrl = m.depUrl4; }
|
||||
else if i == 5 { depName = m.depName5; depUrl = m.depUrl5; }
|
||||
else if i == 6 { depName = m.depName6; depUrl = m.depUrl6; }
|
||||
else if i == 7 { depName = m.depName7; depUrl = m.depUrl7; }
|
||||
StringBuilder_Append(&sb, depName);
|
||||
StringBuilder_Append(&sb, " = \"");
|
||||
StringBuilder_Append(&sb, depUrl);
|
||||
StringBuilder_Append(&sb, "\"\n");
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
return StringBuilder_Build(&sb);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Load manifest from file
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Manifest_Load(path: String) -> Manifest {
|
||||
let content: String = ReadFile(path);
|
||||
return Manifest_Parse(content);
|
||||
}
|
||||
}
|
||||
|
||||
+2284
-2249
File diff suppressed because it is too large
Load Diff
+93
-93
@@ -1,115 +1,115 @@
|
||||
// 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;
|
||||
// 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 = 8192;
|
||||
// Maximum symbols per scope
|
||||
const maxSymbols: int = 8192;
|
||||
|
||||
struct Symbol {
|
||||
kind: int;
|
||||
name: String;
|
||||
typeKind: int;
|
||||
typeName: String;
|
||||
refType: *TypeExpr; // original type expression (for func types, etc.)
|
||||
isMutable: bool;
|
||||
isPublic: bool;
|
||||
decl: *Decl; // associated declaration (for funcs, structs, enums)
|
||||
}
|
||||
|
||||
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;
|
||||
struct Symbol {
|
||||
kind: int;
|
||||
name: String;
|
||||
typeKind: int;
|
||||
typeName: String;
|
||||
refType: *TypeExpr; // original type expression (for func types, etc.)
|
||||
isMutable: bool;
|
||||
isPublic: bool;
|
||||
decl: *Decl; // associated declaration (for funcs, structs, enums)
|
||||
}
|
||||
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 {
|
||||
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 < cur.count {
|
||||
if String_Eq(cur.symbols[i].name, name) {
|
||||
return cur.symbols[i];
|
||||
while i < scope.count {
|
||||
if String_Eq(scope.symbols[i].name, sym.name) {
|
||||
return false;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
cur = cur.parent;
|
||||
}
|
||||
var empty: Symbol = Symbol { kind: 0, name: "", typeKind: 0, typeName: "", refType: null as *TypeExpr, isMutable: false, isPublic: false, decl: null as *Decl };
|
||||
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];
|
||||
if scope.count < maxSymbols {
|
||||
scope.symbols[scope.count] = sym;
|
||||
scope.count = scope.count + 1;
|
||||
return true;
|
||||
}
|
||||
i = i + 1;
|
||||
return false;
|
||||
}
|
||||
var empty: Symbol = Symbol { kind: 0, name: "", typeKind: 0, typeName: "", refType: null as *TypeExpr, isMutable: false, isPublic: false, decl: null as *Decl };
|
||||
return empty;
|
||||
}
|
||||
|
||||
func Scope_LookupUpTo(scope: *Scope, name: String, limit: *Scope) -> Symbol {
|
||||
var cur: *Scope = scope;
|
||||
while cur != null as *Scope {
|
||||
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 = Symbol { kind: 0, name: "", typeKind: 0, typeName: "", refType: null as *TypeExpr, isMutable: false, isPublic: false, decl: null as *Decl };
|
||||
return empty;
|
||||
}
|
||||
|
||||
func Scope_LookupLocal(scope: *Scope, name: String) -> Symbol {
|
||||
var i: int = 0;
|
||||
while i < cur.count {
|
||||
if String_Eq(cur.symbols[i].name, name) {
|
||||
return cur.symbols[i];
|
||||
while i < scope.count {
|
||||
if String_Eq(scope.symbols[i].name, name) {
|
||||
return scope.symbols[i];
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
if cur == limit {
|
||||
break;
|
||||
}
|
||||
cur = cur.parent;
|
||||
var empty: Symbol = Symbol { kind: 0, name: "", typeKind: 0, typeName: "", refType: null as *TypeExpr, isMutable: false, isPublic: false, decl: null as *Decl };
|
||||
return empty;
|
||||
}
|
||||
var empty: Symbol = Symbol { kind: 0, name: "", typeKind: 0, typeName: "", refType: null as *TypeExpr, isMutable: false, isPublic: false, decl: null as *Decl };
|
||||
return empty;
|
||||
}
|
||||
|
||||
func Scope_Free(scope: *Scope) {
|
||||
bux_free(scope.symbols as *void);
|
||||
}
|
||||
func Scope_LookupUpTo(scope: *Scope, name: String, limit: *Scope) -> 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;
|
||||
}
|
||||
if cur == limit {
|
||||
break;
|
||||
}
|
||||
cur = cur.parent;
|
||||
}
|
||||
var empty: Symbol = Symbol { kind: 0, name: "", typeKind: 0, typeName: "", refType: null as *TypeExpr, isMutable: false, isPublic: false, decl: null as *Decl };
|
||||
return empty;
|
||||
}
|
||||
|
||||
func Scope_Free(scope: *Scope) {
|
||||
bux_free(scope.symbols as *void);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2231
-1981
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,13 @@
|
||||
// source_location.bux — Source position tracking
|
||||
module SourceLocation {
|
||||
|
||||
struct SourceLocation {
|
||||
line: uint32;
|
||||
column: uint32;
|
||||
offset: uint32;
|
||||
}
|
||||
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 };
|
||||
}
|
||||
func SourceLocation_New(line: uint32, column: uint32, offset: uint32) -> SourceLocation {
|
||||
return SourceLocation { line: line, column: column, offset: offset };
|
||||
}
|
||||
}
|
||||
|
||||
+330
-326
@@ -1,346 +1,350 @@
|
||||
// token.bux — Token kinds and helpers
|
||||
module Token {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TokenKind enum
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// TokenKind enum
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Literals
|
||||
const tkIntLiteral: int = 0;
|
||||
const tkFloatLiteral: int = 1;
|
||||
const tkStringLiteral: int = 2;
|
||||
const tkCharLiteral: int = 3;
|
||||
const tkBoolLiteral: int = 4;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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;
|
||||
// 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;
|
||||
// Special
|
||||
const tkOwn: int = 98;
|
||||
const tkNewLine: int = 99;
|
||||
const tkEndOfFile: int = 100;
|
||||
const tkUnknown: int = 101;
|
||||
|
||||
// Async / concurrency
|
||||
const tkAsync: int = 102;
|
||||
const tkAwait: int = 103;
|
||||
const tkSpawn: int = 104;
|
||||
const tkDiscard: int = 105;
|
||||
const tkDefer: int = 106;
|
||||
const tkSwitch: int = 107;
|
||||
const tkCase: int = 108;
|
||||
const tkDefault: int = 109;
|
||||
const tkUnsafe: int = 110;
|
||||
// Async / concurrency
|
||||
const tkAsync: int = 102;
|
||||
const tkAwait: int = 103;
|
||||
const tkSpawn: int = 104;
|
||||
const tkDiscard: int = 105;
|
||||
const tkDefer: int = 106;
|
||||
const tkSwitch: int = 107;
|
||||
const tkCase: int = 108;
|
||||
const tkDefault: int = 109;
|
||||
const tkUnsafe: int = 110;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Token struct
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lifetime parameter token: 'a, 'b, ... (not a char literal)
|
||||
const tkLifetime: int = 111;
|
||||
|
||||
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; }
|
||||
if kind == tkSizeOf { return true; }
|
||||
if kind >= tkDefer && kind <= tkUnsafe { return true; }
|
||||
if kind >= tkAsync && kind <= tkSpawn { 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, "defer") { return tkDefer; }
|
||||
if String_Eq(text, "switch") { return tkSwitch; }
|
||||
if String_Eq(text, "case") { return tkCase; }
|
||||
if String_Eq(text, "default") { return tkDefault; }
|
||||
if String_Eq(text, "unsafe") { return tkUnsafe; }
|
||||
if String_Eq(text, "discard") { return tkDiscard; }
|
||||
if String_Eq(text, "async") { return tkAsync; }
|
||||
if String_Eq(text, "await") { return tkAwait; }
|
||||
if String_Eq(text, "spawn") { return tkSpawn; }
|
||||
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 == tkUnsafe { return "unsafe"; }
|
||||
if kind == tkDefer { return "defer"; }
|
||||
if kind == tkSwitch { return "switch"; }
|
||||
if kind == tkCase { return "case"; }
|
||||
if kind == tkDefault { return "default"; }
|
||||
if kind == tkAsync { return "async"; }
|
||||
if kind == tkAwait { return "await"; }
|
||||
if kind == tkSpawn { return "spawn"; }
|
||||
if kind == tkDiscard { return "discard"; }
|
||||
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";
|
||||
}
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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; }
|
||||
if kind == tkSizeOf { return true; }
|
||||
if kind >= tkDefer && kind <= tkUnsafe { return true; }
|
||||
if kind >= tkAsync && kind <= tkSpawn { 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, "defer") { return tkDefer; }
|
||||
if String_Eq(text, "switch") { return tkSwitch; }
|
||||
if String_Eq(text, "case") { return tkCase; }
|
||||
if String_Eq(text, "default") { return tkDefault; }
|
||||
if String_Eq(text, "unsafe") { return tkUnsafe; }
|
||||
if String_Eq(text, "discard") { return tkDiscard; }
|
||||
if String_Eq(text, "async") { return tkAsync; }
|
||||
if String_Eq(text, "await") { return tkAwait; }
|
||||
if String_Eq(text, "spawn") { return tkSpawn; }
|
||||
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 == tkUnsafe { return "unsafe"; }
|
||||
if kind == tkDefer { return "defer"; }
|
||||
if kind == tkSwitch { return "switch"; }
|
||||
if kind == tkCase { return "case"; }
|
||||
if kind == tkDefault { return "default"; }
|
||||
if kind == tkAsync { return "async"; }
|
||||
if kind == tkAwait { return "await"; }
|
||||
if kind == tkSpawn { return "spawn"; }
|
||||
if kind == tkDiscard { return "discard"; }
|
||||
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 == tkLifetime { return "lifetime"; }
|
||||
if kind == tkNewLine { return "newline"; }
|
||||
if kind == tkEndOfFile { return "end of file"; }
|
||||
return "unknown token";
|
||||
}
|
||||
}
|
||||
|
||||
+271
-271
@@ -1,279 +1,279 @@
|
||||
// types.bux — Type system definitions and factories
|
||||
module Types {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TypeKind constants
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// TypeKind constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const tyUnknown: int = 0;
|
||||
const tyVoid: int = 1;
|
||||
const tyBool: int = 2;
|
||||
const tyBool8: int = 3;
|
||||
const tyBool16: int = 4;
|
||||
const tyBool32: int = 5;
|
||||
const tyChar8: int = 6;
|
||||
const tyChar16: int = 7;
|
||||
const tyChar32: int = 8;
|
||||
const tyStr: int = 9;
|
||||
const tyInt8: int = 10;
|
||||
const tyInt16: int = 11;
|
||||
const tyInt32: int = 12;
|
||||
const tyInt64: int = 13;
|
||||
const tyInt: int = 14;
|
||||
const tyUInt8: int = 15;
|
||||
const tyUInt16: int = 16;
|
||||
const tyUInt32: int = 17;
|
||||
const tyUInt64: int = 18;
|
||||
const tyUInt: int = 19;
|
||||
const tyFloat32: int = 20;
|
||||
const tyFloat64: int = 21;
|
||||
const tyPointer: int = 22;
|
||||
const tySlice: int = 23;
|
||||
const tyRange: int = 24;
|
||||
const tyTuple: int = 25;
|
||||
const tyNamed: int = 26;
|
||||
const tyTypeParam: int = 27;
|
||||
const tyFunc: int = 28;
|
||||
const tyUnknown: int = 0;
|
||||
const tyVoid: int = 1;
|
||||
const tyBool: int = 2;
|
||||
const tyBool8: int = 3;
|
||||
const tyBool16: int = 4;
|
||||
const tyBool32: int = 5;
|
||||
const tyChar8: int = 6;
|
||||
const tyChar16: int = 7;
|
||||
const tyChar32: int = 8;
|
||||
const tyStr: int = 9;
|
||||
const tyInt8: int = 10;
|
||||
const tyInt16: int = 11;
|
||||
const tyInt32: int = 12;
|
||||
const tyInt64: int = 13;
|
||||
const tyInt: int = 14;
|
||||
const tyUInt8: int = 15;
|
||||
const tyUInt16: int = 16;
|
||||
const tyUInt32: int = 17;
|
||||
const tyUInt64: int = 18;
|
||||
const tyUInt: int = 19;
|
||||
const tyFloat32: int = 20;
|
||||
const tyFloat64: int = 21;
|
||||
const tyPointer: int = 22;
|
||||
const tySlice: int = 23;
|
||||
const tyRange: int = 24;
|
||||
const tyTuple: int = 25;
|
||||
const tyNamed: int = 26;
|
||||
const tyTypeParam: int = 27;
|
||||
const tyFunc: int = 28;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type struct
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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: tyUnknown, name: "", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeVoid() -> Type {
|
||||
return Type { kind: tyVoid, name: "void", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeBool() -> Type {
|
||||
return Type { kind: tyBool, name: "bool", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeInt() -> Type {
|
||||
return Type { kind: tyInt, name: "int", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeInt64() -> Type {
|
||||
return Type { kind: tyInt64, name: "int64", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeUInt() -> Type {
|
||||
return Type { kind: tyUInt, name: "uint", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeFloat64() -> Type {
|
||||
return Type { kind: tyFloat64, name: "float64", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeStr() -> Type {
|
||||
return Type { kind: tyStr, name: "String", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakePointer(pointee: Type) -> Type {
|
||||
return Type { kind: tyPointer, name: "", innerCount: 1,
|
||||
innerKind1: pointee.kind, innerName1: pointee.name,
|
||||
innerKind2: 0, innerName2: "", innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeNamed(name: String) -> Type {
|
||||
return Type { kind: tyNamed, name: name, innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeTypeParam(name: String) -> Type {
|
||||
return Type { kind: tyTypeParam, 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 == tyInt8 || k == tyInt16 || k == tyInt32 || k == tyInt64 || k == tyInt { return true; }
|
||||
if k == tyUInt8 || k == tyUInt16 || k == tyUInt32 || k == tyUInt64 || k == tyUInt { return true; }
|
||||
if k == tyFloat32 || k == tyFloat64 { return true; }
|
||||
if k == tyUnknown || k == tyNamed || k == tyTypeParam { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
func Type_IsInteger(t: Type) -> bool {
|
||||
let k: int = t.kind;
|
||||
if k == tyInt8 || k == tyInt16 || k == tyInt32 || k == tyInt64 || k == tyInt { return true; }
|
||||
if k == tyUInt8 || k == tyUInt16 || k == tyUInt32 || k == tyUInt64 || k == tyUInt { return true; }
|
||||
if k == tyUnknown || k == tyNamed || k == tyTypeParam { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
func Type_IsBool(t: Type) -> bool {
|
||||
let k: int = t.kind;
|
||||
return k == tyBool || k == tyBool8 || k == tyBool16 || k == tyBool32;
|
||||
}
|
||||
|
||||
func Type_IsPointer(t: Type) -> bool {
|
||||
return t.kind == tyPointer;
|
||||
}
|
||||
|
||||
func Type_IsSlice(t: Type) -> bool {
|
||||
return t.kind == tySlice;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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 == tyNamed || a.kind == tyTypeParam {
|
||||
return String_Eq(a.name, b.name);
|
||||
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: tyUnknown, name: "", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeVoid() -> Type {
|
||||
return Type { kind: tyVoid, name: "void", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeBool() -> Type {
|
||||
return Type { kind: tyBool, name: "bool", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeInt() -> Type {
|
||||
return Type { kind: tyInt, name: "int", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeInt64() -> Type {
|
||||
return Type { kind: tyInt64, name: "int64", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeUInt() -> Type {
|
||||
return Type { kind: tyUInt, name: "uint", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeFloat64() -> Type {
|
||||
return Type { kind: tyFloat64, name: "float64", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeStr() -> Type {
|
||||
return Type { kind: tyStr, name: "String", innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakePointer(pointee: Type) -> Type {
|
||||
return Type { kind: tyPointer, name: "", innerCount: 1,
|
||||
innerKind1: pointee.kind, innerName1: pointee.name,
|
||||
innerKind2: 0, innerName2: "", innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeNamed(name: String) -> Type {
|
||||
return Type { kind: tyNamed, name: name, innerCount: 0,
|
||||
innerKind1: 0, innerName1: "", innerKind2: 0, innerName2: "",
|
||||
innerKind3: 0, innerName3: "" };
|
||||
}
|
||||
|
||||
func Type_MakeTypeParam(name: String) -> Type {
|
||||
return Type { kind: tyTypeParam, 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 == tyInt8 || k == tyInt16 || k == tyInt32 || k == tyInt64 || k == tyInt { return true; }
|
||||
if k == tyUInt8 || k == tyUInt16 || k == tyUInt32 || k == tyUInt64 || k == tyUInt { return true; }
|
||||
if k == tyFloat32 || k == tyFloat64 { return true; }
|
||||
if k == tyUnknown || k == tyNamed || k == tyTypeParam { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
func Type_IsInteger(t: Type) -> bool {
|
||||
let k: int = t.kind;
|
||||
if k == tyInt8 || k == tyInt16 || k == tyInt32 || k == tyInt64 || k == tyInt { return true; }
|
||||
if k == tyUInt8 || k == tyUInt16 || k == tyUInt32 || k == tyUInt64 || k == tyUInt { return true; }
|
||||
if k == tyUnknown || k == tyNamed || k == tyTypeParam { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
func Type_IsBool(t: Type) -> bool {
|
||||
let k: int = t.kind;
|
||||
return k == tyBool || k == tyBool8 || k == tyBool16 || k == tyBool32;
|
||||
}
|
||||
|
||||
func Type_IsPointer(t: Type) -> bool {
|
||||
return t.kind == tyPointer;
|
||||
}
|
||||
|
||||
func Type_IsSlice(t: Type) -> bool {
|
||||
return t.kind == tySlice;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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 == tyNamed || a.kind == tyTypeParam {
|
||||
return String_Eq(a.name, b.name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// toString
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Type_ToString(t: Type) -> String {
|
||||
if t.kind == tyVoid { return "void"; }
|
||||
if t.kind == tyBool { return "bool"; }
|
||||
if t.kind == tyStr { return "String"; }
|
||||
if t.kind == tyInt { return "int"; }
|
||||
if t.kind == tyInt64 { return "int64"; }
|
||||
if t.kind == tyUInt { return "uint"; }
|
||||
if t.kind == tyFloat64 { return "float64"; }
|
||||
if t.kind == tyNamed { return t.name; }
|
||||
if t.kind == tyTypeParam { return t.name; }
|
||||
if t.kind == tyPointer { return String_Concat("*", t.innerName1); }
|
||||
if t.kind == tyFunc { return t.name; }
|
||||
return "?";
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type_FromName — central type-name → kind mapping (used by sema, hir_lower)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Type_FromName(name: String) -> int {
|
||||
if String_Eq(name, "void") { return tyVoid; }
|
||||
if String_Eq(name, "bool") { return tyBool; }
|
||||
if String_Eq(name, "bool8") { return tyBool8; }
|
||||
if String_Eq(name, "bool16") { return tyBool16; }
|
||||
if String_Eq(name, "bool32") { return tyBool32; }
|
||||
if String_Eq(name, "char8") { return tyChar8; }
|
||||
if String_Eq(name, "char16") { return tyChar16; }
|
||||
if String_Eq(name, "char32") { return tyChar32; }
|
||||
if String_Eq(name, "String") { return tyStr; }
|
||||
if String_Eq(name, "str") { return tyStr; }
|
||||
if String_Eq(name, "int8") { return tyInt8; }
|
||||
if String_Eq(name, "int16") { return tyInt16; }
|
||||
if String_Eq(name, "int32") { return tyInt32; }
|
||||
if String_Eq(name, "int64") { return tyInt64; }
|
||||
if String_Eq(name, "int") { return tyInt; }
|
||||
if String_Eq(name, "uint8") { return tyUInt8; }
|
||||
if String_Eq(name, "uint16") { return tyUInt16; }
|
||||
if String_Eq(name, "uint32") { return tyUInt32; }
|
||||
if String_Eq(name, "uint64") { return tyUInt64; }
|
||||
if String_Eq(name, "uint") { return tyUInt; }
|
||||
if String_Eq(name, "float32") { return tyFloat32; }
|
||||
if String_Eq(name, "float64") { return tyFloat64; }
|
||||
if String_Eq(name, "float") { return tyFloat64; }
|
||||
return tyNamed;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type_ToCName — type kind → C type name (used by C backend)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Type_ToCName(kind: int) -> String {
|
||||
if kind == tyVoid { return "void"; }
|
||||
if kind == tyBool || kind == tyBool8 || kind == tyBool16 || kind == tyBool32 { return "bool"; }
|
||||
if kind == tyChar8 { return "char"; }
|
||||
if kind == tyChar16 { return "uint16"; }
|
||||
if kind == tyChar32 { return "uint32"; }
|
||||
if kind == tyStr { return "String"; }
|
||||
if kind == tyInt8 { return "int8"; }
|
||||
if kind == tyInt16 { return "int16"; }
|
||||
if kind == tyInt32 { return "int32"; }
|
||||
if kind == tyInt64 { return "int64"; }
|
||||
if kind == tyInt { return "int"; }
|
||||
if kind == tyUInt8 { return "uint8"; }
|
||||
if kind == tyUInt16 { return "uint16"; }
|
||||
if kind == tyUInt32 { return "uint32"; }
|
||||
if kind == tyUInt64 { return "uint64"; }
|
||||
if kind == tyUInt { return "uint"; }
|
||||
if kind == tyFloat32 { return "float32"; }
|
||||
if kind == tyFloat64 { return "float64"; }
|
||||
if kind == tyPointer { return "void*"; }
|
||||
// Fat function pointer — concrete BuxFn_* name comes from typeName field
|
||||
if kind == tyFunc { return "BuxFn"; }
|
||||
return "";
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Signed / Unsigned / Float predicates
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Type_IsSigned(kind: int) -> bool {
|
||||
return kind == tyInt8 || kind == tyInt16 || kind == tyInt32 || kind == tyInt64 || kind == tyInt;
|
||||
}
|
||||
|
||||
func Type_IsUnsigned(kind: int) -> bool {
|
||||
return kind == tyUInt8 || kind == tyUInt16 || kind == tyUInt32 || kind == tyUInt64 || kind == tyUInt;
|
||||
}
|
||||
|
||||
func Type_IsFloat(kind: int) -> bool {
|
||||
return kind == tyFloat32 || kind == tyFloat64;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type_SizeOf — byte size of a primitive type (0 for non-primitive)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Type_SizeOf(kind: int) -> int {
|
||||
if kind == tyBool || kind == tyBool8 || kind == tyChar8 || kind == tyInt8 || kind == tyUInt8 { return 1; }
|
||||
if kind == tyBool16 || kind == tyChar16 || kind == tyInt16 || kind == tyUInt16 { return 2; }
|
||||
if kind == tyBool32 || kind == tyChar32 || kind == tyInt32 || kind == tyUInt32 || kind == tyFloat32 { return 4; }
|
||||
if kind == tyInt64 || kind == tyUInt64 || kind == tyFloat64 { return 8; }
|
||||
if kind == tyInt || kind == tyUInt { return 8; }
|
||||
if kind == tyPointer { return 8; }
|
||||
return 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// toString
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Type_ToString(t: Type) -> String {
|
||||
if t.kind == tyVoid { return "void"; }
|
||||
if t.kind == tyBool { return "bool"; }
|
||||
if t.kind == tyStr { return "String"; }
|
||||
if t.kind == tyInt { return "int"; }
|
||||
if t.kind == tyInt64 { return "int64"; }
|
||||
if t.kind == tyUInt { return "uint"; }
|
||||
if t.kind == tyFloat64 { return "float64"; }
|
||||
if t.kind == tyNamed { return t.name; }
|
||||
if t.kind == tyTypeParam { return t.name; }
|
||||
if t.kind == tyPointer { return String_Concat("*", t.innerName1); }
|
||||
if t.kind == tyFunc { return t.name; }
|
||||
return "?";
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type_FromName — central type-name → kind mapping (used by sema, hir_lower)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Type_FromName(name: String) -> int {
|
||||
if String_Eq(name, "void") { return tyVoid; }
|
||||
if String_Eq(name, "bool") { return tyBool; }
|
||||
if String_Eq(name, "bool8") { return tyBool8; }
|
||||
if String_Eq(name, "bool16") { return tyBool16; }
|
||||
if String_Eq(name, "bool32") { return tyBool32; }
|
||||
if String_Eq(name, "char8") { return tyChar8; }
|
||||
if String_Eq(name, "char16") { return tyChar16; }
|
||||
if String_Eq(name, "char32") { return tyChar32; }
|
||||
if String_Eq(name, "String") { return tyStr; }
|
||||
if String_Eq(name, "str") { return tyStr; }
|
||||
if String_Eq(name, "int8") { return tyInt8; }
|
||||
if String_Eq(name, "int16") { return tyInt16; }
|
||||
if String_Eq(name, "int32") { return tyInt32; }
|
||||
if String_Eq(name, "int64") { return tyInt64; }
|
||||
if String_Eq(name, "int") { return tyInt; }
|
||||
if String_Eq(name, "uint8") { return tyUInt8; }
|
||||
if String_Eq(name, "uint16") { return tyUInt16; }
|
||||
if String_Eq(name, "uint32") { return tyUInt32; }
|
||||
if String_Eq(name, "uint64") { return tyUInt64; }
|
||||
if String_Eq(name, "uint") { return tyUInt; }
|
||||
if String_Eq(name, "float32") { return tyFloat32; }
|
||||
if String_Eq(name, "float64") { return tyFloat64; }
|
||||
if String_Eq(name, "float") { return tyFloat64; }
|
||||
return tyNamed;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type_ToCName — type kind → C type name (used by C backend)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Type_ToCName(kind: int) -> String {
|
||||
if kind == tyVoid { return "void"; }
|
||||
if kind == tyBool || kind == tyBool8 || kind == tyBool16 || kind == tyBool32 { return "bool"; }
|
||||
if kind == tyChar8 { return "char"; }
|
||||
if kind == tyChar16 { return "uint16"; }
|
||||
if kind == tyChar32 { return "uint32"; }
|
||||
if kind == tyStr { return "String"; }
|
||||
if kind == tyInt8 { return "int8"; }
|
||||
if kind == tyInt16 { return "int16"; }
|
||||
if kind == tyInt32 { return "int32"; }
|
||||
if kind == tyInt64 { return "int64"; }
|
||||
if kind == tyInt { return "int"; }
|
||||
if kind == tyUInt8 { return "uint8"; }
|
||||
if kind == tyUInt16 { return "uint16"; }
|
||||
if kind == tyUInt32 { return "uint32"; }
|
||||
if kind == tyUInt64 { return "uint64"; }
|
||||
if kind == tyUInt { return "uint"; }
|
||||
if kind == tyFloat32 { return "float32"; }
|
||||
if kind == tyFloat64 { return "float64"; }
|
||||
if kind == tyPointer { return "void*"; }
|
||||
// Fat function pointer — concrete BuxFn_* name comes from typeName field
|
||||
if kind == tyFunc { return "BuxFn"; }
|
||||
return "";
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Signed / Unsigned / Float predicates
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Type_IsSigned(kind: int) -> bool {
|
||||
return kind == tyInt8 || kind == tyInt16 || kind == tyInt32 || kind == tyInt64 || kind == tyInt;
|
||||
}
|
||||
|
||||
func Type_IsUnsigned(kind: int) -> bool {
|
||||
return kind == tyUInt8 || kind == tyUInt16 || kind == tyUInt32 || kind == tyUInt64 || kind == tyUInt;
|
||||
}
|
||||
|
||||
func Type_IsFloat(kind: int) -> bool {
|
||||
return kind == tyFloat32 || kind == tyFloat64;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type_SizeOf — byte size of a primitive type (0 for non-primitive)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Type_SizeOf(kind: int) -> int {
|
||||
if kind == tyBool || kind == tyBool8 || kind == tyChar8 || kind == tyInt8 || kind == tyUInt8 { return 1; }
|
||||
if kind == tyBool16 || kind == tyChar16 || kind == tyInt16 || kind == tyUInt16 { return 2; }
|
||||
if kind == tyBool32 || kind == tyChar32 || kind == tyInt32 || kind == tyUInt32 || kind == tyFloat32 { return 4; }
|
||||
if kind == tyInt64 || kind == tyUInt64 || kind == tyFloat64 { return 8; }
|
||||
if kind == tyInt || kind == tyUInt { return 8; }
|
||||
if kind == tyPointer { return 8; }
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user