class TokenType(IntEnum):
IDENT = auto()
STRING = auto()
+ LEFT_PAREN = auto()
+ RIGHT_PAREN = auto()
+ MINUS = auto()
+ RETURNER = auto()
+ LEFT_BRACE = auto()
+ RIGHT_BRACE = auto()
+ PLUS = auto()
+ DIVIDE = auto()
+ MULTIPLY = auto()
+ MODULUS = auto()
+ EQUAL = auto()
+ NOT = auto()
+ NOT_EQUAL = auto()
+ EQUAL_EQUAL = auto()
+ GT = auto()
+ LT = auto()
+ GTE = auto()
+ LTE = auto()
COUNT = auto()
token_type_as_str_map: { TokenType : str } = {
- TokenType.IDENT : "Ident",
- TokenType.STRING : "String",
- TokenType.COUNT : "Count",
+ TokenType.IDENT : "Ident",
+ TokenType.STRING : "String",
+ TokenType.LEFT_PAREN : "Left paren",
+ TokenType.RIGHT_PAREN : "Right paren",
+ TokenType.MINUS : "Minus",
+ TokenType.LEFT_BRACE : "Left brace",
+ TokenType.RIGHT_BRACE : "Right brace",
+ TokenType.RETURNER : "Returner",
+ TokenType.PLUS : "Plus",
+ TokenType.DIVIDE : "Divide",
+ TokenType.MULTIPLY : "Multiply",
+ TokenType.MODULUS : "Modulus",
+ TokenType.EQUAL : "Equal",
+ TokenType.NOT : "Not",
+ TokenType.NOT_EQUAL : "Not Equal",
+ TokenType.EQUAL_EQUAL : "Equal Equal",
+ TokenType.GT : "Greater Than",
+ TokenType.LT : "Less Than",
+ TokenType.GTE : "Greater Than or Equal",
+ TokenType.LTE : "Less Than or Equal",
}
+# NOTE: TokenType.COUNT - 1 because auto() starts from 1
+assert len(token_type_as_str_map) == TokenType.COUNT-1
class Token:
def __init__(self, typ: TokenType, value: str, loc: Loc):
assert self.cur < len(self.src), f"cur: {self.cur}, src_len: {len(self.src)}"
return self.src[self.cur]
+ def peek_next_char(self) -> str | int:
+ if self.cur + 1 >= len(self.src): return -1
+ return self.src[self.cur + 1]
+
def consume_char(self) -> str:
c = self.current_char()
self.cur += 1
c = self.current_char()
- t: Token | None = None
if c == '"':
value, loc = self.consume_string()
- t = Token(TokenType.STRING, value, loc)
+ return Token(TokenType.STRING, value, loc)
elif c.isalpha() or c == '_':
ident, loc = self.consume_identifier()
- t = Token(TokenType.IDENT, ident, loc)
+ return Token(TokenType.IDENT, ident, loc)
+ elif c == '(':
+ loc = Loc(self.filename, self.line, self.row())
+ return Token(TokenType.LEFT_PAREN, self.consume_char(), loc)
+ elif c == ')':
+ loc = Loc(self.filename, self.line, self.row())
+ return Token(TokenType.RIGHT_PAREN, self.consume_char(), loc)
+ elif c == '-':
+ loc = Loc(self.filename, self.line, self.row())
+ # Check if its a returner '->'
+ if self.peek_next_char() == '>':
+ return Token(TokenType.RETURNER, self.consume_char() + self.consume_char(), loc)
+
+ return Token(TokenType.MINUS, self.consume_char(), loc)
+ elif c == '{':
+ loc = Loc(self.filename, self.line, self.row())
+ return Token(TokenType.LEFT_BRACE, self.consume_char(), loc)
+ elif c == '}':
+ loc = Loc(self.filename, self.line, self.row())
+ return Token(TokenType.RIGHT_BRACE, self.consume_char(), loc)
+ elif c == '+':
+ loc = Loc(self.filename, self.line, self.row())
+ return Token(TokenType.PLUS, self.consume_char(), loc)
+ elif c == '/':
+ loc = Loc(self.filename, self.line, self.row())
+ return Token(TokenType.DIVIDE, self.consume_char(), loc)
+ elif c == '*':
+ loc = Loc(self.filename, self.line, self.row())
+ return Token(TokenType.MULTIPLY, self.consume_char(), loc)
+ elif c == '%':
+ loc = Loc(self.filename, self.line, self.row())
+ return Token(TokenType.MODULUS, self.consume_char(), loc)
+ elif c == '=':
+ loc = Loc(self.filename, self.line, self.row())
+ # Check if '=='
+ if self.peek_next_char() == '=':
+ return Token(TokenType.EQUAL_EQUAL, self.consume_char() + self.consume_char(), loc)
+ return Token(TokenType.EQUAL, self.consume_char(), loc)
+ elif c == '!':
+ loc = Loc(self.filename, self.line, self.row())
+ # Check if '!='
+ if self.peek_next_char() == '=':
+ return Token(TokenType.NOT_EQUAL, self.consume_char() + self.consume_char(), loc)
+ return Token(TokenType.NOT, self.consume_char(), loc)
+ elif c == '>':
+ loc = Loc(self.filename, self.line, self.row())
+ # Check if '>='
+ if self.peek_next_char() == '=':
+ return Token(TokenType.GTE, self.consume_char() + self.consume_char(), loc)
+ return Token(TokenType.GT, self.consume_char(), loc)
+ elif c == '<':
+ loc = Loc(self.filename, self.line, self.row())
+ # Check if '<='
+ if self.peek_next_char() == '=':
+ return Token(TokenType.LTE, self.consume_char() + self.consume_char(), loc)
+ return Token(TokenType.LT, self.consume_char(), loc)
else:
fatal(f"Unrecognized character '{c}'")
- return t
+ return None
def main():
program: str = sys.argv.pop(0)
--- /dev/null
+"Token (Left paren, '(', ./tests/06-single-char-symbols.momo:1:0)"
+"Token (Right paren, ')', ./tests/06-single-char-symbols.momo:1:2)"
+"Token (Left brace, '{', ./tests/06-single-char-symbols.momo:1:4)"
+"Token (Right brace, '}', ./tests/06-single-char-symbols.momo:1:5)"
+"Token (Returner, '->', ./tests/06-single-char-symbols.momo:1:7)"
+"Token (Minus, '-', ./tests/06-single-char-symbols.momo:2:0)"
+"Token (Plus, '+', ./tests/06-single-char-symbols.momo:2:2)"
+"Token (Divide, '/', ./tests/06-single-char-symbols.momo:2:4)"
+"Token (Multiply, '*', ./tests/06-single-char-symbols.momo:2:6)"
+"Token (Modulus, '%', ./tests/06-single-char-symbols.momo:2:8)"
+"Token (Equal, '=', ./tests/06-single-char-symbols.momo:3:0)"
+"Token (Not, '!', ./tests/06-single-char-symbols.momo:3:2)"
+"Token (Greater Than or Equal, '>=', ./tests/06-single-char-symbols.momo:4:0)"
+"Token (Greater Than, '>', ./tests/06-single-char-symbols.momo:4:3)"
+"Token (Less Than, '<', ./tests/06-single-char-symbols.momo:4:5)"
+"Token (Less Than or Equal, '<=', ./tests/06-single-char-symbols.momo:4:7)"
+"Token (Not Equal, '!=', ./tests/06-single-char-symbols.momo:4:10)"
+"Token (Equal Equal, '==', ./tests/06-single-char-symbols.momo:4:13)"
+'None'