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

[Merged by Bors] - Create Source to abstract JS code sources #2579

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

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

21 changes: 10 additions & 11 deletions boa_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ use boa_engine::{
context::ContextBuilder,
job::{JobQueue, NativeJob},
vm::flowgraph::{Direction, Graph},
Context, JsResult,
Context, JsResult, Source,
};
use clap::{Parser, ValueEnum, ValueHint};
use colored::{Color, Colorize};
Expand Down Expand Up @@ -189,23 +189,22 @@ enum FlowgraphDirection {
///
/// Returns a error of type String with a message,
/// if the token stream has a parsing error.
fn parse_tokens<S>(src: S, context: &mut Context<'_>) -> Result<StatementList, String>
fn parse_tokens<S>(src: &S, context: &mut Context<'_>) -> Result<StatementList, String>
where
S: AsRef<[u8]>,
S: AsRef<[u8]> + ?Sized,
{
let src_bytes = src.as_ref();
boa_parser::Parser::new(src_bytes)
boa_parser::Parser::new(Source::from_bytes(&src))
.parse_all(context.interner_mut())
.map_err(|e| format!("ParsingError: {e}"))
.map_err(|e| format!("Uncaught SyntaxError: {e}"))
}

/// Dumps the AST to stdout with format controlled by the given arguments.
///
/// Returns a error of type String with a error message,
/// if the source has a syntax or parsing error.
fn dump<S>(src: S, args: &Opt, context: &mut Context<'_>) -> Result<(), String>
fn dump<S>(src: &S, args: &Opt, context: &mut Context<'_>) -> Result<(), String>
where
S: AsRef<[u8]>,
S: AsRef<[u8]> + ?Sized,
{
if let Some(ref arg) = args.dump_ast {
let ast = parse_tokens(src, context)?;
Expand Down Expand Up @@ -233,7 +232,7 @@ fn generate_flowgraph(
format: FlowgraphFormat,
direction: Option<FlowgraphDirection>,
) -> JsResult<String> {
let ast = context.parse(src)?;
let ast = context.parse(Source::from_bytes(src))?;
let code = context.compile(&ast)?;

let direction = match direction {
Expand Down Expand Up @@ -279,7 +278,7 @@ fn main() -> Result<(), io::Error> {
Err(v) => eprintln!("Uncaught {v}"),
}
} else {
match context.eval(&buffer) {
match context.eval(Source::from_bytes(&buffer)) {
Ok(v) => println!("{}", v.display()),
Err(v) => eprintln!("Uncaught {v}"),
}
Expand Down Expand Up @@ -336,7 +335,7 @@ fn main() -> Result<(), io::Error> {
Err(v) => eprintln!("Uncaught {v}"),
}
} else {
match context.eval(line.trim_end()) {
match context.eval(Source::from_bytes(line.trim_end())) {
Ok(v) => {
println!("{}", v.display());
}
Expand Down
8 changes: 4 additions & 4 deletions boa_engine/benches/full.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Benchmarks of the whole execution engine in Boa.

use boa_engine::{realm::Realm, Context};
use boa_engine::{realm::Realm, Context, Source};
use criterion::{criterion_group, criterion_main, Criterion};
use std::hint::black_box;

Expand All @@ -23,7 +23,7 @@ macro_rules! full_benchmarks {
static CODE: &str = include_str!(concat!("bench_scripts/", stringify!($name), ".js"));
let mut context = Context::default();
c.bench_function(concat!($id, " (Parser)"), move |b| {
b.iter(|| context.parse(black_box(CODE)))
b.iter(|| context.parse(black_box(Source::from_bytes(CODE))))
});
}
)*
Expand All @@ -33,7 +33,7 @@ macro_rules! full_benchmarks {
{
static CODE: &str = include_str!(concat!("bench_scripts/", stringify!($name), ".js"));
let mut context = Context::default();
let statement_list = context.parse(CODE).expect("parsing failed");
let statement_list = context.parse(Source::from_bytes(CODE)).expect("parsing failed");
c.bench_function(concat!($id, " (Compiler)"), move |b| {
b.iter(|| {
context.compile(black_box(&statement_list))
Expand All @@ -47,7 +47,7 @@ macro_rules! full_benchmarks {
{
static CODE: &str = include_str!(concat!("bench_scripts/", stringify!($name), ".js"));
let mut context = Context::default();
let statement_list = context.parse(CODE).expect("parsing failed");
let statement_list = context.parse(Source::from_bytes(CODE)).expect("parsing failed");
let code_block = context.compile(&statement_list).unwrap();
c.bench_function(concat!($id, " (Execution)"), move |b| {
b.iter(|| {
Expand Down
109 changes: 78 additions & 31 deletions boa_engine/src/builtins/array/tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use boa_parser::Source;

use super::Array;
use crate::builtins::Number;
use crate::{forward, Context, JsValue};
Expand All @@ -10,60 +12,85 @@ fn is_array() {
var new_arr = new Array();
var many = ["a", "b", "c"];
"#;
context.eval(init).unwrap();
context.eval(Source::from_bytes(init)).unwrap();
assert_eq!(
context.eval("Array.isArray(empty)").unwrap(),
context
.eval(Source::from_bytes("Array.isArray(empty)"))
.unwrap(),
JsValue::new(true)
);
assert_eq!(
context.eval("Array.isArray(new_arr)").unwrap(),
context
.eval(Source::from_bytes("Array.isArray(new_arr)"))
.unwrap(),
JsValue::new(true)
);
assert_eq!(
context.eval("Array.isArray(many)").unwrap(),
context
.eval(Source::from_bytes("Array.isArray(many)"))
.unwrap(),
JsValue::new(true)
);
assert_eq!(
context.eval("Array.isArray([1, 2, 3])").unwrap(),
context
.eval(Source::from_bytes("Array.isArray([1, 2, 3])"))
.unwrap(),
JsValue::new(true)
);
assert_eq!(
context.eval("Array.isArray([])").unwrap(),
context
.eval(Source::from_bytes("Array.isArray([])"))
.unwrap(),
JsValue::new(true)
);
assert_eq!(
context.eval("Array.isArray({})").unwrap(),
context
.eval(Source::from_bytes("Array.isArray({})"))
.unwrap(),
JsValue::new(false)
);
// assert_eq!(context.eval("Array.isArray(new Array)"), "true");
assert_eq!(
context.eval("Array.isArray()").unwrap(),
context
.eval(Source::from_bytes("Array.isArray(new Array)"))
.unwrap(),
JsValue::new(true)
);
assert_eq!(
context.eval(Source::from_bytes("Array.isArray()")).unwrap(),
JsValue::new(false)
);
assert_eq!(
context
.eval("Array.isArray({ constructor: Array })")
.eval(Source::from_bytes("Array.isArray({ constructor: Array })"))
.unwrap(),
JsValue::new(false)
);
assert_eq!(
context
.eval("Array.isArray({ push: Array.prototype.push, concat: Array.prototype.concat })")
.eval(Source::from_bytes(
"Array.isArray({ push: Array.prototype.push, concat: Array.prototype.concat })"
))
.unwrap(),
JsValue::new(false)
);
assert_eq!(
context.eval("Array.isArray(17)").unwrap(),
context
.eval(Source::from_bytes("Array.isArray(17)"))
.unwrap(),
JsValue::new(false)
);
assert_eq!(
context
.eval("Array.isArray({ __proto__: Array.prototype })")
.eval(Source::from_bytes(
"Array.isArray({ __proto__: Array.prototype })"
))
.unwrap(),
JsValue::new(false)
);
assert_eq!(
context.eval("Array.isArray({ length: 0 })").unwrap(),
context
.eval(Source::from_bytes("Array.isArray({ length: 0 })"))
.unwrap(),
JsValue::new(false)
);
}
Expand All @@ -73,48 +100,68 @@ fn of() {
let mut context = Context::default();
assert_eq!(
context
.eval("Array.of(1, 2, 3)")
.eval(Source::from_bytes("Array.of(1, 2, 3)"))
.unwrap()
.to_string(&mut context)
.unwrap(),
context
.eval("[1, 2, 3]")
.eval(Source::from_bytes("[1, 2, 3]"))
.unwrap()
.to_string(&mut context)
.unwrap()
);
assert_eq!(
context
.eval("Array.of(1, 'a', [], undefined, null)")
.eval(Source::from_bytes("Array.of(1, 'a', [], undefined, null)"))
.unwrap()
.to_string(&mut context)
.unwrap(),
context
.eval("[1, 'a', [], undefined, null]")
.eval(Source::from_bytes("[1, 'a', [], undefined, null]"))
.unwrap()
.to_string(&mut context)
.unwrap()
);
assert_eq!(
context
.eval("Array.of()")
.eval(Source::from_bytes("Array.of()"))
.unwrap()
.to_string(&mut context)
.unwrap(),
context.eval("[]").unwrap().to_string(&mut context).unwrap()
context
.eval(Source::from_bytes("[]"))
.unwrap()
.to_string(&mut context)
.unwrap()
);

context
.eval(r#"let a = Array.of.call(Date, "a", undefined, 3);"#)
.eval(Source::from_bytes(
r#"let a = Array.of.call(Date, "a", undefined, 3);"#,
))
.unwrap();
assert_eq!(
context.eval("a instanceof Date").unwrap(),
context
.eval(Source::from_bytes("a instanceof Date"))
.unwrap(),
JsValue::new(true)
);
assert_eq!(context.eval("a[0]").unwrap(), JsValue::new("a"));
assert_eq!(context.eval("a[1]").unwrap(), JsValue::undefined());
assert_eq!(context.eval("a[2]").unwrap(), JsValue::new(3));
assert_eq!(context.eval("a.length").unwrap(), JsValue::new(3));
assert_eq!(
context.eval(Source::from_bytes("a[0]")).unwrap(),
JsValue::new("a")
);
assert_eq!(
context.eval(Source::from_bytes("a[1]")).unwrap(),
JsValue::undefined()
);
assert_eq!(
context.eval(Source::from_bytes("a[2]")).unwrap(),
JsValue::new(3)
);
assert_eq!(
context.eval(Source::from_bytes("a.length")).unwrap(),
JsValue::new(3)
);
}

#[test]
Expand All @@ -124,31 +171,31 @@ fn concat() {
var empty = [];
var one = [1];
"#;
context.eval(init).unwrap();
context.eval(Source::from_bytes(init)).unwrap();
// Empty ++ Empty
let ee = context
.eval("empty.concat(empty)")
.eval(Source::from_bytes("empty.concat(empty)"))
.unwrap()
.display()
.to_string();
assert_eq!(ee, "[]");
// Empty ++ NonEmpty
let en = context
.eval("empty.concat(one)")
.eval(Source::from_bytes("empty.concat(one)"))
.unwrap()
.display()
.to_string();
assert_eq!(en, "[ 1 ]");
// NonEmpty ++ Empty
let ne = context
.eval("one.concat(empty)")
.eval(Source::from_bytes("one.concat(empty)"))
.unwrap()
.display()
.to_string();
assert_eq!(ne, "[ 1 ]");
// NonEmpty ++ NonEmpty
let nn = context
.eval("one.concat(one)")
.eval(Source::from_bytes("one.concat(one)"))
.unwrap()
.display()
.to_string();
Expand Down
4 changes: 2 additions & 2 deletions boa_engine/src/builtins/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use boa_ast::operations::{
contains, contains_arguments, top_level_var_declared_names, ContainsSymbol,
};
use boa_gc::Gc;
use boa_parser::Parser;
use boa_parser::{Parser, Source};
use boa_profiler::Profiler;

#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -124,7 +124,7 @@ impl Eval {
// 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 mut parser = Parser::new(x.as_bytes());
let mut parser = Parser::new(Source::from_bytes(&x));
if strict {
parser.set_strict();
}
Expand Down
25 changes: 13 additions & 12 deletions boa_engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use boa_ast::{
};
use boa_gc::{self, custom_trace, Finalize, Gc, Trace};
use boa_interner::Sym;
use boa_parser::Parser;
use boa_parser::{Parser, Source};
use boa_profiler::Profiler;
use tap::{Conv, Pipe};

Expand Down Expand Up @@ -512,16 +512,17 @@ impl BuiltInFunctionObject {
parameters.push(u16::from(b')'));

// TODO: make parser generic to u32 iterators
let parameters = match Parser::new(String::from_utf16_lossy(&parameters).as_bytes())
.parse_formal_parameters(context.interner_mut(), generator, r#async)
{
Ok(parameters) => parameters,
Err(e) => {
return Err(JsNativeError::syntax()
.with_message(format!("failed to parse function parameters: {e}"))
.into())
}
};
let parameters =
match Parser::new(Source::from_bytes(&String::from_utf16_lossy(&parameters)))
.parse_formal_parameters(context.interner_mut(), generator, r#async)
{
Ok(parameters) => parameters,
Err(e) => {
return Err(JsNativeError::syntax()
.with_message(format!("failed to parse function parameters: {e}"))
.into())
}
};

if generator && contains(&parameters, ContainsSymbol::YieldExpression) {
return Err(JsNativeError::syntax().with_message(
Expand Down Expand Up @@ -549,7 +550,7 @@ impl BuiltInFunctionObject {
let body_arg = body_arg.to_string(context)?;

// TODO: make parser generic to u32 iterators
let body = match Parser::new(body_arg.to_std_string_escaped().as_bytes())
let body = match Parser::new(Source::from_bytes(&body_arg.to_std_string_escaped()))
.parse_function_body(context.interner_mut(), generator, r#async)
{
Ok(statement_list) => statement_list,
Expand Down
Loading