parser: allow passing array items by ref

This commit is contained in:
Ryan Chandler 2022-12-05 13:55:35 +00:00
parent 5815f65737
commit b1f10231e0
No known key found for this signature in database
GPG Key ID: F113BCADDB3B0CCA
21 changed files with 307 additions and 4 deletions

View File

@ -814,6 +814,7 @@ pub struct ArrayItem {
pub key: Option<Expression>, pub key: Option<Expression>,
pub value: Expression, pub value: Expression,
pub unpack: bool, pub unpack: bool,
pub by_ref: bool,
} }
#[derive(Debug, Eq, PartialEq, Clone)] #[derive(Debug, Eq, PartialEq, Clone)]

View File

@ -1187,17 +1187,46 @@ impl Parser {
false false
}; };
let (mut by_ref, amper_span) = if state.current.kind == TokenKind::Ampersand
{
let span = state.current.span;
state.next();
(true, span)
} else {
(false, (0, 0))
};
let mut value = self.expression(state, Precedence::Lowest)?; let mut value = self.expression(state, Precedence::Lowest)?;
// TODO: return error for `[...$a => $b]`. // TODO: return error for `[...$a => $b]`.
if state.current.kind == TokenKind::DoubleArrow { if state.current.kind == TokenKind::DoubleArrow {
state.next(); state.next();
if by_ref {
return Err(ParseError::UnexpectedToken(
TokenKind::Ampersand.to_string(),
amper_span,
));
}
key = Some(value); key = Some(value);
by_ref = if state.current.kind == TokenKind::Ampersand {
state.next();
true
} else {
false
};
value = self.expression(state, Precedence::Lowest)?; value = self.expression(state, Precedence::Lowest)?;
} }
items.push(ArrayItem { key, value, unpack }); items.push(ArrayItem {
key,
value,
unpack,
by_ref,
});
if state.current.kind == TokenKind::Comma { if state.current.kind == TokenKind::Comma {
state.next(); state.next();
@ -1227,6 +1256,7 @@ impl Parser {
key: None, key: None,
value: Expression::Empty, value: Expression::Empty,
unpack: false, unpack: false,
by_ref: false,
}); });
state.next(); state.next();
continue; continue;
@ -1240,16 +1270,42 @@ impl Parser {
false false
}; };
let mut value = self.expression(state, Precedence::Lowest)?; let (mut by_ref, amper_span) = if state.current.kind == TokenKind::Ampersand
{
let span = state.current.span;
state.next();
(true, span)
} else {
(false, (0, 0))
};
let mut value = self.expression(state, Precedence::Lowest)?;
if state.current.kind == TokenKind::DoubleArrow { if state.current.kind == TokenKind::DoubleArrow {
state.next(); state.next();
if by_ref {
return Err(ParseError::UnexpectedToken(
TokenKind::Ampersand.to_string(),
amper_span,
));
}
key = Some(value); key = Some(value);
by_ref = if state.current.kind == TokenKind::Ampersand {
state.next();
true
} else {
false
};
value = self.expression(state, Precedence::Lowest)?; value = self.expression(state, Precedence::Lowest)?;
} }
items.push(ArrayItem { key, value, unpack }); items.push(ArrayItem {
key,
value,
unpack,
by_ref,
});
state.skip_comments(); state.skip_comments();
if state.current.kind == TokenKind::Comma { if state.current.kind == TokenKind::Comma {

View File

@ -37,6 +37,7 @@
}, },
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: Some( key: Some(
@ -66,6 +67,7 @@
}, },
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
], ],
}, },

View File

@ -70,6 +70,7 @@
name: "baz", name: "baz",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -77,6 +78,7 @@
name: "car", name: "car",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
], ],
}, },

View File

@ -8,6 +8,7 @@
i: 1, i: 1,
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -15,11 +16,13 @@
i: 2, i: 2,
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
value: Empty, value: Empty,
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -27,6 +30,7 @@
i: 4, i: 4,
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
], ],
}, },

View File

@ -8,6 +8,7 @@
items: [], items: [],
}, },
unpack: true, unpack: true,
by_ref: false,
}, },
], ],
}, },

View File

@ -12,10 +12,12 @@
i: 1, i: 1,
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
], ],
}, },
unpack: true, unpack: true,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -27,10 +29,12 @@
i: 2, i: 2,
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
], ],
}, },
unpack: true, unpack: true,
by_ref: false,
}, },
], ],
}, },

View File

@ -269,6 +269,7 @@
name: "value", name: "value",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -276,6 +277,7 @@
name: "last_message", name: "last_message",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
], ],
}, },

View File

@ -13,6 +13,7 @@
name: "a", name: "a",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -20,6 +21,7 @@
name: "b", name: "b",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -27,6 +29,7 @@
name: "c", name: "c",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -34,6 +37,7 @@
name: "d", name: "d",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
], ],
}, },

View File

@ -13,6 +13,7 @@
name: "a", name: "a",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -20,6 +21,7 @@
name: "b", name: "b",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -27,6 +29,7 @@
name: "c", name: "c",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
ArrayItem { ArrayItem {
key: None, key: None,
@ -34,6 +37,7 @@
name: "d", name: "d",
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
], ],
}, },

View File

@ -11,6 +11,7 @@
args: [], args: [],
}, },
unpack: false, unpack: false,
by_ref: false,
}, },
], ],
}, },

16
tests/0246/ast.txt Normal file
View File

@ -0,0 +1,16 @@
[
Expression {
expr: Array {
items: [
ArrayItem {
key: None,
value: Variable {
name: "foo",
},
unpack: false,
by_ref: true,
},
],
},
},
]

3
tests/0246/code.php Normal file
View File

@ -0,0 +1,3 @@
<?php
[&$foo];

48
tests/0246/tokens.txt Normal file
View File

@ -0,0 +1,48 @@
[
Token {
kind: OpenTag(
Full,
),
span: (
1,
1,
),
},
Token {
kind: LeftBracket,
span: (
3,
1,
),
},
Token {
kind: Ampersand,
span: (
3,
2,
),
},
Token {
kind: Variable(
"foo",
),
span: (
3,
3,
),
},
Token {
kind: RightBracket,
span: (
3,
7,
),
},
Token {
kind: SemiColon,
span: (
3,
8,
),
},
]

3
tests/0247/code.php Normal file
View File

@ -0,0 +1,3 @@
<?php
[&$foo => $bar];

View File

@ -0,0 +1 @@
UnexpectedToken("&", (3, 2)) -> Parse Error: Unexpected token & on line 3 column 2

64
tests/0247/tokens.txt Normal file
View File

@ -0,0 +1,64 @@
[
Token {
kind: OpenTag(
Full,
),
span: (
1,
1,
),
},
Token {
kind: LeftBracket,
span: (
3,
1,
),
},
Token {
kind: Ampersand,
span: (
3,
2,
),
},
Token {
kind: Variable(
"foo",
),
span: (
3,
3,
),
},
Token {
kind: DoubleArrow,
span: (
3,
8,
),
},
Token {
kind: Variable(
"bar",
),
span: (
3,
11,
),
},
Token {
kind: RightBracket,
span: (
3,
15,
),
},
Token {
kind: SemiColon,
span: (
3,
16,
),
},
]

20
tests/0248/ast.txt Normal file
View File

@ -0,0 +1,20 @@
[
Expression {
expr: Array {
items: [
ArrayItem {
key: Some(
Variable {
name: "foo",
},
),
value: Variable {
name: "bar",
},
unpack: false,
by_ref: true,
},
],
},
},
]

3
tests/0248/code.php Normal file
View File

@ -0,0 +1,3 @@
<?php
[$foo => &$bar];

64
tests/0248/tokens.txt Normal file
View File

@ -0,0 +1,64 @@
[
Token {
kind: OpenTag(
Full,
),
span: (
1,
1,
),
},
Token {
kind: LeftBracket,
span: (
3,
1,
),
},
Token {
kind: Variable(
"foo",
),
span: (
3,
2,
),
},
Token {
kind: DoubleArrow,
span: (
3,
7,
),
},
Token {
kind: Ampersand,
span: (
3,
10,
),
},
Token {
kind: Variable(
"bar",
),
span: (
3,
11,
),
},
Token {
kind: RightBracket,
span: (
3,
15,
),
},
Token {
kind: SemiColon,
span: (
3,
16,
),
},
]

View File

@ -40,7 +40,7 @@ fn third_party_3_symfony_framework() {
"src/Symfony/Component/Config/Tests/Fixtures/ParseError.php", "src/Symfony/Component/Config/Tests/Fixtures/ParseError.php",
// FIXME: Remove this one once I've found the energy to sort out heredocs / nowdocs. // FIXME: Remove this one once I've found the energy to sort out heredocs / nowdocs.
"src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php", "src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/LazyServiceDumper.php",
"src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php" "src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php",
], ],
); );
} }