/* eval.c: evaluates nawmrc code */ /* Copyright (C) 1999 by the Massachusetts Institute of Technology. * * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" * without express or implied warranty. */ #include #include #include #include "nawm.h" #include "lang.h" #include "parser.h" nawmval run_fun(node *cmd); int eval_cmd(node *cmd); nawmval eval_expr(node *expr); int eval_comp(int op, dtype type, nawmval left, nawmval right); nawmval assignval(node *lval, nawmval val); extern int quit, screenwidth, screenheight; extern Window root; extern Display *dpy; nawmval returnval; typedef struct _runscope { nawmval *slots; struct _runscope *parent; } runscope; runscope *scopestack; void initrunscopes(void) { scopestack = NULL; } int eval_cmds(node *cmd) { int val; while (cmd) { val = eval_cmd(cmd); if (val) return val; cmd = cmd->next; } return 0; } int eval_cmd(node *cmd) { int ans = 0; if (!cmd) return 0; new_generation(); switch (cmd->type) { case RETURN: returnval = eval_expr(cmd->vals[0]); /* fall through */ case BREAK: case CONTINUE: ans = cmd->type; break; case IF: if (eval_expr(cmd->vals[0])) ans = eval_cmd(cmd->vals[1]); else ans = eval_cmd(cmd->vals[2]); break; case FOR: if (cmd->vals[0]->type == FOR) { node *fordata = cmd->vals[0]; eval_expr(fordata->vals[0]); while (eval_expr(fordata->vals[1])) { if (eval_cmd(cmd->vals[1]) == BREAK) break; eval_expr(fordata->vals[2]); } } else { arrayiter ai; array *arr = (array *)eval_expr(cmd->vals[0]->vals[1]); nawmval val; val = assignval(cmd->vals[0]->vals[0], array_first(arr, &ai)); while (val) { if (eval_cmd(cmd->vals[1]) == BREAK) break; val = assignval(cmd->vals[0]->vals[0], array_next(arr, &ai)); } } break; case WHILE: while (eval_expr(cmd->vals[0])) { if (eval_cmd(cmd->vals[1]) == BREAK) break; } break; case DO: do { if (eval_cmd(cmd->vals[1]) == BREAK) break; } while (eval_expr(cmd->vals[0])); break; case DEL: array_delete((array *)eval_expr(cmd->vals[0]), eval_expr(cmd->vals[1])); break; case CMD: run_fun(cmd); break; case BODY: ans = eval_cmds(cmd->vals[0]); break; default: eval_expr(cmd); break; } end_generation(); return ans; } nawmval eval_expr(node *expr) { switch (expr->type) { case NUM: case STR: return (nawmval)expr->vals[0]; case VAR: { variable *var = (variable *)expr->vals[0]; if (var->slot == -1) return var->data; else return scopestack->slots[var->slot]; } case SUBSCRIPT: return array_lookup((array *)eval_expr(expr->vals[0]), eval_expr(expr->vals[1])); case ELEMENT: return array_size((array *)eval_expr(expr->vals[0])); case ASSIGN: return assignval(expr->vals[0], eval_expr(expr->vals[1])); case PLUS: return eval_expr(expr->vals[0]) + eval_expr(expr->vals[1]); case NOP: return eval_expr(expr->vals[0]); case MINUS: return eval_expr(expr->vals[0]) - eval_expr(expr->vals[1]); case NEGATE: return -eval_expr(expr->vals[0]); case TIMES: return eval_expr(expr->vals[0]) * eval_expr(expr->vals[1]); case DIVIDE: return eval_expr(expr->vals[0]) / eval_expr(expr->vals[1]); case REMAINDER: return eval_expr(expr->vals[0]) % eval_expr(expr->vals[1]); case AND: return eval_expr(expr->vals[0]) && eval_expr(expr->vals[1]); case OR: return eval_expr(expr->vals[0]) || eval_expr(expr->vals[1]); case NOT: return !eval_expr(expr->vals[0]); case LESS: case LESSEQUAL: case GREATER: case GREATEREQUAL: case EQUAL: case NOTEQUAL: return eval_comp(expr->type, (dtype)expr->vals[2], eval_expr(expr->vals[0]), eval_expr(expr->vals[1])); case CONCAT: { char *left = (char *)eval_expr(expr->vals[0]); char *right = (char *)eval_expr(expr->vals[1]); char *ans = gcmalloc(strlen(left) + strlen(right) + 1, free); sprintf(ans, "%s%s", left, right); return (nawmval)ans; } case IN: return array_contains((array *)eval_expr(expr->vals[1]), eval_expr(expr->vals[0])); case FUN: return run_fun(expr); default: die("unexpected expression type"); } } int eval_comp(int op, dtype type, nawmval left, nawmval right) { if (type == T_WIN && (left || right)) { Window rootret, parent, *children, cw; unsigned int numchildren, n, l = 0, r = 0; XQueryTree(dpy, root, &rootret, &parent, &children, &numchildren); for (n = 0; n < numchildren; n++) { cw = client_window(children[n]); if (cw == (Window)left) l = (nawmval)n; if (cw == (Window)right) r = (nawmval)n; } XFree(children); left = l; right = r; /* fall through */ } if (type == T_INT || type == T_WIN) { switch (op) { case LESS: return left < right; case LESSEQUAL: return left <= right; case GREATER: return left > right; case GREATEREQUAL: return left >= right; case EQUAL: return left == right; case NOTEQUAL: return left != right; } } else { switch (op) { case LESS: return strcmp((char *)left, (char *)right) == -1; break; case LESSEQUAL: return strcmp((char *)left, (char *)right) != 1; break; case GREATER: return strcmp((char *)left, (char *)right) == 1; break; case GREATEREQUAL: return strcmp((char *)left, (char *)right) != -1; break; case EQUAL: return strcmp((char *)left, (char *)right) == 0; break; case NOTEQUAL: return strcmp((char *)left, (char *)right) != 0; break; } } /* can't happen */ return 0; } nawmval run_fun(node *n) { function *fun = (function *)(n->vals[0]); nawmval ans = 0; /* Initialize to make purify happy */ if (fun->numvars != -1) { runscope *scope; int i; node *expr; scope = xmalloc(sizeof(runscope)); scope->slots = xmalloc(fun->numvars * sizeof(nawmval)); memset(scope->slots, 0, fun->numvars * sizeof(nawmval)); /* assign variables */ for (i = 0, expr = n->vals[2]; i < fun->numargs; i++, expr = expr->next) scope->slots[i] = eval_expr(expr); for (; i < fun->numvars; i++) scope->slots[i] = initial_value(fun->vartype[i]); scope->parent = scopestack; scopestack = scope; returnval = 0; eval_cmds((node *)fun->body); ans = returnval; returnval = 0; scopestack = scope->parent; free(scope->slots); free(scope); } else { nawmval *argv; node *arg; int i, nargs; nargs = (nawmval)n->vals[1]; argv = xmalloc(nargs * sizeof(nawmval)); for (i = 0, arg = n->vals[2]; i < nargs; i++, arg = arg->next) argv[i] = eval_expr(arg); fun->body(nargs, argv, &ans); free(argv); } return ans; } nawmval assignval(node *lval, nawmval val) { if (lval->type == VAR) { variable *var = (variable *)lval->vals[0]; assign_var(var, val); } else { array *arr = (array *)eval_expr(lval->vals[0]); array_insert(arr, eval_expr(lval->vals[1]), val); } return val; } void assign_var(variable *var, nawmval val) { nawmval *loc; if (var->slot == -1) loc = &(var->data); else loc = &(scopestack->slots[var->slot]); if (!is_atomic_type(var->type)) { unref((void *)*loc); ref((void *)val); } *loc = val; }