53b43b0f79
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.
28 KiB
28 KiB
Bux — План към „добър“ език (v0.5 → v1.0)
Дата: 2026-07-18
Текущо: v0.5.x — selfhost, C.1, tooling, LSP 0.4, full-tree fmt, package registry (E.1) ✅
Цел: Език, с който се пишат реални проекти комфортно, безопасно (по избор) и с надежден toolchain.
Диагноза (къде сме)
| Слой | Състояние | Оценка |
|---|---|---|
| Frontend (lex/parse) | Пълен Pratt parser, recovery | ★★★★☆ |
| Sema / generics | Monomorphization, trait bounds basic | ★★★★☆ |
| HIR → C | Tuples + fat func ABI в bootstrap и selfhost |
★★★★☆ |
Selfhost (src/) |
~12k LOC, binary-identical loop, closures+tuples | ★★★★★ |
| Gradual ownership | @[Checked], &/&mut, move, Drop, lifetime elision |
★★★★☆ |
| Concurrency | M:N tasks + channels + async | ★★★★☆ |
| Stdlib | Array/Map/Set/String/Iter HOF разширени | ★★★★☆ |
| Tooling | test-errors, LSP diagnostics + hover/def/outline |
★★★★☆ |
| Ecosystem / registry | path+git + file registry index (bux search/add) |
★★★☆☆ |
| Документация | README + QUALITY_PLAN синхронизирани (2026-07-15) | ★★★★☆ |
Силна ниша: gradual ownership (C-скорост на писане + opt-in Rust-safety).
Слабо място: ergonomics на stdlib + maturity на tooling + пълнота на borrow checker.
Какво значи „добър“ за Bux
- Ежедневен DX — колекции, string, assert, грешки, които разбираш за секунди.
- Предвидима безопасност —
@[Checked]да хваща 80% от UAF/double-borrow без lifetime hell. - Selfhost като dogfood — компилаторът и apps (
nexus,boko) са proof. - Инструменти — fmt, test, LSP, package install без ръчна магия.
- Стабилна спецификация — LanguageRef = реалното поведение.
Не целим „по-добър Rust“. Целим единствения език с gradual safety + Go-стил concurrency без GC.
Фази
A — Ergonomics & Stdlib (P0) ✅ (core done)
| # | Задача | Защо | Статус |
|---|---|---|---|
| A.1 | Array: Pop, Clear, IsEmpty, First, Last, Cap, Reserve | Без това колекциите са неудобни | ✅ (тази сесия) |
| A.2 | String: IsEmpty, ReplaceAll | Чести операции; само first-replace досега | ✅ (тази сесия) |
| A.3 | Os_Exit + Test_AssertEqString / richer asserts | Тестове и CLI без raw bux_exit |
✅ (тази сесия) |
| A.4 | Map_Remove / Set polish | Completeness на колекциите | ✅ (тази сесия) |
| A.5 | Iter: map/filter/fold върху closures | Higher-order без boilerplate | ✅ generic Iter_Map/Filter/Fold + Int aliases |
| A.6 | Result helpers: Expect, UnwrapErr, Or | По-малко match boilerplate | ✅ (тази сесия) |
B — Compiler Correctness (P0)
| # | Задача | Защо | Статус |
|---|---|---|---|
| B.1 | Proper tuple types в C backend | (T,U) → Tuple_T_U struct + .0/.1 |
✅ bootstrap + selfhost |
| B.2 | Function pointer types | func(T)->U fat ABI |
✅ bootstrap + selfhost |
| B.3 | Match expression lowering (literals, ranges, enums) | Expression-context match → if-else | ✅ bootstrap + selfhost |
| B.3b | Pattern bindings (Some(value) => value) |
Payload idents bound in arm body | ✅ bootstrap + selfhost |
| B.3c | Match arm guards (p if cond => …) |
Bindings visible in guard; sequential found-flag lower | ✅ bootstrap + selfhost |
| B.4 | Closures multi-instance | Fat BuxFn + heap env |
✅ bootstrap + selfhost |
| B.4b | Closures: || empty params + loop/return body |
Lexer || vs empty closure; while/break/return |
✅ bootstrap + selfhost |
| B.5 | По-добри diagnostics (snippet + hint) | DX #1 за нови потребители | ✅ |
| B.6 | Bootstrap ↔ selfhost feature parity | empty ||, match-as-expr, string interp f"..." bootstrap+selfhost |
✅ |
C — Gradual Ownership 2.0 (P1)
| # | Задача | Защо | Статус |
|---|---|---|---|
| C.1 | Lifetime elision за common cases | Без 'a в 90% от API-тата |
✅ bootstrap + selfhost |
| C.2 | Exclusive &mut vs shared & data-flow |
По-малко false negatives | ✅ let-bound + use-while + call conflict |
| C.3 | Auto-drop edge cases (early return, branches) | RAII да е надежден | ✅ bootstrap + selfhost |
| C.4 | @[Release] zero-cost path документация + golden tests |
Killer story: safe default, free hot path | ✅ partial (unchecked path + goldens) |
D — Tooling (P1)
| # | Задача | Защо | Статус |
|---|---|---|---|
| D.1 | LSP: hover, go-to-def, diagnostics | IDE = adoption | ✅ v0.4.0: position-sensitive locals + inferred let + sema hover |
| D.2 | bux fmt стабилен + CI check |
Единен style | ✅ full-tree format + make fmt-check enforce |
| D.3 | bux test с --filter, exit codes, summary table |
CI-friendly | ✅ --filter / summary / exit 0|1 |
| D.4 | bux doc от /// comments |
Самодокументиращ се stdlib | ✅ bootstrap+selfhost + make docs |
| D.5 | Golden tests за stdlib modules | Регресии без изненади | ✅ tests/stdlib_golden/ + make test-stdlib |
E — Ecosystem & v1.0 (P2)
| # | Задача | Защо | Статус |
|---|---|---|---|
| E.1 | Package registry protocol (git/HTTP) | bux add foo без path hacks |
✅ local index + file/git sources + search |
| E.2 | 3–5 production-quality apps в apps/ |
Showcase | ⏳ partial (nexus, boko, simpledb, jwt-pitbul) |
| E.3 | Language freeze + semver policy | Trust | ✅ draft docs/SEMVER.md |
| E.4 | Debugger/DWARF basics | Systems audience | ⏳ |
| E.5 | Benchmarks vs C/Zig/Nim (micro + nexus) | Marketing + regression | ⏳ |
Препоръчан ред на работа
A (stdlib ergonomics) → B (compiler holes) → C (ownership depth)
↓ ↓
D (tooling) ←────────── dogfood apps
↓
E (v1.0 ecosystem)
Правило: всяка сесия ship-ва нещо runnable (stdlib API, fix, example), не само docs.
Acceptance criteria за „добър v1.0“
- Всички examples + selfhost-loop + 3 apps минават на CI
- Array/Map/String/Test API покрива 90% от ежедневните нужди
@[Checked]хваща use-after-move + double&mut+ dangling return / elision failbux test+bux fmt+bux checkса default developer loop (--filter/--checkshipped)- LanguageRef синхронизиран с компилатора (incl. C.1 elision)
- Поне един външен/temp проект build-ва с registry dep (
tools/smoke_registry.sh)
Сесия 1 (stdlib ergonomics)
Array_Pop,Array_Clear,Array_IsEmpty,Array_First,Array_Last,Array_Cap,Array_ReserveString_IsEmpty,String_ReplaceAllOs_ExitTest_AssertEqString,Test_AssertNeqInt,Test_AssertEqBool- Example + docs update
Сесия 2 (collections + tuples)
Map_Remove/Map_Clear/Map_IsEmpty(+ StringMap)Set_Remove/Set_Clear/Set_IsEmptyResult_Expect/Result_UnwrapErr/Result_OrOption_Expect/Option_Or- Tuples:
(T, U)→typedef struct { T _0; U _1; } Tuple_T_U+ field access.0/.1 - Examples:
tuples,func_ptr,map_remove
Сесия 3 (diagnostics + collections)
- Rust-style errors in bootstrap CLI:
--> file:line:col, source snippet,^caret,= help:hints SourceLocation.filepropagated from lexer- Better caret for type-mismatch on
let(points at initializer) Array_Contains/Array_IndexOf/Array_ExtendIter_AnyEq/Iter_AllEq/Iter_Collect- Selfhost
Diagnostic_Hintfor common messages
Сесия 4 (diagnostics depth + LSP + strings)
- Multi-char underlines (
^^^^^^^under tokens/strings/idents) - Quoted-name highlighting for
undeclared identifier 'x' - Golden error tests (
tests/error_golden/,make test-errors) - LSP runs
buxc checkand publishes real diagnostics String_IsBlank/String_Repeat
Сесия 5 (multi-instance closures)
- Fat function pointers for all
func(...)types:BuxFn { code(env, args...), env } - Capturing closures: heap-allocate env per creation site (independent instances)
- Capture-less closures + named funcs: adapters with
env = NULL - Calls through func values:
f.code(f.env, args...) - Example
multi_closure.bux— MakeAdder(10)/MakeAdder(20) yield 11 and 21 - Selfhost parity: same fat ABI in
src/hir_lower.bux+src/c_backend.bux(makers, adapters)
Сесия 6 (selfhost tuples)
- Parser:
(T, U)types,(a, b)exprs, field access.0/.1 - Sema: tekTuple / ekTuple
- HIR lower →
hStructInitofTuple_int_int - C backend:
typedef struct Tuple_int_int { int _0; int _1; } - Verified with
buxc2onexamples/tuples.bux
Сесия 7 (Iter HOF)
Iter_MapInt/FilterInt/FoldInt/ForEachInt/AnyInt/AllInt/SumInt- Named funcs + capturing closures (fat ABI)
- Example
iter_hof.bux(sum=15, product=120) - Selfhost fix: pointer
->field access; no bogus bounds check onarr.data[len](Push)
Сесия 8 (match expression + error goldens)
- Match expression lowering (B.3):
pkLiteral,pkRange(a..b/a..=b), enum tags, wildcard- Bugfix: literal arms were always-true (
elsebranch) →match 1 { 1=>10, 2=>20 }returned 10 for all skMatchnow also lowers vialowerMatch(void result)
- Bugfix: literal arms were always-true (
- Expanded
examples/pattern_matching.bux(enums + classify ranges + string arms) - Error golden cases (
tests/error_golden/):parse_error— incompletelet x = ;use_after_move—@[Checked]+own Stringdouble_mut_borrow— two&mutof same var
run.shnormalize: absolute paths in "parse errors in …" lines
Сесия 9 (selfhost match — B.6 parity)
- AST:
MatchArmlinked list;Pattern.patChild1/2for ranges;Expr.matchArms - Parser: full
parserParsePattern/parserParseMatchExpr(was skip-arms stub)- literals,
_, ident,Enum::Variant/Enum::Variant(...), ranges - statement
match→skExpr+ekMatch
- literals,
- Sema: type-check subject + arms; propagate first-arm type to
expr.refType - HIR lower:
Lcx_LowerMatch→ alloca result + if-else stores (enum.tag/ simple / literal / range) - Last-expr return:
Lcx_LowerBlockconverts finalskExprintoreturn(needed forfunc F() -> T { match ... }) - Verified:
pattern_matchingvia buxc2; simple enum + ranges; selfhost-loop IDENTICAL ✓
Сесия 10 (pattern bindings — B.3b)
- Bootstrap sema:
extractPatternBindingsresolves enum payload field types from variant decl - Bootstrap HIR:
matchPatternBindings→alloca name; name = subject.data.Variant_ibefore arm body - Match result type: fall back to
currentFuncRetTypewhen arm bodies only use bindings - Multi-field enum layout: positional
fields.len > 1→ nested struct in_Dataunion (no overlay) - Selfhost: parse
patArgslinked list;Sema_BindPattern;Lcx_PatternBindingsin match arms - Example:
pattern_matching.buxusesOption::Some(value) => value(real binding, notopt.data.Some_0) - Verified: bootstrap + buxc2 + all examples + error goldens + selfhost-loop IDENTICAL ✓
Сесия 11 (empty || closures + match-as-expr — B.4b)
- Bug:
|| -> int { ... }lexed astkPipePipe(logical-or), not twotkPipe→ empty-param closures failed to parse - Fix bootstrap: primary
of tkPipePipe:→ zero-paramekClosure - Fix selfhost:
parserParseEmptyClosurefortkPipePipe - Match-as-expr: expression-form match now skips newlines (same as statement form) →
let x = match n { ... }works - Verified control-flow in closure body: while/break, early return from loop, multi-return if-chain
- Pattern bind reuse: one alloca per binding name per function (
patternBoundNames) so two matches can both usev - Selfhost match-as-expr: let-init + binary operands expand yield blocks (
Lcx_IsMatchYield/__binop_N) - Examples:
closure_control.bux,match_let.bux - Verified: bootstrap + buxc2 + all examples + error goldens + selfhost-loop IDENTICAL ✓
Сесия 12 (string interpolation selfhost — B.6)
- Selfhost parser:
parserParseStringInterp— interleaved lit/expr parts incallArgs, nested fragment parse viaLexer_Tokenize+ sub-parser - Selfhost sema/HIR:
ekStringInterp→String_Concat+String_FromInt/FromBool/FromFloat - Bootstrap fix:
f"plain"no longer keeps thefprefix in the literal;\{/\}preserved by lexer and unescaped by interp parser - Lexer:
\{/\}allowed (bootstrap + selfhost) so LanguageRef escape rules work - Compiler hygiene: original dense
&&/||in the large interp loop caused bootstrap OOM (~27 GB) when compilingparser.bux— rewrite with simpler control flow - Example:
examples/string_interp.bux(name/int/bool/plain/escaped braces) - Verified: bootstrap + buxc2 + all 41 examples + error goldens + selfhost-loop IDENTICAL ✓
Сесия 13 (LSP hover / go-to-def / outline — D.1)
- Richer symbol index:
funcsignatures (params+-> Ret),let/var/constwith types,struct/enum/union/interface/type/module - Skip comments/strings during scan (no false
funchits) - Hover: markdown
bux signature+ kind; accurate word range - Go-to-definition: current file + workspace index (scan
.buxunder rootUri) - Document symbols (outline) via
textDocument/documentSymbol - didChange refreshes symbols immediately; didSave/didOpen still run
buxc checkdiagnostics - Fix: responses write to stdout (was writing to stdin stream → broken pipe)
- Version
bux-lsp0.2.0; smoke-tested via JSON-RPC
Сесия 14 (generic Iter map/filter/fold)
Iter_Map<T,U>/Filter<T>/Fold<T,Acc>/Any/All/ForEach— fatfuncparams + monomorphization- Int aliases keep working:
Iter_MapInt→Iter_Map<int,int>, … - Bootstrap fixes:
- call return type for local fat-func (
f: func(T)->U) after mono (was alwaysint→ String map truncated pointers) - generic call
Foo<T>(…)now type-checks args (closures get capture analysis)
- call return type for local fat-func (
- Selfhost fixes:
Lcx_SubstituteTyperecurses intotekFunc(was leavingBuxFn_U_T)- fat typedef emit covers cstr shapes +
#ifndefguards
- Example:
examples/iter_generic.bux(int↔String map, filter, fold, closures) - Verified: bootstrap + buxc2 + selfhost-loop IDENTICAL ✓
Сесия 15 (struct/tuple patterns)
- Tuple patterns:
match t { (a, b) => a + b }— bindsubject._0/._1 - Struct patterns:
Point { x: px, y: py }+ shorthandPoint { x, y } - Bootstrap:
matchPatternBindingsfor pkTuple/pkStruct; field types from struct decl; range registration of local tuple typedefs - Selfhost: parse
()/Name { … }patterns;Sema_BindPattern+Lcx_PatternBindingswith Scope_Define - Fix: operator-overload path treated
String_Eq(null, "")as non-empty → crash ona + bafter pattern bind - Example:
examples/struct_tuple_pat.bux - Verified: bootstrap + buxc2 + selfhost-loop IDENTICAL ✓
Сесия 16 (match block arms + block expressions)
- Block-as-expression:
let r = { let x = 1; x + 2 }— last skExpr is the value - Multi-stmt match arms:
1 => { PrintLine("…"); let a = 10; a + 1 } - Bootstrap:
lowerBlock(..., asExpr)promotes last expression; nested enum/struct pattern bindings - Selfhost: parse
{ … }asekBlock; yield temps__blk_N; fixIsMatchYieldnull-strValue false positive; retTypeKind-2for expr blocks - Nested:
Shape::Dot(Point { x, y })works on bootstrap; selfhost covers struct/tuple/enum + block arms - Example:
examples/match_block.bux - Verified: bootstrap + buxc2 + selfhost-loop IDENTICAL ✓
Сесия 17 (deeper nested patterns + multi-field enum layout)
- Multi-field payload type: nested struct
Enum_Variant_Payload(suffix avoids clash with tagEnum_Variant) - Bootstrap: full
resolveTypeExprfor enum field types (tuples/pointers); sema synthetic field lookup on payload types;data.Two.Two_0construction - LIR C backend: emit tuple typedefs before enums that embed them; topo deps for
*_Payload - Selfhost: enum variants parse full types (
parserParseType) — fixesVal((int,int)); storefieldTypeName*; structs before enums (e.g.Dot(Point)) - Patterns:
Pair::Two(a, b),Box::Val((a, c)),Shape::Dot(Point { x, y })+ block arms - Example:
examples/nested_patterns.bux - Verified: bootstrap + buxc2 + selfhost-loop IDENTICAL ✓
Сесия 18 (match arm guards — B.3c)
- Syntax:
p if cond => body(also after ranges:1..10 if x % 2 == 0) - Parser fix (critical):
isTypeArgListAheadtreatedx < 0as generic when a laterx > 0existed in another arm → infinite parse. Stop lookahead on=>, keywords, literals, arithmetic, comparisons. - Sema: bind inner pattern first; type-check guard as bool in arm scope
- HIR lower: sequential
foundflag (no shared if-else DAG):Bindings are in scope for the guard expression.if (!found) { if (inner_cond) { binds; if (guard) { result = body; found = true; } } } - Selfhost:
pkGuarded+patGuardExpr; same lower strategy; fixreturn match {…}to expand yield block before return - Example:
examples/match_guards.bux(ident/literal/range/enum payload guards) - Verified: bootstrap + buxc2 + all examples + error goldens + selfhost-loop IDENTICAL ✓
Сесия 19 (generic HOF type inference)
- Bootstrap
inferTypeArgs: structural unify of param TypeExpr vs arg Type*Iter<T>/*Array<T>→ extract T from pointee type args or mangledArray_intfunc(T)->U→ bind T/U from function-value type (not whole func as T)- bare
Accfrom init; multi-paramIter_Fold<T,Acc>
- Selfhost: improved
Sema_InferGenericArgs+ return-type subst after inference- Fix:
ekCastmust type-check operand (was skipping → no inference underas) - HIR fallback mono from first *Array/*Iter arg when count=0
- Fix:
- Works without explicit type args:
Array_Push(&nums, 1),Array_Get,Array_Len,Array_IterIter_Map(&it, f),Iter_Filter,Iter_Fold,Iter_Any(int↔String)
- Example:
examples/generic_infer_hof.bux - Verified: bootstrap + buxc2 + all examples + selfhost-loop IDENTICAL ✓
Сесия 20 (LSP hover from real sema — D.1)
bux-lsp0.3.0 links bootstrap (--path:../bootstrap) and runsanalyzeFullon open/save- typeIndex: global scope (stdlib + file) → hover signatures with real types
- File-local priority: user decls override stdlib name collisions (
Max<T>vsMath.Max) - Locals: walk function bodies for
let/varwith explicit type annotations - didChange: fast lightweight rescan; keeps previous typeIndex until save/hover refresh
- Hover shows
bux signature+_kind_ · sema - Smoke:
Main() -> int,PrintLine(String) -> void,Max<T>(a: T, b: T) -> T
Сесия 21 (pattern binding shadowing)
- Problem: C/LIR function-scoped locals — nested
Some(n) => match … Some(n)emitted store beforeint n, andlet v+ patternvcaused redeclaration. - Bootstrap: every pattern binding → unique C name
__pN_srcviapatternRenamesmap; body/guard idents rewritten; binds before body lower insidelowerMatch. - Selfhost: same model —
Lcx_BindPatIdent+patMapFrom/Torename table; arm-scoped push/pop of map. - Semantics: nested pattern name shadows correctly; outer
let vsurvives after match that bindsv. - Example:
examples/pattern_shadow.bux - Verified: bootstrap + buxc2 + all examples + selfhost-loop IDENTICAL ✓
Сесия 22 (Ownership 2.0 — C.2 + C.4 + *p= fix)
- C.2 Exclusive &mut data-flow (
@[Checked]):- Track long-lived let-bound borrows (
activeMutBorrows/activeSharedBorrows) - Reject: second
&mut x, use/assign ofxwhile mutably borrowed,&xwhile&mutlive - Call-site temps conflict with existing let-bound borrows
- Track long-lived let-bound borrows (
- C.4 Golden tests:
tests/error_golden/exclusive_mut_let/tests/error_golden/use_while_mut_borrow/
- Bugfix:
*p = exprnow stores through the pointer (was assigning to a temp) — ownership examples finally mutate correctly - Example:
examples/ownership_checked.bux(unchecked zero-cost + checked OK path) - Verified: 7 error goldens + borrow_test + all examples + selfhost-loop
Сесия 23 (Ownership 2.0 — C.3 auto-drop early return / branches)
- Bootstrap auto-drop for
@[Drop]+ collections:- Parser:
@[Drop]/@[Release]on structs and funcs (declAttrs) autoDropFuncName+ monomorphizeArray_Drop/Free(etc.) so stdlib links- Inject
Type_Drop(&x)onletviadeferStmts
- Parser:
- Early return / multi-path:
- Every
returnsnapshots the full live defer stack (no clear-after-first-return) - Materialize return value before Drop (
return a.idis not use-after-drop) - Move-on-return: skip Drop for a local returned by value (
return out)
- Every
- Branch / loop scopes:
- Bootstrap:
lowerBlockscopesdeferStmts— branch-local drops at block exit; siblings do not see each other - Selfhost C backend:
CBE_EmitDeferskeeps stack for multi-return;CBE_EmitAndPopDefersFrompops branch/loop locals afterif/while/loop
- Bootstrap:
- Selfhost fixes: null-safe ret type; temp name counter; use function
retTypeNamefor__retdrop_N - Example:
examples/drop_early_return.bux(Early + Branched + Scoped → 5 drops) - Verified: bootstrap + buxc2 drop tests, 7 error goldens, key examples, selfhost-loop IDENTICAL ✓
Сесия 24 (tooling — D.2 fmt --check + D.3 test --filter)
- Bootstrap
bux fmt(bootstrap/fmt.nim):- Indent-by-brace-depth formatter (parity with
src/fmt.bux) bux fmt [path...]writes;bux fmt --checkexits 1 if any file would change- Collects single file or recursive
.buxunder directories
- Indent-by-brace-depth formatter (parity with
- Bootstrap
bux test --filter:--filter <s>/--filter=<s>— only runtests/*.buxwhose name containss- Summary table (
PASS/FAIL[:code]) +Results: N passed, M failed, T total - Exit
0all pass,1failures or no match
- Selfhost parity (
src/cli.bux,src/fmt.bux):Fmt_WouldChange/Fmt_CheckFile;Cli_Fmt(dir, checkOnly)Cli_Test(dir, filter)with summary + skip count; filter skips Main package run
- CI hooks:
make fmt-checksmoke (clean→0, dirty→1); full-tree enforce deferred until a one-shot format pass onlib//examples/ - Idempotence fix: drop trailing split-empty so re-format is a no-op
- Verified: unit suite +
./buxc test --filter first _test_runner+ selfhostbuxc2fmt/test parity
Сесия 25 (Ownership 2.0 — C.1 lifetime elision)
- Elision rules in
@[Checked](bootstrap/sema.nim):- Each elided input
&/&mut→ distinct#elidedN - One input lifetime → assigned to elided return
- First param
self/Selfpreferred when multiple inputs - Multiple inputs + elided return →
lifetime elision failed(need'a)
- Each elided input
- Return checks:
cannot return reference to local variable(return &local/ let-bound local ref)no input reference to borrow from(return ref with zero input refs)- Explicit
'amismatch between return and value
- Body check for lifetime-only generics (
func F<'a>(...)) — no longer skipped - Diagnostics hints for elision / dangling / mismatch
- Tests: 8 new borrow_test cases; goldens
return_local_ref,elision_multi_input - Example:
examples/lifetime_elision.bux(Identity / explicit / ViaLet / self) - LanguageRef + QUALITY_PLAN updated
- Verified: borrow_test 24/24, 9 error goldens, example runs
Сесия 26 (C.1 selfhost parity)
- Lexer (
src/lexer.bux+tkLifetime=111):'avs char'x'(same heuristic as bootstrap) - Parser:
&'a T/&'a mut T→TypeExpr.refLifetimefunc F<'a, T>(…)— lifetime params accepted and skipped for mono slots
- Sema lifetime elision (fixed 8-slot maps, same rules as bootstrap):
- single-input elision,
selfpreference, multi-input fail - return-local / no-input-ref / explicit mismatch
- let-bound ref lifetime propagation
- single-input elision,
- Fixed
checkFuncelse-branch that wipedcheckedFuncwhen retType was void - Verified:
buxc2 run lifetime_elisionPASS; goldens on buxc2 show same errors; bootstrap still green; selfhost-loop expected IDENTICAL
Сесия 27 (tooling — D.4 bux doc + D.5 stdlib goldens)
- D.5 Stdlib goldens (
tests/stdlib_golden/):- Packages:
array,string,collections(Map/Set/Result/Option) run.shbuilds viabuxc runand matches expected PASS linesmake test-stdlibwired intomake test
- Packages:
- D.4
bux doc:- Bootstrap:
bootstrap/docgen.nim—///+ adjacent/* */ - Selfhost:
Cli_Docline scanner for/// bux doc [--out file] [path](default pathlib/)make docs→docs/api/stdlib.md
- Bootstrap:
- Stdlib docs:
///on Array / String / Test public helpers - Verified:
make test-stdlib,./buxc doc lib/Array.bux | head, selfhost build
Сесия 28 (LSP v0.4.0 — position-sensitive locals + inferred lets)
LocalBindingwith scope range (scopeStartLine…scopeEndLine) per let/param- Sema-backed inference (
checkExprForLsp/resolveType):let x = 42→ hoverlet x: int· inferredlet s: String = "…"→ annotated, not inferred- params:
param a: intvisible for whole function
- Position-sensitive hover / go-to-def / completion (innermost scope wins on shadowing)
- Nested scopes: if/while/for/match/block arms
- Version bux-lsp 0.4.0; tests:
tools/test_lsp_locals.nim,tools/smoke_lsp_hover.sh - Verified: hover shows
let sum: int · inferred,param a: int,let n: int · inferred
Сесия 29 (full-tree bux fmt + CI enforce)
- One-shot format of
lib/(33),examples/(23),src/(15),tests/(8),apps/(12) - Idempotent: second
--check→ 0 would reformat on all trees - CI:
make fmt-checkenforces full tree + dirty-path smoke (exit 1) make fmthelper to reformat the same roots- Verified:
test-stdlib, key examples, selfhost + selfhost-loop IDENTICAL ✓
Сесия 30 (E.1 package registry + E.3 semver draft)
- Registry index (
config/registry.toml,$BUX_REGISTRY,~/.bux/registry.toml)[[package]]withname/version/source/descriptionfile:/path:(relative to index) or git URL
- CLI:
bux search [q],bux add <name>resolves registry,bux installlocks path/git - Demo package:
registry/packages/greet(Greet_Hello,Greet_Version) - Smoke:
tools/smoke_registry.sh/make test-registry— temp app outside tree - Semver policy:
docs/SEMVER.md(0.x vs 1.0, registry version match) - Packages.md updated
Следващи стъпки
- E.2 polish apps / E.5 benchmarks
- HTTP-fetchable registry index URL (beyond local file)
- LSP: workspace rename / references (optional)