Skip to content

Instantly share code, notes, and snippets.

@bramp
Created October 1, 2017 19:21
Show Gist options
  • Save bramp/625e1a149703710cd3367ea09814e21f to your computer and use it in GitHub Desktop.
Save bramp/625e1a149703710cd3367ea09814e21f to your computer and use it in GitHub Desktop.
Example of a failing ANTLR MySQL Parser
/**
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package mysql_test
import (
"bramp.net/antlr4-grammars/mysql"
"github.com/antlr/antlr4/runtime/Go/antlr"
"path/filepath"
"testing"
"unicode"
)
// CaseChangingStream wraps an existing CharStream, but upper cases, or
// lower cases the input before it is tokenized.
type CaseChangingStream struct {
antlr.CharStream
upper bool
}
func (is *CaseChangingStream) LA(offset int) int {
in := is.CharStream.LA(offset)
if in < 0 {
// Such as antlr.TokenEOF which is -1
return in
}
if is.upper {
return int(unicode.ToUpper(rune(in)))
}
return int(unicode.ToLower(rune(in)))
}
func newCharStream(filename string) (antlr.CharStream, error) {
input, err := antlr.NewFileStream(filepath.Join("..", filename))
if err != nil {
return nil, err
}
return &CaseChangingStream{input, true}, nil
}
// TestingErrorListener is a antlr.ErrorListener which fails the given test
// if a SyntaxError is found. The other Report errors are ignored.
type TestingErrorListener struct {
*antlr.DefaultErrorListener
t *testing.T
idx int
name string
}
func (l *TestingErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
l.t.Errorf("[%d] %s: SyntaxError %d:%d: %s", l.idx, l.name, line, column, msg)
}
func TestMySqlParser(t *testing.T) {
var examples = []string{
"grammars-v4/mysql/examples/ddl_create.sql",
"grammars-v4/mysql/examples/dml_delete.sql",
}
for i, file := range examples {
input, err := newCharStream(file)
if err != nil {
t.Errorf("Failed to open example file: %s", err)
}
// Create the Lexer
lexer := mysql.NewMySqlLexer(input)
stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
// Create the Parser
p := mysql.NewMySqlParser(stream)
p.BuildParseTrees = true
p.AddErrorListener(&TestingErrorListener{t: t, idx: i, name: file})
// Finally test
p.Root()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment