{"id":39584766,"url":"https://github.com/aleloi/zepl","last_synced_at":"2026-01-24T22:48:15.445Z","repository":{"id":277814975,"uuid":"933547038","full_name":"aleloi/zepl","owner":"aleloi","description":"Experimental repl for zig","archived":false,"fork":false,"pushed_at":"2025-02-23T15:19:27.000Z","size":2548,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-23T16:25:24.609Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Zig","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/aleloi.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":"2025-02-16T08:16:57.000Z","updated_at":"2025-02-22T19:16:18.000Z","dependencies_parsed_at":"2025-02-16T10:39:37.783Z","dependency_job_id":null,"html_url":"https://github.com/aleloi/zepl","commit_stats":null,"previous_names":["aleloi/zepl"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/aleloi/zepl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleloi%2Fzepl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleloi%2Fzepl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleloi%2Fzepl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleloi%2Fzepl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aleloi","download_url":"https://codeload.github.com/aleloi/zepl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aleloi%2Fzepl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28738979,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T22:12:27.248Z","status":"ssl_error","status_checked_at":"2026-01-24T22:12:10.529Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":"2026-01-18T07:35:27.100Z","updated_at":"2026-01-24T22:48:15.429Z","avatar_url":"https://github.com/aleloi.png","language":"Zig","funding_links":[],"categories":["\u003ca name=\"Zig\"\u003e\u003c/a\u003eZig"],"sub_categories":[],"readme":"## Zepl\n\nExperimental Zig REPL.\n\n### Usage\n![examples/zepl_cast.svg](examples/zepl_cast.svg)\n\n```C\n$ git clone https://github.com/aleloi/zepl.git \u0026\u0026 cd zepl\n$ zig build\n$ ./zig-out/bin/zepl\nzepl\u003e var x: i32 = 123;\nzepl\u003e @import(\"std\").debug.print(\"interactive zig!\\n\", .{});\n interactive zig!\n interactive zig!\nzepl\u003e const alloc = @import(\"std\").heap.page_allocator;\n mem.Allocator{ .ptr = anyopaque@0, .vtable = mem.Allocator.VTable{ ... } }\n mem.Allocator{ .ptr = anyopaque@0, .vtable = mem.Allocator.VTable{ ... } }\nzepl\u003e x\n 123\n 123\nzepl\u003e @import(\"builtin\").zig_version\n 0.13.0\n 0.13.0\nzepl\u003e const std = @import(\"std\");\nzepl\u003e std.SemanticVersion.parse\n fn ([]const u8) @typeInfo(@typeInfo(@TypeOf(SemanticVersion.parse)).Fn.return_type.?).ErrorUnion.error_set!SemanticVersion@1032c0930\n fn ([]const u8) @typeInfo(@typeInfo(@TypeOf(SemanticVersion.parse)).Fn.return_type.?).ErrorUnion.error_set!SemanticVersion@1032c0930\nzepl\u003e std.json.parseFromSlice(struct {x: i32, y:i32}, alloc.*, \"{\\\"x\\\": 10, \\\"y\\\": 0}\", .{}) catch |err| err\n json.static.Parsed(snippet_4.__snippet_4__struct_1667){ .arena = {...} , .state = {...}, .end_index = 0, .value = snippet_4.__snippet_4__struct_1667{ .x = 10, .y = 0 } }\n// suppose testfile.zig has `pub fn sqr(i32) i32` and `pub var string_constant = \"abc\"`\nzepl\u003e const tst = @import(\"testfile.zig\");\nzepl\u003e tst.string_constant\n{ 97, 98, 99 }\n// change the constant to \"123\"\nzepl\u003e tst.string_constant\n{ 49, 50, 51 }\n```\n\n\n### How it works\nTDLR: check the zig docs https://aleloi.github.io/zepl/ \n\nIf you set the log level to .debug in `main.zig` it prints\n```python\n```python\nzepl\u003e var x: i32 = 0;\n  [debug] (zepl_parse)  ParseError as a value, trying container-level member\n  [debug] (zepl_comp)  wrote tmpfile_0.zig, checking if it compiles\n  [debug] (zepl_comp)  tmpfile_0.zig compilation exit code: 0\n  [debug] (zepl)  Parsed AST: parse.ParseResult.Tag.container_level_decl\n  [debug] (zepl_prpc)  Top level is: zig.Ast.Node.Tag.simple_var_decl\n  [debug] (zepl_prpc)  parsed decl, before mut is: ''\n    mut is: 'var'\n    name is: 'x'\n    tpe is 'i32 '\n    rhs is '0'\n  [debug] (zepl_prpc)  trying exporting as C-ABI value ;y\n  [debug] (zepl_comp)  wrote tmpfile_1.zig, checking if it compiles\n  [debug] (zepl_comp)  tmpfile_1.zig compilation exit code: 0\n  [debug] (zepl_comp)  wrote tmpfile_2.zig, checking if it compiles\n  [debug] (zepl_comp)  tmpfile_2.zig compilation exit code: 0\n  [debug] (zepl_comp)  compiling snippet_1.zig\n  [debug] (zepl_comp)  compiled snippet_1.zig into ./libsnippet_1.dylib\n  [debug] (zepl)  loading dylib: ./libsnippet_1.dylib\n```\n\nIt tries to compile each command by itself and dynamically load it in the REPL process. We need the context of previous snippets which is included though lots of `@extern` and `@export` declarations. All comptime statements have to be zeplayed for each snippet. When we can't `@export` a variable, we export its adress. That's the reason for why your non-pointer types change to pointers.\nIt tries to compile each command by itself and dynamically load it in the REPL process. We need the context of previous snippets which is included though lots of `@extern` and `@export` declarations. All comptime statements have to be zeplayed for each snippet. When we can't `@export` a variable, we export its adress. That's the reason for why your non-pointer types change to pointers.\n\n### Missing features, contributors welcome!\nA list of features that are relatively easy to implement:\n* handle more input, e.g. `command1; command2;`, `command; // comment`, `command_returning_error_without_catch_or_try;`\n* code completion. E.g. feed a command history to ZLS and fetch completions.\n* syntax highlighting\n* `@export` for functions, not just variables. I think it only works for ABI-compatible param types.\n* searchable history\n* multiline input\n* custom build-file to list additional dependencies.\n* describe the semantics of what commands are allowed. Currenly it just tries to do a few (up to 3) versions of each command until it finds one that compiles.\n* make it build with 0.14.0-pre\n* make it respect `const` - I think I made a bug so that all non-ABI compatible vars are mutable\n\n\nMore complex:\n* find free variables in the input snippet and only add their declarations in the context. std.zig.Ast doesn't make it easy.\n* automatically dereference variables that we converted to pointers\n\nA list of features that I'd like to have but don't know how to implement:\n* don't re-evaluate the whole chain of comptime expressions on each snippet. ZLS uses a comptime interpreter somehow, look in to that?\n* don't recompile non-generic functions. This requires understanding more of the compiler. Dynamic loading is not enough.\n\n* Gurus say that [hot-reloading](https://github.com/ziglang/zig/issues/68) and [`--watch`](https://ziggit.dev/t/initial-implementation-of-zig-build-watch-just-landed-in-master-branch/5117) is relevant.\n\nChores\n* stop leaking memory\n* add a few tests\n* make a test setup for feeding container-level statements one-by-one into the zepl. It will definitely crash for some.\n\n#### Planned features\n* use something similar to this from the compiler https://github.com/ziglang/zig/blob/master/lib/compiler/reduce/Walk.zig to walk the Ast and find free vars in an expression. Make sure to auto-defererence the ones that the early step made pointers.\n* once that's done: write a test framework that we feed the top-level container members of zig files one expression at a time. For now to check that it compiles+interprets, but later to have an option similar to `python -i script.py`. It would interpret each top-level statement of a file and then enter a repl context with everything evaluated.\n\n\n### Known issues\nMost variables enter the scope as pointers. When you type `const alloc = std.heap.page_allocator;`, you get `alloc: *std.mem.Allocator` instead of `alloc: std.mem.Allocator`. Sometimes you don't even notice, because members can be accessed on a struct without explicit dereferencing. \n\nModules loaded with `const otherfile = @import(\"otherfile.zig\")` are re-compiled on every snippet, meaning that changing `otherfile.mutable_var` from within the repl has no effect.\n\nIt allows a bit too much. E.g. `var x: i32 = x;` is OKAY because it's processed into\n```zig\n  // context\nexport var x: i32  = undefined;\n  // export\n  // comptime\nexport fn __snippet_1 () void {\n    x = x;\n\n}\n  // side effects\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faleloi%2Fzepl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faleloi%2Fzepl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faleloi%2Fzepl/lists"}