diff options
author | 2021-04-17 15:21:31 -0700 | |
---|---|---|
committer | 2021-04-17 15:21:31 -0700 | |
commit | 025fe36defe2468ca1ed224855aa1effa09001ca (patch) | |
tree | 908735f5fedc8cf5a1e668c1112f66a312d8d213 /src | |
download | bun-025fe36defe2468ca1ed224855aa1effa09001ca.tar.gz bun-025fe36defe2468ca1ed224855aa1effa09001ca.tar.zst bun-025fe36defe2468ca1ed224855aa1effa09001ca.zip |
woot
Diffstat (limited to 'src')
-rw-r--r-- | src/lexer/js_lexer.zig | 176 | ||||
-rw-r--r-- | src/logger/logger.zig | 103 | ||||
-rw-r--r-- | src/main.zig | 6 |
3 files changed, 285 insertions, 0 deletions
diff --git a/src/lexer/js_lexer.zig b/src/lexer/js_lexer.zig new file mode 100644 index 000000000..587ea2caa --- /dev/null +++ b/src/lexer/js_lexer.zig @@ -0,0 +1,176 @@ +const std = @import("std"); + +pub const T = enum(u8) { + t_end_of_file, + t_syntax_error, + + // "#!/usr/bin/env node" + t_hashbang, + + // literals + t_no_substitution_template_literal, // contents are in lexer.string_literal ([]uint16) + t_numeric_literal, // contents are in lexer.number (float64) + t_string_literal, // contents are in lexer.string_literal ([]uint16) + t_big_integer_literal, // contents are in lexer.identifier (string) + + // pseudo-literals + t_template_head, // contents are in lexer.string_literal ([]uint16) + t_template_middle, // contents are in lexer.string_literal ([]uint16) + t_template_tail, // contents are in lexer.string_literal ([]uint16) + + // punctuation + t_ampersand, + t_ampersand_ampersand, + t_asterisk, + t_asterisk_asterisk, + t_at, + t_bar, + t_bar_bar, + t_caret, + t_close_brace, + t_close_bracket, + t_close_paren, + t_colon, + t_comma, + t_dot, + t_dot_dot_dot, + t_equals_equals, + t_equals_equals_equals, + t_equals_greater_than, + t_exclamation, + t_exclamation_equals, + t_exclamation_equals_equals, + t_greater_than, + t_greater_than_equals, + t_greater_than_greater_than, + t_greater_than_greater_than_greater_than, + t_less_than, + t_less_than_equals, + t_less_than_less_than, + t_minus, + t_minus_minus, + t_open_brace, + t_open_bracket, + t_open_paren, + t_percent, + t_plus, + t_plus_plus, + t_question, + t_question_dot, + t_question_question, + t_semicolon, + t_slash, + t_tilde, + + // assignments (keep in sync with is_assign() below) + t_ampersand_ampersand_equals, + t_ampersand_equals, + t_asterisk_asterisk_equals, + t_asterisk_equals, + t_bar_bar_equals, + t_bar_equals, + t_caret_equals, + t_equals, + t_greater_than_greater_than_equals, + t_greater_than_greater_than_greater_than_equals, + t_less_than_less_than_equals, + t_minus_equals, + t_percent_equals, + t_plus_equals, + t_question_question_equals, + t_slash_equals, + + // class-private fields and methods + t_private_identifier, + + // identifiers + t_identifier, // contents are in lexer.identifier (string) + t_escaped_keyword, // a keyword that has been escaped as an identifer + + // reserved words + t_break, + t_case, + t_catch, + t_class, + t_const, + t_continue, + t_debugger, + t_default, + t_delete, + t_do, + t_else, + t_enum, + t_export, + t_extends, + t_false, + t_finally, + t_for, + t_function, + t_if, + t_import, + t_in, + t_instanceof, + t_new, + t_null, + t_return, + t_super, + t_switch, + t_this, + t_throw, + t_true, + t_try, + t_typeof, + t_var, + t_void, + t_while, + t_with, + + pub fn isAssign() bool { + return self >= T.t_ampersand_ampersand_equals and self <= T.t_slash_equals; + } + + pub fn isReservedWord() bool { + return self >= T.t_break and self <= T.t_with; + } +}; + +pub const Keywords = std.ComptimeStringMap(T, .{ + .{ "break", .t_break }, + .{ "case", .t_case }, + .{ "catch", .t_catch }, + .{ "class", .t_class }, + .{ "const", .t_const }, + .{ "continue", .t_continue }, + .{ "debugger", .t_debugger }, + .{ "default", .t_default }, + .{ "delete", .t_delete }, + .{ "do", .t_do }, + .{ "else", .t_else }, + .{ "enum", .t_enum }, + .{ "export", .t_export }, + .{ "extends", .t_extends }, + .{ "false", .t_false }, + .{ "finally", .t_finally }, + .{ "for", .t_for }, + .{ "function", .t_function }, + .{ "if", .t_if }, + .{ "import", .t_import }, + .{ "in", .t_in }, + .{ "instanceof", .t_instanceof }, + .{ "new", .t_new }, + .{ "null", .t_null }, + .{ "return", .t_return }, + .{ "super", .t_super }, + .{ "switch", .t_switch }, + .{ "this", .t_this }, + .{ "throw", .t_throw }, + .{ "true", .t_true }, + .{ "try", .t_try }, + .{ "typeof", .t_typeof }, + .{ "var", .t_var }, + .{ "void", .t_void }, + .{ "while", .t_while }, + .{ "with", .t_with }, +}); + +const Lexer = struct {}; diff --git a/src/logger/logger.zig b/src/logger/logger.zig new file mode 100644 index 000000000..8409d767a --- /dev/null +++ b/src/logger/logger.zig @@ -0,0 +1,103 @@ +const std = @import("std"); + +const expect = std.testing.expect; + +const ArrayList = std.ArrayList; + +pub const Msg = struct { + pub const Kind = enum { + err, + warn, + note, + debug, + + pub fn string(self: Kind) []const u8 { + return switch (self) { + .err => "error", + .warn => "warn", + .note => "note", + .debug => "debug", + }; + } + }; + + pub const Location = struct { + file: []u8, + namespace: []u8 = "file", + line: i32 = 1, // 1-based + column: i32 = 0, // 0-based, in bytes + length: u32 = 0, // in bytes + line_text: ?[]u8, + suggestion: ?[]u8, + + pub fn init(file: []u8, namespace: []u8, line: i32, column: i32, length: u32, line_text: ?[]u8, suggestion: ?[]u8) Location { + return Location{ + .file = file, + .namespace = namespace, + .line = line, + .column = column, + .length = length, + .line_text = line_text, + .suggestion = suggestion, + }; + } + + pub fn init_file(file: []u8, line: i32, column: i32, length: u32, line_text: ?[]u8, suggestion: ?[]u8) Location { + var namespace = "file".*; + return Location{ + .file = file, + .namespace = &namespace, + .line = line, + .column = column, + .length = length, + .line_text = line_text, + .suggestion = suggestion, + }; + } + }; + + pub const Data = struct { text: []u8, location: *Msg.Location }; + + kind: Kind, + data: Data, +}; + +pub const Log = struct { + debug: bool = false, + warnings: u8 = 0, + errors: u8 = 0, + msgs: ArrayList(Msg), + + pub fn add_msg(self: *Log, msg: Msg) !void { + try self.msgs.append(msg); + } + + pub fn print(self: *Log) void { + if (self.msgs.items.len > 0) { + var msg: Msg = self.msgs.items[0]; + std.debug.print("\n\n{s}: {s}\n{s}\n{s}:{}:{}", .{ msg.kind.string(), msg.data.text, msg.data.location.line_text, msg.data.location.file, msg.data.location.line, msg.data.location.column }); + } + } +}; + +pub const Source = struct { index: u32, contents: []u8, +// An identifier that is mixed in to automatically-generated symbol names to +// improve readability. For example, if the identifier is "util" then the +// symbol for an "export default" statement will be called "util_default". +identifier_name: []u8 }; + +test "print msg" { + var log = Log{ .msgs = ArrayList(Msg).init(std.testing.allocator) }; + defer log.msgs.deinit(); + var filename = "test.js".*; + var syntax = "for(i = 0;)".*; + var err = "invalid syntax".*; + var namespace = "file".*; + + try log.add_msg(Msg{ + .kind = .err, + .data = Msg.Data{ .location = &Msg.Location.init_file(&filename, 1, 3, 0, &syntax, ""), .text = &err }, + }); + + log.print(); +} diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 000000000..582427975 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,6 @@ +const std = @import("std"); +const lex = @import("lexer/js_lexer.zig"); + +pub fn main() anyerror!void { + std.log.info("All your codebase are belong to us. {s}", .{lex.Keywords.get("hey")}); +} |