140 lines
2.8 KiB
Go
140 lines
2.8 KiB
Go
package lexer
|
|
|
|
import "fmt"
|
|
import "testing"
|
|
import "strings"
|
|
import "git.tebibyte.media/fspl/fspl/errors"
|
|
|
|
func tok (kind TokenKind, value string) Token {
|
|
return Token {
|
|
Kind: kind,
|
|
Value: value,
|
|
}
|
|
}
|
|
|
|
func testString (
|
|
test *testing.T,
|
|
input string,
|
|
correct ...Token,
|
|
) {
|
|
testStringErr(test, "", "", 0, 0, input, correct...)
|
|
}
|
|
|
|
func testStringErr (
|
|
test *testing.T,
|
|
errMessage string,
|
|
errLine string,
|
|
errRow int,
|
|
errStart int,
|
|
input string,
|
|
correct ...Token,
|
|
) {
|
|
testError := func (err error) bool {
|
|
got := err.(errors.Error)
|
|
gotMessage := got.Error()
|
|
gotLine := got.Position().Line
|
|
gotRow := got.Position().Row
|
|
gotStart := got.Position().Start
|
|
correct :=
|
|
gotMessage == errMessage &&
|
|
gotLine == errLine &&
|
|
gotRow == errRow &&
|
|
gotStart == errStart
|
|
if !correct {
|
|
test.Log("errors do not match")
|
|
test.Log("got:\n" + errors.Format(got))
|
|
test.Log("correct:\n" + errors.Format(errors.Errorf (
|
|
errors.Position {
|
|
File: "input.fspl",
|
|
Line: errLine,
|
|
Row: errRow,
|
|
Start: errStart,
|
|
End: errStart,
|
|
},
|
|
errMessage,
|
|
)))
|
|
test.Fail()
|
|
}
|
|
return correct
|
|
}
|
|
|
|
printUnexpectedErr := func (err error) {
|
|
test.Log("lexer returned error:\n" + errors.Format(err))
|
|
}
|
|
|
|
reader := strings.NewReader(input)
|
|
lx, err := LexReader("input.fspl", reader)
|
|
if err != nil {
|
|
if errMessage == "" {
|
|
printUnexpectedErr(err)
|
|
test.Fail()
|
|
return
|
|
} else {
|
|
if !testError(err) { return }
|
|
}
|
|
}
|
|
|
|
var tokens []Token
|
|
for {
|
|
got, err := lx.Next()
|
|
tokens = append(tokens, got)
|
|
if got.EOF() { break }
|
|
if err != nil {
|
|
if errMessage == "" {
|
|
printUnexpectedErr(err)
|
|
test.Fail()
|
|
} else {
|
|
if !testError(err) { return }
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
printColumns := func (left, right string) {
|
|
test.Logf("%-50v | %v", left, right)
|
|
}
|
|
|
|
dumpToken := func (token Token) string {
|
|
return fmt.Sprintf("%12v: \"%s\"", token.Kind, token.Value)
|
|
}
|
|
|
|
compareTokens := func () {
|
|
length := len(tokens)
|
|
if len(correct) > length { length = len(correct) }
|
|
|
|
printColumns("CORRECT", "GOT")
|
|
for index := 0; index < length; index ++ {
|
|
left := "..."
|
|
right := "..."
|
|
|
|
if index < len(correct) {
|
|
left = dumpToken(correct[index])
|
|
}
|
|
if index < len(tokens) {
|
|
right = dumpToken(tokens[index])
|
|
}
|
|
|
|
printColumns(left, right)
|
|
}
|
|
}
|
|
|
|
if len(tokens) != len(correct) {
|
|
test.Logf (
|
|
"len(correct) and len(got) do not match (%v, %v)",
|
|
len(correct), len(tokens))
|
|
compareTokens()
|
|
test.Fail()
|
|
return
|
|
}
|
|
|
|
for index, token := range correct {
|
|
gotToken := tokens[index]
|
|
if token.Kind != gotToken.Kind || token.Value != gotToken.Value {
|
|
test.Logf("correct and got do not match at %v", index)
|
|
compareTokens()
|
|
test.Fail()
|
|
return
|
|
}
|
|
}
|
|
}
|