public function evaluate(AST\Node $expression, array $environment) : float { if ($expression instanceof AST\Constant) { return $expression->getValue(); } else { if ($expression instanceof AST\Variable) { if (!isset($environment[$expression->getName()])) { throw new \Exception("'{$expression->getName()} must be defined!"); } return $environment[$expression->getName()]; } else { if ($expression instanceof AST\Operator) { static $cachedOperators = []; if (!isset($cachedOperators[$expression->getKind()])) { $operatorFunction = create_function('$a, $b', 'return ' . OPERATORS[$expression->getKind()]['expression'] . ';'); $cachedOperators[$expression->getKind()] = $operatorFunction; } else { $operatorFunction = $cachedOperators[$expression->getKind()]; } $left = $this->evaluate($expression->getLeftOperand(), $environment); $right = $this->evaluate($expression->getRightOperand(), $environment); return $operatorFunction($left, $right); } else { if ($expression instanceof AST\FunctionCall) { $arguments = array_map(function ($argument) use($environment) { return $this->evaluate($argument, $environment); }, $expression->getArguments()); return FUNCTIONS[$expression->getName()]['phpFunction'](...$arguments); } else { throw new \Exception("Unexpected node type " . get_class($expression)); } } } } }
private function compileExpression(AST\Node $expression) : string { if ($expression instanceof AST\Constant) { return var_export($expression->getValue(), true); } else { if ($expression instanceof AST\Variable) { return '$' . $expression->getName(); } else { if ($expression instanceof AST\Operator) { $operatorTemplate = OPERATORS[$expression->getKind()]['expression']; $leftString = $this->compileExpression($expression->getLeftOperand()); $rightString = $this->compileExpression($expression->getRightOperand()); $string = preg_replace(['/\\$a/', '/\\$b/'], [$leftString, $rightString], $operatorTemplate); return '(' . $string . ')'; } else { if ($expression instanceof AST\FunctionCall) { $argumentStrings = array_map([$this, 'compileExpression'], $expression->getArguments()); $string = FUNCTIONS[$expression->getName()]['phpFunction'] . '(' . implode(',', $argumentStrings) . ')'; return $string; } else { throw new \Exception("Unexpected node type: {getclass({$expression})}"); } } } } }