{"id":23328017,"url":"https://github.com/andy-byers/paw","last_synced_at":"2025-09-04T01:39:55.836Z","repository":{"id":228914071,"uuid":"773512793","full_name":"andy-byers/paw","owner":"andy-byers","description":"A statically-strong typed embeddable scripting language for C","archived":false,"fork":false,"pushed_at":"2025-08-12T05:21:55.000Z","size":3649,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-22T23:12:22.960Z","etag":null,"topics":["c","scripting-language"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andy-byers.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-03-17T21:20:32.000Z","updated_at":"2025-08-12T05:21:33.000Z","dependencies_parsed_at":"2024-05-05T22:25:11.077Z","dependency_job_id":"97c27e73-634f-4bb9-a3ae-c968e1ae8c7b","html_url":"https://github.com/andy-byers/paw","commit_stats":null,"previous_names":["andy-byers/paw"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/andy-byers/paw","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andy-byers%2Fpaw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andy-byers%2Fpaw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andy-byers%2Fpaw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andy-byers%2Fpaw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andy-byers","download_url":"https://codeload.github.com/andy-byers/paw/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andy-byers%2Fpaw/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273539293,"owners_count":25123499,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"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":["c","scripting-language"],"created_at":"2024-12-20T20:54:14.368Z","updated_at":"2025-09-04T01:39:55.816Z","avatar_url":"https://github.com/andy-byers.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# paw\n\n\u003e NOTE: Paw is under active development and is not ready for production use.\n\u003e See the [roadmap](#roadmap) to get an idea of where things are going.\n\u003e Also see [known issues](#known-issues) for a list of known problems that will eventually be fixed.\n\nA cute little scripting language\n\nPaw is a high-level, statically-typed, embeddable scripting language.\nIt is designed to run on a virtual machine written in C.\n\n## Features\n+ No dependencies\n+ Static strong typing\n+ Bidirectional type checking\n+ Block expressions\n+ Module system\n+ Exhaustive pattern matching and sum types\n+ Traits (interfaces checked at compile time)\n+ Generics and generic bounds\n+ Unboxed objects using \"inline\" keyword\n+ Container literals (`[T]` and `[K: V]`)\n\n## Examples\n\n### Hello world\n```paw\npub fn main() {\n    println(\"Hello, world!\");\n}\n```\n\n### FizzBuzz\n```paw\npub fn main() {\n    // Create a closure. The type of \"n\" is inferred as \"int\" and the \n    // return type as \"str\".\n    let fizzbuzz = |n| {\n        if n % 15 == 0 { \n            \"FizzBuzz\" \n        } else if n % 3 == 0 {\n            \"Fizz\"\n        } else if n % 5 == 0 {\n            \"Buzz\" \n        } else { \n            n.to_str() \n        }\n    };\n\n    // Call the closure for each integer 1 to 100, exclusive.\n    for i in 1..100 {\n        println(\"fizzbuzz(\\{i}) = \\{fizzbuzz(i)}\");\n    }\n}\n```\n\n### Containers\n```paw\npub fn main() {\n    let list = []; // [int]\n\n    // add a single element to the end\n    list.push(1); // [1]\n\n    // concatenate with another list\n    list += [2, 3, 4]; // [1, 2, 3, 4]\n\n    // lists (and \"str\") can be indexed with range objects\n    let suffix = list[-2..]; // [3, 4]\n    let prefix = list[0..3]; // [1, 2, 3]\n\n\n    let map = [:]; // [char: int]\n\n    // add a few key-value pairs\n    map['a'] = 1;\n    map['b'] = 2;\n    map['c'] = 3;\n\n    match map.get('a') {\n        Some(v) =\u003e println(\"map['a'] = \\{v}\"),\n        None =\u003e panic(\"not found\"),\n    }\n\n    assert(map.get_or('d', 4) == 4);\n}\n```\n\n### Sum types\nNote that \"inline\" cannot be used on a recursive type as this would cause resulting objects to have a size of infinity (see [value types](#value-types)).\n```paw\npub enum Expr {\n    Zero,\n    Succ(Expr),\n    Add(Expr, Expr)\n}\n\n// import variants into the global value namespace\nuse Expr::*;\n\npub fn eval(e: Expr) -\u003e int {\n    // match expressions must be exhaustive\n    match e {\n        Zero =\u003e 0,\n        Succ(x) =\u003e eval(x) + 1,\n        Add(x, y) =\u003e eval(x) + eval(y),\n    }\n}\n\npub fn three() -\u003e int {\n    let zero = Zero;\n    let one = Succ(zero);\n    let two = Add(one, one);\n    eval(Add(one, two))\n}\n```\n\n### Generics\nPaw supports parametric polymorphism, a.k.a. generic type parameters.\n\n```paw\n// type aliases can accept type arguments\ntype VecList2\u003cT\u003e = [(T, T)];\n\nfn map2\u003cX, Y\u003e(f: fn(X, X) -\u003e Y, xs: VecList2\u003cX\u003e) -\u003e [Y] {\n    let ys = [];\n    // destructuring is supported in \"for\" loops and \"let\" declarations\n    for (a, b) in xs {\n        ys.push(f(a, b));\n    }\n    ys\n}\n\npub fn main() {\n    let data = [\n        (1, 2),\n        (2, 3),\n        (3, 4),\n        (4, 5),\n        (5, 6),\n    ];\n\n    let data = map2(|x: int, y| x + y, data);\n\n    let total = 0;\n    for value in data {\n        total = total + value;\n    }\n\n    println(\"total = \\{total}\"); // total = 35\n}\n\n```\n\n### Traits\n\n```paw\npub trait Get\u003cT\u003e {\n    fn get(self) -\u003e T;\n}\n\nstruct Inner\u003cX\u003e: Get\u003cX\u003e {\n    pub value: X,\n\n    pub fn get(self) -\u003e X {\n        self.value\n    }\n}\n\nstruct Outer\u003cX: Get\u003cY\u003e, Y\u003e: Get\u003cY\u003e {\n    pub value: X,\n\n    pub fn get(self) -\u003e Y {\n        self.value.get()\n    }\n}\n\nfn get\u003cX: Get\u003cY\u003e, Y\u003e(x: X) -\u003e Y {\n    x.get()\n}\n\npub fn main() {\n    let inner = Inner{value: 123};\n    let outer = Outer{value: inner};\n    let value = get(outer);\n\n    println(\"value = \\{value}\"); // value = 123\n}\n```\n\n### Value types\nStructures and enumerations have reference semantics by default.\nThe `inline` keyword can be used to give a type value semantics.\nPrimitives (`int`, `float`, etc.) and tuples are always value types.\nInline types can be used to reduce memory consumption in programs containing many small objects.\nThey can also be used to implement \"newtype\" wrappers with no additional runtime overhead.\n```paw\ninline struct Data\u003cT\u003e {\n    pub value: T,\n}\n\npub fn main() {\n    // \"data\" consists of exactly 3 integers stored directly in the activation frame\n    let data = Data{value: Data{value: (1, (2, 3))}};\n\n    // all fields are copied: \"copy\" is independent from \"data\"\n    let copy = data;\n}\n```\n\n## Error handling\nPaw uses `Result\u003cT, E\u003e` to express a recoverable error, e.g. \"no such file or directory\".\nRuntime panics are issued for unrecoverable errors, e.g. \"out of memory\", an assertion failure, or an out-of-bounds element access.\nPanics cannot be caught inside Paw.\nA panic always stops execution at the location of the panic and causes the VM entrpoint function to return with an error.\nA panic can also be caused by calling the `panic` builtin function.\n\n## Operators\n\n|Precedence|Operator                 |Description                                  |Associativity|\n|:---------|:------------------------|:--------------------------------------------|:------------|\n|14        |`() [] . ?`              |Call, Subscript, Member access, Question mark|Left         |\n|13        |`! - ~ #`                |Not, Negate, Bitwise not, length             |Right        |\n|12        |`as`                     |Cast                                         |Left         |\n|11        |`* / %`                  |Multiply, Divide, Modulus                    |Left         |\n|10        |`+ -`                    |Add, Subtract                                |Left         |\n|9         |`\u003c\u003c \u003e\u003e`                  |Shift left, Shift right                      |Left         |\n|8         |`\u0026`                      |Bitwise and                                  |Left         |\n|7         |`^`                      |Bitwise xor                                  |Left         |\n|6         |\u003ccode\u003e\u0026#124;\u003c/code\u003e      |Bitwise or                                   |Left         |\n|5         |`\u003c \u003c= \u003e \u003e=`              |Relational comparisons                       |Left         |\n|4         |`== !=`                  |Equality comparisons                         |Left         |\n|3         |`\u0026\u0026`                     |And                                          |Left         |\n|2         |\u003ccode\u003e\u0026#124;\u0026#124;\u003c/code\u003e|Or                                           |Left         |\n|1         |`= op=`                  |Assignment, operator assignment              |Right        |\n\n## Roadmap\n+ [x] fix list/str slice operation (should use `Range`, `RangeTo`, etc.)\n+ [ ] use `mut` to indicate mutability and make immutable the default for local variables\n+ [ ] decide on and implement either RAII or \"defer\" for cleaning up resources\n+ [ ] overflow checks for `paw_Int` operations during constant folding and inside VM\n+ [ ] function inlining\n+ [ ] refactor user-provided allocation interface to allow heap expansion\n\n## Known problems\n+ These need to be converted into issues, along with some TODO comments scattered throughout the codebase...\n+ Paw requires that \"int\" be at least 32 bits (probably fine in practice)\n+ Need to make sure functions/closures with a return type annotation of \"!\" diverge unconditionally \n    + See TODO comment in `test_error.c` `test_divergence` function\n    + Consider returns to be jumps to a special block, possibly after setting the return variable\n    + Unconditionally-diverging functions should not have any writes to this variable\n+ Pointer tracking (test only) feature is broken on MSVC\n    + Might indicate a problem somewhere in the library\n    + Need a machine that can run Windows for debugging\n+ Need a lower-level CFG-based IR (LIR) to use for register allocation and codegen\n    + Convert the `scalarize`/`ssa` pass into `lower_mir`, which will output LIR in SSA form\n    + Perform constant propagation on the LIR, monomorphization doesn't need to change\n    + LIR will contain `GETFIELD`, `SETELEMENT`, etc. instructions, which are represented by places in the MIR\n    + Each LIR register will represent a single Paw value (`Value` structure in C), while MIR registers can be multiple values wide\n    + This representation is needed due to the attempt to unbox composite values, it is a bit painful to operate on the MIR\n    + This is somewhat low-priority, since the MIR will work for unboxed values, it's just not quite as nice to work with\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandy-byers%2Fpaw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandy-byers%2Fpaw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandy-byers%2Fpaw/lists"}