Skip to content

Commit

Permalink
Feat/throw error (#9)
Browse files Browse the repository at this point in the history
* feat: throw value

* feat: test262
  • Loading branch information
echosoar authored Mar 16, 2023
1 parent 4456240 commit 881d1a1
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 28 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
.test
.test
262_result.json
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "tests/test262"]
path = tests/test262
[submodule "test262"]
path = test262
url = [email protected]:tc39/test262.git
9 changes: 6 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
## JSI

JSI is a JavaScript Interpreter written in Rust.
---

<img src="https://img.shields.io/badge/Test262-1235/48876-brightgreen.svg" alt="test262 passed" />

<img src="https://img.shields.io/badge/Test262-1316/48876-brightgreen.svg" alt="test262 passed" />

---
### Usage
Expand Down Expand Up @@ -33,10 +34,12 @@ assert_eq!(result , Value::String(String::from("2:4")));
```

### Development
+ git submodule

+ git submodule `git submodule update --init --recursive`
+ test262 `RUST_MIN_STACK=8388608 cargo test --package jsi --test test262_test -- test_all_262 --exact --nocapture`

### Refs

+ Ecma Standard: https://tc39.es/ecma262/multipage/#sec-intro
+ Test262: https://github.com/tc39/test262

Expand Down
15 changes: 13 additions & 2 deletions src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// AST
// mod super::token::TokenKeywords;
use std::{io, fmt};
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, CaseClause, NewExpression, TryCatchStatement, CatchClause};
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, NewExpression, TryCatchStatement, CatchClause, ThrowStatement};
use crate::ast_utils::{get_hex_number_value, chars_to_string};
use crate::error::{JSIResult, JSIError, JSIErrorType};
pub struct AST {
Expand Down Expand Up @@ -127,6 +127,9 @@ impl AST{
Token::Try => {
self.parse_try_catch_statment()
},
Token::Throw => {
self.parse_throw_statement()
},
Token::LeftBrace => {
// block
self.parse_block_statement()
Expand Down Expand Up @@ -517,6 +520,14 @@ impl AST{
})
}

fn parse_throw_statement(&mut self) -> JSIResult<Statement> {
self.check_token_and_next(Token::Throw)?;
let expression = self.parse_expression()?;
Ok(Statement::Throw(ThrowStatement {
expression
}))
}

fn parse_try_catch_statment(&mut self) -> JSIResult<Statement> {
self.check_token_and_next(Token::Try)?;

Expand Down
6 changes: 6 additions & 0 deletions src/ast_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub enum Statement {
Label(LabeledStatement),
Return(ReturnStatement),
Switch(SwitchStatement),
Throw(ThrowStatement),
Try(TryCatchStatement),
Unknown, // 未知
Var(VariableDeclarationStatement),
Expand Down Expand Up @@ -168,6 +169,11 @@ pub struct ForStatement {
}


#[derive(Debug, Clone, PartialEq)]
pub struct ThrowStatement {
pub expression: Expression
}

#[derive(Debug, Clone, PartialEq)]
pub struct TryCatchStatement {
pub body: BlockStatement,
Expand Down
16 changes: 11 additions & 5 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};

use crate::{ast::Program, ast_node::{Statement, Declaration, ObjectLiteral, AssignExpression, CallContext, ArrayLiteral, ClassType, ForStatement, VariableFlag, PostfixUnaryExpression, IdentifierLiteral, PrefixUnaryExpression, SwitchStatement}, ast_node::{Expression, CallExpression, Keywords, BinaryExpression, NewExpression}, 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, get_global_object_by_name, IS_GLOABL_OBJECT}, array::create_array}, error::{JSIResult, JSIError, JSIErrorType}, constants::{GLOBAL_ERROR_NAME, GLOBAL_BOOLEAN_NAME, GLOBAL_STRING_NAME, GLOBAL_NUMBER_NAME, GLOBAL_OBJECT_NAME_LIST}};
use crate::{ast::Program, ast_node::{Statement, Declaration, ObjectLiteral, AssignExpression, CallContext, ArrayLiteral, ClassType, ForStatement, VariableFlag, PostfixUnaryExpression, IdentifierLiteral, PrefixUnaryExpression, SwitchStatement}, ast_node::{Expression, CallExpression, Keywords, BinaryExpression, NewExpression}, 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, IS_GLOABL_OBJECT}, array::create_array}, error::{JSIResult, JSIError, JSIErrorType}, constants::{GLOBAL_OBJECT_NAME_LIST}};


use super::ast::AST;
Expand Down Expand Up @@ -161,6 +161,12 @@ impl Context {

Ok(true)
},
Statement::Throw(throw) => {
let throw_value = self.execute_expression(&throw.expression)?;
let mut err = JSIError::new(JSIErrorType::Unknown, format!(""), 0, 0);
err.set_value(throw_value);
Err(err)
},
Statement::Block(block) => {
self.switch_scope(Some(Rc::clone(&self.cur_scope)));
let result = self.call_block(&vec![], &block.statements)?;
Expand Down Expand Up @@ -632,7 +638,7 @@ impl Context {


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

let mut matched: i32 = switch_statment.default_index;
Expand Down Expand Up @@ -710,7 +716,7 @@ impl Context {
this: weak,
reference: None,
};
Object::call(call_ctx, String::from("push"), arguments);
Object::call(call_ctx, String::from("push"), arguments)?;
}
Ok(array)
}
Expand Down Expand Up @@ -818,7 +824,7 @@ impl Context {
}

// 获取当前调用栈
fn get_current_stack() {
// fn get_current_stack() {

}
// }
}
9 changes: 9 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct JSIError {
pub message: String,
pub line: i32,
pub column: i32,
pub value: Option<Value>
}

impl JSIError {
Expand All @@ -32,10 +33,14 @@ impl JSIError {
message,
line,
column,
value: None
}
}

pub fn to_error_object(&self, global: &Rc<RefCell<Object>>) -> Rc<RefCell<Object>> {
if let Some(value) = &self.value {
return value.to_object(global);
}
let new_error = create_error(global, Value::String(self.message.clone()));
// TODO: set error line/stack
let obj = if let Value::Object(obj) = new_error {
Expand All @@ -45,4 +50,8 @@ impl JSIError {
}.unwrap();
return obj;
}

pub fn set_value(&mut self, value: Value) {
self.value = Some(value);
}
}
1 change: 1 addition & 0 deletions test262
Submodule test262 added at 9704d7
13 changes: 13 additions & 0 deletions tests/error_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,17 @@ fn run_read_properties_of_null_error_catch() {
}
")).unwrap();
assert_eq!(result , Value::String(String::from("Cannot read properties of null (reading 'a')")));
}

#[test]
fn run_throw_error_catch() {
let mut jsi = JSI::new();
let result = jsi.run(String::from("\
try {
throw {a: 'abc'}
} catch (obj) {
obj.a
}
")).unwrap();
assert_eq!(result , Value::String(String::from("abc")));
}
1 change: 0 additions & 1 deletion tests/test262
Submodule test262 deleted from 2c599b
31 changes: 17 additions & 14 deletions tests/test262_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl Test262Dir {
let result = panic::catch_unwind(|| {
let mut jsi = JSI::new();
// println!("run: {:?}", code);
let result = jsi.run(format!("{};{}", preload_code, file.code));
let result = jsi.run(format!("{}\n{}", preload_code, file.code));
// println!("result: {:?}", result);
if let Ok(_) = result {
return true;
Expand Down Expand Up @@ -125,19 +125,22 @@ impl Test262DirResult {
}
}


fn load_harness(path: &str) -> String {
let mut file = File::open(format!("test262/{}", path)).unwrap();
let mut code = String::new();
file.read_to_string(&mut code).unwrap();
return code;
}

#[test]
fn test_all_262() {
let mut test262 = Test262Dir::new(String::from("base"), String::from("tests/test262/test"));
test262.run("");
let serialized_result = serde_json::to_string_pretty(&test262.result).unwrap();
let file_name = ".test/262_result.json";
let mut file = File::create(file_name).unwrap();
file.write_all(serialized_result.as_bytes()).unwrap();
println!("result: {:?}/{:?}", test262.passed, test262.cases)
let prelaod = format!("{}\n", load_harness("harness/assert.js"));
let mut test262 = Test262Dir::new(String::from("base"), String::from("test262/test"));
test262.run(prelaod.as_str());
let serialized_result = serde_json::to_string_pretty(&test262.result).unwrap();
let file_name = "./262_result.json";
let mut file = File::create(file_name).unwrap();
file.write_all(serialized_result.as_bytes()).unwrap();
println!("result: {:?}/{:?}", test262.passed, test262.cases)
}
/*
装载一些测试工具 harness
+ harness/assert.js
+ harness/sta.js
*/

0 comments on commit 881d1a1

Please sign in to comment.