diff --git a/runtime/Go/antlr/v4/lexer.go b/runtime/Go/antlr/v4/lexer.go index 6533f05164..0d81c9d6ac 100644 --- a/runtime/Go/antlr/v4/lexer.go +++ b/runtime/Go/antlr/v4/lexer.go @@ -118,7 +118,7 @@ const ( LexerMaxCharValue = 0x10FFFF ) -func (b *BaseLexer) reset() { +func (b *BaseLexer) Reset() { // wack Lexer state variables if b.input != nil { b.input.Seek(0) // rewind the input @@ -280,7 +280,7 @@ func (b *BaseLexer) inputStream() CharStream { func (b *BaseLexer) SetInputStream(input CharStream) { b.input = nil b.tokenFactorySourcePair = &TokenSourceCharStreamPair{b, b.input} - b.reset() + b.Reset() b.input = input b.tokenFactorySourcePair = &TokenSourceCharStreamPair{b, b.input} } diff --git a/runtime/Go/antlr/v4/testing_api_test.go b/runtime/Go/antlr/v4/testing_api_test.go new file mode 100644 index 0000000000..eed3ce34be --- /dev/null +++ b/runtime/Go/antlr/v4/testing_api_test.go @@ -0,0 +1,30 @@ +package antlr + +import ( + "testing" +) + +func next(t *testing.T, lexer *LexerB, want string) { + var token = lexer.NextToken() + var got = token.String() + if got != want { + t.Errorf("got %q, wanted %q", got, want) + } +} + +func TestString(t *testing.T) { + str := NewInputStream("a b c 1 2 3") + lexer := NewLexerB(str) + next(t, lexer, "[@-1,0:0='a',<1>,1:0]") + next(t, lexer, "[@-1,1:1=' ',<7>,1:1]") + next(t, lexer, "[@-1,2:2='b',<1>,1:2]") + next(t, lexer, "[@-1,3:3=' ',<7>,1:3]") + next(t, lexer, "[@-1,4:4='c',<1>,1:4]") + next(t, lexer, "[@-1,5:5=' ',<7>,1:5]") + next(t, lexer, "[@-1,6:6='1',<2>,1:6]") + next(t, lexer, "[@-1,7:7=' ',<7>,1:7]") + next(t, lexer, "[@-1,8:8='2',<2>,1:8]") + next(t, lexer, "[@-1,9:9=' ',<7>,1:9]") + next(t, lexer, "[@-1,10:10='3',<2>,1:10]") + next(t, lexer, "[@-1,11:10='',<-1>,1:11]") +} diff --git a/runtime/Go/antlr/v4/token.go b/runtime/Go/antlr/v4/token.go index f73b06bc6a..a77b941427 100644 --- a/runtime/Go/antlr/v4/token.go +++ b/runtime/Go/antlr/v4/token.go @@ -35,6 +35,8 @@ type Token interface { GetTokenSource() TokenSource GetInputStream() CharStream + + String() string } type BaseToken struct { diff --git a/runtime/Go/antlr/v4/tree.go b/runtime/Go/antlr/v4/tree.go index 85b4f137b5..756f3092e6 100644 --- a/runtime/Go/antlr/v4/tree.go +++ b/runtime/Go/antlr/v4/tree.go @@ -250,4 +250,62 @@ func (p *ParseTreeWalker) ExitRule(listener ParseTreeListener, r RuleNode) { listener.ExitEveryRule(ctx) } +//goland:noinspection GoUnusedGlobalVariable var ParseTreeWalkerDefault = NewParseTreeWalker() + +type IterativeParseTreeWalker struct { + *ParseTreeWalker +} + +func NewIterativeParseTreeWalker() *IterativeParseTreeWalker { + return new(IterativeParseTreeWalker) +} + +func (i *IterativeParseTreeWalker) Walk(listener ParseTreeListener, t Tree) { + var stack []Tree + var indexStack []int + currentNode := t + currentIndex := 0 + + for currentNode != nil { + // pre-order visit + switch tt := currentNode.(type) { + case ErrorNode: + listener.VisitErrorNode(tt) + case TerminalNode: + listener.VisitTerminal(tt) + default: + i.EnterRule(listener, currentNode.(RuleNode)) + } + // Move down to first child, if exists + if currentNode.GetChildCount() > 0 { + stack = append(stack, currentNode) + indexStack = append(indexStack, currentIndex) + currentIndex = 0 + currentNode = currentNode.GetChild(0) + continue + } + + for { + // post-order visit + if ruleNode, ok := currentNode.(RuleNode); ok { + i.ExitRule(listener, ruleNode) + } + // No parent, so no siblings + if len(stack) == 0 { + currentNode = nil + currentIndex = 0 + break + } + // Move to next sibling if possible + currentIndex++ + if stack[len(stack)-1].GetChildCount() > currentIndex { + currentNode = stack[len(stack)-1].GetChild(currentIndex) + break + } + // No next, sibling, so move up + currentNode, stack = stack[len(stack)-1], stack[:len(stack)-1] + currentIndex, indexStack = indexStack[len(indexStack)-1], indexStack[:len(indexStack)-1] + } + } +}