extern crate alloc;
use alloc::format;
use crate::address::Address;
use crate::bytecode::GenericValue;
use crate::float::Float;
use crate::vm::{GenericVm, VmError};
use crate::word::Word;
fn check_arity<W: Word, F: Float>(
name: &str,
expected: usize,
args: &[GenericValue<W, F>],
) -> Result<(), VmError> {
if args.len() != expected {
return Err(VmError::NativeError(format!(
"{}: expected {} argument{}, got {}",
name,
expected,
if expected == 1 { "" } else { "s" },
args.len()
)));
}
Ok(())
}
fn native_println<W: Word, F: Float>(
args: &[GenericValue<W, F>],
) -> Result<GenericValue<W, F>, VmError> {
check_arity("println", 1, args)?;
Ok(GenericValue::Unit)
}
pub fn register_utility_natives<'a, 'arena, W: Word, A: Address, F: Float>(
vm: &mut GenericVm<'a, 'arena, W, A, F>,
) {
vm.register_native("println", native_println::<W, F>);
}
#[cfg(all(test, feature = "compile", feature = "verify", feature = "floats"))]
mod tests {
use super::*;
use crate::bytecode::Value;
use crate::compiler::compile;
use crate::lexer::tokenize;
use crate::parser::parse;
use crate::vm::{DEFAULT_ARENA_CAPACITY, Vm, VmState};
fn run_with_utilities(src: &str, arena: &keleusma_arena::Arena) -> Value {
let tokens = tokenize(src).expect("lex error");
let program = parse(&tokens).expect("parse error");
let module = compile(&program).expect("compile error");
let mut vm = Vm::new(module, arena).unwrap();
register_utility_natives(&mut vm);
vm.register_library(crate::stddsl::Math);
match vm.call(&[]).unwrap() {
VmState::Finished(v) => v,
VmState::Yielded(v) => panic!("unexpected yield: {:?}", v),
VmState::Reset => panic!("unexpected reset"),
VmState::BreakpointHit { chunk, op } => {
panic!("unexpected breakpoint at chunk {} op {}", chunk, op)
}
}
}
#[test]
fn println_returns_unit() {
let arena = keleusma_arena::Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
let val = run_with_utilities("use println\nfn main() -> () { println(42) }", &arena);
assert_eq!(val, Value::Unit);
}
#[test]
fn sqrt_value() {
let arena = keleusma_arena::Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
let val = run_with_utilities(
"use math::sqrt\nfn main() -> Float { math::sqrt(9.0) }",
&arena,
);
assert_eq!(val, Value::Float(3.0));
}
#[test]
fn floor_value() {
let arena = keleusma_arena::Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
let val = run_with_utilities(
"use math::floor\nfn main() -> Float { math::floor(3.7) }",
&arena,
);
assert_eq!(val, Value::Float(3.0));
}
#[test]
fn log2_value() {
let arena = keleusma_arena::Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
let val = run_with_utilities(
"use math::log2\nfn main() -> Float { math::log2(8.0) }",
&arena,
);
assert_eq!(val, Value::Float(3.0));
}
}