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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use super::{Instruction, RlValue};
use crate::{
expressions::{Expr, Value},
lexing::Lexer,
parsing::Parser,
syntax::Punct,
};
#[cfg(test)]
mod tests;
pub(crate) fn compile(source: &str) -> Vec<Instruction> {
let tokens = Lexer::from(source).lex_all().expect("Lexing failed");
let expr = Parser::from(tokens).parse_all().expect("Parsing failed");
compile_expr(&expr, source)
}
pub(crate) fn compile_expr(expr: &Expr, source: &str) -> Vec<Instruction> {
let mk_str = |(start, end): &(usize, usize)| -> String {
source.chars().skip(*start).take(*end - *start).collect()
};
let mut instrs = Vec::new();
match expr {
Expr::Multiple(exprs) => {
for expr in exprs.iter() {
instrs.append(&mut compile_expr(&expr, source));
}
}
Expr::Declaration { name, val } => {
instrs.append(&mut compile_expr(&val, source));
instrs.push(Instruction::Declare(mk_str(name)));
}
Expr::Rpn(exprs) => {
return exprs
.iter()
.map(|expr| match expr {
Expr::Value(Value::Num(x)) => Instruction::Push(RlValue::Num(*x)),
Expr::IdentLookup(range) => Instruction::PushLocal(mk_str(range)),
Expr::Op(Punct::Add) => Instruction::Add,
Expr::Op(Punct::Sub) => Instruction::Sub,
Expr::Op(Punct::Mul) => Instruction::Mul,
_ => unimplemented!("{:?}", &expr),
})
.collect()
}
Expr::Value(Value::Num(x)) => instrs.push(Instruction::Push(RlValue::Num(*x))),
Expr::Value(Value::Str((start, end))) => {
instrs.push(Instruction::Push(RlValue::Str(mk_str(&(*start, *end)))));
}
Expr::Range { from, to } => {
instrs.append(&mut compile_expr(&from, source));
instrs.append(&mut compile_expr(&to, source));
instrs.push(Instruction::MakeRange);
}
Expr::IdentLookup(range) => {
instrs.push(Instruction::PushLocal(mk_str(range)));
}
Expr::FunctionDeclaration { name, params, body } => {
let mut body = compile_expr(&body, source);
let start = instrs.len() + 3;
let end = start + body.len() + params.len() + 1;
instrs.push(Instruction::Push(RlValue::Function(
start,
params.len() as u8,
)));
instrs.push(Instruction::Push(RlValue::Addr(end)));
instrs.push(Instruction::Jump);
instrs.append(
&mut params
.iter()
.rev()
.map(|p| Instruction::Declare(mk_str(p)))
.collect(),
);
instrs.append(&mut body);
instrs.push(Instruction::Ret);
instrs.push(Instruction::Declare(mk_str(name)));
}
Expr::FunctionCall { name, args } => {
let fn_name = mk_str(name);
args.iter()
.for_each(|arg| instrs.append(&mut compile_expr(arg, source)));
let instr = match fn_name.as_ref() {
"print" => Instruction::CallNative(fn_name),
_ => Instruction::Call(fn_name),
};
instrs.push(instr);
}
_ => unimplemented!("{:?}", &expr),
}
instrs
}