[1011] in Coldmud discussion meeting
[COLD] List ops, take 2
daemon@ATHENA.MIT.EDU (Sat Jun 8 21:38:22 1996
)
Date: Sun, 9 Jun 1996 03:20:22 +0200
From: silovic@srce.hr (Miroslav Silovic)
To: brandon@tombstone.sunrem.com, coldstuff@cold.org
Ok, the first message didn't get through and it was my fault.
Here:
I proposed the new syntax. New expressions would be
<list> maplist <var> onto <expr>
loops var through the list, evals expr for each value and colects
them into a list
<list> mapindex <var> onto <expr>
same except that var will loop through indices insread of elements
<list> find <var> where <expr>
return the index of the first element of the list such that expr
is true
<list> filter <var> where <expr>
filter the elements of the list for which expr is true
EXAMPLE:
;;var a; .tell(( [1,2,3] maplist a onto ">>> "+a+" <<<" ).columnize(2));
>> 1 <<< >>> 2 <<<
>> 3 <<<
=> $user_miro
I'm totally open about the syntax of there. The two patches that
follow (one for src and the other for src/ops) are sample implementation
for maplist/onto keywords.
PATCH 1
--------------------------------------------------
diff -c old/Genesis-1.0p7/src/codegen.c Genesis-1.0p7/src/codegen.c
*** old/Genesis-1.0p7/src/codegen.c Fri Apr 5 04:57:52 1996
--- Genesis-1.0p7/src/codegen.c Sat Jun 8 23:24:35 1996
***************
*** 528,533 ****
--- 528,545 ----
return cnew;
}
+ Expr *map_expr(Expr *src, char *var, Expr *job)
+ {
+ Expr *cnew = PMALLOC(compiler_pile, Expr, 1);
+
+ cnew->type = OP_MAP;
+ cnew->lineno = cur_lineno();
+ cnew->u.map.src = src;
+ cnew->u.map.var = var;
+ cnew->u.map.job = job;
+ return cnew;
+ }
+
Expr *critical_expr(Expr *expr)
{
Expr *cnew = PMALLOC(compiler_pile, Expr, 1);
***************
*** 1378,1383 ****
--- 1390,1433 ----
compile_expr(expr->u.cond.false);
/* Set end_dest to here. */
+ set_jump_dest_here(end_dest);
+
+ break;
+ }
+
+ case OP_MAP: {
+ int n, begin_dest = new_jump_dest(), end_dest = new_jump_dest();
+
+ /* Find the variable in the method's local variables. */
+ n = find_local_var(expr->u.map.var);
+ if (n == -1) {
+ compiler_error(expr->lineno, "%s is not a local variable.",
+ expr->u.map.var);
+ break;
+ }
+
+ /* Compile the list expression, and code a ZERO opcode to push a zero
+ * value onto the stack. This will serve as the loop index. */
+ compile_expr(expr->u.map.src);
+ code(ZERO);
+
+ /* another ZERO for the initial returned value */
+ code(ZERO);
+
+ /* Set begin_dest to here, and begin the loop with a FOR_LIST opcode,
+ * with a jump argument pointing to the end of the loop. */
+ set_jump_dest_here(begin_dest);
+ code(OP_MAP);
+ code(end_dest);
+ code(n);
+
+ /* Compile the loop body. */
+ compile_expr(expr->u.map.job);
+
+ /* Code an END opcode with a jump argument pointing to the beginning
+ * of the loop, and set end_dest. */
+ code(END);
+ code(begin_dest);
set_jump_dest_here(end_dest);
break;
Common subdirectories: old/Genesis-1.0p7/src/data and Genesis-1.0p7/src/data
diff -c old/Genesis-1.0p7/src/decode.c Genesis-1.0p7/src/decode.c
*** old/Genesis-1.0p7/src/decode.c Tue Apr 23 03:28:45 1996
--- Genesis-1.0p7/src/decode.c Sun Jun 9 01:30:14 1996
***************
*** 106,133 ****
{ MULT_EQ, 1 },
{ DIV_EQ, 1 },
{ CONDITIONAL, 2 },
! { OR, 3 },
! { AND, 4 },
! { IN, 5 },
! { EQ, 6 },
! { NE, 6 },
! { '>', 6 },
! { GE, 6 },
! { '<', 6 },
! { LE, 6 },
! { '+', 7 },
! { '-', 7 },
! { '*', 8 },
! { '/', 8 },
! { '%', 8 },
! { '!', 9 },
! { NEG, 9 },
! { P_INCREMENT, 10 },
! { P_DECREMENT, 10 },
! { INCREMENT, 10 },
! { DECREMENT, 10 },
! { CALL_METHOD, 11 },
! { INDEX, 12 }
};
int line_number(method_t *method, int pc) {
--- 106,134 ----
{ MULT_EQ, 1 },
{ DIV_EQ, 1 },
{ CONDITIONAL, 2 },
! { OP_MAP, 3 },
! { OR, 4 },
! { AND, 5 },
! { IN, 6 },
! { EQ, 7 },
! { NE, 7 },
! { '>', 7 },
! { GE, 7 },
! { '<', 7 },
! { LE, 7 },
! { '+', 8 },
! { '-', 8 },
! { '*', 9 },
! { '/', 9 },
! { '%', 9 },
! { '!', 10 },
! { NEG, 10 },
! { P_INCREMENT, 11 },
! { P_DECREMENT, 11 },
! { INCREMENT, 11 },
! { DECREMENT, 11 },
! { CALL_METHOD, 12 },
! { INDEX, 13 }
};
int line_number(method_t *method, int pc) {
***************
*** 929,934 ****
--- 930,949 ----
break;
}
+ case OP_MAP: {
+ Expr_list *job;
+
+ end = the_opcodes[pos + 1];
+ s = varname(the_opcodes[pos + 2]);
+ pos+=3;
+ job = decompile_expressions_bounded(&pos, end - 2);
+ pos = end;
+ /* delete the two ZEROs */
+ stack = stack->next->next;
+ stack->expr = map_expr(stack->expr, s, job->expr);
+ break;
+ }
+
case CONDITIONAL: {
Expr_list *true, *false;
***************
*** 1543,1548 ****
--- 1558,1571 ----
str = unparse_expr_prec(str, expr->u.or.left, OR, 1);
str = string_add_chars(str, " || ", 4);
return unparse_expr_prec(str, expr->u.or.right, OR, 0);
+
+ case OP_MAP:
+ s = expr->u.map.var;
+ str = unparse_expr_prec(str, expr->u.map.src, OP_MAP, 1);
+ str = string_add_chars(str, " maplist ",9);
+ str = string_add_chars(str, s, strlen(s));
+ str = string_add_chars(str, " onto ",6);
+ return unparse_expr_prec(str, expr->u.map.job, OP_MAP, 0);
case CONDITIONAL:
str = unparse_expr_prec(str, expr->u.cond.cond, CONDITIONAL, 1);
diff -c old/Genesis-1.0p7/src/grammar.y Genesis-1.0p7/src/grammar.y
*** old/Genesis-1.0p7/src/grammar.y Thu Apr 25 22:16:38 1996
--- Genesis-1.0p7/src/grammar.y Sat Jun 8 23:24:33 1996
***************
*** 92,97 ****
--- 92,98 ----
%right MINUS_EQ DIV_EQ MULT_EQ PLUS_EQ
%left TO
%right OP_COND_IF ':' OP_COND_OTHER_ELSE
+ %right OP_MAP ONTO
%right OR
%right AND
%left IN
***************
*** 299,304 ****
--- 300,306 ----
| expr AND expr { $$ = and_expr($1, $3); }
| expr OR expr { $$ = or_expr($1, $3); }
| expr OP_COND_IF expr ':' expr { $$ = cond_expr($1, $3, $5); }
+ | expr OP_MAP IDENT ONTO expr { $$ = map_expr($1,$3,$5); }
| expr OP_COND_IF expr OP_COND_OTHER_ELSE expr { $$ = cond_expr($1, $3, $5); }
| IDENT MULT_EQ expr { $$ = doeq_expr(MULT_EQ, $1, $3); }
| IDENT DIV_EQ expr { $$ = doeq_expr(DIV_EQ, $1, $3); }
Common subdirectories: old/Genesis-1.0p7/src/include and Genesis-1.0p7/src/include
Common subdirectories: old/Genesis-1.0p7/src/modules and Genesis-1.0p7/src/modules
diff -c old/Genesis-1.0p7/src/opcodes.c Genesis-1.0p7/src/opcodes.c
*** old/Genesis-1.0p7/src/opcodes.c Fri Apr 26 19:10:11 1996
--- Genesis-1.0p7/src/opcodes.c Sun Jun 9 00:04:53 1996
***************
*** 75,80 ****
--- 75,81 ----
{ AND, "AND", op_and, JUMP },
{ OR, "OR", op_or, JUMP },
{ CONDITIONAL, "CONDITIONAL", op_if, JUMP },
+ { OP_MAP, "OP_MAP", op_map, JUMP, VAR },
{ SPLICE, "SPLICE", op_splice },
{ CRITICAL, "CRITICAL", op_critical, JUMP },
{ CRITICAL_END, "CRITICAL_END", op_critical_end },
Common subdirectories: old/Genesis-1.0p7/src/ops and Genesis-1.0p7/src/ops
diff -c old/Genesis-1.0p7/src/token.c Genesis-1.0p7/src/token.c
*** old/Genesis-1.0p7/src/token.c Sat Apr 20 20:05:19 1996
--- Genesis-1.0p7/src/token.c Sat Jun 8 21:46:30 1996
***************
*** 44,49 ****
--- 44,51 ----
{ "handler", HANDLER },
{ "if", IF },
{ "in", IN },
+ { "maplist", OP_MAP },
+ { "onto", ONTO },
{ "pass", PASS },
{ "return", RETURN },
{ "switch", SWITCH },
PATCH 2
-----------------------------------------------------
diff -c old/Genesis-1.0p7/src/ops/operators.c Genesis-1.0p7/src/ops/operators.c
*** old/Genesis-1.0p7/src/ops/operators.c Wed May 22 01:34:38 1996
--- Genesis-1.0p7/src/ops/operators.c Sun Jun 9 01:00:20 1996
***************
*** 72,77 ****
--- 72,142 ----
pop(1);
}
+ void op_map(void) {
+ data_t *returned;
+ data_t *counter;
+ data_t *domain;
+ int var, len, cnt;
+ list_t *pair;
+
+ returned = &stack[stack_pos - 1];
+ counter = &stack[stack_pos - 2];
+ domain = &stack[stack_pos - 3];
+ var = cur_frame->var_start + cur_frame->opcodes[cur_frame->pc + 1];
+
+ /* Make sure we're iterating over a list. We know the counter is okay. */
+ if (domain->type != LIST && domain->type != DICT) {
+ cthrow(type_id, "Domain (%D) is not a list or dictionary.", domain);
+ return;
+ }
+
+ len = (domain->type == LIST) ? list_length(domain->u.list)
+ : dict_size(domain->u.dict);
+
+ /* Prepare the mapping list in the first iteration */
+
+ if (counter->type == INTEGER) {
+ counter->type = LIST;
+ counter->u.list = list_new (len);
+ }
+
+ cnt = list_length(counter->u.list);
+
+ /* If counter is non-zero, there is a returned result from the
+ evaluation on top of the stack */
+
+ if (cnt) {
+ data_dup(list_last(counter->u.list), returned);
+ }
+
+ /* pop the returned value */
+
+ pop(1);
+
+ if (cnt >= len) {
+ /* We're finished; pop the domain and jump to the end. */
+
+ data_discard(domain);
+ data_dup(domain,counter);
+ pop(1);
+ cur_frame->pc = cur_frame->opcodes[cur_frame->pc];
+ return;
+ }
+ else
+ counter->u.list->len++;
+
+ /* Replace the index variable with the next list element */
+ data_discard(&stack[var]);
+ if (domain->type == LIST) {
+ data_dup(&stack[var], list_elem(domain->u.list, cnt));
+ } else {
+ pair = dict_key_value_pair(domain->u.dict, cnt);
+ stack[var].type = LIST;
+ stack[var].u.list = pair;
+ }
+ cur_frame->pc += 2;
+ }
+
void op_else(void) {
cur_frame->pc = cur_frame->opcodes[cur_frame->pc];
}