Limitations
"Implemented" means it runs and has a test in tests/. "Partial" means it works for the documented cases and no others. "Planned" means it does not exist yet.
Implemented
Core language: variables (=, let, const), function-level scoping, all listed types, arithmetic/comparison/logical operators, string interpolation, if/otherwise if/otherwise, for each, for ... from ... to ..., repeat ... times, while, break, continue, functions with default arguments and closures, try/catch with typed errors.
Filesystem: create file/folder, write, append, read, delete file/folder, list files in, file/folder ... exists, path(...) with .name/.extension/.parent/.exists.
Processes: run "cmd" (no shell), run "cmd" with arguments [...], with timeout ... seconds, structured results, real process-to-process piping with ->.
HTTP: get/post/put/patch/delete, with header {...}, with query {...}, with timeout ... seconds, send json {...}, download/save as, is successful/is failed, TLS always verified, JSON body parsing on .json.
JSON: parse_json, to_json (pretty by default); map/list literals are already JSON-shaped.
Modules: use "./local_file" (or .ez), built-in module name validation.
Concurrency: parallel block (thread-per-assignment, join-all).
Misc: matches (regex), wait N seconds, a generic -> pipeline binding it, a CLI (ezy run|check|repl), a REPL, arguments for CLI scripts, defined exit codes.
Tests: 118 automated tests covering the lexer, parser, interpreter semantics (scoping, closures, error types, edge cases like division by zero and out-of-range indexing), filesystem operations in isolated temp directories, process execution (missing command, non-zero exit, a real timeout), HTTP against a local test server (no external network required for the suite), and CLI exit codes and argument handling.
Partial
parallelonly accepts a flat list ofname = expressionassignments at its top level — no per-task cancellation, no nestedparallel, no timeout on the whole block. It is genuinely threaded, which helps for I/O-bound scripts but does not parallelize CPU-bound Ezy code because of CPython's GIL.readonly supports UTF-8 text files; a binary file raises a clearFileErrorrather than crashing unpredictably or silently corrupting data.- The REPL's multi-line block detection is a heuristic, not a full incremental parse. It handles the common cases but can be confused by unusual formatting.
->pipelines: when every stage is arun "..."call, it performs a real OS-level pipe. Otherwise it bindsitto the previous value — it does not lazily stream large collections.
Planned (not implemented)
- Package manager (
package install/remove/update/publish). A significant trust boundary — signature verification, lock files, a real registry — a fake or insecure one would be worse than none.use "./local_file"covers the single-project case for now. - Formatter (
ezy format). A half-working formatter that occasionally reflows a script incorrectly is worse than none. - Linter beyond syntax checking.
ezy checkcurrently validates syntax only. - A declarative CLI-definition DSL (
command "name" / argument ... required). Use the built-inargumentslist andinteger(...)/string(...)conversions directly for now. - HEAD/OPTIONS/custom HTTP methods, proxies, client certificates, cookies as a first-class object, HTTP/2/3, streaming responses, resumable downloads, Unix-socket transport. The HTTP subsystem covers the common REST-client case on top of
requests, which itself doesn't support HTTP/2/3 or Unix sockets. every N seconds ...recurring scheduler. A statement that blocks forever running a callback is a meaningfully different execution model (a long-lived service, not a one-shot script) and was left out rather than half-implemented.- Windows support. Development and testing were done on Linux; nothing has been verified on Windows.
- Bytecode compiler / VM. The interpreter tree-walks the AST directly — see Architecture.
- Sandboxing. See Security — scripts have the same filesystem/process/network access as the OS user running them.
Deliberate design deviations from the original brief
- Pipeline modifiers use explicit function calls over
it(-> filter(it, is_even)) rather than a bare-predicate DSL (-> filter age >= 18). A point-free predicate syntax needs its own parsing rules layered onto expressions, which fragments the grammar; routing everything through one expression grammar is more coherent, at the cost of a few extra characters per stage. - HTTP request modifiers are trailing
with/sendclauses rather than an indented sub-block. This keeps modifiers composable in a single expression instead of only valid as a special statement shape, and reuses map literals instead of inventing a second way to write a map. filesis a contextual keyword, recognized only immediately afterlist, rather than fully reserved — because the canonical example (files = list files in "projects") uses "files" as both a variable name and part of the syntax on the same line. Every other keyword is fully reserved; this is the one deliberate exception.- String interpolation reserves
{and}inside string literals, requiring\{/\}for a literal brace. Standard for languages with{}interpolation — building the same data as a map/list literal avoids the issue entirely.