@@ -838,6 +838,7 @@ function compile_call(ctx::JSCompilationContext, expr::Expr)
838838 if resolved_fn === Base. getproperty && length (args) >= 3
839839 mod_arg = args[2 ]
840840 field_arg = args[3 ]
841+ # Check if first arg is a Module and second is a QuoteNode(:name)
841842 mod_val = nothing
842843 if mod_arg isa GlobalRef
843844 mod_val = try getfield (mod_arg. mod, mod_arg. name) catch ; nothing end
@@ -848,6 +849,7 @@ function compile_call(ctx::JSCompilationContext, expr::Expr)
848849 end
849850 end
850851 if mod_val isa Module
852+ # Suppress — the result will be used as a callee and matched by package registry
851853 return " "
852854 end
853855 end
@@ -874,7 +876,17 @@ function compile_call(ctx::JSCompilationContext, expr::Expr)
874876 end
875877 end
876878 # Array indexing: arr[i] → arr[i-1]
879+ # Range indexing: arr[a:b] → arr.slice(a-1, b)
877880 if length (call_args) == 2
881+ idx_arg = args[3 ] # The index argument (before compilation)
882+ idx_type = nothing
883+ if idx_arg isa Core. SSAValue
884+ idx_type = try ctx. code_info. ssavaluetypes[idx_arg. id] catch ; nothing end
885+ end
886+ # Check if index is a range (UnitRange) → slice
887+ if idx_type != = nothing && idx_type isa DataType && idx_type <: AbstractRange
888+ return " $(call_args[1 ]) .slice(($(call_args[2 ]) ).start-1,($(call_args[2 ]) ).stop)"
889+ end
878890 return " $(call_args[1 ]) [($(call_args[2 ]) ) - 1]"
879891 end
880892 return " []"
@@ -984,6 +996,92 @@ function compile_call(ctx::JSCompilationContext, expr::Expr)
984996 end
985997 end
986998
999+ # ─── String operations (by name) ───
1000+ if fn_name == " lowercase"
1001+ return " $(call_args[1 ]) .toLowerCase()"
1002+ end
1003+ if fn_name == " uppercase"
1004+ return " $(call_args[1 ]) .toUpperCase()"
1005+ end
1006+ if fn_name == " strip"
1007+ return " $(call_args[1 ]) .trim()"
1008+ end
1009+ if fn_name == " contains" && length (call_args) >= 2
1010+ # Julia: contains(haystack, needle) → haystack.includes(needle)
1011+ return " $(call_args[1 ]) .includes($(call_args[2 ]) )"
1012+ end
1013+ if fn_name == " occursin" && length (call_args) >= 2
1014+ # Julia: occursin(needle, haystack) → haystack.includes(needle)
1015+ return " $(call_args[2 ]) .includes($(call_args[1 ]) )"
1016+ end
1017+ if fn_name == " startswith" && length (call_args) >= 2
1018+ return " $(call_args[1 ]) .startsWith($(call_args[2 ]) )"
1019+ end
1020+ if fn_name == " endswith" && length (call_args) >= 2
1021+ return " $(call_args[1 ]) .endsWith($(call_args[2 ]) )"
1022+ end
1023+ if fn_name == " split" && length (call_args) >= 2
1024+ return " $(call_args[1 ]) .split($(call_args[2 ]) )"
1025+ end
1026+ if fn_name == " join" && length (call_args) >= 2
1027+ return " $(call_args[1 ]) .join($(call_args[2 ]) )"
1028+ end
1029+
1030+ # ─── Array operations (by name) ───
1031+ if fn_name == " sort" && length (call_args) >= 1
1032+ return " $(call_args[1 ]) .slice().sort()"
1033+ end
1034+ if fn_name == " copy" && length (call_args) >= 1
1035+ return " $(call_args[1 ]) .slice()"
1036+ end
1037+ if fn_name == " reverse" && length (call_args) >= 1
1038+ return " [...$(call_args[1 ]) ].reverse()"
1039+ end
1040+
1041+ # ─── Higher-order (by name) ───
1042+ if fn_name == " map" && length (call_args) >= 2
1043+ return " $(call_args[2 ]) .map($(call_args[1 ]) )"
1044+ end
1045+ if fn_name == " filter" && length (call_args) >= 2
1046+ return " $(call_args[2 ]) .filter($(call_args[1 ]) )"
1047+ end
1048+ if fn_name == " any" && length (call_args) >= 2
1049+ return " $(call_args[2 ]) .some($(call_args[1 ]) )"
1050+ end
1051+ if fn_name == " all" && length (call_args) >= 2
1052+ return " $(call_args[2 ]) .every($(call_args[1 ]) )"
1053+ end
1054+ if fn_name == " findfirst" && length (call_args) >= 2
1055+ return " ($(call_args[2 ]) .findIndex($(call_args[1 ]) )+1)"
1056+ end
1057+ if fn_name == " reduce" && length (call_args) >= 2
1058+ return " $(call_args[2 ]) .reduce($(call_args[1 ]) )"
1059+ end
1060+
1061+ # ─── Construction (by name) ───
1062+ if fn_name == " zeros" && length (call_args) >= 1
1063+ return " new Array($(call_args[1 ]) ).fill(0)"
1064+ end
1065+ if fn_name == " ones" && length (call_args) >= 1
1066+ return " new Array($(call_args[1 ]) ).fill(1)"
1067+ end
1068+ if fn_name == " fill" && length (call_args) >= 2
1069+ return " new Array($(call_args[2 ]) ).fill($(call_args[1 ]) )"
1070+ end
1071+
1072+ # ─── Parsing (by name) ───
1073+ if fn_name == " parse" && length (call_args) >= 2
1074+ tp = call_args[1 ]
1075+ if contains (tp, " Int" ); return " parseInt($(call_args[2 ]) ,10)" ; end
1076+ if contains (tp, " Float" ); return " parseFloat($(call_args[2 ]) )" ; end
1077+ end
1078+
1079+ # IO
1080+ if fn_name == " println"
1081+ require_runtime! (ctx, :jl_println )
1082+ return " jl_println($(join (call_args, " , " )) )"
1083+ end
1084+
9871085 # Fallback: emit as function call
9881086 return " $(fn_name) ($(join (call_args, " , " )) )"
9891087 end
@@ -1015,11 +1113,30 @@ function compile_call(ctx::JSCompilationContext, expr::Expr)
10151113 # Check package registry
10161114 compiler_fn = lookup_package_compilation (fn_mod, fn_name)
10171115 if compiler_fn != = nothing
1018- # Extract kwargs from NamedTuple construction
10191116 kwargs = _extract_kwargs (ctx, kwargs_ssa)
10201117 pos_args = [compile_value (ctx, a) for a in pos_raw]
10211118 return compiler_fn (ctx, kwargs, pos_args)
10221119 end
1120+
1121+ # sort(arr; by=f, rev=true) → arr.slice().sort(compareFn)
1122+ if fn === Base. sort || fn_name === :sort
1123+ kwargs = _extract_kwargs (ctx, kwargs_ssa)
1124+ pos_args = [compile_value (ctx, a) for a in pos_raw]
1125+ arr_js = pos_args[1 ]
1126+ by_js = get (kwargs, :by , nothing )
1127+ rev = get (kwargs, :rev , nothing )
1128+ is_rev = rev != = nothing && rev != " false"
1129+ if by_js != = nothing
1130+ cmp = is_rev ?
1131+ " (function(a,b){var _a=$(by_js) (a),_b=$(by_js) (b);return _a<_b?1:_a>_b?-1:0})" :
1132+ " (function(a,b){var _a=$(by_js) (a),_b=$(by_js) (b);return _a<_b?-1:_a>_b?1:0})"
1133+ return " $(arr_js) .slice().sort($(cmp) )"
1134+ elseif is_rev
1135+ return " $(arr_js) .slice().sort().reverse()"
1136+ else
1137+ return " $(arr_js) .slice().sort()"
1138+ end
1139+ end
10231140 end
10241141 end
10251142 # Fallback: compile as regular call (strip kwargs)
@@ -1111,6 +1228,8 @@ function compile_call(ctx::JSCompilationContext, expr::Expr)
11111228 end
11121229
11131230 # Base.getproperty(Module, :name) → suppress (module field access in unoptimized IR)
1231+ # e.g., PlotlyBase.scatter becomes getproperty(PlotlyBase, :scatter)
1232+ # The result is used as a callee in a subsequent call, which the package registry handles.
11141233 if bname === :getproperty && callee. mod === Base && length (args) >= 3
11151234 mod_arg = args[2 ]
11161235 mod_val = nothing
@@ -1417,8 +1536,10 @@ function compile_invoke(ctx::JSCompilationContext, expr::Expr)
14171536 override_fn = ctx. callable_overrides[receiver_type]
14181537 receiver_js = compile_value (ctx, expr. args[2 ])
14191538
1420- # Trace receiver SSA back to defining getfield to resolve correct
1421- # captured_vars value (handles multiple same-type signal getters/setters)
1539+ # Trace receiver SSA back to its defining getfield statement to
1540+ # resolve the correct captured_vars value. This handles multiple
1541+ # overrides of the same type (e.g., two SignalSetter{Int} or two
1542+ # SignalGetter{Int} — each maps to a different signal variable).
14221543 if ! isempty (ctx. captured_vars) && expr. args[2 ] isa Core. SSAValue
14231544 recv_ssa_id = expr. args[2 ]. id
14241545 if recv_ssa_id >= 1 && recv_ssa_id <= length (ctx. code_info. code)
@@ -1547,6 +1668,28 @@ function compile_invoke(ctx::JSCompilationContext, expr::Expr)
15471668 elseif func_name == " empty!"
15481669 arr_val = compile_value (ctx, expr. args[3 ])
15491670 return " ($(arr_val) .length = 0, $(arr_val) )"
1671+ elseif func_name == " copy"
1672+ arr_val = compile_value (ctx, expr. args[3 ])
1673+ return " $(arr_val) .slice()"
1674+ elseif func_name == " reverse" || func_name == " reverse!"
1675+ arr_val = compile_value (ctx, expr. args[3 ])
1676+ return " [...$(arr_val) ].reverse()"
1677+ elseif func_name == " setindex!"
1678+ arr_val = compile_value (ctx, expr. args[3 ])
1679+ val_val = compile_value (ctx, expr. args[4 ])
1680+ idx_val = compile_value (ctx, expr. args[5 ])
1681+ return " ($(arr_val) [($(idx_val) )-1] = $(val_val) )"
1682+ elseif func_name == " deleteat!"
1683+ arr_val = compile_value (ctx, expr. args[3 ])
1684+ idx_val = compile_value (ctx, expr. args[4 ])
1685+ return " ($(arr_val) .splice(($(idx_val) )-1, 1), $(arr_val) )"
1686+ elseif func_name == " in" || func_name == " ∈"
1687+ val_val = compile_value (ctx, expr. args[3 ])
1688+ arr_val = compile_value (ctx, expr. args[4 ])
1689+ return " $(arr_val) .includes($(val_val) )"
1690+ elseif func_name == " sort" || func_name == " sort!"
1691+ arr_val = compile_value (ctx, expr. args[3 ])
1692+ return " $(arr_val) .slice().sort()"
15501693 end
15511694 end
15521695
@@ -1687,6 +1830,51 @@ function compile_invoke(ctx::JSCompilationContext, expr::Expr)
16871830 return call_args[2 ]
16881831 end
16891832
1833+ # Higher-order array functions: map, filter, any, all, findfirst
1834+ if func_name == " map" && length (call_args) >= 2
1835+ return " $(call_args[2 ]) .map($(call_args[1 ]) )"
1836+ end
1837+ if func_name == " filter" && length (call_args) >= 2
1838+ return " $(call_args[2 ]) .filter($(call_args[1 ]) )"
1839+ end
1840+ if func_name == " any" && length (call_args) >= 2
1841+ return " $(call_args[2 ]) .some($(call_args[1 ]) )"
1842+ end
1843+ if func_name == " all" && length (call_args) >= 2
1844+ return " $(call_args[2 ]) .every($(call_args[1 ]) )"
1845+ end
1846+ if func_name == " findfirst" && length (call_args) >= 2
1847+ return " ($(call_args[2 ]) .findIndex($(call_args[1 ]) )+1)"
1848+ end
1849+ if func_name == " reduce" && length (call_args) >= 2
1850+ if length (call_args) >= 3
1851+ return " $(call_args[2 ]) .reduce($(call_args[1 ]) ,$(call_args[3 ]) )"
1852+ end
1853+ return " $(call_args[2 ]) .reduce($(call_args[1 ]) )"
1854+ end
1855+
1856+ # Array/collection construction
1857+ if func_name == " zeros" && length (call_args) >= 1
1858+ return " new Array($(call_args[1 ]) ).fill(0)"
1859+ end
1860+ if func_name == " ones" && length (call_args) >= 1
1861+ return " new Array($(call_args[1 ]) ).fill(1)"
1862+ end
1863+ if func_name == " fill" && length (call_args) >= 2
1864+ return " new Array($(call_args[2 ]) ).fill($(call_args[1 ]) )"
1865+ end
1866+
1867+ # Number parsing
1868+ if func_name == " parse" && length (call_args) >= 2
1869+ type_arg = call_args[1 ]
1870+ str_arg = call_args[2 ]
1871+ if contains (type_arg, " Int" )
1872+ return " parseInt($(str_arg) , 10)"
1873+ elseif contains (type_arg, " Float" )
1874+ return " parseFloat($(str_arg) )"
1875+ end
1876+ end
1877+
16901878 # Check package compilation registry (for registered functions like sort_for, plotly, etc.)
16911879 fn_mod = meth. module
16921880 fn_name_sym = meth. name
@@ -1971,6 +2159,10 @@ function compile_intrinsic(ctx::JSCompilationContext, name::Symbol, args::Abstra
19712159 return " $(compiled_args[1 ]) < $(compiled_args[2 ]) "
19722160 elseif name === :sle_int
19732161 return " $(compiled_args[1 ]) <= $(compiled_args[2 ]) "
2162+ elseif name === :sgt_int
2163+ return " $(compiled_args[1 ]) > $(compiled_args[2 ]) "
2164+ elseif name === :sge_int
2165+ return " $(compiled_args[1 ]) >= $(compiled_args[2 ]) "
19742166 elseif name === :eq_float
19752167 return " $(compiled_args[1 ]) === $(compiled_args[2 ]) "
19762168 elseif name === :ne_float
0 commit comments