func lexer()

in variables.go [365:449]


func lexer(in string) (<-chan token, <-chan error) {
	lex := make(chan token, 1)
	errors := make(chan error, 1)

	go func() {
		off := 0
		content := in

		defer func() {
			if len(content) > 0 {
				lex <- token{tokString, content}
			}
			close(lex)
			close(errors)
		}()

		strToken := func(s string) {
			if s != "" {
				lex <- token{tokString, s}
			}
		}

		varcount := 0
		for len(content) > 0 {
			idx := -1
			if varcount == 0 {
				idx = strings.IndexAny(content[off:], "$")
			} else {
				idx = strings.IndexAny(content[off:], "$:}")
			}
			if idx < 0 {
				return
			}

			idx += off
			off = idx + 1
			switch content[idx] {
			case ':':
				if len(content) <= off { // found ':' at end of string
					return
				}

				strToken(content[:idx])
				switch content[off] {
				case '+':
					off++
					lex <- sepAltToken
				case '?':
					off++
					lex <- sepErrToken
				default:
					lex <- sepDefToken
				}

			case '}':
				strToken(content[:idx])
				lex <- closeToken
				varcount--

			case '$':
				if len(content) <= off { // found '$' at end of string
					return
				}

				switch content[off] {
				case '{': // start variable
					strToken(content[:idx])
					lex <- openToken
					off++
					varcount++
				case '$', '}': // escape $} and $$
					content = content[:idx] + content[off:]
					continue
				default:
					continue
				}
			}

			content = content[off:]
			off = 0
		}
	}()

	return lex, errors
}