aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/js_ast.zig2
-rw-r--r--src/js_lexer.zig2
-rw-r--r--src/js_parser.zig11
-rw-r--r--src/js_printer.zig196
-rw-r--r--src/json_parser.zig17
-rw-r--r--src/main.zig9
-rw-r--r--src/main_wasm.zig12
-rw-r--r--src/string_mutable.zig21
8 files changed, 247 insertions, 23 deletions
diff --git a/src/js_ast.zig b/src/js_ast.zig
index 7ab5e39ad..5a5e6dec4 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -2372,7 +2372,7 @@ pub const Case = struct { loc: logger.Loc, value: ?ExprNodeIndex, body: StmtNode
pub const Op = struct {
// If you add a new token, remember to add it to "OpTable" too
- pub const Code = packed enum(u6) {
+ pub const Code = enum {
// Prefix
un_pos,
un_neg,
diff --git a/src/js_lexer.zig b/src/js_lexer.zig
index 3118f31d2..bef9893c8 100644
--- a/src/js_lexer.zig
+++ b/src/js_lexer.zig
@@ -595,7 +595,7 @@ pub fn NewLexerType(comptime jsonOptions: ?JSONOptions) type {
},
else => {
- lexer.token = T.t_plus;
+ lexer.token = T.t_minus;
},
}
},
diff --git a/src/js_parser.zig b/src/js_parser.zig
index e32adc859..44cb5e036 100644
--- a/src/js_parser.zig
+++ b/src/js_parser.zig
@@ -405,8 +405,15 @@ pub const Parser = struct {
// Pop the module scope to apply the "ContainsDirectEval" rules
p.popScope();
- result = p.toAST(parts);
- result.source_map_comment = p.lexer.source_mapping_url;
+ result.ast = js_ast.Ast{
+ .parts = parts.toOwnedSlice(),
+ .symbols = p.symbols.toOwnedSlice(),
+ .module_scope = p.module_scope.*,
+ };
+ result.ok = true;
+
+ // result = p.toAST(parts);
+ // result.source_map_comment = p.lexer.source_mapping_url;
}
return result;
diff --git a/src/js_printer.zig b/src/js_printer.zig
index fb7d83f14..243e4bb11 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -33,6 +33,14 @@ const Scope = js_ast.Scope;
const locModuleScope = logger.Loc.Empty;
const Ast = js_ast.Ast;
+const hex_chars = "0123456789ABCDEF";
+const first_ascii = 0x20;
+const last_ascii = 0x7E;
+const first_high_surrogate = 0xD800;
+const last_high_surrogate = 0xDBFF;
+const first_low_surrogate = 0xDC00;
+const last_low_surrogate = 0xDFFF;
+
fn notimpl() void {
std.debug.panic("Not implemented yet!", .{});
}
@@ -100,6 +108,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
prev_reg_exp_end: i32 = -1,
call_target: ?Expr.Data = null,
int_to_bytes_buffer: [64]u8 = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ writer: MutableString.Writer,
allocator: *std.mem.Allocator,
const Printer = @This();
@@ -150,8 +159,21 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
// }
// }
- pub fn print(p: *Printer, str: string) void {
- p.js.append(str) catch unreachable;
+ pub fn print(p: *Printer, str: anytype) void {
+ switch (@TypeOf(str)) {
+ string => {
+ p.js.append(str) catch unreachable;
+ },
+ u8 => {
+ p.js.appendChar(str) catch unreachable;
+ },
+ u16 => {
+ p.js.appendChar(@intCast(u8, str)) catch unreachable;
+ },
+ else => {
+ p.js.append(@as(string, str)) catch unreachable;
+ },
+ }
}
pub fn unsafePrint(p: *Printer, str: string) void {
@@ -184,7 +206,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
pub fn printSemicolonIfNeeded(p: *Printer) void {
notimpl();
}
- pub fn printSpaceBeforeIdentifier(p: *Printer) void {
+ pub fn printSpaceBeforeIdentifier(
+ p: *Printer,
+ ) void {
const n = p.js.len();
if (n > 0 and (js_lexer.isIdentifierContinue(p.js.list.items[n - 1]) or n == p.prev_reg_exp_end)) {
p.print(" ");
@@ -223,6 +247,125 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
pub fn printClass(p: *Printer, class: G.Class) void {
notimpl();
}
+
+ pub fn bestQuoteCharForString(p: *Printer, str: JavascriptString, allow_backtick: bool) u8 {
+ var single_cost: usize = 0;
+ var double_cost: usize = 0;
+ var backtick_cost: usize = 0;
+ var char: u8 = 0;
+ var i: usize = 0;
+ while (i < str.len) {
+ switch (str[i]) {
+ '\'' => {
+ single_cost += 1;
+ },
+ '"' => {
+ double_cost += 1;
+ },
+ '`' => {
+ backtick_cost += 1;
+ },
+ '$' => {
+ if (i + 1 < str.len and str[i + 1] == '{') {
+ backtick_cost += 1;
+ }
+ },
+ else => {},
+ }
+ i += 1;
+ }
+
+ char = '"';
+ if (double_cost > single_cost) {
+ char = '\'';
+
+ if (single_cost > backtick_cost and allow_backtick) {
+ char = '`';
+ }
+ } else if (double_cost > backtick_cost and allow_backtick) {
+ char = '`';
+ }
+
+ return char;
+ }
+
+ pub fn printNonNegativeFloat(p: *Printer, float: f64) void {
+ // cool thing about languages like this
+ // i know this is going to be in the stack and not the heap
+ var parts = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ // normally, you pay the cost of parsing a string formatter at runtime
+ // not in zig! CI pays for it instead
+ // its probably still doing some unnecessary integer conversion somewhere though
+ var slice = std.fmt.bufPrint(&parts, "{d}", .{float}) catch unreachable;
+ p.js.list.appendSlice(p.allocator, slice) catch unreachable;
+ }
+
+ pub fn printQuotedUTF16(e: *Printer, text: JavascriptString, quote: u8) void {
+ // utf-8 is a max of 4 bytes
+ var temp = [4]u8{ 0, 0, 0, 0 };
+ var i: usize = 0;
+ const n: usize = text.len;
+ var c: u16 = 0;
+
+ e.js.growIfNeeded(text.len) catch unreachable;
+
+ while (i < n) {
+ c = text[i];
+ i += 1;
+
+ // TODO: here
+ switch (c) {
+ // Special-case the null character since it may mess with code written in C
+ // that treats null characters as the end of the string.
+ 0x00 => {
+ // We don't want "\x001" to be written as "\01"
+ if (i < n) {
+ e.print("\\x00");
+ } else {
+ e.print("\\0");
+ }
+ },
+
+ // Special-case the bell character since it may cause dumping this file to
+ // the terminal to make a sound, which is undesirable. Note that we can't
+ // use an octal literal to print this shorter since octal literals are not
+ // allowed in strict mode (or in template strings).
+ 0x07 => {
+ e.print("\\x07");
+ },
+ 0x08 => {
+ e.print("\\b");
+ },
+ 0x0C => {
+ e.print("\\f");
+ },
+ '\n' => {
+ if (quote == '`') {
+ e.print("\n");
+ } else {
+ e.print("\\n");
+ }
+ },
+ 0x0D => {
+ e.print("\\r");
+ },
+ 0x0B => {
+ e.print("\\r");
+ },
+ 0x5C => {},
+ '\'' => {},
+ '"' => {},
+ '`' => {},
+ '$' => {},
+ 0x2028 => {},
+ 0x2029 => {},
+ 0xFEFF => {},
+ else => {},
+ }
+ }
+ }
+
pub fn printExpr(p: *Printer, expr: Expr, level: Level, flags: ExprFlag) void {
p.addSourceMapping(expr.loc);
@@ -295,7 +438,18 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(if (e.value) "true" else "false");
},
.e_string => |e| {
- notimpl();
+ // If this was originally a template literal, print it as one as long as we're not minifying
+ if (e.prefer_template) {
+ p.print("`");
+ p.printQuotedUTF16(e.value, '`');
+ p.print("`");
+ return;
+ }
+
+ const c = p.bestQuoteCharForString(e.value, true);
+ p.print(c);
+ p.printQuotedUTF16(e.value, c);
+ p.print(c);
},
.e_template => |e| {
notimpl();
@@ -323,7 +477,13 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.printSpaceBeforeIdentifier();
p.print("(-Infinity)");
}
- } else if (!std.math.signbit(value)) {} else if (level.gte(.prefix)) {
+ } else if (!std.math.signbit(value)) {
+ p.printSpaceBeforeIdentifier();
+ p.printNonNegativeFloat(absValue);
+
+ // Remember the end of the latest number
+ p.prev_num_end = p.js.lenI();
+ } else if (level.gte(.prefix)) {
// Expressions such as "(-1).toString" need to wrap negative numbers.
// Instead of testing for "value < 0" we test for "signbit(value)" and
// "!isNaN(value)" because we need this to be true for "-0" and "-0 < 0"
@@ -332,7 +492,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.printNonNegativeFloat(absValue);
p.print(")");
} else {
- p.printSpaceBeforeIdentifier(Op.Code.un_neg);
+ p.printSpaceBeforeOperator(Op.Code.un_neg);
p.print("-");
p.printNonNegativeFloat(absValue);
@@ -364,6 +524,26 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
}
+ pub fn printSpaceBeforeOperator(p: *Printer, next: Op.Code) void {
+ // if (p.prev_op_end == p.js.lenI()) {
+ // const prev = p.prev_op;
+ // "+ + y" => "+ +y"
+ // "+ ++ y" => "+ ++y"
+ // "x + + y" => "x+ +y"
+ // "x ++ + y" => "x+++y"
+ // "x + ++ y" => "x+ ++y"
+ // "-- >" => "-- >"
+ // "< ! --" => "<! --"
+ // if (((prev == Op.Code.bin_add or prev == Op.Code.un_pos) and (next == Op.Code.bin_add or next == Op.Code.un_pos or next == Op.Code.un_pre_inc)) or
+ // ((prev == Op.Code.bin_sub or prev == Op.Code.un_neg) and (next == Op.Code.bin_sub or next == Op.Code.un_neg or next == Op.Code.un_pre_dec)) or
+ // (prev == Op.Code.un_post_dec and next == Op.Code.bin_gt) or
+ // (prev == Op.Code.un_not and next == Op.Code.un_pre_dec and p.js.len() > 1 and p.js.list.items[p.js.list.items.len - 2] == '<'))
+ // {
+ // p.print(" ");
+ // }
+ // }
+ }
+
pub fn printProperty(p: *Printer, prop: G.Property) void {
notimpl();
}
@@ -438,12 +618,14 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
pub fn init(allocator: *std.mem.Allocator, tree: Ast, symbols: Symbol.Map, opts: Options) !Printer {
+ var js = try MutableString.init(allocator, 1024);
return Printer{
.allocator = allocator,
.import_records = tree.import_records,
.options = opts,
.symbols = symbols,
- .js = try MutableString.init(allocator, 1024),
+ .js = js,
+ .writer = js.writer(),
};
}
};
diff --git a/src/json_parser.zig b/src/json_parser.zig
index c6b7ec9aa..0654c074c 100644
--- a/src/json_parser.zig
+++ b/src/json_parser.zig
@@ -210,6 +210,9 @@ pub fn ParseTSConfig(log: logger.Loc, source: logger.Source, allocator: *std.mem
const duplicateKeyJson = "{ \"name\": \"valid\", \"name\": \"invalid\" }";
+const js_printer = @import("js_printer.zig");
+const renamer = @import("renamer.zig");
+
fn expectPrintedJSON(_contents: string, expected: string) void {
if (alloc.dynamic_manager == null) {
alloc.setup(std.heap.page_allocator) catch unreachable;
@@ -219,15 +222,14 @@ fn expectPrintedJSON(_contents: string, expected: string) void {
std.mem.copy(u8, contents, _contents);
contents[contents.len - 1] = ';';
var log = logger.Log.init(alloc.dynamic);
- const js_printer = @import("js_printer.zig");
- const renamer = @import("renamer.zig");
+ defer log.msgs.deinit();
var source = logger.Source.initPathString(
"source.json",
contents,
);
const expr = try ParseJSON(&source, &log, alloc.dynamic);
- var stmt = Stmt.alloc(std.heap.page_allocator, S.SExpr{ .value = expr }, logger.Loc{ .start = 0 });
+ var stmt = Stmt.alloc(alloc.dynamic, S.SExpr{ .value = expr }, logger.Loc{ .start = 0 });
var part = js_ast.Part{
.stmts = &([_]Stmt{stmt}),
@@ -238,7 +240,7 @@ fn expectPrintedJSON(_contents: string, expected: string) void {
std.debug.panic("--FAIL--\nExpr {s}\nLog: {s}\n--FAIL--", .{ expr, log.msgs.items[0].data.text });
}
- const result = js_printer.printAst(std.heap.page_allocator, tree, symbol_map, true, js_printer.Options{ .to_module_ref = Ref{ .inner_index = 0 } }) catch unreachable;
+ const result = js_printer.printAst(alloc.dynamic, tree, symbol_map, true, js_printer.Options{ .to_module_ref = Ref{ .inner_index = 0 } }) catch unreachable;
var js = result.js;
@@ -259,6 +261,13 @@ test "ParseJSON" {
expectPrintedJSON("true", "true");
expectPrintedJSON("false", "false");
expectPrintedJSON("1", "1");
+ expectPrintedJSON("10", "10");
+ expectPrintedJSON("100", "100");
+ expectPrintedJSON("100.1", "100.1");
+ expectPrintedJSON("19.1", "19.1");
+ expectPrintedJSON("19.12", "19.12");
+ expectPrintedJSON("3.4159820837456", "3.4159820837456");
+ expectPrintedJSON("-10000.25", "-10000.25");
}
test "ParseJSON DuplicateKey warning" {
diff --git a/src/main.zig b/src/main.zig
index 6bdd34cb4..5410b0e2a 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -4,6 +4,8 @@ const logger = @import("logger.zig");
const alloc = @import("alloc.zig");
const options = @import("options.zig");
const js_parser = @import("js_parser.zig");
+const js_printer = @import("js_printer.zig");
+const js_ast = @import("js_ast.zig");
pub fn main() anyerror!void {
try alloc.setup(std.heap.page_allocator);
@@ -20,11 +22,14 @@ pub fn main() anyerror!void {
const entryPointName = "/var/foo/index.js";
const code = "for (let i = 0; i < 100; i++) { console.log('hi') aposkdpoaskdpokasdpokasdpokasdpokasdpoaksdpoaksdpoaskdpoaksdpoaksdpoaskdpoaskdpoasdk; ";
- var log = logger.Log.init(alloc.dynamic);
+
const opts = try options.TransformOptions.initUncached(alloc.dynamic, entryPointName, code);
+ var log = logger.Log.init(alloc.dynamic);
var source = logger.Source.initFile(opts.entry_point, alloc.dynamic);
var parser = try js_parser.Parser.init(opts, &log, &source, alloc.dynamic);
var res = try parser.parse();
- std.debug.print("{s}", .{res});
+ const printed = try js_printer.printAst(alloc.dynamic, res.ast, js_ast.Symbol.Map{}, false, js_printer.Options{ .to_module_ref = js_ast.Ref{ .inner_index = 0 } });
+
+ std.debug.print("{s}\n{s}", .{ res, printed });
}
diff --git a/src/main_wasm.zig b/src/main_wasm.zig
index 73f03f9ad..5410b0e2a 100644
--- a/src/main_wasm.zig
+++ b/src/main_wasm.zig
@@ -4,6 +4,8 @@ const logger = @import("logger.zig");
const alloc = @import("alloc.zig");
const options = @import("options.zig");
const js_parser = @import("js_parser.zig");
+const js_printer = @import("js_printer.zig");
+const js_ast = @import("js_ast.zig");
pub fn main() anyerror!void {
try alloc.setup(std.heap.page_allocator);
@@ -20,8 +22,14 @@ pub fn main() anyerror!void {
const entryPointName = "/var/foo/index.js";
const code = "for (let i = 0; i < 100; i++) { console.log('hi') aposkdpoaskdpokasdpokasdpokasdpokasdpoaksdpoaksdpoaskdpoaksdpoaksdpoaskdpoaskdpoasdk; ";
- var parser = try js_parser.Parser.init(try options.TransformOptions.initUncached(alloc.dynamic, entryPointName, code), alloc.dynamic);
+
+ const opts = try options.TransformOptions.initUncached(alloc.dynamic, entryPointName, code);
+ var log = logger.Log.init(alloc.dynamic);
+ var source = logger.Source.initFile(opts.entry_point, alloc.dynamic);
+ var parser = try js_parser.Parser.init(opts, &log, &source, alloc.dynamic);
var res = try parser.parse();
- std.debug.print("{s}", .{res});
+ const printed = try js_printer.printAst(alloc.dynamic, res.ast, js_ast.Symbol.Map{}, false, js_printer.Options{ .to_module_ref = js_ast.Ref{ .inner_index = 0 } });
+
+ std.debug.print("{s}\n{s}", .{ res, printed });
}
diff --git a/src/string_mutable.zig b/src/string_mutable.zig
index 8c9c9e99e..7a7964dec 100644
--- a/src/string_mutable.zig
+++ b/src/string_mutable.zig
@@ -7,15 +7,24 @@ pub const MutableString = struct {
allocator: *std.mem.Allocator,
list: std.ArrayListUnmanaged(u8),
- pub const Writer = std.io.Writer(@This(), anyerror, MutableString.writeAll);
+ pub const Writer = std.io.Writer(*@This(), anyerror, MutableString.writeAll);
pub fn writer(self: *MutableString) Writer {
return Writer{
.context = self,
};
}
- pub fn writeAll(self: *MutableString, bytes: []u8) !usize {
- try self.list.appendSlice(self.allocator, bytes);
+ pub fn growIfNeeded(self: *MutableString, amount: usize) !void {
+ const new_capacity = self.list.items.len + amount;
+ if (self.list.capacity < new_capacity) {
+ try self.list.ensureCapacity(self.allocator, new_capacity);
+ }
+ }
+
+ pub fn writeAll(self: *MutableString, bytes: string) !usize {
+ const new_capacity = self.list.items.len + bytes.len;
+ try self.list.ensureCapacity(self.allocator, new_capacity);
+ self.list.appendSliceAssumeCapacity(bytes);
return self.list.items.len;
}
@@ -74,7 +83,11 @@ pub const MutableString = struct {
}
}
pub fn growBy(self: *MutableString, amount: usize) callconv(.Inline) !void {
- try self.list.ensureCapacity(self.allocator, self.list.capacity + amount);
+ try self.ensureCapacity(self.list.capacity + amount);
+ }
+
+ pub fn ensureCapacity(self: *MutableString, amount: usize) callconv(.Inline) !void {
+ try self.list.ensureCapacity(self.allocator, amount);
}
pub fn deinit(self: *MutableString) !void {