| ... | @@ -5,60 +5,66 @@ const heap = @import("std").heap; | ... | @@ -5,60 +5,66 @@ const heap = @import("std").heap; |
| 5 | const warn = @import("std").debug.warn; | 5 | const warn = @import("std").debug.warn; |
| 6 | const assert = @import("std").debug.assert; | 6 | const assert = @import("std").debug.assert; |
| 7 | const mem = @import("std").mem; | 7 | const mem = @import("std").mem; |
| | 8 | const ArrayList = @import("std").ArrayList; |
| | 9 | |
| 8 | | 10 | |
| 9 | const Token = struct { | 11 | const Token = struct { |
| 10 | id: Id, | 12 | id: Id, |
| 11 | start: usize, | 13 | start: usize, |
| 12 | end: usize, | 14 | end: usize, |
| 13 | | 15 | |
| 14 | const Keyword = enum { | 16 | const KeywordId = struct { |
| 15 | @"align", | 17 | bytes: []const u8, |
| 16 | @"and", | 18 | id: Id, |
| 17 | @"asm", | 19 | }; |
| 18 | @"break", | 20 | |
| 19 | @"coldcc", | 21 | const keywords = []KeywordId { |
| 20 | @"comptime", | 22 | KeywordId{.bytes="align", .id = Id {.Keyword_align = {}}}, |
| 21 | @"const", | 23 | KeywordId{.bytes="and", .id = Id {.Keyword_and = {}}}, |
| 22 | @"continue", | 24 | KeywordId{.bytes="asm", .id = Id {.Keyword_asm = {}}}, |
| 23 | @"defer", | 25 | KeywordId{.bytes="break", .id = Id {.Keyword_break = {}}}, |
| 24 | @"else", | 26 | KeywordId{.bytes="coldcc", .id = Id {.Keyword_coldcc = {}}}, |
| 25 | @"enum", | 27 | KeywordId{.bytes="comptime", .id = Id {.Keyword_comptime = {}}}, |
| 26 | @"error", | 28 | KeywordId{.bytes="const", .id = Id {.Keyword_const = {}}}, |
| 27 | @"export", | 29 | KeywordId{.bytes="continue", .id = Id {.Keyword_continue = {}}}, |
| 28 | @"extern", | 30 | KeywordId{.bytes="defer", .id = Id {.Keyword_defer = {}}}, |
| 29 | @"false", | 31 | KeywordId{.bytes="else", .id = Id {.Keyword_else = {}}}, |
| 30 | @"fn", | 32 | KeywordId{.bytes="enum", .id = Id {.Keyword_enum = {}}}, |
| 31 | @"for", | 33 | KeywordId{.bytes="error", .id = Id {.Keyword_error = {}}}, |
| 32 | @"goto", | 34 | KeywordId{.bytes="export", .id = Id {.Keyword_export = {}}}, |
| 33 | @"if", | 35 | KeywordId{.bytes="extern", .id = Id {.Keyword_extern = {}}}, |
| 34 | @"inline", | 36 | KeywordId{.bytes="false", .id = Id {.Keyword_false = {}}}, |
| 35 | @"nakedcc", | 37 | KeywordId{.bytes="fn", .id = Id {.Keyword_fn = {}}}, |
| 36 | @"noalias", | 38 | KeywordId{.bytes="for", .id = Id {.Keyword_for = {}}}, |
| 37 | @"null", | 39 | KeywordId{.bytes="goto", .id = Id {.Keyword_goto = {}}}, |
| 38 | @"or", | 40 | KeywordId{.bytes="if", .id = Id {.Keyword_if = {}}}, |
| 39 | @"packed", | 41 | KeywordId{.bytes="inline", .id = Id {.Keyword_inline = {}}}, |
| 40 | @"pub", | 42 | KeywordId{.bytes="nakedcc", .id = Id {.Keyword_nakedcc = {}}}, |
| 41 | @"return", | 43 | KeywordId{.bytes="noalias", .id = Id {.Keyword_noalias = {}}}, |
| 42 | @"stdcallcc", | 44 | KeywordId{.bytes="null", .id = Id {.Keyword_null = {}}}, |
| 43 | @"struct", | 45 | KeywordId{.bytes="or", .id = Id {.Keyword_or = {}}}, |
| 44 | @"switch", | 46 | KeywordId{.bytes="packed", .id = Id {.Keyword_packed = {}}}, |
| 45 | @"test", | 47 | KeywordId{.bytes="pub", .id = Id {.Keyword_pub = {}}}, |
| 46 | @"this", | 48 | KeywordId{.bytes="return", .id = Id {.Keyword_return = {}}}, |
| 47 | @"true", | 49 | KeywordId{.bytes="stdcallcc", .id = Id {.Keyword_stdcallcc = {}}}, |
| 48 | @"undefined", | 50 | KeywordId{.bytes="struct", .id = Id {.Keyword_struct = {}}}, |
| 49 | @"union", | 51 | KeywordId{.bytes="switch", .id = Id {.Keyword_switch = {}}}, |
| 50 | @"unreachable", | 52 | KeywordId{.bytes="test", .id = Id {.Keyword_test = {}}}, |
| 51 | @"use", | 53 | KeywordId{.bytes="this", .id = Id {.Keyword_this = {}}}, |
| 52 | @"var", | 54 | KeywordId{.bytes="true", .id = Id {.Keyword_true = {}}}, |
| 53 | @"volatile", | 55 | KeywordId{.bytes="undefined", .id = Id {.Keyword_undefined = {}}}, |
| 54 | @"while", | 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 { | 64 | fn getKeyword(bytes: []const u8) -> ?Id { |
| 58 | comptime var i = 0; | 65 | for (keywords) |kw| { |
| 59 | inline while (i < @memberCount(Keyword)) : (i += 1) { | 66 | if (mem.eql(u8, kw.bytes, bytes)) { |
| 60 | if (mem.eql(u8, @memberName(Keyword, i), bytes)) { | 67 | return kw.id; |
| 61 | return Keyword(i); | | |
| 62 | } | 68 | } |
| 63 | } | 69 | } |
| 64 | return null; | 70 | return null; |
| ... | @@ -69,7 +75,6 @@ const Token = struct { | ... | @@ -69,7 +75,6 @@ const Token = struct { |
| 69 | const Id = union(enum) { | 75 | const Id = union(enum) { |
| 70 | Invalid, | 76 | Invalid, |
| 71 | Identifier, | 77 | Identifier, |
| 72 | Keyword: Keyword, | | |
| 73 | StringLiteral: StrLitKind, | 78 | StringLiteral: StrLitKind, |
| 74 | Eof, | 79 | Eof, |
| 75 | Builtin, | 80 | Builtin, |
| ... | @@ -83,6 +88,46 @@ const Token = struct { | ... | @@ -83,6 +88,46 @@ const Token = struct { |
| 83 | Period, | 88 | Period, |
| 84 | Minus, | 89 | Minus, |
| 85 | Arrow, | 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,8 +238,8 @@ const Tokenizer = struct { |
| 193 | State.Identifier => switch (c) { | 238 | State.Identifier => switch (c) { |
| 194 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, | 239 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, |
| 195 | else => { | 240 | else => { |
| 196 | if (Token.getKeyword(self.buffer[result.start..self.index])) |keyword_id| { | 241 | if (Token.getKeyword(self.buffer[result.start..self.index])) |id| { |
| 197 | result.id = Token.Id { .Keyword = keyword_id }; | 242 | result.id = id; |
| 198 | } | 243 | } |
| 199 | break; | 244 | break; |
| 200 | }, | 245 | }, |
| ... | @@ -251,6 +296,73 @@ const Tokenizer = struct { | ... | @@ -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 | pub fn main() -> %void { | 367 | pub fn main() -> %void { |
| 256 | main2() %% |err| { | 368 | main2() %% |err| { |
| ... | @@ -271,12 +383,18 @@ pub fn main2() -> %void { | ... | @@ -271,12 +383,18 @@ pub fn main2() -> %void { |
| 271 | | 383 | |
| 272 | warn("{}", target_file_buf); | 384 | warn("{}", target_file_buf); |
| 273 | | 385 | |
| 274 | var tokenizer = Tokenizer.init(target_file_buf); | 386 | { |
| 275 | while (true) { | 387 | var tokenizer = Tokenizer.init(target_file_buf); |
| 276 | const token = tokenizer.next(); | 388 | while (true) { |
| 277 | tokenizer.dump(token); | 389 | const token = tokenizer.next(); |
| 278 | if (@TagType(Token.Id)(token.id) == Token.Id.Eof) { | 390 | tokenizer.dump(token); |
| 279 | break; | 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 | } |