Skip to content

Commit

Permalink
Merge pull request #47 from flaneur2020/add-bihuan
Browse files Browse the repository at this point in the history
add 闭环
  • Loading branch information
flaneur2020 committed Apr 25, 2021
2 parents cecbe9d + 7a288e4 commit d60eefa
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 34 deletions.
4 changes: 4 additions & 0 deletions src/ast.rs
Expand Up @@ -63,6 +63,10 @@ pub enum Expr {
consequence: BlockStmt,
alternative: Option<BlockStmt>,
},
While {
cond: Box<Expr>,
consequence: BlockStmt,
},
Func {
params: Vec<Ident>,
body: BlockStmt,
Expand Down
109 changes: 75 additions & 34 deletions src/evaluator/mod.rs
Expand Up @@ -37,11 +37,11 @@ impl Evaluator {
}
}

pub fn eval(&mut self, program: Program) -> Option<Object> {
pub fn eval(&mut self, program: &Program) -> Option<Object> {
let mut result = None;

for stmt in program {
if stmt == Stmt::Blank {
if *stmt == Stmt::Blank {
continue;
}

Expand All @@ -55,11 +55,11 @@ impl Evaluator {
result
}

fn eval_block_stmt(&mut self, stmts: BlockStmt) -> Option<Object> {
fn eval_block_stmt(&mut self, stmts: &BlockStmt) -> Option<Object> {
let mut result = None;

for stmt in stmts {
if stmt == Stmt::Blank {
if *stmt == Stmt::Blank {
continue;
}

Expand All @@ -73,7 +73,7 @@ impl Evaluator {
result
}

fn eval_stmt(&mut self, stmt: Stmt) -> Option<Object> {
fn eval_stmt(&mut self, stmt: &Stmt) -> Option<Object> {
match stmt {
Stmt::Let(ident, expr) => {
let value = match self.eval_expr(expr) {
Expand All @@ -84,7 +84,7 @@ impl Evaluator {
Some(value)
} else {
let Ident(name) = ident;
self.env.borrow_mut().set(name, &value);
self.env.borrow_mut().set(name.clone(), &value);
None
}
}
Expand All @@ -104,29 +104,29 @@ impl Evaluator {
}
}

fn eval_expr(&mut self, expr: Expr) -> Option<Object> {
fn eval_expr(&mut self, expr: &Expr) -> Option<Object> {
match expr {
Expr::Ident(ident) => Some(self.eval_ident(ident)),
Expr::Literal(literal) => Some(self.eval_literal(literal)),
Expr::Prefix(prefix, right_expr) => {
if let Some(right) = self.eval_expr(*right_expr) {
if let Some(right) = self.eval_expr(&*right_expr) {
Some(self.eval_prefix_expr(prefix, right))
} else {
None
}
}
Expr::Infix(infix, left_expr, right_expr) => {
let left = self.eval_expr(*left_expr);
let right = self.eval_expr(*right_expr);
let left = self.eval_expr(&*left_expr);
let right = self.eval_expr(&*right_expr);
if left.is_some() && right.is_some() {
Some(self.eval_infix_expr(infix, left.unwrap(), right.unwrap()))
} else {
None
}
}
Expr::Index(left_expr, index_expr) => {
let left = self.eval_expr(*left_expr);
let index = self.eval_expr(*index_expr);
let left = self.eval_expr(&*left_expr);
let index = self.eval_expr(&*index_expr);
if left.is_some() && index.is_some() {
Some(self.eval_index_expr(left.unwrap(), index.unwrap()))
} else {
Expand All @@ -137,13 +137,17 @@ impl Evaluator {
cond,
consequence,
alternative,
} => self.eval_if_expr(*cond, consequence, alternative),
Expr::Func { params, body } => Some(Object::Func(params, body, Rc::clone(&self.env))),
} => self.eval_if_expr(&*cond, consequence, alternative),
Expr::While {
cond,
consequence,
} => self.eval_while_expr(&*cond, consequence),
Expr::Func { params, body } => Some(Object::Func(params.clone(), body.clone(), Rc::clone(&self.env))),
Expr::Call { func, args } => Some(self.eval_call_expr(func, args)),
}
}

fn eval_ident(&mut self, ident: Ident) -> Object {
fn eval_ident(&mut self, ident: &Ident) -> Object {
let Ident(name) = ident;

match self.env.borrow_mut().get(name.clone()) {
Expand All @@ -152,7 +156,7 @@ impl Evaluator {
}
}

fn eval_prefix_expr(&mut self, prefix: Prefix, right: Object) -> Object {
fn eval_prefix_expr(&mut self, prefix: &Prefix, right: Object) -> Object {
match prefix {
Prefix::Not => self.eval_not_op_expr(right),
Prefix::Minus => self.eval_minus_prefix_op_expr(right),
Expand Down Expand Up @@ -183,7 +187,7 @@ impl Evaluator {
}
}

fn eval_infix_expr(&mut self, infix: Infix, left: Object, right: Object) -> Object {
fn eval_infix_expr(&mut self, infix: &Infix, left: Object, right: Object) -> Object {
match left {
Object::Int(left_value) => {
if let Object::Int(right_value) = right {
Expand Down Expand Up @@ -237,7 +241,7 @@ impl Evaluator {
}
}

fn eval_infix_int_expr(&mut self, infix: Infix, left: i64, right: i64) -> Object {
fn eval_infix_int_expr(&mut self, infix: &Infix, left: i64, right: i64) -> Object {
match infix {
Infix::Plus => Object::Int(left + right),
Infix::Minus => Object::Int(left - right),
Expand All @@ -252,7 +256,7 @@ impl Evaluator {
}
}

fn eval_infix_string_expr(&mut self, infix: Infix, left: String, right: String) -> Object {
fn eval_infix_string_expr(&mut self, infix: &Infix, left: String, right: String) -> Object {
match infix {
Infix::Plus => Object::String(format!("{}{}", left, right)),
_ => Object::Error(String::from(format!(
Expand All @@ -262,26 +266,26 @@ impl Evaluator {
}
}

fn eval_literal(&mut self, literal: Literal) -> Object {
fn eval_literal(&mut self, literal: &Literal) -> Object {
match literal {
Literal::Int(value) => Object::Int(value),
Literal::Bool(value) => Object::Bool(value),
Literal::String(value) => Object::String(value),
Literal::Int(value) => Object::Int(*value),
Literal::Bool(value) => Object::Bool(*value),
Literal::String(value) => Object::String(value.clone()),
Literal::Array(objects) => self.eval_array_literal(objects),
Literal::Hash(pairs) => self.eval_hash_literal(pairs),
}
}

fn eval_array_literal(&mut self, objects: Vec<Expr>) -> Object {
fn eval_array_literal(&mut self, objects: &Vec<Expr>) -> Object {
Object::Array(
objects
.iter()
.map(|e| self.eval_expr(e.clone()).unwrap_or(Object::Null))
.map(|e| self.eval_expr(&e.clone()).unwrap_or(Object::Null))
.collect::<Vec<_>>(),
)
}

fn eval_hash_literal(&mut self, pairs: Vec<(Expr, Expr)>) -> Object {
fn eval_hash_literal(&mut self, pairs: &Vec<(Expr, Expr)>) -> Object {
let mut hash = HashMap::new();

for (key_expr, value_expr) in pairs {
Expand All @@ -303,9 +307,9 @@ impl Evaluator {

fn eval_if_expr(
&mut self,
cond: Expr,
consequence: BlockStmt,
alternative: Option<BlockStmt>,
cond: &Expr,
consequence: &BlockStmt,
alternative: &Option<BlockStmt>,
) -> Option<Object> {
let cond = match self.eval_expr(cond) {
Some(cond) => cond,
Expand All @@ -321,13 +325,35 @@ impl Evaluator {
}
}

fn eval_call_expr(&mut self, func: Box<Expr>, args: Vec<Expr>) -> Object {
fn eval_while_expr(
&mut self,
cond: &Expr,
consequence: &BlockStmt,
) -> Option<Object> {
let mut result: Option<Object> = None;

loop {
let cond_result = match self.eval_expr(cond) {
Some(cond) => cond,
None => break,
};
if !Self::is_truthy(cond_result.clone()) {
break;
}

result = self.eval_block_stmt(consequence);
}

return result;
}

fn eval_call_expr(&mut self, func: &Box<Expr>, args: &Vec<Expr>) -> Object {
let args = args
.iter()
.map(|e| self.eval_expr(e.clone()).unwrap_or(Object::Null))
.map(|e| self.eval_expr(e).unwrap_or(Object::Null))
.collect::<Vec<_>>();

let (params, body, env) = match self.eval_expr(*func) {
let (params, body, env) = match self.eval_expr(&*func) {
Some(Object::Func(params, body, env)) => (params, body, env),
Some(Object::Builtin(expect_param_num, f)) => {
if expect_param_num < 0 || expect_param_num == args.len() as i32 {
Expand Down Expand Up @@ -362,7 +388,7 @@ impl Evaluator {

self.env = Rc::new(RefCell::new(scoped_env));

let object = self.eval_block_stmt(body);
let object = self.eval_block_stmt(&body);

self.env = current_env;

Expand All @@ -383,7 +409,7 @@ mod tests {

fn eval(input: &str) -> Option<Object> {
Evaluator::new(Rc::new(RefCell::new(Env::from(new_builtins()))))
.eval(Parser::new(Lexer::new(input)).parse())
.eval(&Parser::new(Lexer::new(input)).parse())
}

#[test]
Expand Down Expand Up @@ -577,6 +603,20 @@ let two = "two";
}
}

#[test]
fn test_while_expr() {
let tests = vec![
("let i = 1; while (i < 3) { let i = i + 1 }; i;", Some(Object::Int(3))),
("赋能 i = 1; 闭环 (i < 3) { 赋能 i = i + 1 }; i;", Some(Object::Int(3))),
("闭环 (4 < 3) { 3 };", None),
("赋能 i = 1; 闭环 (i < 3) { 赋能 i = i+1; i}", Some(Object::Int(3))),
];

for (input, expect) in tests {
assert_eq!(expect, eval(input));
}
}

#[test]
fn test_return_stmt() {
let tests = vec![
Expand Down Expand Up @@ -606,6 +646,7 @@ if (10 > 1) {
let tests = vec![
("let a = 5; a;", Some(Object::Int(5))),
("let a = 5 * 5; a;", Some(Object::Int(25))),
("let a = 1; let a = 2; a;", Some(Object::Int(2))),
("let a = 5; let b = a; b;", Some(Object::Int(5))),
(
"let a = 5; let b = a; let c = a + b + 5; c;",
Expand Down
23 changes: 23 additions & 0 deletions src/formatter/mod.rs
Expand Up @@ -147,6 +147,10 @@ impl Formatter {
consequence,
alternative,
} => self.format_if_expr(cond, consequence, alternative),
Expr::While {
cond,
consequence,
} => self.format_while_expr(cond, consequence),
Expr::Func { params, body } => self.format_func_expr(params, body),
Expr::Call { func, args } => self.format_call_expr(func, args),
}
Expand Down Expand Up @@ -346,6 +350,25 @@ impl Formatter {
result
}

fn format_while_expr(
&mut self,
cond: Box<Expr>,
consequence: BlockStmt,
) -> String {
let cond_str = self.format_expr(*cond, Precedence::Lowest);
self.indent += 1;

let consequence_str = self.format_block_stmt(consequence);
let indent_str = self.indent_str(-1);
self.indent -= 1;

let result = format!(
"while ({}) {{\n{}\n{}}}",
cond_str, consequence_str, indent_str
);
result
}

fn format_func_expr(&mut self, params: Vec<Ident>, body: BlockStmt) -> String {
let mut params_str = String::new();

Expand Down
2 changes: 2 additions & 0 deletions src/lexer/mod.rs
Expand Up @@ -222,6 +222,7 @@ impl Lexer {
"true" => Token::Bool(true),
"false" => Token::Bool(false),
"if" => Token::If,
"while" => Token::While,
"else" => Token::Else,
"return" => Token::Return,
// PUA Aba-aba keywords
Expand All @@ -231,6 +232,7 @@ impl Lexer {
"三二五" => Token::Bool(false),
"细分" => Token::If,
"路径" => Token::Else,
"闭环" => Token::While,
"反哺" => Token::Return,
"对齐" => Token::Equal,
"联动" => Token::Plus,
Expand Down
25 changes: 25 additions & 0 deletions src/parser/mod.rs
Expand Up @@ -217,6 +217,7 @@ impl Parser {
Token::Bang | Token::Minus | Token::Plus => self.parse_prefix_expr(),
Token::Lparen => self.parse_grouped_expr(),
Token::If => self.parse_if_expr(),
Token::While => self.parse_while_expr(),
Token::Func => self.parse_func_expr(),
_ => {
self.error_no_prefix_parser();
Expand Down Expand Up @@ -469,6 +470,30 @@ impl Parser {
})
}

fn parse_while_expr(&mut self) -> Option<Expr> {
if !self.expect_next_token(Token::Lparen) {
return None;
}

self.bump();

let cond = match self.parse_expr(Precedence::Lowest) {
Some(expr) => expr,
None => return None,
};

if !self.expect_next_token(Token::Rparen) || !self.expect_next_token(Token::Lbrace) {
return None;
}

let consequence = self.parse_block_stmt();

Some(Expr::While {
cond: Box::new(cond),
consequence,
})
}

fn parse_func_expr(&mut self) -> Option<Expr> {
if !self.expect_next_token(Token::Lparen) {
return None;
Expand Down
1 change: 1 addition & 0 deletions src/token.rs
Expand Up @@ -14,6 +14,7 @@ pub enum Token {
Assign,
If,
Else,
While,

// Operators
Plus,
Expand Down

0 comments on commit d60eefa

Please sign in to comment.