Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: condition #6

Merged
merged 14 commits into from
Feb 20, 2023
Prev Previous commit
Next Next commit
feat: switch case
  • Loading branch information
echosoar committed Feb 17, 2023
commit 6465f54496c58d90c8909498ab06c028a91b512e
33 changes: 14 additions & 19 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::io;

use crate::ast_token::{get_token_keyword, Token, get_token_literal};
use crate::ast_node::{ Expression, NumberLiteral, StringLiteral, Statement, IdentifierLiteral, ExpressionStatement, PropertyAccessExpression, BinaryExpression, ConditionalExpression, CallExpression, Keywords, Parameter, BlockStatement, ReturnStatement, Declaration, PropertyAssignment, ObjectLiteral, ElementAccessExpression, FunctionDeclaration, PostfixUnaryExpression, PrefixUnaryExpression, AssignExpression, GroupExpression, VariableDeclaration, VariableDeclarationStatement, VariableFlag, ClassDeclaration, ClassMethodDeclaration, ArrayLiteral, ComputedPropertyName, IfStatement, ForStatement, BreakStatement, ContinueStatement, LabeledStatement, SwitchStatement, CaseBlocks, CaseClause};
use crate::ast_node::{ Expression, NumberLiteral, StringLiteral, Statement, IdentifierLiteral, ExpressionStatement, PropertyAccessExpression, BinaryExpression, ConditionalExpression, CallExpression, Keywords, Parameter, BlockStatement, ReturnStatement, Declaration, PropertyAssignment, ObjectLiteral, ElementAccessExpression, FunctionDeclaration, PostfixUnaryExpression, PrefixUnaryExpression, AssignExpression, GroupExpression, VariableDeclaration, VariableDeclarationStatement, VariableFlag, ClassDeclaration, ClassMethodDeclaration, ArrayLiteral, ComputedPropertyName, IfStatement, ForStatement, BreakStatement, ContinueStatement, LabeledStatement, SwitchStatement, CaseClause};
use crate::ast_utils::{get_hex_number_value, chars_to_string};
pub struct AST {
// 当前字符
Expand Down Expand Up @@ -232,9 +232,8 @@ impl AST{
self.check_token_and_next(Token::LeftParenthesis);
let condition = self.parse_expression();
self.check_token_and_next(Token::RightParenthesis);
println!("condition: {:?}", condition);
self.check_token_and_next(Token::LeftBrace);
let mut default = None;
let mut default_index: i32 = -1;
let mut clauses: Vec<CaseClause> = vec![];
loop {
if self.token == Token::EOF || self.token == Token::RightBrace {
Expand All @@ -247,10 +246,10 @@ impl AST{
};
// parse case
if self.token == Token::Default {
if let Some(_) = default {
if default_index != -1 {
// TODO: throw new error
} else {
is_default = true;
default_index = clauses.len() as i32;
self.next();
}
} else {
Expand All @@ -265,23 +264,15 @@ impl AST{
let statement = self.parse_statement();
clause.statements.push(statement);
}

if is_default {
default = Some(clause);
} else {
clauses.push(clause);
}
clauses.push(clause);
}

println!("clauses {:?}", clauses);

self.check_token_and_next(Token::RightBrace);
Statement::Switch(SwitchStatement {
condition,
blocks: CaseBlocks {
clauses,
default
}
clauses,
default_index
})
}

Expand All @@ -296,10 +287,9 @@ impl AST{
if self.token == Token::Var || self.token == Token::Let {
initializer = self.parse_variable_statement();
} else if self.token != Token::Semicolon {
initializer = Statement::Expression(ExpressionStatement { expression: self.parse_expression() })
initializer = Statement::Expression(ExpressionStatement { expression: self.parse_expression() });
self.check_token_and_next(Token::Semicolon);
}
println!("xxx");
let codition = self.parse_expression();
self.check_token_and_next(Token::Semicolon);
let incrementor = self.parse_expression();
Expand Down Expand Up @@ -729,7 +719,12 @@ impl AST{
self.read();
break;
},
_ => {}
_ => {
// EOF
if self.cur_char_index >= self.length {
break;
}
}
};
}
continue;
Expand Down
9 changes: 2 additions & 7 deletions src/ast_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,8 @@ pub struct IfStatement {
#[derive(Debug, Clone, PartialEq)]
pub struct SwitchStatement {
pub condition: Expression,
pub blocks: CaseBlocks
}

#[derive(Debug, Clone, PartialEq)]
pub struct CaseBlocks {
pub clauses: Vec<CaseClause>,
pub default: Option<CaseClause>
pub clauses: Vec<CaseClause>,
pub default_index: i32
}

#[derive(Debug, Clone, PartialEq)]
Expand Down
40 changes: 37 additions & 3 deletions src/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{rc::{Rc, Weak}, cell::RefCell, ops::Index};

use crate::{ast::Program, ast_node::{Statement, Declaration, ObjectLiteral, AssignExpression, CallContext, ArrayLiteral, ClassType, ForStatement, VariableFlag, PostfixUnaryExpression, IdentifierLiteral, PrefixUnaryExpression}, ast_node::{Expression, CallExpression, Keywords, BinaryExpression}, value::{Value, ValueInfo, CallStatementOptions}, scope::{Scope, get_value_and_scope}, ast_token::Token, builtins::{object::{Object, Property, create_object}, function::{create_function, get_function_this}, global::{new_global_this, get_global_object}, array::create_array}};
use crate::{ast::Program, ast_node::{Statement, Declaration, ObjectLiteral, AssignExpression, CallContext, ArrayLiteral, ClassType, ForStatement, VariableFlag, PostfixUnaryExpression, IdentifierLiteral, PrefixUnaryExpression, SwitchStatement, CaseClause}, ast_node::{Expression, CallExpression, Keywords, BinaryExpression}, value::{Value, ValueInfo, CallStatementOptions}, scope::{Scope, get_value_and_scope}, ast_token::Token, builtins::{object::{Object, Property, create_object}, function::{create_function, get_function_this}, global::{new_global_this, get_global_object}, array::create_array}};

use super::ast::AST;
pub struct Context {
Expand Down Expand Up @@ -87,7 +87,8 @@ impl Context {
},
Statement::Return(return_statement) => {
(*result_value) = self.execute_expression(&return_statement.expression);
(*last_statement_value) = result_value.clone()
(*last_statement_value) = result_value.clone();
(*interrupt) = Value::Interrupt(Token::Return, Expression::Unknown);
},
Statement::Function(_) => {
// skip, 因为函数声明前置了
Expand Down Expand Up @@ -125,6 +126,9 @@ impl Context {
Statement::While(for_statment) => {
self.execute_for(for_statment, result_value, last_statement_value, interrupt, call_options)
},
Statement::Switch(switch_statement) => {
self.execute_switch(switch_statement, result_value, last_statement_value, interrupt, call_options)
},
Statement::Block(block) => {
self.switch_scope(Some(Rc::clone(&self.cur_scope)));
let result = self.call_block(&vec![], &block.statements);
Expand Down Expand Up @@ -410,7 +414,6 @@ impl Context {
},
_ => {}
}
println!("new_value2: {:?}", new_value);
let value = Value::Number(new_value);
operand_info.set_value(value.clone());
value
Expand Down Expand Up @@ -524,6 +527,37 @@ impl Context {
self.close_scope();
}


// 执行循环
fn execute_switch(&mut self, switch_statment: &SwitchStatement, result_value: &mut Value, last_statement_value: &mut Value, interrupt: &mut Value, call_options: CallStatementOptions) {
let value = self.execute_expression(&switch_statment.condition);

let mut matched: i32 = switch_statment.default_index;
let clause_len = switch_statment.clauses.len();
for case_index in 0..clause_len {
if case_index as i32 == switch_statment.default_index {
continue;
}
let case = &switch_statment.clauses[case_index];
if let Some(condition) = &case.condition {
let case_value = self.execute_expression(condition);
if case_value.is_equal_to(&value, true) {
matched = case_index as i32;
}
}
}

for case_index in (matched as usize)..clause_len {
let case = &switch_statment.clauses[case_index];
let result = self.call_block(&vec![], &case.statements);
if let Value::Interrupt(token, _) = result.2 {
if token == Token::Break {
break;
}
}
}
}

fn new_object(&mut self, expression: &ObjectLiteral) -> Value {
// 获取 object 实例
let object = create_object(&self.global,ClassType::Array, None);
Expand Down
20 changes: 11 additions & 9 deletions tests/confitional_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,20 @@ fn run_if_else() {
fn run_switch_case() {
let mut jsi = JSI::new();
let result = jsi.run(String::from("\
let res;
switch('a') {
case 'a':
1;
res = 1;
break;
case 'b':
2;
res = 2;
break;
default:
3;
res = 3;
break;
}"));
assert_eq!(result , Value::Number(2f64));
}
res"));
assert_eq!(result , Value::Number(1f64));
}

#[test]
Expand All @@ -40,10 +42,10 @@ fn run_for() {
let result = jsi.run(String::from("\
let a = [];
let i;
// for(i = 0; i < 3; i++) {
// a.push(++i);
// }
// a.join(':')"));
for(i = 0; i < 3; i++) {
a.push(++i);
}
a.join(':')"));
assert_eq!(result , Value::String(String::from("1:3")));
}

Expand Down