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 }