null
/** * @throws SyntaxErrorException */ public function render() { if (!$this->_containsInterpolation($this->_text)) { return $this->_text; } $pieces = array(); $glueL = $this->_phpCtx ? '.' : '<?php echo '; $glueR = $this->_phpCtx ? '.' : ' ?>'; $encapsL = $this->_phpCtx ? '(' : ''; $encapsR = $this->_phpCtx ? ')' : ';'; $s = new StringScanner($this->_text); $quote = $s->scan(StringScanner::rQUOTE); while (!$s->eos) { trim($s->scan('/(.*?)(?<!\\\\)\\#\\{/sm')); if (!empty($s[1])) { $pieces[] = $quote . $s[1] . $quote; } trim($s->scan('/(.*?)(?<!\\\\)}/sm')); if (!empty($s[1])) { if ($this->_containsInterpolation($s[1])) { throw new SyntaxErrorException("Nesting interpolation is not allowed: " . $this->_text); } $pieces[] = $glueL; $pieces[] = $encapsL . $s[1] . $encapsR; $pieces[] = $glueR; } else { throw new SyntaxErrorException("Unclosed interpolation in: " . $this->_text); } if (!$this->_containsInterpolation($s->rest)) { $rest = trim($s->scan('/.*/sm'), " {$quote}"); if (!empty($rest)) { $pieces[] = $quote . $rest . $quote; } } } if ($this->_phpCtx) { // can't have glue on the edges if ($pieces[0] == $glueL) { array_shift($pieces); } // can't have glue on the edges if ($pieces[count($pieces) - 1] == $glueR) { array_pop($pieces); } // don't nee the parenteses if it is only one thing if (count($pieces) == 1) { $pieces[0] = s($pieces[0])->trimBalanced('(', ')'); } } return join($pieces); }
public function testUnscan() { $s = new StringScanner('test string'); $this->assertEquals('test', $s->scan('/\\w+/')); $s->unscan(); $this->assertEquals('te', $s->scan('/../')); $this->assertNull($s->scan('/\\d/')); try { $s->unscan(); # ScanError: unscan failed: previous match record not exist } catch (Exception $e) { } $this->assertNotNull($e); $s->reset(); $this->assertEquals('test ', $s->scan('/\\w+\\s/')); $this->assertEquals('st', $s->scan('/st/')); $this->assertEquals('ri', $s->scan('/ri/')); $s->unscan(); $this->assertEquals(7, $s->pos); $this->assertEquals('ri', $s->scan('/ri/')); }
function testOtag() { $sc = new StringScanner("{{foo}}{{bla}}"); $res = $sc->scan("{{"); $this->assertEqual($res, "{{"); $this->assertEqual($sc->rest(), "foo}}{{bla}}"); $res = $sc->scan("[#^\\/=!<>^{]"); $this->assertEqual($res, null); $this->assertEqual($sc->rest(), "foo}}{{bla}}"); }
/** * @param StringScanner $scanner * @return array an array with the parsed elements */ private function _parseHashAttrs(StringScanner $scanner) { $atts = array('class' => array(), 'id' => array()); $litRe = '/(["\\\']).*?\\2(?=[\\s|=])|:?[\\-\\w:]*/'; $scanner->scan('/\\s*\\{?\\s*/'); while (!$scanner->scan('/}/')) { $scanner->scan('/\\s*/'); $name = trim($scanner->scan($litRe), ':"\''); if (!$name) { throw new SyntaxErrorException("Invalid attribute list. Expecting an attribute name"); } if (!$scanner->scan('/\\s*=>\\s*/')) { // it's an attribute function if (!($scanner->rest[0] == '(')) { throw new SyntaxErrorException("Invalid attribute list. Either missing attribute function parameters or attribute value"); } list($balanced, $value, $rest, $count) = $this->balance($scanner, '(', ')', 0); if (!$balanced) { throw new SyntaxErrorException("Unbalanced brackets in attribute function"); } $value = $name . $value; $name = 'fn_' . count($atts); $atts[$name] = array('t' => 'function', 'v' => $value); $scanner->scan('/\\s*,\\s*/'); continue; } switch ($scanner->rest[0]) { case '"': case "'": $quote = $scanner->scan('/["\']/'); $scanner->scan("/(.*?[^\\\\]){$quote}/"); $value = $scanner[1]; if ($name == 'class' || $name == 'id') { $atts[$name][] = array('t' => 'str', 'v' => $scanner[1]); } else { $atts[$name] = array('t' => 'str', 'v' => $quote . $value . $quote); } break; case '[': $value = $scanner->scanUntil('/\\]/'); $items = mb_substr($value, 1, -1); if ($name == 'class' || $name == 'id') { $atts[$name][] = array('t' => 'php', 'v' => "array({$items})"); } else { $atts[$name] = array('t' => 'php', 'v' => "array({$items})"); } break; case '$': $value = $scanner->scanUntil('/(?=[,\\}])/'); if ($name == 'class' || $name == 'id') { $atts[$name][] = array('t' => 'php', 'v' => $value); } else { $atts[$name] = array('t' => 'str', 'v' => '"#{' . $value . '}"'); } break; case '{': list($balanced, $value, $rest, $count) = $this->balance($scanner, '{', '}', 0); if ($name == 'data') { $data_arr = $this->_parseHashAttrs(new StringScanner($value)); foreach ($data_arr as $key => $val) { $atts["data-{$key}"] = $val; } } else { $value = mb_substr($value, 1, -1); if ($name == 'class' || $name == 'id') { $atts[$name][] = array('t' => 'php', 'v' => $value); } else { $atts[$name] = array('t' => 'php', 'v' => $value); } } break; default: if ($scanner->scan('/true|false/i')) { if ($scanner[0] == 'true') { $atts[$name] = array('t' => 'static', 'v' => true); } else { $atts[$name] = array('t' => 'static', 'v' => false); } } else { $value = trim($scanner->scanUntil('/(?=[,\\}])/')); if ($name == 'class' || $name == 'id') { $atts[$name][] = array('t' => 'php', 'v' => $value); } else { $atts[$name] = array('t' => 'str', 'v' => $value); } } } $scanner->scan('/\\s*,?\\s*/'); if ($scanner->eos) { $next_line = ' ' . trim($this->_compiler->getNextLine()); $scanner->concat($next_line); } } if (count($atts['id']) == 0) { unset($atts['id']); } if (count($atts['class']) == 0) { unset($atts['class']); } return $atts; }