Add classes, enums, pattern matching, error throwing, while loops, function returns, break and continue, bitwise operations under the math library, and the new push and pop functions - #67
Conversation
WalkthroughThis update introduces extensive enhancements to the Bussin X language, including new language constructs such as classes, enums, pattern matching, error handling, and advanced control flow (while loops, break, continue, return, throw). These features are supported across the lexer, parser, AST, interpreter, runtime, and documentation. Additionally, the CLI and REPL gain new commands and improved language toggling, while the transcriber is updated for expanded slang-to-keyword mapping. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI/REPL
participant Transcriber
participant Parser
participant AST
participant Interpreter
participant Runtime
User->>CLI/REPL: Provide source file or command
CLI/REPL->>Transcriber: Transcribe slang to keywords (if .bsx or Bussin X mode)
Transcriber-->>CLI/REPL: Return normalized code
CLI/REPL->>Parser: Parse code to AST
Parser-->>AST: Build AST (with new nodes: class, enum, match, etc.)
CLI/REPL->>Interpreter: Evaluate AST
Interpreter->>Runtime: Execute statements (supporting new constructs)
Runtime-->>Interpreter: Return results (with class/enum/match support)
Interpreter-->>CLI/REPL: Output result or handle control flow
CLI/REPL-->>User: Display output or error
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
npm error Exit handler never called! ✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 7
🔭 Outside diff range comments (1)
src/utils/transcriber.ts (1)
104-107:⚠️ Potential issueIncorrect replacement order breaks
minusminus/plusplustokens
Short tokens (minus,plus) are replaced before their double forms, so the stringminusminusbecomes--after the first pass and the later replacement never matches.- .replace_fr("minus", "-") - .replace_fr("plus", "+") - .replace_fr("minusminus", "--") - .replace_fr("plusplus", "++") + // longer substrings first to avoid premature matches + .replace_fr("minusminus", "--") + .replace_fr("plusplus", "++") + .replace_fr("minus", "-") + .replace_fr("plus", "+")
🧹 Nitpick comments (11)
src/utils/transcriber.ts (1)
61-123: Consider table-driven replacements for maintainability
The 60-line fluent chain is hard to diff and easy to mis-order (see issue above). A singleconst lexicon: Record<string,string>looped withObject.entries()would be clearer, easier to extend, and O(n) instead of creating n intermediate strings.src/runtime/eval/native-fns.ts (1)
40-55: Nice coverage of new runtime types
The added cases provide human-readable output for classes & enums, 👍. Minor nit: consider extracting theClassValue.parent.name/ enum formatting into helpers to keep the switch concise, but not blocking.src/runtime/interpreter.ts (1)
1-6: Remove unused TypeScript-AST imports
ClassDeclaration, ReturnStatement, ThrowStatement, WhileStatementimported fromtypescriptare never referenced—TS 5.8 will flag these. Drop the line to keep the build clean.src/frontend/lexer.ts (1)
151-153: Guard againstundefinedinisskippable.
charCodeAt(0)will throw ifstrisundefined.
Although callers currently ensure a character exists, adding a quick falsy check avoids future foot-guns:-function isskippable(str: string) { - return str == " " || str == "\n" || str == "\t" || str == '\r' || str.charCodeAt(0)==8; +function isskippable(str?: string) { + return !str + || str === " " || str === "\n" || str === "\t" + || str === "\r" || str.charCodeAt(0) === 8; }src/main.ts (2)
56-60: Avoid redundantget_currencycalls.
run()performstakeInput()(which already resolves currency for.bsx) and then immediately callsget_currencyagain.
Cache the value once and pass it through to prevent an extra prompt/API hit.
86-90: REPL continually re-prompts for currency.Inside the Bussin X mode every line re-invokes
get_currency, which can become painfully slow or spam external services.
Consider caching the chosen currency for the session rather than querying on each loop iteration.README.md (2)
8-10: Nit: command name typo –unbeautifyvs code’sunbeautify.The README lists
npm run bussin unbeautify; the CLI arg insrc/main.tsis'unbeautify'.
Make sure the docs mirror the actual flag.
29-42: Minor markdown lint: heading increment & list indenting.H3 immediately after H1 (MD001) and inconsistent list indentation (MD007) trigger common linters.
Runningmarkdownlint --fixcleans these automatically.🧰 Tools
🪛 LanguageTool
[grammar] ~39-~39: This phrase is duplicated. You should probably use “Learn about” only once.
Context: ...Learn about booleans](#booleans) - Learn aboutnull- Learn about arrays - [Learn about obj...(PHRASE_REPETITION)
🪛 markdownlint-cli2 (0.17.2)
36-36: Unordered list indentation
Expected: 2; Actual: 4(MD007, ul-indent)
37-37: Unordered list indentation
Expected: 2; Actual: 4(MD007, ul-indent)
38-38: Unordered list indentation
Expected: 2; Actual: 4(MD007, ul-indent)
39-39: Unordered list indentation
Expected: 2; Actual: 4(MD007, ul-indent)
40-40: Unordered list indentation
Expected: 2; Actual: 4(MD007, ul-indent)
41-41: Unordered list indentation
Expected: 2; Actual: 4(MD007, ul-indent)
src/runtime/environment.ts (2)
22-25: Shared globalrlcan cause prompt collisions.The same readline interface services both the public REPL and internal
input()native fn.
Concurrentquestion()calls will race and interleave output.
Consider spinning up a dedicated interface for REPL and re-using it only via a shallow queue, or serialising calls.
591-596: Enum member access returns shallow-copied parent.Creating the enum value with
{ ...pastVal }strips methods/prototype and wastes memory.
Simply reference the original object:-return { type: "enum", parent: { ...pastVal }, tagged: undefined, name: currentProp } as EnumValue; +return { type: "enum", parent: pastVal as StaticEnumValue, name: currentProp } as EnumValue;src/frontend/parser.ts (1)
239-239: Fix typos in error messages- this.expect(TokenType.Equals, `Expetced equals ("=") following static field declaration to show the initial value of the static field.`); + this.expect(TokenType.Equals, `Expected equals ("=") following static field declaration to show the initial value of the static field.`);- this.expect(TokenType.CloseParen, `Expected a closing parenthesis ("0") following the "new" expression's parameters.`); + this.expect(TokenType.CloseParen, `Expected a closing parenthesis (")") following the "new" expression's parameters.`);Also applies to: 401-401
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (14)
README.md(4 hunks)examples/main.bsx(1 hunks)package.json(1 hunks)src/frontend/ast.ts(3 hunks)src/frontend/lexer.ts(4 hunks)src/frontend/parser.ts(9 hunks)src/main.ts(2 hunks)src/runtime/environment.ts(4 hunks)src/runtime/eval/expressions.ts(4 hunks)src/runtime/eval/native-fns.ts(3 hunks)src/runtime/eval/statements.ts(5 hunks)src/runtime/interpreter.ts(2 hunks)src/runtime/values.ts(2 hunks)src/utils/transcriber.ts(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/runtime/eval/native-fns.ts (1)
src/runtime/values.ts (6)
RuntimeVal(20-22)ClassValue(51-56)StaticClassValue(42-49)ClassFunctionValue(37-40)EnumValue(30-35)StaticEnumValue(24-28)
src/runtime/eval/expressions.ts (4)
src/runtime/values.ts (8)
ClassFunctionValue(37-40)RuntimeVal(20-22)StaticClassValue(42-49)MK_NULL(111-113)ClassValue(51-56)EnumValue(30-35)NativeFnValue(99-102)FunctionValue(89-95)src/frontend/ast.ts (4)
NewExpr(138-141)MatchExpr(151-156)CallExpr(173-177)Identifier(196-199)src/runtime/environment.ts (1)
Environment(495-615)src/runtime/interpreter.ts (1)
evaluate(9-80)
src/runtime/environment.ts (2)
src/runtime/values.ts (4)
RuntimeVal(20-22)StaticClassValue(42-49)ClassValue(51-56)EnumValue(30-35)src/frontend/ast.ts (1)
Identifier(196-199)
src/frontend/parser.ts (2)
src/frontend/lexer.ts (1)
Token(126-131)src/frontend/ast.ts (12)
ThrowStmt(56-59)BreakStmt(67-69)ContinueStmt(71-73)EnumDeclarationStmt(61-65)WhileStmt(75-79)ReturnStmt(81-84)ClassDeclarationStmt(86-93)Expr(131-131)FunctionDeclaration(115-120)Stmt(43-45)NewExpr(138-141)MatchExpr(151-156)
🪛 LanguageTool
README.md
[style] ~12-~12: The preposition ‘amongst’ is correct, but some people think that it is old-fashioned or literary. A more frequently used alternative is the preposition “among”.
Context: ...find an example at /examples/main.bs, amongst many others. # Bussin X 🚀 We, at Buss...
(AMONGST)
[grammar] ~39-~39: This phrase is duplicated. You should probably use “Learn about” only once.
Context: ...Learn about booleans](#booleans) - Learn about null - Learn about arrays - [Learn about obj...
(PHRASE_REPETITION)
[duplication] ~232-~232: Possible typo: you repeated a word.
Context: ...sin.Ballin) rn // Bussin.Ballin ``` ## Functions Functions in programming are intricate entities t...
(ENGLISH_WORD_REPEAT_RULE)
🪛 markdownlint-cli2 (0.17.2)
README.md
19-19: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3
(MD001, heading-increment)
36-36: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
37-37: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
38-38: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
39-39: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
40-40: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
41-41: Unordered list indentation
Expected: 2; Actual: 4
(MD007, ul-indent)
287-287: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
341-341: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
357-357: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
🔇 Additional comments (12)
examples/main.bsx (1)
55-66: Keyword migration looks correct
fuck around / find outnow aligns with the new spaced-keyword convention and the transcriber mapping, so the example should run unchanged.package.json (1)
7-15: Verify tooling version jumps & lock-file before merge
You’re bumping TypeScript from 5.2 → 5.8 and addingts-node. Make sure:
npm run bussinstill type-checks and runs on CI.- A fresh
npm ciwith the lock-file reproduces these exact versions (commit the regeneratedpackage-lock.json/pnpm-lock.yaml).Nothing blocking, just double-check before publishing.
src/frontend/lexer.ts (1)
215-226: Arrow token logic LGTM.
=>detection is correctly inserted without disturbing==/=handling.src/main.ts (1)
24-30: File-system path is brittle for compiled builds.
__dirname + "/../src/utils/currencies.json"assumes thesrctree is shipped with the built code.
After transpiling todist/, this path will resolve to<root>/dist/../src/..., which may not exist in production installs.
Preferpath.resolve(__dirname, "..", "utils", "currencies.json")and copy the file into the build output.Also applies to: 57-59
src/runtime/values.ts (1)
4-18: Runtime type additions look solid.Union and interface shapes align with interpreter usage. No concerns.
src/runtime/eval/expressions.ts (4)
122-149: LGTM! Proper handling of class methods and early returnsThe implementation correctly:
- Binds
thisto the parent class for class methods- Handles early exits from functions via the
exitWithmechanism- Properly resets
exitWithafter function execution to prevent state leakage
151-179: Well-implemented class instantiation logicThe function correctly:
- Validates that only static classes can be instantiated
- Initializes instance fields to NULL
- Properly sets up instance methods with correct parent references
- Calls the constructor if present
181-238: Pattern matching implementation looks good, with a minor concernThe implementation correctly handles enum matching, tagged enums with variable binding, and default cases. However, using
JSON.stringifyfor comparison (line 184 and 207) could cause issues with circular references or complex objects.Consider whether the current JSON.stringify approach will handle all expected use cases. For simple values and enums it should work fine, but you may want to document this limitation or implement a more robust comparison for complex objects in the future.
240-265: Clean refactoring to switch statementThe refactored implementation is more readable and properly handles all callable types with appropriate error messages.
src/frontend/ast.ts (1)
7-94: Well-structured AST type definitionsAll new AST node types are properly defined with appropriate fields and follow the existing patterns in the codebase.
Also applies to: 133-156
src/runtime/eval/statements.ts (1)
71-98: Excellent control flow management improvementsThe addition of the
leakScopeparameter and proper handling ofexitWith,continue, andbreaksignals ensures correct control flow behavior across nested environments in loops, conditionals, and try-catch blocks.Also applies to: 100-131, 187-206
src/frontend/parser.ts (1)
99-135: Well-implemented parser extensionsThe new parsing methods for classes, enums, pattern matching, and control flow statements are properly structured and follow the existing parser patterns. Error messages are clear and descriptive.
Also applies to: 137-194, 213-261, 386-408, 681-720
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 6
🔭 Outside diff range comments (1)
src/frontend/parser.ts (1)
68-74:⚠️ Potential issue
expect()prints potentially‐undefinedprev.typeand exits the processIf the token stream is empty (
previsundefined) the log statement attempts to accessprev.type, throwing before the intendedprocess.exit(1). Guard first:- if (!prev || prev.type != type) { - console.error(`Parser error: (Ln ${this.lastNonNLLine}, Col ${this.lastNonNLColumn + 1})\n`, err, "Expecting:", type, 'Got:', prev.type); + if (!prev || prev.type !== type) { + const got = prev ? prev.type : "<none>"; + console.error( + `Parser error: (Ln ${this.lastNonNLLine}, Col ${this.lastNonNLColumn + 1})\n`, + err, + "Expecting:", + type, + "Got:", + got, + );
♻️ Duplicate comments (1)
src/frontend/parser.ts (1)
667-671: Function literals duplicate parser logicSame duplication issue as earlier statement case. Unify the parsing of
fn
declarations/expressions to one code path.
🧹 Nitpick comments (2)
src/frontend/parser.ts (2)
104-109:throwshould optionally swallow a trailing semicolonAfter parsing the thrown value a stray semicolon currently bubbles up to the next
statement and produces an error. Consider:return { kind: "ThrowStatement", value: this.parse_expr(), } as ThrowStmt; + +if (this.at().type === TokenType.Semicolon) this.eat();
385-407: Minor: misleading error string innewexpression
"Expected a closing parenthesis ("0")looks like a typo.-this.expect(TokenType.CloseParen, `Expected a closing parenthesis ("0") …`); +this.expect(TokenType.CloseParen, `Expected a closing parenthesis (")") …`);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/frontend/parser.ts(9 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/frontend/parser.ts (2)
src/frontend/lexer.ts (1)
Token(126-131)src/frontend/ast.ts (12)
ThrowStmt(56-59)BreakStmt(67-69)ContinueStmt(71-73)EnumDeclarationStmt(61-65)WhileStmt(75-79)ReturnStmt(81-84)ClassDeclarationStmt(86-93)Expr(131-131)FunctionDeclaration(115-120)Stmt(43-45)NewExpr(138-141)MatchExpr(151-156)
🔇 Additional comments (1)
src/frontend/parser.ts (1)
125-130: Break / Continue look goodStraight-through translation to AST – nothing to flag here.
There was a problem hiding this comment.
Actionable comments posted: 8
♻️ Duplicate comments (2)
src/frontend/parser.ts (2)
99-103: Duplicatefnparsing logic still present
TokenType.Fnhandling exists here and inparse_primary_expr().
Keeping two nearly identical code paths invites divergent behaviour.
Please consolidate via a shared helper (e.g.parse_function(isExpr: boolean)).
184-202:⚠️ Potential issue
return;producesIdentifier("null")– will crash at runtimeFor bare
returnstatements you fabricate anIdentifiernamed"null".
Unless the user manually declared a variable callednull, the interpreter will throw an
“undefined variable” error.Make the value optional (or introduce a
NullLiteral) instead:-export interface ReturnStmt extends Stmt { - kind: "ReturnStatement"; - value: Expr; -} +export interface ReturnStmt extends Stmt { + kind: "ReturnStatement"; + value?: Expr; // optional +} … - } else { - this.eat(); - value = { kind: "Identifier", symbol: "null" } as Identifier; + } else { // bare `return;` + this.eat(); + value = undefined; }Complement this with interpreter logic to treat an undefined
valueasMK_NULL().
🧹 Nitpick comments (3)
src/runtime/interpreter.ts (1)
1-6: Remove unusedtypescriptimports to keep bundle lean
ClassDeclaration,ReturnStatement,ThrowStatement, andWhileStatementare imported from thetypescriptpackage but never referenced.
They introduce an unnecessary dependency edge and may confuse maintainers.-import { ClassDeclaration, ReturnStatement, ThrowStatement, WhileStatement } from "typescript";src/runtime/eval/statements.ts (1)
37-39: Dead variablemain_env– delete to silence TS/linters
main_envis declared but never used.
Drop it to clean up the loop implementation.- const main_env = new Environment(env);src/frontend/ast.ts (1)
86-93: PreferReadonlyMap/ReadonlySetfor AST immutabilityUse read-only collections to communicate intent and avoid accidental mutations during analysis passes.
- fields: Set<string>; - staticFields: Map<string, Expr>; - funs: Map<string, FunctionDeclaration>; - staticFuns: Map<string, FunctionDeclaration>; + fields: ReadonlySet<string>; + staticFields: ReadonlyMap<string, Expr>; + funs: ReadonlyMap<string, FunctionDeclaration>; + staticFuns: ReadonlyMap<string, FunctionDeclaration>;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/frontend/ast.ts(3 hunks)src/frontend/parser.ts(9 hunks)src/runtime/environment.ts(4 hunks)src/runtime/eval/expressions.ts(4 hunks)src/runtime/eval/statements.ts(5 hunks)src/runtime/interpreter.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/runtime/environment.ts
🧰 Additional context used
🧠 Learnings (1)
src/frontend/parser.ts (2)
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/parser.ts:213-260
Timestamp: 2025-06-15T17:38:03.399Z
Learning: In parser implementations, variable shadowing is acceptable when the scopes are clearly separated and the variables serve different semantic purposes, such as an outer variable holding a class name and an inner loop-scoped variable holding member names. Context and usage patterns matter more than strict shadowing avoidance in such cases.
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/parser.ts:136-153
Timestamp: 2025-06-15T17:39:47.445Z
Learning: The user prefers clean syntax without trailing commas in match expressions, as they would create weird syntax like `match 1 { 1,2, 3, => { true } }` where the trailing comma before the arrow looks awkward.
🧬 Code Graph Analysis (2)
src/runtime/interpreter.ts (4)
src/runtime/eval/expressions.ts (2)
eval_new_expr(149-177)eval_match_expr(179-236)src/frontend/ast.ts (9)
NewExpr(138-141)MatchExpr(151-156)VarDeclaration(95-100)FunctionDeclaration(115-120)ThrowStmt(56-59)ReturnStmt(81-84)ClassDeclarationStmt(86-93)EnumDeclarationStmt(61-65)WhileStmt(75-79)src/runtime/eval/statements.ts (5)
eval_val_declaration(17-21)eval_function_declaration(23-34)eval_class_declaration(132-175)eval_enum_declaration(177-184)eval_while_statement(36-56)src/runtime/values.ts (1)
MK_NULL(111-113)
src/frontend/parser.ts (2)
src/frontend/lexer.ts (1)
Token(126-131)src/frontend/ast.ts (12)
ThrowStmt(56-59)BreakStmt(67-69)ContinueStmt(71-73)EnumDeclarationStmt(61-65)WhileStmt(75-79)ReturnStmt(81-84)ClassDeclarationStmt(86-93)Expr(131-131)FunctionDeclaration(115-120)Stmt(43-45)NewExpr(138-141)MatchExpr(151-156)
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (3)
src/frontend/parser.ts (3)
676-680: Duplicate function-parsing logic
TokenType.Fnis now handled here and earlier inparse_stmt(), duplicating the same code path. Consolidate into a single helper (e.g.parse_function(isExpr: boolean)).
696-726:MatchExpr.casesusesMap<Expr[], …>– array keys break equalityJS
Mapkeys are compared by reference; two structurally identical pattern arrays won’t match.
Storing cases in an ordered array (or canonicalising the key) avoids subtle bugs.
138-149: 🛠️ Refactor suggestionEnum parser allows duplicates and gives opaque error on trailing comma
- Duplicate member names (
{ Red, Red }) are silently accepted.enum Color { Red, }triggersComma expectedbecause the loop still demands a comma after the last identifier.Small tweaks address both:
- members.push(this.expect(TokenType.Identifier, `Identifier expected for enum name.`).value); - if (this.at().type != TokenType.CloseBrace) { - this.expect(TokenType.Comma, `Comma expected following enum member.`); - } + const id = this.expect(TokenType.Identifier, `Identifier expected for enum member.`).value; + if (members.includes(id)) { + throw `Duplicate enum member "${id}".`; + } + members.push(id); + if (this.at().type == TokenType.Comma) this.eat(); // optional trailing comma
🧹 Nitpick comments (2)
src/runtime/eval/expressions.ts (1)
156-158: Instance fields are always initialised tonullStatic classes can specify default values in
staticFields, but ordinary fields lose any initialiser that might have been declared in the class body.
If initialisers are part of the language spec, capture them when parsing and apply here; otherwise consider throwing when a non-static field tries to provide= valueto avoid silent loss.src/frontend/parser.ts (1)
238-252: Instance field initialisers not supportedThe parser rejects
field = 42;for non-static fields, yet such syntax is common and already usable for static fields.
Consider permitting initialisers for instance fields to maintain feature parity and avoid surprising users.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/frontend/ast.ts(3 hunks)src/frontend/parser.ts(9 hunks)src/runtime/eval/expressions.ts(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/frontend/ast.ts
🧰 Additional context used
🧠 Learnings (2)
src/runtime/eval/expressions.ts (1)
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/runtime/eval/expressions.ts:167-170
Timestamp: 2025-06-15T17:55:02.358Z
Learning: In the Bussin language, functions cannot be mutated by design, making it safe to share the same ClassFunctionValue objects between class instances without the typical "last-instance wins" mutation issues.
src/frontend/parser.ts (4)
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/ast.ts:81-84
Timestamp: 2025-06-15T17:49:11.578Z
Learning: In the Bussin language, return statements always have a value - there are no void returns. When no explicit value is provided in a return statement (e.g., `return;`), the parser defaults to returning null. Therefore, the ReturnStmt AST interface correctly requires a `value: Expr` field rather than making it optional.
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/parser.ts:138-155
Timestamp: 2025-06-15T17:44:33.847Z
Learning: The enum parsing logic in src/frontend/parser.ts already supports trailing commas correctly. After parsing a trailing comma, the current token becomes the closing brace, causing the while loop condition to fail and exit cleanly.
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/parser.ts:213-260
Timestamp: 2025-06-15T17:38:03.399Z
Learning: In parser implementations, variable shadowing is acceptable when the scopes are clearly separated and the variables serve different semantic purposes, such as an outer variable holding a class name and an inner loop-scoped variable holding member names. Context and usage patterns matter more than strict shadowing avoidance in such cases.
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/parser.ts:136-153
Timestamp: 2025-06-15T17:39:47.445Z
Learning: The user prefers clean syntax without trailing commas in match expressions, as they would create weird syntax like `match 1 { 1,2, 3, => { true } }` where the trailing comma before the arrow looks awkward.
🧬 Code Graph Analysis (2)
src/runtime/eval/expressions.ts (4)
src/runtime/values.ts (8)
ClassFunctionValue(37-40)RuntimeVal(20-22)StaticClassValue(42-49)MK_NULL(111-113)ClassValue(51-56)EnumValue(30-35)NativeFnValue(99-102)FunctionValue(89-95)src/frontend/ast.ts (4)
NewExpr(138-142)MatchExpr(152-157)CallExpr(174-178)Identifier(197-200)src/runtime/environment.ts (1)
Environment(501-621)src/runtime/interpreter.ts (1)
evaluate(9-80)
src/frontend/parser.ts (2)
src/frontend/lexer.ts (1)
Token(126-131)src/frontend/ast.ts (13)
ThrowStmt(56-59)BreakStmt(67-69)ContinueStmt(71-73)EnumDeclarationStmt(61-65)WhileStmt(75-79)ReturnStmt(81-84)Identifier(197-200)ClassDeclarationStmt(86-93)Expr(131-131)FunctionDeclaration(115-120)Stmt(43-45)NewExpr(138-142)MatchExpr(152-157)
🔇 Additional comments (1)
src/runtime/eval/expressions.ts (1)
173-176: Constructor return value is discarded
eval_functionreturns aRuntimeVal, yet its result is ignored when the constructor finishes.
If the language intends to supportreturninside constructors (e.g. to create factories) this value should replacebase, otherwise an explicit comment or check forbiddingreturnwould avoid confusion.
… array push/pop methods, add bitwise operations under the math library, and improved parser error messages
break, and continuebreak, and continue, bitwise operations under the math library, and the new push and pop functions
There was a problem hiding this comment.
Actionable comments posted: 3
🔭 Outside diff range comments (1)
src/frontend/parser.ts (1)
30-41: 🛠️ Refactor suggestionDuplicate state updates corrupt
lastNonNL*bookkeeping
lastNonNLLine/Columnare reassigned twice in the same branch, so the “previous
token” coordinates are wrong after every non-newline token.
Delete the inner pair (lines 39-40) or merge the two blocks.
♻️ Duplicate comments (1)
src/frontend/parser.ts (1)
694-725: Array keys inMapbreak pattern equality – see earlier review.JavaScript compares arrays by reference; two structurally equal pattern lists
won’t match. Store cases in an ordered array or stringify the pattern list.
🧹 Nitpick comments (2)
showcase/rule110.bsx (2)
25-26: Return explicitly for readabilityRelying on the implicit “last expression wins” rule hides intent.
An explicitreturnmakes it obvious to readers (and future tooling) thattostringGenhands back a string.- strcon(buf, "\n") + return strcon(buf, "\n")
32-38: Bit-twiddling works but is cryptic; document or isolate constantUsing the magic literal
110(decimal) obscures that this is the bitmap0b01101110for Rule-110. At a glance it looks like an arbitrary number.Recommend extracting a named constant (or at least an inline comment) so future maintainers don’t have to reverse-engineer the intent:
- push(next, nerd.band(nerd.brsh(110, state), 1)) + # Rule 110 mask: 0b0110_1110 + push(next, nerd.band(nerd.brsh(110, state), 1))Even better, lift it out:
lit RULE_110_MASK be 110 rn # 0b0110_1110 ... push(next, nerd.band(nerd.brsh(RULE_110_MASK, state), 1))
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
.gitignore(0 hunks)examples/classes.bs(1 hunks)examples/classes.bsx(1 hunks)examples/enums.bs(1 hunks)examples/enums.bsx(1 hunks)examples/returns.bs(1 hunks)showcase/rule110.bsx(1 hunks)src/frontend/parser.ts(9 hunks)src/runtime/environment.ts(6 hunks)
💤 Files with no reviewable changes (1)
- .gitignore
✅ Files skipped from review due to trivial changes (1)
- examples/classes.bs
🚧 Files skipped from review as they are similar to previous changes (1)
- src/runtime/environment.ts
🧰 Additional context used
🧠 Learnings (1)
src/frontend/parser.ts (6)
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/ast.ts:81-84
Timestamp: 2025-06-15T17:49:11.578Z
Learning: In the Bussin language, return statements always have a value - there are no void returns. When no explicit value is provided in a return statement (e.g., `return;`), the parser defaults to returning null. Therefore, the ReturnStmt AST interface correctly requires a `value: Expr` field rather than making it optional.
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/parser.ts:138-155
Timestamp: 2025-06-15T17:44:33.847Z
Learning: The enum parsing logic in src/frontend/parser.ts already supports trailing commas correctly. After parsing a trailing comma, the current token becomes the closing brace, causing the while loop condition to fail and exit cleanly.
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/parser.ts:213-260
Timestamp: 2025-06-15T17:38:03.399Z
Learning: In parser implementations, variable shadowing is acceptable when the scopes are clearly separated and the variables serve different semantic purposes, such as an outer variable holding a class name and an inner loop-scoped variable holding member names. Context and usage patterns matter more than strict shadowing avoidance in such cases.
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/parser.ts:136-153
Timestamp: 2025-06-15T17:39:47.445Z
Learning: The user prefers clean syntax without trailing commas in match expressions, as they would create weird syntax like `match 1 { 1,2, 3, => { true } }` where the trailing comma before the arrow looks awkward.
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/parser.ts:184-201
Timestamp: 2025-06-15T18:02:52.438Z
Learning: In the Bussin language, there are no null literal AST nodes. Instead, null is handled as a predefined global variable in the runtime environment. When parsing bare `return;` statements, the parser creates an Identifier node with symbol "null" to reference this global null variable, rather than using a dedicated NullLiteral node type.
Learnt from: artofcoding212
PR: face-hh/bussin#67
File: src/frontend/parser.ts:0-0
Timestamp: 2025-06-15T18:05:21.638Z
Learning: In src/frontend/parser.ts, the parse_function_declaration method is designed to accept a name parameter, with callers responsible for parsing function names. This allows for different naming contexts: anonymous functions use "<anonymous>", class methods have names parsed by class declaration logic, and regular functions have names parsed by statement logic. This design eliminates code duplication while supporting the language's various function declaration contexts.
🧬 Code Graph Analysis (1)
src/frontend/parser.ts (2)
src/frontend/lexer.ts (1)
Token(126-131)src/frontend/ast.ts (12)
ThrowStmt(56-59)BreakStmt(67-69)ContinueStmt(71-73)EnumDeclarationStmt(61-65)WhileStmt(75-79)ReturnStmt(81-84)ClassDeclarationStmt(86-93)Expr(131-131)FunctionDeclaration(115-120)Stmt(43-45)NewExpr(138-142)MatchExpr(152-157)
🔇 Additional comments (6)
showcase/rule110.bsx (1)
44-49: Duplicate printing: current generation appears twiceLine 44 prints the initial generation immediately, and then the loop starting on line 46 appends the same generation to
buf, which is printed again on line 51. Result: generation 0 shows up twice.Two simple fixes:
- Remove the eager
waffleand rely solely on the buffered output, or- Start the accumulation after computing the first
nextGen.-waffle(tostringGen(current)) -lit buf be "" rn -yall (lit i be 0 rn i smol genCount rn i plusplus) { - current be nextGen(current) rn - buf be strcon(buf, tostringGen(current)) rn -} +lit buf be tostringGen(current) rn # seed with gen 0 +yall (lit i be 0 rn i smol genCount rn i plusplus) { + current be nextGen(current) rn + buf be strcon(buf, tostringGen(current)) rn +}src/frontend/parser.ts (1)
184-195:⚠️ Potential issueBare
returnfollowed by newline is mis-parsedThe check only treats a semicolon as statement terminator;
returnat EOL
(return\nfoo()) will wrongly consumefoo()as the return value.
Consider treating newline as a terminator when it immediately followsreturn.⛔ Skipped due to learnings
Learnt from: artofcoding212 PR: face-hh/bussin#67 File: src/frontend/ast.ts:81-84 Timestamp: 2025-06-15T17:49:11.578Z Learning: In the Bussin language, return statements always have a value - there are no void returns. When no explicit value is provided in a return statement (e.g., `return;`), the parser defaults to returning null. Therefore, the ReturnStmt AST interface correctly requires a `value: Expr` field rather than making it optional.examples/returns.bs (1)
1-16: Example looks goodThe snippet exercises nested returns and error handling clearly.
examples/enums.bs (1)
1-23: Enum sample is clear and matches new syntaxNo problems spotted.
examples/classes.bsx (1)
1-17: Class example LGTMDemonstrates static field, constructor, method invocation – all good.
examples/enums.bsx (1)
1-20: Slang enum example reads wellIllustrates match/default correctly.
break, and continue, bitwise operations under the math library, and the new push and pop functionsbreak and continue, bitwise operations under the math library, and the new push and pop functions
Description
I was bored one day and made these changes in 2 or 3 hours.
I've made numerous interpreters with implementation exactly like this as well as compilers and bytecode interpreters, so this was a breeze.
I'm surprised that some of the features I added weren't here in the first place.
Main Changes:
Now, you can declare classes with the
classorchadkeyword!Here's an example I wrote:
Of course, there's Bussin X syntax to this as well.
This one's easy enough to understand. We have while loops with the
whilekeyword!Enums can be declared with the
enumkeyword.You can use the
Enum.Namesyntax to make an enum.Tagged enums also work with the
Enum.Name(Value)syntax. You match on them like so:As shown above, you can use the
matchkeyword with a Rust-like syntax. Matching on multiple members is done by separating them with commas.Use the default keyword to match the default case.
You can match on anything thanks to the interpreter comparing cases by
JSON.stringify().Another simple one: use the
throw <expression>syntax to throw errors. You can try and catch on them like normal.I got the idea from Add support for optional return statement #63; though, I'm not too sure why we never had function returning in the first place.
In reality, it was just a simple trick that stores a return value in the Environment and Environments can carry over return values in things like if statements.
The approach to this one was very similar to the one with function returns: there's just two variables in the Environment that signifies if you can continue/break and whether or not you're continuing or breaking from the loop.
Misc. Changes:
push<T>(arr: T[], val: T)andpop<T>(arr: T[]): TfunctionsIn the unfortunate scenario of ambiguous syntax, you can include semicolons at the end of expressions. This also means that the
rnkeyword can be put in places that make sense.I added a table of contents (as there's way too much stuff to shuffle through) and updated the new section. I also took the time to write some minor documentation for the things I added in the style of how it has been previously done.
This means that the
fuck_withkeyword can now be thefuck withkeyword. I still kept the original keywords to make sure legacy code is supported.[...] view-ast [file]usage.[...] unbeautify [file]usage.New Transcriber Keyword Additions
Not the greatest at slang, I just kind of Googled a list of brainrot words and occasionally chose a word that actually made sense.
Summary by CodeRabbit
New Features
.bsxfiles to.bsfiles.Bug Fixes
Documentation
Chores