vrmm build files

This commit is contained in:
allexanderbergmns
2026-08-25 14:45:19 +02:00
parent 9b22be48a5
commit 387079d720
20 changed files with 646 additions and 1 deletions
+62
View File
@@ -33,6 +33,9 @@ vr run <file.vr|file.vbin> compile+link+run, or run a binary
vr debug <file.vr|file.vbin> run with an instruction trace
vr test <file.vr> run every test_* function
vr bench <file.vr> [iterations] benchmark main()
vr make [target] [args...] run build.vrmm (target = main)
vr make -f <file.vrmm> [target] [args...] run another build module
vr build [target] [args...] alias for make
vr clean remove .vobj/.vbin artifacts
vr up rebuild bin/vr
vr symlink link bin/vr into your PATH
@@ -71,6 +74,64 @@ Quick start:
./bin/vr run use_lib.vbin
```
## Build modules (.vrmm)
A **VuurRaaf Make Module** (`.vrmm`) is build instructions for the toolchain,
written in VuurRaaf itself — the same idea as V's `.vsh` scripts. The toolchain
compiles the module and runs one of its functions (a *target*) with the
`build_*` builtins available, so the script can drive every stage of the
pipeline: compile, assemble, link, run, test, bench, clean, and shell out to
the host.
```
# build.vrmm
fn main() {
build_compile("main.vr", "main.vobj")
build_link(["main.vobj"], "main.vbin")
}
fn clean() {
build_clean()
}
```
```bash
vr make # runs main() from build.vrmm
vr make clean # runs the clean() target
vr make deploy --prod # runs deploy() with args() == ["--prod"]
vr make -f x.vrmm t # run target t from another module
```
A target that returns a nonzero integer, calls `exit(n)` with `n > 0`, or
`throw`s fails the build. Paths are relative to the working directory;
`build_root()` returns the module's own directory for absolute paths.
Build builtins:
| builtin | description |
|---------|-------------|
| `build_compile(src, out)` | source → object (out defaults to `src.vobj`); returns the out path |
| `build_assemble(src, out)` | `.vasm` → object; returns the out path |
| `build_link(objs, out)` | objects → executable; returns the out path |
| `build_run(file)` | compile+link+run a `.vr`, or run a `.vbin`; returns the exit code |
| `build_test(file)` | run every `test_*` function; throws if any fail |
| `build_bench(file, n)` | benchmark `main()` n times |
| `build_clean()` | remove `.vobj`/`.vbin` in the cwd; returns the count |
| `build_exec(cmd)` | run a shell command; returns its output (throws on nonzero exit) |
| `build_exec_status(cmd)` | run a shell command; returns its exit code |
| `build_exists(path)` | 1 if the path exists, else 0 |
| `build_mkdir(path)` | create a directory (and parents) |
| `build_rm(path)` | remove a file or directory tree; returns 1 if something was removed |
| `build_copy(src, dst)` | copy a file or a whole directory tree |
| `build_glob(pattern)` | list files matching a glob (e.g. `"src/*.vr"`) |
| `build_ls(dir)` | list a directory's entries |
| `build_base(path)` / `build_dir(path)` / `build_join(a, b)` | path helpers |
| `build_root()` | absolute directory of the running `.vrmm` |
`vr init` scaffolds a project with a working `build.vrmm`; see
`examples/build.vrmm` for a tour (targets: `main`, `multi`, `test`, `bench`,
`deploy`, `clean`).
## The VuurRaaf language
A small, V-flavored language. Values are 64-bit integers, 64-bit floats,
@@ -261,6 +322,7 @@ main.v CLI entry point (vr <command> ...)
repl.v interactive REPL
fmt.v source formatter
pkg.v package manager (init/get/install/list)
vm/native.v host builtins incl. the build_* (.vrmm) builtins
v.mod module definition
compiler/ assembler/ linker/ vm/ obj/ the toolchain itself
bin/ built binary + standalone tools
+6
View File
@@ -552,6 +552,12 @@ fn builtin_result_type(name string) TypeInfo {
'args', 'keys' { TypeInfo{ kind: .array_t } }
'len' { TypeInfo{ kind: .int_t } }
'write_file', 'setenv', 'exit', 'sleep', 'eprint' { TypeInfo{ kind: .unknown } }
// build-module builtins (.vrmm)
'build_compile', 'build_assemble', 'build_link', 'build_exec', 'build_base',
'build_dir', 'build_join', 'build_root' { TypeInfo{ kind: .string_t } }
'build_glob', 'build_ls' { TypeInfo{ kind: .array_t } }
'build_run', 'build_test', 'build_bench', 'build_clean', 'build_exec_status',
'build_exists', 'build_mkdir', 'build_rm', 'build_copy' { TypeInfo{ kind: .int_t } }
else { TypeInfo{ kind: .unknown } }
}
}
+22
View File
@@ -903,6 +903,26 @@ fn builtin_spec(name string) (int, int) {
'read_file' { native_read_file, 1 }
'write_file' { native_write_file, 2 }
'eprint' { native_eprint, 1 }
// build-module builtins (.vrmm) — see vm/native.v
'build_compile' { native_build_compile, 2 }
'build_assemble' { native_build_assemble, 2 }
'build_link' { native_build_link, 2 }
'build_run' { native_build_run, 1 }
'build_test' { native_build_test, 1 }
'build_bench' { native_build_bench, 2 }
'build_clean' { native_build_clean, 0 }
'build_exec' { native_build_exec, 1 }
'build_exec_status' { native_build_exec_status, 1 }
'build_exists' { native_build_exists, 1 }
'build_mkdir' { native_build_mkdir, 1 }
'build_rm' { native_build_rm, 1 }
'build_copy' { native_build_copy, 2 }
'build_glob' { native_build_glob, 1 }
'build_ls' { native_build_ls, 1 }
'build_base' { native_build_base, 1 }
'build_dir' { native_build_dir, 1 }
'build_join' { native_build_join, 2 }
'build_root' { native_build_root, 0 }
else { -1, 0 }
}
}
@@ -1131,6 +1151,8 @@ fn (mut g Gen) expr_type(e Expr) string {
if e.kind == .call {
return match e.name {
'upper', 'lower', 'trim', 'str', 'getenv', 'read_file', 'join' { 'string' }
'build_compile', 'build_assemble', 'build_link', 'build_exec', 'build_base',
'build_dir', 'build_join', 'build_root' { 'string' }
else { '' }
}
}
+22
View File
@@ -105,3 +105,25 @@ const native_sleep = 134
const native_read_file = 135
const native_write_file = 136
const native_eprint = 137
// build-module builtins (.vrmm) — available to `vr make` scripts and to any
// program that wants to drive the toolchain
const native_build_compile = 138
const native_build_assemble = 139
const native_build_link = 140
const native_build_run = 141
const native_build_test = 142
const native_build_bench = 143
const native_build_clean = 144
const native_build_exec = 145
const native_build_exec_status = 146
const native_build_exists = 147
const native_build_mkdir = 148
const native_build_rm = 149
const native_build_copy = 150
const native_build_glob = 151
const native_build_ls = 152
const native_build_base = 153
const native_build_dir = 154
const native_build_join = 155
const native_build_root = 156
+55
View File
@@ -0,0 +1,55 @@
// build.vrmm — a VuurRaaf Make Module: build instructions for the toolchain,
// written in VuurRaaf itself (like V's .vsh, but for this language).
//
// ./bin/vr make -f examples/build.vrmm build + run hello
// ./bin/vr make -f examples/build.vrmm multi compile/link/run a 2-file program
// ./bin/vr make -f examples/build.vrmm test run tests.vr
// ./bin/vr make -f examples/build.vrmm clean remove artifacts
// ./bin/vr make -f examples/build.vrmm deploy --prod deploy() with args()
//
// Paths are relative to the working directory; build_root() returns this
// module's own directory for scripts that want absolute paths.
fn main() {
// compile + link + run in one step
build_run("examples/hello.vr")
}
fn multi() {
// drive each toolchain stage explicitly
let root = build_root()
let lib = build_compile(build_join(root, "lib.vr"), build_join(root, "lib.vobj"))
let use = build_compile(build_join(root, "use_lib.vr"), build_join(root, "use_lib.vobj"))
let bin = build_link([lib, use], build_join(root, "use_lib.vbin"))
build_run(bin)
}
fn test() {
// run every test_* function; fails the build if any test fails
build_test("examples/tests.vr")
}
fn bench() {
// benchmark main() of fib.vr 2000 times
build_bench("examples/fib.vr", 2000)
}
fn deploy() {
// arguments after the target arrive via args()
let args = args()
if len(args) == 0 {
throw "deploy needs a flag: vr make deploy --prod"
}
println("deploying with args: " + join(args, " "))
let out = build_exec("echo 'deploy step ok'")
println(out)
}
fn clean() {
// remove this module's artifacts (build_rm returns 1 if it removed something)
let root = build_root()
for f in ["lib.vobj", "lib.vbin", "use_lib.vobj", "use_lib.vbin", "hello.vbin"] {
build_rm(build_join(root, f))
}
println("cleaned")
}
+9
View File
@@ -0,0 +1,9 @@
// debug: does the function work at all?
fn double(x) {
return x * 2
}
fn main() {
println(double(21))
}
+11
View File
@@ -0,0 +1,11 @@
// debug: generic function
fn first[T](arr) {
return arr[0]
}
fn main() {
let nums = [10, 20, 30]
let x = first(nums)
println(x)
}
+13
View File
@@ -0,0 +1,13 @@
// debug: trace function execution
fn first[T](arr) {
let x = arr[0]
println(x)
return x
}
fn main() {
let nums = [10, 20, 30]
let x = first(nums)
println("main got: ${x}")
}
+16
View File
@@ -0,0 +1,16 @@
// debug: trace everything
fn first[T](arr) {
println("inside first")
println(arr)
let x = arr[0]
println("x = ${x}")
return x
}
fn main() {
println("calling first")
let nums = [10, 20, 30]
let result = first(nums)
println("result = ${result}")
}
+12
View File
@@ -0,0 +1,12 @@
// debug: test arr[0] in function body
fn first(arr) {
println(arr[0])
return arr[0]
}
fn main() {
let nums = [10, 20, 30]
let result = first(nums)
println("result = ${result}")
}
+10
View File
@@ -0,0 +1,10 @@
// debug: basic arr[0]
fn get_first(arr) {
return arr[0]
}
fn main() {
let nums = [10, 20, 30]
println(get_first(nums))
}
+6
View File
@@ -0,0 +1,6 @@
// debug: inline arr[0]
fn main() {
let nums = [10, 20, 30]
println(nums[0])
}
+10
View File
@@ -0,0 +1,10 @@
// simple generic test
fn first[T](arr) {
return arr[0]
}
fn main() {
let nums = [10, 20, 30]
println(first[int](nums))
}
+10
View File
@@ -0,0 +1,10 @@
// simple generic test - no type args
fn first[T](arr) {
return arr[0]
}
fn main() {
let nums = [10, 20, 30]
println(first(nums))
}
+73
View File
@@ -91,6 +91,9 @@ fn main() {
'clean' {
toolchain_clean()
}
'make', 'm', 'build' {
toolchain_make(rest) or { die('make', err) }
}
'up' {
toolchain_up() or { die('up', err) }
}
@@ -177,6 +180,9 @@ fn toolchain_help() {
println(' get <owner/repo | url | ./path> fetch a package into vendor/')
println(' install install deps from vr.mod')
println(' list show the project manifest')
println(' make [target] [args...] run build.vrmm (target = main)')
println(' make -f <file.vrmm> [target] [args...] run another build module (.vrmm)')
println(' build alias for make')
println(' clean remove build artifacts')
println(' up rebuild the vr binary into bin/')
println(' symlink link bin/vr into your PATH')
@@ -468,6 +474,73 @@ fn run_src_with_args(src string, entry string, trace bool, args []string) ! {
// ---------------------------------------------------------------------------
// housekeeping
// ---------------------------------------------------------------------------
// make — run a .vrmm build module
// toolchain_make compiles a .vrmm build module and runs one of its targets.
// A build module is a VuurRaaf program that drives the toolchain through the
// build_* builtins (build_compile, build_link, build_run, build_exec, ...).
//
// vr make runs main() (or build()) from build.vrmm
// vr make clean runs the clean() target
// vr make deploy --prod runs deploy() with args() == ["--prod"]
// vr make -f x.vrmm t runs target t from x.vrmm
//
// A target that returns nonzero (or calls exit(n>0) / throws) fails the build.
fn toolchain_make(args []string) ! {
mut file := 'build.vrmm'
mut rest := []string{}
mut i := 0
for i < args.len {
if args[i] == '-f' && i + 1 < args.len {
file = args[i + 1]
i += 2
} else {
rest << args[i]
i++
}
}
if !os.exists(file) {
return error('no build module "${file}" found (write one, or run `vr init` to scaffold it)')
}
mut target := 'main'
if rest.len > 0 {
target = rest[0]
rest = rest[1..].clone()
}
// compile and link the build module itself
tmp_obj := os.join_path(os.temp_dir(), 'vr_make_${os.getpid()}.vobj')
tmp_bin := os.join_path(os.temp_dir(), 'vr_make_${os.getpid()}.vbin')
defer {
os.rm(tmp_obj) or {}
os.rm(tmp_bin) or {}
}
o := compiler.compile_file(file)!
obj.write(tmp_obj, o)!
linker.link([tmp_obj], tmp_bin)!
bin := obj.read_bin(tmp_bin)!
// pick the entry: an explicit target, else main, else build
mut names := []string{}
for f in bin.fns {
names << f.name
}
mut entry := ''
if target == 'main' && 'main' in names {
entry = 'main'
} else if target == 'main' && 'build' in names {
entry = 'build'
} else if target in names {
entry = target
} else {
return error('no target function "${target}" in ${file} (available: ${names.join(', ')} or main)')
}
println('vr make: ${file} [${entry}]')
code := vm.run_build(bin, entry, rest, os.abs_path(os.dir(file)))!
if code != 0 {
return error('target ${entry} finished with exit code ${code}')
}
}
fn toolchain_clean() {
mut n := 0
if files := os.ls('.') {
+23 -1
View File
@@ -24,7 +24,29 @@ fn toolchain_init(args []string) ! {
if !os.exists('main.vr') {
os.write_file('main.vr', 'fn main() {\n\tprintln("hello from ${pkg}")\n}\n')!
}
println('initialized project "${pkg}" (${manifest_file}, main.vr)')
if !os.exists('build.vrmm') {
os.write_file('build.vrmm', '// build.vrmm build instructions for the VuurRaaf toolchain.
//
// vr make runs main()
// vr make clean runs the clean() target
//
// Build builtins: build_compile, build_assemble, build_link, build_run,
// build_test, build_bench, build_clean, build_exec, build_exec_status,
// build_exists, build_mkdir, build_rm, build_copy, build_glob, build_ls,
// build_base, build_dir, build_join, build_root.
fn main() {
build_compile("main.vr", "main.vobj")
build_link(["main.vobj"], "main.vbin")
println("built main.vbin run it with: vr run main.vbin")
}
fn clean() {
build_clean()
}
')!
}
println('initialized project "${pkg}" (${manifest_file}, main.vr, build.vrmm)')
}
fn toolchain_get(args []string) ! {
+252
View File
@@ -11,6 +11,10 @@ import os
import math
import rand
import time
import obj
import compiler
import assembler
import linker
fn (mut v Vm) native(id int, _argc int) ! {
match id {
@@ -346,12 +350,260 @@ fn (mut v Vm) native(id int, _argc int) ! {
x := v.pop()!
eprintln(v.val_str(x, 0))
}
// -------------------------------------------------------------------
// build-module builtins (.vrmm) — these let a VuurRaaf program drive
// the toolchain itself, the way V's .vsh scripts drive `v build`.
native_build_compile {
out := v.pop_str()!
src := v.pop_str()!
o := compiler.compile_file(src) or { return error('build_compile: ${err.msg()}') }
o_path := if out.len == 0 { src.all_before_last('.') + '.vobj' } else { out }
obj.write(o_path, o) or { return error('build_compile: cannot write ${o_path}: ${err.msg()}') }
println('compiled ${src} -> ${o_path} (${o.code.len} bytes code, ${o.symbols.len} symbols)')
v.push(v.alloc_str(o_path))!
}
native_build_assemble {
out := v.pop_str()!
src := v.pop_str()!
o := assembler.assemble_file(src) or { return error('build_assemble: ${err.msg()}') }
o_path := if out.len == 0 { src.all_before_last('.') + '.vobj' } else { out }
obj.write(o_path, o) or { return error('build_assemble: cannot write ${o_path}: ${err.msg()}') }
println('assembled ${src} -> ${o_path} (${o.code.len} bytes code)')
v.push(v.alloc_str(o_path))!
}
native_build_link {
out := v.pop_str()!
h := v.pop()!
if !v.is_arr(h) || !v.valid_arr_handle(h) {
return error('build_link() expects an array of object files as its first argument')
}
mut objs := []string{}
for x in v.arrays[v.hand(h)] {
if !v.is_str(x) || !v.valid_handle(x) {
return error('build_link() expects string paths inside the object array')
}
objs << v.strings[v.hand(x)]
}
if objs.len == 0 {
return error('build_link() needs at least one object file')
}
o_path := if out.len == 0 { os.base(objs[0]).all_before_last('.') + '.vbin' } else { out }
linker.link(objs, o_path) or { return error('build_link: ${err.msg()}') }
println('linked ${objs.len} object file(s) -> ${o_path}')
v.push(v.alloc_str(o_path))!
}
native_build_run {
f := v.pop_str()!
if f.ends_with('.vbin') {
bin := obj.read_bin(f) or { return error('build_run: ${err.msg()}') }
code := run_with_args(bin, 'main', false, []string{}) or {
return error('build_run: ${err.msg()}')
}
v.push(v.enc_int(code))!
return
}
if !f.ends_with('.vr') {
return error('build_run() expects a .vr or .vbin file')
}
tmp_obj := os.join_path(os.temp_dir(), 'vr_build_${os.getpid()}.vobj')
tmp_bin := os.join_path(os.temp_dir(), 'vr_build_${os.getpid()}.vbin')
defer {
os.rm(tmp_obj) or {}
os.rm(tmp_bin) or {}
}
o := compiler.compile_file(f) or { return error('build_run: ${err.msg()}') }
obj.write(tmp_obj, o) or { return error('build_run: ${err.msg()}') }
linker.link([tmp_obj], tmp_bin) or { return error('build_run: ${err.msg()}') }
bin := obj.read_bin(tmp_bin) or { return error('build_run: ${err.msg()}') }
code := run_with_args(bin, 'main', false, []string{}) or {
return error('build_run: ${err.msg()}')
}
v.push(v.enc_int(code))!
}
native_build_test {
src := v.pop_str()!
o := compiler.compile_file(src) or { return error('build_test: ${err.msg()}') }
mut tests := []string{}
for s in o.symbols {
if s.name.starts_with('test_') {
tests << s.name
}
}
if tests.len == 0 {
return error('build_test: no test_* functions found in ${src}')
}
tmp_obj := os.join_path(os.temp_dir(), 'vr_build_${os.getpid()}.vobj')
tmp_bin := os.join_path(os.temp_dir(), 'vr_build_${os.getpid()}.vbin')
defer {
os.rm(tmp_obj) or {}
os.rm(tmp_bin) or {}
}
obj.write(tmp_obj, o) or { return error('build_test: ${err.msg()}') }
linker.link([tmp_obj], tmp_bin) or { return error('build_test: ${err.msg()}') }
bin := obj.read_bin(tmp_bin) or { return error('build_test: ${err.msg()}') }
mut passes := 0
mut fails := 0
for t in tests {
run(bin, t, false) or {
eprintln(' FAIL ${t} ${err}')
fails++
continue
}
println(' PASS ${t}')
passes++
}
if fails > 0 {
return error('build_test: ${fails} of ${tests.len} test(s) failed in ${src}')
}
println('${passes} test(s) passed')
v.push(v.enc_int(i64(passes)))!
}
native_build_bench {
n := int(v.dec_int(v.pop()!))
src := v.pop_str()!
if n < 1 {
return error('build_bench() expects a positive iteration count')
}
tmp_obj := os.join_path(os.temp_dir(), 'vr_build_${os.getpid()}.vobj')
tmp_bin := os.join_path(os.temp_dir(), 'vr_build_${os.getpid()}.vbin')
defer {
os.rm(tmp_obj) or {}
os.rm(tmp_bin) or {}
}
o := compiler.compile_file(src) or { return error('build_bench: ${err.msg()}') }
obj.write(tmp_obj, o) or { return error('build_bench: ${err.msg()}') }
linker.link([tmp_obj], tmp_bin) or { return error('build_bench: ${err.msg()}') }
bin := obj.read_bin(tmp_bin) or { return error('build_bench: ${err.msg()}') }
start := time.now().unix_milli()
for _ in 0..n {
run(bin, 'main', false) or { return error('build_bench: ${err.msg()}') }
}
ms := time.now().unix_milli() - start
rate := if ms > 0 { f64(n) / (f64(ms) / 1000.0) } else { f64(0) }
println('bench: ${n} runs of main() in ${ms}ms (${rate:.0} runs/s)')
v.push(v.enc_int(0))!
}
native_build_clean {
mut n := 0
if files := os.ls('.') {
for f in files {
if f.ends_with('.vobj') || f.ends_with('.vbin') {
os.rm(f) or {}
n++
}
}
}
println('cleaned ${n} artifact(s)')
v.push(v.enc_int(i64(n)))!
}
native_build_exec {
cmd := v.pop_str()!
res := os.execute(cmd)
if res.exit_code != 0 {
return error('build_exec: "${cmd}" failed with exit code ${res.exit_code}: ${res.output}')
}
v.push(v.alloc_str(res.output))!
}
native_build_exec_status {
cmd := v.pop_str()!
res := os.execute(cmd)
v.push(v.enc_int(i64(res.exit_code)))!
}
native_build_exists {
p := v.pop_str()!
v.push(v.enc_int(bool_i64(os.exists(p))))!
}
native_build_mkdir {
p := v.pop_str()!
os.mkdir_all(p) or { return error('build_mkdir: cannot create ${p}: ${err.msg()}') }
v.push(v.enc_int(0))!
}
native_build_rm {
p := v.pop_str()!
if !os.exists(p) {
v.push(v.enc_int(0))!
return
}
if os.is_dir(p) {
os.rmdir_all(p) or { return error('build_rm: cannot remove ${p}: ${err.msg()}') }
} else {
os.rm(p) or { return error('build_rm: cannot remove ${p}: ${err.msg()}') }
}
v.push(v.enc_int(1))!
}
native_build_copy {
dst := v.pop_str()!
src := v.pop_str()!
if os.is_dir(src) {
v.copy_tree(src, dst) or { return error('build_copy: ${err.msg()}') }
} else {
os.cp(src, dst, os.CopyParams{}) or {
return error('build_copy: cannot copy ${src} -> ${dst}: ${err.msg()}')
}
}
v.push(v.enc_int(0))!
}
native_build_glob {
pat := v.pop_str()!
files := os.glob(pat) or { return error('build_glob: ${err.msg()}') }
mut arr := []i64{}
for f in files {
v.strings << f
arr << v.mkstr(v.strings.len - 1)
}
v.arrays << arr
v.push(v.mkarr(v.arrays.len - 1))!
}
native_build_ls {
dir := v.pop_str()!
entries := os.ls(dir) or { return error('build_ls: cannot read ${dir}: ${err.msg()}') }
mut arr := []i64{}
for f in entries {
v.strings << f
arr << v.mkstr(v.strings.len - 1)
}
v.arrays << arr
v.push(v.mkarr(v.arrays.len - 1))!
}
native_build_base {
p := v.pop_str()!
v.push(v.alloc_str(os.base(p)))!
}
native_build_dir {
p := v.pop_str()!
v.push(v.alloc_str(os.dir(p)))!
}
native_build_join {
b := v.pop_str()!
a := v.pop_str()!
v.push(v.alloc_str(os.join_path(a, b)))!
}
native_build_root {
v.push(v.alloc_str(v.build_root))!
}
else {
return error('unknown native builtin ${id}')
}
}
}
// copy_tree recursively copies a directory tree (used by build_copy).
fn (mut v Vm) copy_tree(src string, dst string) ! {
if !os.is_dir(src) {
return error('${src} is not a directory')
}
os.mkdir_all(dst) or { return error('cannot create ${dst}: ${err.msg()}') }
for entry in os.ls(src) or { return error('cannot read ${src}: ${err.msg()}') } {
sp := os.join_path(src, entry)
dp := os.join_path(dst, entry)
if os.is_dir(sp) {
v.copy_tree(sp, dp)!
} else if os.is_file(sp) {
os.cp(sp, dp, os.CopyParams{}) or { return error('cannot copy ${sp}: ${err.msg()}') }
}
}
}
// pop_str pops the top value and requires it to be a string.
fn (mut v Vm) pop_str() !string {
x := v.pop()!
+21
View File
@@ -105,3 +105,24 @@ const native_sleep = 134
const native_read_file = 135
const native_write_file = 136
const native_eprint = 137
// build-module builtins (.vrmm) — driven by `vr make`
const native_build_compile = 138
const native_build_assemble = 139
const native_build_link = 140
const native_build_run = 141
const native_build_test = 142
const native_build_bench = 143
const native_build_clean = 144
const native_build_exec = 145
const native_build_exec_status = 146
const native_build_exists = 147
const native_build_mkdir = 148
const native_build_rm = 149
const native_build_copy = 150
const native_build_glob = 151
const native_build_ls = 152
const native_build_base = 153
const native_build_dir = 154
const native_build_join = 155
const native_build_root = 156
+1
View File
@@ -49,6 +49,7 @@ mut:
lines []obj.LineInfo // debug info: code offset -> source line
const_strs int // strings[0..const_strs] are bytecode constants, never collected
last_heap int // heap size at the last GC check (allocation trigger)
build_root string // directory of the .vrmm build module (build_root() builtin)
}
fn bool_i64(b bool) i64 {
+12
View File
@@ -17,6 +17,17 @@ pub fn run(bin obj.Bin, entry string, trace bool) !i64 {
// run_with_args is run() with command-line arguments exposed to the program
// via the `args()` builtin.
pub fn run_with_args(bin obj.Bin, entry string, trace bool, args []string) !i64 {
return run_internal(bin, entry, trace, args, '')!
}
// run_build executes a .vrmm build module: the entry target receives the
// extra CLI arguments via `args()`, and `build_root()` reports the module's
// own directory so scripts can find files regardless of the working directory.
pub fn run_build(bin obj.Bin, entry string, args []string, root string) !i64 {
return run_internal(bin, entry, false, args, root)!
}
fn run_internal(bin obj.Bin, entry string, trace bool, args []string, root string) !i64 {
mut v := Vm{
code: bin.code
strings: bin.strings.clone()
@@ -25,6 +36,7 @@ pub fn run_with_args(bin obj.Bin, entry string, trace bool, args []string) !i64
prog_args: args
lines: bin.lines
const_strs: bin.strings.len
build_root: root
}
mut entry_ip := -1
for f in bin.fns {