BarefootJS
view release on metacpan or search on metacpan
lib/BarefootJS/Evaluator.pm view on Meta::CPAN
if (_is_string($l) && _is_string($r)) {
$c = $l lt $r ? -1 : $l gt $r ? 1 : 0;
}
else {
my $ln = _to_number($l);
my $rn = _to_number($r);
return _bool(0) if $ln != $ln || $rn != $rn; # NaN â false
$c = $ln < $rn ? -1 : $ln > $rn ? 1 : 0;
}
return _bool($c < 0) if $op eq '<';
return _bool($c <= 0) if $op eq '<=';
return _bool($c > 0) if $op eq '>';
return _bool($c >= 0) if $op eq '>=';
return _bool(0);
}
sub _strict_eq ($l, $r) {
# Strict `===`: equal JS type and value, no coercion.
my $ln = _is_number($l);
my $rn = _is_number($r);
if ($ln && $rn) {
my ($lf, $rf) = ($l + 0, $r + 0);
return 0 if $lf != $lf || $rf != $rf; # NaN
return $lf == $rf ? 1 : 0;
}
return 0 if $ln != $rn; # one numeric, one not
if (!defined $l) { return !defined $r ? 1 : 0 }
return 0 if !defined $r;
my $lb = ref $l eq 'JSON::PP::Boolean';
my $rb = ref $r eq 'JSON::PP::Boolean';
if ($lb || $rb) {
return 0 unless $lb && $rb;
return ((!!$l) == (!!$r)) ? 1 : 0;
}
return ($l eq $r ? 1 : 0) if _is_string($l) && _is_string($r);
return 0;
}
# _same_value_zero: `Array.prototype.includes` membership test â `===`
# except `NaN` equals itself (and +0/-0 are not distinguished, which the
# JSON-decoded values here can't represent anyway). Reuses `_strict_eq`'s
# type/value rules and only special-cases the two-NaN case that `_strict_eq`
# (deliberately, for `===`) reports as unequal.
sub _same_value_zero ($l, $r) {
if (_is_number($l) && _is_number($r)) {
my ($lf, $rf) = ($l + 0, $r + 0);
return 1 if $lf != $lf && $rf != $rf; # NaN sameValueZero NaN
}
return _strict_eq($l, $r);
}
sub _unary ($op, $v) {
return _bool(!_truthy($v)) if $op eq '!';
return -_to_number($v) if $op eq '-';
return _to_number($v) if $op eq '+';
return undef;
}
# ---------------------------------------------------------------------------
# Built-in calls (the deterministic allowlist). Locale-sensitive builtins
# (localeCompare) are deliberately excluded to keep the backends isomorphic.
# ---------------------------------------------------------------------------
# _builtin_name: resolve a `call` callee to its builtin name (e.g.
# "Math.max"), or '' when the callee is not an allowlisted builtin reference.
sub _builtin_name ($callee) {
return '' unless ref $callee eq 'HASH';
my $kind = $callee->{kind} // '';
if ($kind eq 'identifier') {
return $callee->{name} // '';
}
if ($kind eq 'member' && !$callee->{computed}) {
my $obj = $callee->{object};
return '' unless ref $obj eq 'HASH' && ($obj->{kind} // '') eq 'identifier';
return ($obj->{name} // '') . '.' . ($callee->{property} // '');
}
return '';
}
# _math_round: half rounds toward +Infinity (JS Math.round: 2.5â3, -2.5â-2),
# matching the existing round helper rather than half-away-from-zero.
sub _math_round ($n) {
return POSIX::floor($n + 0.5);
}
sub _call_builtin ($name, $args) {
if ($name eq 'Math.max') {
my $m = -(9**9**9); # JS Math.max() with no args is -Infinity
for my $a (@$args) {
my $n = _to_number($a);
return $n if $n != $n; # any NaN argument â NaN (JS / Go)
$m = $n if $n > $m;
}
return $m;
}
if ($name eq 'Math.min') {
my $m = 9**9**9; # JS Math.min() with no args is +Infinity
for my $a (@$args) {
my $n = _to_number($a);
return $n if $n != $n; # any NaN argument â NaN (JS / Go)
$m = $n if $n < $m;
}
return $m;
}
return abs(_to_number($args->[0])) if $name eq 'Math.abs';
return POSIX::floor(_to_number($args->[0])) if $name eq 'Math.floor';
return POSIX::ceil(_to_number($args->[0])) if $name eq 'Math.ceil';
return _math_round(_to_number($args->[0])) if $name eq 'Math.round';
return _to_string($args->[0]) if $name eq 'String';
return _to_number($args->[0]) if $name eq 'Number';
return _bool(_truthy($args->[0])) if $name eq 'Boolean';
# Any other callee is outside the subset (refused upstream).
return undef;
}
# ---------------------------------------------------------------------------
# Member / index access
# ---------------------------------------------------------------------------
sub _read_property ($obj, $key) {
return undef unless defined $obj;
( run in 0.573 second using v1.01-cache-2.11-cpan-a5162978ef8 )