<?php require_once 'SugarFunction.php'; require_once '../AutoLoader.php'; if (!defined('sugarEntry')) { define('sugarEntry', true); } require_once 'include/entryPoint.php'; global $current_user; $current_user = BeanFactory::getBean("Users", "1"); $env = array('*' => array('SugarFunction', 'multiplication'), '+' => array('SugarFunction', 'addition'), 'new-bean' => array('SugarFunction', 'newBean'), 'get-bean' => array('SugarFunction', 'getBean'), 'get-property' => array('SugarFunction', 'getProperty'), 'execute-sql' => array('SugarFunction', 'executeSQL'), 'array-to-string' => array('SugarFunction', 'arrayToString')); echo "SugarScript LISP machine activated.\n"; echo "Example: (begin (define user (get-bean (quote Users) 1)) (print (get-property (quote is_admin) user)))\n"; echo "Example: (print (execute-sql (quote (select id, user_name from users))))\n"; echo "Example: (print (get-property (quote id) (new-bean (quote Users) (quote ((user_name a) (first_name Test))))))\n"; while (true) { echo "> "; try { $x = new TinyLisp($env); echo $x->run(readline()) . "\n"; } catch (Exception $e) { echo "ERROR: {$e->getMessage()}\n"; } }
/** * 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)); } } }