Skip to content

Commit 87df512

Browse files
committed
Added array argument type support
1 parent b9d72c0 commit 87df512

File tree

5 files changed

+248
-72
lines changed

5 files changed

+248
-72
lines changed

src/Coduo/PHPMatcher/Lexer.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ class Lexer extends AbstractLexer
99
const T_NONE = 1;
1010
const T_EXPANDER_NAME = 2;
1111
const T_CLOSE_PARENTHESIS = 3;
12-
const T_STRING = 4;
13-
const T_NUMBER = 5;
14-
const T_BOOLEAN = 6;
15-
const T_NULL = 7;
16-
const T_COMMA = 8;
17-
const T_TYPE_PATTERN = 9;
12+
const T_OPEN_CURLY_BRACE = 4;
13+
const T_CLOSE_CURLY_BRACE = 5;
14+
const T_STRING = 6;
15+
const T_NUMBER = 7;
16+
const T_BOOLEAN = 8;
17+
const T_NULL = 9;
18+
const T_COMMA = 10;
19+
const T_COLON = 11;
20+
const T_TYPE_PATTERN = 12;
1821

1922
/**
2023
* Lexical catchable patterns.
@@ -56,6 +59,12 @@ protected function getType(&$value)
5659
switch($value) {
5760
case ')':
5861
return self::T_CLOSE_PARENTHESIS;
62+
case '{':
63+
return self::T_OPEN_CURLY_BRACE;
64+
case '}':
65+
return self::T_CLOSE_CURLY_BRACE;
66+
case ':':
67+
return self::T_COLON;
5968
case ',':
6069
return self::T_COMMA;
6170
default:

src/Coduo/PHPMatcher/Parser.php

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ private function addArgumentValues(AST\Expander $expander)
194194
$this->lexer->moveNext();
195195

196196
if ($this->lexer->isNextToken(Lexer::T_CLOSE_PARENTHESIS)) {
197-
$this->unexpectedSyntaxError($this->lexer->lookahead, "string or number argument");
197+
$this->unexpectedSyntaxError($this->lexer->lookahead, "string, number, boolean or null argument");
198198
}
199199
}
200200
}
@@ -216,8 +216,12 @@ private function getNextArgumentValue()
216216
return ;
217217
}
218218

219+
if ($this->lexer->isNextToken(Lexer::T_OPEN_CURLY_BRACE)) {
220+
return $this->getArrayArgument();
221+
}
222+
219223
if (!$this->lexer->isNextTokenAny($validArgumentTypes)) {
220-
$this->unexpectedSyntaxError($this->lexer->lookahead, "string or number argument");
224+
$this->unexpectedSyntaxError($this->lexer->lookahead, "string, number, boolean or null argument");
221225
}
222226

223227
$tokenType = $this->lexer->lookahead['type'];
@@ -231,6 +235,63 @@ private function getNextArgumentValue()
231235
return $argument;
232236
}
233237

238+
/**
239+
* return array
240+
*/
241+
private function getArrayArgument()
242+
{
243+
$arrayArgument = array();
244+
$this->lexer->moveNext();
245+
246+
while ($this->getNextArrayElement($arrayArgument) !== null) {
247+
$this->lexer->moveNext();
248+
}
249+
250+
if (!$this->lexer->isNextToken(Lexer::T_CLOSE_CURLY_BRACE)) {
251+
$this->unexpectedSyntaxError($this->lexer->lookahead, "}");
252+
}
253+
254+
$this->lexer->moveNext();
255+
256+
return $arrayArgument;
257+
}
258+
259+
/**
260+
* @param array $array
261+
* @return bool
262+
* @throws PatternException
263+
*/
264+
private function getNextArrayElement(array &$array)
265+
{
266+
if ($this->lexer->isNextToken(Lexer::T_CLOSE_CURLY_BRACE)) {
267+
return ;
268+
}
269+
270+
$key = $this->getNextArgumentValue();
271+
if ($key === self::NULL_VALUE) {
272+
$key = "";
273+
}
274+
275+
if (!$this->lexer->isNextToken(Lexer::T_COLON)) {
276+
$this->unexpectedSyntaxError($this->lexer->lookahead, ":");
277+
}
278+
279+
$this->lexer->moveNext();
280+
281+
$value = $this->getNextArgumentValue();
282+
if ($value === self::NULL_VALUE) {
283+
$value = null;
284+
}
285+
286+
$array[$key] = $value;
287+
288+
if (!$this->lexer->isNextToken(Lexer::T_COMMA)) {
289+
return ;
290+
}
291+
292+
return true;
293+
}
294+
234295
/**
235296
* @return bool
236297
*/

tests/Coduo/PHPMatcher/LexerTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,30 @@ public function test_close_parenthesis()
126126
$this->assertEquals($lexer->lookahead['type'], Lexer::T_CLOSE_PARENTHESIS);
127127
}
128128

129+
public function test_close_open_brace()
130+
{
131+
$lexer = new Lexer();
132+
$lexer->setInput('{');
133+
$lexer->moveNext();
134+
$this->assertEquals($lexer->lookahead['type'], Lexer::T_OPEN_CURLY_BRACE);
135+
}
136+
137+
public function test_close_curly_brace()
138+
{
139+
$lexer = new Lexer();
140+
$lexer->setInput('}');
141+
$lexer->moveNext();
142+
$this->assertEquals($lexer->lookahead['type'], Lexer::T_CLOSE_CURLY_BRACE);
143+
}
144+
145+
public function test_colon()
146+
{
147+
$lexer = new Lexer();
148+
$lexer->setInput(':');
149+
$lexer->moveNext();
150+
$this->assertEquals($lexer->lookahead['type'], Lexer::T_COLON);
151+
}
152+
129153
public function test_comma()
130154
{
131155
$lexer = new Lexer();
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
namespace Coduo\PHPMatcher\Tests;
4+
5+
use Coduo\PHPMatcher\Lexer;
6+
use Coduo\PHPMatcher\Parser;
7+
8+
class ParserSyntaxErrorTest extends \PHPUnit_Framework_TestCase
9+
{
10+
/**
11+
* @var Parser
12+
*/
13+
private $parser;
14+
15+
public function setUp()
16+
{
17+
$this->parser = new Parser(new Lexer());
18+
}
19+
20+
/**
21+
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
22+
* @expectedExceptionMessage [Syntax Error] line 0, col 0: Error: Expected "@type@ pattern", got "not"
23+
*/
24+
public function test_unexpected_statement_at_type_position()
25+
{
26+
$this->parser->getAST("not_valid_type");
27+
}
28+
29+
/**
30+
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
31+
* @expectedExceptionMessage [Syntax Error] line 0, col 6: Error: Expected ".expanderName(args) definition", got "anything"
32+
*/
33+
public function test_unexpected_statement_instead_of_expander()
34+
{
35+
$this->parser->getAST("@type@anything");
36+
}
37+
38+
/**
39+
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
40+
* @expectedExceptionMessage [Syntax Error] line 0, col 14: Error: Expected ")", got end of string.end of string
41+
*/
42+
public function test_end_of_string_after_opening_parenthesis()
43+
{
44+
$this->parser->getAST("@[email protected](");
45+
}
46+
47+
/**
48+
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
49+
* @expectedExceptionMessage [Syntax Error] line 0, col 16: Error: Expected "string, number, boolean or null argument", got "not"
50+
*/
51+
public function test_not_argument_after_opening_parenthesis()
52+
{
53+
$this->parser->getAST("@[email protected](not_argument");
54+
}
55+
56+
/**
57+
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
58+
* @expectedExceptionMessage [Syntax Error] line 0, col 22: Error: Expected ")", got end of string.end of string
59+
*/
60+
public function test_missing_close_parenthesis_after_single_argument()
61+
{
62+
$this->parser->getAST("@[email protected]('string'");
63+
}
64+
65+
/**
66+
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
67+
* @expectedExceptionMessage [Syntax Error] line 0, col 26: Error: Expected ")", got end of string.end of string
68+
*/
69+
public function test_missing_close_parenthesis_after_multiple_arguments()
70+
{
71+
$this->parser->getAST("@[email protected]('string',1");
72+
}
73+
74+
/**
75+
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
76+
* @expectedExceptionMessage [Syntax Error] line 0, col 25: Error: Expected "string, number, boolean or null argument", got ")"
77+
*/
78+
public function test_missing_argument_after_comma()
79+
{
80+
$this->parser->getAST("@[email protected]('string',)");
81+
}
82+
83+
/**
84+
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
85+
* @expectedExceptionMessage [Syntax Error] line 0, col 25: Error: Expected "string, number, boolean or null argument", got "not"
86+
*/
87+
public function test_not_argument_after_comma()
88+
{
89+
$this->parser->getAST("@[email protected]('string',not_argument");
90+
}
91+
}

tests/Coduo/PHPMatcher/ParserTest.php

Lines changed: 55 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -70,74 +70,65 @@ public function test_many_expanders()
7070
}
7171

7272
/**
73-
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
74-
* @expectedExceptionMessage [Syntax Error] line 0, col 0: Error: Expected "@type@ pattern", got "not"
73+
* @dataProvider expandersWithArrayArguments
7574
*/
76-
public function test_unexpected_statement_at_type_position()
75+
public function test_single_array_argument_with_string_key_value($pattern, $expectedArgument)
7776
{
78-
$this->parser->getAST("not_valid_type");
79-
}
80-
81-
/**
82-
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
83-
* @expectedExceptionMessage [Syntax Error] line 0, col 6: Error: Expected ".expanderName(args) definition", got "anything"
84-
*/
85-
public function test_unexpected_statement_instead_of_expander()
86-
{
87-
$this->parser->getAST("@type@anything");
88-
}
89-
90-
/**
91-
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
92-
* @expectedExceptionMessage [Syntax Error] line 0, col 14: Error: Expected ")", got end of string.end of string
93-
*/
94-
public function test_end_of_string_after_opening_parenthesis()
95-
{
96-
$this->parser->getAST("@[email protected](");
97-
}
98-
99-
/**
100-
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
101-
* @expectedExceptionMessage [Syntax Error] line 0, col 16: Error: Expected "string or number argument", got "not"
102-
*/
103-
public function test_not_argument_after_opening_parenthesis()
104-
{
105-
$this->parser->getAST("@[email protected](not_argument");
106-
}
107-
108-
/**
109-
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
110-
* @expectedExceptionMessage [Syntax Error] line 0, col 22: Error: Expected ")", got end of string.end of string
111-
*/
112-
public function test_missing_close_parenthesis_after_single_argument()
113-
{
114-
$this->parser->getAST("@[email protected]('string'");
115-
}
116-
117-
/**
118-
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
119-
* @expectedExceptionMessage [Syntax Error] line 0, col 26: Error: Expected ")", got end of string.end of string
120-
*/
121-
public function test_missing_close_parenthesis_after_multiple_arguments()
122-
{
123-
$this->parser->getAST("@[email protected]('string',1");
124-
}
125-
126-
/**
127-
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
128-
* @expectedExceptionMessage [Syntax Error] line 0, col 25: Error: Expected "string or number argument", got ")"
129-
*/
130-
public function test_missing_argument_after_comma()
131-
{
132-
$this->parser->getAST("@[email protected]('string',)");
77+
$expanders = $this->parser->getAST($pattern)->getExpanders();
78+
$this->assertEquals($expectedArgument, $expanders[0]->getArguments());
13379
}
13480

135-
/**
136-
* @expectedException \Coduo\PHPMatcher\Exception\PatternException
137-
* @expectedExceptionMessage [Syntax Error] line 0, col 25: Error: Expected "string or number argument", got "not"
138-
*/
139-
public function test_not_argument_after_comma()
81+
public static function expandersWithArrayArguments()
14082
{
141-
$this->parser->getAST("@[email protected]('string',not_argument");
83+
return array(
84+
array(
85+
"@[email protected]({\"foo\":\"bar\"})",
86+
array(array("foo" => "bar"))
87+
),
88+
array(
89+
"@[email protected]({1 : \"bar\"})",
90+
array(array(1 => "bar"))
91+
),
92+
array(
93+
"@[email protected]({\"foo\":\"bar\"}, {\"foz\" : \"baz\"})",
94+
array(array("foo" => "bar"), array("foz" => "baz"))
95+
),
96+
array(
97+
"@[email protected]({1 : 1})",
98+
array(array(1 => 1))
99+
),
100+
array(
101+
"@[email protected]({1 : true})",
102+
array(array(1 => true))
103+
),
104+
array(
105+
"@[email protected]({1 : 1}, {1 : 1})",
106+
array(array(1 => 1), array(1 => 1))
107+
),
108+
array(
109+
"@[email protected]({1 : {\"foo\" : \"bar\"}}, {1 : 1})",
110+
array(array(1 => array("foo" => "bar")), array(1 => 1))
111+
),
112+
array(
113+
"@[email protected]({null: \"bar\"})",
114+
array(array("" => "bar"))
115+
),
116+
array(
117+
"@[email protected]({\"foo\": null})",
118+
array(array("foo" => null))
119+
),
120+
array(
121+
"@[email protected]({\"foo\" : \"bar\", \"foz\" : \"baz\"})",
122+
array(array("foo" => "bar", "foz" => "baz"))
123+
),
124+
array(
125+
"@[email protected]({\"foo\" : \"bar\", \"foo\" : \"baz\"})",
126+
array(array("foo" => "baz"))
127+
),
128+
array(
129+
"@[email protected]({\"foo\" : \"bar\", 1 : {\"first\" : 1, \"second\" : 2}})",
130+
array(array("foo" => "bar", 1 => array("first" => 1, "second" => 2)))
131+
)
132+
);
142133
}
143134
}

0 commit comments

Comments
 (0)