# Baba Yaga Code Formatter (`fmt.js`) A code formatter for the Baba Yaga programming language, similar to Go's `fmt` tool. It automatically formats Baba Yaga source code according to consistent style guidelines. ## Features - **Consistent Formatting**: Applies standard formatting rules across all Baba Yaga code - **Automatic Indentation**: Proper indentation for nested structures (functions, when expressions, with blocks) - **Operator Spacing**: Consistent spacing around operators and punctuation - **Line Breaking**: Smart line breaking for long expressions and data structures - **Comment Preservation**: Maintains existing comments (work in progress) - **Type Annotation Formatting**: Proper formatting of typed function parameters and return types ## Installation The formatter uses the existing Baba Yaga lexer and parser. Ensure you have the core language files: - `lexer.js` - `parser.js` - `fmt.js` ## Usage ### Command Line ```bash # Format and print to stdout node fmt.js file.baba # Format and write back to file node fmt.js --write file.baba node fmt.js -w file.baba # Check if file is already formatted (exit code 0 if formatted, 1 if not) node fmt.js --check file.baba node fmt.js -c file.baba # Custom indentation size (default: 2 spaces) node fmt.js --indent=4 file.baba ``` ### As a Module ```javascript import { BabaYagaFormatter } from './fmt.js'; const formatter = new BabaYagaFormatter({ indentSize: 2, maxLineLength: 100, preserveComments: true }); const source = `x:2+3;y:x*2;`; const formatted = formatter.format(source); console.log(formatted); // Output: // x : 2 + 3; // y : x * 2; ``` ## Formatting Rules ### Function Body Indentation All function bodies are properly indented relative to the function name: ```baba // Simple function body inc : x -> x + 1; // Complex function body with when expression classify : n -> when n is 0 then "zero" _ then "other"; // Function with with header calculate : a b -> with ( sum : a + b; product : a * b; ) -> {sum: sum, product: product}; ``` ### Basic Declarations **Before:** ```baba x:42;y:"hello"; ``` **After:** ```baba x : 42; y : "hello"; ``` ### Functions **Before:** ```baba add:x y->x+y; multiply:(x:Int,y:Int)->Int->x*y; ``` **After:** ```baba add : x y -> x + y; multiply : (x: Int, y: Int) -> Int -> x * y; ``` ### When Expressions **Before:** ```baba check:x->when x is 1 then"one"2 then"two"_ then"other"; ``` **After:** ```baba check : x -> when x is 1 then "one" 2 then "two" _ then "other"; ``` ### Then Keyword Alignment The formatter ensures all `then` keywords within a `when` expression scope are aligned for maximum readability: **Before:** ```baba processRequest : method path -> when method path is "GET" "/" then "Home page" "GET" "/about" then "About page" "POST" "/api/users" then "Create user" "DELETE" "/api/users" then "Delete user" _ _ then "Not found"; ``` **After:** ```baba processRequest : method path -> when method path is "GET" "/" then "Home page" "GET" "/about" then "About page" "POST" "/api/users" then "Create user" "DELETE" "/api/users" then "Delete user" _ _ then "Not found"; ``` This alignment is maintained within each `when` scope, making nested when expressions highly readable. ### Lists and Tables **Before:** ```baba nums:[1,2,3,4,5]; person:{name:"Alice",age:30,active:true}; ``` **After:** ```baba nums : [1, 2, 3, 4, 5]; person : {name: "Alice", age: 30, active: true}; ``` For longer structures, the formatter uses multi-line format: ```baba longList : [ 1, 2, 3, 4, 5 ]; complexTable : { name: "Alice", details: { age: 30, city: "Boston" }, preferences: ["tea", "books", "coding"] }; ``` ### With Headers **Before:** ```baba calc:x y->with(a:x+1;b:y*2;)->a+b; ``` **After:** ```baba calc : x y -> with ( a : x + 1; b : y * 2; ) -> a + b; ``` ### Function Calls **Before:** ```baba result:add 5 3; complex:map(x->x*2)[1,2,3]; ``` **After:** ```baba result : add 5 3; complex : map (x -> x * 2) [1, 2, 3]; ``` ## Supported Node Types The formatter handles all major Baba Yaga language constructs: - **Declarations**: Variables, functions, types - **Expressions**: Binary, unary, function calls, member access - **Literals**: Numbers, strings, booleans, lists, tables - **Control Flow**: When expressions with pattern matching - **Advanced Features**: With headers, curried functions, anonymous functions - **Type Annotations**: Typed parameters and return types ## Error Handling If the formatter encounters a parsing error, it will report the issue and exit with a non-zero status code: ```bash $ node fmt.js invalid.baba Error formatting 'invalid.baba': Formatting failed: Expected token type COLON but got SEMICOLON at 1:5 ``` ## Integration with Editors The formatter can be integrated with various editors: ### VS Code Add to your `settings.json`: ```json { "[baba]": { "editor.defaultFormatter": "none", "editor.formatOnSave": false } } ``` Then create a task in `.vscode/tasks.json`: ```json { "version": "2.0.0", "tasks": [ { "label": "Format Baba Yaga", "type": "shell", "command": "node", "args": ["fmt.js", "--write", "${file}"], "group": "build", "presentation": { "echo": true, "reveal": "silent", "focus": false, "panel": "shared" } } ] } ``` ### Command Line Integration Add to your shell profile (`.bashrc`, `.zshrc`, etc.): ```bash # Format all .baba files in current directory alias babafmt='find . -name "*.baba" -exec node /path/to/fmt.js --write {} \;' # Check formatting of all .baba files alias babafmtcheck='find . -name "*.baba" -exec node /path/to/fmt.js --check {} \;' ``` ## Examples ### Before Formatting ```baba // Unformatted Baba Yaga code factorial:n->when n is 0 then 1 1 then 1 _ then n*(factorial(n-1)); numbers:[1,2,3,4,5];sum:reduce(acc x->acc+x)0 numbers; user:{name:"Alice",age:30,calculate:x y->x+y}; ``` ### After Formatting ```baba // Unformatted Baba Yaga code factorial : n -> when n is 0 then 1 1 then 1 _ then n * (factorial (n - 1)); numbers : [1, 2, 3, 4, 5]; sum : reduce (acc x -> acc + x) 0 numbers; user : { name: "Alice", age: 30, calculate: x y -> x + y }; ``` ## Contributing The formatter is built using the existing Baba Yaga AST structure. To add support for new language features: 1. Add the new node type to the `visitNode` method 2. Implement a corresponding `format*` method 3. Add test cases 4. Update this documentation ## Known Limitations - Comment preservation is basic and may not handle all edge cases - Very complex nested expressions might need manual formatting - Error recovery could be improved for malformed input ## License Same as the Baba Yaga language implementation.