godog/gherkin/lexer.go

217 строки
5 КиБ
Go

package gherkin
import (
"bufio"
"io"
"regexp"
"strings"
"unicode"
)
var matchers = map[string]*regexp.Regexp{
"feature": regexp.MustCompile("^(\\s*)Feature:\\s*([^#]*)(#.*)?"),
"scenario": regexp.MustCompile("^(\\s*)Scenario:\\s*([^#]*)(#.*)?"),
"scenario_outline": regexp.MustCompile("^(\\s*)Scenario Outline:\\s*([^#]*)(#.*)?"),
"examples": regexp.MustCompile("^(\\s*)Examples:(\\s*#.*)?"),
"background": regexp.MustCompile("^(\\s*)Background:(\\s*#.*)?"),
"step": regexp.MustCompile("^(\\s*)(Given|When|Then|And|But)\\s+([^#]*)(#.*)?"),
"comment": regexp.MustCompile("^(\\s*)#(.+)"),
"pystring": regexp.MustCompile("^(\\s*)\\\"\\\"\\\""),
"tags": regexp.MustCompile("^(\\s*)@([^#]*)(#.*)?"),
"table_row": regexp.MustCompile("^(\\s*)\\|([^#]*)(#.*)?"),
}
// for now only english language is supported
var keywords = map[TokenType]string{
// special
ILLEGAL: "Illegal",
EOF: "End of file",
NEWLINE: "New line",
TAGS: "Tags",
COMMENT: "Comment",
PYSTRING: "PyString",
TABLEROW: "Table row",
TEXT: "Text",
// general
GIVEN: "Given",
WHEN: "When",
THEN: "Then",
AND: "And",
BUT: "But",
FEATURE: "Feature",
BACKGROUND: "Background",
SCENARIO: "Scenario",
OUTLINE: "Scenario Outline",
EXAMPLES: "Examples",
}
type lexer struct {
reader *bufio.Reader
lines int
}
func newLexer(r io.Reader) *lexer {
return &lexer{
reader: bufio.NewReader(r),
}
}
func (l *lexer) read() *Token {
line, err := l.reader.ReadString(byte('\n'))
if err != nil && len(line) == 0 {
return &Token{
Type: EOF,
Line: l.lines + 1,
Keyword: keywords[EOF],
}
}
l.lines++
line = strings.TrimRightFunc(line, unicode.IsSpace)
// newline
if len(line) == 0 {
return &Token{
Type: NEWLINE,
Line: l.lines,
Keyword: keywords[NEWLINE],
}
}
// comment
if m := matchers["comment"].FindStringSubmatch(line); len(m) > 0 {
comment := strings.TrimSpace(m[2])
return &Token{
Type: COMMENT,
Indent: len(m[1]),
Line: l.lines,
Value: comment,
Text: line,
Comment: comment,
Keyword: keywords[COMMENT],
}
}
// pystring
if m := matchers["pystring"].FindStringSubmatch(line); len(m) > 0 {
return &Token{
Type: PYSTRING,
Indent: len(m[1]),
Line: l.lines,
Text: line,
Keyword: keywords[PYSTRING],
}
}
// step
if m := matchers["step"].FindStringSubmatch(line); len(m) > 0 {
tok := &Token{
Indent: len(m[1]),
Line: l.lines,
Value: strings.TrimSpace(m[3]),
Text: line,
Comment: strings.Trim(m[4], " #"),
}
switch m[2] {
case "Given":
tok.Type = GIVEN
case "When":
tok.Type = WHEN
case "Then":
tok.Type = THEN
case "And":
tok.Type = AND
case "But":
tok.Type = BUT
}
tok.Keyword = keywords[tok.Type]
return tok
}
// scenario
if m := matchers["scenario"].FindStringSubmatch(line); len(m) > 0 {
return &Token{
Type: SCENARIO,
Indent: len(m[1]),
Line: l.lines,
Value: strings.TrimSpace(m[2]),
Text: line,
Comment: strings.Trim(m[3], " #"),
Keyword: keywords[SCENARIO],
}
}
// background
if m := matchers["background"].FindStringSubmatch(line); len(m) > 0 {
return &Token{
Type: BACKGROUND,
Indent: len(m[1]),
Line: l.lines,
Text: line,
Comment: strings.Trim(m[2], " #"),
Keyword: keywords[BACKGROUND],
}
}
// feature
if m := matchers["feature"].FindStringSubmatch(line); len(m) > 0 {
return &Token{
Type: FEATURE,
Indent: len(m[1]),
Line: l.lines,
Value: strings.TrimSpace(m[2]),
Text: line,
Comment: strings.Trim(m[3], " #"),
Keyword: keywords[FEATURE],
}
}
// tags
if m := matchers["tags"].FindStringSubmatch(line); len(m) > 0 {
return &Token{
Type: TAGS,
Indent: len(m[1]),
Line: l.lines,
Value: strings.TrimSpace(m[2]),
Text: line,
Comment: strings.Trim(m[3], " #"),
Keyword: keywords[TAGS],
}
}
// table row
if m := matchers["table_row"].FindStringSubmatch(line); len(m) > 0 {
return &Token{
Type: TABLEROW,
Indent: len(m[1]),
Line: l.lines,
Value: strings.TrimSpace(m[2]),
Text: line,
Comment: strings.Trim(m[3], " #"),
Keyword: keywords[TABLEROW],
}
}
// scenario outline
if m := matchers["scenario_outline"].FindStringSubmatch(line); len(m) > 0 {
return &Token{
Type: OUTLINE,
Indent: len(m[1]),
Line: l.lines,
Value: strings.TrimSpace(m[2]),
Text: line,
Comment: strings.Trim(m[3], " #"),
Keyword: keywords[OUTLINE],
}
}
// examples
if m := matchers["examples"].FindStringSubmatch(line); len(m) > 0 {
return &Token{
Type: EXAMPLES,
Indent: len(m[1]),
Line: l.lines,
Text: line,
Comment: strings.Trim(m[2], " #"),
Keyword: keywords[EXAMPLES],
}
}
// text
text := strings.TrimLeftFunc(line, unicode.IsSpace)
return &Token{
Type: TEXT,
Line: l.lines,
Value: text,
Indent: len(line) - len(text),
Text: line,
Keyword: keywords[TEXT],
}
}