string_ops/string_ops.rs
1//! End-to-end demonstration of string concatenation, slicing, and
2//! f-string interpolation.
3//!
4//! `concat(a, b)` and `slice(s, start, end)` are utility natives.
5//! f-strings `f"hello {name}"` desugar at lex time to a chain of
6//! `concat` and `to_string` calls. The desugaring is performed by
7//! the lexer, which queues the synthesized tokens; the parser sees
8//! a regular function-call AST and emits the corresponding bytecode.
9//!
10//! WCET note. String concatenation and slicing produce dynamic
11//! strings whose worst-case output length is the sum of operand
12//! lengths (concat) or `end - start` (slice). The current verifier
13//! treats native function allocations as the per-native attestation
14//! supplied through `Vm::set_native_bounds`. Hosts that rely on
15//! `verify_resource_bounds` for real-time embedding must declare
16//! heap bounds for `concat` and `slice` before constructing the VM
17//! through the safe constructor.
18//!
19//! Run with: `cargo run --example string_ops`
20
21use keleusma::compiler::compile;
22use keleusma::lexer::tokenize;
23use keleusma::parser::parse;
24use keleusma::utility_natives::register_utility_natives;
25use keleusma::vm::{DEFAULT_ARENA_CAPACITY, Vm, VmState};
26use keleusma::{Arena, Value};
27
28fn main() {
29 let src = r#"
30 use to_string
31 use concat
32 use slice
33 fn main() -> String {
34 let name = "Keleusma";
35 let n: i64 = 42;
36 let greeting = f"hello, {name}! n = {n}";
37 let head = slice(greeting, 0, 5);
38 concat(head, "...")
39 }
40 "#;
41 let tokens = tokenize(src).expect("lex");
42 let program = parse(&tokens).expect("parse");
43 let module = compile(&program).expect("compile");
44 let arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
45 let mut vm = Vm::new(module, &arena).expect("verify");
46 register_utility_natives(&mut vm);
47 match vm.call(&[]) {
48 Ok(VmState::Finished(Value::DynStr(s))) => {
49 println!("result: {}", s);
50 assert_eq!(s, "hello...");
51 println!("string ops executed end to end");
52 }
53 other => panic!("unexpected: {:?}", other),
54 }
55}