| ... | ... | @@ -5,60 +5,66 @@ const heap = @import("std").heap; |
| 5 | 5 | const warn = @import("std").debug.warn; |
| 6 | 6 | const assert = @import("std").debug.assert; |
| 7 | 7 | const mem = @import("std").mem; |
| 8 | const ArrayList = @import("std").ArrayList; |
| 9 | |
| 8 | 10 | |
| 9 | 11 | const Token = struct { |
| 10 | 12 | id: Id, |
| 11 | 13 | start: usize, |
| 12 | 14 | end: usize, |
| 13 | 15 | |
| 14 | | const Keyword = enum { |
| 15 | | @"align", |
| 16 | | @"and", |
| 17 | | @"asm", |
| 18 | | @"break", |
| 19 | | @"coldcc", |
| 20 | | @"comptime", |
| 21 | | @"const", |
| 22 | | @"continue", |
| 23 | | @"defer", |
| 24 | | @"else", |
| 25 | | @"enum", |
| 26 | | @"error", |
| 27 | | @"export", |
| 28 | | @"extern", |
| 29 | | @"false", |
| 30 | | @"fn", |
| 31 | | @"for", |
| 32 | | @"goto", |
| 33 | | @"if", |
| 34 | | @"inline", |
| 35 | | @"nakedcc", |
| 36 | | @"noalias", |
| 37 | | @"null", |
| 38 | | @"or", |
| 39 | | @"packed", |
| 40 | | @"pub", |
| 41 | | @"return", |
| 42 | | @"stdcallcc", |
| 43 | | @"struct", |
| 44 | | @"switch", |
| 45 | | @"test", |
| 46 | | @"this", |
| 47 | | @"true", |
| 48 | | @"undefined", |
| 49 | | @"union", |
| 50 | | @"unreachable", |
| 51 | | @"use", |
| 52 | | @"var", |
| 53 | | @"volatile", |
| 54 | | @"while", |
| 16 | const KeywordId = struct { |
| 17 | bytes: []const u8, |
| 18 | id: Id, |
| 19 | }; |
| 20 | |
| 21 | const keywords = []KeywordId { |
| 22 | KeywordId{.bytes="align", .id = Id {.Keyword_align = {}}}, |
| 23 | KeywordId{.bytes="and", .id = Id {.Keyword_and = {}}}, |
| 24 | KeywordId{.bytes="asm", .id = Id {.Keyword_asm = {}}}, |
| 25 | KeywordId{.bytes="break", .id = Id {.Keyword_break = {}}}, |
| 26 | KeywordId{.bytes="coldcc", .id = Id {.Keyword_coldcc = {}}}, |
| 27 | KeywordId{.bytes="comptime", .id = Id {.Keyword_comptime = {}}}, |
| 28 | KeywordId{.bytes="const", .id = Id {.Keyword_const = {}}}, |
| 29 | KeywordId{.bytes="continue", .id = Id {.Keyword_continue = {}}}, |
| 30 | KeywordId{.bytes="defer", .id = Id {.Keyword_defer = {}}}, |
| 31 | KeywordId{.bytes="else", .id = Id {.Keyword_else = {}}}, |
| 32 | KeywordId{.bytes="enum", .id = Id {.Keyword_enum = {}}}, |
| 33 | KeywordId{.bytes="error", .id = Id {.Keyword_error = {}}}, |
| 34 | KeywordId{.bytes="export", .id = Id {.Keyword_export = {}}}, |
| 35 | KeywordId{.bytes="extern", .id = Id {.Keyword_extern = {}}}, |
| 36 | KeywordId{.bytes="false", .id = Id {.Keyword_false = {}}}, |
| 37 | KeywordId{.bytes="fn", .id = Id {.Keyword_fn = {}}}, |
| 38 | KeywordId{.bytes="for", .id = Id {.Keyword_for = {}}}, |
| 39 | KeywordId{.bytes="goto", .id = Id {.Keyword_goto = {}}}, |
| 40 | KeywordId{.bytes="if", .id = Id {.Keyword_if = {}}}, |
| 41 | KeywordId{.bytes="inline", .id = Id {.Keyword_inline = {}}}, |
| 42 | KeywordId{.bytes="nakedcc", .id = Id {.Keyword_nakedcc = {}}}, |
| 43 | KeywordId{.bytes="noalias", .id = Id {.Keyword_noalias = {}}}, |
| 44 | KeywordId{.bytes="null", .id = Id {.Keyword_null = {}}}, |
| 45 | KeywordId{.bytes="or", .id = Id {.Keyword_or = {}}}, |
| 46 | KeywordId{.bytes="packed", .id = Id {.Keyword_packed = {}}}, |
| 47 | KeywordId{.bytes="pub", .id = Id {.Keyword_pub = {}}}, |
| 48 | KeywordId{.bytes="return", .id = Id {.Keyword_return = {}}}, |
| 49 | KeywordId{.bytes="stdcallcc", .id = Id {.Keyword_stdcallcc = {}}}, |
| 50 | KeywordId{.bytes="struct", .id = Id {.Keyword_struct = {}}}, |
| 51 | KeywordId{.bytes="switch", .id = Id {.Keyword_switch = {}}}, |
| 52 | KeywordId{.bytes="test", .id = Id {.Keyword_test = {}}}, |
| 53 | KeywordId{.bytes="this", .id = Id {.Keyword_this = {}}}, |
| 54 | KeywordId{.bytes="true", .id = Id {.Keyword_true = {}}}, |
| 55 | KeywordId{.bytes="undefined", .id = Id {.Keyword_undefined = {}}}, |
| 56 | KeywordId{.bytes="union", .id = Id {.Keyword_union = {}}}, |
| 57 | KeywordId{.bytes="unreachable", .id = Id {.Keyword_unreachable = {}}}, |
| 58 | KeywordId{.bytes="use", .id = Id {.Keyword_use = {}}}, |
| 59 | KeywordId{.bytes="var", .id = Id {.Keyword_var = {}}}, |
| 60 | KeywordId{.bytes="volatile", .id = Id {.Keyword_volatile = {}}}, |
| 61 | KeywordId{.bytes="while", .id = Id {.Keyword_while = {}}}, |
| 55 | 62 | }; |
| 56 | 63 | |
| 57 | | fn getKeyword(bytes: []const u8) -> ?Keyword { |
| 58 | | comptime var i = 0; |
| 59 | | inline while (i < @memberCount(Keyword)) : (i += 1) { |
| 60 | | if (mem.eql(u8, @memberName(Keyword, i), bytes)) { |
| 61 | | return Keyword(i); |
| 64 | fn getKeyword(bytes: []const u8) -> ?Id { |
| 65 | for (keywords) |kw| { |
| 66 | if (mem.eql(u8, kw.bytes, bytes)) { |
| 67 | return kw.id; |
| 62 | 68 | } |
| 63 | 69 | } |
| 64 | 70 | return null; |
| ... | ... | @@ -69,7 +75,6 @@ const Token = struct { |
| 69 | 75 | const Id = union(enum) { |
| 70 | 76 | Invalid, |
| 71 | 77 | Identifier, |
| 72 | | Keyword: Keyword, |
| 73 | 78 | StringLiteral: StrLitKind, |
| 74 | 79 | Eof, |
| 75 | 80 | Builtin, |
| ... | ... | @@ -83,6 +88,46 @@ const Token = struct { |
| 83 | 88 | Period, |
| 84 | 89 | Minus, |
| 85 | 90 | Arrow, |
| 91 | Keyword_align, |
| 92 | Keyword_and, |
| 93 | Keyword_asm, |
| 94 | Keyword_break, |
| 95 | Keyword_coldcc, |
| 96 | Keyword_comptime, |
| 97 | Keyword_const, |
| 98 | Keyword_continue, |
| 99 | Keyword_defer, |
| 100 | Keyword_else, |
| 101 | Keyword_enum, |
| 102 | Keyword_error, |
| 103 | Keyword_export, |
| 104 | Keyword_extern, |
| 105 | Keyword_false, |
| 106 | Keyword_fn, |
| 107 | Keyword_for, |
| 108 | Keyword_goto, |
| 109 | Keyword_if, |
| 110 | Keyword_inline, |
| 111 | Keyword_nakedcc, |
| 112 | Keyword_noalias, |
| 113 | Keyword_null, |
| 114 | Keyword_or, |
| 115 | Keyword_packed, |
| 116 | Keyword_pub, |
| 117 | Keyword_return, |
| 118 | Keyword_stdcallcc, |
| 119 | Keyword_struct, |
| 120 | Keyword_switch, |
| 121 | Keyword_test, |
| 122 | Keyword_this, |
| 123 | Keyword_true, |
| 124 | Keyword_undefined, |
| 125 | Keyword_union, |
| 126 | Keyword_unreachable, |
| 127 | Keyword_use, |
| 128 | Keyword_var, |
| 129 | Keyword_volatile, |
| 130 | Keyword_while, |
| 86 | 131 | }; |
| 87 | 132 | }; |
| 88 | 133 | |
| ... | ... | @@ -193,8 +238,8 @@ const Tokenizer = struct { |
| 193 | 238 | State.Identifier => switch (c) { |
| 194 | 239 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, |
| 195 | 240 | else => { |
| 196 | | if (Token.getKeyword(self.buffer[result.start..self.index])) |keyword_id| { |
| 197 | | result.id = Token.Id { .Keyword = keyword_id }; |
| 241 | if (Token.getKeyword(self.buffer[result.start..self.index])) |id| { |
| 242 | result.id = id; |
| 198 | 243 | } |
| 199 | 244 | break; |
| 200 | 245 | }, |
| ... | ... | @@ -251,6 +296,73 @@ const Tokenizer = struct { |
| 251 | 296 | } |
| 252 | 297 | }; |
| 253 | 298 | |
| 299 | const AstNode = struct { |
| 300 | |
| 301 | }; |
| 302 | |
| 303 | const Parser = struct { |
| 304 | tokenizer: &Tokenizer, |
| 305 | allocator: &mem.Allocator, |
| 306 | |
| 307 | fn init(tokenizer: &Tokenizer, allocator: &mem.Allocator) -> Parser { |
| 308 | return Parser { |
| 309 | .tokenizer = tokenizer, |
| 310 | .allocator = allocator, |
| 311 | }; |
| 312 | } |
| 313 | |
| 314 | const StackFrame = struct { |
| 315 | |
| 316 | }; |
| 317 | |
| 318 | const State = enum { |
| 319 | TopLevel, |
| 320 | Expression, |
| 321 | }; |
| 322 | |
| 323 | fn parse(self: &Parser) -> %void { |
| 324 | var stack = ArrayList(StackFrame).init(self.allocator); |
| 325 | defer stack.deinit(); |
| 326 | |
| 327 | var state = State.TopLevel; |
| 328 | while (true) { |
| 329 | const token = self.tokenizer.next(); |
| 330 | switch (state) { |
| 331 | State.TopLevel => switch (token.id) { |
| 332 | Token.Id.Keyword_pub => { |
| 333 | const next_token = self.tokenizer.next(); |
| 334 | switch (next_token.id) { |
| 335 | Token.Id.Keyword_fn => { |
| 336 | const fn_name = self.tokenizer.next(); |
| 337 | if (@TagType(Token.Id)(fn_name.id) != Token.Id.Identifier) { |
| 338 | @panic("parse error"); |
| 339 | } |
| 340 | |
| 341 | const lparen = self.tokenizer.next(); |
| 342 | if (@TagType(Token.Id)(lparen.id) != Token.Id.LParen) { |
| 343 | @panic("parse error"); |
| 344 | } |
| 345 | }, |
| 346 | Token.Id.Keyword_const => @panic("TODO"), |
| 347 | Token.Id.Keyword_var => @panic("TODO"), |
| 348 | Token.Id.Keyword_use => @panic("TODO"), |
| 349 | else => @panic("parse error"), |
| 350 | } |
| 351 | }, |
| 352 | Token.Id.Keyword_const => @panic("TODO"), |
| 353 | Token.Id.Keyword_var => @panic("TODO"), |
| 354 | Token.Id.Keyword_fn => @panic("TODO"), |
| 355 | Token.Id.Keyword_export => @panic("TODO"), |
| 356 | Token.Id.Keyword_use => @panic("TODO"), |
| 357 | Token.Id.Keyword_comptime => @panic("TODO"), |
| 358 | else => @panic("parse error"), |
| 359 | }, |
| 360 | State.Expression => @panic("TODO"), |
| 361 | } |
| 362 | } |
| 363 | } |
| 364 | }; |
| 365 | |
| 254 | 366 | |
| 255 | 367 | pub fn main() -> %void { |
| 256 | 368 | main2() %% |err| { |
| ... | ... | @@ -271,12 +383,18 @@ pub fn main2() -> %void { |
| 271 | 383 | |
| 272 | 384 | warn("{}", target_file_buf); |
| 273 | 385 | |
| 274 | | var tokenizer = Tokenizer.init(target_file_buf); |
| 275 | | while (true) { |
| 276 | | const token = tokenizer.next(); |
| 277 | | tokenizer.dump(token); |
| 278 | | if (@TagType(Token.Id)(token.id) == Token.Id.Eof) { |
| 279 | | break; |
| 386 | { |
| 387 | var tokenizer = Tokenizer.init(target_file_buf); |
| 388 | while (true) { |
| 389 | const token = tokenizer.next(); |
| 390 | tokenizer.dump(token); |
| 391 | if (@TagType(Token.Id)(token.id) == Token.Id.Eof) { |
| 392 | break; |
| 393 | } |
| 280 | 394 | } |
| 281 | 395 | } |
| 396 | |
| 397 | var tokenizer = Tokenizer.init(target_file_buf); |
| 398 | var parser = Parser.init(&tokenizer, allocator); |
| 399 | %return parser.parse(); |
| 282 | 400 | } |