Skip to content

Commit 2768608

Browse files
committed
core: tokenizer recognize extra whitespace/line terminators; create arguments object for constructors; throw TypeError for non-constructors; support spread assignment parsing
1 parent 0e0921e commit 2768608

File tree

4 files changed

+86
-6
lines changed

4 files changed

+86
-6
lines changed

src/core/eval.rs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2765,7 +2765,34 @@ fn evaluate_expr_assign<'gc>(
27652765
Err(EvalError::Js(raise_eval_error!("Cannot assign to property of non-object")))
27662766
}
27672767
}
2768-
_ => todo!("Assignment target not supported"),
2768+
_ => {
2769+
// Diagnostic: report the specific Expr variant of the unsupported assignment target
2770+
let variant = match target {
2771+
Expr::Var(_, _, _) => "Var",
2772+
Expr::Property(_, _) => "Property",
2773+
Expr::Index(_, _) => "Index",
2774+
Expr::Array(_) => "Array",
2775+
Expr::Object(_) => "Object",
2776+
Expr::Spread(_) => "Spread",
2777+
Expr::Call(_, _) => "Call",
2778+
Expr::New(_, _) => "New",
2779+
Expr::Function(_, _, _) => "Function",
2780+
Expr::ArrowFunction(_, _) => "ArrowFunction",
2781+
Expr::Assign(_, _) => "Assign",
2782+
Expr::Comma(_, _) => "Comma",
2783+
Expr::OptionalProperty(_, _) => "OptionalProperty",
2784+
Expr::OptionalIndex(_, _) => "OptionalIndex",
2785+
Expr::OptionalCall(_, _) => "OptionalCall",
2786+
Expr::TaggedTemplate(_, _, _) => "TaggedTemplate",
2787+
Expr::TemplateString(_) => "TemplateString",
2788+
Expr::GeneratorFunction(_, _, _) => "GeneratorFunction",
2789+
Expr::AsyncFunction(_, _, _) => "AsyncFunction",
2790+
Expr::AsyncArrowFunction(_, _) => "AsyncArrowFunction",
2791+
_ => "Other",
2792+
};
2793+
log::error!("Unsupported assignment target reached in evaluate_expr_assign: {}", variant);
2794+
Err(EvalError::Js(raise_eval_error!("Assignment target not supported")))
2795+
}
27692796
}
27702797
}
27712798

@@ -4897,7 +4924,32 @@ pub fn evaluate_expr<'gc>(mc: &MutationContext<'gc>, env: &JSObjectDataPtr<'gc>,
48974924
evaluate_expr(mc, env, left)?;
48984925
evaluate_expr(mc, env, right)
48994926
}
4900-
Expr::Assign(target, value_expr) => evaluate_expr_assign(mc, env, target, value_expr),
4927+
Expr::Assign(target, value_expr) => {
4928+
// Diagnostic: log the assignment target variant to help identify unsupported targets
4929+
let target_variant = match &**target {
4930+
Expr::Var(_, _, _) => "Var",
4931+
Expr::Property(_, _) => "Property",
4932+
Expr::Index(_, _) => "Index",
4933+
Expr::Spread(inner) => {
4934+
// log inner variant for better diagnostics
4935+
let inner_variant = match &**inner {
4936+
Expr::Array(_) => "Array",
4937+
Expr::Index(_, _) => "Index",
4938+
Expr::Property(_, _) => "Property",
4939+
Expr::Var(_, _, _) => "Var",
4940+
Expr::Call(_, _) => "Call",
4941+
_ => "Other",
4942+
};
4943+
log::debug!("evaluate_expr: Assign target is Spread with inner variant = {}", inner_variant);
4944+
"Spread"
4945+
}
4946+
Expr::Array(_) => "Array",
4947+
Expr::Object(_) => "Object",
4948+
_ => "Other",
4949+
};
4950+
log::debug!("evaluate_expr: Assign target variant = {}", target_variant);
4951+
evaluate_expr_assign(mc, env, target, value_expr)
4952+
}
49014953
Expr::AddAssign(target, value_expr) => evaluate_expr_add_assign(mc, env, target, value_expr),
49024954
Expr::SubAssign(target, value_expr) => evaluate_expr_sub_assign(mc, env, target, value_expr),
49034955
Expr::MulAssign(target, value_expr) => evaluate_expr_mul_assign(mc, env, target, value_expr),
@@ -7041,6 +7093,9 @@ fn evaluate_expr_new<'gc>(
70417093
_ => {}
70427094
}
70437095
}
7096+
7097+
crate::js_class::create_arguments_object(mc, &call_env, &eval_args)?;
7098+
70447099
let body_clone = cl.body.clone();
70457100
match evaluate_statements_with_labels(mc, &call_env, &body_clone, &[], &[])? {
70467101
ControlFlow::Return(Value::Object(obj)) => Ok(Value::Object(obj)),
@@ -7163,7 +7218,7 @@ fn evaluate_expr_new<'gc>(
71637218
Err(EvalError::Js(raise_type_error!("Not a constructor")))
71647219
}
71657220
}
7166-
_ => todo!("New expression with non-object constructor not implemented yet"),
7221+
_ => Err(EvalError::Js(raise_type_error!("Not a constructor"))),
71677222
}
71687223
}
71697224

src/core/parser.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2248,7 +2248,11 @@ fn parse_primary(tokens: &[TokenData], index: &mut usize, allow_call: bool) -> R
22482248
Expr::Decrement(Box::new(inner))
22492249
}
22502250
Token::Spread => {
2251-
let inner = parse_primary(tokens, index, true)?;
2251+
// Parse the inner expression as an AssignmentExpression so that
2252+
// constructs like `...target = source` are parsed as `Spread(Assign(...))`
2253+
// rather than `Assign(Spread(...))` which would make `Spread` the
2254+
// assignment target (invalid for assignment).
2255+
let inner = parse_assignment(tokens, index)?;
22522256
Expr::Spread(Box::new(inner))
22532257
}
22542258
Token::TemplateString(parts) => {

src/core/token.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,13 @@ pub fn tokenize(expr: &str) -> Result<Vec<TokenData>, JSError> {
217217
while i < chars.len() {
218218
let start_col = column;
219219
match chars[i] {
220-
' ' | '\t' | '\r' => {
220+
// Treat common whitespace characters (including VT, FF, NBSP) as whitespace
221+
' ' | '\t' | '\r' | '\u{000B}' | '\u{000C}' | '\u{00A0}' => {
221222
i += 1;
222223
column += 1;
223224
}
224-
'\n' => {
225+
// Line terminators: LF, LS (U+2028), PS (U+2029)
226+
'\n' | '\u{2028}' | '\u{2029}' => {
225227
tokens.push(TokenData {
226228
token: Token::LineTerminator,
227229
line,

src/js_class.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,20 @@ pub(crate) fn evaluate_this<'gc>(_mc: &MutationContext<'gc>, env: &JSObjectDataP
9090
Ok(Value::Object(last_seen))
9191
}
9292

93+
pub fn create_arguments_object<'gc>(
94+
mc: &MutationContext<'gc>,
95+
func_env: &JSObjectDataPtr<'gc>,
96+
evaluated_args: &[Value<'gc>],
97+
) -> Result<(), JSError> {
98+
let arguments_obj = crate::js_array::create_array(mc, func_env)?;
99+
crate::js_array::set_array_length(mc, &arguments_obj, evaluated_args.len())?;
100+
for (i, arg) in evaluated_args.iter().enumerate() {
101+
object_set_key_value(mc, &arguments_obj, i, arg.clone())?;
102+
}
103+
object_set_key_value(mc, func_env, "arguments", Value::Object(arguments_obj))?;
104+
Ok(())
105+
}
106+
93107
pub(crate) fn evaluate_new<'gc>(
94108
mc: &MutationContext<'gc>,
95109
env: &JSObjectDataPtr<'gc>,
@@ -167,6 +181,9 @@ pub(crate) fn evaluate_new<'gc>(
167181
Some(env),
168182
)?;
169183

184+
// Create the arguments object
185+
create_arguments_object(mc, &func_env, evaluated_args)?;
186+
170187
// Execute constructor body
171188
evaluate_statements(mc, &func_env, body)?;
172189

@@ -452,6 +469,8 @@ pub(crate) fn evaluate_new<'gc>(
452469
Some(env),
453470
)?;
454471

472+
create_arguments_object(mc, &func_env, evaluated_args)?;
473+
455474
// Execute function body
456475
evaluate_statements(mc, &func_env, body)?;
457476

0 commit comments

Comments
 (0)