Logo Search packages:      
Sourcecode: nawm version File versions  Download package

eval.c

/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

Generated by  Doxygen 1.6.0   Back to index