openrat-cms

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

DslInterpreter.class.php (2811B)


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