-
Notifications
You must be signed in to change notification settings - Fork 0
Merge wasm-playground branch into master #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9da1baa
05dd70e
801db80
edba121
ce3b9a4
d85b7bf
71a433c
28e808f
6d60c58
2f6d982
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| # Hybroid Live - Project Context | ||
|
|
||
| ## Project Overview | ||
|
|
||
| **Hybroid Live** is a statically-typed programming language designed specifically for creating content for the game **PewPew Live**. It transpiles to Lua, which is the scripting language used by the game. | ||
|
|
||
| **Key Goals:** | ||
| * Provide a better developer experience than raw Lua. | ||
| * Add features missing in Lua (classes, enums, strict typing). | ||
| * Optimize for PewPew Live specifics (tick loops, fixed-point math). | ||
| * Provide robust error messages. | ||
|
|
||
| **Status:** Alpha (expect breaking changes). | ||
|
|
||
| ## Architecture | ||
|
|
||
| The project is written in **Go** and follows a standard compiler architecture: | ||
| 1. **Lexer (`lexer/`)**: Tokenizes source code. | ||
| 2. **Parser (`parser/`)**: Constructs the AST (`ast/`). | ||
| 3. **Walker (`walker/`)**: Performs semantic analysis, type checking, and scope resolution. | ||
| 4. **Generator (`generator/`)**: Transpiles the AST into Lua code. | ||
| 5. **LSP (`lsp/`)**: Provides Language Server Protocol support for editors (VS Code). | ||
|
|
||
| ## Development Environments | ||
|
|
||
| Hybroid supports distinct "environments" that dictate available standard libraries and compilation behavior: | ||
| * `Level`: For game levels (access to `fmath`, restricted Lua stdlib). | ||
| * `Mesh`: For generating meshes (full math support). | ||
| * `Sound`: For generating sounds. | ||
|
|
||
| ## Build & Usage | ||
|
|
||
| ### Prerequisites | ||
| * Go 1.23+ | ||
| * Python 3 (for build scripts) | ||
|
|
||
| ### Building the CLI | ||
| To build the native CLI executable: | ||
| ```bash | ||
| go build -o hybroid main_native.go | ||
| ``` | ||
|
|
||
| ### Running the CLI | ||
| ```bash | ||
| ./hybroid <command> [arguments] | ||
| ``` | ||
| Common commands: | ||
| * `init`: Initialize a new Hybroid project. | ||
| * `build`: Compile Hybroid code to Lua. | ||
| * `watch`: Watch for changes and recompile. | ||
|
|
||
| ### Building for Release | ||
| Use the Python helper script: | ||
| ```bash | ||
| python utils/build_hybroid.py | ||
| ``` | ||
|
|
||
| ### Testing | ||
| Run standard Go tests: | ||
| ```bash | ||
| go test ./... | ||
| ``` | ||
|
|
||
| ## Directory Structure | ||
|
|
||
| * `alerts/`: Error reporting system (diagnostics, pretty printing). | ||
| * `ast/`: Abstract Syntax Tree node definitions. | ||
| * `cli/`: Implementation of CLI commands. | ||
| * `core/`: Core data structures (Queue, Stack, Span). | ||
| * `docs/`: Documentation website (Astro). | ||
| * `evaluator/`: Constant evaluation and testing logic. | ||
| * `examples/`: Sample Hybroid projects and code snippets. | ||
| * `generator/`: Lua code generation logic. | ||
| * `lexer/`: Source code tokenization. | ||
| * `lsp/`: Language Server Protocol implementation. | ||
| * `parser/`: Recursive descent parser. | ||
| * `tokens/`: Token type definitions. | ||
| * `utils/`: Python scripts for build, API generation, and maintenance. | ||
| * `walker/`: Semantic analysis and type checking. | ||
| * `wasm/`: WASM bindings for the web playground. | ||
|
|
||
| ## Key Files | ||
|
|
||
| * `main_native.go`: Entry point for the CLI. | ||
| * `spec.md`: The Hybroid language specification. | ||
| * `hybconfig.toml`: Project configuration file (seen in examples). | ||
| * `go.mod`: Go dependencies. | ||
|
|
||
| ## Conventions | ||
|
|
||
| * **Language:** Go for the toolchain, Python for build scripts. | ||
| * **Style:** Follows standard Go formatting (`gofmt`). | ||
| * **Testing:** Uses Go's built-in testing framework. | ||
| * **Documentation:** Maintained in `docs/` and `spec.md`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| //go:build !js | ||
|
|
||
| package main | ||
|
|
||
| import ( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| //go:build js && wasm | ||
|
|
||
| package main | ||
|
|
||
| import ( | ||
| _ "hybroid/wasm" | ||
| ) | ||
|
|
||
| func main() { | ||
| // Prevent the program from exiting so the JS functions remain registered | ||
| select {} | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,168 @@ | ||||||||||||||||||
| //go:build js && wasm | ||||||||||||||||||
|
|
||||||||||||||||||
| package wasm | ||||||||||||||||||
|
|
||||||||||||||||||
| import ( | ||||||||||||||||||
| "bufio" | ||||||||||||||||||
| "errors" | ||||||||||||||||||
| "fmt" | ||||||||||||||||||
| "hybroid/alerts" | ||||||||||||||||||
| "hybroid/ast" | ||||||||||||||||||
| "hybroid/generator" | ||||||||||||||||||
| "hybroid/lexer" | ||||||||||||||||||
| "hybroid/parser" | ||||||||||||||||||
| "hybroid/walker" | ||||||||||||||||||
| "strings" | ||||||||||||||||||
| "syscall/js" | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
| // Helper to reconstruct lines from source code | ||||||||||||||||||
| func sourceToLines(source string) map[int][]byte { | ||||||||||||||||||
| lines := make(map[int][]byte) | ||||||||||||||||||
| scanner := bufio.NewScanner(strings.NewReader(source)) | ||||||||||||||||||
| lineNum := 1 | ||||||||||||||||||
| for scanner.Scan() { | ||||||||||||||||||
| // Copy the bytes because scanner reuses the buffer | ||||||||||||||||||
| txt := scanner.Text() | ||||||||||||||||||
| lines[lineNum] = []byte(txt) | ||||||||||||||||||
| lineNum++ | ||||||||||||||||||
| } | ||||||||||||||||||
| return lines | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
Tasty-Kiwi marked this conversation as resolved.
|
||||||||||||||||||
| // formatAlerts converts a list of alerts into a formatted string with ANSI color codes, including error locations and code snippets. | ||||||||||||||||||
| func formatAlerts(alertsList []alerts.Alert, source string) string { | ||||||||||||||||||
| lines := sourceToLines(source) | ||||||||||||||||||
| var sb strings.Builder | ||||||||||||||||||
|
|
||||||||||||||||||
| for _, alert := range alertsList { | ||||||||||||||||||
| msg := "" | ||||||||||||||||||
| switch alert.AlertType() { | ||||||||||||||||||
| case alerts.Error: | ||||||||||||||||||
| msg = fmt.Sprintf("[light_red][bold]error[%s]: [reset]", alert.ID()) | ||||||||||||||||||
| case alerts.Warning: | ||||||||||||||||||
| msg = fmt.Sprintf("[light_yellow][bold]warning[%s]: [default]", alert.ID()) | ||||||||||||||||||
| } | ||||||||||||||||||
| sb.WriteString(msg) | ||||||||||||||||||
| sb.WriteString(fmt.Sprintf("[bold]%s[reset]\n", alert.Message())) | ||||||||||||||||||
|
|
||||||||||||||||||
| // Location | ||||||||||||||||||
| tokensList := alert.SnippetSpecifier().GetTokens() | ||||||||||||||||||
| if len(tokensList) > 0 { | ||||||||||||||||||
| sb.WriteString(fmt.Sprintf(" at line %d:%d\n", tokensList[0].Line, tokensList[0].Column.Start)) | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // Snippet | ||||||||||||||||||
| snippet := alert.SnippetSpecifier().GetSnippet(lines, alert) | ||||||||||||||||||
| sb.WriteString(snippet) | ||||||||||||||||||
|
|
||||||||||||||||||
| // Note | ||||||||||||||||||
| if alert.Note() != "" { | ||||||||||||||||||
| sb.WriteString(fmt.Sprintf("note: %s\n", alert.Note())) | ||||||||||||||||||
| } | ||||||||||||||||||
| sb.WriteString("\n") | ||||||||||||||||||
| } | ||||||||||||||||||
| return sb.String() | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
||||||||||||||||||
| // compile transpiles Hybroid source code to Lua, collecting and formatting any | |
| // warnings or errors encountered during lexing, parsing, and semantic analysis. | |
| // The input parameter code is the Hybroid source as a string. It returns the | |
| // generated Lua source code, or a non-nil error if a fatal issue is detected. |
Copilot
AI
Jan 15, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error messages returned to JavaScript callers are very generic ('expected 1 argument', 'expected string'). Consider making these more descriptive, such as 'hybroidCompile expects exactly 1 argument (code as string)' to provide better developer experience for JavaScript users of the API.
| return "expected 1 argument" | |
| } | |
| if args[0].Type() != js.TypeString { | |
| return "expected string" | |
| return "hybroidCompile expects exactly 1 argument (code as string)" | |
| } | |
| if args[0].Type() != js.TypeString { | |
| return "hybroidCompile expects its first argument to be a string containing the code to compile" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file removal logic will fail if the build directory contains subdirectories, as os.remove only works with files. Consider using os.path.isfile() to filter only files, or handle the exception when attempting to remove a directory.