This commit is contained in:
Jarred Sumner
2021-04-29 20:22:25 -07:00
parent 38c7eb73c1
commit 2567243c8d
5 changed files with 1493 additions and 51 deletions

View File

@@ -30,6 +30,7 @@ pub const UserDefines = std.StringHashMap(DefineData);
pub const DefineData = struct {
value: js_ast.Expr.Data,
valueless: bool = false,
original_name: ?string = null,
// True if accessing this value is known to not have any side effects. For
@@ -46,6 +47,10 @@ pub const DefineData = struct {
// So we can create just one struct for it.
pub const GlobalDefineData = DefineData{};
pub fn isUndefined(self: *const DefineData) bool {
return self.valueless;
}
pub fn merge(a: DefineData, b: DefineData) DefineData {
return DefineData{
.value = b.value,
@@ -142,7 +147,7 @@ pub const Define = struct {
dots: std.StringHashMap([]DotDefine),
allocator: *std.mem.Allocator,
pub fn init(allocator: *std.mem.Allocator, user_defines: UserDefines) !*@This() {
pub fn init(allocator: *std.mem.Allocator, _user_defines: ?UserDefines) !*@This() {
var define = try allocator.create(Define);
define.allocator = allocator;
define.identifiers = std.StringHashMap(IdentifierDefine).init(allocator);
@@ -155,7 +160,7 @@ pub const Define = struct {
var ident_define = IdentifierDefine{
.value = val,
};
var value_define = DefineData{ .value = val };
var value_define = DefineData{ .value = val, .valueless = true };
// Step 1. Load the globals into the hash tables
for (GlobalDefinesKey) |global| {
if (global.len == 1) {
@@ -204,7 +209,7 @@ pub const Define = struct {
// Step 3. Load user data into hash tables
// At this stage, user data has already been validated.
if (user_defines.count() > 0) {
if (_user_defines) |user_defines| {
var iter = user_defines.iterator();
while (iter.next()) |user_define| {
// If it has a dot, then it's a DotDefine.

View File

@@ -608,11 +608,11 @@ pub const Symbol = struct {
};
pub fn isKindPrivate(kind: Symbol.Kind) bool {
return kind >= Symbol.Kind.private_field and kind <= Symbol.Kind.private_static_get_set_pair;
return @enumToInt(kind) >= @enumToInt(Symbol.Kind.private_field) and @enumToInt(kind) <= @enumToInt(Symbol.Kind.private_static_get_set_pair);
}
pub fn isKindHoisted(kind: Symbol.Kind) bool {
return kind == Symbol.Kind.hoisted or kind == Symbol.Kind.hoisted_function;
return @enumToInt(kind) == @enumToInt(Symbol.Kind.hoisted) or @enumToInt(kind) == @enumToInt(Symbol.Kind.hoisted_function);
}
pub fn isHoisted(self: *Symbol) bool {
@@ -1222,6 +1222,14 @@ pub const Expr = struct {
pub const EFlags = enum { none, ts_decorator };
pub fn extractNumericValues(left: Expr.Data, right: Expr.Data) ?[2]f64 {
if (!(@as(Expr.Tag, left) == .e_number and @as(Expr.Tag, right) == .e_number)) {
return null;
}
return [2]f64{ left.e_number.value, right.e_number.value };
}
pub fn isAnonymousNamed(e: *Expr) bool {
switch (e.data) {
.e_arrow => {
@@ -2045,6 +2053,38 @@ pub const Expr = struct {
}
};
pub fn isBoolean(a: Expr) bool {
switch (a.data) {
.e_boolean => {
return true;
},
.e_if => |ex| {
return isBoolean(ex.yes) and isBoolean(ex.no);
},
.e_unary => |ex| {
return ex.op == .un_not or ex.op == .un_delete;
},
.e_binary => |ex| {
switch (ex.op) {
.bin_strict_eq, .bin_strict_ne, .bin_loose_eq, .bin_loose_ne, .bin_lt, .bin_gt, .bin_le, .bin_ge, .bin_instanceof, .bin_in => {
return true;
},
.bin_logical_or => {
return isBoolean(ex.left) and isBoolean(ex.right);
},
.bin_logical_and => {
return isBoolean(ex.left) and isBoolean(ex.right);
},
else => {},
}
},
else => {},
}
return false;
}
pub fn assign(a: Expr, b: Expr, allocator: *std.mem.Allocator) Expr {
return alloc(allocator, E.Binary{
.op = .bin_assign,
@@ -2052,16 +2092,16 @@ pub const Expr = struct {
.right = b,
}, a.loc);
}
pub fn at(expr: *Expr, t: anytype, allocator: *std.mem.allocator) callconv(.Inline) Expr {
return alloc(allocator, t, loc);
pub fn at(expr: *Expr, t: anytype, allocator: *std.mem.Allocator) callconv(.Inline) Expr {
return alloc(allocator, t, expr.loc);
}
// Wraps the provided expression in the "!" prefix operator. The expression
// will potentially be simplified to avoid generating unnecessary extra "!"
// operators. For example, calling this with "!!x" will return "!x" instead
// of returning "!!!x".
pub fn not(expr: Expr, allocator: *std.mem.Allocator) Expr {
return maybeSimplifyNot(&expr, allocator) orelse expr;
pub fn not(expr: *Expr, allocator: *std.mem.Allocator) Expr {
return maybeSimplifyNot(expr, allocator) orelse expr.*;
}
// The given "expr" argument should be the operand of a "!" prefix operator
@@ -2086,16 +2126,16 @@ pub const Expr = struct {
.e_function,
.e_arrow,
.e_reg_exp,
=> |b| {
=> {
return expr.at(E.Boolean{ .value = false }, allocator);
},
// "!!!a" => "!a"
.e_unary => |un| {
if (un.op == Op.Code.un_not and isBooleanValue(un.value)) {
return un.value.*;
if (un.op == Op.Code.un_not and isBoolean(un.value)) {
return un.value;
}
},
.e_binary => |*ex| {
.e_binary => |ex| {
// TODO: evaluate whether or not it is safe to do this mutation since it's modifying in-place.
// Make sure that these transformations are all safe for special values.
// For example, "!(a < b)" is not the same as "a >= b" if a and/or b are
@@ -2105,20 +2145,20 @@ pub const Expr = struct {
ex.op = .bin_loose_ne;
return expr.*;
},
Op.Code.bin_op_loose_ne => {
Op.Code.bin_loose_ne => {
ex.op = .bin_loose_eq;
return expr.*;
},
Op.Code.bin_op_strict_eq => {
Op.Code.bin_strict_eq => {
ex.op = .bin_strict_ne;
return expr.*;
},
Op.Code.bin_op_strict_ne => {
Op.Code.bin_strict_ne => {
ex.op = .bin_strict_eq;
return expr.*;
},
Op.Code.bin_op_comma => {
ex.right = ex.right.not();
Op.Code.bin_comma => {
ex.right = ex.right.not(allocator);
return expr.*;
},
else => {},

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@ const js_printer = @import("js_printer.zig");
const js_ast = @import("js_ast.zig");
const linker = @import("linker.zig");
usingnamespace @import("ast/base.zig");
usingnamespace @import("defines.zig");
pub fn main() anyerror!void {
try alloc.setup(std.heap.page_allocator);
@@ -31,6 +32,15 @@ pub fn main() anyerror!void {
var log = logger.Log.init(alloc.dynamic);
var source = logger.Source.initFile(opts.entry_point, alloc.dynamic);
var ast: js_ast.Ast = undefined;
var raw_defines = RawDefines.init(alloc.static);
try raw_defines.put("process.env.NODE_ENV", "\"development\"");
var user_defines = try DefineData.from_input(raw_defines, &log, alloc.static);
var define = try Define.init(
alloc.static,
user_defines,
);
switch (opts.loader) {
.json => {
@@ -47,7 +57,7 @@ pub fn main() anyerror!void {
ast = js_ast.Ast.initTest(&([_]js_ast.Part{part}));
},
.jsx, .tsx, .ts, .js => {
var parser = try js_parser.Parser.init(opts, &log, &source, alloc.dynamic);
var parser = try js_parser.Parser.init(opts, &log, &source, define, alloc.dynamic);
var res = try parser.parse();
ast = res.ast;
},

View File

@@ -181,7 +181,7 @@ pub fn toUTF16Buf(in: string, out: []u16) usize {
}
}
return utf8Iterator.i;
return i;
}
pub fn toUTF16Alloc(in: string, allocator: *std.mem.Allocator) !JavascriptString {