token.odin 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. Asm, // asm
  138. Inline, // inline
  139. No_Inline, // no_inline
  140. Matrix, // matrix
  141. B_Keyword_End,
  142. COUNT,
  143. B_Custom_Keyword_Begin = COUNT+1,
  144. // ... Custom keywords
  145. }
  146. tokens := [Token_Kind.COUNT]string {
  147. "Invalid",
  148. "EOF",
  149. "Comment",
  150. "",
  151. "identifier",
  152. "integer",
  153. "float",
  154. "imaginary",
  155. "rune",
  156. "string",
  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. "..",
  219. "..<",
  220. "..=",
  221. "",
  222. "",
  223. "import",
  224. "foreign",
  225. "package",
  226. "typeid",
  227. "when",
  228. "where",
  229. "if",
  230. "else",
  231. "for",
  232. "switch",
  233. "in",
  234. "not_in",
  235. "do",
  236. "case",
  237. "break",
  238. "continue",
  239. "fallthrough",
  240. "defer",
  241. "return",
  242. "proc",
  243. "struct",
  244. "union",
  245. "enum",
  246. "bit_set",
  247. "map",
  248. "dynamic",
  249. "auto_cast",
  250. "cast",
  251. "transmute",
  252. "distinct",
  253. "using",
  254. "context",
  255. "or_else",
  256. "or_return",
  257. "asm",
  258. "inline",
  259. "no_inline",
  260. "matrix",
  261. "",
  262. }
  263. custom_keyword_tokens: []string
  264. is_newline :: proc(tok: Token) -> bool {
  265. return tok.kind == .Semicolon && tok.text == "\n"
  266. }
  267. token_to_string :: proc(tok: Token) -> string {
  268. if is_newline(tok) {
  269. return "newline"
  270. }
  271. return to_string(tok.kind)
  272. }
  273. to_string :: proc(kind: Token_Kind) -> string {
  274. if .Invalid <= kind && kind < .COUNT {
  275. return tokens[kind]
  276. }
  277. if .B_Custom_Keyword_Begin < kind {
  278. n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin))
  279. if n < len(custom_keyword_tokens) {
  280. return custom_keyword_tokens[n]
  281. }
  282. }
  283. return "Invalid"
  284. }
  285. is_literal :: proc(kind: Token_Kind) -> bool {
  286. return .B_Literal_Begin < kind && kind < .B_Literal_End
  287. }
  288. is_operator :: proc(kind: Token_Kind) -> bool {
  289. #partial switch kind {
  290. case .B_Operator_Begin ..= .B_Operator_End:
  291. return true
  292. case .In, .Not_In:
  293. return true
  294. case .If:
  295. return true
  296. }
  297. return false
  298. }
  299. is_assignment_operator :: proc(kind: Token_Kind) -> bool {
  300. return .B_Assign_Op_Begin < kind && kind < .B_Assign_Op_End || kind == .Eq
  301. }
  302. is_keyword :: proc(kind: Token_Kind) -> bool {
  303. switch {
  304. case .B_Keyword_Begin < kind && kind < .B_Keyword_End:
  305. return true
  306. case .B_Custom_Keyword_Begin < kind:
  307. return true
  308. }
  309. return false
  310. }