aboutsummaryrefslogtreecommitdiff
path: root/src/z/parser/js/ast/pat.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/z/parser/js/ast/pat.zig')
-rw-r--r--src/z/parser/js/ast/pat.zig190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/z/parser/js/ast/pat.zig b/src/z/parser/js/ast/pat.zig
new file mode 100644
index 0000000..fdc8f55
--- /dev/null
+++ b/src/z/parser/js/ast/pat.zig
@@ -0,0 +1,190 @@
+const std = @import("std");
+const Loc = @import("loc.zig").Loc;
+const Expr = @import("expr.zig").Expr;
+const PropKey = @import("expr.zig").PropKey;
+const Parser = @import("../parser.zig").Parser;
+const Formatter = @import("../formatter.zig").Formatter;
+const ParseError = @import("../parser.zig").ParseError;
+
+pub const PatType = union(enum) {
+ ident: []const u8,
+ object: ObjectPat,
+ array: ArrayPat,
+ assign: AssignPat,
+ rest: RestPat,
+};
+
+pub const Pat = struct {
+ loc: Loc,
+ data: PatType,
+
+ pub fn parse(p: *Parser) ParseError!Pat {
+ const start = p.tok().loc.start;
+
+ switch (p.peek()) {
+ .identifier, .await, .yield => {
+ const t = p.advanceTok();
+ const name = p.tokenSlice(t);
+ return Pat{ .loc = .{ .start = start, .end = t.loc.end }, .data = .{ .ident = name } };
+ },
+ .lbrace => {
+ p.advance();
+ var props: [128]PatProp = undefined;
+ var count: usize = 0;
+ var rest: ?*const Pat = null;
+
+ while (p.peek() != .rbrace and p.peek() != .eof) {
+ if (p.peek() == .@"...") {
+ p.advance();
+ const pat = try Pat.parse(p);
+ rest = p.arena.patPtr(pat.data, pat.loc);
+ break;
+ }
+ if (p.peek() == .identifier) {
+ const name_tok = p.tok();
+ const name = p.tokenSlice(name_tok);
+ p.advance();
+ if (p.peek() == .@":") {
+ p.advance();
+ const val_pat = try Pat.parse(p);
+ props[count] = .{ .key_value = .{ .key = .{ .ident = name }, .value = p.arena.patPtr(val_pat.data, val_pat.loc) } };
+ count += 1;
+ } else {
+ props[count] = .{ .shorthand = name };
+ count += 1;
+ }
+ } else if (p.peek() == .lbracket) {
+ const key = try p.parsePropKey();
+ try p.expect(.@":");
+ const val_pat = try Pat.parse(p);
+ props[count] = .{ .key_value = .{ .key = key, .value = p.arena.patPtr(val_pat.data, val_pat.loc) } };
+ count += 1;
+ } else {
+ break;
+ }
+ if (!p.match(.comma)) break;
+ }
+
+ try p.expect(.rbrace);
+ return Pat{ .loc = .{ .start = start, .end = p.tok().loc.start }, .data = .{ .object = .{ .loc = .{ .start = start, .end = p.tok().loc.start }, .props = props[0..count], .rest = rest } } };
+ },
+ .lbracket => {
+ p.advance();
+ var elems: [128]?Pat = undefined;
+ var count: usize = 0;
+ var rest: ?*const Pat = null;
+
+ while (p.peek() != .rbracket and p.peek() != .eof) {
+ if (p.match(.comma)) {
+ elems[count] = null;
+ count += 1;
+ } else if (p.peek() == .@"...") {
+ p.advance();
+ const pat = try Pat.parse(p);
+ rest = p.arena.patPtr(pat.data, pat.loc);
+ break;
+ } else {
+ const pat = try Pat.parse(p);
+ elems[count] = pat;
+ count += 1;
+ if (!p.match(.comma)) break;
+ }
+ }
+
+ try p.expect(.rbracket);
+ return Pat{ .loc = .{ .start = start, .end = p.tok().loc.start }, .data = .{ .array = .{ .loc = .{ .start = start, .end = p.tok().loc.start }, .elems = elems[0..count], .rest = rest } } };
+ },
+ else => return ParseError.ExpectedParameterName,
+ }
+ }
+
+ pub fn fmt(self: @This(), f: *Formatter) void {
+ switch (self.data) {
+ .ident => |name| f.write(name),
+ .object => |o| o.fmt(f),
+ .array => |a| a.fmt(f),
+ .assign => |a| {
+ a.left.*.fmt(f);
+ f.write(" = ");
+ a.right.*.fmt(f);
+ },
+ .rest => |r| {
+ f.write("...");
+ r.arg.*.fmt(f);
+ },
+ }
+ }
+};
+
+pub const ObjectPat = struct {
+ loc: Loc,
+ props: []const PatProp,
+ rest: ?*const Pat,
+
+ pub fn fmt(self: @This(), f: *Formatter) void {
+ f.writeChar('{');
+ var first = true;
+ for (self.props) |prop| {
+ if (!first) f.write(", ");
+ first = false;
+ switch (prop) {
+ .key_value => |kv| {
+ kv.key.fmt(f);
+ f.write(": ");
+ kv.value.*.fmt(f);
+ },
+ .shorthand => |name| f.write(name),
+ .rest => |r| {
+ f.write("...");
+ r.*.fmt(f);
+ },
+ }
+ }
+ if (self.rest) |rest| {
+ if (!first) f.write(", ");
+ f.write("...");
+ rest.*.fmt(f);
+ }
+ f.writeChar('}');
+ }
+};
+
+pub const PatProp = union(enum) {
+ key_value: struct {
+ key: PropKey,
+ value: *const Pat,
+ },
+ shorthand: []const u8,
+ rest: *const Pat,
+};
+
+pub const ArrayPat = struct {
+ loc: Loc,
+ elems: []const ?Pat,
+ rest: ?*const Pat,
+
+ pub fn fmt(self: @This(), f: *Formatter) void {
+ f.writeChar('[');
+ for (self.elems, 0..) |elem, i| {
+ if (i > 0) f.write(", ");
+ if (elem) |pat| pat.fmt(f);
+ }
+ if (self.rest) |rest| {
+ if (self.elems.len > 0) f.write(", ");
+ f.write("...");
+ rest.*.fmt(f);
+ }
+ f.writeChar(']');
+ }
+};
+
+pub const AssignPat = struct {
+ loc: Loc,
+ left: *const Pat,
+ right: *const Expr,
+};
+
+pub const RestPat = struct {
+ loc: Loc,
+ arg: *const Pat,
+};