This commit is contained in:
Jarred Sumner
2021-04-19 20:53:54 -07:00
parent 17df86ca17
commit 5ae24b75ae
18 changed files with 1433 additions and 190 deletions

View File

@@ -11,9 +11,16 @@ pub fn build(b: *std.build.Builder) void {
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("esdev", "src/main.zig");
var exe: *std.build.LibExeObjStep = undefined;
if (target.getCpuArch().isWasm()) {
exe = b.addExecutable("esdev", "src/main_wasm.zig");
} else {
exe = b.addExecutable("esdev", "src/main.zig");
}
exe.setTarget(target);
exe.setBuildMode(mode);
exe.addLibPath("/usr/local/lib");
exe.install();

View File

@@ -1,10 +1,15 @@
const std = @import("std");
const options = @import("options.zig");
const logger = @import("logger.zig");
const js_ast = @import("js_ast.zig");
pub const Bundler = struct {
options: options.TransformOptions,
options: options.TransformOptions,
logger: logger.Log,
pub fn init(options: options.TransformOptions, allocator: *std.mem.Allocator) Bundler {
var log = logger.Log{ .msgs = ArrayList(Msg).init(allocator) };
}
pub fn
}
pub fn scan() void {}
};

3
src/flags.zig Normal file
View File

@@ -0,0 +1,3 @@
const std = @import("std");
pub const isWasm = std.Target.Os.Tag.freestanding == std.Target.current.os.tag;

View File

@@ -1,8 +1,12 @@
const std = @import("std");
const strings = @import("strings.zig");
usingnamespace @import("strings.zig");
const alloc = @import("alloc.zig");
const expect = std.testing.expect;
// pub const FilesystemImplementation = @import("fs_impl.zig");
pub const FileSystem = struct { tree: std.AutoHashMap(FileSystemEntry) };
pub const FileSystemEntry = union(enum) {
@@ -10,22 +14,44 @@ pub const FileSystemEntry = union(enum) {
directory: Directory,
};
pub const File = struct { path: Path, mtime: ?usize, contents: ?[]u8 };
pub const File = struct {
path: Path,
mtime: ?usize,
contents: ?string,
};
pub const Directory = struct { path: Path, mtime: ?usize, contents: []FileSystemEntry };
pub const PathName = struct {
base: []u8,
dir: []u8,
ext: []u8,
base: string,
dir: string,
ext: string,
pub fn init(_path: []const u8, allocator: *std.mem.Allocator) PathName {
// TODO: leak.
var path: []u8 = allocator.alloc(u8, _path.len) catch unreachable;
std.mem.copy(u8, path, _path);
// For readability, the names of certain automatically-generated symbols are
// derived from the file name. For example, instead of the CommonJS wrapper for
// a file being called something like "require273" it can be called something
// like "require_react" instead. This function generates the part of these
// identifiers that's specific to the file path. It can take both an absolute
// path (OS-specific) and a path in the source code (OS-independent).
//
// Note that these generated names do not at all relate to the correctness of
// the code as far as avoiding symbol name collisions. These names still go
// through the renaming logic that all other symbols go through to avoid name
// collisions.
pub fn nonUniqueNameString(self: *PathName, allocator: *std.mem.Allocator) !string {
if (strings.eql("index", self.base)) {
if (self.dir.len > 0) {
return MutableString.ensureValidIdentifier(PathName.init(self.dir), allocator);
}
}
return MutableString.ensureValidIdentifier(self.base, allocator);
}
pub fn init(_path: string) PathName {
var path = _path;
var base = path;
var dir = path;
var ext = path;
var dir = path;
var _i = strings.lastIndexOfChar(path, '/');
while (_i) |i| {
@@ -58,13 +84,13 @@ pub const PathName = struct {
};
pub const Path = struct {
pretty_path: []const u8,
text: []const u8,
namespace: []const u8,
pretty_path: string,
text: string,
namespace: string,
name: PathName,
pub fn init(text: []const u8, allocator: *std.mem.Allocator) Path {
return Path{ .pretty_path = text, .text = text, .namespace = "file", .name = PathName.init(text, allocator) };
pub fn init(text: string) Path {
return Path{ .pretty_path = text, .text = text, .namespace = "file", .name = PathName.init(text) };
}
pub fn isBefore(a: *Path, b: Path) bool {
@@ -77,7 +103,9 @@ pub const Path = struct {
test "PathName.init" {
var file = "/root/directory/file.ext".*;
const res = PathName.init(&file, std.heap.page_allocator);
const res = PathName.init(
&file,
);
std.testing.expectEqualStrings(res.dir, "/root/directory");
std.testing.expectEqualStrings(res.base, "file");
std.testing.expectEqualStrings(res.ext, ".ext");

10
src/fs_impl.zig Normal file
View File

@@ -0,0 +1,10 @@
const std = @import("std");
usingnamespace @import("flags.zig");
pub const FS = comptime {
if (isWASM) {
return @import("fs_impl_wasm.zig");
} else {
return @import("fs_impl_native.zig");
}
};

3
src/fs_impl_native.zig Normal file
View File

@@ -0,0 +1,3 @@
const std = @import("std");
const fs = std.fs;

0
src/fs_impl_wasm.zig Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,8 @@ const tables = @import("js_lexer_tables.zig");
const alloc = @import("alloc.zig");
const build_options = @import("build_options");
usingnamespace @import("strings.zig");
const _f = @import("./test/fixtures.zig");
const unicode = std.unicode;
@@ -18,8 +20,6 @@ pub const jsxEntity = tables.jsxEntity;
// TODO: JSON
const IS_JSON_FILE = false;
const string = []const u8;
pub const Lexer = struct {
// pub const Error = error{
// UnexpectedToken,
@@ -1158,7 +1158,10 @@ fn test_lexer(contents: []const u8) Lexer {
.msgs = msgs,
};
const source = logger.Source.initPathString("index.js", contents, std.heap.page_allocator);
const source = logger.Source.initPathString(
"index.js",
contents,
);
return Lexer.init(log, source, alloc.dynamic) catch unreachable;
}
@@ -1208,7 +1211,10 @@ test "Lexer.step()" {
};
defer std.testing.allocator.free(msgs.items);
const source = logger.Source.initPathString("index.js", "for (let i = 0; i < 100; i++) { console.log('hi'); }", std.heap.page_allocator);
const source = logger.Source.initPathString(
"index.js",
"for (let i = 0; i < 100; i++) { console.log('hi'); }",
);
var lex = try Lexer.init(log, source, std.testing.allocator);
std.testing.expect('f' == lex.code_point);

View File

@@ -2,9 +2,3 @@ const std = @import("std");
const logger = @import("logger.zig");
const lexer = @import("lexer.zig");
const ast = @import("js_ast.zig");
pub fn Parse(
log: logger.Log,
source: logger.Source,
)

View File

@@ -1,5 +1,7 @@
const std = @import("std");
const strings = @import("strings.zig");
usingnamespace @import("strings.zig");
const fs = @import("fs.zig");
const unicode = std.unicode;
@@ -13,7 +15,7 @@ pub const Kind = enum {
note,
debug,
pub fn string(self: Kind) []const u8 {
pub fn string(self: Kind) string {
return switch (self) {
.err => "error",
.warn => "warn",
@@ -26,13 +28,13 @@ pub const Kind = enum {
pub const Loc = i32;
pub const Location = struct {
file: []const u8,
namespace: []const u8 = "file",
file: string,
namespace: string = "file",
line: i32 = 1, // 1-based
column: i32 = 0, // 0-based, in bytes
length: usize = 0, // in bytes
line_text: ?[]const u8 = null,
suggestion: ?[]const u8 = null,
line_text: ?string = null,
suggestion: ?string = null,
pub fn init(file: []u8, namespace: []u8, line: i32, column: i32, length: u32, line_text: ?[]u8, suggestion: ?[]u8) Location {
return Location{
@@ -62,7 +64,7 @@ pub const Location = struct {
}
}
pub fn init_file(file: []const u8, line: i32, column: i32, length: u32, line_text: ?[]u8, suggestion: ?[]u8) Location {
pub fn init_file(file: string, line: i32, column: i32, length: u32, line_text: ?[]u8, suggestion: ?[]u8) Location {
var namespace = "file".*;
return Location{
@@ -84,7 +86,11 @@ pub const Msg = struct {
data: Data,
};
pub const Range = struct { loc: Loc = 0, len: i32 = 0 };
pub const Range = struct {
loc: Loc = 0,
len: i32 = 0,
const Empty = Range{ .loc = 0, .len = 0 };
};
pub const Log = struct {
debug: bool = false,
@@ -178,17 +184,22 @@ pub fn usize2Loc(loc: usize) Loc {
pub const Source = struct {
path: fs.Path,
index: u32 = 0,
contents: []const u8,
contents: string,
// 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,
identifier_name: string,
pub const ErrorPosition = struct { line_start: usize, line_end: usize, column_count: usize, line_count: usize };
pub fn initPathString(pathString: []const u8, contents: []const u8, allocator: *std.mem.Allocator) Source {
const path = fs.Path.init(pathString, allocator);
pub fn initFile(file: fs.File, allocator: *std.mem.Allocator) Source {
std.debug.assert(file.contents != null);
return Source{ .path = path, .identifier_name = file.path.name.nonUniqueNameString(allocator) catch unreachable, .contents = file.contents };
}
pub fn initPathString(pathString: string, contents: string) Source {
const path = fs.Path.init(pathString);
return Source{ .path = path, .identifier_name = path.name.base, .contents = contents };
}
@@ -256,7 +267,7 @@ pub const Source = struct {
}
};
pub fn rangeData(source: ?Source, r: Range, text: []u8) Data {
fn rangeData(source: ?Source, r: Range, text: []u8) Data {
return Data{ .text = text, .location = Location.init_or_nil(source, r) };
}

View File

@@ -1,7 +1,18 @@
const std = @import("std");
const lex = @import("js_lexer.zig");
const alloc = @import("alloc.zig");
pub fn main() anyerror!void {
std.log.info("All your codebase are belong to us. {s}", .{lex.Keywords.get("hey")});
const args = try std.process.argsAlloc(alloc.dynamic);
const stdout = std.io.getStdOut();
const stderr = std.io.getStdErr();
if (args.len < 1) {
const len = stderr.write("Pass a file path");
return;
}
// const path = try std.fs.realpathAlloc(alloc.dynamic, args[args.len - 1]);
// const file = try std.fs.openFileAbsolute(path, std.fs.File.OpenFlags{});
// const bytes = try file.readToEndAlloc(alloc.dynamic, std.math.maxInt(usize));
}

31
src/main_wasm.zig Normal file
View File

@@ -0,0 +1,31 @@
const std = @import("std");
const lex = @import("js_lexer.zig");
const logger = @import("logger.zig");
const alloc = @import("alloc.zig");
pub fn main() anyerror!void {
try alloc.setup(std.heap.page_allocator);
// const args = try std.process.argsAlloc(alloc.dynamic);
// // const stdout = std.io.getStdOut();
// // const stderr = std.io.getStdErr();
// // if (args.len < 1) {
// // const len = stderr.write("Pass a file");
// // return;
// // }
// // alloc
const msgs = std.ArrayList(logger.Msg).init(alloc.dynamic);
const log = logger.Log{
.msgs = msgs,
};
const source = logger.Source.initPathString("index.js", "for (let i = 0; i < 100; i++) { console.log('hi') aposkdpoaskdpokasdpokasdpokasdpokasdpoaksdpoaksdpoaskdpoaksdpoaksdpoaskdpoaskdpoasdk; }", alloc.dynamic);
var lexer = try lex.Lexer.init(log, source, alloc.dynamic);
lexer.next();
while (lexer.token != lex.T.t_end_of_file) {
lexer.next();
}
const v = try std.io.getStdOut().write("Finished");
}

View File

@@ -1,26 +1,74 @@
const std = @import("std");
const log = @import("logger.zig");
const fs = @import("fs.zig");
usingnamespace @import("strings.zig");
const assert = std.debug.assert;
pub const Loader = enum {
jsx,
js,
ts,
tsx,
css,
file,
};
pub const defaultLoaders = std.ComptimeStringMap(Loader, .{
.{ ".jsx", Loader.jsx },
.{ ".js", Loader.js },
.{ ".mjs", Loader.js },
.{ ".css", Loader.css },
.{ ".ts", Loader.ts },
.{ ".tsx", Loader.tsx },
});
pub const TransformOptions = struct {
footer: []u8 = "",
banner: []u8 = "",
define: std.StringHashMap([]u8),
footer: []const u8 = "",
banner: []const u8 = "",
define: std.StringHashMap(string),
loader: Loader = Loader.tsx,
resolve_dir: []u8 = "/",
resolve_dir: []const u8 = "/",
react_fast_refresh: bool = false,
jsx_factory: []u8 = "React.createElement",
jsx_pragma: []u8 = "jsx",
inject: [][]u8,
public_url: []u8,
jsx_factory: []const u8 = "React.createElement",
jsx_pragma: []const u8 = "jsx",
inject: ?[][]const u8 = null,
public_url: []const u8 = "/",
filesystem_cache: std.StringHashMap(fs.File),
entry_point: fs.File,
entry_point: *fs.File,
pub fn initUncached(allocator: *std.mem.Allocator, entryPointName: string, code: string) !TransformOptions {
assert(entryPointName.len > 0);
const filesystemCache = std.StringHashMap(string).init(allocator);
var entryPoint = !allocator.Create(fs.file);
entryPoint.path = fs.Path.init(entryPointName, allocator);
entryPoint.contents = code;
const define = std.StringHashMap(string).init(allocator);
try define.ensureCapacity(1);
define.putAssumeCapacity("process.env.NODE_ENV", "development");
var loader = Loader.file;
if (defaultLoaders.get(entryPoint.path.name.ext)) |defaultLoader| {
loader = defaultLoader;
}
assert(loader != .file);
assert(code.len > 0);
try filesystemCache.put(entryPointName, entryPoint);
return TransformOptions{
.entry_point = entryPoint,
.define = define,
.loader = loader,
.filesystem_cache = filesystemCache,
.resolve_dir = entryPoint.path.name.dir,
};
}
};
pub const OutputFile = struct {

28
src/string_immutable.zig Normal file
View File

@@ -0,0 +1,28 @@
const std = @import("std");
const expect = std.testing.expect;
usingnamespace @import("string_types.zig");
pub fn containsChar(self: string, char: u8) bool {
return std.mem(char) != null;
}
pub fn indexOfChar(self: string, char: u8) ?usize {
return std.mem.indexOfScalar(@TypeOf(char), self, char);
}
pub fn lastIndexOfChar(self: string, char: u8) ?usize {
return std.mem.lastIndexOfScalar(u8, self, char);
}
pub fn lastIndexOf(self: string, str: u8) ?usize {
return std.mem.lastIndexOf(u8, self, str);
}
pub fn indexOf(self: string, str: u8) ?usize {
return std.mem.indexOf(u8, self, str);
}
pub fn eql(self: string, other: anytype) bool {
return std.mem.eql(u8, self, other);
}

126
src/string_mutable.zig Normal file
View File

@@ -0,0 +1,126 @@
const std = @import("std");
const expect = std.testing.expect;
usingnamespace @import("string_types.zig");
pub const MutableString = struct {
allocator: *std.mem.Allocator,
list: std.ArrayListUnmanaged(u8),
pub fn init(allocator: *std.mem.Allocator, capacity: usize) !MutableString {
return MutableString{ .allocator = allocator, .list = try std.ArrayListUnmanaged(u8).initCapacity(allocator, capacity) };
}
pub fn initCopy(allocator: *std.mem.Allocator, str: anytype) !MutableString {
var mutable = try MutableString.init(allocator, std.mem.len(str));
try mutable.copy(str);
return mutable;
}
// Convert it to an ASCII identifier. Note: If you change this to a non-ASCII
// identifier, you're going to potentially cause trouble with non-BMP code
// points in target environments that don't support bracketed Unicode escapes.
pub fn ensureValidIdentifier(str: string, allocator: *std.mem.Allocator) !string {
if (str.len == 0) {
return "_";
}
var mutable = try MutableString.init(allocator, 0);
var needsGap = false;
for (str) |c| {
if (std.ascii.isLower(c) or std.ascii.isUpper(c) or (mutable.len() > 0 and std.ascii.isAlNum(c))) {
if (needsGap) {
try mutable.appendChar('_');
needsGap = false;
}
try mutable.appendChar(c);
} else if (!needsGap) {
needsGap = true;
}
}
if (mutable.len() > 0) {
return mutable.list.toOwnedSlice(allocator);
} else {
return str;
}
}
pub fn len(self: *MutableString) usize {
return self.list.items.len;
}
pub fn copy(self: *MutableString, str: anytype) !void {
try self.list.ensureCapacity(self.allocator, std.mem.len(str[0..]));
if (self.list.items.len == 0) {
try self.list.insertSlice(self.allocator, 0, str);
} else {
try self.list.replaceRange(self.allocator, 0, std.mem.len(str[0..]), str[0..]);
}
}
pub fn deinit(self: *MutableString) !void {
self.list.deinit(self.allocator);
}
pub fn appendChar(self: *MutableString, char: u8) !void {
try self.list.append(self.allocator, char);
}
pub fn appendCharAssumeCapacity(self: *MutableString, char: u8) !void {
try self.list.appendAssumeCapacity(self.allocator, char);
}
pub fn append(self: *MutableString, char: []const u8) !void {
try self.list.appendSlice(self.allocator, char);
}
pub fn appendAssumeCapacity(self: *MutableString, char: []const u8) !void {
try self.list.appendSliceAssumeCapacity(self.allocator, char);
}
// pub fn deleteAt(self: *MutableString, i: usize) {
// self.list.swapRemove(i);
// }
pub fn containsChar(self: *MutableString, char: u8) bool {
return self.indexOfChar(char) != null;
}
pub fn indexOfChar(self: *MutableString, char: u8) ?usize {
return std.mem.indexOfScalar(@TypeOf(char), self.list.items, char);
}
pub fn lastIndexOfChar(self: *MutableString, char: u8) ?usize {
return std.mem.lastIndexOfScalar(@TypeOf(char), self.list.items, char);
}
pub fn lastIndexOf(self: *MutableString, str: u8) ?usize {
return std.mem.lastIndexOf(u8, self.list.items, str);
}
pub fn indexOf(self: *MutableString, str: u8) ?usize {
return std.mem.indexOf(u8, self.list.items, str);
}
pub fn eql(self: *MutableString, other: anytype) bool {
return std.mem.eql(u8, self.list.items, other);
}
};
test "MutableString" {
const alloc = std.heap.page_allocator;
var str = try MutableString.initCopy(alloc, "hello");
expect(str.eql("hello"));
}
test "MutableString.ensureValidIdentifier" {
const alloc = std.heap.page_allocator;
std.testing.expectEqualStrings("jquery", try MutableString.ensureValidIdentifier("jquery", alloc));
std.testing.expectEqualStrings("jquery_foo", try MutableString.ensureValidIdentifier("jquery😋foo", alloc));
}

2
src/string_types.zig Normal file
View File

@@ -0,0 +1,2 @@
pub const string = []const u8;
pub const stringMutable = []u8;

View File

@@ -1,8 +1,7 @@
const std = @import("std");
pub fn indexOfChar(contents: []u8, char: u8) callconv(.Inline) ?usize {
return std.mem.indexOfScalar(u8, contents, char);
}
const mutable = @import("string_mutable.zig");
pub fn lastIndexOfChar(contents: []u8, char: u8) callconv(.Inline) ?usize {
return std.mem.lastIndexOfScalar(u8, contents, char);
}
pub usingnamespace @import("string_types.zig");
pub const strings = @import("string_immutable.zig");
pub const MutableString = mutable.MutableString;