From c28076f882698ff9839e2b826a1c98515f5bcd81 Mon Sep 17 00:00:00 2001 From: Per Hedbor <ph@opera.com> Date: Thu, 14 Aug 2014 17:32:45 +0200 Subject: [PATCH] Fixed some more cases of automap on the left side of an assignment. It more or less works as one would expect now. --- src/array.c | 54 +++++++++++++++++++++++++++++++++++++++ src/array.h | 4 +++ src/docode.c | 32 ++++++++++++++++++++++- src/interpret_functions.h | 21 +++++---------- 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/src/array.c b/src/array.c index a0aa7df036..72d692477e 100644 --- a/src/array.c +++ b/src/array.c @@ -2276,6 +2276,60 @@ PMOD_EXPORT struct array *append_array(struct array *a, struct svalue *s) return a; } +/** Automap assignments + * This implements X[*] = ...[*].. + * Assign elements in a at @level to elements from b at the same @level. + * This will not actually modify any of the arrays, only change the + * values in them. + */ +void assign_array_level( struct array *a, struct array *b, int level ) +{ + if( a->size != b->size ) + /* this should not really happen. */ + Pike_error("Source and destination differs in size in automap?!\n"); + + if( level > 1 ) + { + /* recurse. */ + unsigned int i; + for( i=0; i<a->size; i++ ) + { + if( TYPEOF(a->item[i]) != PIKE_T_ARRAY ) + Pike_error("Too many automap levels.\n"); + if( TYPEOF(b->item[i]) != PIKE_T_ARRAY ) /* obscure messages much? */ + Pike_error("Not enough levels of mapping in RHS\n"); + assign_array_level( a->item[i].u.array, b->item[i].u.array, level-1 ); + } + } + else + assign_svalues( a->item, b->item, a->size, a->type_field|b->type_field ); +} + +/* Assign all elemnts in a at level to b. + * This implements X[*] = expression without automap. + */ +void assign_array_level_value( struct array *a, struct svalue *b, int level ) +{ + unsigned int i; + if( level > 1 ) + { + /* recurse. */ + for( i=0; i<a->size; i++ ) + { + if( TYPEOF(a->item[i]) != PIKE_T_ARRAY ) + Pike_error("Too many automap levels.\n"); + assign_array_level_value( a->item[i].u.array, b, level-1 ); + } + } + else + { + if( a->type_field & BIT_REF_TYPES ) free_mixed_svalues( a->item, a->size ); + if( REFCOUNTED_TYPE(TYPEOF(*b)) ) *b->u.refs+=a->size; + for( i=0; i<a->size; i++) + a->item[i] = *b; + } +} + typedef char *(* explode_searchfunc)(void *,void *,size_t); /** Explode a string into an array by a delimiter. diff --git a/src/array.h b/src/array.h index 0ceaee5313..1333f70930 100644 --- a/src/array.h +++ b/src/array.h @@ -211,6 +211,10 @@ void debug_dump_array(struct array *a); void count_memory_in_arrays(size_t *num_, size_t *size_); PMOD_EXPORT struct array *explode_array(struct array *a, struct array *b); PMOD_EXPORT struct array *implode_array(struct array *a, struct array *b); + +/* Automap internals. */ +void assign_array_level_value( struct array *a, struct svalue *b, int level ); +void assign_array_level( struct array *a, struct array *b, int level ); /* Prototypes end here */ #define array_get_flags(a) ((a)->flags) diff --git a/src/docode.c b/src/docode.c index 8910c521be..edbd404558 100644 --- a/src/docode.c +++ b/src/docode.c @@ -430,6 +430,24 @@ static INT32 count_cases(node *n) } } +static int has_automap(node *n) +{ + if(!n) return 0; + switch(n->token) + { + case F_AUTO_MAP_MARKER: + case F_AUTO_MAP: + return 1; + + default: + if(car_is_node(n) && has_automap(CAR(n)) ) + return 1; + if( cdr_is_node(n) && has_automap(CDR(n)) ) + return 1; + } + return 0; +} + int generate_call_function(node *n) { @@ -1173,7 +1191,19 @@ static int do_docode2(node *n, int flags) do_docode(lval,0); /* note: not lvalue */ if(do_docode(CAR(n),0)!=1) yyerror("RHS is void!"); - emit1(F_ASSIGN_INDICES,depth); + + if( CAR(n)->token == F_AUTO_MAP_MARKER || + CAR(n)->token == F_AUTO_MAP || + /* Well, hello there... ;) */ + /* This is what is generated by a[*] += 10 and such. */ + (CAR(n)->token == F_SOFT_CAST && + has_automap(CAR(n)))) + { + emit1(F_ASSIGN_INDICES,depth); + } + else + emit1(F_ASSIGN_ALL_INDICES,depth); + if( flags & DO_POP ) emit0( F_POP_VALUE ); return !(flags&DO_POP); diff --git a/src/interpret_functions.h b/src/interpret_functions.h index 994b80790d..f7c52401cd 100644 --- a/src/interpret_functions.h +++ b/src/interpret_functions.h @@ -1102,25 +1102,18 @@ OPCODE0(F_ASSIGN, "assign", I_UPDATE_SP, { }); OPCODE1(F_ASSIGN_INDICES, "assign[]", I_UPDATE_SP, { - LOCAL_VAR(struct array *arr); - LOCAL_VAR(struct array *from); - LOCAL_VAR(int i); - - /* Note: All thse checks are presumably fairly pointless. */ if(TYPEOF(Pike_sp[-2]) != PIKE_T_ARRAY ) PIKE_ERROR("[*]=", "Destination is not an array.\n", Pike_sp, 1); - if(TYPEOF(Pike_sp[-1]) != PIKE_T_ARRAY ) PIKE_ERROR("[*]=", "Source is not an array.\n", Pike_sp-1, 1); + assign_array_level( Pike_sp[-2].u.array, Pike_sp[-1].u.array, arg1 ); + pop_stack(); /* leaves arr on stack. */ +}); - arr = Pike_sp[-2].u.array; - from = Pike_sp[-1].u.array; - - if( arr->size != from->size ) - Pike_error("Source and destination differs in size in automap.\n"); - - assign_svalues(arr->item,from->item,arr->size,arr->type_field|from->type_field); - +OPCODE1(F_ASSIGN_ALL_INDICES, "assign[*]", I_UPDATE_SP, { + if(TYPEOF(Pike_sp[-2]) != PIKE_T_ARRAY ) + PIKE_ERROR("[*]=", "Destination is not an array.\n", Pike_sp, 1); + assign_array_level_value( Pike_sp[-2].u.array, Pike_sp-1, arg1 ); pop_stack(); /* leaves arr on stack. */ }); -- GitLab