Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions internal/php5/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
)

type ParserBrackets struct {
ast.AttributeBag
Position *position.Position
OpenBracketTkn *token.Token
Child ast.Vertex
Expand All @@ -22,6 +23,7 @@ func (parserBrackets *ParserBrackets) GetPosition() *position.Position {
}

type ParserSeparatedList struct {
ast.AttributeBag
Position *position.Position
Items []ast.Vertex
SeparatorTkns []*token.Token
Expand All @@ -37,6 +39,7 @@ func (parserSeparatedList *ParserSeparatedList) GetPosition() *position.Position

// TraitAdaptationList node
type TraitAdaptationList struct {
ast.AttributeBag
Position *position.Position
OpenCurlyBracketTkn *token.Token
Adaptations []ast.Vertex
Expand All @@ -53,6 +56,7 @@ func (traitAdaptationList *TraitAdaptationList) GetPosition() *position.Position

// ArgumentList node
type ArgumentList struct {
ast.AttributeBag
Position *position.Position
OpenParenthesisTkn *token.Token
Arguments []ast.Vertex
Expand All @@ -70,6 +74,7 @@ func (argumentList *ArgumentList) GetPosition() *position.Position {

// TraitMethodRef node
type TraitMethodRef struct {
ast.AttributeBag
Position *position.Position
Trait ast.Vertex
DoubleColonTkn *token.Token
Expand Down
6 changes: 6 additions & 0 deletions internal/php7/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
)

type ParserBrackets struct {
ast.AttributeBag
Position *position.Position
OpenBracketTkn *token.Token
Child ast.Vertex
Expand All @@ -22,6 +23,7 @@ func (parserBrackets *ParserBrackets) GetPosition() *position.Position {
}

type ParserSeparatedList struct {
ast.AttributeBag
Position *position.Position
Items []ast.Vertex
SeparatorTkns []*token.Token
Expand All @@ -37,6 +39,7 @@ func (parserSeparatedList *ParserSeparatedList) GetPosition() *position.Position

// TraitAdaptationList node
type TraitAdaptationList struct {
ast.AttributeBag
Position *position.Position
OpenCurlyBracketTkn *token.Token
Adaptations []ast.Vertex
Expand All @@ -53,6 +56,7 @@ func (traitAdaptationList *TraitAdaptationList) GetPosition() *position.Position

// ArgumentList node
type ArgumentList struct {
ast.AttributeBag
Position *position.Position
OpenParenthesisTkn *token.Token
Arguments []ast.Vertex
Expand All @@ -69,6 +73,7 @@ func (argumentList *ArgumentList) GetPosition() *position.Position {
}

type ReturnType struct {
ast.AttributeBag
Position *position.Position
ColonTkn *token.Token
Type ast.Vertex
Expand All @@ -84,6 +89,7 @@ func (returnType *ReturnType) GetPosition() *position.Position {

// TraitMethodRef node
type TraitMethodRef struct {
ast.AttributeBag
Position *position.Position
Trait ast.Vertex
DoubleColonTkn *token.Token
Expand Down
8 changes: 8 additions & 0 deletions internal/php8/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
)

type ParserBrackets struct {
ast.AttributeBag
Position *position.Position
OpenBracketTkn *token.Token
Child ast.Vertex
Expand All @@ -22,6 +23,7 @@ func (parserBrackets *ParserBrackets) GetPosition() *position.Position {
}

type ParserSeparatedList struct {
ast.AttributeBag
Position *position.Position
Items []ast.Vertex
SeparatorTkns []*token.Token
Expand All @@ -37,6 +39,7 @@ func (parserSeparatedList *ParserSeparatedList) GetPosition() *position.Position

// TraitAdaptationList node
type TraitAdaptationList struct {
ast.AttributeBag
Position *position.Position
OpenCurlyBracketTkn *token.Token
Adaptations []ast.Vertex
Expand All @@ -53,6 +56,7 @@ func (traitAdaptationList *TraitAdaptationList) GetPosition() *position.Position

// ArgumentList node
type ArgumentList struct {
ast.AttributeBag
Position *position.Position
OpenParenthesisTkn *token.Token
Arguments []ast.Vertex
Expand All @@ -69,6 +73,7 @@ func (argumentList *ArgumentList) GetPosition() *position.Position {
}

type EnumBackingType struct {
ast.AttributeBag
Position *position.Position
ColonTkn *token.Token
Type ast.Vertex
Expand All @@ -83,6 +88,7 @@ func (enumBackingType *EnumBackingType) GetPosition() *position.Position {
}

type EnumCaseValue struct {
ast.AttributeBag
Position *position.Position
EqualTkn *token.Token
Expr ast.Vertex
Expand All @@ -97,6 +103,7 @@ func (enumCaseValue *EnumCaseValue) GetPosition() *position.Position {
}

type ReturnType struct {
ast.AttributeBag
Position *position.Position
ColonTkn *token.Token
Type ast.Vertex
Expand All @@ -112,6 +119,7 @@ func (returnType *ReturnType) GetPosition() *position.Position {

// TraitMethodRef node
type TraitMethodRef struct {
ast.AttributeBag
Position *position.Position
Trait ast.Vertex
DoubleColonTkn *token.Token
Expand Down
4 changes: 4 additions & 0 deletions pkg/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import "github.com/rectorphp/php-parser-in-go/pkg/position"
type Vertex interface {
Accept(visitor Visitor)
GetPosition() *position.Position
// SetAttribute stores metadata assigned after parsing, such as a resolved type.
SetAttribute(key string, value any)
// GetAttribute returns a stored attribute and whether it was present.
GetAttribute(key string) (any, bool)
}

type Visitor interface {
Expand Down
30 changes: 30 additions & 0 deletions pkg/ast/attribute_bag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ast

import "reflect"

// AttributeBag is embedded in every AST node to carry metadata assigned after
// parsing, such as a resolved type. Attributes are keyed by string and allocated
// lazily, so a node that never gets one costs nothing.
type AttributeBag struct {
attributes map[string]any
}

// Equal lets go-cmp compare nodes that embed a bag without reaching its
// unexported field; two bags are equal when they hold the same attributes.
func (bag AttributeBag) Equal(other AttributeBag) bool {
return reflect.DeepEqual(bag.attributes, other.attributes)
}

// SetAttribute stores value under key, allocating the backing map on first use.
func (bag *AttributeBag) SetAttribute(key string, value any) {
if bag.attributes == nil {
bag.attributes = map[string]any{}
}
bag.attributes[key] = value
}

// GetAttribute returns the value stored under key and whether it was present.
func (bag *AttributeBag) GetAttribute(key string) (any, bool) {
value, ok := bag.attributes[key]
return value, ok
}
50 changes: 50 additions & 0 deletions pkg/ast/attribute_bag_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package ast

import "testing"

func TestAttributeBagSetGet(test *testing.T) {
var bag AttributeBag

if _, ok := bag.GetAttribute("type"); ok {
test.Fatal("empty bag reported a value")
}

bag.SetAttribute("type", "User")
value, ok := bag.GetAttribute("type")
if !ok || value != "User" {
test.Fatalf("got %v, %v; want User, true", value, ok)
}

bag.SetAttribute("type", "Admin")
if value, _ := bag.GetAttribute("type"); value != "Admin" {
test.Fatalf("overwrite failed: got %v", value)
}
}

func TestAttributeBagEqual(test *testing.T) {
var empty, other AttributeBag
if !empty.Equal(other) {
test.Fatal("two empty bags should be equal")
}

set := AttributeBag{}
set.SetAttribute("type", "User")
if empty.Equal(set) {
test.Fatal("empty bag should differ from a populated one")
}

same := AttributeBag{}
same.SetAttribute("type", "User")
if !set.Equal(same) {
test.Fatal("bags with the same attributes should be equal")
}
}

// node embeds AttributeBag, so every node satisfies the Vertex attribute methods.
func TestNodeCarriesAttributes(test *testing.T) {
var node Vertex = &ExprVariable{}
node.SetAttribute("type", "string")
if value, ok := node.GetAttribute("type"); !ok || value != "string" {
test.Fatalf("node attribute not stored: got %v, %v", value, ok)
}
}
Loading
Loading