[#82] Arrow function and assign coalesce
This commit is contained in:
parent
0e55cb3b25
commit
7b4c72a3af
@ -4,9 +4,9 @@ package freefloating
|
|||||||
|
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
|
||||||
const _Position_name = "StartEndSlashColonSemiColonAltEndDollarAmpersandNamePrefixKeyVarUseTypeReturnTypeOptionalTypeCaseSeparatorLexicalVarsParamsRefCastExprInitExprCondExprIncExprTrueCondHaltCompillerNamespaceStaticClassUseWhileForSwitchBreakForeachDeclareLabelFinallyListDefaultIfElseIfElseVariadicFunctionAliasAsEqualExitArrayIssetEmptyEvalEchoTryCatchUnsetStmtsVarListConstListNameListParamListModifierListArrayPairListCaseListStartCaseListEndArgumentListPropertyListParameterListAdaptationListLexicalVarListUseDeclarationListOpenParenthesisTokenCloseParenthesisToken"
|
const _Position_name = "StartEndSlashColonSemiColonAltEndDollarAmpersandNamePrefixKeyVarUseTypeReturnTypeOptionalTypeCaseSeparatorLexicalVarsParamsRefCastExprInitExprCondExprIncExprTrueCondHaltCompillerNamespaceStaticClassUseWhileForSwitchBreakForeachDeclareLabelFinallyListDefaultIfElseIfElseVariadicFunctionDoubleArrowAliasAsEqualExitArrayIssetEmptyEvalEchoTryCatchUnsetStmtsVarListConstListNameListParamListModifierListArrayPairListCaseListStartCaseListEndArgumentListPropertyListParameterListAdaptationListLexicalVarListUseDeclarationListOpenParenthesisTokenCloseParenthesisToken"
|
||||||
|
|
||||||
var _Position_index = [...]uint16{0, 5, 8, 13, 18, 27, 33, 39, 48, 52, 58, 61, 64, 71, 81, 93, 106, 117, 123, 126, 130, 134, 142, 150, 157, 161, 165, 178, 187, 193, 198, 201, 206, 209, 215, 220, 227, 234, 239, 246, 250, 257, 259, 265, 269, 277, 285, 290, 292, 297, 301, 306, 311, 316, 320, 324, 327, 332, 337, 342, 349, 358, 366, 375, 387, 400, 413, 424, 436, 448, 461, 475, 489, 507, 527, 548}
|
var _Position_index = [...]uint16{0, 5, 8, 13, 18, 27, 33, 39, 48, 52, 58, 61, 64, 71, 81, 93, 106, 117, 123, 126, 130, 134, 142, 150, 157, 161, 165, 178, 187, 193, 198, 201, 206, 209, 215, 220, 227, 234, 239, 246, 250, 257, 259, 265, 269, 277, 285, 296, 301, 303, 308, 312, 317, 322, 327, 331, 335, 338, 343, 348, 353, 360, 369, 377, 386, 398, 411, 424, 435, 447, 459, 472, 486, 500, 518, 538, 559}
|
||||||
|
|
||||||
func (i Position) String() string {
|
func (i Position) String() string {
|
||||||
if i < 0 || i >= Position(len(_Position_index)-1) {
|
if i < 0 || i >= Position(len(_Position_index)-1) {
|
||||||
|
@ -61,6 +61,7 @@ const (
|
|||||||
Else
|
Else
|
||||||
Variadic
|
Variadic
|
||||||
Function
|
Function
|
||||||
|
DoubleArrow
|
||||||
Alias
|
Alias
|
||||||
As
|
As
|
||||||
Equal
|
Equal
|
||||||
|
66
node/expr/assign/n_coalesce.go
Normal file
66
node/expr/assign/n_coalesce.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package assign
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/z7zmey/php-parser/freefloating"
|
||||||
|
"github.com/z7zmey/php-parser/node"
|
||||||
|
"github.com/z7zmey/php-parser/position"
|
||||||
|
"github.com/z7zmey/php-parser/walker"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Coalesce node
|
||||||
|
type Coalesce struct {
|
||||||
|
FreeFloating freefloating.Collection
|
||||||
|
Position *position.Position
|
||||||
|
Variable node.Node
|
||||||
|
Expression node.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCoalesce node constructor
|
||||||
|
func NewCoalesce(Variable node.Node, Expression node.Node) *Coalesce {
|
||||||
|
return &Coalesce{
|
||||||
|
FreeFloating: nil,
|
||||||
|
Variable: Variable,
|
||||||
|
Expression: Expression,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPosition sets node position
|
||||||
|
func (n *Coalesce) SetPosition(p *position.Position) {
|
||||||
|
n.Position = p
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPosition returns node positions
|
||||||
|
func (n *Coalesce) GetPosition() *position.Position {
|
||||||
|
return n.Position
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Coalesce) GetFreeFloating() *freefloating.Collection {
|
||||||
|
return &n.FreeFloating
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributes returns node attributes as map
|
||||||
|
func (n *Coalesce) Attributes() map[string]interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk traverses nodes
|
||||||
|
// Walk is invoked recursively until v.EnterNode returns true
|
||||||
|
func (n *Coalesce) Walk(v walker.Visitor) {
|
||||||
|
if v.EnterNode(n) == false {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.Variable != nil {
|
||||||
|
v.EnterChildNode("Variable", n)
|
||||||
|
n.Variable.Walk(v)
|
||||||
|
v.LeaveChildNode("Variable", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.Expression != nil {
|
||||||
|
v.EnterChildNode("Expression", n)
|
||||||
|
n.Expression.Walk(v)
|
||||||
|
v.LeaveChildNode("Expression", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
v.LeaveNode(n)
|
||||||
|
}
|
@ -1272,3 +1272,73 @@ func TestShiftRight(t *testing.T) {
|
|||||||
actual = php5parser.GetRootNode()
|
actual = php5parser.GetRootNode()
|
||||||
assert.DeepEqual(t, expected, actual)
|
assert.DeepEqual(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCoalesce(t *testing.T) {
|
||||||
|
src := `<? $a ??= $b;`
|
||||||
|
|
||||||
|
expected := &node.Root{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 13,
|
||||||
|
},
|
||||||
|
Stmts: []node.Node{
|
||||||
|
&stmt.Expression{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 13,
|
||||||
|
},
|
||||||
|
Expr: &assign.Coalesce{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 12,
|
||||||
|
},
|
||||||
|
Variable: &expr.Variable{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 5,
|
||||||
|
},
|
||||||
|
VarName: &node.Identifier{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 5,
|
||||||
|
},
|
||||||
|
Value: "a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Expression: &expr.Variable{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 10,
|
||||||
|
EndPos: 12,
|
||||||
|
},
|
||||||
|
VarName: &node.Identifier{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 10,
|
||||||
|
EndPos: 12,
|
||||||
|
},
|
||||||
|
Value: "b",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
php7parser := php7.NewParser([]byte(src), "7.4")
|
||||||
|
php7parser.Parse()
|
||||||
|
actual := php7parser.GetRootNode()
|
||||||
|
assert.DeepEqual(t, expected, actual)
|
||||||
|
}
|
||||||
|
@ -41,6 +41,9 @@ var nodes = []node.Node{
|
|||||||
&assign.BitwiseXor{
|
&assign.BitwiseXor{
|
||||||
FreeFloating: expected,
|
FreeFloating: expected,
|
||||||
},
|
},
|
||||||
|
&assign.Coalesce{
|
||||||
|
FreeFloating: expected,
|
||||||
|
},
|
||||||
&assign.Concat{
|
&assign.Concat{
|
||||||
FreeFloating: expected,
|
FreeFloating: expected,
|
||||||
},
|
},
|
||||||
|
@ -56,6 +56,14 @@ var nodesToTest = []struct {
|
|||||||
[]string{"Variable", "Expression"},
|
[]string{"Variable", "Expression"},
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
&assign.Coalesce{
|
||||||
|
Variable: &expr.Variable{},
|
||||||
|
Expression: &expr.Variable{},
|
||||||
|
},
|
||||||
|
[]string{"Variable", "Expression"},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
&assign.Concat{
|
&assign.Concat{
|
||||||
Variable: &expr.Variable{},
|
Variable: &expr.Variable{},
|
||||||
|
88
node/expr/n_arrow_function.go
Normal file
88
node/expr/n_arrow_function.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/z7zmey/php-parser/freefloating"
|
||||||
|
"github.com/z7zmey/php-parser/node"
|
||||||
|
"github.com/z7zmey/php-parser/position"
|
||||||
|
"github.com/z7zmey/php-parser/walker"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ArrowFunction node
|
||||||
|
type ArrowFunction struct {
|
||||||
|
FreeFloating freefloating.Collection
|
||||||
|
Position *position.Position
|
||||||
|
ReturnsRef bool
|
||||||
|
Static bool
|
||||||
|
PhpDocComment string
|
||||||
|
Params []node.Node
|
||||||
|
ReturnType node.Node
|
||||||
|
Expr node.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewArrowFunction node constructor
|
||||||
|
func NewArrowFunction(Params []node.Node, ReturnType node.Node, Stmt node.Node, Static bool, ReturnsRef bool, PhpDocComment string) *ArrowFunction {
|
||||||
|
return &ArrowFunction{
|
||||||
|
FreeFloating: nil,
|
||||||
|
ReturnsRef: ReturnsRef,
|
||||||
|
Static: Static,
|
||||||
|
PhpDocComment: PhpDocComment,
|
||||||
|
Params: Params,
|
||||||
|
ReturnType: ReturnType,
|
||||||
|
Expr: Stmt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPosition sets node position
|
||||||
|
func (n *ArrowFunction) SetPosition(p *position.Position) {
|
||||||
|
n.Position = p
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPosition returns node positions
|
||||||
|
func (n *ArrowFunction) GetPosition() *position.Position {
|
||||||
|
return n.Position
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *ArrowFunction) GetFreeFloating() *freefloating.Collection {
|
||||||
|
return &n.FreeFloating
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributes returns node attributes as map
|
||||||
|
func (n *ArrowFunction) Attributes() map[string]interface{} {
|
||||||
|
return map[string]interface{}{
|
||||||
|
"ReturnsRef": n.ReturnsRef,
|
||||||
|
"Static": n.Static,
|
||||||
|
"PhpDocComment": n.PhpDocComment,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk traverses nodes
|
||||||
|
// Walk is invoked recursively until v.EnterNode returns true
|
||||||
|
func (n *ArrowFunction) Walk(v walker.Visitor) {
|
||||||
|
if v.EnterNode(n) == false {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.Params != nil {
|
||||||
|
v.EnterChildList("Params", n)
|
||||||
|
for _, nn := range n.Params {
|
||||||
|
if nn != nil {
|
||||||
|
nn.Walk(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.LeaveChildList("Params", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.ReturnType != nil {
|
||||||
|
v.EnterChildNode("ReturnType", n)
|
||||||
|
n.ReturnType.Walk(v)
|
||||||
|
v.LeaveChildNode("ReturnType", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.Expr != nil {
|
||||||
|
v.EnterChildNode("Expr", n)
|
||||||
|
n.Expr.Walk(v)
|
||||||
|
v.LeaveChildNode("Expr", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
v.LeaveNode(n)
|
||||||
|
}
|
144
node/expr/t_arrow_function_test.go
Normal file
144
node/expr/t_arrow_function_test.go
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package expr_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/z7zmey/php-parser/node"
|
||||||
|
"github.com/z7zmey/php-parser/node/expr"
|
||||||
|
"github.com/z7zmey/php-parser/node/name"
|
||||||
|
"github.com/z7zmey/php-parser/node/stmt"
|
||||||
|
"github.com/z7zmey/php-parser/php7"
|
||||||
|
"github.com/z7zmey/php-parser/position"
|
||||||
|
"gotest.tools/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestArrowFunction(t *testing.T) {
|
||||||
|
src := `<? fn() => $a;`
|
||||||
|
|
||||||
|
expected := &node.Root{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 14,
|
||||||
|
},
|
||||||
|
Stmts: []node.Node{
|
||||||
|
&stmt.Expression{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 14,
|
||||||
|
},
|
||||||
|
Expr: &expr.ArrowFunction{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 13,
|
||||||
|
},
|
||||||
|
ReturnsRef: false,
|
||||||
|
Static: false,
|
||||||
|
PhpDocComment: "",
|
||||||
|
Expr: &expr.Variable{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 11,
|
||||||
|
EndPos: 13,
|
||||||
|
},
|
||||||
|
VarName: &node.Identifier{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 11,
|
||||||
|
EndPos: 13,
|
||||||
|
},
|
||||||
|
Value: "a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
php7parser := php7.NewParser([]byte(src), "7.4")
|
||||||
|
php7parser.Parse()
|
||||||
|
actual := php7parser.GetRootNode()
|
||||||
|
assert.DeepEqual(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArrowFunctionReturnType(t *testing.T) {
|
||||||
|
src := `<? fn & () : foo => $a;`
|
||||||
|
|
||||||
|
expected := &node.Root{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 23,
|
||||||
|
},
|
||||||
|
Stmts: []node.Node{
|
||||||
|
&stmt.Expression{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 23,
|
||||||
|
},
|
||||||
|
Expr: &expr.ArrowFunction{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 3,
|
||||||
|
EndPos: 22,
|
||||||
|
},
|
||||||
|
Static: false,
|
||||||
|
PhpDocComment: "",
|
||||||
|
ReturnsRef: true,
|
||||||
|
ReturnType: &name.Name{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 13,
|
||||||
|
EndPos: 16,
|
||||||
|
},
|
||||||
|
Parts: []node.Node{
|
||||||
|
&name.NamePart{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 13,
|
||||||
|
EndPos: 16,
|
||||||
|
},
|
||||||
|
Value: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Expr: &expr.Variable{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 20,
|
||||||
|
EndPos: 22,
|
||||||
|
},
|
||||||
|
VarName: &node.Identifier{
|
||||||
|
Position: &position.Position{
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
StartPos: 20,
|
||||||
|
EndPos: 22,
|
||||||
|
},
|
||||||
|
Value: "a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
php7parser := php7.NewParser([]byte(src), "7.4")
|
||||||
|
php7parser.Parse()
|
||||||
|
actual := php7parser.GetRootNode()
|
||||||
|
assert.DeepEqual(t, expected, actual)
|
||||||
|
}
|
@ -35,6 +35,9 @@ var nodes = []node.Node{
|
|||||||
&expr.Array{
|
&expr.Array{
|
||||||
FreeFloating: expected,
|
FreeFloating: expected,
|
||||||
},
|
},
|
||||||
|
&expr.ArrowFunction{
|
||||||
|
FreeFloating: expected,
|
||||||
|
},
|
||||||
&expr.BitwiseNot{
|
&expr.BitwiseNot{
|
||||||
FreeFloating: expected,
|
FreeFloating: expected,
|
||||||
},
|
},
|
||||||
|
@ -97,6 +97,18 @@ var nodesToTest = []struct {
|
|||||||
[]string{"Params", "ClosureUse", "ReturnType", "Stmts"},
|
[]string{"Params", "ClosureUse", "ReturnType", "Stmts"},
|
||||||
map[string]interface{}{"ReturnsRef": true, "Static": false, "PhpDocComment": ""},
|
map[string]interface{}{"ReturnsRef": true, "Static": false, "PhpDocComment": ""},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
&expr.ArrowFunction{
|
||||||
|
ReturnsRef: true,
|
||||||
|
Static: false,
|
||||||
|
PhpDocComment: "",
|
||||||
|
Params: []node.Node{&node.Parameter{}},
|
||||||
|
ReturnType: &name.Name{},
|
||||||
|
Expr: &expr.Variable{},
|
||||||
|
},
|
||||||
|
[]string{"Params", "ReturnType", "Expr"},
|
||||||
|
map[string]interface{}{"ReturnsRef": true, "Static": false, "PhpDocComment": ""},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
&expr.ConstFetch{
|
&expr.ConstFetch{
|
||||||
Constant: &node.Identifier{Value: "foo"},
|
Constant: &node.Identifier{Value: "foo"},
|
||||||
|
4938
php7/php7.go
4938
php7/php7.go
File diff suppressed because it is too large
Load Diff
84
php7/php7.y
84
php7/php7.y
@ -271,6 +271,7 @@ import (
|
|||||||
%type <node> switch_case_list
|
%type <node> switch_case_list
|
||||||
%type <node> method_body
|
%type <node> method_body
|
||||||
%type <node> foreach_statement for_statement while_statement
|
%type <node> foreach_statement for_statement while_statement
|
||||||
|
%type <node> inline_function
|
||||||
%type <ClassExtends> extends_from
|
%type <ClassExtends> extends_from
|
||||||
%type <ClassImplements> implements_list
|
%type <ClassImplements> implements_list
|
||||||
%type <InterfaceExtends> interface_extends_list
|
%type <InterfaceExtends> interface_extends_list
|
||||||
@ -318,7 +319,7 @@ reserved_non_modifiers:
|
|||||||
| T_THROW {$$=$1} | T_USE {$$=$1} | T_INSTEADOF {$$=$1} | T_GLOBAL {$$=$1} | T_VAR {$$=$1} | T_UNSET {$$=$1} | T_ISSET {$$=$1} | T_EMPTY {$$=$1} | T_CONTINUE {$$=$1} | T_GOTO {$$=$1}
|
| T_THROW {$$=$1} | T_USE {$$=$1} | T_INSTEADOF {$$=$1} | T_GLOBAL {$$=$1} | T_VAR {$$=$1} | T_UNSET {$$=$1} | T_ISSET {$$=$1} | T_EMPTY {$$=$1} | T_CONTINUE {$$=$1} | T_GOTO {$$=$1}
|
||||||
| T_FUNCTION {$$=$1} | T_CONST {$$=$1} | T_RETURN {$$=$1} | T_PRINT {$$=$1} | T_YIELD {$$=$1} | T_LIST {$$=$1} | T_SWITCH {$$=$1} | T_ENDSWITCH {$$=$1} | T_CASE {$$=$1} | T_DEFAULT {$$=$1} | T_BREAK {$$=$1}
|
| T_FUNCTION {$$=$1} | T_CONST {$$=$1} | T_RETURN {$$=$1} | T_PRINT {$$=$1} | T_YIELD {$$=$1} | T_LIST {$$=$1} | T_SWITCH {$$=$1} | T_ENDSWITCH {$$=$1} | T_CASE {$$=$1} | T_DEFAULT {$$=$1} | T_BREAK {$$=$1}
|
||||||
| T_ARRAY {$$=$1} | T_CALLABLE {$$=$1} | T_EXTENDS {$$=$1} | T_IMPLEMENTS {$$=$1} | T_NAMESPACE {$$=$1} | T_TRAIT {$$=$1} | T_INTERFACE {$$=$1} | T_CLASS {$$=$1}
|
| T_ARRAY {$$=$1} | T_CALLABLE {$$=$1} | T_EXTENDS {$$=$1} | T_IMPLEMENTS {$$=$1} | T_NAMESPACE {$$=$1} | T_TRAIT {$$=$1} | T_INTERFACE {$$=$1} | T_CLASS {$$=$1}
|
||||||
| T_CLASS_C {$$=$1} | T_TRAIT_C {$$=$1} | T_FUNC_C {$$=$1} | T_METHOD_C {$$=$1} | T_LINE {$$=$1} | T_FILE {$$=$1} | T_DIR {$$=$1} | T_NS_C {$$=$1}
|
| T_CLASS_C {$$=$1} | T_TRAIT_C {$$=$1} | T_FUNC_C {$$=$1} | T_METHOD_C {$$=$1} | T_LINE {$$=$1} | T_FILE {$$=$1} | T_DIR {$$=$1} | T_NS_C {$$=$1} | T_FN {$$=$1}
|
||||||
;
|
;
|
||||||
|
|
||||||
semi_reserved:
|
semi_reserved:
|
||||||
@ -3398,6 +3399,19 @@ expr_without_variable:
|
|||||||
yylex.(*Parser).MoveFreeFloating($1, $$)
|
yylex.(*Parser).MoveFreeFloating($1, $$)
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.Var, $2.FreeFloating)
|
yylex.(*Parser).setFreeFloating($$, freefloating.Var, $2.FreeFloating)
|
||||||
|
|
||||||
|
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
||||||
|
}
|
||||||
|
| variable T_COALESCE_EQUAL expr
|
||||||
|
{
|
||||||
|
$$ = assign.NewCoalesce($1, $3)
|
||||||
|
|
||||||
|
// save position
|
||||||
|
$$.SetPosition(yylex.(*Parser).positionBuilder.NewNodesPosition($1, $3))
|
||||||
|
|
||||||
|
// save comments
|
||||||
|
yylex.(*Parser).MoveFreeFloating($1, $$)
|
||||||
|
yylex.(*Parser).setFreeFloating($$, freefloating.Var, $2.FreeFloating)
|
||||||
|
|
||||||
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
||||||
}
|
}
|
||||||
| variable T_INC
|
| variable T_INC
|
||||||
@ -4122,7 +4136,36 @@ expr_without_variable:
|
|||||||
|
|
||||||
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
||||||
}
|
}
|
||||||
| T_FUNCTION returns_ref backup_doc_comment '(' parameter_list ')' lexical_vars return_type '{' inner_statement_list '}'
|
| inline_function
|
||||||
|
{
|
||||||
|
$$ = $1;
|
||||||
|
|
||||||
|
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
||||||
|
}
|
||||||
|
| T_STATIC inline_function
|
||||||
|
{
|
||||||
|
$$ = $2;
|
||||||
|
|
||||||
|
switch n := $$.(type) {
|
||||||
|
case *expr.Closure :
|
||||||
|
n.Static = true;
|
||||||
|
case *expr.ArrowFunction :
|
||||||
|
n.Static = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// save position
|
||||||
|
$$.SetPosition(yylex.(*Parser).positionBuilder.NewTokenNodePosition($1, $2))
|
||||||
|
|
||||||
|
// save comments
|
||||||
|
yylex.(*Parser).setFreeFloating($$, freefloating.Static, (*$$.GetFreeFloating())[freefloating.Start]); delete((*$$.GetFreeFloating()), freefloating.Start)
|
||||||
|
yylex.(*Parser).setFreeFloating($$, freefloating.Start, $1.FreeFloating);
|
||||||
|
|
||||||
|
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
inline_function:
|
||||||
|
T_FUNCTION returns_ref backup_doc_comment '(' parameter_list ')' lexical_vars return_type '{' inner_statement_list '}'
|
||||||
{
|
{
|
||||||
$$ = expr.NewClosure($5, $7, $8, $10, false, $2 != nil, $3)
|
$$ = expr.NewClosure($5, $7, $8, $10, false, $2 != nil, $3)
|
||||||
|
|
||||||
@ -4154,36 +4197,31 @@ expr_without_variable:
|
|||||||
|
|
||||||
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
||||||
}
|
}
|
||||||
| T_STATIC T_FUNCTION returns_ref backup_doc_comment '(' parameter_list ')' lexical_vars return_type '{' inner_statement_list '}'
|
| T_FN returns_ref '(' parameter_list ')' return_type backup_doc_comment T_DOUBLE_ARROW expr
|
||||||
{
|
{
|
||||||
$$ = expr.NewClosure($6, $8, $9, $11, true, $3 != nil, $4)
|
$$ = expr.NewArrowFunction($4, $6, $9, false, $2 != nil, $7)
|
||||||
|
|
||||||
// save position
|
// save position
|
||||||
$$.SetPosition(yylex.(*Parser).positionBuilder.NewTokensPosition($1, $12))
|
$$.SetPosition(yylex.(*Parser).positionBuilder.NewTokenNodePosition($1, $9))
|
||||||
|
|
||||||
// save comments
|
// save comments
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.Start, $1.FreeFloating)
|
yylex.(*Parser).setFreeFloating($$, freefloating.Start, $1.FreeFloating)
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.Static, $2.FreeFloating)
|
if $2 == nil {
|
||||||
if $3 == nil {
|
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.Function, $5.FreeFloating)
|
|
||||||
} else {
|
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.Function, $3.FreeFloating)
|
yylex.(*Parser).setFreeFloating($$, freefloating.Function, $3.FreeFloating)
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.Ampersand, $5.FreeFloating)
|
} else {
|
||||||
}
|
yylex.(*Parser).setFreeFloating($$, freefloating.Function, $2.FreeFloating)
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.ParameterList, $7.FreeFloating)
|
yylex.(*Parser).setFreeFloating($$, freefloating.Ampersand, $3.FreeFloating)
|
||||||
if $9 != nil {
|
};
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.LexicalVars, (*$9.GetFreeFloating())[freefloating.Colon]); delete((*$9.GetFreeFloating()), freefloating.Colon)
|
yylex.(*Parser).setFreeFloating($$, freefloating.ParameterList, $5.FreeFloating)
|
||||||
}
|
if $6 != nil {
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.ReturnType, $10.FreeFloating)
|
yylex.(*Parser).setFreeFloating($$, freefloating.Params, (*$6.GetFreeFloating())[freefloating.Colon]); delete((*$6.GetFreeFloating()), freefloating.Colon)
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.Stmts, $12.FreeFloating)
|
};
|
||||||
|
yylex.(*Parser).setFreeFloating($$, freefloating.ReturnType, $8.FreeFloating)
|
||||||
|
|
||||||
// normalize
|
// normalize
|
||||||
if $9 == nil {
|
if $6 == nil {
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.LexicalVars, (*$$.GetFreeFloating())[freefloating.ReturnType]); delete((*$$.GetFreeFloating()), freefloating.ReturnType)
|
yylex.(*Parser).setFreeFloating($$, freefloating.Params, (*$$.GetFreeFloating())[freefloating.ReturnType]); delete((*$$.GetFreeFloating()), freefloating.ReturnType)
|
||||||
}
|
};
|
||||||
if $8 == nil {
|
|
||||||
yylex.(*Parser).setFreeFloating($$, freefloating.Params, (*$$.GetFreeFloating())[freefloating.LexicalVarList]); delete((*$$.GetFreeFloating()), freefloating.LexicalVarList)
|
|
||||||
}
|
|
||||||
|
|
||||||
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,8 @@ func (p *Printer) printNode(n node.Node) {
|
|||||||
p.printAssignBitwiseOr(n)
|
p.printAssignBitwiseOr(n)
|
||||||
case *assign.BitwiseXor:
|
case *assign.BitwiseXor:
|
||||||
p.printAssignBitwiseXor(n)
|
p.printAssignBitwiseXor(n)
|
||||||
|
case *assign.Coalesce:
|
||||||
|
p.printAssignCoalesce(n)
|
||||||
case *assign.Concat:
|
case *assign.Concat:
|
||||||
p.printAssignConcat(n)
|
p.printAssignConcat(n)
|
||||||
case *assign.Div:
|
case *assign.Div:
|
||||||
@ -236,6 +238,8 @@ func (p *Printer) printNode(n node.Node) {
|
|||||||
p.printExprArrayItem(n)
|
p.printExprArrayItem(n)
|
||||||
case *expr.Array:
|
case *expr.Array:
|
||||||
p.printExprArray(n)
|
p.printExprArray(n)
|
||||||
|
case *expr.ArrowFunction:
|
||||||
|
p.printExprArrowFunction(n)
|
||||||
case *expr.BitwiseNot:
|
case *expr.BitwiseNot:
|
||||||
p.printExprBitwiseNot(n)
|
p.printExprBitwiseNot(n)
|
||||||
case *expr.BooleanNot:
|
case *expr.BooleanNot:
|
||||||
@ -712,6 +716,17 @@ func (p *Printer) printAssignBitwiseXor(n node.Node) {
|
|||||||
p.printFreeFloating(nn, freefloating.End)
|
p.printFreeFloating(nn, freefloating.End)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Printer) printAssignCoalesce(n node.Node) {
|
||||||
|
nn := n.(*assign.Coalesce)
|
||||||
|
p.printFreeFloating(nn, freefloating.Start)
|
||||||
|
p.Print(nn.Variable)
|
||||||
|
p.printFreeFloating(nn, freefloating.Var)
|
||||||
|
io.WriteString(p.w, "??=")
|
||||||
|
p.Print(nn.Expression)
|
||||||
|
|
||||||
|
p.printFreeFloating(nn, freefloating.End)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Printer) printAssignConcat(n node.Node) {
|
func (p *Printer) printAssignConcat(n node.Node) {
|
||||||
nn := n.(*assign.Concat)
|
nn := n.(*assign.Concat)
|
||||||
p.printFreeFloating(nn, freefloating.Start)
|
p.printFreeFloating(nn, freefloating.Start)
|
||||||
@ -1313,6 +1328,45 @@ func (p *Printer) printExprArray(n node.Node) {
|
|||||||
p.printFreeFloating(nn, freefloating.End)
|
p.printFreeFloating(nn, freefloating.End)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Printer) printExprArrowFunction(n node.Node) {
|
||||||
|
nn := n.(*expr.ArrowFunction)
|
||||||
|
p.printFreeFloating(nn, freefloating.Start)
|
||||||
|
|
||||||
|
if nn.Static {
|
||||||
|
io.WriteString(p.w, "static")
|
||||||
|
}
|
||||||
|
p.printFreeFloating(nn, freefloating.Static)
|
||||||
|
if nn.Static && n.GetFreeFloating().IsEmpty() {
|
||||||
|
io.WriteString(p.w, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
io.WriteString(p.w, "fn")
|
||||||
|
p.printFreeFloating(nn, freefloating.Function)
|
||||||
|
|
||||||
|
if nn.ReturnsRef {
|
||||||
|
io.WriteString(p.w, "&")
|
||||||
|
}
|
||||||
|
p.printFreeFloating(nn, freefloating.Ampersand)
|
||||||
|
|
||||||
|
io.WriteString(p.w, "(")
|
||||||
|
p.joinPrint(",", nn.Params)
|
||||||
|
p.printFreeFloating(nn, freefloating.ParameterList)
|
||||||
|
io.WriteString(p.w, ")")
|
||||||
|
p.printFreeFloating(nn, freefloating.Params)
|
||||||
|
|
||||||
|
if nn.ReturnType != nil {
|
||||||
|
io.WriteString(p.w, ":")
|
||||||
|
p.Print(nn.ReturnType)
|
||||||
|
}
|
||||||
|
p.printFreeFloating(nn, freefloating.ReturnType)
|
||||||
|
|
||||||
|
io.WriteString(p.w, "=>")
|
||||||
|
|
||||||
|
p.printNode(nn.Expr)
|
||||||
|
|
||||||
|
p.printFreeFloating(nn, freefloating.End)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Printer) printExprBitwiseNot(n node.Node) {
|
func (p *Printer) printExprBitwiseNot(n node.Node) {
|
||||||
nn := n.(*expr.BitwiseNot)
|
nn := n.(*expr.BitwiseNot)
|
||||||
p.printFreeFloating(nn, freefloating.Start)
|
p.printFreeFloating(nn, freefloating.Start)
|
||||||
|
@ -270,6 +270,7 @@ func TestParseAndPrintAssign(t *testing.T) {
|
|||||||
$a &= $b ;
|
$a &= $b ;
|
||||||
$a |= $b ;
|
$a |= $b ;
|
||||||
$a ^= $b ;
|
$a ^= $b ;
|
||||||
|
$a ??= $b ;
|
||||||
$a .= $b ;
|
$a .= $b ;
|
||||||
$a /= $b ;
|
$a /= $b ;
|
||||||
$a -= $b ;
|
$a -= $b ;
|
||||||
@ -482,6 +483,18 @@ func TestParseAndPrintClosure(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseAndPrintArrowFunction(t *testing.T) {
|
||||||
|
src := `<?php
|
||||||
|
$a = static fn & ( $b ) : void => $c ;
|
||||||
|
`
|
||||||
|
|
||||||
|
actual := print(parse(src))
|
||||||
|
|
||||||
|
if src != actual {
|
||||||
|
t.Errorf("\nexpected: %s\ngot: %s\n", src, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseAndPrintConstFetch(t *testing.T) {
|
func TestParseAndPrintConstFetch(t *testing.T) {
|
||||||
src := `<?php
|
src := `<?php
|
||||||
null ;
|
null ;
|
||||||
|
@ -586,6 +586,27 @@ func TestPrinterPrintAssignBitwiseXor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrinterPrintAssignCoalesce(t *testing.T) {
|
||||||
|
o := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
p := printer.NewPrinter(o)
|
||||||
|
p.Print(&assign.Coalesce{
|
||||||
|
Variable: &expr.Variable{
|
||||||
|
VarName: &node.Identifier{Value: "a"},
|
||||||
|
},
|
||||||
|
Expression: &expr.Variable{
|
||||||
|
VarName: &node.Identifier{Value: "b"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expected := `$a??=$b`
|
||||||
|
actual := o.String()
|
||||||
|
|
||||||
|
if expected != actual {
|
||||||
|
t.Errorf("\nexpected: %s\ngot: %s\n", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPrinterPrintAssignConcat(t *testing.T) {
|
func TestPrinterPrintAssignConcat(t *testing.T) {
|
||||||
o := bytes.NewBufferString("")
|
o := bytes.NewBufferString("")
|
||||||
|
|
||||||
@ -1706,6 +1727,40 @@ func TestPrinterPrintExprClosure(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrinterPrintExprArrowFunction(t *testing.T) {
|
||||||
|
o := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
p := printer.NewPrinter(o)
|
||||||
|
p.Print(&stmt.Expression{
|
||||||
|
Expr: &expr.ArrowFunction{
|
||||||
|
Static: true,
|
||||||
|
ReturnsRef: true,
|
||||||
|
Params: []node.Node{
|
||||||
|
&node.Parameter{
|
||||||
|
ByRef: true,
|
||||||
|
Variadic: false,
|
||||||
|
Variable: &expr.Variable{
|
||||||
|
VarName: &node.Identifier{Value: "var"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReturnType: &name.FullyQualified{
|
||||||
|
Parts: []node.Node{&name.NamePart{Value: "Foo"}},
|
||||||
|
},
|
||||||
|
Expr: &expr.Variable{
|
||||||
|
VarName: &node.Identifier{Value: "a"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expected := `static fn&(&$var):\Foo=>$a;`
|
||||||
|
actual := o.String()
|
||||||
|
|
||||||
|
if expected != actual {
|
||||||
|
t.Errorf("\nexpected: %s\ngot: %s\n", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPrinterPrintExprConstFetch(t *testing.T) {
|
func TestPrinterPrintExprConstFetch(t *testing.T) {
|
||||||
o := bytes.NewBufferString("")
|
o := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
10039
scanner/scanner.go
10039
scanner/scanner.go
File diff suppressed because it is too large
Load Diff
@ -231,6 +231,7 @@ func (lex *Lexer) Lex(lval Lval) int {
|
|||||||
'for'i => {lex.setTokenPosition(token); tok = T_FOR; fbreak;};
|
'for'i => {lex.setTokenPosition(token); tok = T_FOR; fbreak;};
|
||||||
'foreach'i => {lex.setTokenPosition(token); tok = T_FOREACH; fbreak;};
|
'foreach'i => {lex.setTokenPosition(token); tok = T_FOREACH; fbreak;};
|
||||||
'function'i | 'cfunction'i => {lex.setTokenPosition(token); tok = T_FUNCTION; fbreak;};
|
'function'i | 'cfunction'i => {lex.setTokenPosition(token); tok = T_FUNCTION; fbreak;};
|
||||||
|
'fn'i => {lex.setTokenPosition(token); tok = T_FN; fbreak;};
|
||||||
'global'i => {lex.setTokenPosition(token); tok = T_GLOBAL; fbreak;};
|
'global'i => {lex.setTokenPosition(token); tok = T_GLOBAL; fbreak;};
|
||||||
'goto'i => {lex.setTokenPosition(token); tok = T_GOTO; fbreak;};
|
'goto'i => {lex.setTokenPosition(token); tok = T_GOTO; fbreak;};
|
||||||
'if'i => {lex.setTokenPosition(token); tok = T_IF; fbreak;};
|
'if'i => {lex.setTokenPosition(token); tok = T_IF; fbreak;};
|
||||||
@ -305,6 +306,7 @@ func (lex *Lexer) Lex(lval Lval) int {
|
|||||||
'<<' => {lex.setTokenPosition(token); tok = T_SL; fbreak;};
|
'<<' => {lex.setTokenPosition(token); tok = T_SL; fbreak;};
|
||||||
'>>' => {lex.setTokenPosition(token); tok = T_SR; fbreak;};
|
'>>' => {lex.setTokenPosition(token); tok = T_SR; fbreak;};
|
||||||
'??' => {lex.setTokenPosition(token); tok = T_COALESCE; fbreak;};
|
'??' => {lex.setTokenPosition(token); tok = T_COALESCE; fbreak;};
|
||||||
|
'??=' => {lex.setTokenPosition(token); tok = T_COALESCE_EQUAL; fbreak;};
|
||||||
|
|
||||||
'(' whitespace* 'array'i whitespace* ')' => {lex.setTokenPosition(token); tok = T_ARRAY_CAST; fbreak;};
|
'(' whitespace* 'array'i whitespace* ')' => {lex.setTokenPosition(token); tok = T_ARRAY_CAST; fbreak;};
|
||||||
'(' whitespace* ('bool'i|'boolean'i) whitespace* ')' => {lex.setTokenPosition(token); tok = T_BOOL_CAST; fbreak;};
|
'(' whitespace* ('bool'i|'boolean'i) whitespace* ')' => {lex.setTokenPosition(token); tok = T_BOOL_CAST; fbreak;};
|
||||||
|
Loading…
Reference in New Issue
Block a user