diff --git a/src/docode.c b/src/docode.c index a7e8b70db23bc3d636e42312569512f28ba247fc..f12a32d1d71b26bdccdc9830f40fb9dd2ad65fd3 100644 --- a/src/docode.c +++ b/src/docode.c @@ -1149,6 +1149,17 @@ static int do_docode2(node *n, int flags) return 1; } + case F_APPEND_MAPPING: { + emit0(F_MARK); + PUSH_CLEANUP_FRAME(do_pop_mark, 0); + do_docode(CAR(n),DO_LVALUE); + emit0(F_CONST0); /* Reserved for svalue. */ + do_docode(CDR(n),0); + emit0(F_APPEND_MAPPING); + POP_AND_DONT_CLEANUP; + return 1; + } + case '?': { INT32 *prev_switch_jumptable = current_switch.jumptable; diff --git a/src/interpret_functions.h b/src/interpret_functions.h index e67e12c7ac5544ca06b2d231ee0ffbece85d214e..bfffd60b8c4c2393d8d4d2babd1419f96fd522be 100644 --- a/src/interpret_functions.h +++ b/src/interpret_functions.h @@ -2021,6 +2021,10 @@ OPCODE0(F_APPEND_ARRAY, "append array", I_UPDATE_SP|I_UPDATE_M_SP, { o_append_array(Pike_sp - *(--Pike_mark_sp)); }); +OPCODE0(F_APPEND_MAPPING, "append mapping", I_UPDATE_SP|I_UPDATE_M_SP, { + o_append_mapping(Pike_sp - *(--Pike_mark_sp)); + }); + OPCODE2(F_LOCAL_LOCAL_INDEX, "local[local]", I_UPDATE_SP, { LOCAL_VAR(struct svalue *s); s = Pike_fp->locals + arg1; diff --git a/src/las.c b/src/las.c index c4d4e2ab2e94ea2efb7db906f66160b23c5903ea..ba0ae0e11c6daa43c7ff6d90c2246b4aaf388898 100644 --- a/src/las.c +++ b/src/las.c @@ -919,6 +919,7 @@ node *debug_mknode(int token, node *a, node *b) break; case F_APPEND_ARRAY: + case F_APPEND_MAPPING: case F_MULTI_ASSIGN: case F_ASSIGN: case F_ASSIGN_SELF: @@ -2742,7 +2743,8 @@ static void find_written_vars(node *n, find_written_vars(CDR(n), p, 1); break; - case F_APPEND_ARRAY: + case F_APPEND_MAPPING: + case F_APPEND_ARRAY: find_written_vars(CAR(n), p, 1); find_written_vars(CDR(n), p, 0); break; @@ -3199,6 +3201,16 @@ void fix_type_field(node *n) } break; + case F_APPEND_MAPPING: + if (!CAR(n) || (CAR(n)->type == void_type_string)) { + yyerror("Assigning a void expression."); + copy_pike_type(n->type, void_type_string); + } + else + /* FIXME: Not really correct, should calculate type of RHS. */ + copy_pike_type(n->type, CAR(n)->type); + break; + case F_APPEND_ARRAY: if (!CAR(n) || (CAR(n)->type == void_type_string)) { yyerror("Assigning a void expression."); diff --git a/src/mapping.c b/src/mapping.c index cfe0e2afaf6ae2076f974059ed9a9af4dea740a8..7421b4d55f22b4631bf937e685dd64567974a3cd 100644 --- a/src/mapping.c +++ b/src/mapping.c @@ -1856,6 +1856,39 @@ PMOD_EXPORT struct mapping *merge_mapping_array_unordered(struct mapping *a, return m; } +void o_append_mapping( INT32 args ) +{ + struct svalue *lval = Pike_sp - args; + struct svalue *val = lval + 2; +#ifdef PIKE_DEBUG + if (args < 3) { + Pike_fatal("Too few arguments to o_append_mapping(): %d\n", args); + } +#endif + args -= 3; + /* Note: val should always be a zero here! */ + lvalue_to_svalue_no_free(val, lval); + + if (TYPEOF(*val) == T_MAPPING) + { + struct mapping *m = val->u.mapping; + if( m->refs == 2 ) + { + int i; + /* fprintf( stderr, "map_refs==2\n" ); */ + for( i=0; i<args; i+=2 ) + low_mapping_insert( m, Pike_sp-(i+2), Pike_sp-(i+1), 0 ); + stack_pop_n_elems_keep_top(2+args); + return; + } + } + + f_aggregate_mapping(args); + f_add(2); + assign_lvalue(lval, val); + stack_pop_2_elems_keep_top(); +} + /* NOTE: May perform destructive operations on either of the arguments * if it has only a single reference. */ diff --git a/src/mapping.h b/src/mapping.h index f4e11165c5358b51b3dc12d9bac75b4ba66e9116..62c790bcd196ed62958aac7a5832776987679552 100644 --- a/src/mapping.h +++ b/src/mapping.h @@ -390,6 +390,7 @@ int mapping_is_constant(struct mapping *m, struct processing *p); void free_all_mapping_blocks(void); +void o_append_mapping( INT32 args ); /* Prototypes end here */ #define allocate_mapping(X) dmalloc_touch(struct mapping *,debug_allocate_mapping(X)) diff --git a/src/treeopt.in b/src/treeopt.in index a66af5c311840f2fdfa5bb2f1ca8e0737ae8db63..4115308a46c769dc2f77dceb470e643cb637b86f 100644 --- a/src/treeopt.in +++ b/src/treeopt.in @@ -995,6 +995,21 @@ F_ADD_EQ(0, F_APPLY(F_CONSTANT [$$->u.sval.u.efun->function == debug_f_aggregate], 1)): F_APPEND_ARRAY($0, $1); + +// a += ([ args... ]) -> F_APPEND_MAPPING(a, args...) +F_ADD_EQ(0, F_APPLY(F_CONSTANT + [TYPEOF($$->u.sval) == T_FUNCTION] + [SUBTYPEOF($$->u.sval) == FUNCTION_BUILTIN] + [$$->u.sval.u.efun->function == f_aggregate_mapping], 1)): + F_APPEND_MAPPING($0, $1); + +// a += ([ args... ]) -> F_APPEND_MAPPING(a, args...) +F_OR_EQ(0, F_APPLY(F_CONSTANT + [TYPEOF($$->u.sval) == T_FUNCTION] + [SUBTYPEOF($$->u.sval) == FUNCTION_BUILTIN] + [$$->u.sval.u.efun->function == f_aggregate_mapping], 1)): + F_APPEND_MAPPING($0, $1); + F_INDEX(-, 0 = *): F_COMMA_EXPR(F_POP_VALUE($0, -), 0);