Example #1
0
 /**
  * Uses the specified variable within the context.
  *
  * @param string $variable The variable name.
  * @param boolean $isGlobal Is the variable global or local?
  * @param string $contextFormat The format enforced by the occurence context.
  * @return array
  */
 public function useVariable($variable, $type, $isGlobal, $contextFormat = null)
 {
     if (!isset($this->_variables[$type . $variable])) {
         // In this case the variable has not been used yet. We must check
         // if the user have not selected any format for it, calculate the
         // default format and modify the context format.
         $manager = $this->_compiler->getCdfManager();
         try {
             // In case of template variables, we should not check the data formats
             // because we would run into several problems. We immediately jump to the
             // format resolution algorithm.
             if ($type == '@') {
                 throw new Exception();
             }
             // OK, look for a variable
             $this->_variables[$type . $variable] = $manager->getFormat('variable', $variable, $this);
             return array('format' => $this->_variables[$type . $variable], 'replacement' => null, 'cast' => null);
         } catch (Exception $exception) {
             if ($contextFormat === null) {
                 // This is very strange. It seems that someone has used
                 // an uninitialized variable, so we can set it to null and
                 // report it as an unused variable.
                 Opt_Support::warning('Uninitialized variable ' . $variable . ' - casting to NULL');
                 return array('format' => null, 'replacement' => 'null');
             } else {
                 $manager->addFormat('variable', $variable, $contextFormat, $this->getElementLocation('variable', $variable));
                 $this->_variables[$type . $variable] = $manager->getFormat('variable', $variable, $this);
                 return array('format' => $this->_variables[$type . $variable], 'replacement' => null, 'cast' => null);
             }
         }
     } else {
         // The variable has already been used. We must match the
         // previously selected format.
         if ($contextFormat !== null) {
             return array('format' => $this->_variables[$type . $variable], 'replacement' => null, 'cast' => $this->_variables[$type . $variable]->getName());
         } else {
             return array('format' => $this->_variables[$type . $variable], 'replacement' => null);
         }
     }
 }
Example #2
0
 /**
  * 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;
 }