Beispiel #1
0
 public function Compile($sexp)
 {
     //$this->Emit(new StringExpression("// " . Expression::Render($sexp)));
     if ($sexp instanceof Symbol) {
         $this->Emit(new ReturnCE(new StringExpression("@\$env->environment['" . addslashes($sexp->name) . "'];")));
         return;
     } elseif (!is_array($sexp)) {
         $this->Emit(new ReturnCE(new CompiledExpression($sexp)));
         return;
     }
     $lambda = $sexp[0];
     $args = array_slice($sexp, 1);
     if (is_array($lambda)) {
         $evald = $this->Compile($lambda);
         //echo Expression::Render($lambda) . " ~~> " . Expression::Render($evald) . "\n";
         $lambda = $evald;
     }
     if ($lambda instanceof Symbol && ($val = @$this->environment[$lambda->name]) !== NULL) {
         $lambda = $val;
     }
     $phpName = NULL;
     if ($lambda instanceof Symbol) {
         $phpName = ($in = @self::$_internalNames[$lambda->name]) === NULL ? str_replace('-', '_', $lambda->name) : $in;
     }
     if ($lambda instanceof Macro) {
         $list = NULL;
         foreach ($lambda->expressions as $e) {
             // macro-expansion-time
             $applied = $lambda->arguments === NULL ? $e : $this->Apply($e, $lambda->arguments, $args);
             //echo Expression::Render($e) . " =APPLY=> " . Expression::Render($applied) . "\n";
             $expanded = $this->Evaluate($applied);
             //echo Expression::Render($applied) . " =MACROEXPAND=> " . Expression::Render($expanded) . "\n";
         }
         return $this->Compile($expanded);
     }
     if ($lambda instanceof Symbol) {
         // special forms (non-evaluated parameters)
         $specialForm = "lizp_special_form_{$phpName}";
         if (function_exists($specialForm)) {
             $this->Emit(new ReturnCE(new FunctionCallCE($specialForm, array("env", new CompiledExpression($args)))));
             return;
         }
     }
     // We evaluate the parameters
     $paramNames = array();
     $params = array();
     $expandNext = FALSE;
     $rand = rand(1, 1000000);
     foreach ($args as $i => $v) {
         if ($v instanceof AtSign) {
             $expandNext = TRUE;
             continue;
         }
         $this->Compile($v);
         $this->Emit(new LoadCE("param_{$rand}_{$i}"));
         if ($expandNext && is_array($r)) {
             $params = array_merge($params, $r);
         } else {
             $params[] = "\$param_{$rand}_{$i}";
             //r;
             $paramNames[] = "param_{$rand}_{$i}";
             //r;
         }
         $expandNext = FALSE;
     }
     if ($lambda instanceof Lambda) {
         $r = NULL;
         foreach ($lambda->expressions as $e) {
             $args = array();
             foreach ($params as $i) {
                 if (is_array($i)) {
                     $i = array(Symbol::Make('quote'), $i);
                 }
                 $args[] = $i;
             }
             //$params = $args;
             $applied = $lambda->arguments === NULL ? $e : $this->Apply($e, $lambda->arguments, $params);
             //echo Expression::Render($e) . " -APPLY-> " . Expression::Render($applied) . "\n";
             // $r =
             $this->Compile($applied);
             //echo Expression::Render($applied) . " -EVAL-> " . Expression::Render($r) . "\n";
         }
         return;
         // $r
     }
     if ($lambda instanceof Symbol) {
         // internal functions / php functions
         $internalFn = "lizp_internal_fn_{$phpName}";
         if (($isInternal = function_exists($internalFn)) || function_exists($phpName)) {
             if ($isInternal) {
                 $this->Emit(new ReturnCE(new FunctionCallCE($internalFn, array("env", new StringExpression("array(" . implode(', ', $params) . ")")))));
                 return;
             }
             $this->Emit(new ReturnCE(new FunctionCallCE($phpName, $paramNames)));
             $this->Emit(new StringExpression('if (is_array($r) && count($r) == 0) $r = NULL;'));
             return;
         }
     }
     $this->Emit("/* Unable to evaluate Expression: " . Expression::Render($sexp) . " because function name evaluates to " . Expression::Render($lambda) . " */");
 }
Beispiel #2
0
 public static function Parse(&$s, &$position = NULL)
 {
     if ($position === NULL) {
         $pos = $position = 0;
     } else {
         $pos = $position;
     }
     $len = strlen($s);
     $tokens = array();
     $didClose = FALSE;
     $qStack = array();
     $qSymbol = Symbol::Make('quote');
     $qqSymbol = Symbol::Make('quasiquote');
     $append = FALSE;
     for (;;) {
         // append any expressions to our list
         if ($append !== FALSE) {
             while (count($qStack) > 0) {
                 $qChar = array_pop($qStack);
                 switch ($qChar) {
                     case "'":
                         $append = array($qSymbol, $append);
                         break;
                     case "`":
                         $append = is_array($append) ? array_merge(array($qqSymbol), $append) : array($qSymbol, $append);
                         break;
                 }
             }
             $tokens[] = $append;
             $append = FALSE;
         }
         // end reached?
         if ($pos >= $len) {
             break;
         }
         // closing?
         if ($s[$pos] == ')') {
             if ($position === 0) {
                 throw new Exception("Missing (!");
             }
             $didClose = TRUE;
             $pos++;
             break;
         }
         // consume whitespace
         if (preg_match('/\\s/', $s[$pos])) {
             $pos++;
             continue;
         }
         // consume comments
         if ($s[$pos] == ';') {
             if (($nl = strpos($s, "\n", $pos)) !== FALSE) {
                 $pos = $nl;
             }
             $pos++;
             continue;
         }
         // open paren
         if ($s[$pos] == '(') {
             $p = $pos + 1;
             $append = self::Parse($s, $p);
             $pos = $p;
             continue;
         }
         // quote and quasiquote
         if ($s[$pos] == "`" || $s[$pos] == "'") {
             array_push($qStack, $s[$pos]);
             $pos++;
             continue;
         }
         // tilde
         if ($s[$pos] == "~") {
             $append = new Tilde();
             $pos++;
             continue;
         }
         // at sign
         if ($s[$pos] == "@") {
             $append = new AtSign();
             $pos++;
             continue;
         }
         // from here on i'll need an actual substring,
         // because the regexp functions do not allow matching
         // at a specified offset only. :(
         $sub = substr($s, $pos);
         // consume strings
         if (preg_match('/^"((?:\\\\"|[^"])*)"/s', $sub, $m)) {
             $append = stripslashes($m[1]);
             $pos += strlen($m[1]) + 2;
             continue;
         }
         // consume integers
         if (preg_match('/^([+-]?[0-9]+)/s', $sub, $m)) {
             $append = (int) $m[1];
             $pos += strlen($m[1]);
             continue;
         }
         // consume symbols
         if (preg_match('/^([^0-9][^\\s\\(\\)\\[\\]\\{\\}]*)/s', $sub, $m)) {
             $sname = $m[1];
             $supper = strtoupper($sname);
             if ($supper == 'T') {
                 $append = TRUE;
             } elseif ($supper == 'NIL') {
                 $append = NULL;
             } else {
                 $symbol = new Symbol();
                 $symbol->name = $sname;
                 $append = $symbol;
             }
             $pos += strlen($sname);
             continue;
         }
         throw new Exception("Unexpected character at pos {$pos}: {$s[$pos]}");
     }
     if ($position !== 0 && !$didClose) {
         throw new Exception("Missing )!");
     }
     $position = $pos;
     return empty($tokens) ? NULL : $tokens;
 }
Beispiel #3
0
function lizp_special_form_defmacro($env, $args)
{
    if (!@$args[0] instanceof Symbol || !(is_array(@$args[1]) || @$args[1] === NULL || @$args[1] === FALSE)) {
        throw new Exception("Syntax Error: (DEFMACRO <id> (<params>*) <expr>*)");
    }
    $lambda = new Macro();
    $lambda->arguments = empty($args[1]) ? NULL : $args[1];
    $lambda->expressions = array_slice($args, 2);
    $env->environment[$args[0]->name] = $lambda;
    return Symbol::Make($args[0]->name);
}
Beispiel #4
0
function lizp_internal_fn_map($env, $args)
{
    if (count($args) !== 2 || !($args[0] instanceof Lambda || $args[0] instanceof Symbol) || !is_array($args[1]) && $args[1] !== NULL) {
        throw new Exception("syntax: (MAP <lambda> <list>)");
    }
    $r = array();
    foreach ((array) $args[1] as $i => $v) {
        $r[] = $env->Evaluate(array($args[0], array(Symbol::Make('quote'), $v), array(Symbol::Make('quote'), $i)));
    }
    return empty($r) ? NULL : $r;
}