Files
bux-lang/src/ast.bux
T
dimgigov 6f2a3b1d88
ci / make test (push) Has been cancelled
selfhost-loop / bootstrap determinism (push) Has been cancelled
feat(selfhost): quote/graft hygiene API for macros and mono
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.
2026-07-20 00:31:23 +03:00

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 };
}
}