6f2a3b1d88
Add Ast_Graft/Clone/Quote helpers, HIR Lcx_GraftSourceFile, and force definition-site paths on monomorphized bodies. Smoke checks Array mono #line stays in lib while Main stays isolated.
797 lines
29 KiB
Plaintext
797 lines
29 KiB
Plaintext
// 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 / 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,
|
|
// Source file for multi-file #line / future macros (empty = inherit Decl)
|
|
sourceFile: String,
|
|
// 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,
|
|
sourceFile: String, // multi-file #line (empty = inherit Decl)
|
|
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,
|
|
// Source file for multi-file #line / future macros (empty = inherit Decl)
|
|
sourceFile: String,
|
|
// 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)
|
|
// Source file path for #line / diagnostics (multi-file projects)
|
|
sourceFile: String,
|
|
// 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, sourceFile: "",
|
|
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, sourceFile: "",
|
|
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 };
|
|
}
|
|
|
|
/// Stamp sourceFile on an expression tree (empty slots only — keeps grafted macro nodes).
|
|
func Ast_StampExprFile(e: *Expr, path: String) {
|
|
if e == null as *Expr { return; }
|
|
if path == null as String || String_Eq(path, "") { return; }
|
|
if e.sourceFile == null as String || String_Eq(e.sourceFile, "") {
|
|
e.sourceFile = path;
|
|
}
|
|
Ast_StampExprFile(e.child1, path);
|
|
Ast_StampExprFile(e.child2, path);
|
|
Ast_StampExprFile(e.child3, path);
|
|
if e.refBlock != null as *Block {
|
|
Ast_StampBlockFile(e.refBlock, path);
|
|
}
|
|
var args: *ExprList = e.callArgs;
|
|
while args != null as *ExprList {
|
|
Ast_StampExprFile(args.expr, path);
|
|
args = args.next;
|
|
}
|
|
// Match arms (guard lives on Pattern as patGuardExpr when pkGuarded)
|
|
var arm: *MatchArm = e.matchArms;
|
|
while arm != null as *MatchArm {
|
|
Ast_StampExprFile(arm.body, path);
|
|
if arm.pattern != null as *Pattern {
|
|
Ast_StampPatternFile(arm.pattern, path);
|
|
}
|
|
arm = arm.next;
|
|
}
|
|
// Closure default param exprs
|
|
if e.closureParams != null as *Decl {
|
|
var pi: int = 0;
|
|
while pi < e.closureParams.paramCount {
|
|
var p: *Param = null as *Param;
|
|
if pi == 0 { p = &e.closureParams.param0; }
|
|
else if pi == 1 { p = &e.closureParams.param1; }
|
|
else if pi == 2 { p = &e.closureParams.param2; }
|
|
else if pi == 3 { p = &e.closureParams.param3; }
|
|
else if pi == 4 { p = &e.closureParams.param4; }
|
|
else if pi == 5 { p = &e.closureParams.param5; }
|
|
else if pi == 6 { p = &e.closureParams.param6; }
|
|
else if pi == 7 { p = &e.closureParams.param7; }
|
|
else if pi == 8 { p = &e.closureParams.param8; }
|
|
if p != null as *Param && p.defaultExpr != null as *Expr {
|
|
Ast_StampExprFile(p.defaultExpr, path);
|
|
}
|
|
pi = pi + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
func Ast_StampPatternFile(pat: *Pattern, path: String) {
|
|
if pat == null as *Pattern { return; }
|
|
if path == null as String || String_Eq(path, "") { return; }
|
|
if pat.patGuardExpr != null as *Expr {
|
|
Ast_StampExprFile(pat.patGuardExpr, path);
|
|
}
|
|
Ast_StampPatternFile(pat.patChild1, path);
|
|
Ast_StampPatternFile(pat.patChild2, path);
|
|
Ast_StampPatternFile(pat.patArgs, path);
|
|
Ast_StampPatternFile(pat.patNext, path);
|
|
}
|
|
|
|
func Ast_StampBlockFile(b: *Block, path: String) {
|
|
if b == null as *Block { return; }
|
|
if path == null as String || String_Eq(path, "") { return; }
|
|
if b.sourceFile == null as String || String_Eq(b.sourceFile, "") {
|
|
b.sourceFile = path;
|
|
}
|
|
var s: *Stmt = b.firstStmt;
|
|
while s != null as *Stmt {
|
|
Ast_StampStmtFile(s, path);
|
|
s = s.nextStmt;
|
|
}
|
|
}
|
|
|
|
func Ast_StampStmtFile(s: *Stmt, path: String) {
|
|
if s == null as *Stmt { return; }
|
|
if path == null as String || String_Eq(path, "") { return; }
|
|
if s.sourceFile == null as String || String_Eq(s.sourceFile, "") {
|
|
s.sourceFile = path;
|
|
}
|
|
Ast_StampExprFile(s.child1, path);
|
|
Ast_StampExprFile(s.child2, path);
|
|
Ast_StampExprFile(s.child3, path);
|
|
if s.refStmtBlock != null as *Block {
|
|
Ast_StampBlockFile(s.refStmtBlock, path);
|
|
}
|
|
if s.refStmtElse != null as *Block {
|
|
Ast_StampBlockFile(s.refStmtElse, path);
|
|
}
|
|
if s.refStmtDecl != null as *Decl {
|
|
// nested decl inside stmt — body stamp via Decl stamp
|
|
discard;
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Macro / quote hygiene — graft sourceFile onto AST trees
|
|
// ---------------------------------------------------------------------------
|
|
// Stamp* = fill empty only (merge file paths; keep pre-set macro grafts)
|
|
// Graft* = force overwrite (call-site attribution after expansion)
|
|
// Clone* = deep copy for templates
|
|
// Quote* = clone + hygiene policy (def-site keep file | call-site graft)
|
|
|
|
/// Force-set sourceFile on an expression tree (overwrites existing).
|
|
func Ast_GraftExprFile(e: *Expr, path: String) {
|
|
if e == null as *Expr { return; }
|
|
if path == null as String || String_Eq(path, "") { return; }
|
|
e.sourceFile = path;
|
|
Ast_GraftExprFile(e.child1, path);
|
|
Ast_GraftExprFile(e.child2, path);
|
|
Ast_GraftExprFile(e.child3, path);
|
|
if e.refBlock != null as *Block {
|
|
Ast_GraftBlockFile(e.refBlock, path);
|
|
}
|
|
var args: *ExprList = e.callArgs;
|
|
while args != null as *ExprList {
|
|
Ast_GraftExprFile(args.expr, path);
|
|
args = args.next;
|
|
}
|
|
var arm: *MatchArm = e.matchArms;
|
|
while arm != null as *MatchArm {
|
|
Ast_GraftExprFile(arm.body, path);
|
|
if arm.pattern != null as *Pattern {
|
|
Ast_GraftPatternFile(arm.pattern, path);
|
|
}
|
|
arm = arm.next;
|
|
}
|
|
}
|
|
|
|
func Ast_GraftPatternFile(pat: *Pattern, path: String) {
|
|
if pat == null as *Pattern { return; }
|
|
if path == null as String || String_Eq(path, "") { return; }
|
|
if pat.patGuardExpr != null as *Expr {
|
|
Ast_GraftExprFile(pat.patGuardExpr, path);
|
|
}
|
|
Ast_GraftPatternFile(pat.patChild1, path);
|
|
Ast_GraftPatternFile(pat.patChild2, path);
|
|
Ast_GraftPatternFile(pat.patArgs, path);
|
|
Ast_GraftPatternFile(pat.patNext, path);
|
|
}
|
|
|
|
func Ast_GraftBlockFile(b: *Block, path: String) {
|
|
if b == null as *Block { return; }
|
|
if path == null as String || String_Eq(path, "") { return; }
|
|
b.sourceFile = path;
|
|
var s: *Stmt = b.firstStmt;
|
|
while s != null as *Stmt {
|
|
Ast_GraftStmtFile(s, path);
|
|
s = s.nextStmt;
|
|
}
|
|
}
|
|
|
|
func Ast_GraftStmtFile(s: *Stmt, path: String) {
|
|
if s == null as *Stmt { return; }
|
|
if path == null as String || String_Eq(path, "") { return; }
|
|
s.sourceFile = path;
|
|
Ast_GraftExprFile(s.child1, path);
|
|
Ast_GraftExprFile(s.child2, path);
|
|
Ast_GraftExprFile(s.child3, path);
|
|
if s.refStmtBlock != null as *Block {
|
|
Ast_GraftBlockFile(s.refStmtBlock, path);
|
|
}
|
|
if s.refStmtElse != null as *Block {
|
|
Ast_GraftBlockFile(s.refStmtElse, path);
|
|
}
|
|
}
|
|
|
|
/// Set line/column/sourceFile on a single node (no recurse).
|
|
func Ast_SetExprLoc(e: *Expr, line: uint32, col: uint32, path: String) {
|
|
if e == null as *Expr { return; }
|
|
e.line = line;
|
|
e.column = col;
|
|
if path != null as String && !String_Eq(path, "") {
|
|
e.sourceFile = path;
|
|
}
|
|
}
|
|
|
|
func Ast_SetStmtLoc(s: *Stmt, line: uint32, col: uint32, path: String) {
|
|
if s == null as *Stmt { return; }
|
|
s.line = line;
|
|
s.column = col;
|
|
if path != null as String && !String_Eq(path, "") {
|
|
s.sourceFile = path;
|
|
}
|
|
}
|
|
|
|
/// Effective source path for #line / diagnostics (empty if unknown).
|
|
func Ast_ExprSourceFile(e: *Expr) -> String {
|
|
if e == null as *Expr { return ""; }
|
|
if e.sourceFile == null as String { return ""; }
|
|
return e.sourceFile;
|
|
}
|
|
|
|
// Deep clone for quote / macro expansion templates (shares TypeExpr/Decl pointers).
|
|
func Ast_ClonePattern(pat: *Pattern) -> *Pattern {
|
|
if pat == null as *Pattern { return null as *Pattern; }
|
|
let n: *Pattern = bux_alloc(sizeof(Pattern)) as *Pattern;
|
|
n.kind = pat.kind;
|
|
n.line = pat.line;
|
|
n.column = pat.column;
|
|
n.patIdent = pat.patIdent;
|
|
n.patLitKind = pat.patLitKind;
|
|
n.patLitText = pat.patLitText;
|
|
n.patRangeInclusive = pat.patRangeInclusive;
|
|
n.patEnumPath = pat.patEnumPath;
|
|
n.patStructName = pat.patStructName;
|
|
n.patFieldName = pat.patFieldName;
|
|
n.patChild1 = Ast_ClonePattern(pat.patChild1);
|
|
n.patChild2 = Ast_ClonePattern(pat.patChild2);
|
|
n.patArgs = Ast_ClonePattern(pat.patArgs);
|
|
n.patNext = Ast_ClonePattern(pat.patNext);
|
|
n.patGuardExpr = Ast_CloneExpr(pat.patGuardExpr);
|
|
return n;
|
|
}
|
|
|
|
func Ast_CloneExprList(list: *ExprList) -> *ExprList {
|
|
if list == null as *ExprList { return null as *ExprList; }
|
|
let n: *ExprList = bux_alloc(sizeof(ExprList)) as *ExprList;
|
|
n.expr = Ast_CloneExpr(list.expr);
|
|
n.next = Ast_CloneExprList(list.next);
|
|
n.argName = list.argName;
|
|
return n;
|
|
}
|
|
|
|
func Ast_CloneMatchArm(arm: *MatchArm) -> *MatchArm {
|
|
if arm == null as *MatchArm { return null as *MatchArm; }
|
|
let n: *MatchArm = bux_alloc(sizeof(MatchArm)) as *MatchArm;
|
|
n.line = arm.line;
|
|
n.column = arm.column;
|
|
n.pattern = Ast_ClonePattern(arm.pattern);
|
|
n.body = Ast_CloneExpr(arm.body);
|
|
n.next = Ast_CloneMatchArm(arm.next);
|
|
return n;
|
|
}
|
|
|
|
func Ast_CloneExpr(e: *Expr) -> *Expr {
|
|
if e == null as *Expr { return null as *Expr; }
|
|
let n: *Expr = bux_alloc(sizeof(Expr)) as *Expr;
|
|
n.kind = e.kind;
|
|
n.line = e.line;
|
|
n.column = e.column;
|
|
n.sourceFile = e.sourceFile;
|
|
n.strValue = e.strValue;
|
|
n.intValue = e.intValue;
|
|
n.boolValue = e.boolValue;
|
|
n.tokKind = e.tokKind;
|
|
n.tokText = e.tokText;
|
|
n.child1 = Ast_CloneExpr(e.child1);
|
|
n.child2 = Ast_CloneExpr(e.child2);
|
|
n.child3 = Ast_CloneExpr(e.child3);
|
|
n.refType = e.refType; // share TypeExpr
|
|
n.refBlock = Ast_CloneBlock(e.refBlock);
|
|
n.genericCallee = e.genericCallee;
|
|
n.genericTypeArg0 = e.genericTypeArg0;
|
|
n.genericTypeArg1 = e.genericTypeArg1;
|
|
n.genericTypeArgCount = e.genericTypeArgCount;
|
|
n.structName = e.structName;
|
|
n.structFieldCount = e.structFieldCount;
|
|
n.closureParams = e.closureParams; // share param decl
|
|
n.captureCount = e.captureCount;
|
|
n.captureName0 = e.captureName0;
|
|
n.captureName1 = e.captureName1;
|
|
n.captureName2 = e.captureName2;
|
|
n.captureName3 = e.captureName3;
|
|
n.captureName4 = e.captureName4;
|
|
n.captureName5 = e.captureName5;
|
|
n.captureName6 = e.captureName6;
|
|
n.captureName7 = e.captureName7;
|
|
n.captureType0 = e.captureType0;
|
|
n.captureType1 = e.captureType1;
|
|
n.captureType2 = e.captureType2;
|
|
n.captureType3 = e.captureType3;
|
|
n.captureType4 = e.captureType4;
|
|
n.captureType5 = e.captureType5;
|
|
n.captureType6 = e.captureType6;
|
|
n.captureType7 = e.captureType7;
|
|
n.callArgs = Ast_CloneExprList(e.callArgs);
|
|
n.callArgCount = e.callArgCount;
|
|
n.matchArms = Ast_CloneMatchArm(e.matchArms);
|
|
n.matchArmCount = e.matchArmCount;
|
|
return n;
|
|
}
|
|
|
|
func Ast_CloneStmt(s: *Stmt) -> *Stmt {
|
|
if s == null as *Stmt { return null as *Stmt; }
|
|
let n: *Stmt = bux_alloc(sizeof(Stmt)) as *Stmt;
|
|
n.kind = s.kind;
|
|
n.line = s.line;
|
|
n.column = s.column;
|
|
n.sourceFile = s.sourceFile;
|
|
n.strValue = s.strValue;
|
|
n.boolValue = s.boolValue;
|
|
n.child1 = Ast_CloneExpr(s.child1);
|
|
n.child2 = Ast_CloneExpr(s.child2);
|
|
n.child3 = Ast_CloneExpr(s.child3);
|
|
n.refStmtType = s.refStmtType;
|
|
n.refStmtPattern = Ast_ClonePattern(s.refStmtPattern);
|
|
n.refStmtDecl = s.refStmtDecl;
|
|
n.refStmtBlock = Ast_CloneBlock(s.refStmtBlock);
|
|
n.refStmtElse = Ast_CloneBlock(s.refStmtElse);
|
|
n.elseIfCount = s.elseIfCount;
|
|
n.nextStmt = Ast_CloneStmt(s.nextStmt);
|
|
return n;
|
|
}
|
|
|
|
func Ast_CloneBlock(b: *Block) -> *Block {
|
|
if b == null as *Block { return null as *Block; }
|
|
let n: *Block = bux_alloc(sizeof(Block)) as *Block;
|
|
n.line = b.line;
|
|
n.column = b.column;
|
|
n.sourceFile = b.sourceFile;
|
|
n.stmtCount = b.stmtCount;
|
|
n.firstStmt = Ast_CloneStmt(b.firstStmt);
|
|
// Rebuild lastStmt
|
|
var cur: *Stmt = n.firstStmt;
|
|
var last: *Stmt = null as *Stmt;
|
|
while cur != null as *Stmt {
|
|
last = cur;
|
|
cur = cur.nextStmt;
|
|
}
|
|
n.lastStmt = last;
|
|
return n;
|
|
}
|
|
|
|
/// Definition-site quote: clone template, keep sourceFile (macro body locations).
|
|
func Ast_QuoteDefSite(e: *Expr) -> *Expr {
|
|
return Ast_CloneExpr(e);
|
|
}
|
|
|
|
/// Call-site quote: clone template, graft call-site file and span for #line / diags.
|
|
func Ast_QuoteCallSite(e: *Expr, siteFile: String, siteLine: uint32, siteCol: uint32) -> *Expr {
|
|
let n: *Expr = Ast_CloneExpr(e);
|
|
if n == null as *Expr { return null as *Expr; }
|
|
Ast_GraftExprFile(n, siteFile);
|
|
// Root span is the invocation; children keep structure but share site file
|
|
n.line = siteLine;
|
|
n.column = siteCol;
|
|
return n;
|
|
}
|
|
|
|
/// Apply call-site graft to a whole statement tree (for stmt-producing macros).
|
|
func Ast_QuoteStmtCallSite(s: *Stmt, siteFile: String, siteLine: uint32, siteCol: uint32) -> *Stmt {
|
|
let n: *Stmt = Ast_CloneStmt(s);
|
|
if n == null as *Stmt { return null as *Stmt; }
|
|
Ast_GraftStmtFile(n, siteFile);
|
|
n.line = siteLine;
|
|
n.column = siteCol;
|
|
return n;
|
|
}
|
|
|
|
func Ast_MakeDecl(kind: int, line: uint32, col: uint32) -> Decl {
|
|
return Decl { kind: kind, line: line, column: col, isPublic: false,
|
|
sourceFile: "",
|
|
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 };
|
|
}
|
|
}
|