Skip to content

Commit 01e33ea

Browse files
gh-5: Add remaining non-THR operators.
1 parent a855404 commit 01e33ea

File tree

14 files changed

+1459
-85
lines changed

14 files changed

+1459
-85
lines changed

build.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,4 @@ Write-Host "Cleaning up temp build dir: $buildDir"
7171
Remove-Item -Recurse -Force $buildDir -ErrorAction SilentlyContinue
7272

7373
Write-Host "Build succeeded and exe copied to: $(Join-Path $script 'prefix.exe')"
74-
exit 0
74+
exit 0

docs/SPECIFICATION.html

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,8 @@
449449

450450
- The interpreter may support additional flags and a different ordering of arguments; the rules above define the semantics for `argv[1]`, `-source`, and `-verbose` specifically and are intended to be stable for tooling and replay purposes.
451451

452+
- Exit codes: On normal termination (the program completes without an explicit `EXIT()` call and without encountering a runtime error or uncaught exception) the interpreter returns exit code `0` to the operating system. If execution terminates due to a runtime error or uncaught exception the interpreter returns exit code `1`. If the program invokes `EXIT(n)`, the interpreter returns the supplied integer `n` as the process exit code.
453+
452454
Example invocations (illustrative):
453455

454456
- File mode: `prefix program.pre`
@@ -500,7 +502,7 @@
500502
501503
### 12.1 Function / Operator Signatures (expression position)
502504
503-
- `RUN(STR: s)` ; Run a string as an Prefix program within the current environment;
505+
- `RUN(STR: s)` ; Run a string as a Prefix program within the current environment;
504506
505507
- `ASSERT(ANY: a)` ; crashes if `INT`-style` truthiness of `a` is 0
506508

@@ -817,7 +819,7 @@
817819
818820
Package imports: Prefix supports package namespaces using `..` as the package separator. The canonical form is `package..subpackage..module`. When `IMPORT(pkg)` is used the interpreter will prefer a package layout and attempt to load `pkg/init.pre` from the referring source's directory (falling back to the interpreter `lib/` directory). If a directory named `pkg` exists but contains no `init.pre` the import raises a clear error. When `IMPORT(pkg..mod)` is used the interpreter resolves to `pkg/mod.pre` (or the corresponding file under `lib/`). When a package directory and a same-named module file both exist in the same search location, the package takes precedence. Items within the package are still imported using their full dotted names (for example, `pkg..mod.FOO`).
819821
820-
- `IMPORT_PATH(STR: path)` — Loads an Prefix module from the absolute filesystem `path` provided as a `STR`. The argument must be an absolute path to a `.pre` source file. The imported module is treated the same as `IMPORT` with respect to parsing, execution isolation, function/module caching, and companion extension loading (companion `<module>.prex` alongside the resolved file and a built-in `ext/<module>.py` are both checked and loaded if present). The module's basename (filename without extension) is used as the module identifier for qualifying exported bindings.
822+
- `IMPORT_PATH(STR: path)` — Loads a Prefix module from the absolute filesystem `path` provided as a `STR`. The argument must be an absolute path to a `.pre` source file. The imported module is treated the same as `IMPORT` with respect to parsing, execution isolation, function/module caching, and companion extension loading (companion `<module>.prex` alongside the resolved file and a built-in `ext/<module>.py` are both checked and loaded if present). The module's basename (filename without extension) is used as the module identifier for qualifying exported bindings.
821823
822824
The first argument must be an identifier naming a module; the interpreter first looks for a file named `<name>.pre` in the same directory as the referring source file. When the referring source is provided via the `-source` string literal mode, the primary search directory is the process's current working directory. If the module file is not found there, the interpreter will additionally attempt to load the file from a `lib` subdirectory located alongside the interpreter implementation (that is, `<interpreter_dir>/lib/<name>.pre`, where `<interpreter_dir>` is the directory containing the interpreter script or executable).
823825
@@ -826,7 +828,7 @@
826828
After the module finishes executing the first time, the interpreter caches the module's top-level environment and the module-qualified function objects. Subsequent `IMPORT` calls for the same module identifier within the same interpreter process reuse that cached namespace/instance and do not re-execute the module source. Callers importing the same module later will observe the same shared module environment (that is, the same binding objects and the same function objects). By default bindings are exposed under the module's own dotted prefix (`module.FOO`, `module.bar`, etc.); however, if the importer supplied an alias the bindings are instead exposed under the alias prefix (`alias.FOO`, `alias.bar`). Multiple different aliases for the same module identifier will each get their own dotted view into the same cached module instance. If the module imported other modules during its execution, those nested qualified bindings are preserved in the cached namespace and remain accessible via the same dotted paths (for example, `module.other.SYM` or `alias.other.SYM` or `module.alias.SYM`).
827829
828830
This caching behavior ensures that importing a module multiple times produces the same shared module namespace instance for all importers. The interpreter does not automatically perform cycle detection beyond using the cached instance once execution has completed; careful module design should avoid import cycles where possible.
829-
831+
830832
When a module is imported, the interpreter also attempts to load any associated runtime extensions so their operators are immediately available to the importer. The interpreter first looks for a companion pointer file named `<module>.prex` next to the resolved module file (or in the interpreter `lib/` fallback) and loads any extensions listed there. If no pointer file is present (or as an additional fallback), the interpreter will also check its built-in `ext/` directory for a single-file extension named `<module>.py` and load it if present. Operators registered by such extensions are attached to the running interpreter at import time and become callable (typically under the module-qualified names they register).
831833
832834
- `EXPORT(SYMBOL: symbol, MODULE: module):INT` Adds the caller's binding for the identifier `symbol` into the namespace of the imported module named by the identifier `module`. The first argument must be an identifier (not a string literal); its current value in the caller's environment is copied into the imported module's namespace and becomes available as the qualified name `module.symbol` in the caller's environment. The second argument must be an identifier naming a previously-imported module; if the module has not been imported yet, the interpreter raises a runtime error (rewrite: EXPORT). `EXPORT` returns `INT` 0 on success.

src/ast.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,15 @@ Stmt* stmt_return(Expr* value, int line, int column) {
217217
return stmt;
218218
}
219219

220+
Stmt* stmt_pop(char* name, int line, int column) {
221+
Stmt* stmt = ast_alloc(sizeof(Stmt));
222+
stmt->type = STMT_POP;
223+
stmt->line = line;
224+
stmt->column = column;
225+
stmt->as.pop_stmt.name = name;
226+
return stmt;
227+
}
228+
220229
Stmt* stmt_break(Expr* value, int line, int column) {
221230
Stmt* stmt = ast_alloc(sizeof(Stmt));
222231
stmt->type = STMT_BREAK;
@@ -382,6 +391,9 @@ void free_stmt(Stmt* stmt) {
382391
case STMT_RETURN:
383392
free_expr(stmt->as.return_stmt.value);
384393
break;
394+
case STMT_POP:
395+
free(stmt->as.pop_stmt.name);
396+
break;
385397
case STMT_BREAK:
386398
free_expr(stmt->as.break_stmt.value);
387399
break;

src/ast.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ typedef enum {
7575
STMT_RETURN,
7676
STMT_BREAK,
7777
STMT_CONTINUE,
78+
STMT_POP,
7879
STMT_TRY,
7980
STMT_GOTO,
8081
STMT_GOTOPOINT
@@ -121,6 +122,7 @@ struct Stmt {
121122
struct { Expr* value; } break_stmt;
122123
struct { Stmt* try_block; char* catch_name; Stmt* catch_block; } try_stmt;
123124
struct { Expr* target; } goto_stmt;
125+
struct { char* name; } pop_stmt;
124126
struct { Expr* target; } gotopoint_stmt;
125127
} as;
126128
};
@@ -146,6 +148,7 @@ Stmt* stmt_while(Expr* cond, Stmt* body, int line, int column);
146148
Stmt* stmt_for(char* counter, Expr* target, Stmt* body, int line, int column);
147149
Stmt* stmt_func(char* name, DeclType ret, Stmt* body, int line, int column);
148150
Stmt* stmt_return(Expr* value, int line, int column);
151+
Stmt* stmt_pop(char* name, int line, int column);
149152
Stmt* stmt_break(Expr* value, int line, int column);
150153
Stmt* stmt_continue(int line, int column);
151154
Stmt* stmt_try(Stmt* try_block, char* catch_name, Stmt* catch_block, int line, int column);

0 commit comments

Comments
 (0)