Skip to content

Commit

Permalink
Extract the parser into a crate
Browse files Browse the repository at this point in the history
  • Loading branch information
jedel1043 committed Nov 5, 2022
1 parent e03e9dd commit a764b30
Show file tree
Hide file tree
Showing 124 changed files with 1,411 additions and 1,430 deletions.
20 changes: 20 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ members = [
"boa_cli",
"boa_engine",
"boa_ast",
"boa_parser",
"boa_gc",
"boa_interner",
"boa_profiler",
Expand Down Expand Up @@ -30,6 +31,7 @@ boa_profiler = { version = "0.16.0", path = "boa_profiler" }
boa_unicode = { version = "0.16.0", path = "boa_unicode" }
boa_macros = { version = "0.16.0", path = "boa_macros" }
boa_ast = { version = "0.16.0", path = "boa_ast" }
boa_parser = { version = "0.16.0", path = "boa_parser" }

[workspace.metadata.workspaces]
allow_branch = "main"
Expand Down
1 change: 1 addition & 0 deletions boa_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rust-version.workspace = true
boa_engine = { workspace = true, features = ["deser", "console"] }
boa_ast = { workspace = true, features = ["serde"]}
boa_interner.workspace = true
boa_parser.workspace = true
rustyline = "10.0.0"
rustyline-derive = "0.7.0"
clap = { version = "4.0.18", features = ["derive"] }
Expand Down
6 changes: 2 additions & 4 deletions boa_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,9 @@ fn parse_tokens<S>(src: S, context: &mut Context) -> Result<StatementList, Strin
where
S: AsRef<[u8]>,
{
use boa_engine::syntax::parser::Parser;

let src_bytes = src.as_ref();
Parser::new(src_bytes)
.parse_all(context)
boa_parser::Parser::new(src_bytes)
.parse_all(context.interner_mut())
.map_err(|e| format!("ParsingError: {e}"))
}

Expand Down
1 change: 1 addition & 0 deletions boa_engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ boa_gc.workspace = true
boa_profiler.workspace = true
boa_macros.workspace = true
boa_ast.workspace = true
boa_parser.workspace = true
gc = "0.4.1"
serde = { version = "1.0.147", features = ["derive", "rc"] }
serde_json = "1.0.87"
Expand Down
92 changes: 84 additions & 8 deletions boa_engine/src/builtins/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ use crate::{
error::JsNativeError,
object::FunctionBuilder,
property::Attribute,
Context, JsResult, JsValue,
Context, JsResult, JsString, JsValue,
};
use boa_ast::operations::{
contains, contains_arguments, top_level_var_declared_names, ContainsSymbol,
};
use boa_ast::operations::top_level_var_declared_names;
use boa_gc::Gc;
use boa_parser::Parser;
use boa_profiler::Profiler;

#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -68,6 +71,16 @@ impl Eval {
mut strict: bool,
context: &mut Context,
) -> JsResult<JsValue> {
#[derive(Debug, Default)]
#[allow(clippy::struct_excessive_bools)]
/// Flags used to throw early errors on invalid `eval` calls.
struct Flags {
in_function: bool,
in_method: bool,
in_derived_constructor: bool,
in_class_field_initializer: bool,
}

/// Possible actions that can be executed after exiting this function to restore the environment to its
/// original state.
enum EnvStackAction {
Expand All @@ -93,19 +106,82 @@ impl Eval {
debug_assert!(direct || !strict);

// 2. If Type(x) is not String, return x.
let Some(x) = x.as_string() else {
// TODO: rework parser to take an iterator of `u32` unicode codepoints
let Some(x) = x.as_string().map(JsString::to_std_string_escaped) else {
return Ok(x.clone());
};

// Because of implementation details the following code differs from the spec.
// TODO: rework parser to take an iterator of `u32` unicode codepoints

// Parse the script body and handle early errors (6 - 11)
let body = match context.parse_eval(x.to_std_string_escaped().as_bytes(), direct, strict) {
Ok(body) => body,
Err(e) => return Err(JsNativeError::syntax().with_message(e.to_string()).into()),
// 5. Perform ? HostEnsureCanCompileStrings(evalRealm).
let mut parser = Parser::new(x.as_bytes());
if strict {
parser.set_strict();
}
// 11. Perform the following substeps in an implementation-defined order, possibly interleaving parsing and error detection:
// a. Let script be ParseText(StringToCodePoints(x), Script).
// b. If script is a List of errors, throw a SyntaxError exception.
// c. If script Contains ScriptBody is false, return undefined.
// d. Let body be the ScriptBody of script.
let body = parser.parse_eval(direct, context.interner_mut())?;

// 6. Let inFunction be false.
// 7. Let inMethod be false.
// 8. Let inDerivedConstructor be false.
// 9. Let inClassFieldInitializer be false.
// a. Let thisEnvRec be GetThisEnvironment().
let flags = match context
.realm
.environments
.get_this_environment()
.as_function_slots()
{
// 10. If direct is true, then
// b. If thisEnvRec is a Function Environment Record, then
Some(function_env) if direct => {
let function_env = function_env.borrow();
// i. Let F be thisEnvRec.[[FunctionObject]].
let function_object = function_env.function_object().borrow();
Flags {
// ii. Set inFunction to true.
in_function: true,
// iii. Set inMethod to thisEnvRec.HasSuperBinding().
in_method: function_env.has_super_binding(),
// iv. If F.[[ConstructorKind]] is derived, set inDerivedConstructor to true.
in_derived_constructor: function_object
.as_function()
.expect("must be function object")
.is_derived_constructor(),
// TODO:
// v. Let classFieldInitializerName be F.[[ClassFieldInitializerName]].
// vi. If classFieldInitializerName is not empty, set inClassFieldInitializer to true.
in_class_field_initializer: false,
}
}
_ => Flags::default(),
};

if !flags.in_function && contains(&body, ContainsSymbol::NewTarget) {
return Err(JsNativeError::syntax()
.with_message("invalid `new.target` expression inside eval")
.into());
}
if !flags.in_method && contains(&body, ContainsSymbol::SuperProperty) {
return Err(JsNativeError::syntax()
.with_message("invalid `super` reference inside eval")
.into());
}
if !flags.in_derived_constructor && contains(&body, ContainsSymbol::SuperCall) {
return Err(JsNativeError::syntax()
.with_message("invalid `super` call inside eval")
.into());
}
if flags.in_class_field_initializer && contains_arguments(&body) {
return Err(JsNativeError::syntax()
.with_message("invalid `arguments` reference inside eval")
.into());
}

strict |= body.strict();

// Because our environment model does not map directly to the spec, this section looks very different.
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ use crate::{
property::{Attribute, PropertyDescriptor, PropertyKey},
string::utf16,
symbol::WellKnownSymbols,
syntax::Parser,
value::IntegerOrInfinity,
Context, JsResult, JsString, JsValue,
};
Expand All @@ -37,6 +36,7 @@ use boa_ast::{
};
use boa_gc::{self, custom_trace, Finalize, Gc, Trace};
use boa_interner::Sym;
use boa_parser::Parser;
use boa_profiler::Profiler;
use dyn_clone::DynClone;
use std::{
Expand Down
2 changes: 1 addition & 1 deletion boa_engine/src/builtins/regexp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ use crate::{
property::{Attribute, PropertyDescriptorBuilder},
string::{utf16, CodePoint},
symbol::WellKnownSymbols,
syntax::lexer::regex::RegExpFlags,
value::JsValue,
Context, JsResult, JsString,
};
use boa_parser::lexer::regex::RegExpFlags;
use boa_profiler::Profiler;
use regress::Regex;
use std::str::FromStr;
Expand Down
23 changes: 3 additions & 20 deletions boa_engine/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ use crate::{
object::{FunctionBuilder, GlobalPropertyMap, JsObject, ObjectData},
property::{Attribute, PropertyDescriptor, PropertyKey},
realm::Realm,
syntax::{parser::ParseError, Parser},
vm::{CallFrame, CodeBlock, FinallyReturn, GeneratorResumeKind, Vm},
JsResult, JsString, JsValue,
};

use boa_ast::StatementList;
use boa_gc::Gc;
use boa_interner::{Interner, Sym};
use boa_parser::{Error as ParseError, Parser};
use boa_profiler::Profiler;

#[cfg(feature = "intl")]
Expand Down Expand Up @@ -162,24 +162,7 @@ impl Context {
S: AsRef<[u8]>,
{
let mut parser = Parser::new(src.as_ref());
parser.parse_all(self)
}

/// Parse the given source text with eval specific handling.
pub(crate) fn parse_eval<S>(
&mut self,
src: S,
direct: bool,
strict: bool,
) -> Result<StatementList, ParseError>
where
S: AsRef<[u8]>,
{
let mut parser = Parser::new(src.as_ref());
if strict {
parser.set_strict();
}
parser.parse_eval(direct, self)
parser.parse_all(&mut self.interner)
}

/// `Call ( F, V [ , argumentsList ] )`
Expand Down Expand Up @@ -471,7 +454,7 @@ impl Context {
{
let main_timer = Profiler::global().start_event("Evaluation", "Main");

let statement_list = Parser::new(src.as_ref()).parse_all(self)?;
let statement_list = Parser::new(src.as_ref()).parse_all(&mut self.interner)?;

let code_block = self.compile(&statement_list)?;
let result = self.execute(code_block);
Expand Down
9 changes: 4 additions & 5 deletions boa_engine/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::{
object::JsObject,
object::ObjectData,
property::PropertyDescriptor,
syntax::parser,
Context, JsString, JsValue,
};
use boa_gc::{Finalize, Trace};
Expand Down Expand Up @@ -320,8 +319,8 @@ impl JsError {
}
}

impl From<parser::ParseError> for JsError {
fn from(err: parser::ParseError) -> Self {
impl From<boa_parser::Error> for JsError {
fn from(err: boa_parser::Error) -> Self {
Self::from(JsNativeError::from(err))
}
}
Expand Down Expand Up @@ -655,8 +654,8 @@ impl JsNativeError {
}
}

impl From<parser::ParseError> for JsNativeError {
fn from(err: parser::ParseError) -> Self {
impl From<boa_parser::Error> for JsNativeError {
fn from(err: boa_parser::Error) -> Self {
Self::syntax().with_message(err.to_string())
}
}
Expand Down
1 change: 0 additions & 1 deletion boa_engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ pub mod property;
pub mod realm;
pub mod string;
pub mod symbol;
pub mod syntax;
pub mod value;
pub mod vm;

Expand Down
8 changes: 0 additions & 8 deletions boa_engine/src/syntax/mod.rs

This file was deleted.

1 change: 1 addition & 0 deletions boa_examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ boa_engine = { workspace = true, features = ["console"] }
boa_ast.workspace = true
boa_interner.workspace = true
boa_gc.workspace = true
boa_parser.workspace = true
gc = "0.4.1"
5 changes: 3 additions & 2 deletions boa_examples/src/bin/commuter_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ use boa_ast::{
visitor::{VisitWith, VisitorMut},
Expression,
};
use boa_engine::{syntax::Parser, Context};
use boa_engine::Context;
use boa_interner::ToInternedString;
use boa_parser::Parser;
use core::ops::ControlFlow;
use std::{convert::Infallible, fs::File, io::BufReader};

Expand Down Expand Up @@ -69,7 +70,7 @@ fn main() {
));
let mut ctx = Context::default();

let mut statements = parser.parse_all(&mut ctx).unwrap();
let mut statements = parser.parse_all(ctx.interner_mut()).unwrap();

let mut visitor = CommutorVisitor::default();

Expand Down
5 changes: 3 additions & 2 deletions boa_examples/src/bin/symbol_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
// which mutates the AST.

use boa_ast::visitor::Visitor;
use boa_engine::{syntax::Parser, Context};
use boa_engine::Context;
use boa_interner::Sym;
use boa_parser::Parser;
use core::ops::ControlFlow;
use std::{collections::HashSet, convert::Infallible, fs::File, io::BufReader};

Expand All @@ -28,7 +29,7 @@ fn main() {
));
let mut ctx = Context::default();

let statements = parser.parse_all(&mut ctx).unwrap();
let statements = parser.parse_all(ctx.interner_mut()).unwrap();

let mut visitor = SymbolVisitor::default();

Expand Down
Loading

0 comments on commit a764b30

Please sign in to comment.