Skip to content
Merged
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
20 changes: 18 additions & 2 deletions crates/perry-codegen-js/src/emit/exprs_more.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,32 @@ impl JsEmitter {
self.emit_expr(value);
self.output.push(')');
}
Expr::ArrayIndexOf { array, value } => {
Expr::ArrayIndexOf {
array,
value,
from_index,
} => {
self.emit_expr(array);
self.output.push_str(".indexOf(");
self.emit_expr(value);
if let Some(fi) = from_index {
self.output.push_str(", ");
self.emit_expr(fi);
}
self.output.push(')');
}
Expr::ArrayIncludes { array, value } => {
Expr::ArrayIncludes {
array,
value,
from_index,
} => {
self.emit_expr(array);
self.output.push_str(".includes(");
self.emit_expr(value);
if let Some(fi) = from_index {
self.output.push_str(", ");
self.emit_expr(fi);
}
self.output.push(')');
}
Expr::ArraySlice { array, start, end } => {
Expand Down
14 changes: 12 additions & 2 deletions crates/perry-codegen-wasm/src/emit/expr/arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,23 @@ impl<'a> FuncEmitCtx<'a> {
}));
self.emit_memcall(func, "array_join", 2);
}
Expr::ArrayIndexOf { array, value } => {
Expr::ArrayIndexOf {
array,
value,
from_index: _,
} => {
// NOTE: the wasm backend's array_index_of helper does not yet
// honor the optional fromIndex (#2804 covers the native path).
self.emit_frame_begin(func, 2);
self.emit_store_arg(func, 0, array);
self.emit_store_arg(func, 1, value);
self.emit_memcall(func, "array_index_of", 2);
}
Expr::ArrayIncludes { array, value } => {
Expr::ArrayIncludes {
array,
value,
from_index: _,
} => {
self.emit_frame_begin(func, 2);
self.emit_store_arg(func, 0, array);
self.emit_store_arg(func, 1, value);
Expand Down
14 changes: 13 additions & 1 deletion crates/perry-codegen-wasm/src/emit/string_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,9 +674,21 @@ impl WasmModuleEmitter {
}
self.intern_string(","); // default separator
}
Expr::ArrayIndexOf { array, value } | Expr::ArrayIncludes { array, value } => {
Expr::ArrayIndexOf {
array,
value,
from_index,
}
| Expr::ArrayIncludes {
array,
value,
from_index,
} => {
self.collect_strings_in_expr(array);
self.collect_strings_in_expr(value);
if let Some(fi) = from_index {
self.collect_strings_in_expr(fi);
}
}
Expr::ArrayMap { array, callback }
| Expr::ArrayFilter { array, callback }
Expand Down
14 changes: 10 additions & 4 deletions crates/perry-codegen/src/collectors/escape_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,11 +594,17 @@ pub fn check_escapes_in_expr(
check_escapes_in_expr(e, candidates, classes, escaped);
}
}
Expr::ArrayIncludes { array, value } | Expr::ArrayIndexOf { array, value } => {
check_escapes_in_expr(array, candidates, classes, escaped);
check_escapes_in_expr(value, candidates, classes, escaped);
Expr::ArrayIncludes {
array,
value,
from_index,
}
| Expr::ArrayIndexOf {
array,
value,
from_index,
}
Expr::ArrayLastIndexOf {
| Expr::ArrayLastIndexOf {
array,
value,
from_index,
Expand Down
14 changes: 10 additions & 4 deletions crates/perry-codegen/src/collectors/escape_news.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,11 +454,17 @@ fn collect_used_new_fields_in_expr(
collect_used_new_fields_in_expr(end, non_escaping_news, used);
}
}
Expr::ArrayIncludes { array, value } | Expr::ArrayIndexOf { array, value } => {
collect_used_new_fields_in_expr(array, non_escaping_news, used);
collect_used_new_fields_in_expr(value, non_escaping_news, used);
Expr::ArrayIncludes {
array,
value,
from_index,
}
| Expr::ArrayIndexOf {
array,
value,
from_index,
}
Expr::ArrayLastIndexOf {
| Expr::ArrayLastIndexOf {
array,
value,
from_index,
Expand Down
9 changes: 8 additions & 1 deletion crates/perry-codegen/src/collectors/i32_locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1285,9 +1285,16 @@ pub fn collect_localset_ids_in_expr_filtered(
walk(e, out);
}
}
Expr::ArrayIncludes { array, value } => {
Expr::ArrayIncludes {
array,
value,
from_index,
} => {
walk(array, out);
walk(value, out);
if let Some(fi) = from_index {
walk(fi, out);
}
}
Expr::Object(props) => {
for (_, v) in props {
Expand Down
18 changes: 13 additions & 5 deletions crates/perry-codegen/src/collectors/refs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,16 @@ pub fn collect_ref_ids_in_expr(e: &perry_hir::Expr, out: &mut HashSet<u32>) {
walk(e, out);
}
}
Expr::ArrayIncludes { array, value } => {
Expr::ArrayIncludes {
array,
value,
from_index,
} => {
walk(array, out);
walk(value, out);
if let Some(fi) = from_index {
walk(fi, out);
}
}
Expr::Object(props) => {
for (_, v) in props {
Expand Down Expand Up @@ -719,11 +726,12 @@ pub fn collect_ref_ids_in_expr(e: &perry_hir::Expr, out: &mut HashSet<u32>) {
out.insert(*array_id);
walk(source, out);
}
Expr::ArrayIndexOf { array, value } => {
walk(array, out);
walk(value, out);
Expr::ArrayIndexOf {
array,
value,
from_index,
}
Expr::ArrayLastIndexOf {
| Expr::ArrayLastIndexOf {
array,
value,
from_index,
Expand Down
19 changes: 17 additions & 2 deletions crates/perry-codegen/src/expr/instance_misc1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,9 +633,19 @@ pub(crate) fn lower(ctx: &mut FnCtx<'_>, expr: &Expr) -> Result<String> {
}

// -------- arr.includes(value) -> boolean --------
Expr::ArrayIncludes { array, value } => {
Expr::ArrayIncludes {
array,
value,
from_index,
} => {
let arr_box = lower_expr(ctx, array)?;
let v = lower_expr(ctx, value)?;
// #2804: optional fromIndex. has_from=1 + lowered index when
// present; otherwise has_from=0 with a placeholder DOUBLE (`v`).
let (from_box, has_from) = match from_index {
Some(fi) => (lower_expr(ctx, fi)?, "1"),
None => (v.clone(), "0"),
};
let blk = ctx.block();
let arr_handle = unbox_to_i64(blk, &arr_box);
// Use `js_array_includes_jsvalue` which does deep-value
Expand All @@ -645,7 +655,12 @@ pub(crate) fn lower(ctx: &mut FnCtx<'_>, expr: &Expr) -> Result<String> {
let i32_v = blk.call(
I32,
"js_array_includes_jsvalue",
&[(I64, &arr_handle), (DOUBLE, &v)],
&[
(I64, &arr_handle),
(DOUBLE, &v),
(DOUBLE, &from_box),
(I32, has_from),
],
);
// Convert i32 boolean to NaN-tagged TAG_TRUE/FALSE so
// console.log prints "true"/"false".
Expand Down
19 changes: 17 additions & 2 deletions crates/perry-codegen/src/expr/misc_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,15 +467,30 @@ pub(crate) fn lower(ctx: &mut FnCtx<'_>, expr: &Expr) -> Result<String> {
// match by content (handles SSO + heap-string mixed arrays).
// Mirrors the `includes` arm + the `lower_array_method::indexOf`
// arm.
Expr::ArrayIndexOf { array, value } => {
Expr::ArrayIndexOf {
array,
value,
from_index,
} => {
let arr_box = lower_expr(ctx, array)?;
let v = lower_expr(ctx, value)?;
// #2804: optional fromIndex. has_from=1 + lowered index when
// present; otherwise has_from=0 with a placeholder DOUBLE (`v`).
let (from_box, has_from) = match from_index {
Some(fi) => (lower_expr(ctx, fi)?, "1"),
None => (v.clone(), "0"),
};
let blk = ctx.block();
let arr_handle = unbox_to_i64(blk, &arr_box);
let i32_v = blk.call(
I32,
"js_array_indexOf_jsvalue",
&[(I64, &arr_handle), (DOUBLE, &v)],
&[
(I64, &arr_handle),
(DOUBLE, &v),
(DOUBLE, &from_box),
(I32, has_from),
],
);
Ok(blk.sitofp(I32, &i32_v, DOUBLE))
}
Expand Down
36 changes: 30 additions & 6 deletions crates/perry-codegen/src/lower_array_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,13 +410,20 @@ pub(crate) fn lower_array_method(
Ok(double_literal(f64::from_bits(crate::nanbox::TAG_UNDEFINED)))
}
"includes" => {
if args.len() != 1 {
if args.is_empty() || args.len() > 2 {
bail!(
"perry-codegen: Array.includes expects 1 arg, got {}",
"perry-codegen: Array.includes expects 1-2 args, got {}",
args.len()
);
}
let val_box = lower_expr(ctx, &args[0])?;
// #2804: optional fromIndex (2nd arg). has_from=1 + lowered index
// when present; otherwise has_from=0 with a placeholder DOUBLE.
let (from_box, has_from) = if args.len() == 2 {
(lower_expr(ctx, &args[1])?, "1")
} else {
(val_box.clone(), "0")
};
let blk = ctx.block();
let recv_handle = unbox_to_i64(blk, &recv_box);
// Use `js_array_includes_jsvalue` for deep equality so
Expand All @@ -427,7 +434,12 @@ pub(crate) fn lower_array_method(
let i32_v = blk.call(
I32,
"js_array_includes_jsvalue",
&[(I64, &recv_handle), (DOUBLE, &val_box)],
&[
(I64, &recv_handle),
(DOUBLE, &val_box),
(DOUBLE, &from_box),
(I32, has_from),
],
);
// Convert i32 boolean to NaN-boxed true/false
let bit = blk.icmp_ne(I32, &i32_v, "0");
Expand All @@ -441,13 +453,20 @@ pub(crate) fn lower_array_method(
Ok(blk.bitcast_i64_to_double(&tagged))
}
"indexOf" => {
if args.len() != 1 {
if args.is_empty() || args.len() > 2 {
bail!(
"perry-codegen: Array.indexOf expects 1 arg, got {}",
"perry-codegen: Array.indexOf expects 1-2 args, got {}",
args.len()
);
}
let val_box = lower_expr(ctx, &args[0])?;
// #2804: optional fromIndex (2nd arg). has_from=1 + lowered index
// when present; otherwise has_from=0 with a placeholder DOUBLE.
let (from_box, has_from) = if args.len() == 2 {
(lower_expr(ctx, &args[1])?, "1")
} else {
(val_box.clone(), "0")
};
let blk = ctx.block();
let recv_handle = unbox_to_i64(blk, &recv_box);
// Issue #214: route through `_jsvalue` so string elements
Expand All @@ -459,7 +478,12 @@ pub(crate) fn lower_array_method(
let i32_v = blk.call(
I32,
"js_array_indexOf_jsvalue",
&[(I64, &recv_handle), (DOUBLE, &val_box)],
&[
(I64, &recv_handle),
(DOUBLE, &val_box),
(DOUBLE, &from_box),
(I32, has_from),
],
);
Ok(blk.sitofp(I32, &i32_v, DOUBLE))
}
Expand Down
9 changes: 7 additions & 2 deletions crates/perry-codegen/src/runtime_decls/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -721,14 +721,19 @@ pub fn declare_phase_b_strings(module: &mut LlModule) {
module.declare_function("js_date_new_from_timestamp", DOUBLE, &[DOUBLE]);
module.declare_function("js_date_new_from_value", DOUBLE, &[DOUBLE]);
module.declare_function("js_array_indexOf_f64", I32, &[I64, DOUBLE]);
module.declare_function("js_array_indexOf_jsvalue", I32, &[I64, DOUBLE]);
// #2804: indexOf/includes carry an optional fromIndex (value, fromIndex, has_from).
module.declare_function("js_array_indexOf_jsvalue", I32, &[I64, DOUBLE, DOUBLE, I32]);
module.declare_function(
"js_array_last_index_of_jsvalue",
I32,
&[I64, DOUBLE, DOUBLE, I32],
);
module.declare_function("js_array_includes_f64", I32, &[I64, DOUBLE]);
module.declare_function("js_array_includes_jsvalue", I32, &[I64, DOUBLE]);
module.declare_function(
"js_array_includes_jsvalue",
I32,
&[I64, DOUBLE, DOUBLE, I32],
);
module.declare_function("js_map_size", I32, &[I64]);
module.declare_function("js_map_clear", VOID, &[I64]);
module.declare_function("js_set_clear", VOID, &[I64]);
Expand Down
2 changes: 1 addition & 1 deletion crates/perry-hir/src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ pub(crate) fn collect_assigned_locals_expr(expr: &Expr, assigned: &mut Vec<Local
Expr::ArrayPop(_array_id) | Expr::ArrayShift(_array_id) => {
// These modify the array but don't reallocate
}
Expr::ArrayIndexOf { array, value } | Expr::ArrayIncludes { array, value } => {
Expr::ArrayIndexOf { array, value, .. } | Expr::ArrayIncludes { array, value, .. } => {
collect_assigned_locals_expr(array, assigned);
collect_assigned_locals_expr(value, assigned);
}
Expand Down
6 changes: 4 additions & 2 deletions crates/perry-hir/src/ir/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1231,7 +1231,8 @@ pub enum Expr {
ArrayIndexOf {
array: Box<Expr>,
value: Box<Expr>,
}, // arr.indexOf(value) -> index
from_index: Option<Box<Expr>>,
}, // arr.indexOf(value, fromIndex?) -> index
ArrayLastIndexOf {
array: Box<Expr>,
value: Box<Expr>,
Expand All @@ -1240,7 +1241,8 @@ pub enum Expr {
ArrayIncludes {
array: Box<Expr>,
value: Box<Expr>,
}, // arr.includes(value) -> boolean
from_index: Option<Box<Expr>>,
}, // arr.includes(value, fromIndex?) -> boolean
ArraySlice {
array: Box<Expr>,
start: Box<Expr>,
Expand Down
14 changes: 13 additions & 1 deletion crates/perry-hir/src/js_transform/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,9 +1002,21 @@ pub fn transform_expr(
Expr::ArrayPush { value, .. } | Expr::ArrayUnshift { value, .. } | Expr::ArrayPushSpread { source: value, .. } => {
transform_expr(value, js_imports, extern_func_to_js, local_name_to_js, tracker);
}
Expr::ArrayIndexOf { array, value } | Expr::ArrayIncludes { array, value } => {
Expr::ArrayIndexOf {
array,
value,
from_index,
}
| Expr::ArrayIncludes {
array,
value,
from_index,
} => {
transform_expr(array, js_imports, extern_func_to_js, local_name_to_js, tracker);
transform_expr(value, js_imports, extern_func_to_js, local_name_to_js, tracker);
if let Some(fi) = from_index {
transform_expr(fi, js_imports, extern_func_to_js, local_name_to_js, tracker);
}
}
Expr::ArraySlice { array, start, end } => {
transform_expr(array, js_imports, extern_func_to_js, local_name_to_js, tracker);
Expand Down
Loading