/**
  * @param string    $source
  * @param int       $pos
  *
  * @return int
  */
 public function parse($source, $pos = 0)
 {
     $this->length = 0;
     $this->match = '';
     $this->host = '';
     $this->item = '';
     $this->function = '';
     $p = $pos;
     if (!isset($source[$p]) || $source[$p] !== '{') {
         return self::PARSE_FAIL;
     }
     $p++;
     if (!$this->parseHost($source, $p)) {
         return self::PARSE_FAIL;
     }
     if (!isset($source[$p]) || $source[$p] !== ':') {
         return self::PARSE_FAIL;
     }
     $p++;
     $p2 = $p;
     if ($this->item_key_parser->parse($source, $p) == CParser::PARSE_FAIL) {
         return self::PARSE_FAIL;
     }
     $p += $this->item_key_parser->getLength();
     // for instance, agent.ping.last(0)
     if ($this->item_key_parser->getParamsNum() == 0 && isset($source[$p]) && $source[$p] == '(') {
         for (; $p > $p2 && $source[$p] != '.'; $p--) {
             // Code is not missing here.
         }
         if ($p == $p2) {
             return self::PARSE_FAIL;
         }
     }
     $p3 = $p;
     if (!isset($source[$p]) || $source[$p] !== '.') {
         return self::PARSE_FAIL;
     }
     $p++;
     if ($this->function_parser->parse($source, $p) == CParser::PARSE_FAIL) {
         return self::PARSE_FAIL;
     }
     $p += $this->function_parser->getLength();
     if (!isset($source[$p]) || $source[$p] !== '}') {
         return self::PARSE_FAIL;
     }
     $p++;
     $this->length = $p - $pos;
     $this->match = substr($source, $pos, $this->length);
     $this->host = substr($source, $pos + 1, $p2 - $pos - 2);
     $this->item = substr($source, $p2, $p3 - $p2);
     $this->function = $this->function_parser->getMatch();
     return isset($source[$pos + $this->length]) ? self::PARSE_SUCCESS_CONT : self::PARSE_SUCCESS;
 }
 /**
  * Resolves macros in the trigger function parameters.
  *
  * @param string $function	a trigger function
  * @param array  $macros	the list of macros (['{<MACRO>}' => '<value>', ...])
  * @param array  $types		the types of macros (see getMacroPositions() for more details)
  *
  * @return string
  */
 protected function resolveFunctionMacros($function, array $macros, array $types)
 {
     $function_parser = new CFunctionParser();
     if ($function_parser->parse($function) == CParser::PARSE_SUCCESS) {
         $params_raw = $function_parser->getParamsRaw();
         $function_chain = $params_raw['raw'];
         foreach (array_reverse($params_raw['parameters']) as $param_raw) {
             $param = $param_raw['raw'];
             $forced = false;
             switch ($param_raw['type']) {
                 case CFunctionParser::PARAM_QUOTED:
                     $param = CFunctionParser::unquoteParam($param);
                     $forced = true;
                     // break; is not missing here
                 // break; is not missing here
                 case CFunctionParser::PARAM_UNQUOTED:
                     $matched_macros = $this->getMacroPositions($param, $types);
                     foreach (array_reverse($matched_macros, true) as $pos => $macro) {
                         $param = substr_replace($param, $macros[$macro], $pos, strlen($macro));
                     }
                     $param = quoteFunctionParam($param, $forced);
                     break;
             }
             $function_chain = substr_replace($function_chain, $param, $param_raw['pos'], strlen($param_raw['raw']));
         }
         $function = substr_replace($function, $function_chain, $params_raw['pos'], strlen($params_raw['raw']));
     }
     return $function;
 }
 /**
  * Parses a trigger function macro constant in the trigger expression and
  * moves a current position ($this->pos) on a last symbol of the macro
  *
  * @return bool returns true if parsed successfully, false otherwise
  */
 private function parseFunctionMacro()
 {
     $startPos = $this->pos;
     if ($this->function_macro_parser->parse($this->expression, $this->pos) == CParser::PARSE_FAIL) {
         return false;
     }
     if ($this->function_parser->parse($this->function_macro_parser->getFunction()) == CParser::PARSE_FAIL) {
         return false;
     }
     $this->pos += $this->function_macro_parser->getLength() - 1;
     $function_param_list = [];
     for ($n = 0; $n < $this->function_parser->getParamsNum(); $n++) {
         $function_param_list[] = $this->function_parser->getParam($n);
     }
     $this->result->addToken(CTriggerExpressionParserResult::TOKEN_TYPE_FUNCTION_MACRO, $this->function_macro_parser->getMatch(), $startPos, $this->function_macro_parser->getLength(), ['host' => $this->function_macro_parser->getHost(), 'item' => $this->function_macro_parser->getItem(), 'function' => $this->function_macro_parser->getFunction(), 'functionName' => $this->function_parser->getFunction(), 'functionParams' => $function_param_list]);
     $this->expressions[] = ['expression' => $this->function_macro_parser->getMatch(), 'pos' => $startPos, 'host' => $this->function_macro_parser->getHost(), 'item' => $this->function_macro_parser->getItem(), 'function' => $this->function_macro_parser->getFunction(), 'functionName' => $this->function_parser->getFunction(), 'functionParam' => $this->function_parser->getParameters(), 'functionParamList' => $function_param_list];
     return true;
 }