[#82] Arrow function and assign coalesce
This commit is contained in:
parent
0e55cb3b25
commit
7b4c72a3af
@ -4,9 +4,9 @@ package freefloating
|
||||
|
||||
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 {
|
||||
if i < 0 || i >= Position(len(_Position_index)-1) {
|
||||
|
@ -61,6 +61,7 @@ const (
|
||||
Else
|
||||
Variadic
|
||||
Function
|
||||
DoubleArrow
|
||||
Alias
|
||||
As
|
||||
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()
|
||||
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{
|
||||
FreeFloating: expected,
|
||||
},
|
||||
&assign.Coalesce{
|
||||
FreeFloating: expected,
|
||||
},
|
||||
&assign.Concat{
|
||||
FreeFloating: expected,
|
||||
},
|
||||
|
@ -56,6 +56,14 @@ var nodesToTest = []struct {
|
||||
[]string{"Variable", "Expression"},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
&assign.Coalesce{
|
||||
Variable: &expr.Variable{},
|
||||
Expression: &expr.Variable{},
|
||||
},
|
||||
[]string{"Variable", "Expression"},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
&assign.Concat{
|
||||
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{
|
||||
FreeFloating: expected,
|
||||
},
|
||||
&expr.ArrowFunction{
|
||||
FreeFloating: expected,
|
||||
},
|
||||
&expr.BitwiseNot{
|
||||
FreeFloating: expected,
|
||||
},
|
||||
|
@ -97,6 +97,18 @@ var nodesToTest = []struct {
|
||||
[]string{"Params", "ClosureUse", "ReturnType", "Stmts"},
|
||||
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{
|
||||
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> method_body
|
||||
%type <node> foreach_statement for_statement while_statement
|
||||
%type <node> inline_function
|
||||
%type <ClassExtends> extends_from
|
||||
%type <ClassImplements> implements_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_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_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:
|
||||
@ -3398,6 +3399,19 @@ expr_without_variable:
|
||||
yylex.(*Parser).MoveFreeFloating($1, $$)
|
||||
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)
|
||||
}
|
||||
| variable T_INC
|
||||
@ -4122,7 +4136,36 @@ expr_without_variable:
|
||||
|
||||
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)
|
||||
|
||||
@ -4154,36 +4197,31 @@ expr_without_variable:
|
||||
|
||||
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
|
||||
$$.SetPosition(yylex.(*Parser).positionBuilder.NewTokensPosition($1, $12))
|
||||
$$.SetPosition(yylex.(*Parser).positionBuilder.NewTokenNodePosition($1, $9))
|
||||
|
||||
// save comments
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Start, $1.FreeFloating)
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Static, $2.FreeFloating)
|
||||
if $3 == nil {
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Function, $5.FreeFloating)
|
||||
} else {
|
||||
if $2 == nil {
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Function, $3.FreeFloating)
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Ampersand, $5.FreeFloating)
|
||||
}
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.ParameterList, $7.FreeFloating)
|
||||
if $9 != nil {
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.LexicalVars, (*$9.GetFreeFloating())[freefloating.Colon]); delete((*$9.GetFreeFloating()), freefloating.Colon)
|
||||
}
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.ReturnType, $10.FreeFloating)
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Stmts, $12.FreeFloating)
|
||||
} else {
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Function, $2.FreeFloating)
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Ampersand, $3.FreeFloating)
|
||||
};
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.ParameterList, $5.FreeFloating)
|
||||
if $6 != nil {
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Params, (*$6.GetFreeFloating())[freefloating.Colon]); delete((*$6.GetFreeFloating()), freefloating.Colon)
|
||||
};
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.ReturnType, $8.FreeFloating)
|
||||
|
||||
// normalize
|
||||
if $9 == nil {
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.LexicalVars, (*$$.GetFreeFloating())[freefloating.ReturnType]); delete((*$$.GetFreeFloating()), freefloating.ReturnType)
|
||||
}
|
||||
if $8 == nil {
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Params, (*$$.GetFreeFloating())[freefloating.LexicalVarList]); delete((*$$.GetFreeFloating()), freefloating.LexicalVarList)
|
||||
}
|
||||
if $6 == nil {
|
||||
yylex.(*Parser).setFreeFloating($$, freefloating.Params, (*$$.GetFreeFloating())[freefloating.ReturnType]); delete((*$$.GetFreeFloating()), freefloating.ReturnType)
|
||||
};
|
||||
|
||||
yylex.(*Parser).returnTokenToPool(yyDollar, &yyVAL)
|
||||
}
|
||||
|
@ -135,6 +135,8 @@ func (p *Printer) printNode(n node.Node) {
|
||||
p.printAssignBitwiseOr(n)
|
||||
case *assign.BitwiseXor:
|
||||
p.printAssignBitwiseXor(n)
|
||||
case *assign.Coalesce:
|
||||
p.printAssignCoalesce(n)
|
||||
case *assign.Concat:
|
||||
p.printAssignConcat(n)
|
||||
case *assign.Div:
|
||||
@ -236,6 +238,8 @@ func (p *Printer) printNode(n node.Node) {
|
||||
p.printExprArrayItem(n)
|
||||
case *expr.Array:
|
||||
p.printExprArray(n)
|
||||
case *expr.ArrowFunction:
|
||||
p.printExprArrowFunction(n)
|
||||
case *expr.BitwiseNot:
|
||||
p.printExprBitwiseNot(n)
|
||||
case *expr.BooleanNot:
|
||||
@ -712,6 +716,17 @@ func (p *Printer) printAssignBitwiseXor(n node.Node) {
|
||||
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) {
|
||||
nn := n.(*assign.Concat)
|
||||
p.printFreeFloating(nn, freefloating.Start)
|
||||
@ -1313,6 +1328,45 @@ func (p *Printer) printExprArray(n node.Node) {
|
||||
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) {
|
||||
nn := n.(*expr.BitwiseNot)
|
||||
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 ;
|
||||
@ -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) {
|
||||
src := `<?php
|
||||
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) {
|
||||
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) {
|
||||
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;};
|
||||
'foreach'i => {lex.setTokenPosition(token); tok = T_FOREACH; 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;};
|
||||
'goto'i => {lex.setTokenPosition(token); tok = T_GOTO; 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_SR; 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* ('bool'i|'boolean'i) whitespace* ')' => {lex.setTokenPosition(token); tok = T_BOOL_CAST; fbreak;};
|
||||
|
Loading…
Reference in New Issue
Block a user