mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
wap
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -595,7 +595,7 @@ pub fn NewLexerType(comptime jsonOptions: ?JSONOptions) type {
|
||||
},
|
||||
|
||||
else => {
|
||||
lexer.token = T.t_plus;
|
||||
lexer.token = T.t_minus;
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user