scanner: use a better token type
This commit is contained in:
parent
760a028e8a
commit
8169cb79d7
@ -8,8 +8,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/fatih/hcl/token"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// eof represents a marker rune for the end of the reader.
|
// eof represents a marker rune for the end of the reader.
|
||||||
@ -126,7 +124,7 @@ func (s *Scanner) peek() rune {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scan scans the next token and returns the token.
|
// Scan scans the next token and returns the token.
|
||||||
func (s *Scanner) Scan() token.Token {
|
func (s *Scanner) Scan() Token {
|
||||||
ch := s.next()
|
ch := s.next()
|
||||||
|
|
||||||
// skip white space
|
// skip white space
|
||||||
@ -134,7 +132,7 @@ func (s *Scanner) Scan() token.Token {
|
|||||||
ch = s.next()
|
ch = s.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
var tok token.Token
|
var tok TokenType
|
||||||
|
|
||||||
// token text markings
|
// token text markings
|
||||||
s.tokBuf.Reset()
|
s.tokBuf.Reset()
|
||||||
@ -157,54 +155,59 @@ func (s *Scanner) Scan() token.Token {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
case isLetter(ch):
|
case isLetter(ch):
|
||||||
tok = token.IDENT
|
tok = IDENT
|
||||||
lit := s.scanIdentifier()
|
lit := s.scanIdentifier()
|
||||||
if lit == "true" || lit == "false" {
|
if lit == "true" || lit == "false" {
|
||||||
tok = token.BOOL
|
tok = BOOL
|
||||||
}
|
}
|
||||||
case isDecimal(ch):
|
case isDecimal(ch):
|
||||||
tok = s.scanNumber(ch)
|
tok = s.scanNumber(ch)
|
||||||
default:
|
default:
|
||||||
switch ch {
|
switch ch {
|
||||||
case eof:
|
case eof:
|
||||||
tok = token.EOF
|
tok = EOF
|
||||||
case '"':
|
case '"':
|
||||||
tok = token.STRING
|
tok = STRING
|
||||||
s.scanString()
|
s.scanString()
|
||||||
case '#', '/':
|
case '#', '/':
|
||||||
tok = token.COMMENT
|
tok = COMMENT
|
||||||
s.scanComment(ch)
|
s.scanComment(ch)
|
||||||
case '.':
|
case '.':
|
||||||
tok = token.PERIOD
|
tok = PERIOD
|
||||||
ch = s.peek()
|
ch = s.peek()
|
||||||
if isDecimal(ch) {
|
if isDecimal(ch) {
|
||||||
tok = token.FLOAT
|
tok = FLOAT
|
||||||
ch = s.scanMantissa(ch)
|
ch = s.scanMantissa(ch)
|
||||||
ch = s.scanExponent(ch)
|
ch = s.scanExponent(ch)
|
||||||
}
|
}
|
||||||
case '[':
|
case '[':
|
||||||
tok = token.LBRACK
|
tok = LBRACK
|
||||||
case ']':
|
case ']':
|
||||||
tok = token.RBRACK
|
tok = RBRACK
|
||||||
case '{':
|
case '{':
|
||||||
tok = token.LBRACE
|
tok = LBRACE
|
||||||
case '}':
|
case '}':
|
||||||
tok = token.RBRACE
|
tok = RBRACE
|
||||||
case ',':
|
case ',':
|
||||||
tok = token.COMMA
|
tok = COMMA
|
||||||
case '=':
|
case '=':
|
||||||
tok = token.ASSIGN
|
tok = ASSIGN
|
||||||
case '+':
|
case '+':
|
||||||
tok = token.ADD
|
tok = ADD
|
||||||
case '-':
|
case '-':
|
||||||
tok = token.SUB
|
tok = SUB
|
||||||
default:
|
default:
|
||||||
s.err("illegal char")
|
s.err("illegal char")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.tokEnd = s.srcPos.Offset
|
s.tokEnd = s.srcPos.Offset
|
||||||
return tok
|
|
||||||
|
return Token{
|
||||||
|
token: tok,
|
||||||
|
pos: s.tokPos,
|
||||||
|
text: s.TokenText(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenText returns the literal string corresponding to the most recently
|
// TokenText returns the literal string corresponding to the most recently
|
||||||
@ -261,7 +264,7 @@ func (s *Scanner) scanComment(ch rune) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// scanNumber scans a HCL number definition starting with the given rune
|
// scanNumber scans a HCL number definition starting with the given rune
|
||||||
func (s *Scanner) scanNumber(ch rune) token.Token {
|
func (s *Scanner) scanNumber(ch rune) TokenType {
|
||||||
if ch == '0' {
|
if ch == '0' {
|
||||||
// check for hexadecimal, octal or float
|
// check for hexadecimal, octal or float
|
||||||
ch = s.next()
|
ch = s.next()
|
||||||
@ -282,7 +285,7 @@ func (s *Scanner) scanNumber(ch rune) token.Token {
|
|||||||
s.unread()
|
s.unread()
|
||||||
}
|
}
|
||||||
|
|
||||||
return token.NUMBER
|
return NUMBER
|
||||||
}
|
}
|
||||||
|
|
||||||
// now it's either something like: 0421(octal) or 0.1231(float)
|
// now it's either something like: 0421(octal) or 0.1231(float)
|
||||||
@ -300,7 +303,7 @@ func (s *Scanner) scanNumber(ch rune) token.Token {
|
|||||||
// literals of form 01e10 are treates as Numbers in HCL, which differs from Go.
|
// literals of form 01e10 are treates as Numbers in HCL, which differs from Go.
|
||||||
if ch == 'e' || ch == 'E' {
|
if ch == 'e' || ch == 'E' {
|
||||||
ch = s.scanExponent(ch)
|
ch = s.scanExponent(ch)
|
||||||
return token.NUMBER
|
return NUMBER
|
||||||
}
|
}
|
||||||
|
|
||||||
if ch == '.' {
|
if ch == '.' {
|
||||||
@ -310,7 +313,7 @@ func (s *Scanner) scanNumber(ch rune) token.Token {
|
|||||||
ch = s.next()
|
ch = s.next()
|
||||||
ch = s.scanExponent(ch)
|
ch = s.scanExponent(ch)
|
||||||
}
|
}
|
||||||
return token.FLOAT
|
return FLOAT
|
||||||
}
|
}
|
||||||
|
|
||||||
if illegalOctal {
|
if illegalOctal {
|
||||||
@ -320,7 +323,7 @@ func (s *Scanner) scanNumber(ch rune) token.Token {
|
|||||||
if ch != eof {
|
if ch != eof {
|
||||||
s.unread()
|
s.unread()
|
||||||
}
|
}
|
||||||
return token.NUMBER
|
return NUMBER
|
||||||
}
|
}
|
||||||
|
|
||||||
s.scanMantissa(ch)
|
s.scanMantissa(ch)
|
||||||
@ -328,7 +331,7 @@ func (s *Scanner) scanNumber(ch rune) token.Token {
|
|||||||
// literals of form 1e10 are treates as Numbers in HCL, which differs from Go.
|
// literals of form 1e10 are treates as Numbers in HCL, which differs from Go.
|
||||||
if ch == 'e' || ch == 'E' {
|
if ch == 'e' || ch == 'E' {
|
||||||
ch = s.scanExponent(ch)
|
ch = s.scanExponent(ch)
|
||||||
return token.NUMBER
|
return NUMBER
|
||||||
}
|
}
|
||||||
|
|
||||||
if ch == '.' {
|
if ch == '.' {
|
||||||
@ -337,11 +340,11 @@ func (s *Scanner) scanNumber(ch rune) token.Token {
|
|||||||
ch = s.next()
|
ch = s.next()
|
||||||
ch = s.scanExponent(ch)
|
ch = s.scanExponent(ch)
|
||||||
}
|
}
|
||||||
return token.FLOAT
|
return FLOAT
|
||||||
}
|
}
|
||||||
|
|
||||||
s.unread()
|
s.unread()
|
||||||
return token.NUMBER
|
return NUMBER
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanMantissa scans the mantissa begining from the rune. It returns the next
|
// scanMantissa scans the mantissa begining from the rune. It returns the next
|
||||||
|
108
scanner/token.go
Normal file
108
scanner/token.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package scanner
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// Token defines a single HCL token which can be obtained via the Scanner
|
||||||
|
type Token struct {
|
||||||
|
token TokenType
|
||||||
|
pos Position
|
||||||
|
text string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenType is the set of lexical tokens of the HCL (HashiCorp Configuration Language)
|
||||||
|
type TokenType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Special tokens
|
||||||
|
ILLEGAL TokenType = iota
|
||||||
|
EOF
|
||||||
|
COMMENT
|
||||||
|
|
||||||
|
literal_beg
|
||||||
|
IDENT // literals
|
||||||
|
NUMBER // 12345
|
||||||
|
FLOAT // 123.45
|
||||||
|
BOOL // true,false
|
||||||
|
STRING // "abc"
|
||||||
|
literal_end
|
||||||
|
|
||||||
|
operator_beg
|
||||||
|
LBRACK // [
|
||||||
|
LBRACE // {
|
||||||
|
COMMA // ,
|
||||||
|
PERIOD // .
|
||||||
|
|
||||||
|
RBRACK // ]
|
||||||
|
RBRACE // }
|
||||||
|
|
||||||
|
ASSIGN // =
|
||||||
|
ADD // +
|
||||||
|
SUB // -
|
||||||
|
operator_end
|
||||||
|
)
|
||||||
|
|
||||||
|
var tokens = [...]string{
|
||||||
|
ILLEGAL: "ILLEGAL",
|
||||||
|
|
||||||
|
EOF: "EOF",
|
||||||
|
COMMENT: "COMMENT",
|
||||||
|
|
||||||
|
IDENT: "IDENT",
|
||||||
|
NUMBER: "NUMBER",
|
||||||
|
FLOAT: "FLOAT",
|
||||||
|
BOOL: "BOOL",
|
||||||
|
STRING: "STRING",
|
||||||
|
|
||||||
|
LBRACK: "LBRACK",
|
||||||
|
LBRACE: "LBRACE",
|
||||||
|
COMMA: "COMMA",
|
||||||
|
PERIOD: "PERIOD",
|
||||||
|
|
||||||
|
RBRACK: "RBRACK",
|
||||||
|
RBRACE: "RBRACE",
|
||||||
|
|
||||||
|
ASSIGN: "ASSIGN",
|
||||||
|
ADD: "ADD",
|
||||||
|
SUB: "SUB",
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string corresponding to the token tok.
|
||||||
|
// For operators, delimiters, and keywords the string is the actual
|
||||||
|
// token character sequence (e.g., for the token ADD, the string is
|
||||||
|
// "+"). For all other tokens the string corresponds to the token
|
||||||
|
// constant name (e.g. for the token IDENT, the string is "IDENT").
|
||||||
|
func (t TokenType) String() string {
|
||||||
|
s := ""
|
||||||
|
if 0 <= t && t < TokenType(len(tokens)) {
|
||||||
|
s = tokens[t]
|
||||||
|
}
|
||||||
|
if s == "" {
|
||||||
|
s = "token(" + strconv.Itoa(int(t)) + ")"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsLiteral returns true for tokens corresponding to identifiers and basic
|
||||||
|
// type literals; it returns false otherwise.
|
||||||
|
func (t TokenType) IsLiteral() bool { return literal_beg < t && t < literal_end }
|
||||||
|
|
||||||
|
// IsOperator returns true for tokens corresponding to operators and
|
||||||
|
// delimiters; it returns false otherwise.
|
||||||
|
func (t TokenType) IsOperator() bool { return operator_beg < t && t < operator_end }
|
||||||
|
|
||||||
|
// Type returns the token's type
|
||||||
|
func (t Token) Type() TokenType {
|
||||||
|
return t.token
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pos returns the token's position
|
||||||
|
func (t Token) Pos() Position {
|
||||||
|
return t.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text retusn the token's literal text. Note that this is only
|
||||||
|
// applicable for certain token types, such as token.IDENT,
|
||||||
|
// token.STRING, etc..
|
||||||
|
func (t Token) Text() string {
|
||||||
|
return t.text
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user