Example #1
0
 /**
  * Function that evaluates a given syntax tree
  * @param array $params
  * @param array $env Environment to be used
  * @return mixed Result
  */
 public function evaluate($params)
 {
     if (is_numeric($params)) {
         return (double) $params;
     } elseif (is_string($params)) {
         $ret = Common::findInEnv($this->env, $params);
         if ($ret === Common::NONE) {
             throw new Exception("undefined atom {$params}");
         } else {
             return $ret;
         }
     } elseif (!is_array($params)) {
         return $params;
     } elseif ($params[0] == 'quote') {
         if (count($params) != 2) {
             throw new Exception("bad syntax for quote");
         }
         return $params[1];
     } elseif ($params[0] == 'lambda') {
         if (count($params) != 3) {
             throw new Exception("bad syntax for lambda");
         }
         $parms = $params[1];
         $body = $params[2];
         $env = $this->env;
         return function ($args) use($parms, $body, $env) {
             $newEnv = new Environment(Common::zip($parms, $args));
             $x = new TinyLisp(array($newEnv, $env));
             return $x->evaluate($body);
         };
     } elseif ($params[0] == 'if') {
         if (count($params) != 4) {
             throw new Exception("bad syntax for if");
         }
         $ret = $this->evaluate($params[1]) ? $this->evaluate($params[2]) : $this->evaluate($params[3]);
         return $ret;
     } elseif ($params[0] == 'define') {
         if (count($params) != 3) {
             throw new Exception("bad syntax for define");
         }
         $multiple_scoped = false;
         foreach ($this->env as $key => $value) {
             if ($value instanceof Environment) {
                 $multiple_scoped = true;
                 break;
             }
         }
         $param = is_array($params[2]) ? $this->evaluate($params[2]) : $params[2];
         if ($multiple_scoped) {
             // multiple scopes, apply this only to the top most
             $this->env->v[0][$params[1]] = $param;
         } else {
             $this->env->v[$params[1]] = $param;
         }
     } elseif ($params[0] == 'print') {
         if (count($params) != 2) {
             throw new Exception("bad syntax for print");
         }
         print_r($this->evaluate($params[1]));
     } else {
         $proc = $this->evaluate($params[0]);
         $args = array();
         // for (define first car), $proc may return 'car', in which case we need to re-evaluate
         if (is_string($proc)) {
             array_shift($params);
             return $this->evaluate(array_merge(array($proc), $params));
         }
         for ($i = 1; $i < count($params); $i++) {
             $args[] = $this->evaluate($params[$i]);
         }
         if (is_callable($proc)) {
             return $proc($args);
         } elseif (is_array($proc) && method_exists($proc[0], $proc[1])) {
             return call_user_func_array($proc, array($args));
         } else {
             throw new Exception("Can't parse " . print_r($params, true));
         }
     }
 }