- Auto-drop now only triggers for user-defined types explicitly marked
with @[Drop] on the struct declaration.
- Added move tracking in C backend to skip auto-drop for variables
that have been moved (via let y = x, return x, or assignment).
- Prevents double-free when ownership is transferred.
- Selfhost bootstrap loop verified: C output is deterministic.
- lib/Drop.bux: interface Drop { func Drop(self: *Self); }
- sema.bux: define TypeName_MethodName in scope for impl block methods
so auto-drop (Lcx_BuildAutoDropFree) can find Drop implementations
via extend Type for Drop, not just @[Drop] or standalone functions
- Verified: extend Buffer for Drop auto-calls Buffer_Drop in @[Checked]
- ast.bux: add isDrop field to Decl
- parser.bux: parse @[Drop] attribute and attach to struct Decls
- hir_lower.bux: auto-drop now looks for TypeName_Drop for any type
- Test: _test_drop_user verifies Buffer_Drop is auto-called
- Auto-register func Type_Method(self: T, ...) as methods in sema.
- Add method table lookup for binary operators in sema.bux ekBinary.
- Add method table lookup for operator_index_get in sema.bux ekIndex.
- Add HIR lowering for binary operators to method calls in hir_lower.bux.
- Add HIR lowering for operator_index_get/set in hir_lower.bux.
- Set expr.refType for overloaded operators so chained ops work.
- Fix hir_lower.bux to recognize Array_int/Iter_string etc. in for-in loops
by checking Array_/Iter_ prefix outside the empty-elemTypeName branch.
- Update all golden expected.c files to include duplicate bux_bounds_check
declaration (matches actual C codegen).
- Remove duplicate Drop trait item from ROADMAP.md.
- Add lib/Slice.bux with Slice<T> generic struct
- Fix C backend to recognize Slice/Slice* as generic types
- Use var instead of let for uninitialized Slice<T> locals
- Selfhost loop passes, tests pass
In @[Checked] functions, variables of type Array<T> automatically get
a defer Array_Free_T(&var) injected at declaration site. This ensures
Array values are freed when they go out of scope, preventing leaks.
Implementation:
- HIR lowering detects Array_<T> types in skLet statements
- Generates Array_Free_T generic instance if needed
- Builds synthetic defer node: defer Array_Free_T(&var)
- Wraps let+defer in hBlock for proper statement chaining
Also adds checkedFunc flag to HirFunc and CEmitter for future use.
Mark as done:
- for x in collection iterator loops
- Trait bounds (T: Comparable)
- CTFE (compile-time const evaluation)
- Selfhost bootstrap loop (deterministic C output)
- Implicit generic type argument inference
- cli: buxc2 build now delegates to Cli_BuildProject for src/Main.bux,
enabling stdlib merging (Array_Iter, Iter_HasNext, etc. available)
- sema: set expr.refType on ekCall from function return type
(needed for for-loop type extraction from MakeArr()-style expressions)
- hir_lower: remove ekIdent restriction on collection-based for loops
- supports arbitrary expressions: for x in MakeArr() { ... }
- creates temp variable __tmp_coll_N for non-identifier iterators
- generates proper Array_T struct instances for temp variables
- Test: for x in MakeArr() sums [10,20,30] → 60
- Selfhost loop: C output IDENTICAL
- parser: extend-for only linked first 2 methods; now uses lastMethod pointer
- sema: trait bounds checking was after indirect-call early return (tyFunc path),
so Max<Circle>(...) skipped bounds check when callee had tekFunc refType.
Moved bounds check before both indirect/direct call returns.
- Negative test: Circle without Comparable impl now correctly errors.
- Selfhost loop: C output IDENTICAL.
- Fix Fmt_Format name conflict between lib/Fmt.bux and src/fmt.bux
by renaming selfhost formatter function to Fmt_FormatSource.
- Fix collection-based for-in loops to handle already-monomorphized
types like Array_int and Iter_string (typeArgCount=0 cases).
- Fix ekSizeOf and ekCast in HIR lowering to apply Lcx_SubstituteType
during generic monomorphization, so sizeof(T) and *T casts emit
correct concrete types in C output.
- Fix sema to infer stmt.refStmtType from initializer expression
when no explicit type annotation is given, ensuring C backend
emits correct pointer types for let data = ... as *T.
- Fix nested Lcx_GenerateStructInstance overwriting parent slot by
incrementing structCount BEFORE field processing
- Fix Lcx_LowerModule to skip generic structs from hm.structs (was missing
continue due to bootstrap compiler codegen limitation)
- Fix C backend to forward-declare ALL structs at top, removing second
generic-only forward declaration section that came too late
- Add empty-name guard in CBE_EmitStructDef
- Import system: parser supports ::* glob imports, sema two-pass resolution
- Add on-demand generic function/struct monomorphization in HIR lower
- Lcx_SubstituteType: substitute type params and mangle names (e.g. Array<int> -> Array_int)
- Lcx_GenerateFuncInstance: clone generic func with active substitution
- Lcx_GenerateStructInstance: create concrete struct definitions
- Detect generic calls (ekCall) and struct inits (ekStructInit)
- Parser: propagate generic type args from ident to ekStructInit node
- Fix duplicate HIR constant: hIndexPtr and hCall both had value 18,
causing index expressions to emit as comma expressions in C backend
- Implement collection-based for-in desugaring:
for x in arr { body } -> __iter = Array_Iter_T(&arr);
while Iter_HasNext_T(&__iter) { x = Iter_Next_T(&__iter); body }
Selfhost loop remains deterministic. All golden tests and examples pass.
- Parser: add parseRange for selfhost (.. / ..=)
- Sema: determine loop variable type from range bounds
- HIR Lower: desugar range for-in to while loop with counter
- Bootstrap sema: fix range-based for variable type (was unknown)
- Selfhost loop remains deterministic
- Mark capture-less closures as ✅ Done in ROADMAP
- Add closure syntax examples to LanguageRef.md Functions section
- Update PHASE8_STRATEGY.md Milestone A with closures
Implement MVP closures — anonymous functions without captures.
Syntax:
|a: int, b: int| -> int { return a + b; }
Changes:
- ast.bux + ast.nim: add ekClosure AST node
- parser.bux + parser.nim: parse |params| -> Ret { body }
- sema.bux + sema.nim: type-check closure params/body, return tyFunc
- hir_lower.bux + hir_lower.nim: generate __closure_N function + hAddrOf
- lir_c_backend.nim: fix function-pointer variable declaration (cParamDecl)
- C backend: closures compile to global functions with unique names
Test: _test_closure/src/Main.bux
- Closure as variable
- Closure passed to higher-order function
- Address of named function as function pointer
Both bootstrap and selfhost compilers build and pass the test.
Updated documentation to reflect changes from the last 2 days:
ROADMAP.md:
- Mark string interpolation, named/default params, bux fmt/test/new/init,
and basic borrow checker as ✅ Done
- Update Recommended Order (next: closures)
PHASE8_STRATEGY.md:
- Update date, achievements, and milestone statuses
- Borrow checker is now ✅ working in selfhost
- CTFE, LSP, formatter, test runner marked done where applicable
LanguageRef.md:
- Add defer, switch/case, string interpolation (f"...")
- Add &T, &mut T, own T to composite types
- Add named/default parameters and operator overloading sections
- Expand @[Checked] rules with double-mut-borrow and use-after-move
- Update keywords and operators
STRATEGY.md:
- Update date and version (0.3.0 selfhost)
- Mark 8.2 borrow checker, 8.4 CTFE, 8.7 LSP as ✅
BuildAndTest.md:
- Add bux init, bux fmt, bux test commands
- Expand test sections with golden tests and Std::Test
Line-based indentation formatter that:
- Adjusts indentation based on { } brace depth (4 spaces)
- Preserves original line structure and comments
- Skips braces inside string/char literals and // comments
- Handles } at line start and mixed brace lines
- 'bux fmt <file>' formats a single file
- 'bux fmt <dir>' formats all .bux files in directory
- Add inline movedName0..7 fields to Sema (avoids dynamic allocation issues)
- Sema_AddMoved: track variable moves from let/var init expressions
- Sema_IsMoved: check if variable was moved before use
- Sema_RemoveMoved: clear moved status on reinitialization (x = value)
- Report 'use of moved value' error for moved variable access
Detect when the same variable is passed as &mut argument twice
in a single function call (e.g. Swap(&x, &x)) inside checked functions.
Matches bootstrap sema.nim behavior (lines 1078-1089).
- Add tekRef and tekMutRef to TypeExpr enum (ast.bux)
- Parse &T and &mut T in parserParseType, before *T handling (parser.bux)
- Map tekRef/tekMutRef to tyPointer in HIR lowering (hir_lower.bux)
- Both emit as T* in C backend (same as raw pointer)
- Borrow checker rejects write-through-pointer in @[Checked] functions
for all pointer types (safe default)
- Add isChecked field to Decl struct (ast.bux)
- Parse @[Checked] attribute in parserParseDecl (parser.bux)
- Add checkedFunc flag and movedVars to Sema struct (sema.bux)
- Enable borrow checking per-function in Sema_Analyze
- Reject assignment through raw pointer (*T) in @[Checked] functions
- Skip newlines between @[Checked] attribute and the declaration keyword
to avoid parser seeing the attribute and function as separate decls
- 'bux test [dir]' builds the project and runs the resulting binary,
reporting 'Tests passed' or 'Tests failed (exit code N)'.
- Builds on existing Cli_BuildProject pipeline — test code goes in
src/ alongside production code; test assertions use lib/Test.bux.
- 'buxc new <name>': creates a new Bux project directory with bux.toml
and src/Main.bux. Supports both relative names and absolute paths.
- 'buxc init': initializes a Bux project in the current directory.
- Adds extern bux_getcwd() and bux_path_parent() declarations.
- Fix mkdir return value check (bux_mkdir_if_needed returns 0 on success).
- Extract package name from path for absolute path arguments.
Add golden tests for: structs, generics, algebraic_enums, enums,
methods, strings. Each test captures the expected C output from the
bootstrap compiler for regression detection.
Also remove leftover 'PARSER FIX V2 ACTIVE' debug print from parser.bux.
- Create child scope in Sema_CheckBlock for every block, matching
bootstrap sema.nim behavior (newScope for ekBlock).
- Fixes "var scoping bug in selfhost sema" where variables declared
with var inside if/while blocks shared parent function scope, causing
duplicate-definition errors between sibling if/else blocks, and C
scoping mismatch between user variables and compiled output.
- Remove stale workaround comments from lib/Json.bux (let instead of
var inside if blocks — no longer needed).
- Update sema.bux TODO comment for type table.
- Remove DEBUG prints from c_backend.bux, hir_lower.bux, lexer.bux, parser.bux
- Remove HACK for stray } in parserParseFuncDecl (no longer needed after
Decl refactor in 4a86009)
- Clean selfhost check/build output
- Replace Decl's 256 inline struct fields with dynamic fields: *StructField
array to avoid parser field limit truncation and name shifts.
- Update parser.bux and hir_lower.bux to use decl.fields[i].
- Fix uninitialized Symbol.refType in three stack-allocated Symbol sites:
loopSym (for-loop iterator), vSym (enum variants), and HIR param sym.
Garbage refType values (e.g. 0xFF) were leaking into scope tables,
later copied to expr->refType, causing SIGSEGV in Lcx_LowerExpr.
- Add tekFunc AST node and TypeExprList linked list for params
- Parse func(T, U) -> R syntax in parser.bux
- Resolve tekFunc to tyFunc in sema.bux
- Track original TypeExpr via Symbol.refType for params/lets/consts/funcs
- Build C function-pointer type names in hir_lower.bux (Ret (*)(Params))
- Lower indirect calls through function-typed values as hCallIndirect
- Add CBE_CParamDecl helper in c_backend.bux to embed name inside (*)
- Emit hCallIndirect and function-pointer variable declarations
- _test_funcptr now builds and runs with selfhost buxc2
- Add tekFunc AST node and parser support for func(Params) -> Ret
- Add tkFunc type resolution in sema and hir_lower
- Add &FuncName address-taking yielding tkMutRef(tkFunc)
- Fix C emission: function pointer params use Ret (*name)(Params) syntax
via cParamDecl helper that embeds the name inside (*)
- Fix forward declarations and temp declarations for function pointers
- Add funcPtrTypes table in C backend so &Fn temps get proper type
- Add _test_funcptr integration test
Bootstrap compiler:
- ast.nim: add exprCallArgNames to ekCall for named arg tracking
- parser.nim: detect name: value syntax in call args
- sema.nim: add resolveCallArgs helper that injects default values
for missing params and reorders named args into param order.
Parser already parsed default param values; sema now uses them.
Selfhost compiler:
- ast.bux: add defaultExpr to Param, argName to ExprList
- parser.bux: parse = defaultExpr in param list, detect name: value
syntax in call arguments
- sema.bux: add Sema_ResolveCallArgs with same logic as bootstrap
Tests:
- _test_named_params verifies defaults, named args, mixed positional+named,
and named args with defaults in both compilers.
All verifications pass: build, selfhost-loop, test-examples, test-golden.
- Add operatorMethodName mapping (tkPlus -> operator_add, etc.)
- Add tryLowerOperatorCall / tryLowerIndexCall in HIR lowerer
- Modify ekBinary lowering to check method table before builtins
- Modify ekAssign lowering to detect ekIndex target and emit
operator_index_set method call when available
- Add sema type-checking for operator overloads in ekBinary
and ekIndex paths (method-table lookup before builtin rules)
- Fix sema compile errors: minfo.params[N].typ -> minfo.params[N]
- Fix hir_lower forward decl ordering for resolveExprType
- Update golden test expected.c files for current C backend
- Update ROADMAP.md and PHASE8_STRATEGY.md status
- Add syntax
- Desugars to if-else chain in HIR lowering (both compilers)
- No new HIR/C backend nodes needed — reuses hIf/hBinary/hBlock
- Supports integer, char, and enum tag dispatch
- Case body can be single statement (no braces required)