@@ -1171,25 +1171,37 @@ static T_sp extract_lambda_list_from_declares(List_sp declares, T_sp defaultll)
11711171 return defaultll;
11721172}
11731173
1174- Lexenv_sp compile_optional_or_key_item (Symbol_sp var, T_sp defaulting_form, size_t var_index , Symbol_sp supplied_var,
1174+ Lexenv_sp compile_optional_or_key_item (Symbol_sp var, T_sp defaulting_form, LexicalVarInfo_sp varinfo , Symbol_sp supplied_var,
11751175 Label_sp next_label, bool var_specialp, bool supplied_specialp, const Context context,
11761176 Lexenv_sp env) {
11771177 Label_sp supplied_label = Label_O::make ();
1178- T_sp varinfo = env->variableInfo (var);
11791178 T_sp supinfo = nil<T_O>();
1180- if (supplied_var.notnilp ()) {
1181- env = env->bind1var (supplied_var, context);
1182- supinfo = env->variableInfo (supplied_var);
1183- }
1184- context.emit_jump_if_supplied (supplied_label, var_index);
1179+ context.emit_jump_if_supplied (supplied_label, varinfo->frameIndex ());
11851180 // Emit code for the case of the variable not being supplied:
11861181 // Bind the var to the default, and the suppliedvar to NIL if applicable.
11871182 compile_form (defaulting_form, env, Context (context, 1 ));
1183+ // Now that the default form is compiled, bind variables (for later vars)
1184+ if (var_specialp)
1185+ env = env->add_specials (Cons_O::createList (var));
1186+ else
1187+ // import the existing info.
1188+ env = Lexenv_O::make (Cons_O::create (Cons_O::create (var, varinfo),
1189+ env->vars ()),
1190+ env->tags (), env->blocks (), env->funs (),
1191+ env->notinlines (), env->frameEnd ());
1192+ if (supplied_var.notnilp ()) {
1193+ if (supplied_specialp)
1194+ env = env->add_specials (Cons_O::createList (supplied_var));
1195+ else
1196+ env = env->bind1var (supplied_var, context);
1197+ supinfo = env->variableInfo (supplied_var);
1198+ }
1199+ // Actually generate the unsupplied case.
11881200 if (var_specialp)
11891201 context.emit_special_bind (var);
11901202 else {
1191- context.maybe_emit_make_cell (gc::As_assert<LexicalVarInfo_sp>( varinfo) );
1192- context.assemble1 (vm_set, var_index );
1203+ context.maybe_emit_make_cell (varinfo);
1204+ context.assemble1 (vm_set, varinfo-> frameIndex () );
11931205 }
11941206 if (supplied_var.notnilp ()) { // bind supplied_var to NIL
11951207 context.assemble0 (vm_nil);
@@ -1205,10 +1217,10 @@ Lexenv_sp compile_optional_or_key_item(Symbol_sp var, T_sp defaulting_form, size
12051217 // Now for when the variable is supplied.
12061218 supplied_label->contextualize (context);
12071219 if (var_specialp) { // we have it in a reg, so rebind
1208- context.assemble1 (vm_ref, var_index );
1220+ context.assemble1 (vm_ref, varinfo-> frameIndex () );
12091221 context.emit_special_bind (var);
12101222 } else { // in the reg already, but maybe needs a cell
1211- context.maybe_emit_encage (gc::As_assert<LexicalVarInfo_sp>( varinfo) );
1223+ context.maybe_emit_encage (varinfo);
12121224 }
12131225 if (supplied_var.notnilp ()) {
12141226 compile_literal (cl::_sym_T_O, env, Context (context, 1 ));
@@ -1221,10 +1233,6 @@ Lexenv_sp compile_optional_or_key_item(Symbol_sp var, T_sp defaulting_form, size
12211233 }
12221234 }
12231235 // That's it for code generation. Now return the new environment.
1224- if (var_specialp)
1225- env = env->add_specials (Cons_O::createList (var));
1226- if (supplied_specialp)
1227- env = env->add_specials (Cons_O::createList (supplied_var));
12281236 return env;
12291237}
12301238
@@ -1253,12 +1261,8 @@ void compile_with_lambda_list(T_sp lambda_list, List_sp body, Lexenv_sp env, con
12531261 for (auto &it : reqs)
12541262 lreqs << it._ArgTarget ;
12551263 Lexenv_sp new_env = env->bind_vars (lreqs.cons (), context);
1264+ // This environment is only used for assigning indices to opt/key variables.
12561265 size_t special_binding_count = 0 ;
1257- // An alist from optional and key variables to their local indices.
1258- // This is needed so that we can properly mark any that are special as
1259- // such while leaving them temporarily "lexically" bound during
1260- // argument parsing.
1261- List_sp opt_key_indices = nil<T_O>();
12621266
12631267 entry_point->contextualize (context);
12641268 // Generate argument count check.
@@ -1290,29 +1294,23 @@ void compile_with_lambda_list(T_sp lambda_list, List_sp body, Lexenv_sp env, con
12901294 }
12911295 new_env = new_env->add_specials (sreqs.cons ());
12921296 }
1297+ Lexenv_sp optkey_env = new_env;
12931298 if (optional_count > 0 ) {
12941299 // Generate code to bind the provided optional args, unprovided args will
12951300 // be initialized with the unbound marker.
12961301 context.assemble2 (vm_bind_optional_args, min_count, optional_count);
12971302 // Mark the locations of each optional. Note that we do this even if
1298- // the variable will be specially bound.
1303+ // the variable will be specially bound, to match the placement by
1304+ // bind_optional_args.
12991305 ql::list opts;
13001306 for (auto &it : optionals)
13011307 opts << it._ArgTarget ;
1302- new_env = new_env->bind_vars (opts.cons (), context);
1303- // Add everything to opt-key-indices.
1304- for (auto &it : optionals) {
1305- T_sp var = it._ArgTarget ;
1306- auto lvinfo = gc::As_assert<LexicalVarInfo_sp>(new_env->variableInfo (var));
1307- opt_key_indices = Cons_O::create (Cons_O::create (var, clasp_make_fixnum (lvinfo->frameIndex ())), opt_key_indices);
1308- }
1309- // Re-mark anything that's special in the outer context as such, so that
1310- // default initforms properly treat them as special.
1311- ql::list sopts;
1312- for (auto &it : optionals)
1313- if (std::holds_alternative<SpecialVarInfoV>(var_info_v (it._ArgTarget , env)))
1314- sopts << it._ArgTarget ;
1315- new_env = new_env->add_specials (sopts.cons ());
1308+ optkey_env = optkey_env->bind_vars (opts.cons (), context);
1309+ // new_env has enough space for the optional arguments, but without the
1310+ // variables actually bound, so that default forms can be compiled correctly
1311+ new_env = Lexenv_O::make (new_env->vars (), optkey_env->tags (),
1312+ optkey_env->blocks (), optkey_env->funs (),
1313+ optkey_env->notinlines (), optkey_env->frameEnd ());
13161314 }
13171315 if (key_flag.notnilp ()) {
13181316 // Generate code to parse the key args. As with optionals, we don't do
@@ -1330,24 +1328,16 @@ void compile_with_lambda_list(T_sp lambda_list, List_sp body, Lexenv_sp env, con
13301328 context.new_literal_index (it._Keyword );
13311329 }
13321330 // now the actual instruction
1333- context.emit_parse_key_args (max_count, keys.size (), first_key_index, new_env ->frameEnd (), aokp.notnilp ());
1331+ context.emit_parse_key_args (max_count, keys.size (), first_key_index, optkey_env ->frameEnd (), aokp.notnilp ());
13341332 ql::list keyvars;
1335- ql::list skeys;
1336- for (auto &it : keys) {
1333+ for (auto &it : keys)
13371334 keyvars << it._ArgTarget ;
1338- if (std::holds_alternative<SpecialVarInfoV>(var_info_v (it._ArgTarget , env)))
1339- skeys << it._ArgTarget ;
1340- }
1341- new_env = new_env->bind_vars (keyvars.cons (), context);
1342- for (auto &it : keys) {
1343- T_sp var = it._ArgTarget ;
1344- auto lvinfo = gc::As_assert<LexicalVarInfo_sp>(new_env->variableInfo (var));
1345- opt_key_indices = Cons_O::create (Cons_O::create (var, clasp_make_fixnum (lvinfo->frameIndex ())), opt_key_indices);
1346- }
1347- new_env = new_env->add_specials (skeys.cons ());
1335+ optkey_env = optkey_env->bind_vars (keyvars.cons (), context);
1336+ new_env = Lexenv_O::make (new_env->vars (), optkey_env->tags (),
1337+ optkey_env->blocks (), optkey_env->funs (),
1338+ optkey_env->notinlines (), optkey_env->frameEnd ());
13481339 }
1349- // Generate defaulting code for optional args, and special-bind them
1350- // if necessary.
1340+ // Generate defaulting code for optional args, and bind them properly.
13511341 if (optional_count > 0 ) {
13521342 Label_sp optional_label = Label_O::make ();
13531343 Label_sp next_optional_label = Label_O::make ();
@@ -1357,10 +1347,9 @@ void compile_with_lambda_list(T_sp lambda_list, List_sp body, Lexenv_sp env, con
13571347 T_sp defaulting_form = it._Default ;
13581348 T_sp supplied_var = it._Sensor ._ArgTarget ;
13591349 bool optional_special_p = special_binding_p (optional_var, specials, env);
1360- T_sp pair = core__alist_assoc_eq (gc::As_assert<Cons_sp>(opt_key_indices), optional_var);
1361- size_t index = oCdr (pair).unsafe_fixnum ();
1350+ auto varinfo = gc::As_assert<LexicalVarInfo_sp>(var_info (optional_var, optkey_env));
13621351 bool supplied_special_p = supplied_var.notnilp () && special_binding_p (supplied_var, specials, env);
1363- new_env = compile_optional_or_key_item (optional_var, defaulting_form, index , supplied_var, next_optional_label,
1352+ new_env = compile_optional_or_key_item (optional_var, defaulting_form, varinfo , supplied_var, next_optional_label,
13641353 optional_special_p, supplied_special_p, context, new_env);
13651354 if (optional_special_p)
13661355 ++special_binding_count;
@@ -1401,10 +1390,9 @@ void compile_with_lambda_list(T_sp lambda_list, List_sp body, Lexenv_sp env, con
14011390 T_sp defaulting_form = it._Default ;
14021391 T_sp supplied_var = it._Sensor ._ArgTarget ;
14031392 bool key_special_p = special_binding_p (key_var, specials, env);
1404- T_sp pair = core__alist_assoc_eq (gc::As<Cons_sp>(opt_key_indices), key_var);
1405- size_t index = oCdr (pair).unsafe_fixnum ();
1393+ auto varinfo = gc::As_assert<LexicalVarInfo_sp>(var_info (key_var, optkey_env));
14061394 bool supplied_special_p = supplied_var.notnilp () && special_binding_p (supplied_var, specials, env);
1407- new_env = compile_optional_or_key_item (key_var, defaulting_form, index , supplied_var, next_key_label, key_special_p,
1395+ new_env = compile_optional_or_key_item (key_var, defaulting_form, varinfo , supplied_var, next_key_label, key_special_p,
14081396 supplied_special_p, context, new_env);
14091397 if (key_special_p)
14101398 ++special_binding_count;
0 commit comments