diff options
Diffstat (limited to 'src/main_wasm.zig')
-rw-r--r-- | src/main_wasm.zig | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/src/main_wasm.zig b/src/main_wasm.zig new file mode 100644 index 000000000..257e56461 --- /dev/null +++ b/src/main_wasm.zig @@ -0,0 +1,348 @@ +const JSParser = @import("./js_parser/js_parser.zig"); +const JSPrinter = @import("./js_printer.zig"); +const JSAst = @import("./js_ast.zig"); +const Api = @import("./api/schema.zig").Api; +const Logger = @import("./logger.zig"); +const global = @import("./global.zig"); +const default_allocator = global.default_allocator; +const std = @import("std"); +const Define = @import("./defines.zig"); +const Options = @import("./options.zig"); +const ApiWriter = @import("./api/schema.zig").Writer; +const ApiReader = @import("./api/schema.zig").Reader; +const ImportKind = @import("./import_record.zig").ImportKind; +const Output = global.Output; + +export var code_buffer_ptr: ?[*]const u8 = null; +pub const bindgen = true; +const Main = @This(); +pub const os = struct { + pub const c = Main.system; + pub const system = Main.system; +}; + +pub extern fn console_error(slice: u64) void; +pub extern fn console_log(slice: u64) void; +pub extern fn console_warn(slice: u64) void; +pub extern fn console_info(slice: u64) void; +pub const Uint8Array = extern struct { + ptr: ?[*]const u8 = null, + len: usize = 0, + + pub fn fromSlice(slice: []const u8) u64 { + return @bitCast(u64, [2]u32{ + @ptrToInt(slice.ptr), + slice.len, + }); + } + + pub fn fromJS(data: u64) []u8 { + const ptrs = @bitCast([2]u32, data); + return @intToPtr([*]u8, ptrs[0])[0..ptrs[1]]; + } +}; + +pub const system = struct { + pub const fd_t = i32; + pub const sockaddr = fd_t; + pub const mode_t = fd_t; + pub const E = enum(u8) { + SUCCESS = 0, + EPERM = 1, + ENOENT = 2, + ESRCH = 3, + EINTR = 4, + EIO = 5, + ENXIO = 6, + E2BIG = 7, + ENOEXEC = 8, + EBADF = 9, + ECHILD = 10, + EDEADLK = 11, + ENOMEM = 12, + EACCES = 13, + EFAULT = 14, + ENOTBLK = 15, + EBUSY = 16, + EEXIST = 17, + EXDEV = 18, + ENODEV = 19, + ENOTDIR = 20, + EISDIR = 21, + EINVAL = 22, + ENFILE = 23, + EMFILE = 24, + ENOTTY = 25, + ETXTBSY = 26, + EFBIG = 27, + ENOSPC = 28, + ESPIPE = 29, + EROFS = 30, + EMLINK = 31, + EPIPE = 32, + EDOM = 33, + ERANGE = 34, + EAGAIN = 35, + EINPROGRESS = 36, + EALREADY = 37, + ENOTSOCK = 38, + EDESTADDRREQ = 39, + EMSGSIZE = 40, + EPROTOTYPE = 41, + ENOPROTOOPT = 42, + EPROTONOSUPPORT = 43, + ESOCKTNOSUPPORT = 44, + ENOTSUP = 45, + EPFNOSUPPORT = 46, + EAFNOSUPPORT = 47, + EADDRINUSE = 48, + EADDRNOTAVAIL = 49, + ENETDOWN = 50, + ENETUNREACH = 51, + ENETRESET = 52, + ECONNABORTED = 53, + ECONNRESET = 54, + ENOBUFS = 55, + EISCONN = 56, + ENOTCONN = 57, + ESHUTDOWN = 58, + ETOOMANYREFS = 59, + ETIMEDOUT = 60, + ECONNREFUSED = 61, + ELOOP = 62, + ENAMETOOLONG = 63, + EHOSTDOWN = 64, + EHOSTUNREACH = 65, + ENOTEMPTY = 66, + EPROCLIM = 67, + EUSERS = 68, + EDQUOT = 69, + ESTALE = 70, + EREMOTE = 71, + EBADRPC = 72, + ERPCMISMATCH = 73, + EPROGUNAVAIL = 74, + EPROGMISMATCH = 75, + EPROCUNAVAIL = 76, + ENOLCK = 77, + ENOSYS = 78, + EFTYPE = 79, + EAUTH = 80, + ENEEDAUTH = 81, + EPWROFF = 82, + EDEVERR = 83, + EOVERFLOW = 84, + EBADEXEC = 85, + EBADARCH = 86, + ESHLIBVERS = 87, + EBADMACHO = 88, + ECANCELED = 89, + EIDRM = 90, + ENOMSG = 91, + EILSEQ = 92, + ENOATTR = 93, + EBADMSG = 94, + EMULTIHOP = 95, + ENODATA = 96, + ENOLINK = 97, + ENOSR = 98, + ENOSTR = 99, + EPROTO = 100, + ETIME = 101, + EOPNOTSUPP = 102, + ENOPOLICY = 103, + ENOTRECOVERABLE = 104, + EOWNERDEAD = 105, + EQFULL = 106, + }; +}; + +export fn cycleStart() void {} +export fn cycleEnd() void {} + +var transform_response: Api.TransformResponse = std.mem.zeroes(Api.TransformResponse); +var output_files: [1]Api.OutputFile = undefined; +var buffer_writer: JSPrinter.BufferWriter = undefined; +var writer: JSPrinter.BufferPrinter = undefined; +var define: *Define.Define = undefined; +export fn bun_malloc(size: usize) u64 { + return @bitCast(u64, [2]u32{ + @ptrToInt((default_allocator.alloc(u8, size) catch unreachable).ptr), + size, + }); +} + +export fn bun_free(bytes: u64) void { + default_allocator.free(Uint8Array.fromJS(bytes)); +} + +var output_stream_buf: [16384]u8 = undefined; +var output_stream = std.io.fixedBufferStream(&output_stream_buf); +var error_stream_buf: [16384]u8 = undefined; +var error_stream = std.io.fixedBufferStream(&error_stream_buf); +var output_source: global.Output.Source = undefined; +export fn init() void { + const Mimalloc = @import("./allocators/mimalloc.zig"); + // reserve 256 MB upfront + Mimalloc.mi_option_set(Mimalloc.mi_option_t.allow_decommit, 0); + Mimalloc.mi_option_set(Mimalloc.mi_option_t.limit_os_alloc, 1); + _ = Mimalloc.mi_reserve_os_memory(2.56e+8, false, true); + + output_source = global.Output.Source.init(output_stream, error_stream); + global.Output.Source.set(&output_source); + JSAst.Stmt.Data.Store.create(default_allocator); + JSAst.Expr.Data.Store.create(default_allocator); + buffer_writer = JSPrinter.BufferWriter.init(default_allocator) catch unreachable; + buffer_writer.buffer.growBy(1024) catch unreachable; + writer = JSPrinter.BufferPrinter.init(buffer_writer); + define = Define.Define.init(default_allocator, null, null) catch unreachable; +} +const Arena = @import("./mimalloc_arena.zig").Arena; + +var log: Logger.Log = undefined; + +export fn transform(opts_array: u64) u64 { + // var arena = std.heap.ArenaAllocator.init(default_allocator); + var arena = Arena.init() catch unreachable; + var allocator = arena.allocator(); + defer arena.deinit(); + log = Logger.Log.init(allocator); + + var reader = ApiReader.init(Uint8Array.fromJS(opts_array), allocator); + var opts = Api.Transform.decode(&reader) catch unreachable; + const loader_ = opts.loader orelse Api.Loader.tsx; + + defer { + JSAst.Stmt.Data.Store.reset(); + JSAst.Expr.Data.Store.reset(); + } + const loader: Options.Loader = switch (loader_) { + .jsx => Options.Loader.jsx, + .js => Options.Loader.js, + .ts => Options.Loader.ts, + .tsx => Options.Loader.tsx, + else => .file, + }; + const path = opts.path orelse loader.stdinName(); + var code = Logger.Source.initPathString(path, opts.contents); + code.contents_is_recycled = true; + + var parser = JSParser.Parser.init(.{ + .jsx = .{}, + }, &log, &code, define, allocator) catch unreachable; + parser.options.jsx.parse = loader.isJSX(); + parser.options.ts = loader.isTypeScript(); + parser.options.features.top_level_await = true; + const result = parser.parse() catch unreachable; + if (result.ok) { + var symbols: [][]JSAst.Symbol = &([_][]JSAst.Symbol{result.ast.symbols}); + + _ = JSPrinter.printAst( + @TypeOf(&writer), + &writer, + result.ast, + JSAst.Symbol.Map.initList(symbols), + &code, + false, + .{}, + void, + null, + ) catch 0; + + output_files[0] = .{ .data = writer.ctx.written, .path = path }; + writer.ctx.reset(); + writer.written = 0; + buffer_writer = writer.ctx; + } else { + output_files[0] = .{ .data = "", .path = path }; + } + + transform_response = Api.TransformResponse{ + .status = if (result.ok) Api.TransformResponseStatus.success else Api.TransformResponseStatus.fail, + .files = &output_files, + .errors = &[_]Api.Message{}, //(log.toAPI(allocator) catch unreachable).msgs, + }; + + var output = std.ArrayList(u8).init(default_allocator); + var output_writer = output.writer(); + const Encoder = ApiWriter(@TypeOf(output_writer)); + var encoder = Encoder.init(output_writer); + transform_response.encode(&encoder) catch unreachable; + return @bitCast(u64, [2]u32{ @ptrToInt(output.items.ptr), output.items.len }); +} + +export fn scan(opts_array: u64) u64 { + // var arena = std.heap.ArenaAllocator.init(default_allocator); + var arena = Arena.init() catch unreachable; + var allocator = arena.allocator(); + defer arena.deinit(); + log = Logger.Log.init(allocator); + + var reader = ApiReader.init(Uint8Array.fromJS(opts_array), allocator); + var opts = Api.Scan.decode(&reader) catch unreachable; + const loader_ = opts.loader orelse Api.Loader.tsx; + + defer { + JSAst.Stmt.Data.Store.reset(); + JSAst.Expr.Data.Store.reset(); + } + const loader: Options.Loader = switch (loader_) { + .jsx => Options.Loader.jsx, + .js => Options.Loader.js, + .ts => Options.Loader.ts, + .tsx => Options.Loader.tsx, + else => .file, + }; + const path = opts.path orelse loader.stdinName(); + var code = Logger.Source.initPathString(path, opts.contents); + code.contents_is_recycled = true; + + var parser = JSParser.Parser.init(.{ + .jsx = .{}, + }, &log, &code, define, allocator) catch unreachable; + parser.options.jsx.parse = loader.isJSX(); + parser.options.ts = loader.isTypeScript(); + parser.options.features.top_level_await = true; + const result = parser.parse() catch unreachable; + var scan_result = std.mem.zeroes(Api.ScanResult); + var output = std.ArrayList(u8).init(default_allocator); + var output_writer = output.writer(); + const Encoder = ApiWriter(@TypeOf(output_writer)); + + if (result.ok) { + var scanned_imports = allocator.alloc(Api.ScannedImport, result.ast.import_records.len) catch unreachable; + var scanned_i: usize = 0; + for (result.ast.import_records) |import_record| { + if (import_record.kind == .internal) continue; + scanned_imports[scanned_i] = Api.ScannedImport{ .path = import_record.path.text, .kind = import_record.kind.toAPI() }; + scanned_i += 1; + } + + scan_result = Api.ScanResult{ .exports = result.ast.named_exports.keys(), .imports = scanned_imports[0..scanned_i] }; + } + + var encoder = Encoder.init(output_writer); + scan_result.encode(&encoder) catch unreachable; + return @bitCast(u64, [2]u32{ @ptrToInt(output.items.ptr), output.items.len }); +} + +// pub fn main() anyerror!void {} + +export fn emsc_main() void { + _ = emsc_main; + _ = cycleEnd; + _ = cycleStart; + _ = transform; + _ = bun_free; + _ = bun_malloc; +} + +comptime { + _ = emsc_main; + _ = cycleEnd; + _ = cycleStart; + _ = transform; + _ = bun_free; + _ = scan; + _ = bun_malloc; +} |