This commit is contained in:
Jarred Sumner
2021-04-17 15:21:31 -07:00
commit 025fe36def
7 changed files with 391 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.DS_Store
zig-cache
*.wasm

35
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,35 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Test",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/zig-cache/bin/test",
"args": ["prevent-panic-by-passing-a-placeholder-arg"],
"preLaunchTask": "test",
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb"
},
{
"name": "Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/zig-cache/bin/esdev",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
"internalConsoleOptions": "openOnSessionStart",
"logging": {
"moduleLoad": false
}
}
]
}

40
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,40 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "zig build",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "run",
"type": "process",
"command": "zig",
"args": ["run", "${file}"],
"group": "build",
"presentation": {
"showReuseMessage": false,
"clear": true
}
},
{
"label": "test",
"type": "process",
"command": "zig",
"args": ["test", "${file}", "-femit-bin=zig-cache/bin/test"],
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"showReuseMessage": false,
"clear": true
}
}
]
}

28
build.zig Normal file
View File

@@ -0,0 +1,28 @@
const std = @import("std");
pub fn build(b: *std.build.Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("esdev", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.addLibPath("/usr/local/lib");
exe.install();
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}

176
src/lexer/js_lexer.zig Normal file
View File

@@ -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 {};

103
src/logger/logger.zig Normal file
View File

@@ -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();
}

6
src/main.zig Normal file
View File

@@ -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")});
}