cleanup, added if statements
This commit is contained in:
parent
9cd84dd28b
commit
9f1c29f712
10 changed files with 240 additions and 96 deletions
|
@ -3,8 +3,6 @@ name = "complexpr"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
num-complex = "0.4.1"
|
num-complex = "0.4.1"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
let square = x -> x^2;
|
let square = x -> x^2;
|
||||||
let also_square(x) = x^2
|
let also_square(x) = x^2;
|
||||||
|
|
||||||
let primes = range(100) |: filter(is_prime);
|
let primes = range(100) |: filter(is_prime);
|
||||||
let prime_squares = range(100) |: map(square);
|
let prime_squares = range(100) |: map(square);
|
||||||
|
|
|
@ -3,12 +3,19 @@ use std::{rc::Rc, cell::RefCell, fs::{File, self}, io::{BufReader, Read}};
|
||||||
use complexpr::{eval::Environment, interpreter::interpret, value::Value};
|
use complexpr::{eval::Environment, interpreter::interpret, value::Value};
|
||||||
use rustyline::{self, error::ReadlineError};
|
use rustyline::{self, error::ReadlineError};
|
||||||
|
|
||||||
|
const C_RESET: &'static str = "\x1b[0m";
|
||||||
|
const C_BLUE: &'static str = "\x1b[94m";
|
||||||
|
const PROMPT: &'static str = "\x1b[94m>> \x1b[0m";
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
if args.len() == 2 {
|
if args.len() == 2 {
|
||||||
let fname = &args[1];
|
let fname = &args[1];
|
||||||
let src = fs::read_to_string(fname)?;
|
let src = fs::read_to_string(fname)?;
|
||||||
interpret(&src, None)?;
|
let res = interpret(&src, Some(fname.into()), None, false);
|
||||||
|
if let Err(e) = res {
|
||||||
|
println!("{}", e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
repl()?;
|
repl()?;
|
||||||
}
|
}
|
||||||
|
@ -16,17 +23,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn repl() -> Result<(), Box<dyn std::error::Error>> {
|
fn repl() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
println!("Press {}Ctrl+D{} to exit.", C_BLUE, C_RESET);
|
||||||
let mut rl = rustyline::Editor::<()>::new()?;
|
let mut rl = rustyline::Editor::<()>::new()?;
|
||||||
let env = Rc::new(RefCell::new(Environment::new()));
|
let env = Rc::new(RefCell::new(Environment::new()));
|
||||||
loop {
|
loop {
|
||||||
let readline = rl.readline(">> ");
|
let readline = rl.readline(PROMPT);
|
||||||
match readline {
|
match readline {
|
||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
let result = interpret(&line, Some(env.clone()));
|
let result = interpret(&line, None, Some(env.clone()), true);
|
||||||
match result {
|
match result {
|
||||||
Ok(Value::Nil) => (),
|
Ok(Value::Nil) => (),
|
||||||
Ok(value) => println!("{:?}", value),
|
Ok(value) => println!("{:?}", value),
|
||||||
Err(e) => println!("Error: {}", e)
|
Err(e) => println!("{}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ReadlineError::Eof) => break,
|
Err(ReadlineError::Eof) => break,
|
||||||
|
|
156
src/eval.rs
156
src/eval.rs
|
@ -2,38 +2,49 @@ use std::{collections::HashMap, rc::Rc, cell::RefCell};
|
||||||
|
|
||||||
use num_complex::Complex64;
|
use num_complex::Complex64;
|
||||||
|
|
||||||
use crate::{value::Value, expr::{Stmt, Expr}, token::{TokenType, Token, OpType}};
|
use crate::{value::Value, expr::{Stmt, Expr}, token::{TokenType, Token, OpType}, RuntimeError};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
parent: Option<Rc<RefCell<Environment>>>,
|
parent: Option<EnvRef>,
|
||||||
map: HashMap<Rc<str>, Value>
|
map: HashMap<Rc<str>, Value>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EnvRef = Rc<RefCell<Environment>>;
|
||||||
|
|
||||||
impl Environment {
|
impl Environment {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { parent: None, map: HashMap::new() }
|
Self { parent: None, map: HashMap::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend(parent: Rc<RefCell<Self>>) -> Self {
|
pub fn wrap(self) -> EnvRef {
|
||||||
|
Rc::new(RefCell::new(self))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend(parent: EnvRef) -> Self {
|
||||||
Self { parent: Some(parent), map: HashMap::new() }
|
Self { parent: Some(parent), map: HashMap::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, name: &str) -> Result<Value,()> {
|
pub fn get(&self, name: &str) -> Result<Value,()> {
|
||||||
match self.map.get(name) {
|
let x = match self.map.get(name) {
|
||||||
Some(v) => Ok(v.clone()),
|
Some(v) => Ok(v.clone()),
|
||||||
None => match self.parent {
|
None => match self.parent {
|
||||||
Some(ref p) => p.borrow().get(name),
|
Some(ref p) => p.borrow().get(name),
|
||||||
None => Err(())
|
None => Err(())
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
println!("get {}: {:?}", name, x);
|
||||||
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn declare(&mut self, name: Rc<str>, value: Value) {
|
pub fn declare(&mut self, name: Rc<str>, value: Value) {
|
||||||
|
println!("declare {}: {:?}", name, value);
|
||||||
self.map.insert(name, value);
|
self.map.insert(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, name: Rc<str>, value: Value) -> Result<(),()> {
|
pub fn set(&mut self, name: Rc<str>, value: Value) -> Result<(),()> {
|
||||||
|
println!("set {}: {:?}", name, value);
|
||||||
match self.map.contains_key(&name) {
|
match self.map.contains_key(&name) {
|
||||||
true => { self.map.insert(name, value); Ok(()) },
|
true => { self.map.insert(name, value); Ok(()) },
|
||||||
false => match self.parent {
|
false => match self.parent {
|
||||||
|
@ -44,7 +55,7 @@ impl Environment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_stmt(stmt: &Stmt, env: Rc<RefCell<Environment>>) -> Result<(), String> {
|
pub fn eval_stmt(stmt: &Stmt, env: EnvRef) -> Result<(), RuntimeError> {
|
||||||
match stmt {
|
match stmt {
|
||||||
Stmt::Expr{ expr }
|
Stmt::Expr{ expr }
|
||||||
=> drop(eval_expr(expr, env)),
|
=> drop(eval_expr(expr, env)),
|
||||||
|
@ -54,55 +65,108 @@ pub fn eval_stmt(stmt: &Stmt, env: Rc<RefCell<Environment>>) -> Result<(), Strin
|
||||||
let r = eval_expr(rhs, env.clone())?;
|
let r = eval_expr(rhs, env.clone())?;
|
||||||
env.borrow_mut().declare(s.clone(), r)
|
env.borrow_mut().declare(s.clone(), r)
|
||||||
},
|
},
|
||||||
Stmt::If { conditions, bodies, else_clause }
|
Stmt::Block { stmts } => {
|
||||||
=> todo!(), // TODO if statements
|
let block_env = Environment::extend(env).wrap();
|
||||||
|
for stmt in stmts {
|
||||||
|
eval_stmt(stmt, block_env.clone())?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stmt::If { if_clauses, else_clause } => {
|
||||||
|
for ic in if_clauses {
|
||||||
|
let cond = eval_expr(&ic.0, env.clone())?;
|
||||||
|
if cond.truthy() {
|
||||||
|
return eval_stmt(&ic.1, env.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(ec) = else_clause {
|
||||||
|
return eval_stmt(&ec, env)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_expr(expr: &Expr, env: Rc<RefCell<Environment>>) -> Result<Value, String> {
|
pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Literal { value } => match &value.ty {
|
Expr::Literal { value } => Ok(eval_literal(value)),
|
||||||
TokenType::Nil => Ok(Value::Nil),
|
Expr::Ident { value } => eval_ident(value, env),
|
||||||
TokenType::True => Ok(Value::Bool(true)),
|
|
||||||
TokenType::False => Ok(Value::Bool(false)),
|
|
||||||
TokenType::Int(n) => Ok(Value::Int(*n)),
|
|
||||||
TokenType::Float(f) => Ok(Value::Float(*f)),
|
|
||||||
TokenType::ImFloat(f) => Ok(Value::Complex(Complex64::new(0.0, *f))),
|
|
||||||
TokenType::String(s) => Ok(Value::String(s.clone())),
|
|
||||||
_ => todo!()
|
|
||||||
},
|
|
||||||
Expr::Ident { value } => if let Token { ty: TokenType::Ident(name), ..} = value {
|
|
||||||
env.borrow_mut().get(name).map_err(|_| "Variable not defined in scope".into())
|
|
||||||
} else { unreachable!() },
|
|
||||||
Expr::Binary { lhs, rhs, op } => match op.ty.get_op_type() {
|
Expr::Binary { lhs, rhs, op } => match op.ty.get_op_type() {
|
||||||
Some(OpType::Assignment) => {
|
Some(OpType::Assignment)
|
||||||
let r = eval_expr(rhs, env.clone())?;
|
=> eval_assignment(lhs, rhs, op, env),
|
||||||
if let Expr::Ident{value: Token{ty: TokenType::Ident(name),..}} = &**lhs {
|
Some(OpType::Additive) | Some(OpType::Multiplicative)
|
||||||
if op.ty == TokenType::Equal {
|
=> eval_binary(lhs, rhs, op, env),
|
||||||
env.borrow_mut().set(name.clone(), r).map_err(|_| "Variable not declared before assignment")?;
|
|
||||||
Ok(Value::Nil)
|
|
||||||
} else {
|
|
||||||
todo!() // TODO +=, -=, etc
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Some(OpType::Additive) | Some(OpType::Multiplicative) => {
|
|
||||||
let l = eval_expr(lhs, env.clone())?;
|
|
||||||
let r = eval_expr(rhs, env)?;
|
|
||||||
match op.ty {
|
|
||||||
TokenType::Plus => &l + &r,
|
|
||||||
TokenType::Minus => &l - &r,
|
|
||||||
TokenType::Star => &l * &r,
|
|
||||||
TokenType::Slash => &l / &r,
|
|
||||||
_ => todo!() // TODO other operations
|
|
||||||
}
|
|
||||||
},
|
|
||||||
o => todo!("{:?}", o) // TODO other operations
|
o => todo!("{:?}", o) // TODO other operations
|
||||||
},
|
},
|
||||||
e => todo!("{:?}", e) // TODO other expression types
|
e => todo!("{:?}", e) // TODO other expression types
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn eval_literal(token: &Token) -> Value {
|
||||||
|
match &token.ty {
|
||||||
|
TokenType::Nil => Value::Nil,
|
||||||
|
TokenType::True => Value::Bool(true),
|
||||||
|
TokenType::False => Value::Bool(false),
|
||||||
|
TokenType::Int(n) => Value::Int(*n),
|
||||||
|
TokenType::Float(f) => Value::Float(*f),
|
||||||
|
TokenType::ImFloat(f) => Value::Complex(Complex64::new(0.0, *f)),
|
||||||
|
TokenType::String(s) => Value::String(s.clone()),
|
||||||
|
_ => todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eval_ident(token: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
|
if let Token { ty: TokenType::Ident(name), ..} = token {
|
||||||
|
env.borrow_mut()
|
||||||
|
.get(name)
|
||||||
|
.map_err(|_| RuntimeError { message: "Variable not defined in scope".into(), pos: token.pos.clone() })
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eval_assignment(lhs: &Box<Expr>, rhs: &Box<Expr>, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
|
// lhs must be an identifier (checked in parser)
|
||||||
|
if let Expr::Ident{value: Token{ty: TokenType::Ident(name),..}} = &**lhs {
|
||||||
|
if op.ty == TokenType::Equal {
|
||||||
|
// plain assignment
|
||||||
|
let r = eval_expr(rhs, env.clone())?;
|
||||||
|
env.borrow_mut()
|
||||||
|
.set(name.clone(), r)
|
||||||
|
.map_err(|_| RuntimeError { message: "Variable not declared before assignment".into(), pos: op.pos.clone() })?;
|
||||||
|
Ok(Value::Nil)
|
||||||
|
} else {
|
||||||
|
// compound assignment
|
||||||
|
let prev_value = env.borrow_mut()
|
||||||
|
.get(name)
|
||||||
|
.map_err(|_| RuntimeError { message: "Variable not defined in scope".into(), pos: op.pos.clone()})?;
|
||||||
|
let r = eval_expr(rhs, env.clone())?;
|
||||||
|
|
||||||
|
let result = match op.ty {
|
||||||
|
TokenType::PlusEqual => &prev_value + &r,
|
||||||
|
TokenType::MinusEqual => &prev_value - &r,
|
||||||
|
TokenType::StarEqual => &prev_value * &r,
|
||||||
|
TokenType::SlashEqual => &prev_value / &r,
|
||||||
|
_ => todo!() // TODO more operations
|
||||||
|
}.map_err(|e| RuntimeError { message: e, pos: op.pos.clone() })?;
|
||||||
|
|
||||||
|
env.borrow_mut()
|
||||||
|
.set(name.clone(), result.clone()).expect("unreachable");
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eval_binary(lhs: &Box<Expr>, rhs: &Box<Expr>, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
||||||
|
let l = eval_expr(lhs, env.clone())?;
|
||||||
|
let r = eval_expr(rhs, env)?;
|
||||||
|
match op.ty {
|
||||||
|
TokenType::Plus => &l + &r,
|
||||||
|
TokenType::Minus => &l - &r,
|
||||||
|
TokenType::Star => &l * &r,
|
||||||
|
TokenType::Slash => &l / &r,
|
||||||
|
_ => todo!() // TODO other operations
|
||||||
|
}.map_err(|e| RuntimeError { message: e, pos: op.pos.clone() })
|
||||||
|
}
|
|
@ -5,7 +5,8 @@ use crate::{token::{Token, OpType}};
|
||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
Expr { expr: Expr },
|
Expr { expr: Expr },
|
||||||
Let { lhs: Token, rhs: Option<Expr> },
|
Let { lhs: Token, rhs: Option<Expr> },
|
||||||
If { conditions: Vec<Expr>, bodies: Vec<Vec<Stmt>>, else_clause: Option<Vec<Stmt>> }
|
Block { stmts: Vec<Stmt> },
|
||||||
|
If { if_clauses: Vec<(Expr, Stmt)>, else_clause: Option<Box<Stmt>> }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Stmt {
|
impl fmt::Debug for Stmt {
|
||||||
|
|
|
@ -2,10 +2,10 @@ use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use crate::{value::Value, lexer::Lexer, parser::Parser, eval::{Environment, eval_stmt, eval_expr}, expr::Stmt};
|
use crate::{value::Value, lexer::Lexer, parser::Parser, eval::{Environment, eval_stmt, eval_expr}, expr::Stmt};
|
||||||
|
|
||||||
pub fn interpret(src: &str, env: Option<Rc<RefCell<Environment>>>) -> Result<Value, Box<dyn std::error::Error>> {
|
pub fn interpret(src: &str, fname: Option<String>, env: Option<Rc<RefCell<Environment>>>, repl: bool) -> Result<Value, Box<dyn std::error::Error>> {
|
||||||
let mut lexer = Lexer::new(src, None);
|
let mut lexer = Lexer::new(src, fname);
|
||||||
lexer.lex()?;
|
lexer.lex()?;
|
||||||
let mut parser = Parser::new(lexer.into_tokens());
|
let mut parser = Parser::new(lexer.into_tokens(), repl);
|
||||||
let ast = parser.parse()?;
|
let ast = parser.parse()?;
|
||||||
let environ;
|
let environ;
|
||||||
if let Some(env) = env {
|
if let Some(env) = env {
|
||||||
|
|
121
src/parser.rs
121
src/parser.rs
|
@ -2,12 +2,13 @@ use crate::{token::{Token, TokenType, OpType}, ParserError, expr::{Stmt, Expr}};
|
||||||
|
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
tokens: Vec<Token>,
|
tokens: Vec<Token>,
|
||||||
|
repl: bool,
|
||||||
idx: usize
|
idx: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
pub fn new(tokens: Vec<Token>) -> Self {
|
pub fn new(tokens: Vec<Token>, repl: bool) -> Self {
|
||||||
Self { tokens, idx: 0 }
|
Self { tokens, repl, idx: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn at_end(&self) -> bool {
|
fn at_end(&self) -> bool {
|
||||||
|
@ -56,34 +57,11 @@ impl Parser {
|
||||||
// let statement
|
// let statement
|
||||||
TokenType::Let => {
|
TokenType::Let => {
|
||||||
self.next();
|
self.next();
|
||||||
let expr = self.assignment()?;
|
return self.letstmt()
|
||||||
|
}
|
||||||
// must be followed by an assignment expression
|
TokenType::LBrace => {
|
||||||
if let Expr::Binary{lhs, rhs, op: Token{ty: TokenType::Equal,..}} = expr {
|
self.next();
|
||||||
if let Expr::Ident{value: tok} = *lhs {
|
return self.block()
|
||||||
if self.at_end() {
|
|
||||||
return Ok(Stmt::Let{lhs: tok, rhs: Some(*rhs)})
|
|
||||||
}
|
|
||||||
let next = self.next();
|
|
||||||
return match next.ty {
|
|
||||||
TokenType::Semicolon => Ok(Stmt::Let{lhs: tok, rhs: Some(*rhs)}),
|
|
||||||
_ => Err(self.mk_error("Missing semicolon after 'let' statement".to_owned()))
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
|
||||||
}
|
|
||||||
} else if let Expr::Ident{value: tok} = expr {
|
|
||||||
if self.at_end() {
|
|
||||||
return Ok(Stmt::Let{lhs: tok, rhs: None})
|
|
||||||
}
|
|
||||||
let next = self.next();
|
|
||||||
return match next.ty {
|
|
||||||
TokenType::Semicolon => Ok(Stmt::Let{lhs: tok, rhs: None}),
|
|
||||||
_ => Err(self.mk_error("Missing semicolon after 'let' statement".to_owned()))
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if statement
|
// if statement
|
||||||
|
@ -96,7 +74,11 @@ impl Parser {
|
||||||
_ => {
|
_ => {
|
||||||
let expr = self.assignment()?;
|
let expr = self.assignment()?;
|
||||||
if self.at_end() {
|
if self.at_end() {
|
||||||
return Ok(Stmt::Expr{expr})
|
if self.repl {
|
||||||
|
return Ok(Stmt::Expr{expr})
|
||||||
|
} else {
|
||||||
|
self.err_on_eof()?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = self.next();
|
let next = self.next();
|
||||||
|
@ -109,6 +91,79 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn letstmt(&mut self) -> Result<Stmt, ParserError> {
|
||||||
|
let expr = self.assignment()?;
|
||||||
|
// must be followed by an assignment expression
|
||||||
|
if let Expr::Binary{lhs, rhs, op: Token{ty: TokenType::Equal,..}} = expr {
|
||||||
|
if let Expr::Ident{value: tok} = *lhs {
|
||||||
|
if self.at_end() {
|
||||||
|
if self.repl {
|
||||||
|
return Ok(Stmt::Let{lhs: tok, rhs: Some(*rhs)})
|
||||||
|
} else {
|
||||||
|
self.err_on_eof()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let next = self.next();
|
||||||
|
return match next.ty {
|
||||||
|
TokenType::Semicolon => Ok(Stmt::Let{lhs: tok, rhs: Some(*rhs)}),
|
||||||
|
_ => Err(self.mk_error("Missing semicolon after 'let' statement".to_owned()))
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
||||||
|
}
|
||||||
|
} else if let Expr::Ident{value: tok} = expr {
|
||||||
|
if self.at_end() {
|
||||||
|
if self.repl {
|
||||||
|
return Ok(Stmt::Let{lhs: tok, rhs: None})
|
||||||
|
} else {
|
||||||
|
self.err_on_eof()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let next = self.next();
|
||||||
|
return match next.ty {
|
||||||
|
TokenType::Semicolon => Ok(Stmt::Let{lhs: tok, rhs: None}),
|
||||||
|
_ => Err(self.mk_error("Missing semicolon after 'let' statement".to_owned()))
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
Err(self.mk_error("Invalid expression after 'let'".to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ifstmt(&mut self) -> Result<Stmt, ParserError> {
|
||||||
|
let mut if_clauses = vec![];
|
||||||
|
let mut ec = false;
|
||||||
|
loop {
|
||||||
|
let condition = self.assignment()?;
|
||||||
|
let body = self.statement()?;
|
||||||
|
if_clauses.push((condition, body));
|
||||||
|
match self.peek().ty {
|
||||||
|
TokenType::Elif => { self.next(); continue },
|
||||||
|
TokenType::Else => { self.next(); ec = true; break },
|
||||||
|
_ => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let else_clause;
|
||||||
|
if ec {
|
||||||
|
else_clause = Some(Box::new(self.statement()?));
|
||||||
|
} else {
|
||||||
|
else_clause = None;
|
||||||
|
}
|
||||||
|
return Ok(Stmt::If{
|
||||||
|
if_clauses: if_clauses,
|
||||||
|
else_clause: else_clause
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block(&mut self) -> Result<Stmt, ParserError> {
|
||||||
|
let mut stmts = vec![];
|
||||||
|
while !self.at_end() && self.peek().ty != TokenType::RBrace {
|
||||||
|
stmts.push(self.statement()?)
|
||||||
|
}
|
||||||
|
self.err_on_eof()?;
|
||||||
|
self.next();
|
||||||
|
return Ok(Stmt::Block{ stmts })
|
||||||
|
}
|
||||||
|
|
||||||
// Generic method for left-associative operators
|
// Generic method for left-associative operators
|
||||||
fn expr(&mut self, op_type: OpType, next_level: fn(&mut Parser) -> Result<Expr, ParserError>) -> Result<Expr, ParserError> {
|
fn expr(&mut self, op_type: OpType, next_level: fn(&mut Parser) -> Result<Expr, ParserError>) -> Result<Expr, ParserError> {
|
||||||
let mut expr = next_level(self)?;
|
let mut expr = next_level(self)?;
|
||||||
|
@ -224,8 +279,4 @@ impl Parser {
|
||||||
Err(self.mk_error(format!("Unexpected token: {:?}", next.ty)))
|
Err(self.mk_error(format!("Unexpected token: {:?}", next.ty)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ifstmt(&mut self) -> Result<Stmt, ParserError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
18
src/value.rs
18
src/value.rs
|
@ -1,5 +1,7 @@
|
||||||
use std::{rc::Rc, collections::HashMap, ops::*};
|
use std::{rc::Rc, collections::HashMap, ops::*};
|
||||||
|
|
||||||
|
use num_traits::Zero;
|
||||||
|
|
||||||
type Rational = num_rational::Ratio<i64>;
|
type Rational = num_rational::Ratio<i64>;
|
||||||
type Complex = num_complex::Complex64;
|
type Complex = num_complex::Complex64;
|
||||||
|
|
||||||
|
@ -56,6 +58,22 @@ pub enum Value {
|
||||||
List(Rc<Vec<Value>>), Map(Rc<HashMap<Value,Value>>),
|
List(Rc<Vec<Value>>), Map(Rc<HashMap<Value,Value>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
pub fn truthy(&self) -> bool {
|
||||||
|
use Value::*;
|
||||||
|
match self {
|
||||||
|
Bool(false) | Nil | Int(0) => false,
|
||||||
|
Float(f) => *f != 0.0,
|
||||||
|
Complex(z) => !z.is_zero(),
|
||||||
|
Rational(r) => !r.is_zero(),
|
||||||
|
String(s) => !s.len() == 0,
|
||||||
|
List(l) => !l.len() == 0,
|
||||||
|
Map(m) => !m.len() == 0,
|
||||||
|
_ => true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
value_from!(Int, u8 u16 u32 i8 i16 i32 i64);
|
value_from!(Int, u8 u16 u32 i8 i16 i32 i64);
|
||||||
value_from!(Float, f32 f64);
|
value_from!(Float, f32 f64);
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
let a = 1;
|
if false {
|
||||||
let b = 2;
|
|
||||||
a = a + b;
|
} elif true {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ use complexpr::{lexer::Lexer, parser::Parser, eval::{Environment, eval_stmt}};
|
||||||
pub fn test() {
|
pub fn test() {
|
||||||
let mut lexer = Lexer::new("let a = 1 + 1; let b = a + 1;", None);
|
let mut lexer = Lexer::new("let a = 1 + 1; let b = a + 1;", None);
|
||||||
lexer.lex().unwrap();
|
lexer.lex().unwrap();
|
||||||
let mut parser = Parser::new(lexer.into_tokens());
|
let mut parser = Parser::new(lexer.into_tokens(), false);
|
||||||
let ast = parser.parse().unwrap();
|
let ast = parser.parse().unwrap();
|
||||||
let env = Rc::new(RefCell::new(Environment::new()));
|
let env = Rc::new(RefCell::new(Environment::new()));
|
||||||
for stmt in ast {
|
for stmt in ast {
|
||||||
|
|
Loading…
Reference in a new issue