token.odin 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. package odin_tokenizer
  2. import "core:strings"
  3. Token :: struct {
  4. kind: Token_Kind,
  5. text: string,
  6. pos: Pos,
  7. }
  8. Pos :: struct {
  9. file: string,
  10. offset: int, // starting at 0
  11. line: int, // starting at 1
  12. column: int, // starting at 1
  13. }
  14. pos_compare :: proc(lhs, rhs: Pos) -> int {
  15. if lhs.offset != rhs.offset {
  16. return -1 if (lhs.offset < rhs.offset) else +1;
  17. }
  18. if lhs.line != rhs.line {
  19. return -1 if (lhs.line < rhs.line) else +1;
  20. }
  21. if lhs.column != rhs.column {
  22. return -1 if (lhs.column < rhs.column) else +1;
  23. }
  24. return strings.compare(lhs.file, rhs.file);
  25. }
  26. Token_Kind :: enum u32 {
  27. Invalid,
  28. EOF,
  29. Comment,
  30. B_Literal_Begin,
  31. Ident, // main
  32. Integer, // 12345
  33. Float, // 123.45
  34. Imag, // 123.45i
  35. Rune, // 'a'
  36. String, // "abc"
  37. B_Literal_End,
  38. B_Operator_Begin,
  39. Eq, // =
  40. Not, // !
  41. Hash, // #
  42. At, // @
  43. Dollar, // $
  44. Pointer, // ^
  45. Question, // ?
  46. Add, // +
  47. Sub, // -
  48. Mul, // *
  49. Quo, // /
  50. Mod, // %
  51. Mod_Mod, // %%
  52. And, // &
  53. Or, // |
  54. Xor, // ~
  55. And_Not, // &~
  56. Shl, // <<
  57. Shr, // >>
  58. Cmp_And, // &&
  59. Cmp_Or, // ||
  60. B_Assign_Op_Begin,
  61. Add_Eq, // +=
  62. Sub_Eq, // -=
  63. Mul_Eq, // *=
  64. Quo_Eq, // /=
  65. Mod_Eq, // %=
  66. Mod_Mod_Eq, // %%=
  67. And_Eq, // &=
  68. Or_Eq, // |=
  69. Xor_Eq, // ~=
  70. And_Not_Eq, // &~=
  71. Shl_Eq, // <<=
  72. Shr_Eq, // >>=
  73. Cmp_And_Eq, // &&=
  74. Cmp_Or_Eq, // ||=
  75. B_Assign_Op_End,
  76. Arrow_Right, // ->
  77. Undef, // ---
  78. B_Comparison_Begin,
  79. Cmp_Eq, // ==
  80. Not_Eq, // !=
  81. Lt, // <
  82. Gt, // >
  83. Lt_Eq, // <=
  84. Gt_Eq, // >=
  85. B_Comparison_End,
  86. Open_Paren, // (
  87. Close_Paren, // )
  88. Open_Bracket, // [
  89. Close_Bracket, // ]
  90. Open_Brace, // {
  91. Close_Brace, // }
  92. Colon, // :
  93. Semicolon, // ;
  94. Period, // .
  95. Comma, // ,
  96. Ellipsis, // ..
  97. Range_Half, // ..<
  98. Back_Slash, // \
  99. B_Operator_End,
  100. B_Keyword_Begin,
  101. Import, // import
  102. Foreign, // foreign
  103. Package, // package
  104. Typeid, // typeid
  105. When, // when
  106. Where, // where
  107. If, // if
  108. Else, // else
  109. For, // for
  110. Switch, // switch
  111. In, // in
  112. Not_In, // not_in
  113. Do, // do
  114. Case, // case
  115. Break, // break
  116. Continue, // continue
  117. Fallthrough, // fallthrough
  118. Defer, // defer
  119. Return, // return
  120. Proc, // proc
  121. Struct, // struct
  122. Union, // union
  123. Enum, // enum
  124. Bit_Set, // bit_set
  125. Map, // map
  126. Dynamic, // dynamic
  127. Auto_Cast, // auto_cast
  128. Cast, // cast
  129. Transmute, // transmute
  130. Distinct, // distinct
  131. Using, // using
  132. Inline, // inline
  133. No_Inline, // no_inline
  134. Context, // context
  135. Asm, // asm
  136. B_Keyword_End,
  137. COUNT,
  138. B_Custom_Keyword_Begin = COUNT+1,
  139. // ... Custom keywords
  140. };
  141. tokens := [Token_Kind.COUNT]string {
  142. "Invalid",
  143. "EOF",
  144. "Comment",
  145. "",
  146. "identifier",
  147. "integer",
  148. "float",
  149. "imaginary",
  150. "rune",
  151. "string",
  152. "",
  153. "",
  154. "=",
  155. "!",
  156. "#",
  157. "@",
  158. "$",
  159. "^",
  160. "?",
  161. "+",
  162. "-",
  163. "*",
  164. "/",
  165. "%",
  166. "%%",
  167. "&",
  168. "|",
  169. "~",
  170. "&~",
  171. "<<",
  172. ">>",
  173. "&&",
  174. "||",
  175. "",
  176. "+=",
  177. "-=",
  178. "*=",
  179. "/=",
  180. "%=",
  181. "%%=",
  182. "&=",
  183. "|=",
  184. "~=",
  185. "&~=",
  186. "<<=",
  187. ">>=",
  188. "&&=",
  189. "||=",
  190. "",
  191. "->",
  192. "---",
  193. "",
  194. "==",
  195. "!=",
  196. "<",
  197. ">",
  198. "<=",
  199. ">=",
  200. "",
  201. "(",
  202. ")",
  203. "[",
  204. "]",
  205. "{",
  206. "}",
  207. ":",
  208. ";",
  209. ".",
  210. ",",
  211. "..",
  212. "..<",
  213. "\\",
  214. "",
  215. "",
  216. "import",
  217. "foreign",
  218. "package",
  219. "typeid",
  220. "when",
  221. "where",
  222. "if",
  223. "else",
  224. "for",
  225. "switch",
  226. "in",
  227. "not_in",
  228. "do",
  229. "case",
  230. "break",
  231. "continue",
  232. "fallthrough",
  233. "defer",
  234. "return",
  235. "proc",
  236. "struct",
  237. "union",
  238. "enum",
  239. "bit_set",
  240. "map",
  241. "dynamic",
  242. "auto_cast",
  243. "cast",
  244. "transmute",
  245. "distinct",
  246. "using",
  247. "inline",
  248. "no_inline",
  249. "context",
  250. "asm",
  251. "",
  252. };
  253. custom_keyword_tokens: []string;
  254. is_newline :: proc(tok: Token) -> bool {
  255. return tok.kind == .Semicolon && tok.text == "\n";
  256. }
  257. token_to_string :: proc(tok: Token) -> string {
  258. if is_newline(tok) {
  259. return "newline";
  260. }
  261. return to_string(tok.kind);
  262. }
  263. to_string :: proc(kind: Token_Kind) -> string {
  264. if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
  265. return tokens[kind];
  266. }
  267. if Token_Kind.B_Custom_Keyword_Begin < kind {
  268. n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin));
  269. if n < len(custom_keyword_tokens) {
  270. return custom_keyword_tokens[n];
  271. }
  272. }
  273. return "Invalid";
  274. }
  275. is_literal :: proc(kind: Token_Kind) -> bool {
  276. return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End;
  277. }
  278. is_operator :: proc(kind: Token_Kind) -> bool {
  279. #partial switch kind {
  280. case .B_Operator_Begin .. .B_Operator_End:
  281. return true;
  282. case .In, .Not_In:
  283. return true;
  284. case .If:
  285. return true;
  286. }
  287. return false;
  288. }
  289. is_assignment_operator :: proc(kind: Token_Kind) -> bool {
  290. return Token_Kind.B_Assign_Op_Begin < kind && kind < Token_Kind.B_Assign_Op_End || kind == Token_Kind.Eq;
  291. }
  292. is_keyword :: proc(kind: Token_Kind) -> bool {
  293. switch {
  294. case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End:
  295. return true;
  296. case Token_Kind.B_Custom_Keyword_Begin < kind:
  297. return true;
  298. }
  299. return false;
  300. }