/** * @param CompilationContext $compilationContext * @throws CompilerException */ public function compile(CompilationContext $compilationContext) { $readDetector = new ReadDetector(); $statement = $this->_statement; foreach ($statement['assignments'] as $assignment) { $variable = $assignment['variable']; /** * Get the symbol from the symbol table if necessary */ switch ($assignment['assign-type']) { case 'static-property': case 'static-property-append': case 'static-property-array-index': case 'static-property-array-index-append': case 'dynamic-variable-string': $symbolVariable = null; break; case 'array-index': case 'variable-append': case 'object-property': case 'array-index-append': case 'string-dynamic-object-property': case 'variable-dynamic-object-property': $symbolVariable = $compilationContext->symbolTable->getVariableForUpdate($variable, $compilationContext, $assignment); break; default: $symbolVariable = $compilationContext->symbolTable->getVariableForWrite($variable, $compilationContext, $assignment); break; } /** * Incr/Decr assignments don't require an expression */ if (isset($assignment['expr'])) { $expr = new Expression($assignment['expr']); switch ($assignment['assign-type']) { case 'variable': if (!$readDetector->detect($variable, $assignment['expr'])) { if (isset($assignment['operator'])) { if ($assignment['operator'] == 'assign') { $expr->setExpectReturn(true, $symbolVariable); } } else { $expr->setExpectReturn(true, $symbolVariable); } } else { if (isset($assignment['operator'])) { if ($assignment['operator'] == 'assign') { $expr->setExpectReturn(true); } } else { $expr->setExpectReturn(true); } } break; } switch ($assignment['expr']['type']) { case 'property-access': case 'array-access': case 'type-hint': $expr->setReadOnly(true); break; } $resolvedExpr = $expr->compile($compilationContext); /** * Bad implemented operators could return values different than objects */ if (!is_object($resolvedExpr)) { throw new CompilerException("Resolved expression is not valid", $assignment['expr']); } } /** * There are four types of assignments */ switch ($assignment['assign-type']) { case 'variable': $let = new LetVariable(); $let->assign($variable, $symbolVariable, $resolvedExpr, $readDetector, $compilationContext, $assignment); break; case 'variable-append': $let = new LetVariableAppend(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; case 'object-property': $let = new LetObjectProperty(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; case 'variable-dynamic-object-property': $let = new LetObjectDynamicProperty(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; case 'string-dynamic-object-property': $let = new LetObjectDynamicStringProperty(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; case 'static-property': $let = new LetStaticProperty(); $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment); break; case 'static-property-append': $let = new LetStaticPropertyAppend(); $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment); break; case 'static-property-array-index': $let = new LetStaticPropertyArrayIndex(); $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment); break; case 'static-property-array-index-append': $let = new LetStaticPropertyArrayIndexAppend(); $let->assignStatic($variable, $assignment['property'], $resolvedExpr, $compilationContext, $assignment); break; case 'array-index': $let = new LetArrayIndex(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; case 'array-index-append': $let = new LetArrayIndexAppend(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; case 'object-property-append': $let = new LetObjectPropertyAppend(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; case 'object-property-array-index': $let = new LetObjectPropertyArrayIndex(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; case 'object-property-array-index-append': $let = new LetObjectPropertyArrayIndexAppend(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; case 'incr': $let = new LetIncr(); $let->assign($variable, $symbolVariable, $compilationContext, $assignment); break; case 'decr': $let = new LetDecr(); $let->assign($variable, $symbolVariable, $compilationContext, $assignment); break; case 'object-property-incr': $let = new LetObjectPropertyIncr(); $let->assign($variable, $assignment['property'], $symbolVariable, $compilationContext, $assignment); break; case 'object-property-decr': $let = new LetObjectPropertyDecr(); $let->assign($variable, $assignment['property'], $symbolVariable, $compilationContext, $assignment); break; case 'dynamic-variable': $let = new LetExportSymbol(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; case 'dynamic-variable-string': $let = new LetExportSymbolString(); $let->assign($variable, $symbolVariable, $resolvedExpr, $compilationContext, $assignment); break; default: throw new CompilerException("Unknown assignment: " . $assignment['assign-type'], $assignment); } } }