Files
Odin/core/odin/tokenizer/token.odin
2023-09-30 15:04:17 +01:00

347 lines
5.3 KiB
Odin

package odin_tokenizer
import "core:strings"
Token :: struct {
kind: Token_Kind,
text: string,
pos: Pos,
}
Pos :: struct {
file: string,
offset: int, // starting at 0
line: int, // starting at 1
column: int, // starting at 1
}
pos_compare :: proc(lhs, rhs: Pos) -> int {
if lhs.offset != rhs.offset {
return -1 if (lhs.offset < rhs.offset) else +1
}
if lhs.line != rhs.line {
return -1 if (lhs.line < rhs.line) else +1
}
if lhs.column != rhs.column {
return -1 if (lhs.column < rhs.column) else +1
}
return strings.compare(lhs.file, rhs.file)
}
Token_Kind :: enum u32 {
Invalid,
EOF,
Comment,
B_Literal_Begin,
Ident, // main
Integer, // 12345
Float, // 123.45
Imag, // 123.45i
Rune, // 'a'
String, // "abc"
B_Literal_End,
B_Operator_Begin,
Eq, // =
Not, // !
Hash, // #
At, // @
Dollar, // $
Pointer, // ^
Question, // ?
Add, // +
Sub, // -
Mul, // *
Quo, // /
Mod, // %
Mod_Mod, // %%
And, // &
Or, // |
Xor, // ~
And_Not, // &~
Shl, // <<
Shr, // >>
Cmp_And, // &&
Cmp_Or, // ||
B_Assign_Op_Begin,
Add_Eq, // +=
Sub_Eq, // -=
Mul_Eq, // *=
Quo_Eq, // /=
Mod_Eq, // %=
Mod_Mod_Eq, // %%=
And_Eq, // &=
Or_Eq, // |=
Xor_Eq, // ~=
And_Not_Eq, // &~=
Shl_Eq, // <<=
Shr_Eq, // >>=
Cmp_And_Eq, // &&=
Cmp_Or_Eq, // ||=
B_Assign_Op_End,
Increment, // ++
Decrement, // --
Arrow_Right, // ->
Undef, // ---
B_Comparison_Begin,
Cmp_Eq, // ==
Not_Eq, // !=
Lt, // <
Gt, // >
Lt_Eq, // <=
Gt_Eq, // >=
B_Comparison_End,
Open_Paren, // (
Close_Paren, // )
Open_Bracket, // [
Close_Bracket, // ]
Open_Brace, // {
Close_Brace, // }
Colon, // :
Semicolon, // ;
Period, // .
Comma, // ,
Ellipsis, // ..
Range_Half, // ..<
Range_Full, // ..=
B_Operator_End,
B_Keyword_Begin,
Import, // import
Foreign, // foreign
Package, // package
Typeid, // typeid
When, // when
Where, // where
If, // if
Else, // else
For, // for
Switch, // switch
In, // in
Not_In, // not_in
Do, // do
Case, // case
Break, // break
Continue, // continue
Fallthrough, // fallthrough
Defer, // defer
Return, // return
Proc, // proc
Struct, // struct
Union, // union
Enum, // enum
Bit_Set, // bit_set
Map, // map
Dynamic, // dynamic
Auto_Cast, // auto_cast
Cast, // cast
Transmute, // transmute
Distinct, // distinct
Using, // using
Context, // context
Or_Else, // or_else
Or_Return, // or_return
Or_Break, // or_break
Or_Continue, // or_continue
Asm, // asm
Inline, // inline
No_Inline, // no_inline
Matrix, // matrix
B_Keyword_End,
COUNT,
B_Custom_Keyword_Begin = COUNT+1,
// ... Custom keywords
}
tokens := [Token_Kind.COUNT]string {
"Invalid",
"EOF",
"Comment",
"",
"identifier",
"integer",
"float",
"imaginary",
"rune",
"string",
"",
"",
"=",
"!",
"#",
"@",
"$",
"^",
"?",
"+",
"-",
"*",
"/",
"%",
"%%",
"&",
"|",
"~",
"&~",
"<<",
">>",
"&&",
"||",
"",
"+=",
"-=",
"*=",
"/=",
"%=",
"%%=",
"&=",
"|=",
"~=",
"&~=",
"<<=",
">>=",
"&&=",
"||=",
"",
"++",
"--",
"->",
"---",
"",
"==",
"!=",
"<",
">",
"<=",
">=",
"",
"(",
")",
"[",
"]",
"{",
"}",
":",
";",
".",
",",
"..",
"..<",
"..=",
"",
"",
"import",
"foreign",
"package",
"typeid",
"when",
"where",
"if",
"else",
"for",
"switch",
"in",
"not_in",
"do",
"case",
"break",
"continue",
"fallthrough",
"defer",
"return",
"proc",
"struct",
"union",
"enum",
"bit_set",
"map",
"dynamic",
"auto_cast",
"cast",
"transmute",
"distinct",
"using",
"context",
"or_else",
"or_return",
"or_break",
"or_continue",
"asm",
"inline",
"no_inline",
"matrix",
"",
}
custom_keyword_tokens: []string
is_newline :: proc(tok: Token) -> bool {
return tok.kind == .Semicolon && tok.text == "\n"
}
token_to_string :: proc(tok: Token) -> string {
if is_newline(tok) {
return "newline"
}
return to_string(tok.kind)
}
to_string :: proc(kind: Token_Kind) -> string {
if .Invalid <= kind && kind < .COUNT {
return tokens[kind]
}
if .B_Custom_Keyword_Begin < kind {
n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin))
if n < len(custom_keyword_tokens) {
return custom_keyword_tokens[n]
}
}
return "Invalid"
}
is_literal :: proc(kind: Token_Kind) -> bool {
return .B_Literal_Begin < kind && kind < .B_Literal_End
}
is_operator :: proc(kind: Token_Kind) -> bool {
#partial switch kind {
case .B_Operator_Begin ..= .B_Operator_End:
return true
case .In, .Not_In:
return true
case .If:
return true
}
return false
}
is_assignment_operator :: proc(kind: Token_Kind) -> bool {
return .B_Assign_Op_Begin < kind && kind < .B_Assign_Op_End || kind == .Eq
}
is_keyword :: proc(kind: Token_Kind) -> bool {
switch {
case .B_Keyword_Begin < kind && kind < .B_Keyword_End:
return true
case .B_Custom_Keyword_Begin < kind:
return true
}
return false
}