1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#![recursion_limit = "1024"]
pub mod ast;
#[cfg(not(feature = "web"))]
pub mod check;
#[cfg(not(feature = "web"))]
pub mod debug;
pub mod parse;
pub mod program;
pub mod runner;
pub mod targets;
pub use ast::*;
pub use parse::*;
use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
use std::path::{Path, PathBuf};
pub const PRELUDE: &str = include_str!("../lib/prelude.fth");
pub const PRELUDE_GB: &str = include_str!("../lib/libra/prelude-gameboy.fth");
pub trait ForthCompiler {
fn preludes() -> Vec<(PathBuf, String)>;
fn compile(program: &PaxProgram) -> String;
fn parse(code: &str, arg_file: Option<&Path>) -> PaxProgram {
if let Some(arg) = arg_file {
let arg_str = arg.to_string_lossy().to_string();
parse_to_pax(&code, Some(&arg_str), Self::preludes())
} else {
parse_to_pax(&code, None, Self::preludes())
}
}
}
pub fn dump_blocks(blocks: &[Block]) {
for (i, block) in blocks.iter().enumerate() {
println!(" Block({})", i);
for command in block.opcodes() {
println!(
" {:<30} {}",
format!("{:?}", command.0),
format!("// {:>80}", command.1)
);
}
{
let terminator = block.terminator();
println!(
" {:<30} {}",
format!("{:?}", terminator.0),
format!("// {:>80}", terminator.1)
);
}
}
println!();
}
pub fn dump_program(source_program: &PaxProgram) {
for (name, code) in source_program {
println!("( fn \"{}\" )", name);
dump_blocks(&code);
println!();
}
}
pub fn name_slug(name: &str) -> String {
const NON_ALPHA: AsciiSet = NON_ALPHANUMERIC.remove(b'_');
utf8_percent_encode(name, &NON_ALPHA)
.to_string()
.replace("$", "$$")
.replace("%", "$")
.to_string()
}