Implements `if-else` compliation

pull/4/head
azur 2022-12-13 23:55:52 +07:00
parent 2cf6688e39
commit 07e3af2664
5 changed files with 71 additions and 15 deletions

View File

@ -99,6 +99,21 @@ impl Compiler {
}
instrs
}
Expr::If(c, t, f) => {
let mut instrs = self.compile_expr(c.0);
let t = self.compile_expr(t.0);
if let Some(f) = f {
let f = self.compile_expr(f.0);
instrs.push(Instr::JumpIfFalse(t.len() + 1));
instrs.extend(t);
instrs.push(Instr::Jump(f.len()));
instrs.extend(f);
} else {
instrs.push(Instr::JumpIfFalse(t.len()));
instrs.extend(t);
}
instrs
}
Expr::Do(es) => {
let mut instrs = vec![];
for e in es {

View File

@ -1,14 +1,4 @@
fun foo = \x -> x
fun main = do
foo(1)
[1, 2, 3]
true
print("Hello, World")
let seven = 7 in
print(5 - seven)
let a = 34 in
let b = 35 in
print(a + b)
end
let foo = if true then 10 else 5 in
print(foo)
end

View File

@ -44,6 +44,9 @@ pub enum Token {
Fun,
Let,
In,
If,
Then,
Else,
Do,
End,
}
@ -102,6 +105,9 @@ impl std::fmt::Display for Token {
Token::Fun => write!(f, "fun"),
Token::Let => write!(f, "let"),
Token::In => write!(f, "in"),
Token::If => write!(f, "if"),
Token::Then => write!(f, "then"),
Token::Else => write!(f, "else"),
Token::Do => write!(f, "do"),
Token::End => write!(f, "end"),
}
@ -155,6 +161,9 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
"fun" => Token::Fun,
"let" => Token::Let,
"in" => Token::In,
"if" => Token::If,
"then" => Token::Then,
"else" => Token::Else,
"do" => Token::Do,
"end" => Token::End,
_ => Token::Sym(s),
@ -223,6 +232,11 @@ pub enum Expr {
Lambda(Vec<String>, Box<Spanned<Self>>),
Call(Box<Spanned<Self>>, Vec<Spanned<Self>>),
Let(Vec<(String, Spanned<Self>)>, Option<Box<Spanned<Self>>>),
If(
Box<Spanned<Self>>,
Box<Spanned<Self>>,
Option<Box<Spanned<Self>>>,
),
Do(Vec<Spanned<Expr>>),
}
@ -327,6 +341,15 @@ pub fn expr_parser() -> impl P<Spanned<Expr>> {
.map(|binds| Expr::Let(binds, None))
.labelled("let");
let if_ = just(Token::If)
.ignore_then(expr.clone())
.then_ignore(just(Token::Then))
.then(expr.clone())
.then(just(Token::Else).ignore_then(expr.clone()).or_not())
.map(|((cond, then), else_)| {
Expr::If(Box::new(cond), Box::new(then), else_.map(Box::new))
});
let block = just(Token::Do)
.ignore_then(expr.clone().repeated())
.then_ignore(just(Token::End))
@ -339,6 +362,7 @@ pub fn expr_parser() -> impl P<Spanned<Expr>> {
.or(lam)
.or(let_in)
.or(let_def)
.or(if_)
.or(block)
.map_with_span(|e, s| (e, s))
.boxed()

View File

@ -31,7 +31,7 @@ impl Executor {
}
pub fn run(&mut self) -> Result<(), Error> {
for _ in 0..self.instrs.len() {
while self.ip < self.instrs.len() {
self.step()?;
self.ip += 1;
}
@ -249,6 +249,19 @@ impl Executor {
self.set(name, v)?;
}
Instr::Jump(n) => {
self.ip += n;
}
Instr::JumpIfFalse(n) => {
if let Value::Bool(b) = self.pop()? {
if !b {
self.ip += n;
}
} else {
return Err(Error::make("can't apply `if` to non-boolean", self.ip));
}
}
Instr::Print => {
let v = self.pop()?;
println!("{}", v);

View File

@ -159,6 +159,9 @@ pub enum Instr {
Get(String), // ┐ 1 + string.len() + 1 bytes
Set(String), // ┘
Jump(usize), // ┐ 9 bytes: 1 byte for the enum, 8 bytes for the usize (64-bit)
JumpIfFalse(usize), // ┘
Print, // 1 byte
}
@ -178,7 +181,7 @@ impl Instr {
Instr::Pop | Instr::Dup => 1,
Instr::ListMake(_) | Instr::ListGet(_) | Instr::ListSet(_) => {
std::mem::size_of::<usize>() + 1
1 + std::mem::size_of::<usize>()
}
Instr::ListLen | Instr::ListJoin => 1,
@ -193,6 +196,8 @@ impl Instr {
Instr::Get(s) | Instr::Set(s) => 1 + s.len() + 1,
Instr::Jump(_) | Instr::JumpIfFalse(_) => 1 + std::mem::size_of::<usize>(),
Instr::Print => 1,
}
}
@ -285,6 +290,15 @@ impl Instr {
bytes.push(0x00);
}
Instr::Jump(n) => {
bytes.push(index!());
bytes.extend(n.to_le_bytes());
}
Instr::JumpIfFalse(n) => {
bytes.push(index!());
bytes.extend(n.to_le_bytes());
}
Instr::Print => bytes.push(index!()),
}
bytes