use lex_ast::canonicalize_program;
use lex_bytecode::{compile_program, vm::Vm, Value};
use lex_runtime::{DefaultHandler, Policy};
use lex_syntax::parse_source;
use std::collections::BTreeSet;
use std::sync::Arc;
const SRC: &str = r#"
import "std.vcs" as vcs
# Put content, then read it back by the returned sha. Returns the content.
fn put_get(content :: Str) -> [vcs, fs_write, fs_read] Str {
match vcs.put_blob(content) {
Err(e) => str_err(e),
Ok(sha) => match vcs.get_blob(sha) {
Err(e) => str_err(e),
Ok(c) => c,
},
}
}
# Bind ns/key to sha, then resolve it back. Returns the resolved sha.
fn ref_roundtrip(ns :: Str, key :: Str, sha :: Str) -> [vcs, fs_write, fs_read] Str {
match vcs.ref_set(ns, key, sha) {
Err(e) => str_err(e),
Ok(_) => match vcs.ref_get(ns, key) {
Err(e) => str_err(e),
Ok(s) => s,
},
}
}
fn str_err(e :: Str) -> Str { e }
"#;
fn policy_with(effects: &[&str]) -> Policy {
let mut p = Policy::pure();
p.allow_effects = effects.iter().map(|s| s.to_string()).collect::<BTreeSet<_>>();
p
}
fn compile() -> Arc<lex_bytecode::Program> {
let prog = parse_source(SRC).expect("parse");
let stages = canonicalize_program(&prog);
if let Err(errs) = lex_types::check_program(&stages) {
panic!("type errors:\n{errs:#?}");
}
Arc::new(compile_program(&stages))
}
fn call_str(bc: &Arc<lex_bytecode::Program>, func: &str, args: Vec<Value>) -> String {
let handler = DefaultHandler::new(policy_with(&["vcs", "fs_write", "fs_read"]))
.with_program(Arc::clone(bc));
let mut vm = Vm::with_handler(bc, Box::new(handler));
match vm.call(func, args).expect("vm call") {
Value::Str(s) => s.to_string(),
other => panic!("expected Str, got {other:?}"),
}
}
#[test]
fn blob_and_ref_roundtrip_through_vm() {
let tmp = tempfile::tempdir().unwrap();
std::env::set_var("LEX_STORE_ROOT", tmp.path());
let bc = compile();
let got = call_str(&bc, "put_get", vec![Value::Str("hello loom artifact".into())]);
assert_eq!(got, "hello loom artifact");
let sha = "deadbeefcafe";
let resolved = call_str(
&bc,
"ref_roundtrip",
vec![
Value::Str("loom/sprint-demo".into()),
Value::Str("build-node".into()),
Value::Str(sha.into()),
],
);
assert_eq!(resolved, sha);
assert!(tmp.path().join("blobrefs").join("loom").join("sprint-demo").join("build-node").exists());
std::env::remove_var("LEX_STORE_ROOT");
}