Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: CI

on:
push:
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y libgtest-dev g++
- name: Build and test
run: cd src && make && ./test
- name: Smoke compile C API
run: |
echo '#include "interpreter_c.h"' > /tmp/ir_c_smoke.c
gcc -c -x c /tmp/ir_c_smoke.c -Iinclude
g++ -std=c++17 -O2 -Wall -c src/interpreter_c.cpp -I. -o /tmp/ir_c_api.o
12 changes: 12 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
image: ubuntu:latest

before_script:
- apt-get update -qq
- apt-get install -y -qq libgtest-dev g++

test:
script:
- cd src && make && ./test
- echo '#include "interpreter_c.h"' > /tmp/ir_c_smoke.c
- gcc -c -x c /tmp/ir_c_smoke.c -Iinclude
- g++ -std=c++17 -O2 -Wall -c src/interpreter_c.cpp -I. -o /tmp/ir_c_api.o
53 changes: 30 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ ss << "$a = 5;"
" }"
"}"
"$b";
string res = ir.cmd(ss.str()); // 9
string res = cmdResultToString(ir.cmd(ss.str())); // 9
```

### User functions outside the script
Expand Down Expand Up @@ -132,20 +132,20 @@ l_myLabel1: $a = 4;

```
script = "e = Struct{ one : 5, two : 2}; e.one = summ(e.one, e.two); e.one";
res = ir.cmd(script); // 7
res = cmdResultToString(ir.cmd(script)); // 7

script = "$b = 12; e = Struct{ one : $b + 5, two : 2}; e.three = e.one + e.two + 3; e.three";
res = ir.cmd(script); // 22
res = cmdResultToString(ir.cmd(script)); // 22
```

### Containers from [base lib](https://github.com/Tyill/interpreter/blob/main/include/base_library/containers.h)

```
script = "a = Vector{1,2,3}; a.push_back(4); a.push_back(5); while($v : a) print($v);";
res = ir.cmd(script); // 1 2 3 4 5
res = cmdResultToString(ir.cmd(script)); // 1 2 3 4 5

script = "b = Map{myKeyOne: myValueOne}; b.insert(myKeyTwo, myValueTwo); b.at(myKeyTwo)";
res = ir.cmd(script); // myValueTwo
res = cmdResultToString(ir.cmd(script)); // myValueTwo
```

| Vector | Map |
Expand All @@ -165,7 +165,7 @@ res = ir.cmd(script); // myValueTwo
```
script = "file1 = File{\"main.cpp\"}; file2 = File{\"mainCopy.txt\"}; \
if (file1.exist()) { $data = file1.read(); file2.write($data); }";
res = ir.cmd(script);
res = cmdResultToString(ir.cmd(script));
```

| File | Dir |
Expand All @@ -179,10 +179,10 @@ res = ir.cmd(script);

```
script = "a: int = 123; type(a)";
res = ir.cmd(script); // int
res = cmdResultToString(ir.cmd(script)); // int

script = "b: str = "abc"; type(b)";
res = ir.cmd(script); // str
res = cmdResultToString(ir.cmd(script)); // str
```

### Example of use
Expand Down Expand Up @@ -237,56 +237,63 @@ int main(int argc, char* argv[])
});

string script = "$a = 5; $b = 2; while ($a > 1){ $a = $a - 1; $b = summ($b, $a); if ($a < 4){ break;} } $b;";
string res = ir.cmd(script); // 9
string res = cmdResultToString(ir.cmd(script)); // 9

script = "$a = 5; $b = 2; $c = summ($a, ($a + ($a * ($b + $a))), summ(5)); $c;";
res = ir.cmd(script); // 50
res = cmdResultToString(ir.cmd(script)); // 50

script = "a = Vector; a.push_back(1); a.push_back(2); a.push_back(3); a[2]";
res = ir.cmd(script); // 3
res = cmdResultToString(ir.cmd(script)); // 3

script = "b = Map; b.insert(myKeyOne, myValueOne); b.insert(myKeyTwo, myValueTwo); b[\"myKeyTwo\"]";
res = ir.cmd(script); // myValueTwo
res = cmdResultToString(ir.cmd(script)); // myValueTwo

script = "a = Vector; a.push_back(1); a.push_back(2); a.push_back(3); while($v : a) print($v);";
res = ir.cmd(script); // 1 2 3
res = cmdResultToString(ir.cmd(script)); // 1 2 3

script = "a = Vector{1 + 2, 2 + 3, 3 + 4}; while($v : a) print($v);";
res = ir.cmd(script); // 3 5 7
res = cmdResultToString(ir.cmd(script)); // 3 5 7

script = "$b = 12; c = Map{ one : $b + 5, two : 2}; while($v : c) print($v);";
res = ir.cmd(script); // one 17 two 2
res = cmdResultToString(ir.cmd(script)); // one 17 two 2

script = "e = Struct{ one : 5, two : 2}; e.one = summ(e.one, e.two); e.one";
res = ir.cmd(script); // 7
res = cmdResultToString(ir.cmd(script)); // 7

script = "$b = 12; e = Struct{ one : $b + 5, two : 2}; e.three = e.one + e.two + 3; e.three";
res = ir.cmd(script); // 22
res = cmdResultToString(ir.cmd(script)); // 22

script = "file1 = File{\"main.cpp\"}; file2 = File{\"mainCopy.txt\"}; if (file1.exist()) { $data = file1.read(); file2.write($data); }";
res = ir.cmd(script);
res = cmdResultToString(ir.cmd(script));

script = "$a = 1; $b = 2; function myFunc{ $a += $b; }; myFunc()";
res = ir.cmd(script); // 3
res = cmdResultToString(ir.cmd(script)); // 3

script = "$a = 1; $b = 2; function myFunc{ $a += $b; function myFunc2{ $a += $b; }; myFunc2(); }; myFunc()";
res = ir.cmd(script); // 5
res = cmdResultToString(ir.cmd(script)); // 5

script = "$a = 0; function myFunc{ if ($0 > 1) $a = $0 * myFunc($0 - 1); else $a = 1; $a }; myFunc(5)";
res = ir.cmd(script); // 120
res = cmdResultToString(ir.cmd(script)); // 120

script = "function myFunc{ $0 += $1; }; myFunc(2, 3)";
res = ir.cmd(script); // 5
res = cmdResultToString(ir.cmd(script)); // 5

script = "b: str = \"abc\"; type(b)";
res = ir.cmd(script); // str
res = cmdResultToString(ir.cmd(script)); // str

return 0;
}
```

### [Tests](https://github.com/Tyill/interpreter/blob/main/src/test.cpp)

### Documentation

Extended guides: [docs/README.md](docs/README.md)

### Benchmarks

[docs/benchmarks.md](docs/benchmarks.md)

### License
Licensed under an [MIT-2.0]-[license](LICENSE).
Expand Down
19 changes: 19 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Documentation

English guides for embedding and using the Tiny interpreter library.

| Document | Description |
|----------|-------------|
| [Getting started](getting-started.md) | Build, minimal host setup, running scripts |
| [Script language](script-language.md) | Syntax: variables, control flow, macros, containers |
| [C++ API](cpp-api.md) | `Interpreter`, `Value`, errors, host functions and operators |
| [Base library](base-library.md) | Optional modules: arithmetic, containers, filesystem, … |
| [Limitations](limitations.md) | Known quirks and edge cases |
| [Copy and containers](copy-and-containers.md) | `Interpreter` copy vs `Map` / `Vector` variable visibility |
| [Benchmarks](benchmarks.md) | Local `make bench` throughput (reference numbers) |

**Quick links**

- Core: [`include/interpreter.h`](../include/interpreter.h), [`src/interpreter.cpp`](../src/interpreter.cpp)
- Full sample: [`example/main.cpp`](../example/main.cpp)
- Tests: [`src/test.cpp`](../src/test.cpp)
130 changes: 130 additions & 0 deletions docs/base-library.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Base library

Optional headers under [`include/base_library/`](../include/base_library/) extend the core interpreter with operators and functions. Each class takes `Interpreter&` in its constructor and registers handlers on that instance.

**Rule:** construct every helper on the **same** `Interpreter` you pass scripts to. Example from [`example/main.cpp`](../example/main.cpp):

```cpp
Interpreter ir;
InterpreterBaseLib::ArithmeticOperations ir_ao(ir);
InterpreterBaseLib::ComparisonOperations ir_co(ir);
InterpreterBaseLib::Container ir_bc(ir);
InterpreterBaseLib::Types ir_tp(ir);
InterpreterBaseLib::Filesystem ir_fs(ir);
InterpreterBaseLib::Structure ir_st(ir);
```

Order among helpers does not matter; all must exist before running scripts that need them.

## arithmetic_operations.h

Registers standard arithmetic and compound assignment operators (`+`, `-`, `*`, `/`, `+=`, …) on numeric [`Value`](../include/interpreter.h) types.

Required for almost all numeric scripts.

## comparison_operations.h

Registers comparison operators (`==`, `!=`, `<`, `>`, `<=`, `>=`). Results are usable in `if` / `while` conditions.

## containers.h — `Container`

Enables `Vector` and `Map` in scripts.

**Construction / literals**

```text
a = Vector;
a = Vector{ 1, 2, 3 };
a = Vector{ 1 + 2, 2 + 3 };

c = Map;
c = Map{ keyOne : valueOne, keyTwo : 2 };
```

Expressions inside `{ … }` are evaluated in a snapshot of the bound interpreter (see [Copy and containers](copy-and-containers.md) when using copies).

**Vector methods**

| Method | Description |
|--------|-------------|
| `push_back(value)` | Append |
| `pop_back()` | Remove last |
| `insert(index, value)` | Insert at index |
| `erase(index)` | Remove at index |
| `size()`, `empty()`, `clear()` | Queries / reset |
| `at(index)` or `[index]` | Access |

**Map methods**

| Method | Description |
|--------|-------------|
| `insert(key, value)` | Insert or replace |
| `erase(key)` | Remove key |
| `size()`, `empty()`, `clear()` | Queries / reset |
| `at(key)` or `[key]` | Access |

**Iteration**

```text
while ($v : a) print($v);
```

For `Map`, printed lines are typically `key` and value (tab-separated in host `print` output). See [Limitations](limitations.md).

Syntax details: [Script language — Containers](script-language.md#containers).

## structure.h — `Structure`

Struct-like objects with dotted fields:

```text
e = Struct{ one : 5, two : 2 };
e.one = summ(e.one, e.two);
e.three = e.one + e.two + 3;
```

Fields can be added after construction. Init expressions in `{ … }` follow the same snapshot rules as containers.

## filesystem.h — `Filesystem`

**File**

```text
f = File{"path.txt"};
f.exist();
$data = f.read();
f.write($data);
f.remove();
```

**Dir**

```text
d = Dir{"path"};
d.exist();
d.remove();
```

Paths in literals are usually quoted strings. Init bodies can be expressions.

## types.h — `Types`

Typed variable declarations and `type()`:

```text
a: int = 123;
b: str = "abc";
type(a); // host function returns type name
```

Registers `:` for declarations and the `type` function.

## Linking

Add `interpreter.cpp` once per binary. Base library is header-only (templates and inline registration in constructors); no extra `.cpp` files.

## See also

- [Getting started](getting-started.md)
- [Script language](script-language.md)
- [C++ API](cpp-api.md)
55 changes: 55 additions & 0 deletions docs/benchmarks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Benchmarks

Informal local throughput checks for regression comparison. **Not run in CI.**

Build and run:

```bash
cd src && make bench && ./bench
```

Source: [`src/bench.cpp`](../src/bench.cpp). The host keeps `ArithmeticOperations`, `ComparisonOperations`, and `Container` alive for the whole run (same lifetime pattern as tests).

## Scenarios

| Label | What it measures |
|-------|------------------|
| cmd short loop | `while` + `summ` + `break` (README-style loop) |
| cmd nested expr | Nested `summ` and arithmetic |
| cmd Vector literal | `Vector{1+2, …}` and index |
| cmd Map literal | `Map{one:$b+5, …}` and lookup |
| cmd setMacro #inc | `setMacro("inc", …)` then `#inc` twice |
| cmd (varying script) | Rotating three similar scripts (no AST cache reuse) |
| parseScript+runScript (cached) | Same script text: parse once per call path, then `runScript` |
| copy | `Interpreter` copy constructor only |

Default iteration counts: **5000** per `cmd` case (1000 for Vector/Map, 500 for varying script). Each case warms up **50** iterations before timing.

## Reference results

Snapshot from `g++ -std=c++17 -O2` on Linux x86_64 (single run; **your numbers will differ** by CPU and load):

```
interpreter bench (O2, 5000 iterations per case)

cmd short loop 5000 iter 14.424 ms 346648 ops/s
cmd nested expr 5000 iter 9.555 ms 523299 ops/s
cmd Vector literal 1000 iter 8.718 ms 114700 ops/s
cmd Map literal 1000 iter 8.550 ms 116965 ops/s
cmd setMacro #inc 5000 iter 6.557 ms 762500 ops/s
cmd (varying script) 500 iter 1.529 ms 327061 ops/s
parseScript+runScript (cached) 5000 iter 15.092 ms 331305 ops/s

copy: 500 Interpreter copies in 1.018 ms (490951 /s)
```

### How to read this

- **ops/s** — how many times per second the scenario completed (one `cmd` or one parse+run pair).
- Use results only to compare **before vs after** a change on the **same** machine and `bench` binary.
- These micro-benchmarks do **not** compare this library to Lua, Python, or other engines.

## See also

- [Getting started](getting-started.md)
- [Limitations](limitations.md)
Loading
Loading