token.odin 5.3 KB

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