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()
}