# Pairs tokens with location data.
import options
type
TokenType* {.pure.} = enum
# Base
LEFT_PAREN, RIGHT_PAREN, LEFT_BRACE, RIGHT_BRACE,
COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR,
# One or two character tokens.
BANG, BANG_EQUAL,
EQUAL, EQUAL_EQUAL,
GREATER, GREATER_EQUAL,
LESS, LESS_EQUAL,
# Literals.
IDENTIFIER, STRING, NUMBER,
# Keywords.
AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR,
PRINT, RETURN, SUPER, THIS, TRUE, VAR, WHILE,
EOF
Literal* = ref object of RootObj
s: Option[string]
f: Option[float]
Token* = ref object of RootObj
token_type: TokenType
lexeme: string
literal: Option[Literal]
line: int
proc new_string_literal*(s: string): Literal =
Literal(s: some(s), f: none(float))
proc new_float_literal*(f: float): Literal =
Literal(s: none(string), f: some(f))
proc `$`*(self: Literal): string =
if self.s.isSome():
self.s.get()
else:
$self.f.get()
proc new_literal_token*(
token_type: TokenType,
lexeme: string,
literal: Literal,
line: int
): Token =
Token(token_type: token_type, lexeme: lexeme, literal: some(literal), line: line)
proc new_none_token*(
token_type: TokenType,
lexeme: string,
line: int
): Token =
Token(token_type: token_type, lexeme: lexeme, literal: none(Literal), line: line)
proc `$`*(token: Token): string =
let lit =
if token.literal.isNone():
""
else:
$token.literal.get()
$token.token_type & " " & token.lexeme & " " & lit