github.com/phpstudyer/protoreflect@v1.7.2/desc/protoparse/ast/walk.go (about)

     1  package ast
     2  
     3  // VisitFunc is used to examine a node in the AST when walking the tree.
     4  // It returns true or false as to whether or not the descendants of the
     5  // given node should be visited. If it returns true, the node's children
     6  // will be visisted; if false, they will not. When returning true, it
     7  // can also return a new VisitFunc to use for the children. If it returns
     8  // (true, nil), then the current function will be re-used when visiting
     9  // the children.
    10  //
    11  // See also the Visitor type.
    12  type VisitFunc func(Node) (bool, VisitFunc)
    13  
    14  // Walk conducts a walk of the AST rooted at the given root using the
    15  // given function. It performs a "pre-order traversal", visiting a
    16  // given AST node before it visits that node's descendants.
    17  func Walk(root Node, v VisitFunc) {
    18  	ok, next := v(root)
    19  	if !ok {
    20  		return
    21  	}
    22  	if next != nil {
    23  		v = next
    24  	}
    25  	if comp, ok := root.(CompositeNode); ok {
    26  		for _, child := range comp.Children() {
    27  			Walk(child, v)
    28  		}
    29  	}
    30  }
    31  
    32  // Visitor provides a technique for walking the AST that allows for
    33  // dynamic dispatch, where a particular function is invoked based on
    34  // the runtime type of the argument.
    35  //
    36  // It consists of a number of functions, each of which matches a
    37  // concrete Node type. It also includes functions for sub-interfaces
    38  // of Node and the Node interface itself, to be used as broader
    39  // "catch all" functions.
    40  //
    41  // To use a visitor, provide a function for the node types of
    42  // interest and pass visitor.Visit as the function to a Walk operation.
    43  // When a node is traversed, the corresponding function field of
    44  // the visitor is invoked, if not nil. If the function for a node's
    45  // concrete type is nil/absent but the function for an interface it
    46  // implements is present, that interface visit function will be used
    47  // instead. If no matching function is present, the traversal will
    48  // continue. If a matching function is present, it will be invoked
    49  // and its response determines how the traversal proceeds.
    50  //
    51  // Every visit function returns (bool, *Visitor). If the bool returned
    52  // is false, the visited node's descendants are skipped. Otherwise,
    53  // traversal will continue into the node's children. If the returned
    54  // visitor is nil, the current visitor will continue to be used. But
    55  // if a non-nil visitor is returned, it will be used to visit the
    56  // node's children.
    57  type Visitor struct {
    58  	// VisitFileNode is invoked when visiting a *FileNode in the AST.
    59  	VisitFileNode func(*FileNode) (bool, *Visitor)
    60  	// VisitSyntaxNode is invoked when visiting a *SyntaxNode in the AST.
    61  	VisitSyntaxNode func(*SyntaxNode) (bool, *Visitor)
    62  	// VisitPackageNode is invoked when visiting a *PackageNode in the AST.
    63  	VisitPackageNode func(*PackageNode) (bool, *Visitor)
    64  	// VisitImportNode is invoked when visiting an *ImportNode in the AST.
    65  	VisitImportNode func(*ImportNode) (bool, *Visitor)
    66  	// VisitOptionNode is invoked when visiting an *OptionNode in the AST.
    67  	VisitOptionNode func(*OptionNode) (bool, *Visitor)
    68  	// VisitOptionNameNode is invoked when visiting an *OptionNameNode in the AST.
    69  	VisitOptionNameNode func(*OptionNameNode) (bool, *Visitor)
    70  	// VisitFieldReferenceNode is invoked when visiting a *FieldReferenceNode in the AST.
    71  	VisitFieldReferenceNode func(*FieldReferenceNode) (bool, *Visitor)
    72  	// VisitCompactOptionsNode is invoked when visiting a *CompactOptionsNode in the AST.
    73  	VisitCompactOptionsNode func(*CompactOptionsNode) (bool, *Visitor)
    74  	// VisitMessageNode is invoked when visiting a *MessageNode in the AST.
    75  	VisitMessageNode func(*MessageNode) (bool, *Visitor)
    76  	// VisitExtendNode is invoked when visiting an *ExtendNode in the AST.
    77  	VisitExtendNode func(*ExtendNode) (bool, *Visitor)
    78  	// VisitExtensionRangeNode is invoked when visiting an *ExtensionRangeNode in the AST.
    79  	VisitExtensionRangeNode func(*ExtensionRangeNode) (bool, *Visitor)
    80  	// VisitReservedNode is invoked when visiting a *ReservedNode in the AST.
    81  	VisitReservedNode func(*ReservedNode) (bool, *Visitor)
    82  	// VisitRangeNode is invoked when visiting a *RangeNode in the AST.
    83  	VisitRangeNode func(*RangeNode) (bool, *Visitor)
    84  	// VisitFieldNode is invoked when visiting a *FieldNode in the AST.
    85  	VisitFieldNode func(*FieldNode) (bool, *Visitor)
    86  	// VisitGroupNode is invoked when visiting a *GroupNode in the AST.
    87  	VisitGroupNode func(*GroupNode) (bool, *Visitor)
    88  	// VisitMapFieldNode is invoked when visiting a *MapFieldNode in the AST.
    89  	VisitMapFieldNode func(*MapFieldNode) (bool, *Visitor)
    90  	// VisitMapTypeNode is invoked when visiting a *MapTypeNode in the AST.
    91  	VisitMapTypeNode func(*MapTypeNode) (bool, *Visitor)
    92  	// VisitOneOfNode is invoked when visiting a *OneOfNode in the AST.
    93  	VisitOneOfNode func(*OneOfNode) (bool, *Visitor)
    94  	// VisitEnumNode is invoked when visiting an *EnumNode in the AST.
    95  	VisitEnumNode func(*EnumNode) (bool, *Visitor)
    96  	// VisitEnumValueNode is invoked when visiting an *EnumValueNode in the AST.
    97  	VisitEnumValueNode func(*EnumValueNode) (bool, *Visitor)
    98  	// VisitServiceNode is invoked when visiting a *ServiceNode in the AST.
    99  	VisitServiceNode func(*ServiceNode) (bool, *Visitor)
   100  	// VisitRPCNode is invoked when visiting an *RPCNode in the AST.
   101  	VisitRPCNode func(*RPCNode) (bool, *Visitor)
   102  	// VisitRPCTypeNode is invoked when visiting an *RPCTypeNode in the AST.
   103  	VisitRPCTypeNode func(*RPCTypeNode) (bool, *Visitor)
   104  	// VisitIdentNode is invoked when visiting an *IdentNode in the AST.
   105  	VisitIdentNode func(*IdentNode) (bool, *Visitor)
   106  	// VisitCompoundIdentNode is invoked when visiting a *CompoundIdentNode in the AST.
   107  	VisitCompoundIdentNode func(*CompoundIdentNode) (bool, *Visitor)
   108  	// VisitStringLiteralNode is invoked when visiting a *StringLiteralNode in the AST.
   109  	VisitStringLiteralNode func(*StringLiteralNode) (bool, *Visitor)
   110  	// VisitCompoundStringLiteralNode is invoked when visiting a *CompoundStringLiteralNode in the AST.
   111  	VisitCompoundStringLiteralNode func(*CompoundStringLiteralNode) (bool, *Visitor)
   112  	// VisitUintLiteralNode is invoked when visiting a *UintLiteralNode in the AST.
   113  	VisitUintLiteralNode func(*UintLiteralNode) (bool, *Visitor)
   114  	// VisitPositiveUintLiteralNode is invoked when visiting a *PositiveUintLiteralNode in the AST.
   115  	VisitPositiveUintLiteralNode func(*PositiveUintLiteralNode) (bool, *Visitor)
   116  	// VisitNegativeIntLiteralNode is invoked when visiting a *NegativeIntLiteralNode in the AST.
   117  	VisitNegativeIntLiteralNode func(*NegativeIntLiteralNode) (bool, *Visitor)
   118  	// VisitFloatLiteralNode is invoked when visiting a *FloatLiteralNode in the AST.
   119  	VisitFloatLiteralNode func(*FloatLiteralNode) (bool, *Visitor)
   120  	// VisitSpecialFloatLiteralNode is invoked when visiting a *SpecialFloatLiteralNode in the AST.
   121  	VisitSpecialFloatLiteralNode func(*SpecialFloatLiteralNode) (bool, *Visitor)
   122  	// VisitSignedFloatLiteralNode is invoked when visiting a *SignedFloatLiteralNode in the AST.
   123  	VisitSignedFloatLiteralNode func(*SignedFloatLiteralNode) (bool, *Visitor)
   124  	// VisitBoolLiteralNode is invoked when visiting a *BoolLiteralNode in the AST.
   125  	VisitBoolLiteralNode func(*BoolLiteralNode) (bool, *Visitor)
   126  	// VisitArrayLiteralNode is invoked when visiting an *ArrayLiteralNode in the AST.
   127  	VisitArrayLiteralNode func(*ArrayLiteralNode) (bool, *Visitor)
   128  	// VisitMessageLiteralNode is invoked when visiting a *MessageLiteralNode in the AST.
   129  	VisitMessageLiteralNode func(*MessageLiteralNode) (bool, *Visitor)
   130  	// VisitMessageFieldNode is invoked when visiting a *MessageFieldNode in the AST.
   131  	VisitMessageFieldNode func(*MessageFieldNode) (bool, *Visitor)
   132  	// VisitKeywordNode is invoked when visiting a *KeywordNode in the AST.
   133  	VisitKeywordNode func(*KeywordNode) (bool, *Visitor)
   134  	// VisitRuneNode is invoked when visiting a *RuneNode in the AST.
   135  	VisitRuneNode func(*RuneNode) (bool, *Visitor)
   136  	// VisitEmptyDeclNode is invoked when visiting a *EmptyDeclNode in the AST.
   137  	VisitEmptyDeclNode func(*EmptyDeclNode) (bool, *Visitor)
   138  
   139  	// VisitFieldDeclNode is invoked when visiting a FieldDeclNode in the AST.
   140  	// This function is used when no concrete type function is provided. If
   141  	// both this and VisitMessageDeclNode are provided, and a node implements
   142  	// both (such as *GroupNode and *MapFieldNode), this function will be
   143  	// invoked and not the other.
   144  	VisitFieldDeclNode func(FieldDeclNode) (bool, *Visitor)
   145  	// VisitMessageDeclNode is invoked when visiting a MessageDeclNode in the AST.
   146  	// This function is used when no concrete type function is provided.
   147  	VisitMessageDeclNode func(MessageDeclNode) (bool, *Visitor)
   148  
   149  	// VisitIdentValueNode is invoked when visiting an IdentValueNode in the AST.
   150  	// This function is used when no concrete type function is provided.
   151  	VisitIdentValueNode func(IdentValueNode) (bool, *Visitor)
   152  	// VisitStringValueNode is invoked when visiting a StringValueNode in the AST.
   153  	// This function is used when no concrete type function is provided.
   154  	VisitStringValueNode func(StringValueNode) (bool, *Visitor)
   155  	// VisitIntValueNode is invoked when visiting an IntValueNode in the AST.
   156  	// This function is used when no concrete type function is provided. If
   157  	// both this and VisitFloatValueNode are provided, and a node implements
   158  	// both (such as *UintLiteralNode), this function will be invoked and
   159  	// not the other.
   160  	VisitIntValueNode func(IntValueNode) (bool, *Visitor)
   161  	// VisitFloatValueNode is invoked when visiting a FloatValueNode in the AST.
   162  	// This function is used when no concrete type function is provided.
   163  	VisitFloatValueNode func(FloatValueNode) (bool, *Visitor)
   164  	// VisitValueNode is invoked when visiting a ValueNode in the AST. This
   165  	// function is used when no concrete type function is provided and no
   166  	// more specific ValueNode function is provided that matches the node.
   167  	VisitValueNode func(ValueNode) (bool, *Visitor)
   168  
   169  	// VisitTerminalNode is invoked when visiting a TerminalNode in the AST.
   170  	// This function is used when no concrete type function is provided
   171  	// no more specific interface type function is provided.
   172  	VisitTerminalNode func(TerminalNode) (bool, *Visitor)
   173  	// VisitCompositeNode is invoked when visiting a CompositeNode in the AST.
   174  	// This function is used when no concrete type function is provided
   175  	// no more specific interface type function is provided.
   176  	VisitCompositeNode func(CompositeNode) (bool, *Visitor)
   177  	// VisitNode is invoked when visiting a Node in the AST. This
   178  	// function is only used when no other more specific function is
   179  	// provided.
   180  	VisitNode func(Node) (bool, *Visitor)
   181  }
   182  
   183  // Visit provides the Visitor's implementation of VisitFunc, to be
   184  // used with Walk operations.
   185  func (v *Visitor) Visit(n Node) (bool, VisitFunc) {
   186  	var ok, matched bool
   187  	var next *Visitor
   188  	switch n := n.(type) {
   189  	case *FileNode:
   190  		if v.VisitFileNode != nil {
   191  			matched = true
   192  			ok, next = v.VisitFileNode(n)
   193  		}
   194  	case *SyntaxNode:
   195  		if v.VisitSyntaxNode != nil {
   196  			matched = true
   197  			ok, next = v.VisitSyntaxNode(n)
   198  		}
   199  	case *PackageNode:
   200  		if v.VisitPackageNode != nil {
   201  			matched = true
   202  			ok, next = v.VisitPackageNode(n)
   203  		}
   204  	case *ImportNode:
   205  		if v.VisitImportNode != nil {
   206  			matched = true
   207  			ok, next = v.VisitImportNode(n)
   208  		}
   209  	case *OptionNode:
   210  		if v.VisitOptionNode != nil {
   211  			matched = true
   212  			ok, next = v.VisitOptionNode(n)
   213  		}
   214  	case *OptionNameNode:
   215  		if v.VisitOptionNameNode != nil {
   216  			matched = true
   217  			ok, next = v.VisitOptionNameNode(n)
   218  		}
   219  	case *FieldReferenceNode:
   220  		if v.VisitFieldReferenceNode != nil {
   221  			matched = true
   222  			ok, next = v.VisitFieldReferenceNode(n)
   223  		}
   224  	case *CompactOptionsNode:
   225  		if v.VisitCompactOptionsNode != nil {
   226  			matched = true
   227  			ok, next = v.VisitCompactOptionsNode(n)
   228  		}
   229  	case *MessageNode:
   230  		if v.VisitMessageNode != nil {
   231  			matched = true
   232  			ok, next = v.VisitMessageNode(n)
   233  		}
   234  	case *ExtendNode:
   235  		if v.VisitExtendNode != nil {
   236  			matched = true
   237  			ok, next = v.VisitExtendNode(n)
   238  		}
   239  	case *ExtensionRangeNode:
   240  		if v.VisitExtensionRangeNode != nil {
   241  			matched = true
   242  			ok, next = v.VisitExtensionRangeNode(n)
   243  		}
   244  	case *ReservedNode:
   245  		if v.VisitReservedNode != nil {
   246  			matched = true
   247  			ok, next = v.VisitReservedNode(n)
   248  		}
   249  	case *RangeNode:
   250  		if v.VisitRangeNode != nil {
   251  			matched = true
   252  			ok, next = v.VisitRangeNode(n)
   253  		}
   254  	case *FieldNode:
   255  		if v.VisitFieldNode != nil {
   256  			matched = true
   257  			ok, next = v.VisitFieldNode(n)
   258  		}
   259  	case *GroupNode:
   260  		if v.VisitGroupNode != nil {
   261  			matched = true
   262  			ok, next = v.VisitGroupNode(n)
   263  		}
   264  	case *MapFieldNode:
   265  		if v.VisitMapFieldNode != nil {
   266  			matched = true
   267  			ok, next = v.VisitMapFieldNode(n)
   268  		}
   269  	case *MapTypeNode:
   270  		if v.VisitMapTypeNode != nil {
   271  			matched = true
   272  			ok, next = v.VisitMapTypeNode(n)
   273  		}
   274  	case *OneOfNode:
   275  		if v.VisitOneOfNode != nil {
   276  			matched = true
   277  			ok, next = v.VisitOneOfNode(n)
   278  		}
   279  	case *EnumNode:
   280  		if v.VisitEnumNode != nil {
   281  			matched = true
   282  			ok, next = v.VisitEnumNode(n)
   283  		}
   284  	case *EnumValueNode:
   285  		if v.VisitEnumValueNode != nil {
   286  			matched = true
   287  			ok, next = v.VisitEnumValueNode(n)
   288  		}
   289  	case *ServiceNode:
   290  		if v.VisitServiceNode != nil {
   291  			matched = true
   292  			ok, next = v.VisitServiceNode(n)
   293  		}
   294  	case *RPCNode:
   295  		if v.VisitRPCNode != nil {
   296  			matched = true
   297  			ok, next = v.VisitRPCNode(n)
   298  		}
   299  	case *RPCTypeNode:
   300  		if v.VisitRPCTypeNode != nil {
   301  			matched = true
   302  			ok, next = v.VisitRPCTypeNode(n)
   303  		}
   304  	case *IdentNode:
   305  		if v.VisitIdentNode != nil {
   306  			matched = true
   307  			ok, next = v.VisitIdentNode(n)
   308  		}
   309  	case *CompoundIdentNode:
   310  		if v.VisitCompoundIdentNode != nil {
   311  			matched = true
   312  			ok, next = v.VisitCompoundIdentNode(n)
   313  		}
   314  	case *StringLiteralNode:
   315  		if v.VisitStringLiteralNode != nil {
   316  			matched = true
   317  			ok, next = v.VisitStringLiteralNode(n)
   318  		}
   319  	case *CompoundStringLiteralNode:
   320  		if v.VisitCompoundStringLiteralNode != nil {
   321  			matched = true
   322  			ok, next = v.VisitCompoundStringLiteralNode(n)
   323  		}
   324  	case *UintLiteralNode:
   325  		if v.VisitUintLiteralNode != nil {
   326  			matched = true
   327  			ok, next = v.VisitUintLiteralNode(n)
   328  		}
   329  	case *PositiveUintLiteralNode:
   330  		if v.VisitPositiveUintLiteralNode != nil {
   331  			matched = true
   332  			ok, next = v.VisitPositiveUintLiteralNode(n)
   333  		}
   334  	case *NegativeIntLiteralNode:
   335  		if v.VisitNegativeIntLiteralNode != nil {
   336  			matched = true
   337  			ok, next = v.VisitNegativeIntLiteralNode(n)
   338  		}
   339  	case *FloatLiteralNode:
   340  		if v.VisitFloatLiteralNode != nil {
   341  			matched = true
   342  			ok, next = v.VisitFloatLiteralNode(n)
   343  		}
   344  	case *SpecialFloatLiteralNode:
   345  		if v.VisitSpecialFloatLiteralNode != nil {
   346  			matched = true
   347  			ok, next = v.VisitSpecialFloatLiteralNode(n)
   348  		}
   349  	case *SignedFloatLiteralNode:
   350  		if v.VisitSignedFloatLiteralNode != nil {
   351  			matched = true
   352  			ok, next = v.VisitSignedFloatLiteralNode(n)
   353  		}
   354  	case *BoolLiteralNode:
   355  		if v.VisitBoolLiteralNode != nil {
   356  			matched = true
   357  			ok, next = v.VisitBoolLiteralNode(n)
   358  		}
   359  	case *ArrayLiteralNode:
   360  		if v.VisitArrayLiteralNode != nil {
   361  			matched = true
   362  			ok, next = v.VisitArrayLiteralNode(n)
   363  		}
   364  	case *MessageLiteralNode:
   365  		if v.VisitMessageLiteralNode != nil {
   366  			matched = true
   367  			ok, next = v.VisitMessageLiteralNode(n)
   368  		}
   369  	case *MessageFieldNode:
   370  		if v.VisitMessageFieldNode != nil {
   371  			matched = true
   372  			ok, next = v.VisitMessageFieldNode(n)
   373  		}
   374  	case *KeywordNode:
   375  		if v.VisitKeywordNode != nil {
   376  			matched = true
   377  			ok, next = v.VisitKeywordNode(n)
   378  		}
   379  	case *RuneNode:
   380  		if v.VisitRuneNode != nil {
   381  			matched = true
   382  			ok, next = v.VisitRuneNode(n)
   383  		}
   384  	case *EmptyDeclNode:
   385  		if v.VisitEmptyDeclNode != nil {
   386  			matched = true
   387  			ok, next = v.VisitEmptyDeclNode(n)
   388  		}
   389  	}
   390  
   391  	if !matched {
   392  		// Visitor provided no concrete type visit function, so
   393  		// check interface types. We do this in several passes
   394  		// to provide "priority" for matched interfaces for nodes
   395  		// that actually implement more than one interface.
   396  		//
   397  		// For example, StringLiteralNode implements both
   398  		// StringValueNode and ValueNode. Both cases could match
   399  		// so the first case is what would match. So if we want
   400  		// to test against either, they need to be in different
   401  		// switch statements.
   402  		switch n := n.(type) {
   403  		case FieldDeclNode:
   404  			if v.VisitFieldDeclNode != nil {
   405  				matched = true
   406  				ok, next = v.VisitFieldDeclNode(n)
   407  			}
   408  		case IdentValueNode:
   409  			if v.VisitIdentValueNode != nil {
   410  				matched = true
   411  				ok, next = v.VisitIdentValueNode(n)
   412  			}
   413  		case StringValueNode:
   414  			if v.VisitStringValueNode != nil {
   415  				matched = true
   416  				ok, next = v.VisitStringValueNode(n)
   417  			}
   418  		case IntValueNode:
   419  			if v.VisitIntValueNode != nil {
   420  				matched = true
   421  				ok, next = v.VisitIntValueNode(n)
   422  			}
   423  		}
   424  	}
   425  
   426  	if !matched {
   427  		// These two are excluded from the above switch so that
   428  		// if visitor provides both VisitIntValueNode and
   429  		// VisitFloatValueNode, we'll prefer VisitIntValueNode
   430  		// for *UintLiteralNode (which implements both). Similarly,
   431  		// that way we prefer VisitFieldDeclNode over
   432  		// VisitMessageDeclNode when visiting a *GroupNode.
   433  		switch n := n.(type) {
   434  		case FloatValueNode:
   435  			if v.VisitFloatValueNode != nil {
   436  				matched = true
   437  				ok, next = v.VisitFloatValueNode(n)
   438  			}
   439  		case MessageDeclNode:
   440  			if v.VisitMessageDeclNode != nil {
   441  				matched = true
   442  				ok, next = v.VisitMessageDeclNode(n)
   443  			}
   444  		}
   445  	}
   446  
   447  	if !matched {
   448  		switch n := n.(type) {
   449  		case ValueNode:
   450  			if v.VisitValueNode != nil {
   451  				matched = true
   452  				ok, next = v.VisitValueNode(n)
   453  			}
   454  		}
   455  	}
   456  
   457  	if !matched {
   458  		switch n := n.(type) {
   459  		case TerminalNode:
   460  			if v.VisitTerminalNode != nil {
   461  				matched = true
   462  				ok, next = v.VisitTerminalNode(n)
   463  			}
   464  		case CompositeNode:
   465  			if v.VisitCompositeNode != nil {
   466  				matched = true
   467  				ok, next = v.VisitCompositeNode(n)
   468  			}
   469  		}
   470  	}
   471  
   472  	if !matched {
   473  		// finally, fallback to most generic visit function
   474  		if v.VisitNode != nil {
   475  			matched = true
   476  			ok, next = v.VisitNode(n)
   477  		}
   478  	}
   479  
   480  	if !matched {
   481  		// keep descending with the current visitor
   482  		return true, nil
   483  	}
   484  
   485  	if !ok {
   486  		return false, nil
   487  	}
   488  	if next != nil {
   489  		return true, next.Visit
   490  	}
   491  	return true, v.Visit
   492  }