Skip to content

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

Open
artofcoding212 wants to merge 6 commits into
face-hh:mainfrom
artofcoding212:main

Conversation

@artofcoding212

@artofcoding212 artofcoding212 commented Jun 15, 2025

Copy link
Copy Markdown

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:

  • Add classes
    Now, you can declare classes with the class or chad keyword!
    Here's an example I wrote:
class Apple {
    static class_name = "Apple";
    percent;

    constructor() {
        this.percent = 100;
    }

    eat() {
        this.percent -= 1;
    }
}

println(Apple.class_name);

let myApple = new Apple();
myApple.eat();
println(myApple.percent);
Apple
99

Of course, there's Bussin X syntax to this as well.

  • Add while loops
    This one's easy enough to understand. We have while loops with the while keyword!
  • Add enums
    Enums can be declared with the enum keyword.
    You can use the Enum.Name syntax to make an enum.
    Tagged enums also work with the Enum.Name(Value) syntax. You match on them like so:
enum Foo {}
match Foo.Bar(3) {
   Foo.Bar(n) => { println(n) }
}
3
  • Add pattern matching
    As shown above, you can use the match keyword 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().
  • Add error throwing
    Another simple one: use the throw <expression> syntax to throw errors. You can try and catch on them like normal.
  • Add function returning
    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.
  • Add breaking and continuing from loops
    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:

  • Add push<T>(arr: T[], val: T) and pop<T>(arr: T[]): T functions
  • Add math.bor, math.band, math.bxor, math.blsh, and math.brsh functions
  • Semicolons at the end of expressions
    In the unfortunate scenario of ambiguous syntax, you can include semicolons at the end of expressions. This also means that the rn keyword can be put in places that make sense.
  • Fixed character duplication glitch in REPL due to multiple Readline creations (now there's one global Readline)
  • Updated REPL version and added support for switching to Bussin X syntax within the REPL
  • README Updates
    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.
  • Add support for keywords with spaces in the transcriber
    This means that the fuck_with keyword can now be the fuck with keyword. I still kept the original keywords to make sure legacy code is supported.
  • I added a few more examples in the examples folder to test out classes, enums, and function returns.
  • You can view the AST of a program with the [...] view-ast [file] usage.
  • You can transform a .bsx file to a .bs file with the [...] 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.

Bussin Keyword 👎 Bussin X Keyword 🚀
class chad
this drake
return ghost
break aura
gyatt continue
while diddy
static kai cenat
constructor skibidi toilet
new mog
enum baller
match fw
=> edges
default put the fries in the bag lil bro
throw yeet
try fuck around
catch find out

Summary by CodeRabbit

  • New Features

    • Introduced support for classes, enums, pattern matching, error throwing, while loops, function returns, and loop control keywords.
    • Added new CLI commands to view the AST of a file and to convert .bsx files to .bs files.
    • Enhanced REPL with a new language toggle and stylized prompts.
  • Bug Fixes

    • Corrected language keyword handling in example code and documentation.
  • Documentation

    • Expanded and reorganized the README with detailed instructions, new features, and a comprehensive Table of Contents.
    • Added examples and clarified syntax for new language constructs.
  • Chores

    • Updated and added development dependencies for improved tooling and type support.

@coderabbitai

coderabbitai Bot commented Jun 15, 2025

Copy link
Copy Markdown

Walkthrough

This 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

File(s) Change Summary
README.md Expanded documentation with new features, usage instructions, and detailed Table of Contents. Added sections for classes, enums, pattern matching, error handling, and updated syntax examples.
examples/main.bsx Updated syntax for try-catch blocks to use spaced keywords (fuck around, find out).
package.json Added/updated devDependencies: new types, upgraded TypeScript, added ts-node.
src/frontend/ast.ts Extended AST with node types for throw, class, return, while, break, continue, enum, new, and match constructs; added corresponding interfaces.
src/frontend/lexer.ts Added new keywords and token types for class, static, return, break, continue, while, new, enum, match, default, throw, and arrow (=>). Updated whitespace handling.
src/frontend/parser.ts Parser extended to handle class declarations, enums, while loops, return, throw, break/continue, new expressions, and match expressions. Improved error messages and function parsing.
src/main.ts Added CLI commands for AST viewing and file transformation; refactored input handling; enhanced REPL with language toggle and input transcription.
src/runtime/environment.ts Added runtime support for class and enum types; updated object member access/mutation; exposed a global readline interface; added control flow properties to environment.
src/runtime/eval/expressions.ts Added evaluation logic for class instantiation, class functions, enums, and match expressions; refactored function and call evaluation for new types and early exit handling.
src/runtime/eval/native-fns.ts Updated runtime-to-JS conversion to handle new class and enum types, returning descriptive strings.
src/runtime/eval/statements.ts Added evaluation for while statements, class and enum declarations; improved control flow propagation in loops and try-catch; refactored body evaluation for scope leakage.
src/runtime/interpreter.ts Interpreter extended to evaluate new AST nodes (throw, return, class, enum, while, break, continue, new, match).
src/runtime/values.ts Introduced new runtime value types and interfaces for classes, enums, and class functions.
src/utils/transcriber.ts Expanded slang-to-keyword mappings for new language constructs and updated legacy support.
.gitignore Removed ignore patterns for .bsx and .bs files.
examples/classes.bs Added example class Apple with static and instance properties and methods.
examples/classes.bsx Added example class Apple with properties and methods, demonstrating new syntax.
examples/enums.bs Added example enum Foo with variants and pattern matching usage.
examples/enums.bsx Added example enum Foo with pattern matching forwarding blocks.
examples/returns.bs Added example function demonstrating nested returns and try-catch with return.
showcase/rule110.bsx Added Rule 110 cellular automaton example with input, loops, and bitwise operations.

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
Loading

Poem

🐇
Hopped in with classes, enums, and more,
While loops and matches—what a lore!
"Yeet" for errors, "ghost" to return,
"Diddy" loops where bunnies learn.
Bussin X grows, the docs now gleam—
Code like a rabbit, live your dream!

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

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-16T05_34_55_006Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🔭 Outside diff range comments (1)
src/utils/transcriber.ts (1)

104-107: ⚠️ Potential issue

Incorrect replacement order breaks minusminus / plusplus tokens
Short tokens (minus, plus) are replaced before their double forms, so the string minusminus becomes -- 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 single const lexicon: Record<string,string> looped with Object.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 the ClassValue.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, WhileStatement imported from typescript are never referenced—TS 5.8 will flag these. Drop the line to keep the build clean.

src/frontend/lexer.ts (1)

151-153: Guard against undefined in isskippable.

charCodeAt(0) will throw if str is undefined.
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 redundant get_currency calls.

run() performs takeInput() (which already resolves currency for .bsx) and then immediately calls get_currency again.
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 – unbeautify vs code’s unbeautify.

The README lists npm run bussin unbeautify; the CLI arg in src/main.ts is '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.
Running markdownlint --fix cleans 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 about null - 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 global rl can cause prompt collisions.

The same readline interface services both the public REPL and internal input() native fn.
Concurrent question() 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

📥 Commits

Reviewing files that changed from the base of the PR and between bb15898 and af7b451.

⛔ Files ignored due to path filters (1)
  • package-lock.json is 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 out now 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 adding ts-node. Make sure:

  1. npm run bussin still type-checks and runs on CI.
  2. A fresh npm ci with the lock-file reproduces these exact versions (commit the regenerated package-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 the src tree is shipped with the built code.
After transpiling to dist/, this path will resolve to <root>/dist/../src/..., which may not exist in production installs.
Prefer path.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 returns

The implementation correctly:

  • Binds this to the parent class for class methods
  • Handles early exits from functions via the exitWith mechanism
  • Properly resets exitWith after function execution to prevent state leakage

151-179: Well-implemented class instantiation logic

The 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 concern

The implementation correctly handles enum matching, tagged enums with variable binding, and default cases. However, using JSON.stringify for 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 statement

The 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 definitions

All 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 improvements

The addition of the leakScope parameter and proper handling of exitWith, continue, and break signals 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 extensions

The 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

Comment thread src/runtime/interpreter.ts
Comment thread src/runtime/environment.ts
Comment thread src/runtime/eval/expressions.ts Outdated
Comment thread src/runtime/eval/statements.ts
Comment thread src/runtime/eval/statements.ts Outdated
Comment thread src/runtime/eval/statements.ts
Comment thread src/frontend/parser.ts Outdated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🔭 Outside diff range comments (1)
src/frontend/parser.ts (1)

68-74: ⚠️ Potential issue

expect() prints potentially‐undefined prev.type and exits the process

If the token stream is empty (prev is undefined) the log statement attempts to access prev.type, throwing before the intended process.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 logic

Same 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: throw should optionally swallow a trailing semicolon

After 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 in new expression

"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

📥 Commits

Reviewing files that changed from the base of the PR and between af7b451 and 750e067.

📒 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 good

Straight-through translation to AST – nothing to flag here.

Comment thread src/frontend/parser.ts
Comment thread src/frontend/parser.ts
Comment thread src/frontend/parser.ts
Comment thread src/frontend/parser.ts
Comment thread src/frontend/parser.ts
Comment thread src/frontend/parser.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

♻️ Duplicate comments (2)
src/frontend/parser.ts (2)

99-103: Duplicate fn parsing logic still present

TokenType.Fn handling exists here and in parse_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; produces Identifier("null") – will crash at runtime

For bare return statements you fabricate an Identifier named "null".
Unless the user manually declared a variable called null, 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 value as MK_NULL().

🧹 Nitpick comments (3)
src/runtime/interpreter.ts (1)

1-6: Remove unused typescript imports to keep bundle lean

ClassDeclaration, ReturnStatement, ThrowStatement, and WhileStatement are imported from the typescript package 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 variable main_env – delete to silence TS/linters

main_env is 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: Prefer ReadonlyMap / ReadonlySet for AST immutability

Use 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

📥 Commits

Reviewing files that changed from the base of the PR and between 750e067 and 9fcbb86.

📒 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)

Comment thread src/runtime/eval/expressions.ts
Comment thread src/runtime/eval/expressions.ts
Comment thread src/frontend/parser.ts
Comment thread src/frontend/ast.ts
Comment thread src/frontend/ast.ts
Comment thread src/frontend/ast.ts
Comment thread src/frontend/ast.ts
Comment thread src/frontend/ast.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (3)
src/frontend/parser.ts (3)

676-680: Duplicate function-parsing logic

TokenType.Fn is now handled here and earlier in parse_stmt(), duplicating the same code path. Consolidate into a single helper (e.g. parse_function(isExpr: boolean)).


696-726: MatchExpr.cases uses Map<Expr[], …> – array keys break equality

JS Map keys 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 suggestion

Enum parser allows duplicates and gives opaque error on trailing comma

  1. Duplicate member names ({ Red, Red }) are silently accepted.
  2. enum Color { Red, } triggers Comma expected because 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 to null

Static 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 = value to avoid silent loss.

src/frontend/parser.ts (1)

238-252: Instance field initialisers not supported

The 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

📥 Commits

Reviewing files that changed from the base of the PR and between 9fcbb86 and 5154dd1.

📒 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_function returns a RuntimeVal, yet its result is ignored when the constructor finishes.
If the language intends to support return inside constructors (e.g. to create factories) this value should replace base, otherwise an explicit comment or check forbidding return would avoid confusion.

Comment thread src/runtime/eval/expressions.ts
Comment thread src/runtime/eval/expressions.ts
Comment thread src/frontend/parser.ts
… array push/pop methods, add bitwise operations under the math library, and improved parser error messages
@artofcoding212 artofcoding212 changed the title Add classes, enums, pattern matching, error throwing, while loops, function returns, break, and continue 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 Jun 16, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🔭 Outside diff range comments (1)
src/frontend/parser.ts (1)

30-41: 🛠️ Refactor suggestion

Duplicate state updates corrupt lastNonNL* bookkeeping

lastNonNLLine/Column are 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 in Map break 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 readability

Relying on the implicit “last expression wins” rule hides intent.
An explicit return makes it obvious to readers (and future tooling) that tostringGen hands back a string.

-    strcon(buf, "\n")
+    return strcon(buf, "\n")

32-38: Bit-twiddling works but is cryptic; document or isolate constant

Using the magic literal 110 (decimal) obscures that this is the bitmap 0b01101110 for 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

📥 Commits

Reviewing files that changed from the base of the PR and between 5154dd1 and 5ac0632.

📒 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 twice

Line 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:

  1. Remove the eager waffle and rely solely on the buffered output, or
  2. 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 issue

Bare return followed by newline is mis-parsed

The check only treats a semicolon as statement terminator; return at EOL
(return\nfoo()) will wrongly consume foo() as the return value.
Consider treating newline as a terminator when it immediately follows return.

⛔ 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 good

The snippet exercises nested returns and error handling clearly.

examples/enums.bs (1)

1-23: Enum sample is clear and matches new syntax

No problems spotted.

examples/classes.bsx (1)

1-17: Class example LGTM

Demonstrates static field, constructor, method invocation – all good.

examples/enums.bsx (1)

1-20: Slang enum example reads well

Illustrates match/default correctly.

Comment thread showcase/rule110.bsx
Comment thread showcase/rule110.bsx
Comment thread src/frontend/parser.ts
@artofcoding212 artofcoding212 changed the title 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 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 Jun 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant