Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add opt-in function for editions #265

Closed
wants to merge 9 commits into from
20 changes: 19 additions & 1 deletion ast/enum.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ func NewEnumNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, dec
}
}

func (n *EnumNode) RangeOptions(fn func(*OptionNode) bool) {
for _, decl := range n.Decls {
if opt, ok := decl.(*OptionNode); ok {
if !fn(opt) {
return
}
}
}
}

// EnumElement is an interface implemented by all AST nodes that can
// appear in the body of an enum declaration.
type EnumElement interface {
Expand All @@ -92,7 +102,7 @@ var _ EnumElement = (*EmptyDeclNode)(nil)
// enum values. This allows NoSourceNode to be used in place of *EnumValueNode
// for some usages.
type EnumValueDeclNode interface {
Node
NodeWithOptions
GetName() Node
GetNumber() Node
}
Expand Down Expand Up @@ -165,3 +175,11 @@ func (e *EnumValueNode) GetName() Node {
func (e *EnumValueNode) GetNumber() Node {
return e.Number
}

func (e *EnumValueNode) RangeOptions(fn func(*OptionNode) bool) {
for _, opt := range e.Options.Options {
if !fn(opt) {
return
}
}
}
99 changes: 94 additions & 5 deletions ast/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import "fmt"
// This also allows NoSourceNode and SyntheticMapField to be used in place of
// one of the above for some usages.
type FieldDeclNode interface {
Node
NodeWithOptions
FieldLabel() Node
FieldName() Node
FieldType() Node
Expand Down Expand Up @@ -172,6 +172,14 @@ func (n *FieldNode) GetOptions() *CompactOptionsNode {
return n.Options
}

func (n *FieldNode) RangeOptions(fn func(*OptionNode) bool) {
for _, opt := range n.Options.Options {
if !fn(opt) {
return
}
}
}

// FieldLabel represents the label of a field, which indicates its cardinality
// (i.e. whether it is optional, required, or repeated).
type FieldLabel struct {
Expand Down Expand Up @@ -338,10 +346,40 @@ func (n *GroupNode) GetOptions() *CompactOptionsNode {
return n.Options
}

func (n *GroupNode) MessageName() Node {
func (n *GroupNode) RangeOptions(fn func(*OptionNode) bool) {
for _, opt := range n.Options.Options {
if !fn(opt) {
return
}
}
}

func (n *GroupNode) AsMessage() *SyntheticGroupMessageNode {
return (*SyntheticGroupMessageNode)(n)
}

// SyntheticGroupMessageNode is a view of a GroupNode that implements MessageDeclNode.
// Since a group field implicitly defines a message type, this node represents
// that message type while the corresponding GroupNode represents the field.
//
// This type is considered synthetic since it never appears in a file's AST, but
// is only returned from other accessors (e.g. GroupNode.AsMessage).
type SyntheticGroupMessageNode GroupNode

func (n *SyntheticGroupMessageNode) MessageName() Node {
return n.Name
}

func (n *SyntheticGroupMessageNode) RangeOptions(fn func(*OptionNode) bool) {
for _, decl := range n.Decls {
if opt, ok := decl.(*OptionNode); ok {
if !fn(opt) {
return
}
}
}
}

// OneofDeclNode is a node in the AST that defines a oneof. There are
// multiple types of AST nodes that declare oneofs:
// - *OneofNode
Expand All @@ -350,10 +388,14 @@ func (n *GroupNode) MessageName() Node {
// This also allows NoSourceNode to be used in place of one of the above
// for some usages.
type OneofDeclNode interface {
Node
NodeWithOptions
OneofName() Node
}

var _ OneofDeclNode = (*OneofNode)(nil)
var _ OneofDeclNode = (*SyntheticOneof)(nil)
var _ OneofDeclNode = NoSourceNode{}

// OneofNode represents a one-of declaration. Example:
//
// oneof query {
Expand Down Expand Up @@ -425,6 +467,16 @@ func (n *OneofNode) OneofName() Node {
return n.Name
}

func (n *OneofNode) RangeOptions(fn func(*OptionNode) bool) {
for _, decl := range n.Decls {
if opt, ok := decl.(*OptionNode); ok {
if !fn(opt) {
return
}
}
}
}

// OneofElement is an interface implemented by all AST nodes that can
// appear in the body of a oneof declaration.
type OneofElement interface {
Expand All @@ -439,7 +491,11 @@ var _ OneofElement = (*EmptyDeclNode)(nil)

// SyntheticOneof is not an actual node in the AST but a synthetic node
// that represents the oneof implied by a proto3 optional field.
//
// This type is considered synthetic since it never appears in a file's AST,
// but is only returned from other functions (e.g. NewSyntheticOneof).
type SyntheticOneof struct {
// The proto3 optional field that implies the presence of this oneof.
Field *FieldNode
}

Expand Down Expand Up @@ -471,6 +527,9 @@ func (n *SyntheticOneof) OneofName() Node {
return n.Field.FieldName()
}

func (n *SyntheticOneof) RangeOptions(_ func(*OptionNode) bool) {
}

// MapTypeNode represents the type declaration for a map field. It defines
// both the key and value types for the map. Example:
//
Expand Down Expand Up @@ -627,8 +686,16 @@ func (n *MapFieldNode) GetOptions() *CompactOptionsNode {
return n.Options
}

func (n *MapFieldNode) MessageName() Node {
return n.Name
func (n *MapFieldNode) RangeOptions(fn func(*OptionNode) bool) {
for _, opt := range n.Options.Options {
if !fn(opt) {
return
}
}
}

func (n *MapFieldNode) AsMessage() *SyntheticMapEntryNode {
return (*SyntheticMapEntryNode)(n)
}

func (n *MapFieldNode) KeyField() *SyntheticMapField {
Expand All @@ -639,9 +706,28 @@ func (n *MapFieldNode) ValueField() *SyntheticMapField {
return NewSyntheticMapField(n.MapType.ValueType, 2)
}

// SyntheticMapEntryNode is a view of a MapFieldNode that implements MessageDeclNode.
// Since a map field implicitly defines a message type for the map entry,
// this node represents that message type.
//
// This type is considered synthetic since it never appears in a file's AST, but
// is only returned from other accessors (e.g. MapFieldNode.AsMessage).
type SyntheticMapEntryNode MapFieldNode

func (n *SyntheticMapEntryNode) MessageName() Node {
return n.Name
}

func (n *SyntheticMapEntryNode) RangeOptions(_ func(*OptionNode) bool) {
}

// SyntheticMapField is not an actual node in the AST but a synthetic node
// that implements FieldDeclNode. These are used to represent the implicit
// field declarations of the "key" and "value" fields in a map entry.
//
// This type is considered synthetic since it never appears in a file's AST,
// but is only returned from other accessors and functions (e.g.
// MapFieldNode.KeyField, MapFieldNode.ValueField, and NewSyntheticMapField).
type SyntheticMapField struct {
Ident IdentValueNode
Tag *UintLiteralNode
Expand Down Expand Up @@ -704,3 +790,6 @@ func (n *SyntheticMapField) GetGroupKeyword() Node {
func (n *SyntheticMapField) GetOptions() *CompactOptionsNode {
return nil
}

func (n *SyntheticMapField) RangeOptions(_ func(*OptionNode) bool) {
}
12 changes: 11 additions & 1 deletion ast/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import "fmt"
// FileDeclNode is a placeholder interface for AST nodes that represent files.
// This allows NoSourceNode to be used in place of *FileNode for some usages.
type FileDeclNode interface {
Node
NodeWithOptions
Name() string
NodeInfo(n Node) NodeInfo
}
Expand Down Expand Up @@ -136,6 +136,16 @@ func (f *FileNode) Tokens() Sequence[Token] {
return f.fileInfo.Tokens()
}

func (f *FileNode) RangeOptions(fn func(*OptionNode) bool) {
for _, decl := range f.Decls {
if opt, ok := decl.(*OptionNode); ok {
if !fn(opt) {
return
}
}
}
}

// FileElement is an interface implemented by all AST nodes that are
// allowed as top-level declarations in the file.
type FileElement interface {
Expand Down
20 changes: 15 additions & 5 deletions ast/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ import "fmt"
// MessageDeclNode is a node in the AST that defines a message type. This
// includes normal message fields as well as implicit messages:
// - *MessageNode
// - *GroupNode (the group is a field and inline message type)
// - *MapFieldNode (map fields implicitly define a MapEntry message type)
// - *SyntheticGroupMessageNode (the group is a field and inline message type)
// - *SyntheticMapEntryNode (map fields implicitly define a MapEntry message type)
//
// This also allows NoSourceNode to be used in place of one of the above
// for some usages.
type MessageDeclNode interface {
Node
NodeWithOptions
MessageName() Node
}

var _ MessageDeclNode = (*MessageNode)(nil)
var _ MessageDeclNode = (*GroupNode)(nil)
var _ MessageDeclNode = (*MapFieldNode)(nil)
var _ MessageDeclNode = (*SyntheticGroupMessageNode)(nil)
var _ MessageDeclNode = (*SyntheticMapEntryNode)(nil)
var _ MessageDeclNode = NoSourceNode{}

// MessageNode represents a message declaration. Example:
Expand Down Expand Up @@ -92,6 +92,16 @@ func (n *MessageNode) MessageName() Node {
return n.Name
}

func (n *MessageNode) RangeOptions(fn func(*OptionNode) bool) {
for _, decl := range n.Decls {
if opt, ok := decl.(*OptionNode); ok {
if !fn(opt) {
return
}
}
}
}

// MessageBody represents the body of a message. It is used by both
// MessageNodes and GroupNodes.
type MessageBody struct {
Expand Down
7 changes: 7 additions & 0 deletions ast/no_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ func (n NoSourceNode) MessageName() Node {
return n
}

func (n NoSourceNode) OneofName() Node {
return n
}

func (n NoSourceNode) GetInputType() Node {
return n
}
Expand All @@ -135,3 +139,6 @@ func (n NoSourceNode) GetOutputType() Node {
func (n NoSourceNode) Value() interface{} {
return nil
}

func (n NoSourceNode) RangeOptions(func(*OptionNode) bool) {
}
30 changes: 24 additions & 6 deletions ast/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ type OptionNode struct {
Semicolon *RuneNode // absent for compact options
}

func (n *OptionNode) fileElement() {}
func (n *OptionNode) msgElement() {}
func (n *OptionNode) oneofElement() {}
func (n *OptionNode) enumElement() {}
func (n *OptionNode) serviceElement() {}
func (n *OptionNode) methodElement() {}
func (*OptionNode) fileElement() {}
func (*OptionNode) msgElement() {}
func (*OptionNode) oneofElement() {}
func (*OptionNode) enumElement() {}
func (*OptionNode) serviceElement() {}
func (*OptionNode) methodElement() {}

// NewOptionNode creates a new *OptionNode for a full option declaration (as
// used in files, messages, oneofs, enums, services, and methods). All arguments
Expand Down Expand Up @@ -393,3 +393,21 @@ func (e *CompactOptionsNode) GetElements() []*OptionNode {
}
return e.Options
}

// NodeWithOptions represents a node in the AST that contains
// option statements.
type NodeWithOptions interface {
Node
RangeOptions(func(*OptionNode) bool)
}

var _ NodeWithOptions = FileDeclNode(nil)
var _ NodeWithOptions = MessageDeclNode(nil)
var _ NodeWithOptions = OneofDeclNode(nil)
var _ NodeWithOptions = (*EnumNode)(nil)
var _ NodeWithOptions = (*ServiceNode)(nil)
var _ NodeWithOptions = RPCDeclNode(nil)
var _ NodeWithOptions = FieldDeclNode(nil)
var _ NodeWithOptions = EnumValueDeclNode(nil)
var _ NodeWithOptions = (*ExtensionRangeNode)(nil)
var _ NodeWithOptions = NoSourceNode{}
10 changes: 9 additions & 1 deletion ast/ranges.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type ExtensionRangeNode struct {
Semicolon *RuneNode
}

func (e *ExtensionRangeNode) msgElement() {}
func (*ExtensionRangeNode) msgElement() {}

// NewExtensionRangeNode creates a new *ExtensionRangeNode. All args must be
// non-nil except opts, which may be nil.
Expand Down Expand Up @@ -90,6 +90,14 @@ func NewExtensionRangeNode(keyword *KeywordNode, ranges []*RangeNode, commas []*
}
}

func (e *ExtensionRangeNode) RangeOptions(fn func(*OptionNode) bool) {
for _, opt := range e.Options.Options {
if !fn(opt) {
return
}
}
}

// RangeDeclNode is a placeholder interface for AST nodes that represent
// numeric values. This allows NoSourceNode to be used in place of *RangeNode
// for some usages.
Expand Down
Loading
Loading