token.odin 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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. Increment, // ++
  77. Decrement, // --
  78. Arrow_Right, // ->
  79. Undef, // ---
  80. B_Comparison_Begin,
  81. Cmp_Eq, // ==
  82. Not_Eq, // !=
  83. Lt, // <
  84. Gt, // >
  85. Lt_Eq, // <=
  86. Gt_Eq, // >=
  87. B_Comparison_End,
  88. Open_Paren, // (
  89. Close_Paren, // )
  90. Open_Bracket, // [
  91. Close_Bracket, // ]
  92. Open_Brace, // {
  93. Close_Brace, // }
  94. Colon, // :
  95. Semicolon, // ;
  96. Period, // .
  97. Comma, // ,
  98. Ellipsis, // ..
  99. Range_Half, // ..<
  100. Range_Full, // ..=
  101. B_Operator_End,
  102. B_Keyword_Begin,
  103. Import, // import
  104. Foreign, // foreign
  105. Package, // package
  106. Typeid, // typeid
  107. When, // when
  108. Where, // where
  109. If, // if
  110. Else, // else
  111. For, // for
  112. Switch, // switch
  113. In, // in
  114. Not_In, // not_in
  115. Do, // do
  116. Case, // case
  117. Break, // break
  118. Continue, // continue
  119. Fallthrough, // fallthrough
  120. Defer, // defer
  121. Return, // return
  122. Proc, // proc
  123. Struct, // struct
  124. Union, // union
  125. Enum, // enum
  126. Bit_Set, // bit_set
  127. Map, // map
  128. Dynamic, // dynamic
  129. Auto_Cast, // auto_cast
  130. Cast, // cast
  131. Transmute, // transmute
  132. Distinct, // distinct
  133. Using, // using
  134. Context, // context
  135. Or_Else, // or_else
  136. Or_Return, // or_return
  137. Or_Break, // or_break
  138. Or_Continue, // or_continue
  139. Asm, // asm
  140. Inline, // inline
  141. No_Inline, // no_inline
  142. Matrix, // matrix
  143. B_Keyword_End,
  144. COUNT,
  145. B_Custom_Keyword_Begin = COUNT+1,
  146. // ... Custom keywords
  147. }
  148. tokens := [Token_Kind.COUNT]string {
  149. "Invalid",
  150. "EOF",
  151. "Comment",
  152. "",
  153. "identifier",
  154. "integer",
  155. "float",
  156. "imaginary",
  157. "rune",
  158. "string",
  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. ".",
  219. ",",
  220. "..",
  221. "..<",
  222. "..=",
  223. "",
  224. "",
  225. "import",
  226. "foreign",
  227. "package",
  228. "typeid",
  229. "when",
  230. "where",
  231. "if",
  232. "else",
  233. "for",
  234. "switch",
  235. "in",
  236. "not_in",
  237. "do",
  238. "case",
  239. "break",
  240. "continue",
  241. "fallthrough",
  242. "defer",
  243. "return",
  244. "proc",
  245. "struct",
  246. "union",
  247. "enum",
  248. "bit_set",
  249. "map",
  250. "dynamic",
  251. "auto_cast",
  252. "cast",
  253. "transmute",
  254. "distinct",
  255. "using",
  256. "context",
  257. "or_else",
  258. "or_return",
  259. "or_break",
  260. "or_continue",
  261. "asm",
  262. "inline",
  263. "no_inline",
  264. "matrix",
  265. "",
  266. }
  267. custom_keyword_tokens: []string
  268. is_newline :: proc(tok: Token) -> bool {
  269. return tok.kind == .Semicolon && tok.text == "\n"
  270. }
  271. token_to_string :: proc(tok: Token) -> string {
  272. if is_newline(tok) {
  273. return "newline"
  274. }
  275. return to_string(tok.kind)
  276. }
  277. to_string :: proc(kind: Token_Kind) -> string {
  278. if .Invalid <= kind && kind < .COUNT {
  279. return tokens[kind]
  280. }
  281. if .B_Custom_Keyword_Begin < kind {
  282. n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin))
  283. if n < len(custom_keyword_tokens) {
  284. return custom_keyword_tokens[n]
  285. }
  286. }
  287. return "Invalid"
  288. }
  289. is_literal :: proc(kind: Token_Kind) -> bool {
  290. return .B_Literal_Begin < kind && kind < .B_Literal_End
  291. }
  292. is_operator :: proc(kind: Token_Kind) -> bool {
  293. #partial switch kind {
  294. case .B_Operator_Begin ..= .B_Operator_End:
  295. return true
  296. case .In, .Not_In:
  297. return true
  298. case .If:
  299. return true
  300. }
  301. return false
  302. }
  303. is_assignment_operator :: proc(kind: Token_Kind) -> bool {
  304. return .B_Assign_Op_Begin < kind && kind < .B_Assign_Op_End || kind == .Eq
  305. }
  306. is_keyword :: proc(kind: Token_Kind) -> bool {
  307. switch {
  308. case .B_Keyword_Begin < kind && kind < .B_Keyword_End:
  309. return true
  310. case .B_Custom_Keyword_Begin < kind:
  311. return true
  312. }
  313. return false
  314. }