token.odin 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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. Range_Full, // ..=
  99. Back_Slash, // \
  100. B_Operator_End,
  101. B_Keyword_Begin,
  102. Import, // import
  103. Foreign, // foreign
  104. Package, // package
  105. Typeid, // typeid
  106. When, // when
  107. Where, // where
  108. If, // if
  109. Else, // else
  110. For, // for
  111. Switch, // switch
  112. In, // in
  113. Not_In, // not_in
  114. Do, // do
  115. Case, // case
  116. Break, // break
  117. Continue, // continue
  118. Fallthrough, // fallthrough
  119. Defer, // defer
  120. Return, // return
  121. Proc, // proc
  122. Struct, // struct
  123. Union, // union
  124. Enum, // enum
  125. Bit_Set, // bit_set
  126. Map, // map
  127. Dynamic, // dynamic
  128. Auto_Cast, // auto_cast
  129. Cast, // cast
  130. Transmute, // transmute
  131. Distinct, // distinct
  132. Using, // using
  133. Inline, // inline
  134. No_Inline, // no_inline
  135. Context, // context
  136. Asm, // asm
  137. B_Keyword_End,
  138. COUNT,
  139. B_Custom_Keyword_Begin = COUNT+1,
  140. // ... Custom keywords
  141. };
  142. tokens := [Token_Kind.COUNT]string {
  143. "Invalid",
  144. "EOF",
  145. "Comment",
  146. "",
  147. "identifier",
  148. "integer",
  149. "float",
  150. "imaginary",
  151. "rune",
  152. "string",
  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. "",
  217. "",
  218. "import",
  219. "foreign",
  220. "package",
  221. "typeid",
  222. "when",
  223. "where",
  224. "if",
  225. "else",
  226. "for",
  227. "switch",
  228. "in",
  229. "not_in",
  230. "do",
  231. "case",
  232. "break",
  233. "continue",
  234. "fallthrough",
  235. "defer",
  236. "return",
  237. "proc",
  238. "struct",
  239. "union",
  240. "enum",
  241. "bit_set",
  242. "map",
  243. "dynamic",
  244. "auto_cast",
  245. "cast",
  246. "transmute",
  247. "distinct",
  248. "using",
  249. "inline",
  250. "no_inline",
  251. "context",
  252. "asm",
  253. "",
  254. };
  255. custom_keyword_tokens: []string;
  256. is_newline :: proc(tok: Token) -> bool {
  257. return tok.kind == .Semicolon && tok.text == "\n";
  258. }
  259. token_to_string :: proc(tok: Token) -> string {
  260. if is_newline(tok) {
  261. return "newline";
  262. }
  263. return to_string(tok.kind);
  264. }
  265. to_string :: proc(kind: Token_Kind) -> string {
  266. if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
  267. return tokens[kind];
  268. }
  269. if Token_Kind.B_Custom_Keyword_Begin < kind {
  270. n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin));
  271. if n < len(custom_keyword_tokens) {
  272. return custom_keyword_tokens[n];
  273. }
  274. }
  275. return "Invalid";
  276. }
  277. is_literal :: proc(kind: Token_Kind) -> bool {
  278. return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End;
  279. }
  280. is_operator :: proc(kind: Token_Kind) -> bool {
  281. #partial switch kind {
  282. case .B_Operator_Begin .. .B_Operator_End:
  283. return true;
  284. case .In, .Not_In:
  285. return true;
  286. case .If:
  287. return true;
  288. }
  289. return false;
  290. }
  291. is_assignment_operator :: proc(kind: Token_Kind) -> bool {
  292. return Token_Kind.B_Assign_Op_Begin < kind && kind < Token_Kind.B_Assign_Op_End || kind == Token_Kind.Eq;
  293. }
  294. is_keyword :: proc(kind: Token_Kind) -> bool {
  295. switch {
  296. case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End:
  297. return true;
  298. case Token_Kind.B_Custom_Keyword_Begin < kind:
  299. return true;
  300. }
  301. return false;
  302. }