scriptbox

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

DslInterpreter.class.php (2381B)


      1 <?php
      2 
      3 namespace dsl\executor;
      4 
      5 use dsl\DslAstParser;
      6 use dsl\DslException;
      7 use dsl\DslLexer;
      8 use dsl\standard\Script;
      9 use dsl\standard\StandardArray;
     10 use dsl\standard\StandardDate;
     11 use dsl\standard\StandardMath;
     12 use dsl\standard\System;
     13 use dsl\standard\Write;
     14 
     15 class DslInterpreter
     16 {
     17 	/**
     18 	 * Execution context.
     19 	 *
     20 	 * @var array
     21 	 */
     22 	private $context = [];
     23 
     24 	/**
     25 	 * Holds a reference to the write()-Function for getting the output buffer after execution.
     26 	 * @var Write
     27 	 */
     28 	private $writer;
     29 	private $flags;
     30 
     31 	const FLAG_SHOW_ERROR  = 1;
     32 	const FLAG_SHOW_TRACE  = 2;
     33 	const FLAG_THROW_ERROR = 4;
     34 	const FLAG_DEBUG       = 8;
     35 
     36 	public function __construct( $flags = self::FLAG_SHOW_ERROR )
     37 	{
     38 		$this->flags = $flags;
     39 
     40 		// Standard-Globals
     41 		$this->addContext( [
     42 			'System'=> new System(),
     43 			'Math'  => new StandardMath(),
     44 			'Array' => new StandardArray(),
     45 			'Date'  => new StandardDate(),
     46 			'write' => $this->writer = new Write(),
     47 		] );
     48 	}
     49 
     50 	/**
     51 	 * adds an external context to the interpreter environment.
     52 	 *
     53 	 * @param $context []
     54 	 */
     55 	public function addContext($context ) {
     56 		$this->context = array_merge( $this->context, $context );
     57 	}
     58 
     59 
     60 	/**
     61 	 * Parses and runs the DSL code.
     62 	 *
     63 	 * @param $code String Script-Code
     64 	 * @throws DslException
     65 	 * @return mixed value of last return statement (if any)
     66 	 */
     67 	public function runCode( $code ) {
     68 
     69 		// Step 1: Splitting the source code into tokens (the "Lexer")
     70 		$lexer = new DslLexer();
     71 		$token = $lexer->tokenize( $code );
     72 
     73 		// Step 2: Creating a syntax tree (abstract syntax tree, AST).
     74 		try {
     75 
     76 			$parser = new DslAstParser();
     77 			$parser->parse( $token );
     78 
     79 			//if   ( $this->flags & self::FLAG_DEBUG )
     80 			// it has no security impact, so lets do it always.
     81 				$this->addContext(
     82 					[ 'Script' => new Script( $token,$parser->rootStatement ) ]
     83 				);
     84 
     85 			// Step 3: Executing the syntax tree.
     86 			return $parser->execute( $this->context );
     87 		} catch ( \Exception $e ) {
     88 			if   ( $this->flags & self::FLAG_SHOW_ERROR ) {
     89 				if   ( $this->flags & self::FLAG_SHOW_TRACE )
     90 					$this->writer->buffer .= $e->__toString();
     91 				else
     92 					$this->writer->buffer .= $e->getMessage();
     93 			}
     94 			if   ( $this->flags & self::FLAG_THROW_ERROR )
     95 				throw $e;
     96 		}
     97 	}
     98 
     99 
    100 	/**
    101 	 * Gets the output which was written by the code.
    102 	 *
    103 	 * @return mixed
    104 	 */
    105 	public function getOutput() {
    106 
    107 		return $this->writer->buffer;
    108 	}
    109 }