[1011] in Coldmud discussion meeting

root meeting help first previous next last

[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];
  }