var behaves like let

This commit is contained in:
2025-12-29 00:37:26 -06:00
parent 3b53a9dcc3
commit 4f3e2819fe
6 changed files with 149 additions and 106 deletions

View File

@@ -7,6 +7,7 @@ var SYSYM = '__SYSTEM__'
var hidden = _cell.hidden
var os = hidden.os;
_cell.os = null
var dylib_ext
@@ -412,6 +413,8 @@ globalThis.parallel = pronto.parallel
globalThis.race = pronto.race
globalThis.sequence = pronto.sequence
$_.time_limit = function(requestor, seconds)
{
if (!pronto.is_requestor(requestor))
@@ -486,6 +489,8 @@ _cell.config = config
ENETSERVICE = config.net_service
REPLYTIMEOUT = config.reply_timeout
/*
When handling a message, the message appears like this:
{
@@ -516,8 +521,6 @@ function guid(bits = 256)
return text(guid,'h')
}
var _Symbol = Symbol
var HEADER = _Symbol()
// takes a function input value that will eventually be called with the current time in number form.
@@ -891,12 +894,13 @@ function handle_actor_disconnect(id) {
function handle_sysym(msg)
{
var from
switch(msg.kind) {
case 'stop':
disrupt("got stop message")
break
case 'underling':
var from = msg.from
from = msg.from
var greeter = greeters[from[ACTORDATA].id]
if (greeter) greeter(msg.message)
if (msg.message.type == 'disrupt')
@@ -911,7 +915,7 @@ function handle_sysym(msg)
} else throw new Error('Got a contact message, but no portal is established.')
break
case 'couple': // from must be notified when we die
var from = msg.from
from = msg.from
underlings.add(from[ACTORDATA].id)
log.system(`actor ${from} is coupled to me`)
break
@@ -977,7 +981,6 @@ if (!locator)
// Hide JavaScript built-ins - make them inaccessible
// Store references we need internally before deleting
var _Object = Object
var _Array = Array
var _String = String
var _Number = Number

View File

@@ -63,7 +63,7 @@ var dylib_ext = '.dylib' // Default extension
var use_cache = os.use_cache
var global_shop_path = os.global_shop_path
var $_ = os.$_
var my$_ = os.$_
Shop.get_package_dir = function(name) {
return global_shop_path + '/packages/' + name
@@ -385,7 +385,7 @@ function inject_values(inject) {
for (var i = 0; i < inject.length; i++) {
var key = strip_dollar(inject[i])
if (key == 'fd') vals.push(fd)
else vals.push($_[key])
else vals.push(my$_[key])
}
return vals
}
@@ -400,23 +400,7 @@ var script_form = function(path, script, pkg, inject) {
var pkg_arg = pkg ? `'${pkg}'` : 'null'
var params = inject_params(inject)
// Build $_ object from injected capabilities for backward compatibility
var build_compat = ''
if (inject && inject.length) {
var compat_props = []
for (var i = 0; i < inject.length; i++) {
var name = inject[i]
var key = name
if (key && key[0] == '$') key = key.substring(1)
compat_props.push(key + ': ' + name)
}
build_compat = 'var $_ = {' + compat_props.join(', ') + '};'
}
// use is passed as a parameter, not on globalThis for the script
// $fd is injected as a capability, but we still allow use('fd') for now
// $_ is built from injected capabilities for backward compatibility
var fn = `(function setup_module(args, use${params}){ def arg = args; def PACKAGE = ${pkg_arg}; ${build_compat} ${script}})`
var fn = `(function setup_module(args, use${params}){ def arg = args; def PACKAGE = ${pkg_arg}; ${script}})`
return fn
}
@@ -808,7 +792,7 @@ function execute_module(info)
used = mod_resolve.symbol.call(context, null, use_fn, ...vals)
} else if (c_resolve.scope < 900) {
// C only
used = c_resolve.symbol(null, $_)
used = c_resolve.symbol(null, my$_)
} else {
throw new Error(`Module ${info.path} could not be found`)
} if (!used)

View File

@@ -33,9 +33,9 @@ function fallback(requestor_array) {
return function fallback_requestor(callback, value) {
check_callback(callback, factory)
let index = 0
let current_cancel = null
let cancelled = false
var index = 0
var current_cancel = null
var cancelled = false
function cancel(reason) {
cancelled = true
@@ -98,10 +98,10 @@ function parallel(requestor_array, throttle, need) {
check_callback(callback, factory)
def results = new Array(length)
def cancel_list = new Array(length)
let next_index = 0
let successes = 0
let failures = 0
let finished = false
var next_index = 0
var successes = 0
var failures = 0
var finished = false
function cancel(reason) {
if (finished) return
@@ -154,7 +154,7 @@ function parallel(requestor_array, throttle, need) {
}
def concurrent = throttle ? number.min(throttle, length) : length
for (let i = 0; i < concurrent; i++) start_one()
for (var i = 0; i < concurrent; i++) start_one()
return cancel
}
@@ -180,10 +180,10 @@ function race(requestor_array, throttle, need) {
check_callback(callback, factory)
def results = new Array(length)
def cancel_list = new Array(length)
let next_index = 0
let successes = 0
let failures = 0
let finished = false
var next_index = 0
var successes = 0
var failures = 0
var finished = false
function cancel(reason) {
if (finished) return
@@ -239,7 +239,7 @@ function race(requestor_array, throttle, need) {
}
def concurrent = throttle ? number.min(throttle, length) : length
for (let i = 0; i < concurrent; i++) start_one()
for (var i = 0; i < concurrent; i++) start_one()
return cancel
}
@@ -258,9 +258,9 @@ function sequence(requestor_array) {
return function sequence_requestor(callback, value) {
check_callback(callback, factory)
let index = 0
let current_cancel = null
let cancelled = false
var index = 0
var current_cancel = null
var cancelled = false
function cancel(reason) {
cancelled = true

View File

@@ -15384,7 +15384,6 @@ enum {
/* FutureReservedWords when parsing strict mode code */
TOK_IMPLEMENTS,
TOK_INTERFACE,
TOK_LET,
TOK_PRIVATE,
TOK_PROTECTED,
TOK_PUBLIC,
@@ -18680,18 +18679,15 @@ static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
return js_parse_error(s, "invalid variable name in strict mode");
}
if (name == JS_ATOM_let
&& (tok == TOK_LET || tok == TOK_DEF)) {
&& tok == TOK_DEF) {
return js_parse_error(s, "invalid lexical variable name");
}
switch(tok) {
case TOK_LET:
var_def_type = JS_VAR_DEF_LET;
break;
case TOK_DEF:
var_def_type = JS_VAR_DEF_CONST;
break;
case TOK_VAR:
var_def_type = JS_VAR_DEF_VAR;
var_def_type = JS_VAR_DEF_LET;
break;
case TOK_CATCH:
var_def_type = JS_VAR_DEF_CATCH;
@@ -18749,7 +18745,7 @@ duplicate:
return js_parse_error(s, "duplicate parameter names not allowed in this context");
}
/* tok = TOK_VAR, TOK_LET or TOK_DEF. Return whether a reference
/* tok = TOK_VAR or TOK_DEF. Return whether a reference
must be taken to the variable for proper 'with' or global variable
evaluation */
/* Note: this function is needed only because variable references are
@@ -18757,12 +18753,8 @@ duplicate:
static BOOL need_var_reference(JSParseState *s, int tok)
{
JSFunctionDef *fd = s->cur_func;
if (tok != TOK_VAR)
return FALSE; /* no reference for let/const */
if (!fd->is_global_var)
return FALSE; /* local definitions in strict mode in function or direct eval */
return TRUE;
/* var now behaves like let - no reference needed */
return FALSE;
}
static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
@@ -19075,7 +19067,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
/* store value into lvalue object */
put_lvalue(s, opcode, scope, var_name, label_lvalue,
PUT_LVALUE_NOKEEP_DEPTH,
(tok == TOK_DEF || tok == TOK_LET));
(tok == TOK_DEF || tok == TOK_VAR));
if (s->token.val == '}')
break;
/* accept a trailing comma before the '}' */
@@ -19189,7 +19181,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
/* store value into lvalue object */
put_lvalue(s, opcode, scope, var_name,
label_lvalue, PUT_LVALUE_NOKEEP_DEPTH,
(tok == TOK_DEF || tok == TOK_LET));
(tok == TOK_DEF || tok == TOK_VAR));
}
if (s->token.val == ']')
break;
@@ -20516,7 +20508,7 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
return js_parse_error_reserved_identifier(s);
}
name = JS_DupAtom(ctx, s->token.u.ident.atom);
if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_DEF)) {
if (name == JS_ATOM_let && tok == TOK_DEF) {
js_parse_error(s, "'let' is not a valid lexical identifier");
goto var_error;
}
@@ -20549,7 +20541,7 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
if (js_parse_assign_expr2(s, parse_flags))
goto var_error;
set_object_name(s, name);
emit_op(s, (tok == TOK_DEF || tok == TOK_LET) ?
emit_op(s, (tok == TOK_DEF || tok == TOK_VAR) ?
OP_scope_put_var_init : OP_scope_put_var);
emit_atom(s, name);
emit_u16(s, fd->scope_level);
@@ -20559,7 +20551,7 @@ static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
js_parse_error(s, "missing initializer for const variable");
goto var_error;
}
if (tok == TOK_LET) {
if (tok == TOK_VAR) {
/* initialize lexical variable upon entering its scope */
emit_op(s, OP_null);
emit_op(s, OP_scope_put_var_init);
@@ -20621,7 +20613,6 @@ static int is_let(JSParseState *s, int decl_mask)
}
if (s->token.val == '{' ||
(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) ||
s->token.val == TOK_LET ||
s->token.val == TOK_YIELD ||
s->token.val == TOK_AWAIT) {
/* Check for possible ASI if not scanning for Declaration */
@@ -20682,16 +20673,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name)
emit_label(s, label_next);
tok = s->token.val;
switch (is_let(s, DECL_MASK_OTHER)) {
case TRUE:
tok = TOK_LET;
break;
case FALSE:
break;
default:
return -1;
}
if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_DEF) {
if (tok == TOK_VAR || tok == TOK_DEF) {
if (next_token(s))
return -1;
@@ -20714,7 +20696,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name)
JS_FreeAtom(s->ctx, var_name);
return -1;
}
emit_op(s, (tok == TOK_DEF || tok == TOK_LET) ?
emit_op(s, (tok == TOK_DEF || tok == TOK_VAR) ?
OP_scope_put_var_init : OP_scope_put_var);
emit_atom(s, var_name);
emit_u16(s, fd->scope_level);
@@ -20948,7 +20930,6 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
goto fail;
}
break;
case TOK_LET:
case TOK_DEF:
haslet:
if (!(decl_mask & DECL_MASK_OTHER)) {
@@ -20957,6 +20938,10 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
}
/* fall thru */
case TOK_VAR:
if (!(decl_mask & DECL_MASK_OTHER)) {
js_parse_error(s, "lexical declarations can't appear in single-statement context");
goto fail;
}
if (next_token(s))
goto fail;
if (js_parse_var(s, TRUE, tok, FALSE))
@@ -21096,16 +21081,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
/* initial expression */
tok = s->token.val;
if (tok != ';') {
switch (is_let(s, DECL_MASK_OTHER)) {
case TRUE:
tok = TOK_LET;
break;
case FALSE:
break;
default:
goto fail;
}
if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_DEF) {
if (tok == TOK_VAR || tok == TOK_DEF) {
if (next_token(s))
goto fail;
if (js_parse_var(s, FALSE, tok, FALSE))
@@ -21369,8 +21345,8 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
goto fail;
if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
if (s->token.val == '[' || s->token.val == '{') {
/* XXX: TOK_LET is not completely correct */
if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE, FALSE) < 0)
/* catch variables behave like var (block scoped) */
if (js_parse_destructuring_element(s, TOK_VAR, 0, TRUE, -1, TRUE, FALSE) < 0)
goto fail;
} else {
js_parse_error(s, "identifier expected");
@@ -21490,16 +21466,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
js_parse_error_reserved_identifier(s);
goto fail;
}
/* Determine if `let` introduces a Declaration or an ExpressionStatement */
switch (is_let(s, decl_mask)) {
case TRUE:
tok = TOK_LET;
goto haslet;
case FALSE:
break;
default:
goto fail;
}
/* let keyword is no longer supported */
if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
peek_token(s, TRUE) == TOK_FUNCTION) {
if (!(decl_mask & DECL_MASK_OTHER)) {
@@ -25359,7 +25326,6 @@ static __exception int js_parse_directives(JSParseState *s)
case TOK_EXPORT:
case TOK_IMPORT:
case TOK_INTERFACE:
case TOK_LET:
/* automatic insertion of ';' */
if (s->got_lf)
has_semi = TRUE;
@@ -25581,7 +25547,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
emit_op(s, OP_get_arg);
emit_u16(s, idx);
}
has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE, FALSE);
has_initializer = js_parse_destructuring_element(s, TOK_VAR, 1, TRUE, -1, TRUE, FALSE);
if (has_initializer < 0)
goto fail;
if (has_initializer)

View File

@@ -550,8 +550,9 @@ function finalize_results() {
}
// If no actor tests, finalize immediately
var totals
if (all_actor_tests.length == 0) {
var totals = { total: 0, passed: 0, failed: 0 }
totals = { total: 0, passed: 0, failed: 0 }
for (var i = 0; i < all_results.length; i++) {
totals.total += all_results[i].total
totals.passed += all_results[i].passed
@@ -564,7 +565,6 @@ if (all_actor_tests.length == 0) {
$delay(check_timeouts, 1000)
}
// Generate Reports function
function generate_reports(totals) {
var timestamp = number.floor(time.number()).toString()

View File

@@ -314,10 +314,100 @@ return {
if (x != 10) throw "var reassignment failed"
},
test_var_hoisting: function() {
var result = x
var x = 5
if (result != null) throw "var hoisting should initialize to null"
// ============================================================================
// VAR BLOCK SCOPING (var now behaves like let)
// ============================================================================
test_var_block_scope_basic: function() {
var x = 1
{
var x = 2
if (x != 2) throw "var should be block scoped - inner scope failed"
}
if (x != 1) throw "var should be block scoped - outer scope affected"
},
test_var_block_scope_if: function() {
var x = 1
if (true) {
var x = 2
if (x != 2) throw "var in if block should be scoped"
}
if (x != 1) throw "var in if block should not affect outer scope"
},
test_var_block_scope_for: function() {
var x = 1
for (var i = 0; i < 1; i = i + 1) {
var x = 2
if (x != 2) throw "var in for block should be scoped"
}
if (x != 1) throw "var in for block should not affect outer scope"
},
test_var_for_loop_iterator_scope: function() {
var sum = 0
for (var i = 0; i < 3; i = i + 1) {
sum = sum + i
}
if (sum != 3) throw "for loop should work with block scoped var"
var caught = false
try {
var y = i
} catch (e) {
caught = true
}
if (!caught) throw "for loop iterator should not leak to outer scope"
},
test_var_nested_blocks: function() {
var x = 1
{
var x = 2
{
var x = 3
if (x != 3) throw "var in nested block level 2 failed"
}
if (x != 2) throw "var in nested block level 1 failed"
}
if (x != 1) throw "var in nested blocks outer scope failed"
},
test_var_redeclaration_different_scope: function() {
var x = 1
{
var x = 2
}
if (x != 1) throw "var in different scope should not affect outer"
},
test_var_switch_scope: function() {
var x = 1
switch (1) {
case 1:
var x = 2
if (x != 2) throw "var in switch should be block scoped"
break
}
if (x != 1) throw "var in switch should not affect outer scope"
},
test_var_while_scope: function() {
var x = 1
var count = 0
while (count < 1) {
var x = 2
if (x != 2) throw "var in while should be block scoped"
count = count + 1
}
if (x != 1) throw "var in while should not affect outer scope"
},
test_var_no_initialization: function() {
{
var x
if (x != null) throw "uninitialized var should be null"
}
},
test_multiple_var_declaration: function() {