{"id":19199644,"url":"https://github.com/aaroncoplan/waterfall","last_synced_at":"2026-06-15T02:32:14.538Z","repository":{"id":67336531,"uuid":"169331163","full_name":"AaronCoplan/waterfall","owner":"AaronCoplan","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-21T04:28:43.000Z","size":1414,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-05-21T08:46:00.559Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AaronCoplan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-05T23:48:47.000Z","updated_at":"2026-05-21T04:28:47.000Z","dependencies_parsed_at":"2023-02-27T20:00:54.836Z","dependency_job_id":null,"html_url":"https://github.com/AaronCoplan/waterfall","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/AaronCoplan/waterfall","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AaronCoplan%2Fwaterfall","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AaronCoplan%2Fwaterfall/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AaronCoplan%2Fwaterfall/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AaronCoplan%2Fwaterfall/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AaronCoplan","download_url":"https://codeload.github.com/AaronCoplan/waterfall/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AaronCoplan%2Fwaterfall/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34345576,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T12:28:15.318Z","updated_at":"2026-06-15T02:32:14.534Z","avatar_url":"https://github.com/AaronCoplan.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Waterfall\n\nA single source language that transpiles to **JavaScript**, **Python**, or **C**.\nWrite Waterfall once; emit code in any supported target.\n\n```\n$ ./waterfall --target python examples/FibonacciModule.wf\n# module FibonacciModule\ndef fib(n):\n    if (n \u003c 2):\n        return n\n    return (fib((n - 1)) + fib((n - 2)))\n...\n```\n\n## Quick start\n\nRequirements: a JDK (17 or 21 has been tested). Gradle and Kotlin are\nfetched by the wrapper.\n\n```bash\n./gradlew build                                  # build the compiler jar\n./waterfall examples/FunctionWithBodyModule.wf   # default: js emitter\n./waterfall --target js examples/FibonacciModule.wf\n./waterfall --target python examples/FibonacciModule.wf\n./waterfall --target c examples/FibonacciModule.wf\n```\n\nThe compiler exits non-zero on any compilation error so it composes cleanly with\nshell pipelines.\n\n## Supported targets\n\n| Target  | Flag              | Runtime check                                                          |\n|---------|-------------------|------------------------------------------------------------------------|\n| JavaScript | `--target js`  | Each example's output passes `node --check`. Default when `--target` is omitted. |\n| Python 3 | `--target python` | Each example's output passes `python3 -c \"import ast; ast.parse(...)\"`. |\n| C99     | `--target c`      | Each example's output passes `gcc -fsyntax-only` (warnings suppressed).|\n\nThe per-target byte-equal expected outputs live under\n[`compiler/src/test/resources/golden/\u003ctarget\u003e/`](compiler/src/test/resources/golden)\nand are exercised by `./gradlew test`.\n\n## Language reference\n\n### Modules\n\nEvery `.wf` file is one `module`. Top-level declarations are variables or\nfunctions.\n\n```\nmodule MyModule {\n    int x = 4\n    func double(int n) returns int {\n        return n + n\n    }\n}\n```\n\n### Primitive types\n\n`int`, `dec`, `bool`, `char`. Arrays of any primitive: `int[]`, `dec[]`,\n`bool[]`, `char[]`.\n\n### Variable declarations\n\nTyped (`type name = expr`), untyped (`name := expr` — type inferred from the\nliteral kind), and re-assignment (`name = expr` or any of `+= -= *= /= %=`).\nModifiers `const` and `imm` mark a binding immutable; the JS / Python / C\nbackends translate this to `const` / `typing.Final` / `const` respectively.\n\n```\nint x = 4\nconst dec pi = 3.14159\nimm bool ready = true\ny := 5            // inferred int\nx += 1\n```\n\n### Functions\n\n```\nfunc add(int a, int b) returns int {\n    return a + b\n}\n\nfunc sideEffect() {        // no return type = void\n    doSomething()\n}\n```\n\nThree call styles:\n\n```\nadd(1, 2)                  // local\nMath::sqrt(2)              // module-qualified\nobj.field.method(arg)      // object / chained\n```\n\nBoth positional and named arguments are supported: `fn(a = 1, b = 2)`.\n\n### Control flow\n\n```\nif(cond) { ... } elif(otherCond) { ... } else { ... }\nwhile(cond) { ... }\nfor(item in collection) { ... }\nreturn                       // bare or `return \u003cexpr\u003e`\n```\n\n### Expressions\n\nLiterals: `42`, `3.14`, `true`, `false`, `NULL`, `` `text` ``, `[1, 2, 3]`,\n`|a, b|` (bundle).\n\nOperators in precedence order:\n\n| Operator                         | Notes                                  |\n|----------------------------------|----------------------------------------|\n| `^`                              | Exponentiation (lowered to `pow()` in C, `**` in JS/Python). |\n| `*` `/` `%`                      | Multiplicative.                        |\n| `+` `-`                          | Additive.                              |\n| `\u003c` `\u003e` `\u003c=` `\u003e=`                | Comparison.                            |\n| `equals`                         | Equality. Emits `===` in JS, `==` in C/Python. |\n| `and`                            | Boolean and. Emits `\u0026\u0026` / `and`.       |\n| `or`                             | Boolean or (loosest). Emits `\\|\\|` / `or`. |\n| `arr[i]`                         | Array indexing.                        |\n| `expr castas type`               | Type cast.                             |\n\nLambdas: `(int x, int y) ==\u003e body` where `body` is a function call. (Statement\nbodies are planned — see roadmap.)\n\n### Increment / decrement\n\nPostfix `++` and `--` are statement-level on plain identifiers:\n\n```\ni++\ncounter--\n```\n\n### Casting\n\n```\nconst charVal := c castas int\nconst asPointer := xs castas dec[]\n```\n\n## Examples\n\nEvery file under [`examples/`](examples/) compiles on every target. Pick one\nand try each backend:\n\n```bash\n./waterfall --target js     examples/ArithmeticModule.wf\n./waterfall --target python examples/FibonacciModule.wf\n./waterfall --target c      examples/ArrayParamsModule.wf\n```\n\nA small Fibonacci that exercises functions, recursion, `while`, comparison,\nreturn values, compound assignment, and `++`:\n\n```\nmodule FibonacciModule {\n    func fib(int n) returns int {\n        if(n \u003c 2) {\n            return n\n        }\n        return fib(n - 1) + fib(n - 2)\n    }\n\n    func sumOfFibs(int upTo) returns int {\n        int total = 0\n        int i = 0\n        while(i \u003c upTo) {\n            total += fib(i)\n            i++\n        }\n        return total\n    }\n}\n```\n\nThe same Euler-style sum-of-multiples that appears in many beginner exercises:\n\n```\nmodule ArithmeticModule {\n    func sumOfMultiples(int limit) returns int {\n        int total = 0\n        int n = 0\n        while(n \u003c limit) {\n            if(n % 3 equals 0 or n % 5 equals 0) {\n                total += n\n            }\n            n++\n        }\n        return total\n    }\n}\n```\n\n## Roadmap\n\nWhat's left to build, ordered foundation-first. The companion file\n[`notes/AUDIT-OPEN-QUESTIONS.md`](notes/AUDIT-OPEN-QUESTIONS.md) has the\nper-item \"best-guess we took today\" plus the cleanest fix path.\n\n### Type-system depth\n\n- **`G4`** — Cross-expression type inference. Today `:=` infers from literal\n  kind only (INT_LITERAL → `int`, etc.); calls / identifiers / arithmetic fall\n  back to `int`. A real inference pass would propagate types through the symbol\n  table.\n- **`G5`** — Type-check `if` / `while` / `for` conditions as `bool`. Depends on\n  `G4`.\n\n### Grammar extensions\n\nThree small additions, useful enough that this README's earlier draft showed\nthem in a `canBeFormed` example before they were caught as unparseable:\n\n- Typed for-in iterator (`for(char c in chars)`).\n- Array-element increment (`arr[i]++` / `arr[i]--`).\n- Method calls on type literals (`int[].create(26)`).\n\n### Cross-target semantic decisions\n\n- **`U1`** — Bundle literals `|a, b|`: pick a representation (tuple? struct?\n  tagged record?) before each backend can stop emitting list placeholders.\n- **`U2`** — C lambdas. Lift the body to a static function in the same TU and\n  reference it by name. Requires an AST transform pass.\n- **`U3`** — Named arguments: pick an ABI per target. Today JS uses a single\n  object literal, Python uses native named args, C drops them.\n- **`C1`** — C `for...in` lowering. Today emits a zero-iteration stub with a\n  TODO comment. Requires a collection representation decision.\n- **`C3`** — C method dispatch (`obj.fn(x)`). Biggest design call: vtables vs.\n  function pointers in structs vs. some hybrid.\n- **`C6`** — JS module wrapping: pick ESM / CJS / IIFE.\n\n### Tooling\n\n- **`C2`** — Per-module C headers so `Module::fn(x)` actually links across TUs.\n- **`T2`** — Sweep the Gradle 9 deprecation warnings.\n\n## Project layout\n\n```\nparser/    ANTLR 4 grammar + a small Kotlin frontend that wraps the generated\n           lexer/parser. Builds an AST.\ncompiler/  Kotlin — the verifier, the CodeGenerator interface, and the three\n           backend implementations (js / python / c).\nexamples/  Working .wf programs, one per feature area.\nnotes/     Audit decisions and the running list of open questions.\n```\n\nThe compiler is written in Kotlin 2.0 targeting the JVM 1.8 bytecode. ANTLR\nemits Java for the lexer/parser; everything else (front-end, backends, tests)\nis Kotlin. `./gradlew build` handles the whole pipeline.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaroncoplan%2Fwaterfall","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faaroncoplan%2Fwaterfall","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faaroncoplan%2Fwaterfall/lists"}