Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn advance(s: Lifecycle) -> Lifecycle {
}

fn make_counters() -> Counters {
{ tag: 1, profile_id: 42, activity_count: 7 }
#{ tag: 1, profile_id: 42, activity_count: 7 }
}

fn read_profile_id(c: Counters) -> Int {
Expand Down
2 changes: 1 addition & 1 deletion conformance/valid/011_rows.affine
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ fn get_name[..r](entity: {name: String, ..r}) -> String {
}

fn with_id[..r](record: {..r}, id: Int) -> {id: Int, ..r} {
{ id: id, ..record }
#{ id: id, ..record }
}

type HasPosition[..r] = {x: Int, y: Int, ..r}
Expand Down
4 changes: 2 additions & 2 deletions examples/comprehensive_test.affine
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ enum Shape {
}

fn vec2_add(a: Vec2, b: Vec2) -> Vec2 {
{ x: a.x + b.x, y: a.y + b.y }
#{ x: a.x + b.x, y: a.y + b.y }
}

fn area(s: Shape) -> Int {
Expand All @@ -30,7 +30,7 @@ fn larger_area(s1: Shape, s2: Shape) -> Int = max(area(s1), area(s2));

fn main() -> () {
let circle = Circle(5);
let rect = Rect({ x: 3, y: 4 });
let rect = Rect(#{ x: 3, y: 4 });
let result = larger_area(circle, rect);
();
}
2 changes: 1 addition & 1 deletion examples/rows.affine
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ struct Point3D {
fn getX(p: Point2D) -> Int = p.x;

fn mk_point(x: Int, y: Int) -> Point2D {
{ x: x, y: y }
#{ x: x, y: y }
}
4 changes: 2 additions & 2 deletions examples/typecheck_complete_test.affine
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ enum Color {
}

fn make_point(x: Int, y: Int) -> Point {
{ x: x, y: y }
#{ x: x, y: y }
}

fn origin() -> Point {
{ x: 0, y: 0 }
#{ x: 0, y: 0 }
}

fn mutate_counter() -> Int {
Expand Down
3 changes: 3 additions & 0 deletions lib/lexer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ let rec token state buf =
| "-=" -> MINUSEQ
| "*=" -> STAREQ
| "/=" -> SLASHEQ
(* `#{` opens a record/struct literal (#218); longest-match, and `#` has
no other lexer rule, so this never shadows a single-char token. *)
| "#{" -> HASH_LBRACE

(* Single-char tokens *)
| '(' -> LPAREN
Expand Down
1 change: 1 addition & 0 deletions lib/parse_driver.ml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ let to_menhir_token (tok : Token.t) : Parser.token =
| Token.LPAREN -> Parser.LPAREN
| Token.RPAREN -> Parser.RPAREN
| Token.LBRACE -> Parser.LBRACE
| Token.HASH_LBRACE -> Parser.HASH_LBRACE
| Token.RBRACE -> Parser.RBRACE
| Token.LBRACKET -> Parser.LBRACKET
| Token.RBRACKET -> Parser.RBRACKET
Expand Down
23 changes: 14 additions & 9 deletions lib/parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ let rec effect_union_of_list = function

/* Punctuation */
%token LPAREN RPAREN LBRACE RBRACE LBRACKET RBRACKET
/* `#{` opens a record/struct literal (#218). `{` is ALWAYS a block in
expression position — this structurally removes the block-vs-record
ambiguity (#215 families C+D) with no lookahead heuristic. */
%token HASH_LBRACE
%token COMMA SEMICOLON COLON COLONCOLON DOT DOTDOT
%token ARROW FAT_ARROW PIPE AT UNDERSCORE BACKSLASH QUESTION

Expand Down Expand Up @@ -768,10 +772,10 @@ expr_primary:
ordinary parameter binding named "self". */
| SELF_KW { ExprVar (mk_ident "self" $startpos $endpos) }
| name = lower_ident { ExprVar (mk_ident name $startpos $endpos) }
/* Struct literal: `Point { x: v, y: w }`. Must come before the plain
upper_ident production so Menhir shifts LBRACE rather than reducing
upper_ident to ExprVar when the next token is LBRACE. */
| _ty = upper_ident LBRACE b = expr_record_body RBRACE
/* Struct literal: `Point #{ x: v, y: w }` (#218). The `#{` sigil makes
this unambiguous against the plain `upper_ident` production and against
a following block, so no LBRACE-shift heuristic is needed any more. */
| _ty = upper_ident HASH_LBRACE b = expr_record_body RBRACE
{ ExprRecord { er_fields = fst b; er_spread = snd b } }
| name = upper_ident { ExprVar (mk_ident name $startpos $endpos) }
| ty = upper_ident COLONCOLON variant = upper_ident
Expand All @@ -787,11 +791,12 @@ expr_primary:
/* Arrays */
| LBRACKET es = separated_list(COMMA, expr) RBRACKET { ExprArray es }

/* Records — use a recursive rule (expr_record_body / expr_record_rest) to
avoid the LALR(1) greedy-separator conflict that arises when a ROW_VAR
spread like `..record` follows a COMMA that `separated_list` has already
consumed expecting another record_field. */
| LBRACE b = expr_record_body RBRACE
/* Anonymous record `#{ f: v, ..spread }` (#218). Uses a recursive rule
(expr_record_body / expr_record_rest) to avoid the LALR(1) greedy-
separator conflict that arises when a ROW_VAR spread like `..record`
follows a COMMA that `separated_list` has already consumed expecting
another record_field. */
| HASH_LBRACE b = expr_record_body RBRACE
{ ExprRecord { er_fields = fst b; er_spread = snd b } }

/* Block */
Expand Down
2 changes: 2 additions & 0 deletions lib/token.ml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type t =
| LPAREN
| RPAREN
| LBRACE
| HASH_LBRACE
| RBRACE
| LBRACKET
| RBRACKET
Expand Down Expand Up @@ -186,6 +187,7 @@ let to_string = function
| LPAREN -> "("
| RPAREN -> ")"
| LBRACE -> "{"
| HASH_LBRACE -> "#{"
| RBRACE -> "}"
| LBRACKET -> "["
| RBRACKET -> "]"
Expand Down
2 changes: 1 addition & 1 deletion stdlib/testing.affine
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ fn bench(f: () -> (), iterations: Int) -> BenchResult {
}

let tot = time_now() - start;
{
#{
iterations: iterations,
total_time: tot,
avg_time: tot / float(iterations)
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/fixtures/counter.affine
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fn counter_subs(model: Int) -> String {
// Wire up the TEA runtime and hand off to the interpreter loop.

fn main() -> () {
tea_run({
tea_run(#{
init: counter_init,
update: counter_update,
view: counter_view,
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/fixtures/full_pipeline.affine
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ enum Shape {
}

fn vec2_add(a: Vec2, b: Vec2) -> Vec2 {
{ x: a.x + b.x, y: a.y + b.y }
#{ x: a.x + b.x, y: a.y + b.y }
}

fn area(s: Shape) -> Int {
Expand All @@ -31,7 +31,7 @@ fn larger_area(s1: Shape, s2: Shape) -> Int = max(area(s1), area(s2));

fn main() -> () {
let circle = Circle(5);
let rect = Rect({ x: 3, y: 4 });
let rect = Rect(#{ x: 3, y: 4 });
let result = larger_area(circle, rect);
();
}
2 changes: 1 addition & 1 deletion test/e2e/fixtures/row_polymorphism.affine
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ struct Point3D {
fn getX(p: Point2D) -> Int = p.x;

fn mk_point(x: Int, y: Int) -> Point2D {
{ x: x, y: y }
#{ x: x, y: y }
}
12 changes: 6 additions & 6 deletions test/e2e/fixtures/titlescreen.affine
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct TitleModel {
// ── init ─────────────────────────────────────────────────────────────────────

fn title_init() -> TitleModel {
{
#{
screen_w: 1280,
screen_h: 720,
bgm_playing: 0,
Expand All @@ -58,10 +58,10 @@ fn title_init() -> TitleModel {

fn title_update(msg: TitleMsg, model: TitleModel) -> TitleModel {
match msg {
NewGame => { screen_w: model.screen_w, screen_h: model.screen_h, bgm_playing: model.bgm_playing, selected: "new_game" },
LoadGame => { screen_w: model.screen_w, screen_h: model.screen_h, bgm_playing: model.bgm_playing, selected: "load_game" },
Settings => { screen_w: model.screen_w, screen_h: model.screen_h, bgm_playing: model.bgm_playing, selected: "settings" },
Credits => { screen_w: model.screen_w, screen_h: model.screen_h, bgm_playing: model.bgm_playing, selected: "credits" }
NewGame => #{ screen_w: model.screen_w, screen_h: model.screen_h, bgm_playing: model.bgm_playing, selected: "new_game" },
LoadGame => #{ screen_w: model.screen_w, screen_h: model.screen_h, bgm_playing: model.bgm_playing, selected: "load_game" },
Settings => #{ screen_w: model.screen_w, screen_h: model.screen_h, bgm_playing: model.bgm_playing, selected: "settings" },
Credits => #{ screen_w: model.screen_w, screen_h: model.screen_h, bgm_playing: model.bgm_playing, selected: "credits" }
}
}

Expand All @@ -84,7 +84,7 @@ fn title_subs(model: TitleModel) -> String {
// ── main ──────────────────────────────────────────────────────────────────────

fn main() -> () {
tea_run({
tea_run(#{
init: title_init,
update: title_update,
view: title_view,
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/fixtures/type_decls.affine
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ enum Result[T, E] {
}

fn make_point(x: Int, y: Int) -> Point {
{ x: x, y: y }
#{ x: x, y: y }
}

fn origin() -> Point {
{ x: 0, y: 0 }
#{ x: 0, y: 0 }
}
2 changes: 1 addition & 1 deletion test/golden/rows.affine
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ fn getX[..r](p: {x: Int, ..r}) -> Int {
}

fn addY[..r](p: {..r}) -> {y: Int, ..r} {
{y: 0, ..p}
#{y: 0, ..p}
}
12 changes: 6 additions & 6 deletions tests/borrow/test_move.affine
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ fn test_add_two_negatives() -> TestResult {

/// Run all add conformance tests
fn test_alib_arithmetic_add() -> TestResult {
let suite = {
let suite = #{
name: "aLib arithmetic/add conformance",
tests: [
{ name: "add_positive", test: test_add_positive },
{ name: "add_negative", test: test_add_negative },
{ name: "add_zeros", test: test_add_zeros },
{ name: "add_decimal", test: test_add_decimal },
{ name: "add_two_negatives", test: test_add_two_negatives }
#{ name: "add_positive", test: test_add_positive },
#{ name: "add_negative", test: test_add_negative },
#{ name: "add_zeros", test: test_add_zeros },
#{ name: "add_decimal", test: test_add_decimal },
#{ name: "add_two_negatives", test: test_add_two_negatives }
]
};

Expand Down
2 changes: 1 addition & 1 deletion tests/codegen/test_pattern_record.affine
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Test record pattern matching

fn main() -> Int {
let r = {x: 10, y: 20};
let r = #{x: 10, y: 20};

let result = match r {
{x: a, y: b} => a + b
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen/test_record_multi_field.affine
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Test record with multiple fields

fn main() -> Int {
let r = {x: 10, y: 20, z: 30};
let r = #{x: 10, y: 20, z: 30};
return r.x + r.y + r.z; // Should return 60
}
4 changes: 2 additions & 2 deletions tests/codegen/test_record_multiple.affine
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Test multiple distinct records

fn main() -> Int {
let r1 = {a: 5, b: 10};
let r2 = {x: 20, y: 30, z: 40};
let r1 = #{a: 5, b: 10};
let r2 = #{x: 20, y: 30, z: 40};

return r1.a + r1.b + r2.x + r2.y + r2.z; // 5 + 10 + 20 + 30 + 40 = 105
}
2 changes: 1 addition & 1 deletion tests/codegen/test_record_simple.affine
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Test simple record construction and field access

fn main() -> Int {
let r = {x: 42};
let r = #{x: 42};
return r.x; // Should return 42
}
2 changes: 1 addition & 1 deletion tests/codegen/test_tuple_record_array.affine
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
type Point = { x: Int, y: Int, z: Int };

fn main() -> Int {
let p = { x: 10, y: 20, z: 30 };
let p = #{ x: 10, y: 20, z: 30 };
let t = (1, 2, 3, 4);
let a = [5, 6];
return p.x + p.y + p.z + t.0 + t.1 + t.2 + t.3 + a[0] + a[1];
Expand Down
12 changes: 6 additions & 6 deletions tests/conformance/arithmetic/add.affine
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ fn test_add_two_negatives() -> TestResult {

/// Run all add conformance tests
fn test_alib_arithmetic_add() -> TestResult {
let suite = {
let suite = #{
name: "aLib arithmetic/add conformance",
tests: [
{ name: "add_positive", test: test_add_positive },
{ name: "add_negative", test: test_add_negative },
{ name: "add_zeros", test: test_add_zeros },
{ name: "add_decimal", test: test_add_decimal },
{ name: "add_two_negatives", test: test_add_two_negatives }
#{ name: "add_positive", test: test_add_positive },
#{ name: "add_negative", test: test_add_negative },
#{ name: "add_zeros", test: test_add_zeros },
#{ name: "add_decimal", test: test_add_decimal },
#{ name: "add_two_negatives", test: test_add_two_negatives }
]
};

Expand Down
14 changes: 7 additions & 7 deletions tests/conformance/arithmetic/divide.affine
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ fn test_divide_two_negatives() -> TestResult {

/// Run all divide conformance tests
fn test_alib_arithmetic_divide() -> TestResult {
let suite = {
let suite = #{
name: "aLib arithmetic/divide conformance",
tests: [
{ name: "divide_exact", test: test_divide_exact },
{ name: "divide_fractional", test: test_divide_fractional },
{ name: "divide_zero", test: test_divide_zero },
{ name: "divide_negative_dividend", test: test_divide_negative_dividend },
{ name: "divide_negative_divisor", test: test_divide_negative_divisor },
{ name: "divide_two_negatives", test: test_divide_two_negatives }
#{ name: "divide_exact", test: test_divide_exact },
#{ name: "divide_fractional", test: test_divide_fractional },
#{ name: "divide_zero", test: test_divide_zero },
#{ name: "divide_negative_dividend", test: test_divide_negative_dividend },
#{ name: "divide_negative_divisor", test: test_divide_negative_divisor },
#{ name: "divide_two_negatives", test: test_divide_two_negatives }
]
};

Expand Down
12 changes: 6 additions & 6 deletions tests/conformance/arithmetic/modulo.affine
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ fn test_modulo_large() -> TestResult {

/// Run all modulo conformance tests
fn test_alib_arithmetic_modulo() -> TestResult {
let suite = {
let suite = #{
name: "aLib arithmetic/modulo conformance",
tests: [
{ name: "modulo_basic", test: test_modulo_basic },
{ name: "modulo_no_remainder", test: test_modulo_no_remainder },
{ name: "modulo_nonzero", test: test_modulo_nonzero },
{ name: "modulo_zero", test: test_modulo_zero },
{ name: "modulo_large", test: test_modulo_large }
#{ name: "modulo_basic", test: test_modulo_basic },
#{ name: "modulo_no_remainder", test: test_modulo_no_remainder },
#{ name: "modulo_nonzero", test: test_modulo_nonzero },
#{ name: "modulo_zero", test: test_modulo_zero },
#{ name: "modulo_large", test: test_modulo_large }
]
};

Expand Down
14 changes: 7 additions & 7 deletions tests/conformance/arithmetic/multiply.affine
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ fn test_multiply_two_negatives() -> TestResult {

/// Run all multiply conformance tests
fn test_alib_arithmetic_multiply() -> TestResult {
let suite = {
let suite = #{
name: "aLib arithmetic/multiply conformance",
tests: [
{ name: "multiply_positive", test: test_multiply_positive },
{ name: "multiply_negative", test: test_multiply_negative },
{ name: "multiply_zero", test: test_multiply_zero },
{ name: "multiply_identity", test: test_multiply_identity },
{ name: "multiply_decimal", test: test_multiply_decimal },
{ name: "multiply_two_negatives", test: test_multiply_two_negatives }
#{ name: "multiply_positive", test: test_multiply_positive },
#{ name: "multiply_negative", test: test_multiply_negative },
#{ name: "multiply_zero", test: test_multiply_zero },
#{ name: "multiply_identity", test: test_multiply_identity },
#{ name: "multiply_decimal", test: test_multiply_decimal },
#{ name: "multiply_two_negatives", test: test_multiply_two_negatives }
]
};

Expand Down
Loading
Loading