/** * Compiles the variable call in the specified context. It processes the containers, * assignments and other stuff directly related to the variables, returning an * SplFixedArray object with token information. * * @param array $variable The list of container elements * @param string $type The variable type * @param integer $weight The expression weight * @param integer $context The variable occurence context (normal, assignment, etc.) * @param string $contextInfo The information provided by the context * @param string $extra The support for object and array calls * @return SplFixedArray */ public function _compileVariable(array $variable, $type, $weight, $context = 0, $contextInfo = null, $extra = null) { $conversion = '##simplevar_'; $manager = $this->_compiler->getCdfManager(); $defaultFormat = null; if ($type == '@') { $conversion = '##var_'; $defaultFormat = 'TemplateVariable'; } $state = array('further' => false, 'section' => null); $answer = new SplFixedArray(4); $answer[2] = 'Scalar'; $answer[3] = 0; // If we have an assignment context, we must mark it in the created // expression node for the _finalize() method in order to choose // an appropriate expression type. if ($context == self::CONTEXT_ASSIGN) { $answer[3] = 1; } // The variable scanner $proc = null; if ($this->_compiler->isProcessor('section') !== null) { $proc = $this->_compiler->processor('section'); } $count = sizeof($variable); $final = $count - 1; $localWeight = 0; $code = ''; $path = ''; $previous = null; foreach ($variable as $id => $item) { // Handle conversions $previous = $path; if ($path == '') { // Parsing the first element. First, check the conversions. if (($to = $this->_compiler->convert($conversion . $item[0])) != $conversion . $item[0]) { $item = $to; } $path = $item; $state['first'] = true; } else { // Parsing one of the later elements $path .= '.' . $item; $state['first'] = false; } // Processing section calls if ($proc !== null) { if ($state['section'] === null) { // Check if any section with the specified name exists. $sectionName = $this->_compiler->convert($item[0]); if (($section = $proc->getSection($sectionName)) !== null) { $path = $sectionName; $state['section'] = $section; if ($id == $final) { // This is the last element $hook = 'section:item' . $this->_dfCalls[$context]; if (!$section['format']->property($hook)) { throw new Opt_OperationNotSupported_Exception($name, $this->_dfCalls[$context]); } $section['format']->assign('value', $contextInfo[0]); $section['format']->assign('code', $code); $code = $section['format']->get($hook); $localWeight = self::SECTION_ITEM_WEIGHT; break; } continue; } } else { // The section has been found, we need to process the item. // TODO: Perhaps INCREMENT and DECREMENT must have here a different code... // We must remember that the container call may be longer and they may refer // to the other part of the chain. $state['section']['format']->assign('item', $item); $hook = 'section:variable'; if ($id == $final) { $hook .= $this->_dfCalls[$context]; $section['format']->assign('value', $contextInfo[0]); $section['format']->assign('code', $code); if (!$section['format']->property($hook)) { throw new Opt_OperationNotSupported($name, $this->_dfCalls[$context]); } } $code = $section['format']->get($hook); $localWeight = self::SECTION_VARIABLE_WEIGHT; $state['section'] = null; continue; } } // Now, the normal container calls if ($id == 0) { // The first element processing $info = $this->_compiler->getContextStack()->top()->useVariable($item, $type, false, null); if ($info['replacement'] !== null) { $answer[0] = $info['replacement']; $answer[1] = Opt_Expression_Standard::SCALAR_WEIGHT; return $answer; } $format = $info['format']; $answer[2] = $format->getName(); if ($format->isDecorating()) { $answer[2] = $format; } if (!$format->supports('variable')) { throw new Opt_FormatNotSupported_Exception($format->getName(), 'variable'); } // Check if the format supports capturing the whole container if ($format->property('variable:capture')) { $format->assign('items', $variable); $format->assign('dynamic', $isDynamic); $hook = 'capture'; } else { $hook = 'item'; } $format->assign('item', $item); if ($context > 0) { $format->assign('value', $contextInfo[0]); $format->assign('code', $code); if (!$format->property('variable:' . $hook . $this->_dfCalls[$context])) { throw new Opt_OperationNotSupported_Exception($path, ltrim($this->_dfCalls[$context], '.')); } } $code = $format->get('variable:' . $hook . $this->_dfCalls[$context]); $localWeight = $count * self::CONTAINER_ITEM_WEIGHT; if ($hook == 'capture') { break; } } else { $format = $manager->getFormat('variable', $previous); $answer[2] = $format->getName(); if ($format->isDecorating()) { $answer[2] = $format; } $hook = 'item:item'; $format->assign('item', $item); if ($id == $final) { $hook .= $this->_dfCalls[$context]; $format->assign('value', $contextInfo[0]); $format->assign('code', $code); if ($context > 0 && !$format->property($hook)) { throw new Opt_OperationNotSupported_Exception($path, $this->_dfCalls[$context]); } $code .= $format->get($hook); } else { $code .= $format->get($hook); } $localWeight += self::CONTAINER_ITEM_WEIGHT; } } $answer[0] = $code; $answer[1] = $localWeight + $weight; return $answer; }
/** * This function is executed by the compiler before the second compilation stage, * processing. It migrates syntax from OPT 2.0 to OPT 2.1 */ public function preMigrate(Opt_Compiler_Class $compiler) { if ($compiler->isNamespace($this->getNamespace())) { $name = $this->getXmlName(); //$this->_processXml($compiler, false); // Look for the processor if (!is_null($processor = $compiler->isInstruction($name))) { $processor->migrateNode($this); } elseif ($compiler->isComponent($name)) { $processor = $compiler->processor('component'); $processor->migrateComponent($this); } elseif ($compiler->isBlock($name)) { $processor = $compiler->processor('block'); $processor->migrateBlock($this); } if (is_object($processor)) { $this->set('hidden', false); $compiler->setChildren($processor->getQueue()); } elseif ($this->get('processAll')) { $this->set('hidden', false); $compiler->setChildren($this); } else { // Remember to set the hidden state IF AND ONLY IF // it is not set. $this->get('hidden') === null and $this->set('hidden', true); } } else { $this->_processMigration($compiler); $this->set('hidden', false); if ($this->hasChildren()) { $compiler->setChildren($this); } } }