Skip to main content

target_aware_compile/
target_aware_compile.rs

1//! End-to-end demonstration of target-aware compilation.
2//!
3//! The compiler accepts a `Target` descriptor through
4//! `compile_with_target`. The target's word, address, and float
5//! widths are baked into the bytecode wire format, and the compiler
6//! rejects programs that use features unsupported by the target
7//! (such as floating-point operations on a no-float target).
8//!
9//! The current 64-bit runtime accepts bytecode with widths at most
10//! its own. Emitting for a narrower target produces bytecode the
11//! runtime can still load, with integer arithmetic masked to the
12//! declared width. A future runtime build for a narrower native
13//! target could refuse 64-bit bytecode and admit only its own width.
14//!
15//! Run with: `cargo run --example target_aware_compile`
16
17use keleusma::compiler::compile_with_target;
18use keleusma::lexer::tokenize;
19use keleusma::parser::parse;
20use keleusma::target::Target;
21use keleusma::vm::{DEFAULT_ARENA_CAPACITY, Vm, VmState};
22use keleusma::{Arena, Value};
23
24fn main() {
25    let int_only = r#"
26        fn main() -> i64 {
27            let x: i64 = 7;
28            x * 6
29        }
30    "#;
31    let with_float = r#"
32        fn main() -> f64 {
33            let f: f64 = 1.5;
34            f
35        }
36    "#;
37
38    println!("=== host target (64-bit, all features) ===");
39    compile_and_run(int_only, &Target::host());
40    compile_and_run(with_float, &Target::host());
41
42    println!();
43    println!("=== embedded_32 target (32-bit, all features) ===");
44    compile_with_target_show_widths(int_only, &Target::embedded_32());
45    compile_and_run(int_only, &Target::embedded_32());
46    compile_and_run(with_float, &Target::embedded_32());
47
48    println!();
49    println!("=== embedded_16 target (16-bit, no floats) ===");
50    compile_with_target_show_widths(int_only, &Target::embedded_16());
51    compile_and_run(int_only, &Target::embedded_16());
52    let result = compile_with_target(
53        &parse(&tokenize(with_float).expect("lex")).expect("parse"),
54        &Target::embedded_16(),
55    );
56    match result {
57        Ok(_) => panic!("expected float rejection"),
58        Err(e) => println!("float program rejected: {}", e.message),
59    }
60
61    println!();
62    println!("=== embedded_8 target (8-bit, no floats, no strings) ===");
63    compile_with_target_show_widths(int_only, &Target::embedded_8());
64    compile_and_run(int_only, &Target::embedded_8());
65    let with_string = "fn main() -> i64 { let s = \"hi\"; 0 }";
66    let result = compile_with_target(
67        &parse(&tokenize(with_string).expect("lex")).expect("parse"),
68        &Target::embedded_8(),
69    );
70    match result {
71        Ok(_) => panic!("expected string rejection"),
72        Err(e) => println!("string program rejected: {}", e.message),
73    }
74}
75
76fn compile_with_target_show_widths(src: &str, target: &Target) {
77    let tokens = tokenize(src).expect("lex");
78    let program = parse(&tokens).expect("parse");
79    let module = compile_with_target(&program, target).expect("compile");
80    println!(
81        "  declared widths: word={} addr={} float={}",
82        module.word_bits_log2, module.addr_bits_log2, module.float_bits_log2,
83    );
84}
85
86fn compile_and_run(src: &str, target: &Target) {
87    let tokens = tokenize(src).expect("lex");
88    let program = parse(&tokens).expect("parse");
89    let module = compile_with_target(&program, target).expect("compile");
90    let arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
91    let mut vm = Vm::new(module, &arena).expect("verify");
92    match vm.call(&[]).expect("call") {
93        VmState::Finished(v) => println!("  result: {:?}", v),
94        other => panic!("unexpected: {:?}", other),
95    }
96    let _ = Value::Unit;
97}