{"id":28320198,"url":"https://github.com/testingrequired/reqlang-expr","last_synced_at":"2025-08-17T18:07:55.625Z","repository":{"id":294096937,"uuid":"985970739","full_name":"testingrequired/reqlang-expr","owner":"testingrequired","description":"A tiny (bytecode compiled, stack VM interpreted) expression language for reqlang's templating engine.","archived":false,"fork":false,"pushed_at":"2025-07-07T01:16:02.000Z","size":284,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-11T23:35:43.610Z","etag":null,"topics":["abstract-syntax-tree","bytecode-compiler","grammar","lalrpop","logos","parser","repl","typechecker","types"],"latest_commit_sha":null,"homepage":"http://www.testingrequired.com/reqlang-expr/","language":"Rust","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/testingrequired.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null}},"created_at":"2025-05-18T22:29:50.000Z","updated_at":"2025-07-07T01:16:05.000Z","dependencies_parsed_at":"2025-05-18T23:28:50.049Z","dependency_job_id":"4318f895-11ea-4482-8d6c-b3bdaa4e1e14","html_url":"https://github.com/testingrequired/reqlang-expr","commit_stats":null,"previous_names":["testingrequired/reqlang-expr"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/testingrequired/reqlang-expr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testingrequired%2Freqlang-expr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testingrequired%2Freqlang-expr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testingrequired%2Freqlang-expr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testingrequired%2Freqlang-expr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/testingrequired","download_url":"https://codeload.github.com/testingrequired/reqlang-expr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/testingrequired%2Freqlang-expr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270885366,"owners_count":24662453,"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-08-17T02:00:09.016Z","response_time":129,"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":["abstract-syntax-tree","bytecode-compiler","grammar","lalrpop","logos","parser","repl","typechecker","types"],"created_at":"2025-05-25T10:08:35.327Z","updated_at":"2025-08-17T18:07:55.613Z","avatar_url":"https://github.com/testingrequired.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Reqlang Expression Language\n\nA small (tiny) WIP expression language for [reqlang](https://github.com/testingrequired/reqlang)'s templating engine.\n\n## Install\n\n![Crates.io Version](https://img.shields.io/crates/v/reqlang-expr)\n\n```toml\n[dependencies]\nreqlang-expr = \"0.8.0\"\n```\n\n```sh\ncargo add reqlang-expr\n```\n\n## Usage\n\nSee [USAGE.md](./USAGE.md) and [examples](./examples/) for usage examples.\n\n## Project\n\n[![Verify](https://github.com/testingrequired/reqlang-expr/actions/workflows/ci.yml/badge.svg)](https://github.com/testingrequired/reqlang-expr/actions/workflows/ci.yml)\n\n- [Lexer](./src/lexer.rs)\n- [Parser](./src/parser.rs), [Grammar](./src/grammer.lalrpop), [AST](./src/ast.rs)\n- [Bytecode Compiler](./src/compiler.rs)\n- [VM interpreter](./src/vm.rs)\n- [Disassembler](./src/disassembler.rs)\n- [Types](./src/types.rs)\n- [REPL](#repl)\n- [Example Usage](./examples/)\n- [Specification Examples](./spec/)\n- [Tests](#tests)\n- [Transpile To Typescript](https://github.com/testingrequired/reqlang-expr-tspl)\n\n## Syntax\n\nThe syntax is s-expression like. There are only [builtin functions](#builtin-functions), identifiers and string literals.\n\n| Syntax                             | Description                                                |\n| ---------------------------------- | ---------------------------------------------------------- |\n| `:a`                               | Reference to the variable `a`                              |\n| `?b`                               | Reference to the prompt `b`                                |\n| `!c`                               | Reference to the secret `c`                                |\n| `id`                               | Reference to the builtin `id`                              |\n| `@key`                             | Reference to the client context value `key`                |\n| `(id :a)`                          | Call to builtin `id` with arguments: `:a`                  |\n| `` `foo` ``                        | String literal                                             |\n| `true`                             | Literal boolean value `true`                               |\n| `false`                            | Literal boolean value `false`                              |\n| `String`                           | Literal type `String`                                      |\n| `Bool`                             | Literal type `Bool`                                        |\n| `Type\u003cString\u003e`                     | Literal type `Type` of type `String`                       |\n| `Fn() -\u003e Bool`                     | Literal type for builtin functions (no args)               |\n| `Fn(Value) -\u003e Bool`                | Literal type for builtin functions (1 arg)                 |\n| `Fn(Value, Bool, String) -\u003e Value` | Literal type for builtin functions (n args)                |\n| `Fn(...String) -\u003e String`          | Literal type for builtin functions (variadic arg)          |\n| `Fn(String, ...String) -\u003e String`  | Literal type for builtin functions (args and variadic arg) |\n\nSee [/spec](./spec/) for more syntax examples.\n\n### Builtin Functions\n\n| Fn                                                        | Description                                     |\n| --------------------------------------------------------- | ----------------------------------------------- |\n| `id(value: Value) -\u003e Value`                               | Returns the string arugment passed to it        |\n| `noop() -\u003e String`                                        | Returns the string \"noop\"                       |\n| `is_empty(value: String) -\u003e String`                       | Checks if the given string is empty             |\n| `and(a: Bool, b: Bool) -\u003e Bool`                           | Logical AND operation between two booleans      |\n| `or(a: Bool, b: Bool) -\u003e Bool`                            | Logical OR operation between two booleans       |\n| `cond(cond: Bool, then: Value, else: Value) -\u003e Bool`      | Conditional expression                          |\n| `to_str(value: Value) -\u003e String`                          | Converts a value to its string representation   |\n| `concat(a: String, b: String, ...rest: String) -\u003e String` | Concatenates a list of values in to a string    |\n| `contains(needle: String, haystack: String) -\u003e Bool`      | Checks for a substring match                    |\n| `trim(value: String) -\u003e String`                           | Trim whitespace from a string                   |\n| `trim_start(value: String) -\u003e String`                     | Trim whitespace from the start of a string      |\n| `trim_end(value: String) -\u003e String`                       | Trim whitespace from the end of a string        |\n| `lowercase(value: String) -\u003e String`                      | Return a lowercase version of a string          |\n| `uppercase(value: String) -\u003e String`                      | Return a uppercase version of a string          |\n| `type(value: Value) -\u003e Type`                              | Get the string representation of a value's type |\n| `eq(a: Value, b: Value) -\u003e Bool`                          | Compare two values for equality                 |\n| `not(value: Bool) -\u003e Bool`                                | Logical NOT operation on a boolean value        |\n\n### Why Backticks For Strings?\n\nThese expressions will be embedded in places where double quotes are common (e.g. JSON). Single quotes weren't chosen due to their use in prose e.g. weren't\n\n## Built With\n\n- [lalrpop](https://github.com/lalrpop/lalrpop)\n- [logos](https://github.com/maciejhirsz/logos)\n\n## Running Examples\n\n### Lexer\n\nLex an expression in to a list of tokens.\n\n```sh\ncargo run -q --example lexer spec/valid/call_id.expr\n```\n\n#### stderr\n\n```\n[\n    Ok(\n        (\n            0,\n            LParan,\n            1,\n        ),\n    ),\n    Ok(\n        (\n            1,\n            Identifier(\n                \"id\",\n            ),\n            3,\n        ),\n    ),\n    Ok(\n        (\n            4,\n            LParan,\n            5,\n        ),\n    ),\n    Ok(\n        (\n            5,\n            Identifier(\n                \"noop\",\n            ),\n            9,\n        ),\n    ),\n    Ok(\n        (\n            9,\n            RParan,\n            10,\n        ),\n    ),\n    Ok(\n        (\n            10,\n            RParan,\n            11,\n        ),\n    ),\n]\n```\n\n### Parser\n\nParse an expression into an AST.\n\n```sh\ncargo run -q --example parser spec/valid/call_id.expr\n```\n\n#### stderr\n\n```\nOk(\n    Call(\n        ExprCall {\n            callee: (\n                Identifier(\n                    ExprIdentifier(\n                        \"id\",\n                    ),\n                ),\n                1..3,\n            ),\n            args: [\n                (\n                    Call(\n                        ExprCall {\n                            callee: (\n                                Identifier(\n                                    ExprIdentifier(\n                                        \"noop\",\n                                    ),\n                                ),\n                                5..9,\n                            ),\n                            args: [],\n                        },\n                    ),\n                    4..10,\n                ),\n            ],\n        },\n    ),\n)\n```\n\n### Compiler\n\nCompile an expression into bytecode to stdout.\n\n```sh\ncargo run -q --example compiler -- spec/valid/variable.expr \\\n    --vars b \\\n    \u003e output.exprbin\n```\n\n#### stderr\n\n```\nExprByteCode {\n    codes: [\n        1,\n        1,\n        0,\n    ],\n    strings: [],\n}\n```\n\n#### stdout\n\n```\n...BYTECODE...\n```\n\n### Disassembler\n\nCompile expression and disassemble it.\n\n```sh\ncargo run -q --example disassembler -- spec/valid/call_id.expr\n```\n\n#### stderr\n\n```\nVERSION 0700\n----\n0000 GET BUILTIN         0 == 'id'\n0003 GET BUILTIN         1 == 'noop'\n0006 CALL             (0 args)\n0008 CALL             (1 args)\n```\n\n### Interpreter\n\nInterpret an expression.\n\n```sh\ncargo run -q --example interpreter -- spec/valid/greeting_name.expr \\\n    --vars greeting=Hello \\\n    --prompts name=World\n```\n\n#### stdout\n\n```\n`Hello World`\n```\n\n### REPL\n\nA simple REPL to interpret expressions.\n\n```sh\ncargo run -q --example repl\n```\n\nOr using Docker:\n\n```sh\ndocker build -t reqlang-expr-repl:0.8.0 .\n\ndocker run -it --rm --read-only reqlang-expr-repl:0.8.0\n```\n\n#### Repl Mode\n\nThe REPL works in different modes:\n\n1. Interpret: Fully interpret an expression using the VM. This is the default.\n2. Compile: Compile an expression into its bytecode\n3. Disassemble: Compile and disassemble an expression\n4. Parse: Parse an expression into an AST\n5. Lex: Lex an expression into tokens\n\n```\ninterpret   \u003e /mode\n\nCurrent Mode: Interpret\n\ninterpret   \u003e /mode compile\n\ncompile     \u003e /mode disassemble\n\ndisassemble \u003e /mode parse\n\nparse       \u003e /mode lex\n\nlex         \u003e /mode interpret\n\ninterpret   \u003e /mode\n\nCurrent Mode: Interpret\n```\n\n#### Reference Last String Value\n\nThe last returned string value can be referenced using `@_`.\n\n```\ninterpret   \u003e `value`\n\ninterpret   \u003e @_\n\n`value`\n\ninterpret   \u003e (id @_)\n\n`value`\n\ninterpret   \u003e id\n\nbuiltin id(1)\n\ninterpret   \u003e (@_ `value`)\n\n`value`\n```\n\n#### Set Variable\n\n```\ninterpret   \u003e /set var key = value\n\ninterpret   \u003e :key\n\n`value`\n```\n\n#### Set Prompt\n\n```\ninterpret   \u003e /set prompt key = value\n\ninterpret   \u003e ?key\n\n`value`\n```\n\n#### Set Secret\n\n```\ninterpret   \u003e /set secret key = value\n\ninterpret   \u003e !key\n\n`value`\n```\n\n#### Set Client Context\n\n```\ninterpret   \u003e /set client key = value\n\ninterpret   \u003e @key\n\n`value`\n```\n\n#### Print Current Environment\n\n```\ninterpret   \u003e /env\n\nEnv {\n    builtins: [\n        BuiltinFn {\n            name: \"id\",\n            arity: 1,\n        },\n        BuiltinFn {\n            name: \"noop\",\n            arity: 0,\n        },\n    ],\n    vars: [],\n    prompts: [],\n    secrets: [],\n}\n\n\u003e /set var isActive = true\n\n\u003e /env\n\nEnv {\n    builtins: [\n        BuiltinFn {\n            name: \"id\",\n            arity: 1,\n        },\n        BuiltinFn {\n            name: \"noop\",\n            arity: 0,\n        },\n    ],\n    vars: [\"isActive\"],\n    prompts: [],\n    secrets: [],\n}\n```\n\n#### Exit\n\n```\ninterpret   \u003e /exit\n```\n\n#### Example\n\n```\ninterpret   \u003e (id :foo)\n\n`bar`\n```\n\n## Tests\n\n### Integration Tests\n\nA suite of programmatic tests that validate the behavior of the lexer, parser, compiler, disassembler, and VM.\n\n[./tests/integration_tests.rs](./tests/integration_tests.rs)\n\n### Specification Tests\n\nThese tests read in `*.expr` files in the `spec/` directory and compare the output against their corrosponding expected result files (e.g. `*.expr.tokens`, `*.expr.interpreted`, `*.expr.disasssembled`). These spec files are split between valid and invalid examples.\n\n[./tests/spec_tests.rs](./tests/spec_tests.rs)\n\n#### Compiler and Runtime Environments\n\nThe expected result files `*.expr.interpreted`, `*.expr.disasssembled` accept a CLI formatted list of arguments from the first line. The frist line must be prefixed with `//`. The arguments are passed to the compiler and VM.\n\nThese CLI arguments work the same as the other reqlang-expr CLIs\n\n```\n--vars \u003cVARS\u003e...                      List of indexed variable names\n--prompts \u003cPROMPTS\u003e...                List of indexed prompt names\n--secrets \u003cSECRETS\u003e...                List of indexed secret names\n--client-context \u003cCLIENT_CONTEXT\u003e...  List of indexed client context names\n```\n\n##### Valid Example\n\n[`./spec/valid/greeting_name.expr`](./spec/valid/greeting_name.expr)\n\n```\n(concat :greeting ` ` ?name)\n```\n\n[`./spec/valid/greeting_name.expr.interpreted`](./spec/valid/greeting_name.expr.interpreted)\n\n```\n//--vars greeting=Hello --prompts name=World\n`Hello World`\n```\n\n##### Invalid Example\n\n[`./spec/invalid/eq_no_args.expr`](./spec/invalid/eq_no_args.expr)\n\n```\n(eq)\n```\n\n[`./spec/invalid/eq_no_args.expr.interpreted`](./spec/invalid/eq_no_args.expr.interpreted)\n\n```\n[\n    (\n        CompileError(\n            WrongNumberOfArgs {\n                expected: 2,\n                actual: 0,\n            },\n        ),\n        0..4,\n    ),\n]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftestingrequired%2Freqlang-expr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftestingrequired%2Freqlang-expr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftestingrequired%2Freqlang-expr/lists"}