This document summarizes the implementation of two new record operations in the Cure programming language:
1. Direct field access using dot notation: record.field
2. Record update syntax using pipe notation: Record{base | field: value}
2025-10-31
src/parser/cure_ast.hrl)Added two new expression record types:
%% Field access expressions (record.field)
-record(field_access_expr, {
record, % Expression evaluating to a record
field, % Atom: field name
location
}).
%% Record update expressions (Record{old | field: value})
-record(record_update_expr, {
name, % Record type name
base, % Expression for the base record
fields, % List of #field_expr{} records
location
}).
Updated the expr() type definition to include these new types.
src/parser/cure_parser.erl)parse_postfix_operators/2 function to handle postfix operators like .fieldparse_binary_expression/2 to call postfix operator parsingModule.function()) and field access (record.field)parse_identifier_or_call/1 to detect the | pipe operator in record constructionRecord{field: value} (construction) and Record{base | field: value} (update)is_identifier_token/1 to check if a token is an identifierget_expr_location/1 to handle new expression typessrc/types/cure_typechecker.erl)infer_expr({field_access_expr, RecordExpr, FieldName, Location}, Env) ->
% Infer record type, look up field type from record definition
% Return field type or error if field doesn't exist
infer_expr({record_update_expr, RecordName, BaseExpr, Fields, Location}, Env) ->
% Check base expression matches record type
% Validate updated fields exist and have correct types
% Return updated record type
convert_expr_to_tuple/1 for the new expression typessrc/codegen/cure_codegen.erl)compile_record_expr(#field_access_expr{...}, State) ->
% Generate: maps:get(FieldName, Record)
compile_record_expr(#record_update_expr{...}, State) ->
% Generate: BaseRecord#{field1 := Value1, field2 := Value2, ...}
Added dispatch cases in compile_expression/2 for the new expression types.
src/codegen/cure_beam_compiler.erl)record_field_access: Compiles to maps:get(Field, Record)record_update: Compiles to map update syntax Map#{field := value}Changed record compilation from Erlang records to maps:
- Records are now represented as Erlang maps
- Field access uses maps:get/2
- Updates use map update syntax #{...}
compile_make_record([RecordName, FieldNames, FieldCount], Context) ->
% Generate: #{field1 => Val1, field2 => Val2, ...}
MapForm = {map, Line, MapAssocs}
Note: As of October 31, 2025, the record field access and update operations are fully implemented in the compiler (parser, AST, codegen), but the example files mentioned in earlier documentation do not currently exist.
Existing Examples: The current Cure examples that demonstrate record syntax are:
- examples/04_pattern_guards.cure - Shows record pattern matching with guards (e.g., Point{x: x, y: y} when x == 0.0 and y == 0.0)
- Other example files show basic record construction (e.g., Point{x: 1.0, y: 2.0})
Implementation Status:
- ✅ Parser fully supports both field access (.field) and record update (Record{base | field: value}) syntax
- ✅ AST definitions complete (#field_access_expr{} and #record_update_expr{})
- ✅ Code generation implemented (compile_field_access_expr/2 and compile_record_update_expr/2)
- ⚠️ Example files demonstrating these features have not yet been added
def get_name(p: Person): String =
p.name # Direct field access
# Chained access
def get_nested_field(contact: Contact): String =
contact.person.name # Access nested record fields
def birthday(p: Person): Person =
Person{p | age: p.age + 1} # Update single field
def move_point(pt: Point, dx: Float, dy: Float): Point =
Point{pt | x: pt.x + dx, y: pt.y + dy} # Update multiple fields
✅ Parser Implementation:
- Field access parsing: parse_postfix_operators/2 (lines 2756-2801)
- Record update parsing: lines 3136-3152 in cure_parser.erl
- Proper disambiguation between module qualification and field access
✅ Codegen Implementation:
- compile_field_access_expr/2: lines 1692-1706 in cure_codegen.erl
- compile_record_update_expr/2: lines 1668-1689 in cure_codegen.erl
- Generates record_field_access and update_record BEAM instructions
✅ AST Definitions:
- #field_access_expr{}: lines 293-298 in cure_ast.hrl
- #record_update_expr{}: lines 300-306 in cure_ast.hrl
The parser disambiguates between module qualification and field access by checking:
1. If the base expression is a simple identifier (#identifier_expr{})
2. If there's a ( token after the field name
3. If both are true → module qualification
4. Otherwise → field access
The record update syntax is parsed by:
1. Detecting { after a record type name
2. Parsing the first expression after {
3. Checking for | token
4. If | found → record update, otherwise backtrack to regular construction
Records compile to Erlang maps, which provides:
- Efficient field access via maps:get/2
- Efficient updates via map update syntax
- No runtime record definitions needed
- Better interoperability with Erlang code
Potential improvements for future iterations:
1. Nested updates: Person{p | address.city: "New York"}
2. Pattern-based updates: Person{p | age: a} when a > 18 -> ..}
3. Partial construction: Allow omitting some fields with defaults
4. Record spreading: Person{p1 | ...p2} to merge records
5. Type-safe field access: Compile-time verification of field existence
src/parser/cure_ast.hrl (lines 293-306)src/parser/cure_parser.erlparse_postfix_operators/2)parse_identifier_or_call/1)src/codegen/cure_codegen.erlcompile_field_access_expr/2: lines 1692-1706compile_record_update_expr/2: lines 1668-1689src/types/cure_typechecker.erl (type inference for new expressions)src/codegen/cure_beam_compiler.erl (BEAM bytecode generation)examples/04_pattern_guards.cure (record pattern matching)