Merge remote-tracking branch 'origin/main' into enforce-literal-sizes

This commit is contained in:
Richard Feldman 2025-06-26 18:06:48 -04:00
commit a9fe175a62
No known key found for this signature in database
46 changed files with 2740 additions and 226 deletions

View file

@ -3928,78 +3928,21 @@ fn write_debug_error_type_help(error_type: ErrorType, buf: &mut String, parens:
}
EffectfulFunc => buf.push_str("EffectfulFunc"),
Type(symbol, arguments) => {
// Special handling for Num types with concrete integer/float types
match (symbol, arguments.as_slice()) {
(Symbol::NUM_INTEGER, [Type(inner_symbol, _)]) => {
match inner_symbol {
&Symbol::NUM_UNSIGNED8 => buf.push_str("U8"),
&Symbol::NUM_UNSIGNED16 => buf.push_str("U16"),
&Symbol::NUM_UNSIGNED32 => buf.push_str("U32"),
&Symbol::NUM_UNSIGNED64 => buf.push_str("U64"),
&Symbol::NUM_UNSIGNED128 => buf.push_str("U128"),
&Symbol::NUM_SIGNED8 => buf.push_str("I8"),
&Symbol::NUM_SIGNED16 => buf.push_str("I16"),
&Symbol::NUM_SIGNED32 => buf.push_str("I32"),
&Symbol::NUM_SIGNED64 => buf.push_str("I64"),
&Symbol::NUM_SIGNED128 => buf.push_str("I128"),
_ => {
// Fall back to Num(Integer(...))
write!(buf, "{symbol:?}").unwrap();
for arg in arguments {
buf.push(' ');
write_debug_error_type_help(arg, buf, Parens::InTypeParam);
}
}
}
}
(Symbol::NUM_INTEGER, [arg]) => {
// Integer with a variable, print as Int(a)
buf.push_str("Int");
buf.push('(');
write_debug_error_type_help(arg.clone(), buf, Parens::InTypeParam);
buf.push(')');
}
(Symbol::NUM_FLOATINGPOINT, [Type(inner_symbol, _)]) => {
match inner_symbol {
&Symbol::NUM_BINARY32 => buf.push_str("F32"),
&Symbol::NUM_BINARY64 => buf.push_str("F64"),
&Symbol::NUM_DECIMAL => buf.push_str("Dec"),
_ => {
// Fall back to Num(FloatingPoint(...))
write!(buf, "{symbol:?}").unwrap();
for arg in arguments {
buf.push(' ');
write_debug_error_type_help(arg, buf, Parens::InTypeParam);
}
}
}
}
(Symbol::NUM_FLOATINGPOINT, [arg]) => {
// FloatingPoint with a variable, print as Frac(a)
buf.push_str("Frac");
buf.push('(');
write_debug_error_type_help(arg.clone(), buf, Parens::InTypeParam);
buf.push(')');
}
_ => {
// Default formatting
let write_parens = parens == Parens::InTypeParam && !arguments.is_empty();
let write_parens = parens == Parens::InTypeParam && !arguments.is_empty();
if write_parens {
buf.push('(');
}
write!(buf, "{symbol:?}").unwrap();
if write_parens {
buf.push('(');
}
write!(buf, "{symbol:?}").unwrap();
for arg in arguments {
buf.push(' ');
for arg in arguments {
buf.push(' ');
write_debug_error_type_help(arg, buf, Parens::InTypeParam);
}
write_debug_error_type_help(arg, buf, Parens::InTypeParam);
}
if write_parens {
buf.push(')');
}
}
if write_parens {
buf.push(')');
}
}
Alias(Symbol::NUM_NUM, mut arguments, _actual, _) => {
@ -4008,76 +3951,11 @@ fn write_debug_error_type_help(error_type: ErrorType, buf: &mut String, parens:
let argument = arguments.remove(0);
match argument {
Type(Symbol::NUM_INTEGER, args) => {
if args.is_empty() {
buf.push_str("Int");
} else {
// Check if it's a concrete integer type
match &args[0] {
Type(inner_symbol, _) => match inner_symbol {
&Symbol::NUM_UNSIGNED8 => buf.push_str("U8"),
&Symbol::NUM_UNSIGNED16 => buf.push_str("U16"),
&Symbol::NUM_UNSIGNED32 => buf.push_str("U32"),
&Symbol::NUM_UNSIGNED64 => buf.push_str("U64"),
&Symbol::NUM_UNSIGNED128 => buf.push_str("U128"),
&Symbol::NUM_SIGNED8 => buf.push_str("I8"),
&Symbol::NUM_SIGNED16 => buf.push_str("I16"),
&Symbol::NUM_SIGNED32 => buf.push_str("I32"),
&Symbol::NUM_SIGNED64 => buf.push_str("I64"),
&Symbol::NUM_SIGNED128 => buf.push_str("I128"),
_ => {
buf.push_str("Int(");
write_debug_error_type_help(
args[0].clone(),
buf,
Parens::InTypeParam,
);
buf.push(')');
}
},
_ => {
buf.push_str("Int(");
write_debug_error_type_help(
args[0].clone(),
buf,
Parens::InTypeParam,
);
buf.push(')');
}
}
}
Type(Symbol::NUM_INTEGER, _) => {
buf.push_str("Int");
}
Type(Symbol::NUM_FLOATINGPOINT, args) => {
if args.is_empty() {
buf.push_str("F64");
} else {
// Check if it's a concrete float type
match &args[0] {
Type(inner_symbol, _) => match inner_symbol {
&Symbol::NUM_BINARY32 => buf.push_str("F32"),
&Symbol::NUM_BINARY64 => buf.push_str("F64"),
&Symbol::NUM_DECIMAL => buf.push_str("Dec"),
_ => {
buf.push_str("Frac(");
write_debug_error_type_help(
args[0].clone(),
buf,
Parens::InTypeParam,
);
buf.push(')');
}
},
_ => {
buf.push_str("Frac(");
write_debug_error_type_help(
args[0].clone(),
buf,
Parens::InTypeParam,
);
buf.push(')');
}
}
}
Type(Symbol::NUM_FLOATINGPOINT, _) => {
buf.push_str("F64");
}
other => {
let write_parens = parens == Parens::InTypeParam;

View file

@ -260,3 +260,80 @@ test "readCacheInto after writeToCache" {
const data_bytes = read_buffer[@sizeOf(CacheHeader)..expected_total_bytes];
try std.testing.expectEqualStrings(test_data, data_bytes);
}
// TODO expand this test gradually to more of our Can IR until
// we can round-trip a whole type-checked module from cache
test "NodeStore cache round-trip" {
const NodeStore = @import("check/canonicalize/NodeStore.zig");
const Node = @import("check/canonicalize/Node.zig");
var tmp_dir = std.testing.tmpDir(.{});
defer tmp_dir.cleanup();
var abs_path_buf: [std.fs.max_path_bytes]u8 = undefined;
const abs_cache_dir = try tmp_dir.dir.realpath(".", &abs_path_buf);
const fs = Filesystem.default();
const allocator = std.testing.allocator;
const test_hash = "0123456789abcdef";
var store = NodeStore.initCapacity(allocator, 10);
defer store.deinit();
const expr_node = Node{
.data_1 = 42,
.data_2 = 100,
.data_3 = 200,
.region = .{ .start = .{ .offset = 0 }, .end = .{ .offset = 10 } },
.tag = .expr_string,
};
const expr_idx = store.nodes.append(store.gpa, expr_node);
try store.extra_data.append(store.gpa, 1234);
try store.extra_data.append(store.gpa, 5678);
const store_size = store.serializedSize();
const store_buffer = try allocator.alignedAlloc(u8, @alignOf(Node), store_size);
defer allocator.free(store_buffer);
const serialized = try store.serializeInto(store_buffer);
try std.testing.expectEqual(store_size, serialized.len);
const header_size = @sizeOf(CacheHeader);
const aligned_header_size = std.mem.alignForward(usize, header_size, @alignOf(Node));
const total_size = aligned_header_size + store_size;
var write_buffer = try allocator.alignedAlloc(u8, @alignOf(Node), total_size);
defer allocator.free(write_buffer);
const header = @as(*CacheHeader, @ptrCast(write_buffer.ptr));
header.* = .{
.total_cached_bytes = @intCast(store_size),
};
@memcpy(write_buffer[aligned_header_size..total_size], serialized);
try writeToCache(abs_cache_dir, test_hash, header, fs, allocator);
var read_buffer: [4096]u8 align(@alignOf(Node)) = undefined;
const bytes_read = try readCacheInto(&read_buffer, abs_cache_dir, test_hash, fs, allocator);
const parsed_header = try CacheHeader.initFromBytes(read_buffer[0..bytes_read]);
try std.testing.expectEqual(header.total_cached_bytes, parsed_header.total_cached_bytes);
const data_start = std.mem.alignForward(usize, @sizeOf(CacheHeader), @alignOf(Node));
const data_end = data_start + parsed_header.total_cached_bytes;
var restored_store = try NodeStore.deserializeFrom(@as([]align(@alignOf(Node)) const u8, @alignCast(read_buffer[data_start..data_end])), allocator);
defer restored_store.deinit();
try std.testing.expectEqual(store.nodes.len(), restored_store.nodes.len());
try std.testing.expectEqual(store.extra_data.items.len, restored_store.extra_data.items.len);
const restored_node = restored_store.nodes.get(expr_idx);
try std.testing.expectEqual(expr_node.data_1, restored_node.data_1);
try std.testing.expectEqual(expr_node.data_2, restored_node.data_2);
try std.testing.expectEqual(expr_node.data_3, restored_node.data_3);
try std.testing.expectEqual(expr_node.tag, restored_node.tag);
try std.testing.expectEqual(@as(u32, 1234), restored_store.extra_data.items[0]);
try std.testing.expectEqual(@as(u32, 5678), restored_store.extra_data.items[1]);
}

View file

@ -1369,9 +1369,20 @@ pub fn canonicalize_expr(
.OpPlus => .add,
.OpBinaryMinus => .sub,
.OpStar => .mul,
.OpSlash => .div,
.OpPercent => .rem,
.OpLessThan => .lt,
.OpGreaterThan => .gt,
.OpLessThanOrEq => .le,
.OpGreaterThanOrEq => .ge,
.OpEquals => .eq,
.OpNotEquals => .ne,
.OpCaret => .pow,
.OpDoubleSlash => .div_trunc,
.OpAnd => .@"and",
.OpOr => .@"or",
.OpPizza => .pipe_forward,
.OpDoubleQuestion => .null_coalesce,
else => {
// Unknown operator
const feature = self.can_ir.env.strings.insert(self.can_ir.env.gpa, "binop");
@ -1923,6 +1934,14 @@ fn canonicalize_pattern(
} });
return pattern_idx;
},
.as => |_| {
const feature = self.can_ir.env.strings.insert(self.can_ir.env.gpa, "canonicalize alternatives pattern");
const pattern_idx = self.can_ir.pushMalformed(CIR.Pattern.Idx, CIR.Diagnostic{ .not_implemented = .{
.feature = feature,
.region = Region.zero(),
} });
return pattern_idx;
},
.malformed => |malformed| {
// We won't touch this since it's already a parse error.
_ = malformed;

View file

@ -1230,6 +1230,12 @@ pub const Expr = union(enum) {
ge,
eq,
ne,
pow,
div_trunc,
@"and",
@"or",
pipe_forward,
null_coalesce,
};
pub fn init(op: Op, lhs: Expr.Idx, rhs: Expr.Idx, region: Region) Binop {

View file

@ -1972,3 +1972,86 @@ pub fn addTypeVarSlot(store: *NodeStore, parent_node_idx: Node.Idx, region: base
});
return @enumFromInt(@intFromEnum(nid));
}
/// Calculate the size needed to serialize this NodeStore
pub fn serializedSize(self: *const NodeStore) usize {
// We only serialize nodes and extra_data (the scratch arrays are transient)
return self.nodes.serializedSize() +
@sizeOf(u32) + // extra_data length
(self.extra_data.items.len * @sizeOf(u32));
}
/// Serialize this NodeStore into the provided buffer
/// Buffer must be at least serializedSize() bytes and properly aligned
pub fn serializeInto(self: *const NodeStore, buffer: []align(@alignOf(Node)) u8) ![]u8 {
const size = self.serializedSize();
if (buffer.len < size) return error.BufferTooSmall;
var offset: usize = 0;
// Serialize nodes - cast to proper alignment for Node type
const nodes_buffer = @as([]align(@alignOf(Node)) u8, @alignCast(buffer[offset..]));
const nodes_slice = try self.nodes.serializeInto(nodes_buffer);
offset += nodes_slice.len;
// Serialize extra_data length
const extra_len_ptr = @as(*u32, @ptrCast(@alignCast(buffer.ptr + offset)));
extra_len_ptr.* = @intCast(self.extra_data.items.len);
offset += @sizeOf(u32);
// Serialize extra_data items
if (self.extra_data.items.len > 0) {
const extra_ptr = @as([*]u32, @ptrCast(@alignCast(buffer.ptr + offset)));
@memcpy(extra_ptr, self.extra_data.items);
offset += self.extra_data.items.len * @sizeOf(u32);
}
return buffer[0..offset];
}
/// Deserialize a NodeStore from the provided buffer
pub fn deserializeFrom(buffer: []align(@alignOf(Node)) const u8, allocator: std.mem.Allocator) !NodeStore {
var offset: usize = 0;
// Deserialize nodes - cast to proper alignment for Node type
const nodes_buffer = @as([]align(@alignOf(Node)) const u8, @alignCast(buffer[offset..]));
const nodes = try Node.List.deserializeFrom(nodes_buffer, allocator);
offset += nodes.serializedSize();
// Deserialize extra_data length
if (buffer.len < offset + @sizeOf(u32)) return error.BufferTooSmall;
const extra_len = @as(*const u32, @ptrCast(@alignCast(buffer.ptr + offset))).*;
offset += @sizeOf(u32);
// Deserialize extra_data items
var extra_data = try std.ArrayListUnmanaged(u32).initCapacity(allocator, extra_len);
if (extra_len > 0) {
const remaining = buffer.len - offset;
const expected = extra_len * @sizeOf(u32);
if (remaining < expected) return error.BufferTooSmall;
const extra_ptr = @as([*]const u32, @ptrCast(@alignCast(buffer.ptr + offset)));
extra_data.appendSliceAssumeCapacity(extra_ptr[0..extra_len]);
}
// Create NodeStore with empty scratch arrays
return NodeStore{
.gpa = allocator,
.nodes = nodes,
.extra_data = extra_data,
// All scratch arrays start empty
.scratch_statements = base.Scratch(CIR.Statement.Idx){ .items = .{} },
.scratch_exprs = base.Scratch(CIR.Expr.Idx){ .items = .{} },
.scratch_record_fields = base.Scratch(CIR.RecordField.Idx){ .items = .{} },
.scratch_when_branches = base.Scratch(CIR.WhenBranch.Idx){ .items = .{} },
.scratch_if_branches = base.Scratch(CIR.IfBranch.Idx){ .items = .{} },
.scratch_where_clauses = base.Scratch(CIR.WhereClause.Idx){ .items = .{} },
.scratch_patterns = base.Scratch(CIR.Pattern.Idx){ .items = .{} },
.scratch_pattern_record_fields = base.Scratch(CIR.PatternRecordField.Idx){ .items = .{} },
.scratch_type_annos = base.Scratch(CIR.TypeAnno.Idx){ .items = .{} },
.scratch_anno_record_fields = base.Scratch(CIR.AnnoRecordField.Idx){ .items = .{} },
.scratch_exposed_items = base.Scratch(CIR.ExposedItem.Idx){ .items = .{} },
.scratch_defs = base.Scratch(CIR.Def.Idx){ .items = .{} },
.scratch_diagnostics = base.Scratch(CIR.Diagnostic.Idx){ .items = .{} },
};
}

View file

@ -1,3 +1,5 @@
//! TODO module doc comment here
const std = @import("std");
const testing = std.testing;
const base = @import("../../../base.zig");

View file

@ -1,3 +1,5 @@
//! TODO module doc comment here
const std = @import("std");
const testing = std.testing;
const base = @import("../../../base.zig");

View file

@ -1,3 +1,5 @@
//! TODO module doc comment here
const std = @import("std");
const testing = std.testing;
const base = @import("../../../base.zig");

View file

@ -475,6 +475,7 @@ pub const Diagnostic = struct {
header_unexpected_token,
pattern_unexpected_token,
pattern_unexpected_eof,
bad_as_pattern_name,
ty_anno_unexpected_token,
statement_unexpected_eof,
statement_unexpected_token,
@ -904,6 +905,11 @@ pub const Pattern = union(enum) {
patterns: Pattern.Span,
region: TokenizedRegion,
},
as: struct {
pattern: Pattern.Idx,
name: Token.Idx,
region: TokenizedRegion,
},
malformed: struct {
reason: Diagnostic.Tag,
region: TokenizedRegion,
@ -925,6 +931,7 @@ pub const Pattern = union(enum) {
.tuple => |p| p.region,
.underscore => |p| p.region,
.alternatives => |p| p.region,
.as => |p| p.region,
.malformed => |p| p.region,
};
}
@ -1039,6 +1046,15 @@ pub const Pattern = union(enum) {
}
return node;
},
.as => |a| {
var node = SExpr.init(env.gpa, "p-as");
node.appendRegion(env.gpa, ast.calcRegionInfo(a.region, env.line_starts.items));
var pattern_node = ast.store.getPattern(a.pattern).toSExpr(env, ast);
node.appendStringAttr(env.gpa, "name", ast.resolve(a.name));
node.appendNode(env.gpa, &pattern_node);
return node;
},
.malformed => |a| {
var node = SExpr.init(env.gpa, "p-malformed");
node.appendRegion(env.gpa, ast.calcRegionInfo(a.region, env.line_starts.items));

View file

@ -462,6 +462,12 @@ pub fn addPattern(store: *NodeStore, pattern: AST.Pattern) AST.Pattern.Idx {
node.data.lhs = a.patterns.span.start;
node.data.rhs = a.patterns.span.len;
},
.as => |a| {
node.region = a.region;
node.tag = .as_patt;
node.main_token = a.name;
node.data.lhs = @intFromEnum(a.pattern);
},
.malformed => {
@panic("Use addMalformed instead");
},
@ -1196,6 +1202,13 @@ pub fn getPattern(store: *NodeStore, pattern_idx: AST.Pattern.Idx) AST.Pattern {
.region = node.region,
} };
},
.as_patt => {
return .{ .as = .{
.region = node.region,
.name = node.main_token,
.pattern = @enumFromInt(node.data.lhs),
} };
},
.malformed => {
return .{ .malformed = .{
.reason = @enumFromInt(node.data.lhs),

View file

@ -749,7 +749,6 @@ pub fn parseAppHeader(self: *Parser) AST.Header.Idx {
const packages_end = self.pos;
if (self.peek() != .CloseCurly) {
self.store.clearScratchRecordFieldsFrom(fields_scratch_top);
std.debug.print("Tokens: {any}\n", .{self.tok_buf.tokens.items(.tag)[start..self.pos]});
return self.pushMalformed(AST.Header.Idx, .expected_package_platform_close_curly, start);
}
self.advanceOne(); // Advance past CloseCurly
@ -1309,11 +1308,11 @@ pub fn parsePattern(self: *Parser, alternatives: Alternatives) AST.Pattern.Idx {
if (pattern) |p| {
if (alternatives == .alternatives_forbidden) {
return p;
return self.parseAsPattern(p);
}
if (self.peek() != .OpBar) {
if ((self.store.scratchPatternTop() - patterns_scratch_top) == 0) {
return p;
return self.parseAsPattern(p);
}
self.store.addScratchPattern(p);
break;
@ -1334,6 +1333,25 @@ pub fn parsePattern(self: *Parser, alternatives: Alternatives) AST.Pattern.Idx {
} });
}
fn parseAsPattern(self: *Parser, pattern: AST.Pattern.Idx) AST.Pattern.Idx {
if (self.peek() != .KwAs) {
return pattern;
}
self.advance(); // Advance past KwAs
if (self.peek() != .LowerIdent) {
// The name of a pattern can only be a lower ident
return self.pushMalformed(AST.Pattern.Idx, .bad_as_pattern_name, self.pos);
}
const parent_region = self.store.getPattern(pattern).to_tokenized_region();
const p = self.store.addPattern(.{ .as = .{
.name = self.pos,
.pattern = pattern,
.region = .{ .start = parent_region.start, .end = self.pos },
} });
self.advance(); // Advance past LowerIdent;
return p;
}
fn parsePatternNoAlts(self: *Parser) AST.Pattern.Idx {
return self.parsePattern(.alternatives_forbidden);
}
@ -1359,7 +1377,10 @@ pub fn parsePatternRecordField(self: *Parser, alternatives: Alternatives) AST.Pa
});
}
if (self.peek() != .LowerIdent) {
while (self.peek() != .CloseCurly and self.peek() != .EndOfFile) {
while (self.peek() != .EndOfFile) {
if (self.peek() == .CloseCurly) {
break;
}
self.advance();
}
return self.pushMalformed(AST.PatternRecordField.Idx, .expected_lower_ident_pat_field_name, field_start);
@ -1367,14 +1388,17 @@ pub fn parsePatternRecordField(self: *Parser, alternatives: Alternatives) AST.Pa
const name = self.pos;
self.advance();
var value: ?AST.Pattern.Idx = null;
if (self.peek() != .OpColon and (self.peekNext() != .Comma or self.peekNext() != .CloseCurly)) {
while (self.peek() != .CloseCurly and self.peek() != .EndOfFile) {
self.advance();
// With shorthand the next token is a Comma or the ending CloseCurly
if (self.peek() != .Comma and self.peek() != .CloseCurly) {
// Otherwise we should see an OpColon to introduce the value
if (self.peek() != .OpColon) {
while (self.peek() != .EndOfFile) {
if (self.peek() == .CloseCurly) break;
self.advance();
}
return self.pushMalformed(AST.PatternRecordField.Idx, .expected_colon_after_pat_field_name, field_start);
}
return self.pushMalformed(AST.PatternRecordField.Idx, .expected_colon_after_pat_field_name, field_start);
}
self.advance();
if (self.peekNext() != .Comma or self.peekNext() != .CloseCurly) {
self.advance();
const patt = self.parsePattern(alternatives);
value = patt;
}

View file

@ -1104,6 +1104,11 @@ const Formatter = struct {
i += 1;
}
},
.as => |a| {
_ = try fmt.formatPattern(a.pattern);
try fmt.pushAll(" as ");
try fmt.pushTokenText(a.name);
},
.malformed => {
// Output nothing for malformed node
},

View file

@ -12,27 +12,6 @@ Err(foo)??12>5*5 or 13+2<5 and 10-1>=16 or 12<=3/5
Nothing is named `foo` in this scope.
Is there an `import` or `exposing` missing up-top?
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
# TOKENS
~~~zig
UpperIdent(1:1-1:4),NoSpaceOpenRound(1:4-1:5),LowerIdent(1:5-1:8),CloseRound(1:8-1:9),OpDoubleQuestion(1:9-1:11),Int(1:11-1:13),OpGreaterThan(1:13-1:14),Int(1:14-1:15),OpStar(1:15-1:16),Int(1:16-1:17),OpOr(1:18-1:20),Int(1:21-1:23),OpPlus(1:23-1:24),Int(1:24-1:25),OpLessThan(1:25-1:26),Int(1:26-1:27),OpAnd(1:28-1:31),Int(1:32-1:34),OpBinaryMinus(1:34-1:35),Int(1:35-1:36),OpGreaterThanOrEq(1:36-1:38),Int(1:38-1:40),OpOr(1:41-1:43),Int(1:44-1:46),OpLessThanOrEq(1:46-1:48),Int(1:48-1:49),OpSlash(1:49-1:50),Int(1:50-1:51),EndOfFile(1:51-1:51),
@ -73,9 +52,35 @@ Err(foo) ?? 12 > 5 * 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 / 5
~~~
# CANONICALIZE
~~~clojure
(e-runtime-error (tag "not_implemented") (id 119))
(e-binop @1-1-1-51 (op "or") (id 112)
(e-binop @1-1-1-43 (op "or")
(e-binop @1-1-1-20 (op "gt")
(e-binop @1-1-1-14 (op "null_coalesce")
(e-call @1-1-1-9
(e-tag @1-1-1-4 (ext-var 0) (name "Err") (args "TODO"))
(e-runtime-error (tag "ident_not_in_scope")))
(e-int @1-11-1-13 (num-var 78) (value "12")))
(e-binop @1-14-1-20 (op "mul")
(e-int @1-14-1-15 (num-var 81) (value "5"))
(e-int @1-16-1-17 (num-var 83) (value "5"))))
(e-binop @1-21-1-43 (op "and")
(e-binop @1-21-1-31 (op "lt")
(e-binop @1-21-1-26 (op "add")
(e-int @1-21-1-23 (num-var 87) (value "13"))
(e-int @1-24-1-25 (num-var 89) (value "2")))
(e-int @1-26-1-27 (num-var 92) (value "5")))
(e-binop @1-32-1-43 (op "ge")
(e-binop @1-32-1-38 (op "sub")
(e-int @1-32-1-34 (num-var 95) (value "10"))
(e-int @1-35-1-36 (num-var 97) (value "1")))
(e-int @1-38-1-40 (num-var 100) (value "16")))))
(e-binop @1-44-1-51 (op "le")
(e-int @1-44-1-46 (num-var 105) (value "12"))
(e-binop @1-48-1-51 (op "div")
(e-int @1-48-1-49 (num-var 107) (value "3"))
(e-int @1-50-1-51 (num-var 109) (value "5")))))
~~~
# TYPES
~~~clojure
(expr (id 119) (type "Error"))
(expr (id 112) (type "*"))
~~~

View file

@ -12,27 +12,6 @@ Err(foo) ?? 12 > 5 * 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 / 5
Nothing is named `foo` in this scope.
Is there an `import` or `exposing` missing up-top?
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
# TOKENS
~~~zig
UpperIdent(1:1-1:4),NoSpaceOpenRound(1:4-1:5),LowerIdent(1:5-1:8),CloseRound(1:8-1:9),OpDoubleQuestion(1:10-1:12),Int(1:13-1:15),OpGreaterThan(1:16-1:17),Int(1:18-1:19),OpStar(1:20-1:21),Int(1:22-1:23),OpOr(1:24-1:26),Int(1:27-1:29),OpPlus(1:30-1:31),Int(1:32-1:33),OpLessThan(1:34-1:35),Int(1:36-1:37),OpAnd(1:38-1:41),Int(1:42-1:44),OpBinaryMinus(1:45-1:46),Int(1:47-1:48),OpGreaterThanOrEq(1:49-1:51),Int(1:52-1:54),OpOr(1:55-1:57),Int(1:58-1:60),OpLessThanOrEq(1:61-1:63),Int(1:64-1:65),OpSlash(1:66-1:67),Int(1:68-1:69),EndOfFile(1:69-1:69),
@ -73,9 +52,35 @@ NO CHANGE
~~~
# CANONICALIZE
~~~clojure
(e-runtime-error (tag "not_implemented") (id 119))
(e-binop @1-1-1-69 (op "or") (id 112)
(e-binop @1-1-1-57 (op "or")
(e-binop @1-1-1-26 (op "gt")
(e-binop @1-1-1-17 (op "null_coalesce")
(e-call @1-1-1-9
(e-tag @1-1-1-4 (ext-var 0) (name "Err") (args "TODO"))
(e-runtime-error (tag "ident_not_in_scope")))
(e-int @1-13-1-15 (num-var 78) (value "12")))
(e-binop @1-18-1-26 (op "mul")
(e-int @1-18-1-19 (num-var 81) (value "5"))
(e-int @1-22-1-23 (num-var 83) (value "5"))))
(e-binop @1-27-1-57 (op "and")
(e-binop @1-27-1-41 (op "lt")
(e-binop @1-27-1-35 (op "add")
(e-int @1-27-1-29 (num-var 87) (value "13"))
(e-int @1-32-1-33 (num-var 89) (value "2")))
(e-int @1-36-1-37 (num-var 92) (value "5")))
(e-binop @1-42-1-57 (op "ge")
(e-binop @1-42-1-51 (op "sub")
(e-int @1-42-1-44 (num-var 95) (value "10"))
(e-int @1-47-1-48 (num-var 97) (value "1")))
(e-int @1-52-1-54 (num-var 100) (value "16")))))
(e-binop @1-58-1-69 (op "le")
(e-int @1-58-1-60 (num-var 105) (value "12"))
(e-binop @1-64-1-69 (op "div")
(e-int @1-64-1-65 (num-var 107) (value "3"))
(e-int @1-68-1-69 (num-var 109) (value "5")))))
~~~
# TYPES
~~~clojure
(expr (id 119) (type "Error"))
(expr (id 112) (type "*"))
~~~

170
src/snapshots/binops.md generated Normal file
View file

@ -0,0 +1,170 @@
# META
~~~ini
description=Binops collection
type=expr
~~~
# SOURCE
~~~roc
(
4 + 2,
4 - 2,
4 * 2,
4 / 2,
4 % 2,
4 < 2,
4 > 2,
4 <= 2,
4 >= 2,
4 == 2,
4 != 2,
4 // 2,
True and True,
True or True,
None ?? 0,
)
~~~
# PROBLEMS
NIL
# TOKENS
~~~zig
OpenRound(1:1-1:2),Newline(1:1-1:1),
Int(2:5-2:6),OpPlus(2:7-2:8),Int(2:9-2:10),Comma(2:10-2:11),Newline(1:1-1:1),
Int(3:5-3:6),OpBinaryMinus(3:7-3:8),Int(3:9-3:10),Comma(3:10-3:11),Newline(1:1-1:1),
Int(4:5-4:6),OpStar(4:7-4:8),Int(4:9-4:10),Comma(4:10-4:11),Newline(1:1-1:1),
Int(5:5-5:6),OpSlash(5:7-5:8),Int(5:9-5:10),Comma(5:10-5:11),Newline(1:1-1:1),
Int(6:5-6:6),OpPercent(6:7-6:8),Int(6:9-6:10),Comma(6:10-6:11),Newline(1:1-1:1),
Int(7:5-7:6),OpLessThan(7:7-7:8),Int(7:9-7:10),Comma(7:10-7:11),Newline(1:1-1:1),
Int(8:5-8:6),OpGreaterThan(8:7-8:8),Int(8:9-8:10),Comma(8:10-8:11),Newline(1:1-1:1),
Int(9:5-9:6),OpLessThanOrEq(9:7-9:9),Int(9:10-9:11),Comma(9:11-9:12),Newline(1:1-1:1),
Int(10:5-10:6),OpGreaterThanOrEq(10:7-10:9),Int(10:10-10:11),Comma(10:11-10:12),Newline(1:1-1:1),
Int(11:5-11:6),OpEquals(11:7-11:9),Int(11:10-11:11),Comma(11:11-11:12),Newline(1:1-1:1),
Int(12:5-12:6),OpNotEquals(12:7-12:9),Int(12:10-12:11),Comma(12:11-12:12),Newline(1:1-1:1),
Int(13:5-13:6),OpDoubleSlash(13:7-13:9),Int(13:10-13:11),Comma(13:11-13:12),Newline(1:1-1:1),
UpperIdent(14:5-14:9),OpAnd(14:10-14:13),UpperIdent(14:14-14:18),Comma(14:18-14:19),Newline(1:1-1:1),
UpperIdent(15:5-15:9),OpOr(15:10-15:12),UpperIdent(15:13-15:17),Comma(15:17-15:18),Newline(1:1-1:1),
UpperIdent(16:5-16:9),OpDoubleQuestion(16:10-16:12),Int(16:13-16:14),Comma(16:14-16:15),Newline(1:1-1:1),
CloseRound(17:1-17:2),EndOfFile(17:2-17:2),
~~~
# PARSE
~~~clojure
(e-tuple @1-1-17-2
(e-binop @2-5-2-11 (op "+")
(e-int @2-5-2-6 (raw "4"))
(e-int @2-9-2-10 (raw "2")))
(e-binop @3-5-3-11 (op "-")
(e-int @3-5-3-6 (raw "4"))
(e-int @3-9-3-10 (raw "2")))
(e-binop @4-5-4-11 (op "*")
(e-int @4-5-4-6 (raw "4"))
(e-int @4-9-4-10 (raw "2")))
(e-binop @5-5-5-11 (op "/")
(e-int @5-5-5-6 (raw "4"))
(e-int @5-9-5-10 (raw "2")))
(e-binop @6-5-6-11 (op "%")
(e-int @6-5-6-6 (raw "4"))
(e-int @6-9-6-10 (raw "2")))
(e-binop @7-5-7-11 (op "<")
(e-int @7-5-7-6 (raw "4"))
(e-int @7-9-7-10 (raw "2")))
(e-binop @8-5-8-11 (op ">")
(e-int @8-5-8-6 (raw "4"))
(e-int @8-9-8-10 (raw "2")))
(e-binop @9-5-9-12 (op "<=")
(e-int @9-5-9-6 (raw "4"))
(e-int @9-10-9-11 (raw "2")))
(e-binop @10-5-10-12 (op ">=")
(e-int @10-5-10-6 (raw "4"))
(e-int @10-10-10-11 (raw "2")))
(e-binop @11-5-11-12 (op "==")
(e-int @11-5-11-6 (raw "4"))
(e-int @11-10-11-11 (raw "2")))
(e-binop @12-5-12-12 (op "!=")
(e-int @12-5-12-6 (raw "4"))
(e-int @12-10-12-11 (raw "2")))
(e-binop @13-5-13-12 (op "//")
(e-int @13-5-13-6 (raw "4"))
(e-int @13-10-13-11 (raw "2")))
(e-binop @14-5-14-19 (op "and")
(e-tag @14-5-14-9 (raw "True"))
(e-tag @14-14-14-18 (raw "True")))
(e-binop @15-5-15-18 (op "or")
(e-tag @15-5-15-9 (raw "True"))
(e-tag @15-13-15-17 (raw "True")))
(e-binop @16-5-16-15 (op "??")
(e-tag @16-5-16-9 (raw "None"))
(e-int @16-13-16-14 (raw "0"))))
~~~
# FORMATTED
~~~roc
(
4 + 2,
4 - 2,
4 * 2,
4 / 2,
4 % 2,
4 < 2,
4 > 2,
4 <= 2,
4 >= 2,
4 == 2,
4 != 2,
4 // 2,
True and True,
True or True,
None ?? 0,
)
~~~
# CANONICALIZE
~~~clojure
(e-tuple @1-1-17-2 (tuple-var 147) (id 148)
(elems
(e-binop @2-5-2-11 (op "add")
(e-int @2-5-2-6 (num-var 73) (value "4"))
(e-int @2-9-2-10 (num-var 75) (value "2")))
(e-binop @3-5-3-11 (op "sub")
(e-int @3-5-3-6 (num-var 78) (value "4"))
(e-int @3-9-3-10 (num-var 80) (value "2")))
(e-binop @4-5-4-11 (op "mul")
(e-int @4-5-4-6 (num-var 83) (value "4"))
(e-int @4-9-4-10 (num-var 85) (value "2")))
(e-binop @5-5-5-11 (op "div")
(e-int @5-5-5-6 (num-var 88) (value "4"))
(e-int @5-9-5-10 (num-var 90) (value "2")))
(e-binop @6-5-6-11 (op "rem")
(e-int @6-5-6-6 (num-var 93) (value "4"))
(e-int @6-9-6-10 (num-var 95) (value "2")))
(e-binop @7-5-7-11 (op "lt")
(e-int @7-5-7-6 (num-var 98) (value "4"))
(e-int @7-9-7-10 (num-var 100) (value "2")))
(e-binop @8-5-8-11 (op "gt")
(e-int @8-5-8-6 (num-var 103) (value "4"))
(e-int @8-9-8-10 (num-var 105) (value "2")))
(e-binop @9-5-9-12 (op "le")
(e-int @9-5-9-6 (num-var 108) (value "4"))
(e-int @9-10-9-11 (num-var 110) (value "2")))
(e-binop @10-5-10-12 (op "ge")
(e-int @10-5-10-6 (num-var 113) (value "4"))
(e-int @10-10-10-11 (num-var 115) (value "2")))
(e-binop @11-5-11-12 (op "eq")
(e-int @11-5-11-6 (num-var 118) (value "4"))
(e-int @11-10-11-11 (num-var 120) (value "2")))
(e-binop @12-5-12-12 (op "ne")
(e-int @12-5-12-6 (num-var 123) (value "4"))
(e-int @12-10-12-11 (num-var 125) (value "2")))
(e-binop @13-5-13-12 (op "div_trunc")
(e-int @13-5-13-6 (num-var 128) (value "4"))
(e-int @13-10-13-11 (num-var 130) (value "2")))
(e-binop @14-5-14-19 (op "and")
(e-tag @14-5-14-9 (ext-var 0) (name "True") (args "TODO"))
(e-tag @14-14-14-18 (ext-var 0) (name "True") (args "TODO")))
(e-binop @15-5-15-18 (op "or")
(e-tag @15-5-15-9 (ext-var 0) (name "True") (args "TODO"))
(e-tag @15-13-15-17 (ext-var 0) (name "True") (args "TODO")))
(e-binop @16-5-16-15 (op "null_coalesce")
(e-tag @16-5-16-9 (ext-var 0) (name "None") (args "TODO"))
(e-int @16-13-16-14 (num-var 145) (value "0")))))
~~~
# TYPES
~~~clojure
(expr (id 148) (type "*"))
~~~

View file

@ -0,0 +1,42 @@
# META
~~~ini
description=Record with duplicate field names (error case)
type=expr
~~~
# SOURCE
~~~roc
{ name: "Alice", age: 30, name: "Bob", email: "alice@example.com", age: 25 }
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize record expression
# TOKENS
~~~zig
OpenCurly(1:1-1:2),LowerIdent(1:3-1:7),OpColon(1:7-1:8),StringStart(1:9-1:10),StringPart(1:10-1:15),StringEnd(1:15-1:16),Comma(1:16-1:17),LowerIdent(1:18-1:21),OpColon(1:21-1:22),Int(1:23-1:25),Comma(1:25-1:26),LowerIdent(1:27-1:31),OpColon(1:31-1:32),StringStart(1:33-1:34),StringPart(1:34-1:37),StringEnd(1:37-1:38),Comma(1:38-1:39),LowerIdent(1:40-1:45),OpColon(1:45-1:46),StringStart(1:47-1:48),StringPart(1:48-1:65),StringEnd(1:65-1:66),Comma(1:66-1:67),LowerIdent(1:68-1:71),OpColon(1:71-1:72),Int(1:73-1:75),CloseCurly(1:76-1:77),EndOfFile(1:77-1:77),
~~~
# PARSE
~~~clojure
(e-record @1-1-1-77
(field (field "name") (optional false)
(e-string @1-9-1-16
(e-string-part @1-10-1-15 (raw "Alice"))))
(field (field "age") (optional false)
(e-int @1-23-1-25 (raw "30")))
(field (field "name") (optional false)
(e-string @1-33-1-38
(e-string-part @1-34-1-37 (raw "Bob"))))
(field (field "email") (optional false)
(e-string @1-47-1-66
(e-string-part @1-48-1-65 (raw "alice@example.com"))))
(field (field "age") (optional false)
(e-int @1-73-1-75 (raw "25"))))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(expr (id 73) (type "Error"))
~~~

View file

@ -0,0 +1,50 @@
# META
~~~ini
description=Malformed record syntax (error case)
type=expr
~~~
# SOURCE
~~~roc
{ name: "Alice", : 30, , email: , active Bool.true, "invalid": value, 42: "number key", : }
~~~
# PROBLEMS
**PARSE ERROR**
A parsing error occurred: `expected_expr_record_field_name`
This is an unexpected parsing error. Please check your syntax.
Here is the problematic code:
**error_malformed_syntax.md:1:18:1:22:**
```roc
{ name: "Alice", : 30, , email: , active Bool.true, "invalid": value, 42: "number key", : }
```
**PARSE ERROR**
A parsing error occurred: `expected_expr_close_curly_or_comma`
This is an unexpected parsing error. Please check your syntax.
Here is the problematic code:
**error_malformed_syntax.md:1:20:1:23:**
```roc
{ name: "Alice", : 30, , email: , active Bool.true, "invalid": value, 42: "number key", : }
```
# TOKENS
~~~zig
OpenCurly(1:1-1:2),LowerIdent(1:3-1:7),OpColon(1:7-1:8),StringStart(1:9-1:10),StringPart(1:10-1:15),StringEnd(1:15-1:16),Comma(1:16-1:17),OpColon(1:18-1:19),Int(1:20-1:22),Comma(1:22-1:23),Comma(1:24-1:25),LowerIdent(1:26-1:31),OpColon(1:31-1:32),Comma(1:33-1:34),LowerIdent(1:35-1:41),UpperIdent(1:42-1:46),NoSpaceDotLowerIdent(1:46-1:51),Comma(1:51-1:52),StringStart(1:53-1:54),StringPart(1:54-1:61),StringEnd(1:61-1:62),OpColon(1:62-1:63),LowerIdent(1:64-1:69),Comma(1:69-1:70),Int(1:71-1:73),OpColon(1:73-1:74),StringStart(1:75-1:76),StringPart(1:76-1:86),StringEnd(1:86-1:87),Comma(1:87-1:88),OpColon(1:89-1:90),CloseCurly(1:91-1:92),EndOfFile(1:92-1:92),
~~~
# PARSE
~~~clojure
(e-malformed @1-20-1-23 (reason "expected_expr_close_curly_or_comma"))
~~~
# FORMATTED
~~~roc
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
~~~

View file

@ -0,0 +1,42 @@
# META
~~~ini
description=Malformed record syntax using equals instead of colon (error case)
type=expr
~~~
# SOURCE
~~~roc
{ name = "Alice" }
~~~
# PROBLEMS
**UNUSED VARIABLE**
Variable ``name`` is not used anywhere in your code.
If you don't need this variable, prefix it with an underscore like `_name` to suppress this warning.
The unused variable is declared here:
**error_malformed_syntax_2.md:1:3:1:7:**
```roc
{ name = "Alice" }
```
# TOKENS
~~~zig
OpenCurly(1:1-1:2),LowerIdent(1:3-1:7),OpAssign(1:8-1:9),StringStart(1:10-1:11),StringPart(1:11-1:16),StringEnd(1:16-1:17),CloseCurly(1:18-1:19),EndOfFile(1:19-1:19),
~~~
# PARSE
~~~clojure
(e-block @1-1-1-19
(statements
(s-decl @1-3-1-17
(p-ident @1-3-1-7 (raw "name"))
(e-string @1-10-1-17
(e-string-part @1-11-1-16 (raw "Alice"))))))
~~~
# FORMATTED
~~~roc
name = "Alice"
~~~
# TYPES
~~~clojure
(expr (id 76) (type "*"))
~~~

View file

@ -0,0 +1,51 @@
# META
~~~ini
description=Function with record parameter destructuring and string interpolation
type=expr
~~~
# SOURCE
~~~roc
|{ name, age }| "Hello ${name}, you are ${age.to_str()} years old"
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize record pattern
**UNDEFINED VARIABLE**
Nothing is named `name` in this scope.
Is there an `import` or `exposing` missing up-top?
**UNDEFINED VARIABLE**
Nothing is named `age` in this scope.
Is there an `import` or `exposing` missing up-top?
# TOKENS
~~~zig
OpBar(1:1-1:2),OpenCurly(1:2-1:3),LowerIdent(1:4-1:8),Comma(1:8-1:9),LowerIdent(1:10-1:13),CloseCurly(1:14-1:15),OpBar(1:15-1:16),StringStart(1:17-1:18),StringPart(1:18-1:24),OpenStringInterpolation(1:24-1:26),LowerIdent(1:26-1:30),CloseStringInterpolation(1:30-1:31),StringPart(1:31-1:41),OpenStringInterpolation(1:41-1:43),LowerIdent(1:43-1:46),NoSpaceDotLowerIdent(1:46-1:53),NoSpaceOpenRound(1:53-1:54),CloseRound(1:54-1:55),CloseStringInterpolation(1:55-1:56),StringPart(1:56-1:66),StringEnd(1:66-1:67),EndOfFile(1:67-1:67),
~~~
# PARSE
~~~clojure
(e-lambda @1-1-1-67
(args
(p-record @1-2-1-15
(field @1-4-1-9 (name "name") (rest false))
(field @1-10-1-15 (name "age") (rest false))))
(e-string @1-17-1-67
(e-string-part @1-18-1-24 (raw "Hello "))
(e-ident @1-26-1-30 (qaul "") (raw "name"))
(e-string-part @1-31-1-41 (raw ", you are "))
(e-field-access @1-43-1-56
(e-binop @1-43-1-56 (op "|")
(e-ident @1-43-1-46 (qaul "") (raw "age"))
(e-apply @1-46-1-55
(e-ident @1-46-1-53 (qaul "") (raw ".to_str")))))
(e-string-part @1-56-1-66 (raw " years old"))))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(expr (id 83) (type "*"))
~~~

View file

@ -0,0 +1,50 @@
# META
~~~ini
description=Function with record parameter destructuring and rest pattern, capture whole record using `as`
type=expr
~~~
# SOURCE
~~~roc
|{ name, age, ..a } as person| { greeting: "Hello ${name}", full_record: person, is_adult: age >= 18 }
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize alternatives pattern
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize record expression
# TOKENS
~~~zig
OpBar(1:1-1:2),OpenCurly(1:2-1:3),LowerIdent(1:4-1:8),Comma(1:8-1:9),LowerIdent(1:10-1:13),Comma(1:13-1:14),DoubleDot(1:15-1:17),LowerIdent(1:17-1:18),CloseCurly(1:19-1:20),KwAs(1:21-1:23),LowerIdent(1:24-1:30),OpBar(1:30-1:31),OpenCurly(1:32-1:33),LowerIdent(1:34-1:42),OpColon(1:42-1:43),StringStart(1:44-1:45),StringPart(1:45-1:51),OpenStringInterpolation(1:51-1:53),LowerIdent(1:53-1:57),CloseStringInterpolation(1:57-1:58),StringPart(1:58-1:58),StringEnd(1:58-1:59),Comma(1:59-1:60),LowerIdent(1:61-1:72),OpColon(1:72-1:73),LowerIdent(1:74-1:80),Comma(1:80-1:81),LowerIdent(1:82-1:90),OpColon(1:90-1:91),LowerIdent(1:92-1:95),OpGreaterThanOrEq(1:96-1:98),Int(1:99-1:101),CloseCurly(1:102-1:103),EndOfFile(1:103-1:103),
~~~
# PARSE
~~~clojure
(e-lambda @1-1-1-103
(args
(p-as @1-2-1-30 (name "person")
(p-record @1-2-1-20
(field @1-4-1-9 (name "name") (rest false))
(field @1-10-1-14 (name "age") (rest false))
(field @1-15-1-20 (name "a") (rest true)))))
(e-record @1-32-1-103
(field (field "greeting") (optional false)
(e-string @1-44-1-59
(e-string-part @1-45-1-51 (raw "Hello "))
(e-ident @1-53-1-57 (qaul "") (raw "name"))
(e-string-part @1-58-1-58 (raw ""))))
(field (field "full_record") (optional false)
(e-ident @1-74-1-80 (qaul "") (raw "person")))
(field (field "is_adult") (optional false)
(e-binop @1-92-1-103 (op ">=")
(e-ident @1-92-1-95 (qaul "") (raw "age"))
(e-int @1-99-1-101 (raw "18"))))))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(expr (id 76) (type "*"))
~~~

View file

@ -0,0 +1,50 @@
# META
~~~ini
description=Function with record parameter and rest pattern
type=expr
~~~
# SOURCE
~~~roc
|{ first_name, ..rest }| "Hello ${first_name} ${rest.last_name}"
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize record pattern
**UNDEFINED VARIABLE**
Nothing is named `first_name` in this scope.
Is there an `import` or `exposing` missing up-top?
**UNDEFINED VARIABLE**
Nothing is named `rest` in this scope.
Is there an `import` or `exposing` missing up-top?
# TOKENS
~~~zig
OpBar(1:1-1:2),OpenCurly(1:2-1:3),LowerIdent(1:4-1:14),Comma(1:14-1:15),DoubleDot(1:16-1:18),LowerIdent(1:18-1:22),CloseCurly(1:23-1:24),OpBar(1:24-1:25),StringStart(1:26-1:27),StringPart(1:27-1:33),OpenStringInterpolation(1:33-1:35),LowerIdent(1:35-1:45),CloseStringInterpolation(1:45-1:46),StringPart(1:46-1:47),OpenStringInterpolation(1:47-1:49),LowerIdent(1:49-1:53),NoSpaceDotLowerIdent(1:53-1:63),CloseStringInterpolation(1:63-1:64),StringPart(1:64-1:64),StringEnd(1:64-1:65),EndOfFile(1:65-1:65),
~~~
# PARSE
~~~clojure
(e-lambda @1-1-1-65
(args
(p-record @1-2-1-24
(field @1-4-1-15 (name "first_name") (rest false))
(field @1-16-1-24 (name "rest") (rest true))))
(e-string @1-26-1-65
(e-string-part @1-27-1-33 (raw "Hello "))
(e-ident @1-35-1-45 (qaul "") (raw "first_name"))
(e-string-part @1-46-1-47 (raw " "))
(e-field-access @1-49-1-64
(e-binop @1-49-1-64 (op "|")
(e-ident @1-49-1-53 (qaul "") (raw "rest"))
(e-ident @1-53-1-63 (qaul "") (raw ".last_name"))))
(e-string-part @1-64-1-64 (raw ""))))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(expr (id 83) (type "*"))
~~~

View file

@ -0,0 +1,69 @@
# META
~~~ini
description=Nested record destructuring pattern in a match expression
type=expr
~~~
# SOURCE
~~~roc
match person {
{ name, address: { street, city, zipCode } } => "${name} lives on ${street} in ${city}"
}
~~~
# PROBLEMS
**UNEXPECTED TOKEN IN PATTERN**
The token **match person {
{ name, address: { street, city, zipCode } } => "${name} lives on ${street} in ${city}"
}** is not expected in a pattern.
Patterns can contain identifiers, literals, lists, records, or tags.
Here is the problematic code:
**pattern_destructure_nested.md:1:1:3:2:**
```roc
match person {
{ name, address: { street, city, zipCode } } => "${name} lives on ${street} in ${city}"
}
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **}** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**pattern_destructure_nested.md:3:1:3:2:**
```roc
}
```
**PARSE ERROR**
A parsing error occurred: `expected_close_curly_at_end_of_match`
This is an unexpected parsing error. Please check your syntax.
Here is the problematic code:
**pattern_destructure_nested.md:3:2:3:2:**
```roc
}
```
# TOKENS
~~~zig
KwMatch(1:1-1:6),LowerIdent(1:7-1:13),OpenCurly(1:14-1:15),Newline(1:1-1:1),
OpenCurly(2:5-2:6),LowerIdent(2:7-2:11),Comma(2:11-2:12),LowerIdent(2:13-2:20),OpColon(2:20-2:21),OpenCurly(2:22-2:23),LowerIdent(2:24-2:30),Comma(2:30-2:31),LowerIdent(2:32-2:36),Comma(2:36-2:37),LowerIdent(2:38-2:45),CloseCurly(2:46-2:47),CloseCurly(2:48-2:49),OpFatArrow(2:50-2:52),StringStart(2:53-2:54),StringPart(2:54-2:54),OpenStringInterpolation(2:54-2:56),LowerIdent(2:56-2:60),CloseStringInterpolation(2:60-2:61),StringPart(2:61-2:71),OpenStringInterpolation(2:71-2:73),LowerIdent(2:73-2:79),CloseStringInterpolation(2:79-2:80),StringPart(2:80-2:84),OpenStringInterpolation(2:84-2:86),LowerIdent(2:86-2:90),CloseStringInterpolation(2:90-2:91),StringPart(2:91-2:91),StringEnd(2:91-2:92),Newline(1:1-1:1),
CloseCurly(3:1-3:2),EndOfFile(3:2-3:2),
~~~
# PARSE
~~~clojure
(e-malformed @3-2-3-2 (reason "expected_close_curly_at_end_of_match"))
~~~
# FORMATTED
~~~roc
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
~~~

View file

@ -0,0 +1,69 @@
# META
~~~ini
description=Record destructuring with field renaming
type=expr
~~~
# SOURCE
~~~roc
match person {
{ name: userName, age: userAge } => "User ${userName} is ${userAge.to_str()} years old"
}
~~~
# PROBLEMS
**UNEXPECTED TOKEN IN PATTERN**
The token **match person {
{ name: userName, age: userAge } => "User ${userName} is ${userAge.to_str()} years old"
}** is not expected in a pattern.
Patterns can contain identifiers, literals, lists, records, or tags.
Here is the problematic code:
**pattern_destructure_rename.md:1:1:3:2:**
```roc
match person {
{ name: userName, age: userAge } => "User ${userName} is ${userAge.to_str()} years old"
}
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **}** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**pattern_destructure_rename.md:3:1:3:2:**
```roc
}
```
**PARSE ERROR**
A parsing error occurred: `expected_close_curly_at_end_of_match`
This is an unexpected parsing error. Please check your syntax.
Here is the problematic code:
**pattern_destructure_rename.md:3:2:3:2:**
```roc
}
```
# TOKENS
~~~zig
KwMatch(1:1-1:6),LowerIdent(1:7-1:13),OpenCurly(1:14-1:15),Newline(1:1-1:1),
OpenCurly(2:5-2:6),LowerIdent(2:7-2:11),OpColon(2:11-2:12),LowerIdent(2:13-2:21),Comma(2:21-2:22),LowerIdent(2:23-2:26),OpColon(2:26-2:27),LowerIdent(2:28-2:35),CloseCurly(2:36-2:37),OpFatArrow(2:38-2:40),StringStart(2:41-2:42),StringPart(2:42-2:47),OpenStringInterpolation(2:47-2:49),LowerIdent(2:49-2:57),CloseStringInterpolation(2:57-2:58),StringPart(2:58-2:62),OpenStringInterpolation(2:62-2:64),LowerIdent(2:64-2:71),NoSpaceDotLowerIdent(2:71-2:78),NoSpaceOpenRound(2:78-2:79),CloseRound(2:79-2:80),CloseStringInterpolation(2:80-2:81),StringPart(2:81-2:91),StringEnd(2:91-2:92),Newline(1:1-1:1),
CloseCurly(3:1-3:2),EndOfFile(3:2-3:2),
~~~
# PARSE
~~~clojure
(e-malformed @3-2-3-2 (reason "expected_close_curly_at_end_of_match"))
~~~
# FORMATTED
~~~roc
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
~~~

View file

@ -0,0 +1,42 @@
# META
~~~ini
description=Simple record destructuring pattern
type=expr
~~~
# SOURCE
~~~roc
match person {
{ name, age } => name
}
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize match expression
# TOKENS
~~~zig
KwMatch(1:1-1:6),LowerIdent(1:7-1:13),OpenCurly(1:14-1:15),Newline(1:1-1:1),
OpenCurly(2:5-2:6),LowerIdent(2:7-2:11),Comma(2:11-2:12),LowerIdent(2:13-2:16),CloseCurly(2:17-2:18),OpFatArrow(2:19-2:21),LowerIdent(2:22-2:26),Newline(1:1-1:1),
CloseCurly(3:1-3:2),EndOfFile(3:2-3:2),
~~~
# PARSE
~~~clojure
(e-match
(e-ident @1-7-1-13 (qaul "") (raw "person"))
(branches
(branch @2-5-3-2
(p-record @2-5-2-18
(field @2-7-2-12 (name "name") (rest false))
(field @2-13-2-18 (name "age") (rest false)))
(e-ident @2-22-2-26 (qaul "") (raw "name")))))
~~~
# FORMATTED
~~~roc
match person {
{ name, age } => name
}
~~~
# TYPES
~~~clojure
(expr (id 73) (type "Error"))
~~~

View file

@ -0,0 +1,51 @@
# META
~~~ini
description=Record destructuring with rest pattern
type=expr
~~~
# SOURCE
~~~roc
match person {
{ first_name, ..others } => Str.len(first_name) > Str.len(others.last_name)
}
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize match expression
# TOKENS
~~~zig
KwMatch(1:1-1:6),LowerIdent(1:7-1:13),OpenCurly(1:14-1:15),Newline(1:1-1:1),
OpenCurly(2:5-2:6),LowerIdent(2:7-2:17),Comma(2:17-2:18),DoubleDot(2:19-2:21),LowerIdent(2:21-2:27),CloseCurly(2:28-2:29),OpFatArrow(2:30-2:32),UpperIdent(2:33-2:36),NoSpaceDotLowerIdent(2:36-2:40),NoSpaceOpenRound(2:40-2:41),LowerIdent(2:41-2:51),CloseRound(2:51-2:52),OpGreaterThan(2:53-2:54),UpperIdent(2:55-2:58),NoSpaceDotLowerIdent(2:58-2:62),NoSpaceOpenRound(2:62-2:63),LowerIdent(2:63-2:69),NoSpaceDotLowerIdent(2:69-2:79),CloseRound(2:79-2:80),Newline(1:1-1:1),
CloseCurly(3:1-3:2),EndOfFile(3:2-3:2),
~~~
# PARSE
~~~clojure
(e-match
(e-ident @1-7-1-13 (qaul "") (raw "person"))
(branches
(branch @2-5-3-2
(p-record @2-5-2-29
(field @2-7-2-18 (name "first_name") (rest false))
(field @2-19-2-29 (name "others") (rest true)))
(e-binop @2-33-3-2 (op ">")
(e-apply @2-33-2-52
(e-ident @2-33-2-40 (qaul "Str") (raw ".len"))
(e-ident @2-41-2-51 (qaul "") (raw "first_name")))
(e-apply @2-55-2-80
(e-ident @2-55-2-62 (qaul "Str") (raw ".len"))
(e-field-access @2-63-2-80
(e-binop @2-63-2-80 (op "match")
(e-ident @2-63-2-69 (qaul "") (raw "others"))
(e-ident @2-69-2-79 (qaul "") (raw ".last_name")))))))))
~~~
# FORMATTED
~~~roc
match person {
{ first_name, ..others } => Str.len(first_name) > Str.len(others.last_name)
}
~~~
# TYPES
~~~clojure
(expr (id 73) (type "Error"))
~~~

View file

@ -0,0 +1,52 @@
# META
~~~ini
description=Record pattern destructuring in function parameter
type=statement
~~~
# SOURCE
~~~roc
formatUser = |{ name, age, email }| "User: ${name} (${age.toStr()} years old) - Contact: ${email.display()}"
~~~
# PROBLEMS
NIL
# TOKENS
~~~zig
LowerIdent(1:1-1:11),OpAssign(1:12-1:13),OpBar(1:14-1:15),OpenCurly(1:15-1:16),LowerIdent(1:17-1:21),Comma(1:21-1:22),LowerIdent(1:23-1:26),Comma(1:26-1:27),LowerIdent(1:28-1:33),CloseCurly(1:34-1:35),OpBar(1:35-1:36),StringStart(1:37-1:38),StringPart(1:38-1:44),OpenStringInterpolation(1:44-1:46),LowerIdent(1:46-1:50),CloseStringInterpolation(1:50-1:51),StringPart(1:51-1:53),OpenStringInterpolation(1:53-1:55),LowerIdent(1:55-1:58),NoSpaceDotLowerIdent(1:58-1:64),NoSpaceOpenRound(1:64-1:65),CloseRound(1:65-1:66),CloseStringInterpolation(1:66-1:67),StringPart(1:67-1:90),OpenStringInterpolation(1:90-1:92),LowerIdent(1:92-1:97),NoSpaceDotLowerIdent(1:97-1:105),NoSpaceOpenRound(1:105-1:106),CloseRound(1:106-1:107),CloseStringInterpolation(1:107-1:108),StringPart(1:108-1:108),StringEnd(1:108-1:109),EndOfFile(1:109-1:109),
~~~
# PARSE
~~~clojure
(s-decl @1-1-1-109
(p-ident @1-1-1-11 (raw "formatUser"))
(e-lambda @1-14-1-109
(args
(p-record @1-15-1-35
(field @1-17-1-22 (name "name") (rest false))
(field @1-23-1-27 (name "age") (rest false))
(field @1-28-1-35 (name "email") (rest false))))
(e-string @1-37-1-109
(e-string-part @1-38-1-44 (raw "User: "))
(e-ident @1-46-1-50 (qaul "") (raw "name"))
(e-string-part @1-51-1-53 (raw " ("))
(e-field-access @1-55-1-67
(e-binop @1-55-1-67 (op "formatUser")
(e-ident @1-55-1-58 (qaul "") (raw "age"))
(e-apply @1-58-1-66
(e-ident @1-58-1-64 (qaul "") (raw ".toStr")))))
(e-string-part @1-67-1-90 (raw " years old) - Contact: "))
(e-field-access @1-92-1-108
(e-binop @1-92-1-108 (op "formatUser")
(e-ident @1-92-1-97 (qaul "") (raw "email"))
(e-apply @1-97-1-107
(e-ident @1-97-1-105 (qaul "") (raw ".display")))))
(e-string-part @1-108-1-108 (raw "")))))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
~~~

View file

@ -0,0 +1,36 @@
# META
~~~ini
description=Record field access with function call
type=expr
~~~
# SOURCE
~~~roc
(person.transform)(42)
~~~
# PROBLEMS
**UNDEFINED VARIABLE**
Nothing is named `person` in this scope.
Is there an `import` or `exposing` missing up-top?
# TOKENS
~~~zig
OpenRound(1:1-1:2),LowerIdent(1:2-1:8),NoSpaceDotLowerIdent(1:8-1:18),CloseRound(1:18-1:19),NoSpaceOpenRound(1:19-1:20),Int(1:20-1:22),CloseRound(1:22-1:23),EndOfFile(1:23-1:23),
~~~
# PARSE
~~~clojure
(e-apply @1-1-1-23
(e-tuple @1-1-1-19
(e-field-access @1-2-1-19
(e-binop @1-2-1-19 (op "(")
(e-ident @1-2-1-8 (qaul "") (raw "person"))
(e-ident @1-8-1-18 (qaul "") (raw ".transform")))))
(e-int @1-20-1-22 (raw "42")))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(expr (id 79) (type "*"))
~~~

View file

@ -0,0 +1,35 @@
# META
~~~ini
description=Record field access used in expressions (dot-access)
type=expr
~~~
# SOURCE
~~~roc
person.age + 5
~~~
# PROBLEMS
**UNDEFINED VARIABLE**
Nothing is named `person` in this scope.
Is there an `import` or `exposing` missing up-top?
# TOKENS
~~~zig
LowerIdent(1:1-1:7),NoSpaceDotLowerIdent(1:7-1:11),OpPlus(1:12-1:13),Int(1:14-1:15),EndOfFile(1:15-1:15),
~~~
# PARSE
~~~clojure
(e-binop @1-1-1-15 (op "+")
(e-field-access @1-1-1-13
(e-binop @1-1-1-13 (op "person")
(e-ident @1-1-1-7 (qaul "") (raw "person"))
(e-ident @1-7-1-11 (qaul "") (raw ".age"))))
(e-int @1-14-1-15 (raw "5")))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(expr (id 77) (type "*"))
~~~

View file

@ -0,0 +1,36 @@
# META
~~~ini
description=Chained record field (dot-access)
type=expr
~~~
# SOURCE
~~~roc
person.address.street
~~~
# PROBLEMS
**UNDEFINED VARIABLE**
Nothing is named `person` in this scope.
Is there an `import` or `exposing` missing up-top?
# TOKENS
~~~zig
LowerIdent(1:1-1:7),NoSpaceDotLowerIdent(1:7-1:15),NoSpaceDotLowerIdent(1:15-1:22),EndOfFile(1:22-1:22),
~~~
# PARSE
~~~clojure
(e-field-access @1-1-1-22
(e-binop @1-1-1-22 (op "person")
(e-field-access @1-1-1-22
(e-binop @1-1-1-22 (op "person")
(e-ident @1-1-1-7 (qaul "") (raw "person"))
(e-ident @1-7-1-15 (qaul "") (raw ".address"))))
(e-ident @1-15-1-22 (qaul "") (raw ".street"))))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(expr (id 75) (type "*"))
~~~

View file

@ -0,0 +1,349 @@
# META
~~~ini
description=Record with special character fields (error cases)
type=expr
~~~
# SOURCE
~~~roc
{
_privateField: "leading underscore",
field_: "trailing underscore",
PascalCase: "pascal",
kebab-case: "kebab",
field$special: "dollar",
field@symbol: "at symbol",
}
~~~
# PROBLEMS
**UNEXPECTED TOKEN IN TYPE ANNOTATION**
The token **"leading underscore** is not expected in a type annotation.
Type annotations should contain types like _Str_, _Num a_, or _List U64_.
Here is the problematic code:
**record_different_fields_error.md:2:20:2:39:**
```roc
_privateField: "leading underscore",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **leading underscore"** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:2:21:2:40:**
```roc
_privateField: "leading underscore",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **",** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:2:39:2:41:**
```roc
_privateField: "leading underscore",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:2:40:2:40:**
```roc
_privateField: "leading underscore",
```
**UNEXPECTED TOKEN IN TYPE ANNOTATION**
The token **"trailing underscore** is not expected in a type annotation.
Type annotations should contain types like _Str_, _Num a_, or _List U64_.
Here is the problematic code:
**record_different_fields_error.md:3:13:3:33:**
```roc
field_: "trailing underscore",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **trailing underscore"** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:3:14:3:34:**
```roc
field_: "trailing underscore",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **",** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:3:33:3:35:**
```roc
field_: "trailing underscore",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:3:34:3:34:**
```roc
field_: "trailing underscore",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **: "** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:4:15:4:18:**
```roc
PascalCase: "pascal",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:4:25:4:25:**
```roc
PascalCase: "pascal",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **: "** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:5:15:5:18:**
```roc
kebab-case: "kebab",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:5:24:5:24:**
```roc
kebab-case: "kebab",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **$special** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:6:10:6:18:**
```roc
field$special: "dollar",
```
**UNEXPECTED TOKEN IN TYPE ANNOTATION**
The token **"dollar** is not expected in a type annotation.
Type annotations should contain types like _Str_, _Num a_, or _List U64_.
Here is the problematic code:
**record_different_fields_error.md:6:20:6:27:**
```roc
field$special: "dollar",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **dollar"** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:6:21:6:28:**
```roc
field$special: "dollar",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **",** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:6:27:6:29:**
```roc
field$special: "dollar",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:6:28:6:28:**
```roc
field$special: "dollar",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **@symbol:** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:7:10:7:18:**
```roc
field@symbol: "at symbol",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **: "** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:7:17:7:20:**
```roc
field@symbol: "at symbol",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_error.md:7:30:7:30:**
```roc
field@symbol: "at symbol",
```
**MALFORMED TYPE**
This type annotation is malformed or contains invalid syntax.
**MALFORMED TYPE**
This type annotation is malformed or contains invalid syntax.
**UNDEFINED VARIABLE**
Nothing is named `kebab` in this scope.
Is there an `import` or `exposing` missing up-top?
**UNDEFINED VARIABLE**
Nothing is named `case` in this scope.
Is there an `import` or `exposing` missing up-top?
**UNDEFINED VARIABLE**
Nothing is named `field` in this scope.
Is there an `import` or `exposing` missing up-top?
**MALFORMED TYPE**
This type annotation is malformed or contains invalid syntax.
**UNDEFINED VARIABLE**
Nothing is named `field` in this scope.
Is there an `import` or `exposing` missing up-top?
# TOKENS
~~~zig
OpenCurly(1:1-1:2),Newline(1:1-1:1),
NamedUnderscore(2:5-2:18),OpColon(2:18-2:19),StringStart(2:20-2:21),StringPart(2:21-2:39),StringEnd(2:39-2:40),Comma(2:40-2:41),Newline(1:1-1:1),
LowerIdent(3:5-3:11),OpColon(3:11-3:12),StringStart(3:13-3:14),StringPart(3:14-3:33),StringEnd(3:33-3:34),Comma(3:34-3:35),Newline(1:1-1:1),
UpperIdent(4:5-4:15),OpColon(4:15-4:16),StringStart(4:17-4:18),StringPart(4:18-4:24),StringEnd(4:24-4:25),Comma(4:25-4:26),Newline(1:1-1:1),
LowerIdent(5:5-5:10),OpBinaryMinus(5:10-5:11),LowerIdent(5:11-5:15),OpColon(5:15-5:16),StringStart(5:17-5:18),StringPart(5:18-5:23),StringEnd(5:23-5:24),Comma(5:24-5:25),Newline(1:1-1:1),
LowerIdent(6:5-6:10),MalformedUnknownToken(6:10-6:11),LowerIdent(6:11-6:18),OpColon(6:18-6:19),StringStart(6:20-6:21),StringPart(6:21-6:27),StringEnd(6:27-6:28),Comma(6:28-6:29),Newline(1:1-1:1),
LowerIdent(7:5-7:10),OpaqueName(7:10-7:17),OpColon(7:17-7:18),StringStart(7:19-7:20),StringPart(7:20-7:29),StringEnd(7:29-7:30),Comma(7:30-7:31),Newline(1:1-1:1),
CloseCurly(8:1-8:2),EndOfFile(8:2-8:2),
~~~
# PARSE
~~~clojure
(e-block @1-1-8-2
(statements
(s-type-anno @2-5-2-39 (name "_privateField")
(ty-malformed @2-20-2-39 (tag "ty_anno_unexpected_token")))
(e-malformed @2-21-2-40 (reason "expr_unexpected_token"))
(e-malformed @2-39-2-41 (reason "expr_unexpected_token"))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(s-type-anno @3-5-3-33 (name "field_")
(ty-malformed @3-13-3-33 (tag "ty_anno_unexpected_token")))
(e-malformed @3-14-3-34 (reason "expr_unexpected_token"))
(e-malformed @3-33-3-35 (reason "expr_unexpected_token"))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(e-tag @4-5-4-15 (raw "PascalCase"))
(e-malformed @4-15-4-18 (reason "expr_unexpected_token"))
(e-string @4-17-4-25
(e-string-part @4-18-4-24 (raw "pascal")))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(e-binop @5-5-5-16 (op "-")
(e-ident @5-5-5-10 (qaul "") (raw "kebab"))
(e-ident @5-11-5-15 (qaul "") (raw "case")))
(e-malformed @5-15-5-18 (reason "expr_unexpected_token"))
(e-string @5-17-5-24
(e-string-part @5-18-5-23 (raw "kebab")))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(e-ident @6-5-6-10 (qaul "") (raw "field"))
(e-malformed @6-10-6-18 (reason "expr_unexpected_token"))
(s-type-anno @6-11-6-27 (name "special")
(ty-malformed @6-20-6-27 (tag "ty_anno_unexpected_token")))
(e-malformed @6-21-6-28 (reason "expr_unexpected_token"))
(e-malformed @6-27-6-29 (reason "expr_unexpected_token"))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(e-ident @7-5-7-10 (qaul "") (raw "field"))
(e-malformed @7-10-7-18 (reason "expr_unexpected_token"))
(e-malformed @7-17-7-20 (reason "expr_unexpected_token"))
(e-string @7-19-7-30
(e-string-part @7-20-7-29 (raw "at symbol")))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))))
~~~
# FORMATTED
~~~roc
{
_privateField :
field_ :
PascalCase
"pascal"
kebab - case
"kebab"
field
special :
field
"at symbol"
}
~~~
# TYPES
~~~clojure
(expr (id 109) (type "*"))
~~~

View file

@ -0,0 +1,50 @@
# META
~~~ini
description=Record with special character fields (ok case)
type=expr
~~~
# SOURCE
~~~roc
{
field_with_underscores: "underscore",
field123: "numbers",
camelCase: "camel",
}
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize record expression
# TOKENS
~~~zig
OpenCurly(1:1-1:2),Newline(1:1-1:1),
LowerIdent(2:5-2:27),OpColon(2:27-2:28),StringStart(2:29-2:30),StringPart(2:30-2:40),StringEnd(2:40-2:41),Comma(2:41-2:42),Newline(1:1-1:1),
LowerIdent(3:5-3:13),OpColon(3:13-3:14),StringStart(3:15-3:16),StringPart(3:16-3:23),StringEnd(3:23-3:24),Comma(3:24-3:25),Newline(1:1-1:1),
LowerIdent(4:5-4:14),OpColon(4:14-4:15),StringStart(4:16-4:17),StringPart(4:17-4:22),StringEnd(4:22-4:23),Comma(4:23-4:24),Newline(1:1-1:1),
CloseCurly(5:1-5:2),EndOfFile(5:2-5:2),
~~~
# PARSE
~~~clojure
(e-record @1-1-5-2
(field (field "field_with_underscores") (optional false)
(e-string @2-29-2-41
(e-string-part @2-30-2-40 (raw "underscore"))))
(field (field "field123") (optional false)
(e-string @3-15-3-24
(e-string-part @3-16-3-23 (raw "numbers"))))
(field (field "camelCase") (optional false)
(e-string @4-16-4-23
(e-string-part @4-17-4-22 (raw "camel")))))
~~~
# FORMATTED
~~~roc
{
field_with_underscores: "underscore",
field123: "numbers",
camelCase: "camel",
}
~~~
# TYPES
~~~clojure
(expr (id 73) (type "Error"))
~~~

View file

@ -0,0 +1,290 @@
# META
~~~ini
description=Record with reserved keyword fields (error case)
type=expr
~~~
# SOURCE
~~~roc
{
if: "conditional",
when: "pattern match",
expect: "test assertion",
import: "module load",
and: Bool.true,
or: Bool.false,
}
~~~
# PROBLEMS
**UNEXPECTED TOKEN IN EXPRESSION**
The token **: "** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:2:7:2:10:**
```roc
if: "conditional",
```
**PARSE ERROR**
A parsing error occurred: `no_else`
This is an unexpected parsing error. Please check your syntax.
Here is the problematic code:
**record_different_fields_reserved_error.md:2:22:2:22:**
```roc
if: "conditional",
```
**UNEXPECTED TOKEN IN TYPE ANNOTATION**
The token **"pattern match** is not expected in a type annotation.
Type annotations should contain types like _Str_, _Num a_, or _List U64_.
Here is the problematic code:
**record_different_fields_reserved_error.md:3:11:3:25:**
```roc
when: "pattern match",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **pattern match"** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:3:12:3:26:**
```roc
when: "pattern match",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **",** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:3:25:3:27:**
```roc
when: "pattern match",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:3:26:3:26:**
```roc
when: "pattern match",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **: "** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:4:11:4:14:**
```roc
expect: "test assertion",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:4:29:4:29:**
```roc
expect: "test assertion",
```
**IMPORT MUST BE TOP LEVEL**
Import statements must appear at the top level of a module.
Move this import to the top of the file, after the module header but before any definitions.
Here is the problematic code:
**record_different_fields_reserved_error.md:5:5:5:12:**
```roc
import: "module load",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **: "** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:5:11:5:14:**
```roc
import: "module load",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:5:26:5:26:**
```roc
import: "module load",
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **and:** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:6:5:6:9:**
```roc
and: Bool.true,
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **: Bool** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:6:8:6:14:**
```roc
and: Bool.true,
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:6:19:6:19:**
```roc
and: Bool.true,
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **or:** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:7:5:7:8:**
```roc
or: Bool.false,
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **: Bool** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:7:7:7:13:**
```roc
or: Bool.false,
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_different_fields_reserved_error.md:7:19:7:19:**
```roc
or: Bool.false,
```
**MALFORMED TYPE**
This type annotation is malformed or contains invalid syntax.
**NOT IMPLEMENTED**
This feature is not yet implemented: statement type in block
**NOT IMPLEMENTED**
This feature is not yet implemented: statement type in block
**UNDEFINED VARIABLE**
Nothing is named `true` in this scope.
Is there an `import` or `exposing` missing up-top?
**UNDEFINED VARIABLE**
Nothing is named `false` in this scope.
Is there an `import` or `exposing` missing up-top?
# TOKENS
~~~zig
OpenCurly(1:1-1:2),Newline(1:1-1:1),
KwIf(2:5-2:7),OpColon(2:7-2:8),StringStart(2:9-2:10),StringPart(2:10-2:21),StringEnd(2:21-2:22),Comma(2:22-2:23),Newline(1:1-1:1),
LowerIdent(3:5-3:9),OpColon(3:9-3:10),StringStart(3:11-3:12),StringPart(3:12-3:25),StringEnd(3:25-3:26),Comma(3:26-3:27),Newline(1:1-1:1),
KwExpect(4:5-4:11),OpColon(4:11-4:12),StringStart(4:13-4:14),StringPart(4:14-4:28),StringEnd(4:28-4:29),Comma(4:29-4:30),Newline(1:1-1:1),
KwImport(5:5-5:11),OpColon(5:11-5:12),StringStart(5:13-5:14),StringPart(5:14-5:25),StringEnd(5:25-5:26),Comma(5:26-5:27),Newline(1:1-1:1),
OpAnd(6:5-6:8),OpColon(6:8-6:9),UpperIdent(6:10-6:14),NoSpaceDotLowerIdent(6:14-6:19),Comma(6:19-6:20),Newline(1:1-1:1),
OpOr(7:5-7:7),OpColon(7:7-7:8),UpperIdent(7:9-7:13),NoSpaceDotLowerIdent(7:13-7:19),Comma(7:19-7:20),Newline(1:1-1:1),
CloseCurly(8:1-8:2),EndOfFile(8:2-8:2),
~~~
# PARSE
~~~clojure
(e-block @1-1-8-2
(statements
(e-malformed @1-1-1-1 (reason "no_else"))
(s-type-anno @3-5-3-25 (name "when")
(ty-malformed @3-11-3-25 (tag "ty_anno_unexpected_token")))
(e-malformed @3-12-3-26 (reason "expr_unexpected_token"))
(e-malformed @3-25-3-27 (reason "expr_unexpected_token"))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(s-expect @4-5-4-14
(e-malformed @4-11-4-14 (reason "expr_unexpected_token")))
(e-string @4-13-4-29
(e-string-part @4-14-4-28 (raw "test assertion")))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(s-malformed @5-5-5-12 (tag "import_must_be_top_level"))
(e-malformed @5-11-5-14 (reason "expr_unexpected_token"))
(e-string @5-13-5-26
(e-string-part @5-14-5-25 (raw "module load")))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(e-malformed @6-5-6-9 (reason "expr_unexpected_token"))
(e-malformed @6-8-6-14 (reason "expr_unexpected_token"))
(e-ident @6-10-6-19 (qaul "Bool") (raw ".true"))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(e-malformed @7-5-7-8 (reason "expr_unexpected_token"))
(e-malformed @7-7-7-13 (reason "expr_unexpected_token"))
(e-ident @7-9-7-19 (qaul "Bool") (raw ".false"))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))))
~~~
# FORMATTED
~~~roc
{
when :
expect
"test assertion"
"module load"
Bool.true
Bool.false
}
~~~
# TYPES
~~~clojure
(expr (id 93) (type "*"))
~~~

View file

@ -0,0 +1,112 @@
# META
~~~ini
description=Record update syntax
type=expr
~~~
# SOURCE
~~~roc
{ person &
age: 31,
active: Bool.true,
}
~~~
# PROBLEMS
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_extension_update.md:1:10:1:10:**
```roc
{ person &
```
**UNEXPECTED TOKEN IN TYPE ANNOTATION**
The token **31,** is not expected in a type annotation.
Type annotations should contain types like _Str_, _Num a_, or _List U64_.
Here is the problematic code:
**record_extension_update.md:2:10:2:13:**
```roc
age: 31,
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_extension_update.md:2:12:2:12:**
```roc
age: 31,
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **.true,** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_extension_update.md:3:17:3:23:**
```roc
active: Bool.true,
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**record_extension_update.md:3:22:3:22:**
```roc
active: Bool.true,
```
**UNDEFINED VARIABLE**
Nothing is named `person` in this scope.
Is there an `import` or `exposing` missing up-top?
**MALFORMED TYPE**
This type annotation is malformed or contains invalid syntax.
# TOKENS
~~~zig
OpenCurly(1:1-1:2),LowerIdent(1:3-1:9),OpAmpersand(1:10-1:11),Newline(1:1-1:1),
LowerIdent(2:5-2:8),OpColon(2:8-2:9),Int(2:10-2:12),Comma(2:12-2:13),Newline(1:1-1:1),
LowerIdent(3:5-3:11),OpColon(3:11-3:12),UpperIdent(3:13-3:17),NoSpaceDotLowerIdent(3:17-3:22),Comma(3:22-3:23),Newline(1:1-1:1),
CloseCurly(4:1-4:2),EndOfFile(4:2-4:2),
~~~
# PARSE
~~~clojure
(e-block @1-1-4-2
(statements
(e-ident @1-3-1-9 (qaul "") (raw "person"))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(s-type-anno @2-5-2-13 (name "age")
(ty-malformed @2-10-2-13 (tag "ty_anno_unexpected_token")))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))
(s-type-anno @3-5-3-22 (name "active")
(ty (name "Bool")))
(e-malformed @3-17-3-23 (reason "expr_unexpected_token"))
(e-malformed @1-1-1-1 (reason "expr_unexpected_token"))))
~~~
# FORMATTED
~~~roc
{
person
age :
active : Bool
}
~~~
# TYPES
~~~clojure
(expr (id 83) (type "*"))
~~~

View file

@ -0,0 +1,37 @@
# META
~~~ini
description=Record construction using mixed shorthand and explicit record fields
type=expr
~~~
# SOURCE
~~~roc
{ name, age: 30, email, status: "active", balance }
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize record expression
# TOKENS
~~~zig
OpenCurly(1:1-1:2),LowerIdent(1:3-1:7),Comma(1:7-1:8),LowerIdent(1:9-1:12),OpColon(1:12-1:13),Int(1:14-1:16),Comma(1:16-1:17),LowerIdent(1:18-1:23),Comma(1:23-1:24),LowerIdent(1:25-1:31),OpColon(1:31-1:32),StringStart(1:33-1:34),StringPart(1:34-1:40),StringEnd(1:40-1:41),Comma(1:41-1:42),LowerIdent(1:43-1:50),CloseCurly(1:51-1:52),EndOfFile(1:52-1:52),
~~~
# PARSE
~~~clojure
(e-record @1-1-1-52
(field (field "name") (optional false))
(field (field "age") (optional false)
(e-int @1-14-1-16 (raw "30")))
(field (field "email") (optional false))
(field (field "status") (optional false)
(e-string @1-33-1-41
(e-string-part @1-34-1-40 (raw "active"))))
(field (field "balance") (optional false)))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(expr (id 73) (type "Error"))
~~~

View file

@ -0,0 +1,43 @@
# META
~~~ini
description=Record with mixed field types
type=expr
~~~
# SOURCE
~~~roc
{ name: "Alice", age: 30, active: Bool.true, scores: [95, 87, 92], balance: 1250.75 }
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize record expression
# TOKENS
~~~zig
OpenCurly(1:1-1:2),LowerIdent(1:3-1:7),OpColon(1:7-1:8),StringStart(1:9-1:10),StringPart(1:10-1:15),StringEnd(1:15-1:16),Comma(1:16-1:17),LowerIdent(1:18-1:21),OpColon(1:21-1:22),Int(1:23-1:25),Comma(1:25-1:26),LowerIdent(1:27-1:33),OpColon(1:33-1:34),UpperIdent(1:35-1:39),NoSpaceDotLowerIdent(1:39-1:44),Comma(1:44-1:45),LowerIdent(1:46-1:52),OpColon(1:52-1:53),OpenSquare(1:54-1:55),Int(1:55-1:57),Comma(1:57-1:58),Int(1:59-1:61),Comma(1:61-1:62),Int(1:63-1:65),CloseSquare(1:65-1:66),Comma(1:66-1:67),LowerIdent(1:68-1:75),OpColon(1:75-1:76),Float(1:77-1:84),CloseCurly(1:85-1:86),EndOfFile(1:86-1:86),
~~~
# PARSE
~~~clojure
(e-record @1-1-1-86
(field (field "name") (optional false)
(e-string @1-9-1-16
(e-string-part @1-10-1-15 (raw "Alice"))))
(field (field "age") (optional false)
(e-int @1-23-1-25 (raw "30")))
(field (field "active") (optional false)
(e-ident @1-35-1-44 (qaul "Bool") (raw ".true")))
(field (field "scores") (optional false)
(e-list @1-54-1-66
(e-int @1-55-1-57 (raw "95"))
(e-int @1-59-1-61 (raw "87"))
(e-int @1-63-1-65 (raw "92"))))
(field (field "balance") (optional false)
(e-frac @1-77-1-84 (raw "1250.75"))))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(expr (id 73) (type "Error"))
~~~

View file

@ -0,0 +1,96 @@
# META
~~~ini
description=Nested record creation
type=expr
~~~
# SOURCE
~~~roc
{
person: { name: "Alice", age: 30 },
address: {
street: "123 Main St",
city: "Springfield",
coordinates: { lat: 42.1234, lng: -71.5678 },
},
contact: {
email: "alice@example.com",
phone: { home: "555-1234", work: "555-5678" },
},
}
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize record expression
# TOKENS
~~~zig
OpenCurly(1:1-1:2),Newline(1:1-1:1),
LowerIdent(2:5-2:11),OpColon(2:11-2:12),OpenCurly(2:13-2:14),LowerIdent(2:15-2:19),OpColon(2:19-2:20),StringStart(2:21-2:22),StringPart(2:22-2:27),StringEnd(2:27-2:28),Comma(2:28-2:29),LowerIdent(2:30-2:33),OpColon(2:33-2:34),Int(2:35-2:37),CloseCurly(2:38-2:39),Comma(2:39-2:40),Newline(1:1-1:1),
LowerIdent(3:5-3:12),OpColon(3:12-3:13),OpenCurly(3:14-3:15),Newline(1:1-1:1),
LowerIdent(4:9-4:15),OpColon(4:15-4:16),StringStart(4:17-4:18),StringPart(4:18-4:29),StringEnd(4:29-4:30),Comma(4:30-4:31),Newline(1:1-1:1),
LowerIdent(5:9-5:13),OpColon(5:13-5:14),StringStart(5:15-5:16),StringPart(5:16-5:27),StringEnd(5:27-5:28),Comma(5:28-5:29),Newline(1:1-1:1),
LowerIdent(6:9-6:20),OpColon(6:20-6:21),OpenCurly(6:22-6:23),LowerIdent(6:24-6:27),OpColon(6:27-6:28),Float(6:29-6:36),Comma(6:36-6:37),LowerIdent(6:38-6:41),OpColon(6:41-6:42),Float(6:43-6:51),CloseCurly(6:52-6:53),Comma(6:53-6:54),Newline(1:1-1:1),
CloseCurly(7:5-7:6),Comma(7:6-7:7),Newline(1:1-1:1),
LowerIdent(8:5-8:12),OpColon(8:12-8:13),OpenCurly(8:14-8:15),Newline(1:1-1:1),
LowerIdent(9:9-9:14),OpColon(9:14-9:15),StringStart(9:16-9:17),StringPart(9:17-9:34),StringEnd(9:34-9:35),Comma(9:35-9:36),Newline(1:1-1:1),
LowerIdent(10:9-10:14),OpColon(10:14-10:15),OpenCurly(10:16-10:17),LowerIdent(10:18-10:22),OpColon(10:22-10:23),StringStart(10:24-10:25),StringPart(10:25-10:33),StringEnd(10:33-10:34),Comma(10:34-10:35),LowerIdent(10:36-10:40),OpColon(10:40-10:41),StringStart(10:42-10:43),StringPart(10:43-10:51),StringEnd(10:51-10:52),CloseCurly(10:53-10:54),Comma(10:54-10:55),Newline(1:1-1:1),
CloseCurly(11:5-11:6),Comma(11:6-11:7),Newline(1:1-1:1),
CloseCurly(12:1-12:2),EndOfFile(12:2-12:2),
~~~
# PARSE
~~~clojure
(e-record @1-1-12-2
(field (field "person") (optional false)
(e-record @2-13-2-39
(field (field "name") (optional false)
(e-string @2-21-2-28
(e-string-part @2-22-2-27 (raw "Alice"))))
(field (field "age") (optional false)
(e-int @2-35-2-37 (raw "30")))))
(field (field "address") (optional false)
(e-record @3-14-7-6
(field (field "street") (optional false)
(e-string @4-17-4-30
(e-string-part @4-18-4-29 (raw "123 Main St"))))
(field (field "city") (optional false)
(e-string @5-15-5-28
(e-string-part @5-16-5-27 (raw "Springfield"))))
(field (field "coordinates") (optional false)
(e-record @6-22-6-53
(field (field "lat") (optional false)
(e-frac @6-29-6-36 (raw "42.1234")))
(field (field "lng") (optional false)
(e-frac @6-43-6-51 (raw "-71.5678")))))))
(field (field "contact") (optional false)
(e-record @8-14-11-6
(field (field "email") (optional false)
(e-string @9-16-9-35
(e-string-part @9-17-9-34 (raw "alice@example.com"))))
(field (field "phone") (optional false)
(e-record @10-16-10-54
(field (field "home") (optional false)
(e-string @10-24-10-34
(e-string-part @10-25-10-33 (raw "555-1234"))))
(field (field "work") (optional false)
(e-string @10-42-10-52
(e-string-part @10-43-10-51 (raw "555-5678")))))))))
~~~
# FORMATTED
~~~roc
{
person: { name: "Alice", age: 30 },
address: {
street: "123 Main St",
city: "Springfield",
coordinates: { lat: 42.1234, lng: -71.5678 },
},
contact: {
email: "alice@example.com",
phone: { home: "555-1234", work: "555-5678" },
},
}
~~~
# TYPES
~~~clojure
(expr (id 73) (type "Error"))
~~~

View file

@ -0,0 +1,33 @@
# META
~~~ini
description=Record construction using shorthand field syntax
type=expr
~~~
# SOURCE
~~~roc
{ name, age, email, active }
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize record expression
# TOKENS
~~~zig
OpenCurly(1:1-1:2),LowerIdent(1:3-1:7),Comma(1:7-1:8),LowerIdent(1:9-1:12),Comma(1:12-1:13),LowerIdent(1:14-1:19),Comma(1:19-1:20),LowerIdent(1:21-1:27),CloseCurly(1:28-1:29),EndOfFile(1:29-1:29),
~~~
# PARSE
~~~clojure
(e-record @1-1-1-29
(field (field "name") (optional false))
(field (field "age") (optional false))
(field (field "email") (optional false))
(field (field "active") (optional false)))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(expr (id 73) (type "Error"))
~~~

View file

@ -0,0 +1,147 @@
# META
~~~ini
description=Record construction with complex field types including lists and tag unions
type=expr
~~~
# SOURCE
~~~roc
{
name: "Alice",
scores: [95, 87, 92, 78],
status: Active({ since: "2023-01-15" }),
preferences: { theme: Dark, notifications: Email("alice@example.com") },
metadata: Ok({
tags: ["developer", "senior", "fullstack"],
permissions: [Read, Write, Admin],
}),
callback: |x| x + 1,
nested: {
items: [Some("first"), None, Some("third")],
result: Success({ data: [1, 2, 3], timestamp: "2024-01-01" }),
},
}
~~~
# PROBLEMS
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize record expression
# TOKENS
~~~zig
OpenCurly(1:1-1:2),Newline(1:1-1:1),
LowerIdent(2:5-2:9),OpColon(2:9-2:10),StringStart(2:11-2:12),StringPart(2:12-2:17),StringEnd(2:17-2:18),Comma(2:18-2:19),Newline(1:1-1:1),
LowerIdent(3:5-3:11),OpColon(3:11-3:12),OpenSquare(3:13-3:14),Int(3:14-3:16),Comma(3:16-3:17),Int(3:18-3:20),Comma(3:20-3:21),Int(3:22-3:24),Comma(3:24-3:25),Int(3:26-3:28),CloseSquare(3:28-3:29),Comma(3:29-3:30),Newline(1:1-1:1),
LowerIdent(4:5-4:11),OpColon(4:11-4:12),UpperIdent(4:13-4:19),NoSpaceOpenRound(4:19-4:20),OpenCurly(4:20-4:21),LowerIdent(4:22-4:27),OpColon(4:27-4:28),StringStart(4:29-4:30),StringPart(4:30-4:40),StringEnd(4:40-4:41),CloseCurly(4:42-4:43),CloseRound(4:43-4:44),Comma(4:44-4:45),Newline(1:1-1:1),
LowerIdent(5:5-5:16),OpColon(5:16-5:17),OpenCurly(5:18-5:19),LowerIdent(5:20-5:25),OpColon(5:25-5:26),UpperIdent(5:27-5:31),Comma(5:31-5:32),LowerIdent(5:33-5:46),OpColon(5:46-5:47),UpperIdent(5:48-5:53),NoSpaceOpenRound(5:53-5:54),StringStart(5:54-5:55),StringPart(5:55-5:72),StringEnd(5:72-5:73),CloseRound(5:73-5:74),CloseCurly(5:75-5:76),Comma(5:76-5:77),Newline(1:1-1:1),
LowerIdent(6:5-6:13),OpColon(6:13-6:14),UpperIdent(6:15-6:17),NoSpaceOpenRound(6:17-6:18),OpenCurly(6:18-6:19),Newline(1:1-1:1),
LowerIdent(7:9-7:13),OpColon(7:13-7:14),OpenSquare(7:15-7:16),StringStart(7:16-7:17),StringPart(7:17-7:26),StringEnd(7:26-7:27),Comma(7:27-7:28),StringStart(7:29-7:30),StringPart(7:30-7:36),StringEnd(7:36-7:37),Comma(7:37-7:38),StringStart(7:39-7:40),StringPart(7:40-7:49),StringEnd(7:49-7:50),CloseSquare(7:50-7:51),Comma(7:51-7:52),Newline(1:1-1:1),
LowerIdent(8:9-8:20),OpColon(8:20-8:21),OpenSquare(8:22-8:23),UpperIdent(8:23-8:27),Comma(8:27-8:28),UpperIdent(8:29-8:34),Comma(8:34-8:35),UpperIdent(8:36-8:41),CloseSquare(8:41-8:42),Comma(8:42-8:43),Newline(1:1-1:1),
CloseCurly(9:5-9:6),CloseRound(9:6-9:7),Comma(9:7-9:8),Newline(1:1-1:1),
LowerIdent(10:5-10:13),OpColon(10:13-10:14),OpBar(10:15-10:16),LowerIdent(10:16-10:17),OpBar(10:17-10:18),LowerIdent(10:19-10:20),OpPlus(10:21-10:22),Int(10:23-10:24),Comma(10:24-10:25),Newline(1:1-1:1),
LowerIdent(11:5-11:11),OpColon(11:11-11:12),OpenCurly(11:13-11:14),Newline(1:1-1:1),
LowerIdent(12:9-12:14),OpColon(12:14-12:15),OpenSquare(12:16-12:17),UpperIdent(12:17-12:21),NoSpaceOpenRound(12:21-12:22),StringStart(12:22-12:23),StringPart(12:23-12:28),StringEnd(12:28-12:29),CloseRound(12:29-12:30),Comma(12:30-12:31),UpperIdent(12:32-12:36),Comma(12:36-12:37),UpperIdent(12:38-12:42),NoSpaceOpenRound(12:42-12:43),StringStart(12:43-12:44),StringPart(12:44-12:49),StringEnd(12:49-12:50),CloseRound(12:50-12:51),CloseSquare(12:51-12:52),Comma(12:52-12:53),Newline(1:1-1:1),
LowerIdent(13:9-13:15),OpColon(13:15-13:16),UpperIdent(13:17-13:24),NoSpaceOpenRound(13:24-13:25),OpenCurly(13:25-13:26),LowerIdent(13:27-13:31),OpColon(13:31-13:32),OpenSquare(13:33-13:34),Int(13:34-13:35),Comma(13:35-13:36),Int(13:37-13:38),Comma(13:38-13:39),Int(13:40-13:41),CloseSquare(13:41-13:42),Comma(13:42-13:43),LowerIdent(13:44-13:53),OpColon(13:53-13:54),StringStart(13:55-13:56),StringPart(13:56-13:66),StringEnd(13:66-13:67),CloseCurly(13:68-13:69),CloseRound(13:69-13:70),Comma(13:70-13:71),Newline(1:1-1:1),
CloseCurly(14:5-14:6),Comma(14:6-14:7),Newline(1:1-1:1),
CloseCurly(15:1-15:2),EndOfFile(15:2-15:2),
~~~
# PARSE
~~~clojure
(e-record @1-1-15-2
(field (field "name") (optional false)
(e-string @2-11-2-18
(e-string-part @2-12-2-17 (raw "Alice"))))
(field (field "scores") (optional false)
(e-list @3-13-3-29
(e-int @3-14-3-16 (raw "95"))
(e-int @3-18-3-20 (raw "87"))
(e-int @3-22-3-24 (raw "92"))
(e-int @3-26-3-28 (raw "78"))))
(field (field "status") (optional false)
(e-apply @4-13-4-44
(e-tag @4-13-4-19 (raw "Active"))
(e-record @4-20-4-43
(field (field "since") (optional false)
(e-string @4-29-4-41
(e-string-part @4-30-4-40 (raw "2023-01-15")))))))
(field (field "preferences") (optional false)
(e-record @5-18-5-76
(field (field "theme") (optional false)
(e-tag @5-27-5-31 (raw "Dark")))
(field (field "notifications") (optional false)
(e-apply @5-48-5-74
(e-tag @5-48-5-53 (raw "Email"))
(e-string @5-54-5-73
(e-string-part @5-55-5-72 (raw "alice@example.com")))))))
(field (field "metadata") (optional false)
(e-apply @6-15-9-7
(e-tag @6-15-6-17 (raw "Ok"))
(e-record @6-18-9-6
(field (field "tags") (optional false)
(e-list @7-15-7-51
(e-string @7-16-7-27
(e-string-part @7-17-7-26 (raw "developer")))
(e-string @7-29-7-37
(e-string-part @7-30-7-36 (raw "senior")))
(e-string @7-39-7-50
(e-string-part @7-40-7-49 (raw "fullstack")))))
(field (field "permissions") (optional false)
(e-list @8-22-8-42
(e-tag @8-23-8-27 (raw "Read"))
(e-tag @8-29-8-34 (raw "Write"))
(e-tag @8-36-8-41 (raw "Admin")))))))
(field (field "callback") (optional false)
(e-lambda @10-15-10-25
(args
(p-ident @10-16-10-17 (raw "x")))
(e-binop @10-19-10-25 (op "+")
(e-ident @10-19-10-20 (qaul "") (raw "x"))
(e-int @10-23-10-24 (raw "1")))))
(field (field "nested") (optional false)
(e-record @11-13-14-6
(field (field "items") (optional false)
(e-list @12-16-12-52
(e-apply @12-17-12-30
(e-tag @12-17-12-21 (raw "Some"))
(e-string @12-22-12-29
(e-string-part @12-23-12-28 (raw "first"))))
(e-tag @12-32-12-36 (raw "None"))
(e-apply @12-38-12-51
(e-tag @12-38-12-42 (raw "Some"))
(e-string @12-43-12-50
(e-string-part @12-44-12-49 (raw "third"))))))
(field (field "result") (optional false)
(e-apply @13-17-13-70
(e-tag @13-17-13-24 (raw "Success"))
(e-record @13-25-13-69
(field (field "data") (optional false)
(e-list @13-33-13-42
(e-int @13-34-13-35 (raw "1"))
(e-int @13-37-13-38 (raw "2"))
(e-int @13-40-13-41 (raw "3"))))
(field (field "timestamp") (optional false)
(e-string @13-55-13-67
(e-string-part @13-56-13-66 (raw "2024-01-01"))))))))))
~~~
# FORMATTED
~~~roc
{
name: "Alice",
scores: [95, 87, 92, 78],
status: Active({ since: "2023-01-15" }),
preferences: { theme: Dark, notifications: Email("alice@example.com") },
metadata: Ok(
{
tags: ["developer", "senior", "fullstack"],
permissions: [Read, Write, Admin],
},
),
callback: |x| x + 1,
nested: {
items: [Some("first"), None, Some("third")],
result: Success({ data: [1, 2, 3], timestamp: "2024-01-01" }),
},
}
~~~
# TYPES
~~~clojure
(expr (id 73) (type "Error"))
~~~

View file

@ -0,0 +1,39 @@
# META
~~~ini
description=Record in let binding statement
type=statement
~~~
# SOURCE
~~~roc
person = { name: "Alice", age: 30, email: "alice@example.com" }
~~~
# PROBLEMS
NIL
# TOKENS
~~~zig
LowerIdent(1:1-1:7),OpAssign(1:8-1:9),OpenCurly(1:10-1:11),LowerIdent(1:12-1:16),OpColon(1:16-1:17),StringStart(1:18-1:19),StringPart(1:19-1:24),StringEnd(1:24-1:25),Comma(1:25-1:26),LowerIdent(1:27-1:30),OpColon(1:30-1:31),Int(1:32-1:34),Comma(1:34-1:35),LowerIdent(1:36-1:41),OpColon(1:41-1:42),StringStart(1:43-1:44),StringPart(1:44-1:61),StringEnd(1:61-1:62),CloseCurly(1:63-1:64),EndOfFile(1:64-1:64),
~~~
# PARSE
~~~clojure
(s-decl @1-1-1-64
(p-ident @1-1-1-7 (raw "person"))
(e-record @1-10-1-64
(field (field "name") (optional false)
(e-string @1-18-1-25
(e-string-part @1-19-1-24 (raw "Alice"))))
(field (field "age") (optional false)
(e-int @1-32-1-34 (raw "30")))
(field (field "email") (optional false)
(e-string @1-43-1-62
(e-string-part @1-44-1-61 (raw "alice@example.com"))))))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
~~~

View file

@ -0,0 +1,129 @@
# META
~~~ini
description=Record destructuring in assignment statement
type=file
~~~
# SOURCE
~~~roc
{ name, age, email } = person
~~~
# PROBLEMS
**MISSING HEADER**
Roc files must start with a module header.
For example:
module [main]
or for an app:
app [main!] { pf: platform "../basic-cli/platform.roc" }
Here is the problematic code:
**statement_record_destructure.md:1:1:1:7:**
```roc
{ name, age, email } = person
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **, age** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**statement_record_destructure.md:1:7:1:12:**
```roc
{ name, age, email } = person
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **, email** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**statement_record_destructure.md:1:12:1:19:**
```roc
{ name, age, email } = person
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **} =** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**statement_record_destructure.md:1:20:1:23:**
```roc
{ name, age, email } = person
```
**UNEXPECTED TOKEN IN EXPRESSION**
The token **= person** is not expected in an expression.
Expressions can be identifiers, literals, function calls, or operators.
Here is the problematic code:
**statement_record_destructure.md:1:22:1:30:**
```roc
{ name, age, email } = person
```
**INVALID STATEMENT**
The statement **expr** is not allowed at the top level.
Only definitions, type annotations, and imports are allowed at the top level.
**INVALID STATEMENT**
The statement **expr** is not allowed at the top level.
Only definitions, type annotations, and imports are allowed at the top level.
**INVALID STATEMENT**
The statement **expr** is not allowed at the top level.
Only definitions, type annotations, and imports are allowed at the top level.
**INVALID STATEMENT**
The statement **expr** is not allowed at the top level.
Only definitions, type annotations, and imports are allowed at the top level.
**INVALID STATEMENT**
The statement **expr** is not allowed at the top level.
Only definitions, type annotations, and imports are allowed at the top level.
**INVALID STATEMENT**
The statement **expr** is not allowed at the top level.
Only definitions, type annotations, and imports are allowed at the top level.
**INVALID STATEMENT**
The statement **expr** is not allowed at the top level.
Only definitions, type annotations, and imports are allowed at the top level.
**INVALID STATEMENT**
The statement **expr** is not allowed at the top level.
Only definitions, type annotations, and imports are allowed at the top level.
# TOKENS
~~~zig
OpenCurly(1:1-1:2),LowerIdent(1:3-1:7),Comma(1:7-1:8),LowerIdent(1:9-1:12),Comma(1:12-1:13),LowerIdent(1:14-1:19),CloseCurly(1:20-1:21),OpAssign(1:22-1:23),LowerIdent(1:24-1:30),EndOfFile(1:30-1:30),
~~~
# PARSE
~~~clojure
(file @1-1-1-30
(malformed-header @1-1-1-7 (tag "missing_header"))
(statements
(e-ident @1-3-1-7 (qaul "") (raw "name"))
(e-malformed @1-7-1-12 (reason "expr_unexpected_token"))
(e-ident @1-9-1-12 (qaul "") (raw "age"))
(e-malformed @1-12-1-19 (reason "expr_unexpected_token"))
(e-ident @1-14-1-19 (qaul "") (raw "email"))
(e-malformed @1-20-1-23 (reason "expr_unexpected_token"))
(e-malformed @1-22-1-30 (reason "expr_unexpected_token"))
(e-ident @1-24-1-30 (qaul "") (raw "person"))))
~~~
# FORMATTED
~~~roc
nameageemailperson
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
~~~

View file

@ -0,0 +1,57 @@
# META
~~~ini
description=Constrained record type annotation
type=statement
~~~
# SOURCE
~~~roc
process_user! : { name : Str, age : U32, ..a } => Str
~~~
# PROBLEMS
**UNEXPECTED TOKEN IN TYPE ANNOTATION**
The token **..a** is not expected in a type annotation.
Type annotations should contain types like _Str_, _Num a_, or _List U64_.
Here is the problematic code:
**type_constrained_record.md:1:42:1:45:**
```roc
process_user! : { name : Str, age : U32, ..a } => Str
```
**PARSE ERROR**
A parsing error occurred: `expected_arrow`
This is an unexpected parsing error. Please check your syntax.
Here is the problematic code:
**type_constrained_record.md:1:37:1:41:**
```roc
process_user! : { name : Str, age : U32, ..a } => Str
```
# TOKENS
~~~zig
LowerIdent(1:1-1:14),OpColon(1:15-1:16),OpenCurly(1:17-1:18),LowerIdent(1:19-1:23),OpColon(1:24-1:25),UpperIdent(1:26-1:29),Comma(1:29-1:30),LowerIdent(1:31-1:34),OpColon(1:35-1:36),UpperIdent(1:37-1:40),Comma(1:40-1:41),DoubleDot(1:42-1:44),LowerIdent(1:44-1:45),CloseCurly(1:46-1:47),OpFatArrow(1:48-1:50),UpperIdent(1:51-1:54),EndOfFile(1:54-1:54),
~~~
# PARSE
~~~clojure
(s-type-anno @1-1-1-54 (name "process_user!")
(ty-fn @1-17-1-54
(ty-record @1-17-1-47
(anno-record-field @1-19-1-30 (name "name")
(ty (name "Str")))
(anno-record-field @1-31-1-47 (name "age")
(ty-malformed @1-37-1-47 (tag "expected_arrow"))))
(ty (name "Str"))))
~~~
# FORMATTED
~~~roc
process_user! : { name : Str, age : } => Str
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
~~~

View file

@ -0,0 +1,41 @@
# META
~~~ini
description=Function type annotation returning record
type=statement
~~~
# SOURCE
~~~roc
create_user! : Str, U32 => { name : Str, age : U32, id : U64, active : Bool }
~~~
# PROBLEMS
NIL
# TOKENS
~~~zig
LowerIdent(1:1-1:13),OpColon(1:14-1:15),UpperIdent(1:16-1:19),Comma(1:19-1:20),UpperIdent(1:21-1:24),OpFatArrow(1:25-1:27),OpenCurly(1:28-1:29),LowerIdent(1:30-1:34),OpColon(1:35-1:36),UpperIdent(1:37-1:40),Comma(1:40-1:41),LowerIdent(1:42-1:45),OpColon(1:46-1:47),UpperIdent(1:48-1:51),Comma(1:51-1:52),LowerIdent(1:53-1:55),OpColon(1:56-1:57),UpperIdent(1:58-1:61),Comma(1:61-1:62),LowerIdent(1:63-1:69),OpColon(1:70-1:71),UpperIdent(1:72-1:76),CloseCurly(1:77-1:78),EndOfFile(1:78-1:78),
~~~
# PARSE
~~~clojure
(s-type-anno @1-1-1-78 (name "create_user!")
(ty-fn @1-16-1-78
(ty (name "Str"))
(ty (name "U32"))
(ty-record @1-28-1-78
(anno-record-field @1-30-1-41 (name "name")
(ty (name "Str")))
(anno-record-field @1-42-1-52 (name "age")
(ty (name "U32")))
(anno-record-field @1-53-1-62 (name "id")
(ty (name "U64")))
(anno-record-field @1-63-1-78 (name "active")
(ty (name "Bool"))))))
~~~
# FORMATTED
~~~roc
NO CHANGE
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
~~~

View file

@ -0,0 +1,62 @@
# META
~~~ini
description=Open record type annotation
type=statement
~~~
# SOURCE
~~~roc
process_user! : { name : Str, age : U32, .. } => Str
~~~
# PROBLEMS
**UNEXPECTED TOKEN IN TYPE ANNOTATION**
The token **.. }** is not expected in a type annotation.
Type annotations should contain types like _Str_, _Num a_, or _List U64_.
Here is the problematic code:
**type_open_record.md:1:42:1:46:**
```roc
process_user! : { name : Str, age : U32, .. } => Str
```
**PARSE ERROR**
A parsing error occurred: `expected_arrow`
This is an unexpected parsing error. Please check your syntax.
Here is the problematic code:
**type_open_record.md:1:37:1:41:**
```roc
process_user! : { name : Str, age : U32, .. } => Str
```
**PARSE ERROR**
A parsing error occurred: `expected_ty_close_curly_or_comma`
This is an unexpected parsing error. Please check your syntax.
Here is the problematic code:
**type_open_record.md:1:47:1:53:**
```roc
process_user! : { name : Str, age : U32, .. } => Str
```
# TOKENS
~~~zig
LowerIdent(1:1-1:14),OpColon(1:15-1:16),OpenCurly(1:17-1:18),LowerIdent(1:19-1:23),OpColon(1:24-1:25),UpperIdent(1:26-1:29),Comma(1:29-1:30),LowerIdent(1:31-1:34),OpColon(1:35-1:36),UpperIdent(1:37-1:40),Comma(1:40-1:41),DoubleDot(1:42-1:44),CloseCurly(1:45-1:46),OpFatArrow(1:47-1:49),UpperIdent(1:50-1:53),EndOfFile(1:53-1:53),
~~~
# PARSE
~~~clojure
(s-type-anno @1-1-1-53 (name "process_user!")
(ty-malformed @1-47-1-53 (tag "expected_ty_close_curly_or_comma")))
~~~
# FORMATTED
~~~roc
process_user! :
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
~~~

View file

@ -0,0 +1,41 @@
# META
~~~ini
description=Function type annotation with record parameter
type=statement
~~~
# SOURCE
~~~roc
process_things : { name : Str, age : U32, thing: a }, (a -> Str) -> Str
~~~
# PROBLEMS
NIL
# TOKENS
~~~zig
LowerIdent(1:1-1:15),OpColon(1:16-1:17),OpenCurly(1:18-1:19),LowerIdent(1:20-1:24),OpColon(1:25-1:26),UpperIdent(1:27-1:30),Comma(1:30-1:31),LowerIdent(1:32-1:35),OpColon(1:36-1:37),UpperIdent(1:38-1:41),Comma(1:41-1:42),LowerIdent(1:43-1:48),OpColon(1:48-1:49),LowerIdent(1:50-1:51),CloseCurly(1:52-1:53),Comma(1:53-1:54),OpenRound(1:55-1:56),LowerIdent(1:56-1:57),OpArrow(1:58-1:60),UpperIdent(1:61-1:64),CloseRound(1:64-1:65),OpArrow(1:66-1:68),UpperIdent(1:69-1:72),EndOfFile(1:72-1:72),
~~~
# PARSE
~~~clojure
(s-type-anno @1-1-1-72 (name "process_things")
(ty-fn @1-18-1-72
(ty-record @1-18-1-53
(anno-record-field @1-20-1-31 (name "name")
(ty (name "Str")))
(anno-record-field @1-32-1-42 (name "age")
(ty (name "U32")))
(anno-record-field @1-43-1-53 (name "thing")
(ty-var @1-50-1-51 (raw "a"))))
(ty-fn @1-56-1-64
(ty-var @1-56-1-57 (raw "a"))
(ty (name "Str")))
(ty (name "Str"))))
~~~
# FORMATTED
~~~roc
process_things : { name : Str, age : U32, thing : a }, (a -> Str) -> Str
~~~
# TYPES
~~~clojure
(inferred-types
(defs)
(expressions))
~~~

View file

@ -383,27 +383,6 @@ Is there an `import` or `exposing` missing up-top?
Nothing is named `foo` in this scope.
Is there an `import` or `exposing` missing up-top?
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: binop
**NOT IMPLEMENTED**
This feature is not yet implemented: canonicalize suffix_single_question expression
@ -1309,9 +1288,9 @@ NO CHANGE
(p-assign @81-2-81-3 (ident "a") (id 226))
(p-assign @82-2-82-3 (ident "b") (id 227)))
(e-runtime-error (tag "not_implemented"))))
(d-let (id 443)
(d-let (id 436)
(p-assign @144-1-144-6 (ident "main!") (id 242))
(e-lambda @144-9-196-2 (id 437)
(e-lambda @144-9-196-2 (id 430)
(args
(p-underscore @144-10-144-11 (id 243)))
(e-block @144-13-196-2
@ -1409,10 +1388,36 @@ NO CHANGE
(e-int @186-10-186-11 (num-var 353) (value "3")))))))
(s-let @188-2-189-23
(p-assign @188-2-188-15 (ident "bin_op_result") (id 359))
(e-runtime-error (tag "not_implemented") (id 407)))
(e-binop @188-18-189-23 (op "or") (id 400)
(e-binop @188-18-188-74 (op "or")
(e-binop @188-18-188-43 (op "gt")
(e-binop @188-18-188-34 (op "null_coalesce")
(e-call @188-18-188-26
(e-tag @188-18-188-21 (ext-var 0) (name "Err") (args "TODO"))
(e-runtime-error (tag "ident_not_in_scope")))
(e-int @188-30-188-32 (num-var 366) (value "12")))
(e-binop @188-35-188-43 (op "mul")
(e-int @188-35-188-36 (num-var 369) (value "5"))
(e-int @188-39-188-40 (num-var 371) (value "5"))))
(e-binop @188-44-188-74 (op "and")
(e-binop @188-44-188-58 (op "lt")
(e-binop @188-44-188-52 (op "add")
(e-int @188-44-188-46 (num-var 375) (value "13"))
(e-int @188-49-188-50 (num-var 377) (value "2")))
(e-int @188-53-188-54 (num-var 380) (value "5")))
(e-binop @188-59-188-74 (op "ge")
(e-binop @188-59-188-68 (op "sub")
(e-int @188-59-188-61 (num-var 383) (value "10"))
(e-int @188-64-188-65 (num-var 385) (value "1")))
(e-int @188-69-188-71 (num-var 388) (value "16")))))
(e-binop @188-75-189-23 (op "le")
(e-int @188-75-188-77 (num-var 393) (value "12"))
(e-binop @188-81-189-23 (op "div")
(e-int @188-81-188-82 (num-var 395) (value "3"))
(e-int @188-85-188-86 (num-var 397) (value "5"))))))
(s-let @189-2-190-8
(p-assign @189-2-189-23 (ident "static_dispatch_style") (id 409))
(e-dot-access @189-26-190-8 (field "unknown") (id 414)
(p-assign @189-2-189-23 (ident "static_dispatch_style") (id 402))
(e-dot-access @189-26-190-8 (field "unknown") (id 407)
(receiver
(e-dot-access @189-26-189-110 (field "unknown")
(receiver
@ -1423,7 +1428,7 @@ NO CHANGE
(e-runtime-error (tag "not_implemented")))
(e-call @191-2-195-3
(e-lookup-external
(ext-decl @191-2-191-14 (qualified "pf.Stdout.line!") (module "pf.Stdout") (local "line!") (kind "value") (type-var 419)))
(ext-decl @191-2-191-14 (qualified "pf.Stdout.line!") (module "pf.Stdout") (local "line!") (kind "value") (type-var 412)))
(e-string @192-3-194-18
(e-literal @192-4-192-14 (string "How about "))
(e-call @193-4-193-21
@ -1431,7 +1436,7 @@ NO CHANGE
(e-lookup-local @193-14-193-20
(pattern (id 250))))
(e-literal @194-4-194-17 (string " as a string?"))))))
(annotation @144-1-144-6 (signature 441) (id 442)
(annotation @144-1-144-6 (signature 434) (id 435)
(declared-type
(ty-fn @143-9-143-38 (effectful false)
(ty-apply @143-9-143-21 (symbol "List")
@ -1439,10 +1444,10 @@ NO CHANGE
(ty-apply @143-25-143-38 (symbol "Result")
(ty-record @143-32-143-34)
(ty-underscore @143-36-143-37))))))
(d-let (id 451)
(p-assign @199-1-199-6 (ident "empty") (id 445))
(e-runtime-error (tag "not_implemented") (id 447))
(annotation @199-1-199-6 (signature 449) (id 450)
(d-let (id 444)
(p-assign @199-1-199-6 (ident "empty") (id 438))
(e-runtime-error (tag "not_implemented") (id 440))
(annotation @199-1-199-6 (signature 442) (id 443)
(declared-type
(ty-record @198-9-198-11))))
(s-type-decl @22-1-23-6 (id 84)

View file

@ -4,6 +4,7 @@ const testing = std.testing;
test {
testing.refAllDeclsRecursive(@import("main.zig"));
testing.refAllDeclsRecursive(@import("builtins/main.zig"));
testing.refAllDeclsRecursive(@import("cache.zig"));
// TODO: Remove after hooking up
testing.refAllDeclsRecursive(@import("reporting.zig"));