authorgravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-09-14 22:30:09-04:00
committergravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-09-14 22:30:09-04:00
logd44222bc0e79efa9dd6bfe4c9922c0bc97ad63bc
treef7dfdeb3bcbfa9c2594d06d7b711a964f10dd8e8
parente52a575edb42a6339b121ed77629b3874d1fe8f4
signature Commit is signed but in an unrecognized format.

start tuple


10 files changed, 542 insertions(+), 270 deletions(-)

src/core/Air.Dump.zig+16
......@@ -379,6 +379,22 @@ pub const State = struct {
379379 }
380380 try w.writeAll("'");
381381 },
382 .tuple_type => |tuple_type| {
383 try w.writeAll("(");
384 for (tuple_type.items, 0..) |item, i| {
385 if (i != 0) try w.writeAll(", ");
386 try s.dumpValue(w, item.value());
387 }
388 try w.writeAll(")");
389 },
390 .tuple_value => |tuple_value| {
391 try w.writeAll("(");
392 for (tuple_value.items, 0..) |item, i| {
393 if (i != 0) try w.writeAll(", ");
394 try s.dumpValue(w, item);
395 }
396 try w.writeAll(")");
397 },
382398 }
383399 }
384400
src/core/InternPool.zig+118-3
......@@ -101,6 +101,8 @@ pub const Tag = enum(u8) {
101101 struct_type,
102102 /// An array type
103103 array_type,
104 /// A tuple type
105 tuple_type,
104106 /// A type that can be represented with only an enum tag.
105107 simple_type,
106108
......@@ -129,6 +131,8 @@ pub const Tag = enum(u8) {
129131 external_value,
130132 /// A value masked as "opaque" type
131133 opaque_value,
134 /// A tuple value
135 tuple_value,
132136
133137 pub fn Data(comptime tag: Tag) type {
134138 return switch (tag) {
......@@ -161,6 +165,8 @@ pub const Tag = enum(u8) {
161165 .array_type => ArrayType,
162166 .array_value => ArrayValue,
163167 .external_value => ExternalValue,
168 .tuple_type => TupleType,
169 .tuple_value => TupleValue,
164170 };
165171 }
166172
......@@ -199,6 +205,20 @@ pub const Tag = enum(u8) {
199205 items_len: u32,
200206 };
201207
208 /// Trailing:
209 /// 0. item: Type. Repeated per .items_len
210 pub const TupleType = struct {
211 items_len: u32,
212 };
213
214 /// Trailing:
215 /// 0. value: Value. Repeated per .items_len
216 pub const TupleValue = struct {
217 /// This is the tuple type, not the item type
218 type: Type,
219 items_len: u32,
220 };
221
202222 /// Trailing:
203223 /// 0. value: Value. Repeated .ty.structInfo().field_len
204224 pub const StructValue = struct {
......@@ -216,9 +236,9 @@ pub const Tag = enum(u8) {
216236/// This is an index into .items
217237pub const Value = enum(u32) {
218238 pub const first_type: Value = .opaque_type;
219 pub const last_type: Value = .numeric_literal_array_type;
239 pub const last_type: Value = .empty_tuple_type;
220240 pub const first_value: Value = .void;
221 pub const last_value: Value = .empty_array;
241 pub const last_value: Value = .empty_tuple;
222242
223243 opaque_type,
224244 bool_type,
......@@ -230,6 +250,7 @@ pub const Value = enum(u32) {
230250 numeric_literal_type,
231251 numeric_literal_array_type,
232252 never_array_type,
253 empty_tuple_type,
233254
234255 void,
235256 bool_true,
......@@ -239,6 +260,7 @@ pub const Value = enum(u32) {
239260 nan,
240261 empty_string,
241262 empty_array,
263 empty_tuple,
242264
243265 none = std.math.maxInt(u32),
244266 _,
......@@ -316,6 +338,7 @@ pub const Value = enum(u32) {
316338 .simple_type,
317339 .struct_type,
318340 .array_type,
341 .tuple_type,
319342 => .type,
320343
321344 .simple_value => switch (value.valueData(ip, .simple_value)) {
......@@ -332,6 +355,7 @@ pub const Value = enum(u32) {
332355 .struct_value => value.toKey(ip).struct_value.ty,
333356 .array_value => value.toKey(ip).array_value.type,
334357 .external_value, .opaque_value => .@"opaque",
358 .tuple_value => value.toKey(ip).tuple_value.type,
335359 };
336360 }
337361
......@@ -345,6 +369,7 @@ pub const Value = enum(u32) {
345369 .struct_type,
346370 .simple_type,
347371 .array_type,
372 .tuple_type,
348373 => @enumFromInt(@intFromEnum(value)),
349374
350375 // exception: void is a value AND a type
......@@ -395,6 +420,7 @@ pub const Type = enum(u32) {
395420 numeric_literal = @intFromEnum(Value.numeric_literal_type),
396421 numeric_literal_array = @intFromEnum(Value.numeric_literal_array_type),
397422 never_array = @intFromEnum(Value.never_array_type),
423 empty_tuple = @intFromEnum(Value.empty_tuple_type),
398424 void = @intFromEnum(Value.void),
399425 _,
400426
......@@ -404,6 +430,7 @@ pub const Type = enum(u32) {
404430 struct_type = @intFromEnum(InternPool.Tag.struct_type),
405431 array_type = @intFromEnum(InternPool.Tag.array_type),
406432 simple_type = @intFromEnum(InternPool.Tag.simple_type),
433 tuple_type = @intFromEnum(InternPool.Tag.tuple_type),
407434 };
408435
409436 /// An array of `Index` existing within the `extra` array.
......@@ -446,6 +473,11 @@ pub const Type = enum(u32) {
446473 return ip.valueToKey(ty.value()).array_type;
447474 }
448475
476 pub fn toTupleType(ty: Type, ip: *const InternPool) ?Key.TupleType {
477 if (ty.tag(ip) != .tuple_type) return null;
478 return ip.valueToKey(ty.value()).tuple_type;
479 }
480
449481 /// If it is possible to represent this type at runtime. Some types do not
450482 /// have a defined representation, such as structs (to allow field renaming, unwrapping).
451483 pub fn hasPossibleRepresentation(ty: Type, ip: *const InternPool) bool {
......@@ -466,6 +498,15 @@ pub const Type = enum(u32) {
466498 .struct_type,
467499 .function_type,
468500 => true,
501 .tuple_type => {
502 const tuple_type = ty.toTupleType(ip).?;
503 for (tuple_type.items) |item| {
504 if (!item.hasPossibleRepresentation(ip)) {
505 return false;
506 }
507 }
508 return true;
509 },
469510 .array_type => ty.toArrayType(ip).?.item_type.hasPossibleRepresentation(ip),
470511 },
471512 };
......@@ -490,6 +531,7 @@ pub const Type = enum(u32) {
490531 .simple_type => unreachable, // all simple types are already printed
491532 .struct_type,
492533 .function_type,
534 .tuple_type,
493535 => false,
494536 .array_type => ty.toArrayType(ip).?.item_type.hasDefinedRepresentation(ip),
495537 },
......@@ -546,6 +588,14 @@ pub const Type = enum(u32) {
546588 const array_type = ty.toArrayType(ip).?;
547589 try writer.print("{}", .{array_type.item_type.displayName(ip)});
548590 },
591 .tuple_type => {
592 try writer.writeAll("(");
593 for (ty.toTupleType(ip).?.items, 0..) |item, i| {
594 if (i != 0) try writer.writeAll(", ");
595 try writer.print("{}", .{item.displayName(ip)});
596 }
597 try writer.writeAll(")");
598 },
549599 }
550600 }
551601};
......@@ -584,6 +634,7 @@ pub const static_keys = [_]Key{
584634 SimpleType.numeric_literal.key(),
585635 .{ .array_type = .{ .item_type = Type.numeric_literal } },
586636 .{ .array_type = .{ .item_type = Type.never } },
637 .{ .tuple_type = .{ .items = &.{} } },
587638
588639 SimpleValue.void.key(),
589640 SimpleValue.true.key(),
......@@ -596,6 +647,10 @@ pub const static_keys = [_]Key{
596647 .items = &.{},
597648 } },
598649 .{ .string = "" },
650 .{ .tuple_value = .{
651 .type = .empty_tuple,
652 .items = &.{},
653 } },
599654};
600655
601656/// State that is mutable during semantic analysis. This data is not used for
......@@ -876,11 +931,13 @@ pub const Key = union(enum) {
876931 func: Func,
877932 array_value: ArrayValue,
878933 opaque_value: Value,
934 tuple_value: TupleValue,
879935 // Types
880936 simple_type: SimpleType,
881937 function_type: FunctionType,
882938 struct_type: StructType,
883939 array_type: ArrayType,
940 tuple_type: TupleType,
884941 external_value: ExternalValue,
885942
886943 const Adapter = struct {
......@@ -946,6 +1003,14 @@ pub const Key = union(enum) {
9461003 }
9471004 };
9481005
1006 pub const TupleType = struct {
1007 items: []const Type,
1008
1009 pub fn hash(self: TupleType, hasher: *Hash) void {
1010 std.hash.autoHashStrat(hasher, self.items, .Deep);
1011 }
1012 };
1013
9491014 pub const ExternalValue = struct {
9501015 /// A list of strings to generate the property access
9511016 /// so `console.log` would be .{ "console", "log" }
......@@ -967,6 +1032,17 @@ pub const Key = union(enum) {
9671032 }
9681033 };
9691034
1035 pub const TupleValue = struct {
1036 /// This is the tuple type, not the item type
1037 type: Type,
1038 items: []const Value,
1039
1040 pub fn hash(self: TupleValue, hasher: *Hash) void {
1041 std.hash.autoHash(hasher, self.type);
1042 std.hash.autoHashStrat(hasher, self.items, .Deep);
1043 }
1044 };
1045
9701046 pub const Func = struct {
9711047 ty: Type,
9721048 owner_decl: DeclIndex,
......@@ -1008,6 +1084,8 @@ pub const Key = union(enum) {
10081084 .array_value,
10091085 .array_type,
10101086 .external_value,
1087 .tuple_type,
1088 .tuple_value,
10111089 => |x| {
10121090 var hasher = Hash.init(seed);
10131091 x.hash(&hasher);
......@@ -1047,7 +1125,7 @@ pub const Key = union(enum) {
10471125 return false;
10481126 },
10491127 .struct_type => {
1050 return false; // structs are nomial
1128 return false; // structs are nominal
10511129 },
10521130 .struct_value => |a_info| {
10531131 const b_info = b.struct_value;
......@@ -1066,6 +1144,15 @@ pub const Key = union(enum) {
10661144 const b_info = b.external_value;
10671145 return std.mem.eql(NullTerminatedString, a_info.key, b_info.key);
10681146 },
1147 .tuple_type => |a_info| {
1148 const b_info = b.tuple_type;
1149 return a_info.items.len == b_info.items.len and std.mem.eql(Type, a_info.items, b_info.items);
1150 },
1151 .tuple_value => |a_info| {
1152 const b_info = b.tuple_value;
1153 return a_info.type == b_info.type and
1154 std.mem.eql(Value, a_info.items, b_info.items);
1155 },
10691156 };
10701157 }
10711158};
......@@ -1336,6 +1423,19 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key {
13361423 .key = trail.readNullTerminatedStringSlice(payload.key_count).get(ip),
13371424 } };
13381425 },
1426 .tuple_type => {
1427 const payload: Tag.TupleType, var trail = data.decode(.tuple_type, item.tag).getTrail(ip);
1428 return .{ .tuple_type = .{
1429 .items = trail.readTypeSlice(payload.items_len).get(ip),
1430 } };
1431 },
1432 .tuple_value => {
1433 const payload: Tag.TupleValue, var trail = data.decode(.tuple_value, item.tag).getTrail(ip);
1434 return .{ .tuple_value = .{
1435 .type = payload.type,
1436 .items = trail.readValueSlice(payload.items_len).get(ip),
1437 } };
1438 },
13391439 };
13401440}
13411441
......@@ -1439,6 +1539,21 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value {
14391539 trail.writeSlice(s.key);
14401540 break :brk Item.encode(.external_value, extra);
14411541 },
1542 .tuple_type => |s| brk: {
1543 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.TupleType, .{
1544 .items_len = @intCast(s.items.len),
1545 }, s.items.len);
1546 trail.writeSlice(s.items);
1547 break :brk Item.encode(.tuple_type, extra);
1548 },
1549 .tuple_value => |s| brk: {
1550 const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.TupleValue, .{
1551 .type = s.type,
1552 .items_len = @intCast(s.items.len),
1553 }, s.items.len);
1554 trail.writeSlice(s.items);
1555 break :brk Item.encode(.tuple_value, extra);
1556 },
14421557 };
14431558 ip.items.appendAssumeCapacity(item);
14441559 const index: Value = @enumFromInt(ip.items.len - 1);
src/core/Parse.zig+296-258
......@@ -104,15 +104,216 @@ pub const ExpectedContext = enum {
104104 }
105105};
106106
107const Operator = enum(u8) {
108 add = @intFromEnum(Token.Tag.plus),
109 sub = @intFromEnum(Token.Tag.minus),
110 mul = @intFromEnum(Token.Tag.star),
111 div = @intFromEnum(Token.Tag.slash),
112 rem = @intFromEnum(Token.Tag.percent),
113 pow = @intFromEnum(Token.Tag.star_star),
114 @"and" = @intFromEnum(Token.Tag.and_and),
115 @"or" = @intFromEnum(Token.Tag.pipe_pipe),
116 bit_and = @intFromEnum(Token.Tag.@"and"),
117 bit_or = @intFromEnum(Token.Tag.pipe),
118 bit_xor = @intFromEnum(Token.Tag.caret),
119 shl = @intFromEnum(Token.Tag.lt_lt),
120 shr = @intFromEnum(Token.Tag.gt_gt),
121 eq = @intFromEnum(Token.Tag.equal_equal),
122 ne = @intFromEnum(Token.Tag.bang_equal),
123 lt = @intFromEnum(Token.Tag.lt),
124 le = @intFromEnum(Token.Tag.lt_equal),
125 gt = @intFromEnum(Token.Tag.gt),
126 ge = @intFromEnum(Token.Tag.gt_equal),
127 // Following operators are assignment operators
128 assign = @intFromEnum(Token.Tag.equal),
129 add_assign = @intFromEnum(Token.Tag.plus_equal),
130 sub_assign = @intFromEnum(Token.Tag.minus_equal),
131 mul_assign = @intFromEnum(Token.Tag.star_equal),
132 div_assign = @intFromEnum(Token.Tag.slash_equal),
133 rem_assign = @intFromEnum(Token.Tag.percent_equal),
134 pow_assign = @intFromEnum(Token.Tag.star_star_equal),
135 and_assign = @intFromEnum(Token.Tag.and_and_equal),
136 or_assign = @intFromEnum(Token.Tag.pipe_pipe_equal),
137 bit_and_assign = @intFromEnum(Token.Tag.and_equal),
138 bit_or_assign = @intFromEnum(Token.Tag.pipe_equal),
139 bit_xor_assign = @intFromEnum(Token.Tag.caret_equal),
140 shl_assign = @intFromEnum(Token.Tag.lt_lt_equal),
141 shr_assign = @intFromEnum(Token.Tag.gt_gt_equal),
142
143 const Direction = enum { ltr, rtl };
144
145 /// Only the binary operator levels are actually used,
146 /// but all are listed for reference.
147 const Level = enum {
148 /// e. e[] e()
149 accessor,
150 /// new
151 new,
152 /// ++e, --e, !e, ~e, +e, -e, typeof, void, delete
153 prefix,
154 /// **
155 exponentiation,
156 /// *, /, %
157 multiplicative,
158 /// +, -
159 additive,
160 /// <<, >>, >>>
161 bitwise_shift,
162 /// <, <=, >, >=
163 relational,
164 /// ==, !=
165 equality,
166 /// &
167 bit_and,
168 /// ^
169 bit_xor,
170 /// |
171 bit_or,
172 /// &&
173 logical_and,
174 /// ||, ??
175 logical_or,
176 /// =, +=, -=, *=, /=, %=, / <<=, >>=, >>>=, &=, ^=, |=
177 assign,
178 };
179
180 pub fn direction(op: Operator) Direction {
181 return switch (op) {
182 .pow => .rtl,
183
184 .assign,
185 .add_assign,
186 .sub_assign,
187 .mul_assign,
188 .div_assign,
189 .rem_assign,
190 .pow_assign,
191 .and_assign,
192 .or_assign,
193 .bit_and_assign,
194 .bit_or_assign,
195 .bit_xor_assign,
196 .shl_assign,
197 .shr_assign,
198 => .rtl,
199
200 else => .ltr,
201 };
202 }
203
204 pub fn level(op: Operator) Level {
205 return switch (op) {
206 .pow => .exponentiation,
207 .mul, .div, .rem => .multiplicative,
208 .add, .sub => .additive,
209 .shl, .shr => .bitwise_shift,
210 .lt, .le, .gt, .ge => .relational,
211 .eq, .ne => .equality,
212 .@"and" => .logical_and,
213 .@"or" => .logical_or,
214 .bit_and => .bit_and,
215 .bit_xor => .bit_xor,
216 .bit_or => .bit_or,
217 .assign,
218 .add_assign,
219 .sub_assign,
220 .mul_assign,
221 .div_assign,
222 .rem_assign,
223 .pow_assign,
224 .and_assign,
225 .or_assign,
226 .bit_and_assign,
227 .bit_or_assign,
228 .bit_xor_assign,
229 .shl_assign,
230 .shr_assign,
231 => .assign,
232 };
233 }
234
235 const lut = brk: {
236 const token_tags = std.enums.values(Token.Tag);
237 const op_tags = std.enums.values(Operator);
238
239 var is_operator_lut: [token_tags.len]bool = .{false} ** token_tags.len;
240 for (op_tags) |op| {
241 is_operator_lut[@intFromEnum(op)] = true;
242 }
243
244 var ast_tag_lut: [token_tags.len]Node.Tag = .{.root} ** token_tags.len;
245 for (op_tags) |op| {
246 ast_tag_lut[@intFromEnum(op)] = @field(Node.Tag, @tagName(op));
247 }
248
249 break :brk struct {
250 const is_operator = is_operator_lut;
251 const ast_tag = ast_tag_lut;
252 };
253 };
254
255 pub fn fromToken(tag: Token.Tag) ?Operator {
256 return if (lut.is_operator[@intFromEnum(tag)])
257 @enumFromInt(@intFromEnum(tag))
258 else
259 null;
260 }
261
262 pub fn astTag(op: Operator) Node.Tag {
263 const tag = lut.ast_tag[@intFromEnum(op)];
264 assert(tag != .root); // invalid operator or lut construction
265 return tag;
266 }
267
268 pub fn isAssign(op: Operator) bool {
269 return switch (op) {
270 .assign,
271 .add_assign,
272 .sub_assign,
273 .mul_assign,
274 .div_assign,
275 .rem_assign,
276 .pow_assign,
277 .and_assign,
278 .or_assign,
279 .bit_and_assign,
280 .bit_or_assign,
281 .bit_xor_assign,
282 .shl_assign,
283 .shr_assign,
284 => true,
285 else => false,
286 };
287 }
288};
289
290const ParseExprMode = enum {
291 /// Standard parsing
292 expression,
293 /// Statements allow assignment binary operators in addition to other expressions.
294 statement,
295 /// This bans struct initializations so that parsing stops at a '{'
296 /// Example: "if hello {" must not be parsed as a struct initialization.
297 preceding_block,
298};
299
300/// Some constructs are valid expressions as well as valid top-level
301/// declarations. Top level declarations must have associated names, but the
302/// anonymous versions of these must not have names.
303const ExprParseContext = enum {
304 declaration,
305 expression,
306};
307
308const TypePresence = enum {
309 types_optional,
310 types_required,
311};
312
107313/// When error.SyntaxError is returned, `p.err` is set to this as well as `p.pos`
108314/// When printing these, token list and Ast is not actually available, so full tokens
109315/// are stored in the errors.
110316pub const AstError = union(enum) {
111 // /// Failure during tokenization
112 // tokenization: struct {
113 // err: Tokenizer.TokenizeError,
114 // byte: ByteOffset,
115 // },
116317 /// Unexpected data, expected a token.
117318 unexpected_token: struct {
118319 expected: Token.Tag,
......@@ -134,23 +335,6 @@ pub const AstError = union(enum) {
134335
135336 pub fn build(err: AstError, ctx: *Report.MsgContext) !void {
136337 switch (err) {
137 // .tokenization => |data| {
138 // // TODO: consider making tokenizer emit AstError more directly,
139 // // so that it can just annotate start and ends
140 // try ctx.msg(switch (data.err) {
141 // error.UnterminatedString => .{ .codepoint_eol = data.byte },
142 // else => .{ .codepoint = data.byte },
143 // }, "{s}", .{switch (data.err) {
144 // error.OutOfMemory => unreachable,
145 // error.InvalidSyntax => "unexpected token",
146 // error.TrailingNumericSeparator => "trailing numeric separator",
147 // error.UnterminatedString => "unterminated string literal",
148 // error.InvalidEscapeSequence => "invalid escape sequence",
149 // error.InvalidEscapeCodepoint => "invalid escape codepoint",
150 // error.InvalidUtf8 => "file is not valid utf8",
151 // error.GitConflict => "git merge conflict encountered",
152 // }});
153 // },
154338 .unexpected_token => |data| {
155339 try ctx.msg(.{ .token_stored = data.got }, "expected {s}, but found {s}", .{
156340 data.expected.description(),
......@@ -230,7 +414,8 @@ fn parseModuleMembers(p: *Parse) Error!SubList {
230414 .kw_pub,
231415 => try p.scratch.append(p.gpa, try p.parseModuleDecl()),
232416
233 .kw_struct => try p.scratch.append(p.gpa, try p.parseStructDecl()),
417 .kw_struct => try p.scratch.append(p.gpa, try p.parseStructDecl(.declaration)),
418 .kw_tuple => try p.scratch.append(p.gpa, try p.parseStructDecl(.declaration)),
234419
235420 .id => if (p.isContextualKeyword("test")) {
236421 try p.scratch.append(p.gpa, try p.parseTestDecl());
......@@ -292,14 +477,6 @@ fn parseModuleDecl(p: *Parse) Error!NodeIndex {
292477 };
293478}
294479
295/// Some constructs are valid expressions as well as valid top-level
296/// declarations. Top level declarations must have associated names, but the
297/// anonymous versions of these must not have names.
298const ExprParseContext = enum {
299 declaration,
300 expression,
301};
302
303480fn parseFnDecl(p: *Parse) Error!NodeIndex {
304481 const trace = t.trace(@src());
305482 defer trace.end();
......@@ -339,8 +516,6 @@ fn parseFnDecl(p: *Parse) Error!NodeIndex {
339516 });
340517}
341518
342const TypePresence = enum { types_optional, types_required };
343
344519fn parseParamList(p: *Parse, types: TypePresence) Error!SubList {
345520 const trace = t.trace(@src());
346521 defer trace.end();
......@@ -390,13 +565,16 @@ fn parseParamDecl(p: *Parse, types: TypePresence) Error!NodeIndex {
390565 });
391566}
392567
393fn parseStructDecl(p: *Parse) Error!NodeIndex {
568fn parseStructDecl(p: *Parse, ctx: ExprParseContext) Error!NodeIndex {
394569 const trace = t.trace(@src());
395570 defer trace.end();
396571
397572 const main_token = p.assertToken(.kw_struct);
398573
399 _ = try p.expect(.id);
574 switch (ctx) {
575 .declaration => _ = try p.expect(.id),
576 else => {},
577 }
400578
401579 _ = try p.expect(.start_brace);
402580
......@@ -409,6 +587,28 @@ fn parseStructDecl(p: *Parse) Error!NodeIndex {
409587 });
410588}
411589
590fn parseTupleDecl(p: *Parse, ctx: ExprParseContext) Error!NodeIndex {
591 const trace = t.trace(@src());
592 defer trace.end();
593
594 const main_token = p.assertToken(.kw_tuple);
595
596 switch (ctx) {
597 .declaration => _ = try p.expect(.id),
598 else => {},
599 }
600
601 _ = try p.expect(.start_paren);
602
603 const fields = try p.parseExpressionList(.end_paren, .expression);
604
605 return try p.addNode(.{
606 .tag = .tuple_type,
607 .main_token = main_token,
608 .data = .{ .list = fields },
609 });
610}
611
412612fn parseTestDecl(p: *Parse) Error!NodeIndex {
413613 const trace = t.trace(@src());
414614 defer trace.end();
......@@ -447,9 +647,7 @@ fn parseStructFieldList(p: *Parse) Error!SubList {
447647 try p.scratch.append(p.gpa, try p.parseStructField());
448648
449649 switch (p.currentTag()) {
450 .comma => {
451 _ = p.nextToken();
452 },
650 .comma => _ = p.nextToken(),
453651 .end_brace => break,
454652 else => return p.failUnexpectedToken(.struct_field),
455653 }
......@@ -578,13 +776,13 @@ fn parseVarDecl(p: *Parse) Error!NodeIndex {
578776 _ = try p.expect(.id);
579777
580778 const data_type: OptionalNodeIndex = if (p.eatToken(.colon)) |_|
581 optionalNodeIndex(try p.tryParseExpression(.expression))
779 optionalNodeIndex(try p.parseExpressionOrFail(.expression))
582780 else
583781 .none;
584782
585783 _ = try p.expect(.equal);
586784
587 const data_init = try p.tryParseExpression(.expression);
785 const data_init = try p.parseExpressionOrFail(.expression);
588786
589787 _ = try p.expect(.semi);
590788
......@@ -619,204 +817,13 @@ fn isExpressionStart(p: *Parse) bool {
619817 .string,
620818 .tilde,
621819 .kw_fn,
820 .kw_struct,
821 .kw_tuple,
622822 => true,
623823 else => false,
624824 };
625825}
626826
627const Operator = enum(u8) {
628 add = @intFromEnum(Token.Tag.plus),
629 sub = @intFromEnum(Token.Tag.minus),
630 mul = @intFromEnum(Token.Tag.star),
631 div = @intFromEnum(Token.Tag.slash),
632 rem = @intFromEnum(Token.Tag.percent),
633 pow = @intFromEnum(Token.Tag.star_star),
634 @"and" = @intFromEnum(Token.Tag.and_and),
635 @"or" = @intFromEnum(Token.Tag.pipe_pipe),
636 bit_and = @intFromEnum(Token.Tag.@"and"),
637 bit_or = @intFromEnum(Token.Tag.pipe),
638 bit_xor = @intFromEnum(Token.Tag.caret),
639 shl = @intFromEnum(Token.Tag.lt_lt),
640 shr = @intFromEnum(Token.Tag.gt_gt),
641 eq = @intFromEnum(Token.Tag.equal_equal),
642 ne = @intFromEnum(Token.Tag.bang_equal),
643 lt = @intFromEnum(Token.Tag.lt),
644 le = @intFromEnum(Token.Tag.lt_equal),
645 gt = @intFromEnum(Token.Tag.gt),
646 ge = @intFromEnum(Token.Tag.gt_equal),
647 // Following operators are assignment operators
648 assign = @intFromEnum(Token.Tag.equal),
649 add_assign = @intFromEnum(Token.Tag.plus_equal),
650 sub_assign = @intFromEnum(Token.Tag.minus_equal),
651 mul_assign = @intFromEnum(Token.Tag.star_equal),
652 div_assign = @intFromEnum(Token.Tag.slash_equal),
653 rem_assign = @intFromEnum(Token.Tag.percent_equal),
654 pow_assign = @intFromEnum(Token.Tag.star_star_equal),
655 and_assign = @intFromEnum(Token.Tag.and_and_equal),
656 or_assign = @intFromEnum(Token.Tag.pipe_pipe_equal),
657 bit_and_assign = @intFromEnum(Token.Tag.and_equal),
658 bit_or_assign = @intFromEnum(Token.Tag.pipe_equal),
659 bit_xor_assign = @intFromEnum(Token.Tag.caret_equal),
660 shl_assign = @intFromEnum(Token.Tag.lt_lt_equal),
661 shr_assign = @intFromEnum(Token.Tag.gt_gt_equal),
662
663 const Direction = enum { ltr, rtl };
664
665 /// Only the binary operator levels are actually used,
666 /// but all are listed for reference.
667 const Level = enum {
668 /// e. e[] e()
669 accessor,
670 /// new
671 new,
672 /// ++e, --e, !e, ~e, +e, -e, typeof, void, delete
673 prefix,
674 /// **
675 exponentiation,
676 /// *, /, %
677 multiplicative,
678 /// +, -
679 additive,
680 /// <<, >>, >>>
681 bitwise_shift,
682 /// <, <=, >, >=
683 relational,
684 /// ==, !=
685 equality,
686 /// &
687 bit_and,
688 /// ^
689 bit_xor,
690 /// |
691 bit_or,
692 /// &&
693 logical_and,
694 /// ||, ??
695 logical_or,
696 /// =, +=, -=, *=, /=, %=, / <<=, >>=, >>>=, &=, ^=, |=
697 assign,
698 };
699
700 pub fn direction(op: Operator) Direction {
701 return switch (op) {
702 .pow => .rtl,
703
704 .assign,
705 .add_assign,
706 .sub_assign,
707 .mul_assign,
708 .div_assign,
709 .rem_assign,
710 .pow_assign,
711 .and_assign,
712 .or_assign,
713 .bit_and_assign,
714 .bit_or_assign,
715 .bit_xor_assign,
716 .shl_assign,
717 .shr_assign,
718 => .rtl,
719
720 else => .ltr,
721 };
722 }
723
724 pub fn level(op: Operator) Level {
725 return switch (op) {
726 .pow => .exponentiation,
727 .mul, .div, .rem => .multiplicative,
728 .add, .sub => .additive,
729 .shl, .shr => .bitwise_shift,
730 .lt, .le, .gt, .ge => .relational,
731 .eq, .ne => .equality,
732 .@"and" => .logical_and,
733 .@"or" => .logical_or,
734 .bit_and => .bit_and,
735 .bit_xor => .bit_xor,
736 .bit_or => .bit_or,
737 .assign,
738 .add_assign,
739 .sub_assign,
740 .mul_assign,
741 .div_assign,
742 .rem_assign,
743 .pow_assign,
744 .and_assign,
745 .or_assign,
746 .bit_and_assign,
747 .bit_or_assign,
748 .bit_xor_assign,
749 .shl_assign,
750 .shr_assign,
751 => .assign,
752 };
753 }
754
755 const lut = brk: {
756 const token_tags = std.enums.values(Token.Tag);
757 const op_tags = std.enums.values(Operator);
758
759 var is_operator_lut: [token_tags.len]bool = .{false} ** token_tags.len;
760 for (op_tags) |op| {
761 is_operator_lut[@intFromEnum(op)] = true;
762 }
763
764 var ast_tag_lut: [token_tags.len]Node.Tag = .{.root} ** token_tags.len;
765 for (op_tags) |op| {
766 ast_tag_lut[@intFromEnum(op)] = @field(Node.Tag, @tagName(op));
767 }
768
769 break :brk struct {
770 const is_operator = is_operator_lut;
771 const ast_tag = ast_tag_lut;
772 };
773 };
774
775 pub fn fromToken(tag: Token.Tag) ?Operator {
776 return if (lut.is_operator[@intFromEnum(tag)])
777 @enumFromInt(@intFromEnum(tag))
778 else
779 null;
780 }
781
782 pub fn astTag(op: Operator) Node.Tag {
783 const tag = lut.ast_tag[@intFromEnum(op)];
784 assert(tag != .root); // invalid operator or lut construction
785 return tag;
786 }
787
788 pub fn isAssign(op: Operator) bool {
789 return switch (op) {
790 .assign,
791 .add_assign,
792 .sub_assign,
793 .mul_assign,
794 .div_assign,
795 .rem_assign,
796 .pow_assign,
797 .and_assign,
798 .or_assign,
799 .bit_and_assign,
800 .bit_or_assign,
801 .bit_xor_assign,
802 .shl_assign,
803 .shr_assign,
804 => true,
805 else => false,
806 };
807 }
808};
809
810const ParseExprMode = enum {
811 /// Standard parsing
812 expression,
813 /// Statements allow assignment binary operators in addition to other expressions.
814 statement,
815 /// This bans struct initializations so that parsing stops at a '{'
816 /// Example: "if hello {" must not be parsed as a struct initialization.
817 preceding_block,
818};
819
820827fn parseExpression(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
821828 const trace = t.trace(@src());
822829 defer trace.end();
......@@ -831,8 +838,13 @@ fn parseExpression(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
831838
832839 // These unary operators are greedy, so handle them first.
833840 switch (p.currentTag()) {
834 .kw_return => return p.parseReturn(),
835 .kw_break => return p.parseBreak(),
841 .kw_return => return p.parseReturn(mode),
842 .kw_break => return p.parseBreak(mode),
843
844 .kw_assert => return p.parseGreedyUnary(.assert, mode),
845 .kw_comptime => return p.parseGreedyUnary(.@"comptime", mode),
846 .kw_pure => return p.parseGreedyUnary(.pure, mode),
847
836848 else => {},
837849 }
838850
......@@ -846,7 +858,7 @@ fn parseExpression(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
846858 return expr;
847859}
848860
849fn tryParseExpression(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
861fn parseExpressionOrFail(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
850862 return if (p.isExpressionStart())
851863 p.parseExpression(mode)
852864 else
......@@ -858,7 +870,6 @@ fn parseExpressionPart(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
858870 defer trace.end();
859871
860872 var expr = switch (p.currentTag()) {
861 // Literals
862873 .id => if (p.nextTag() == .colon)
863874 try p.parseLabelExpression()
864875 else
......@@ -867,24 +878,27 @@ fn parseExpressionPart(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
867878 .number_float => try p.blankNode(.number_float),
868879 .string => try p.blankNode(.string),
869880
870 // Complex expressions
871881 .builtin_id => try p.parseBuiltinCall(),
872 .dot => try p.parseAnonInstantiation(),
873 .kw_break => try p.parseBreak(),
882 .dot => try p.parseAnonStructInit(),
874883 .kw_fn => try p.parseAnonFunction(),
875884 .kw_if => try p.parseIf(),
876 .kw_return => try p.parseReturn(),
885 .kw_tuple => try p.parseTupleType(),
886
877887 .start_brace => try p.parseBlock(),
878888 .start_bracket => try p.parseArrayValueOrType(mode),
879 .start_paren => try p.parseTupleType(),
889 .start_paren => try p.parseTupleInit(),
890
891 .kw_struct => try p.parseStructDecl(.expression),
892
893 .kw_return => return p.parseReturn(mode),
894 .kw_break => return p.parseBreak(mode),
895 .kw_assert => return p.parseGreedyUnary(.assert, mode),
896 .kw_comptime => return p.parseGreedyUnary(.@"comptime", mode),
897 .kw_pure => return p.parseGreedyUnary(.pure, mode),
880898
881 // Unary operators
882899 inline .bang,
883900 .tilde,
884901 .minus,
885 .kw_comptime,
886 .kw_pure,
887 .kw_assert,
888902 => |tag| unary: {
889903 const main_token = p.nextToken();
890904 const expr = try p.parseExpressionPart(mode);
......@@ -955,7 +969,7 @@ fn parseExpressionPart(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
955969 return p.fail(.{ .array_type_flipped_hint = p.fullToken(p.pos) });
956970 }
957971
958 const index = try p.tryParseExpression(.expression);
972 const index = try p.parseExpressionOrFail(.expression);
959973
960974 _ = try p.expect(.end_bracket);
961975
......@@ -1020,14 +1034,14 @@ fn parseBinarySuffix(p: *Parse, lhs: NodeIndex, op: Operator, mode: ParseExprMod
10201034 });
10211035}
10221036
1023fn parseReturn(p: *Parse) Error!NodeIndex {
1037fn parseReturn(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
10241038 const trace = t.trace(@src());
10251039 defer trace.end();
10261040
10271041 const main_token = p.assertToken(.kw_return);
10281042
10291043 const expr = if (p.isExpressionStart())
1030 try p.parseExpression(.expression)
1044 try p.parseExpression(mode)
10311045 else
10321046 null;
10331047
......@@ -1040,7 +1054,7 @@ fn parseReturn(p: *Parse) Error!NodeIndex {
10401054 });
10411055}
10421056
1043fn parseBreak(p: *Parse) Error!NodeIndex {
1057fn parseBreak(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
10441058 const trace = t.trace(@src());
10451059 defer trace.end();
10461060
......@@ -1052,7 +1066,7 @@ fn parseBreak(p: *Parse) Error!NodeIndex {
10521066 null;
10531067
10541068 const expr = if (p.isExpressionStart())
1055 try p.parseExpression(.expression)
1069 try p.parseExpression(mode)
10561070 else
10571071 null;
10581072
......@@ -1066,6 +1080,23 @@ fn parseBreak(p: *Parse) Error!NodeIndex {
10661080 });
10671081}
10681082
1083fn parseGreedyUnary(p: *Parse, tag: Node.Tag, mode: ParseExprMode) Error!NodeIndex {
1084 const trace = t.trace(@src());
1085 defer trace.end();
1086
1087 const main_token = p.nextToken();
1088
1089 const expr = try p.parseExpressionOrFail(mode);
1090
1091 return try p.addNode(.{
1092 .tag = tag,
1093 .main_token = main_token,
1094 .data = .{ .un = .{
1095 .expr = expr,
1096 } },
1097 });
1098}
1099
10691100fn parseBuiltinCall(p: *Parse) Error!NodeIndex {
10701101 const trace = t.trace(@src());
10711102 defer trace.end();
......@@ -1083,11 +1114,7 @@ fn parseBuiltinCall(p: *Parse) Error!NodeIndex {
10831114 });
10841115}
10851116
1086fn parseExpressionList(
1087 p: *Parse,
1088 comptime end_token: Token.Tag,
1089 comptime fail_context: ExpectedContext,
1090) Error!SubList {
1117fn parseExpressionList(p: *Parse, comptime end_token: Token.Tag, fail_context: ExpectedContext) Error!SubList {
10911118 const trace = t.trace(@src());
10921119 defer trace.end();
10931120
......@@ -1161,7 +1188,7 @@ fn parseElseValue(p: *Parse) Error!NodeIndex {
11611188 };
11621189}
11631190
1164fn parseAnonInstantiation(p: *Parse) Error!NodeIndex {
1191fn parseAnonStructInit(p: *Parse) Error!NodeIndex {
11651192 const trace = t.trace(@src());
11661193 defer trace.end();
11671194
......@@ -1272,9 +1299,20 @@ fn parseArrayValueOrType(p: *Parse, mode: ParseExprMode) Error!NodeIndex {
12721299 });
12731300}
12741301
1275fn parseTupleType(p: *Parse) Error!NodeIndex {
1302fn parseTupleInit(p: *Parse) Error!NodeIndex {
12761303 const main_token = p.assertToken(.start_paren);
12771304 const list = try p.parseExpressionList(.end_paren, .expression);
1305 return p.addNode(.{
1306 .tag = .tuple_init,
1307 .main_token = main_token,
1308 .data = .{ .list = list },
1309 });
1310}
1311
1312fn parseTupleType(p: *Parse) Error!NodeIndex {
1313 const main_token = p.assertToken(.kw_tuple);
1314 _ = try p.expect(.start_paren);
1315 const list = try p.parseExpressionList(.end_paren, .expression);
12781316 return p.addNode(.{
12791317 .tag = .tuple_type,
12801318 .main_token = main_token,
src/core/Sema.zig+8-7
......@@ -1615,6 +1615,14 @@ fn ensureValueRuntime(s: *Sema, src: LazyNode, ref: Air.Inst.Ref) Error!Air.Inst
16151615 .value => |v| {
16161616 const ty = v.typeOf(s.ip);
16171617 switch (ty) {
1618 // Allowed at runtime
1619 .bool,
1620 .float,
1621 .int32,
1622 .string,
1623 .void,
1624 .empty_tuple,
1625 => {},
16181626 .numeric_literal => {
16191627 const float = v.toFloat(s.ip) orelse unreachable;
16201628
......@@ -1649,13 +1657,6 @@ fn ensureValueRuntime(s: *Sema, src: LazyNode, ref: Air.Inst.Ref) Error!Air.Inst
16491657 .type = ty,
16501658 }),
16511659 .@"opaque" => @panic("TODO: represent comptime-known opaques better"),
1652 // Allowed at runtime
1653 .bool,
1654 .float,
1655 .int32,
1656 .string,
1657 .void,
1658 => {},
16591660 _ => if (!ty.hasPossibleRepresentation(s.ip)) {
16601661 return s.fail(.runtime_incompatible_type, .{
16611662 .src = src,
src/core/Teg.Dump.zig+18
......@@ -319,6 +319,24 @@ const State = struct {
319319 if (data.type_hint != .none)
320320 try writer.writeAll(")");
321321 },
322 .tuple_type => {
323 const data: Teg.TupleType = teg.instPayload(.tuple_type, inst);
324
325 try writer.writeAll("(");
326 try s.dumpRefMarkerList(writer, data.items.slice(teg), '[', ']');
327 try writer.writeAll(")");
328 },
329 .tuple_init => {
330 const data: Teg.TupleInit = teg.instPayload(.tuple_init, inst);
331
332 try writer.writeAll("(");
333 if (data.type_hint.unwrap()) |type_hint| {
334 try s.dumpRef(writer, type_hint);
335 try writer.writeAll(", ");
336 }
337 try s.dumpRefMarkerList(writer, data.items.slice(teg), '[', ']');
338 try writer.writeAll(")");
339 },
322340 .result_type_argument => {
323341 const data: Teg.ResultTypeArgument = teg.instData(.result_type_argument, inst);
324342
src/core/Teg.zig+37-2
......@@ -75,6 +75,9 @@ pub const Tag = enum(u8) {
7575 struct_init,
7676 array_init,
7777
78 tuple_init,
79 tuple_type,
80
7881 add,
7982 sub,
8083 mul,
......@@ -136,6 +139,8 @@ pub const Tag = enum(u8) {
136139 .struct_decl => PlNode(StructDecl),
137140 .struct_init => PlNode(StructInit),
138141 .array_init => PlNode(ArrayInit),
142 .tuple_type => PlNode(TupleType),
143 .tuple_init => PlNode(TupleInit),
139144 .func => PlNode(Func),
140145
141146 .load_decl => StrNode,
......@@ -230,7 +235,7 @@ pub const Inst = struct {
230235 main_module_inst = 0,
231236 _,
232237
233 pub const static_len = @intFromEnum(Ref.empty_array) + 1;
238 pub const static_len = @intFromEnum(Ref.empty_tuple) + 1;
234239
235240 pub fn toRef(i: Index) Inst.Ref {
236241 return @enumFromInt(static_len + @intFromEnum(i));
......@@ -269,6 +274,7 @@ pub const Inst = struct {
269274 numeric_literal_type,
270275 numeric_literal_array_type,
271276 never_array_type,
277 empty_tuple_type,
272278
273279 void,
274280 bool_true,
......@@ -278,7 +284,7 @@ pub const Inst = struct {
278284 nan,
279285 empty_string,
280286 empty_array,
281
287 empty_tuple,
282288 _,
283289
284290 pub const Decoded = union(enum) {
......@@ -423,6 +429,20 @@ pub const ArrayInit = struct {
423429 list: RefList,
424430};
425431
432pub const TupleType = struct {
433 /// The items in the tuple
434 items: RefList,
435};
436
437pub const TupleInit = struct {
438 /// Optionally provide a result type for more reliable type coercion.
439 /// If specified, this must be an array type. Otherwise, the first
440 /// element's type is used.
441 type_hint: Inst.Ref.Optional,
442 /// The items in the tuple
443 items: RefList,
444};
445
426446pub const Decl = struct {
427447 name: NullTerminatedString,
428448 hash: Cache.BinDigest,
......@@ -697,6 +717,8 @@ pub fn writeToHasher(
697717 .struct_decl,
698718 .struct_init,
699719 .array_init,
720 .tuple_init,
721 .tuple_type,
700722 .func,
701723 .store_decl,
702724 .store_field,
......@@ -902,6 +924,19 @@ fn writePlNodeInnerToHasher(
902924 hasher.add(isolatedIndexValue(decl_index, data.body));
903925 hasher.add(data.instruction_count);
904926 },
927 TupleType => {
928 hasher.add(data.items.len);
929 for (data.items.slice(teg)) |item| {
930 hasher.add(isolatedRefValue(decl_index, item));
931 }
932 },
933 TupleInit => {
934 if (data.type_hint.unwrap()) |type_hint|
935 hasher.add(isolatedRefValue(decl_index, type_hint))
936 else
937 hasher.add(@as(i32, std.math.maxInt(i32)));
938 writeRefListToHasher(hasher, decl_index, data.items.slice(teg));
939 },
905940 else => @compileError("hash not implemented for " ++ @typeName(T)),
906941 }
907942}
src/core/Tokenizer.zig+1
......@@ -75,6 +75,7 @@ pub const Token = struct {
7575 kw_return,
7676 kw_struct,
7777 kw_trait,
78 kw_tuple,
7879 kw_var,
7980 kw_while,
8081 // sort-lines: end
src/core/Transform.zig+32
......@@ -903,6 +903,7 @@ fn transformExpression(
903903 switch (node_tag) {
904904 .root,
905905 .param_decl,
906 .struct_field,
906907 => unreachable, // not an expression
907908
908909 .id => {
......@@ -1520,6 +1521,37 @@ fn transformExpression(
15201521 });
15211522 },
15221523
1524 .tuple_init => {
1525 const tuple_init = t.ast.nodeData(node).list;
1526
1527 const items = try t.transformExpressionList(ctx, .none, tuple_init.slice(&t.ast)) orelse return null;
1528
1529 if (items.len == 0) {
1530 return .empty_tuple;
1531 }
1532
1533 return try t.addRef(.tuple_init, .{
1534 .src_node = ctx.nodeOffset(node),
1535 .extra_index = try t.extra.append(t.gpa, Teg.TupleInit, .{
1536 .type_hint = .none,
1537 .items = items,
1538 }),
1539 });
1540 },
1541
1542 .tuple_type => {
1543 const tuple_type = t.ast.nodeData(node).list;
1544
1545 const items = try t.transformExpressionList(ctx, .none, tuple_type.slice(&t.ast)) orelse return null;
1546
1547 return try t.addRef(.tuple_type, .{
1548 .src_node = ctx.nodeOffset(node),
1549 .extra_index = try t.extra.append(t.gpa, Teg.TupleType, .{
1550 .items = items,
1551 }),
1552 });
1553 },
1554
15231555 inline .fn_decl, .fn_expr => |tag| {
15241556 const data = switch (tag) {
15251557 .fn_decl => t.ast.fullFnDecl(node),
src/core/js/NodeGen.zig+2
......@@ -557,6 +557,7 @@ fn valueToExpression(c: *NodeGen, v: Value) !Node.Index {
557557 .simple_type,
558558 .struct_type,
559559 .array_type,
560 .tuple_type,
560561 => unreachable, // Type values are not allowed here
561562
562563 .int32,
......@@ -566,6 +567,7 @@ fn valueToExpression(c: *NodeGen, v: Value) !Node.Index {
566567 .simple_value,
567568 .struct_value,
568569 .array_value,
570 .tuple_value,
569571 => return try c.add(.plain_value, .{ .value = v }),
570572
571573 .external_value => {
test/behavior/tuple created+14
......@@ -0,0 +1,14 @@
1let assertEqual = @extern("assertEqual");
2
3fn hello() -> tuple (int, float) {
4 (5, 2.5)
5}
6
7fn main {
8 let x = hello();
9 assertEqual(x.0, 5);
10 assertEqual(x.1, 2.5);
11}
12
13fn f(a: float) -> float { a }
14fn i(a: int) -> int { a }