diff --git a/src/js/index.html b/src/js/index.html
index d6f4e0e2be..d40678e6c3 100644
--- a/src/js/index.html
+++ b/src/js/index.html
@@ -22,9 +22,9 @@
"@codemirror/state": "https://esm.sh/@codemirror/state@6.2.1",
"@codemirror/language": "https://esm.sh/@codemirror/language@6.9.1",
"@codemirror/view": "https://esm.sh/@codemirror/view@6.21.3",
- "codemirror-lang-liquidsoap": "https://esm.sh/codemirror-lang-liquidsoap@0.2.5?external=@codemirror/state,@codemirror/language,@codemirror/view",
+ "codemirror-lang-liquidsoap": "https://esm.sh/codemirror-lang-liquidsoap@0.2.7?external=@codemirror/state,@codemirror/language,@codemirror/view",
"prettier": "https://esm.sh/prettier@3.0.2/standalone.mjs",
- "liquidsoap-prettier": "https://esm.sh/liquidsoap-prettier/src/index.js"
+ "liquidsoap-prettier": "https://esm.sh/liquidsoap-prettier@1.4.8/src/index.js"
}
}
diff --git a/src/lang/parser.mly b/src/lang/parser.mly
index 84fcc2d31b..56e8b9ce98 100644
--- a/src/lang/parser.mly
+++ b/src/lang/parser.mly
@@ -155,7 +155,7 @@ open Parser_helper
%type pattern
%type pattern_list
%type pattern_list_with_spread
-%type <(string * Parsed_term.t) list> record
+%type record
%type record_pattern
%type record_ty
%type s
@@ -226,13 +226,12 @@ expr:
| ENCODER encoder_opt { mk_encoder ~pos:$loc $1 $2 }
| LPAR RPAR { mk ~pos:$loc (`Tuple []) }
| LPAR inner_tuple RPAR { mk ~pos:$loc (`Tuple $2) }
+ | expr DOT LCUR record RCUR { mk ~pos:$loc (`Methods (Some $1, $4)) }
| expr DOT LCUR record optional_comma RCUR
- { mk ~pos:$loc (`Methods { base = `Term $1; methods = $4 }) }
- | LCUR DOTDOTDOT expr RCUR { mk ~pos:$loc (`Methods { base = `Spread $3; methods = [] }) }
- | LCUR record COMMA DOTDOTDOT expr RCUR
- { mk ~pos:$loc (`Methods { base = `Spread $5; methods = $2 }) }
- | LCUR record optional_comma RCUR { mk ~pos:$loc (`Methods { base = `None; methods = $2 }) }
- | LCUR RCUR { mk ~pos:$loc (`Methods {base = `None; methods = []}) }
+ { mk ~pos:$loc (`Methods (Some $1, $4)) }
+ | LCUR record RCUR { mk ~pos:$loc (`Methods (None, $2)) }
+ | LCUR record optional_comma RCUR { mk ~pos:$loc (`Methods (None, $2)) }
+ | LCUR RCUR { mk ~pos:$loc (`Methods (None, [])) }
| expr QUESTION_DOT invoke { mk ~pos:$loc (`Invoke { invoked = $1; meth = $3; optional = true }) }
| expr DOT invoke { mk ~pos:$loc (`Invoke { invoked = $1; meth = $3; optional = false }) }
| VARLPAR app_list RPAR { mk ~pos:$loc (`App (mk ~pos:$loc($1) (`Var $1), $2)) }
@@ -583,12 +582,13 @@ plain_encoder_params:
| LPAR encoder_params RPAR { $2 }
optional_comma:
- | {}
| COMMA {}
record:
- | VAR GETS expr { [($1, $3)] }
- | record COMMA VAR GETS expr { $1@[($3,$5)] }
+ | VAR GETS expr { [`Method ($1, $3)] }
+ | DOTDOTDOT expr { [`Ellipsis $2] }
+ | record COMMA VAR GETS expr { $1@[`Method ($3,$5)] }
+ | record COMMA DOTDOTDOT expr { $1@[`Ellipsis $4] }
string_interpolation:
| BEGIN_INTERPOLATION string_interpolation_elems END_INTERPOLATION { $1, $2 }
diff --git a/src/lang/term/parsed_term.ml b/src/lang/term/parsed_term.ml
index 8bd6abe628..ef4b7a2146 100644
--- a/src/lang/term/parsed_term.ml
+++ b/src/lang/term/parsed_term.ml
@@ -168,7 +168,7 @@ and parsed_ast =
| `Not of t
| `Get of t
| `Set of t * t
- | `Methods of methods
+ | `Methods of t option * methods list
| `Negative of t
| `Append of t * t
| `Assoc of t * t
@@ -193,11 +193,7 @@ and t = {
mutable comments : (Pos.t * comment) list;
}
-and methods = {
- base : [ `None | `Spread of t | `Term of t ];
- methods : (string * t) list;
-}
-
+and methods = [ `Ellipsis of t | `Method of string * t ]
and string_interpolation = [ `String of string | `Term of t ]
and encoder_params =
@@ -304,11 +300,11 @@ let rec iter_term fn ({ term } as tm) =
iter_term fn tm'
| `Parenthesis tm -> iter_term fn tm
| `Block tm -> iter_term fn tm
- | `Methods { base; methods } ->
- (match base with
- | `None -> ()
- | `Spread tm | `Term tm -> iter_term fn tm);
- List.iter (fun (_, tm) -> iter_term fn tm) methods
+ | `Methods (base, methods) ->
+ (match base with None -> () | Some tm -> iter_term fn tm);
+ List.iter
+ (function `Method (_, tm) | `Ellipsis tm -> iter_term fn tm)
+ methods
| `Int _ -> ()
| `Float _ -> ()
| `String _ -> ()
diff --git a/src/lang/term/term_reducer.ml b/src/lang/term/term_reducer.ml
index 85623a06d7..e2455ec4a2 100644
--- a/src/lang/term/term_reducer.ml
+++ b/src/lang/term/term_reducer.ml
@@ -835,46 +835,46 @@ and to_term (tm : Parsed_term.t) : Term.t =
| `Seq (({ term = `If_version _ } as t), t') ->
concat_term (to_term t) (to_term t')
| `Parenthesis tm | `Block tm -> to_term tm
- | `Methods { base; methods } ->
- let term, base_methods =
- match base with
- | `None -> (`Tuple [], Methods.empty)
- | `Term tm ->
- let { term; methods } = to_term tm in
- (term, methods)
- | `Spread tm ->
- let term = to_term tm in
- (* let _ = tm in let replaces _ = () in _ *)
- let { term; methods } =
+ | `Methods (base, methods) ->
+ (* let _ = src in
+ let replaces _ = dst in
+ _ *)
+ let replace_methods ~src dst =
+ mk ~pos:tm.pos
+ (`Let
+ {
+ doc = None;
+ replace = false;
+ pat = `PVar ["_"];
+ gen = [];
+ def = src;
+ body =
mk ~pos:tm.pos
(`Let
{
doc = None;
- replace = false;
+ replace = true;
pat = `PVar ["_"];
gen = [];
- def = term;
- body =
- mk ~pos:tm.pos
- (`Let
- {
- doc = None;
- replace = true;
- pat = `PVar ["_"];
- gen = [];
- def = mk ~pos:tm.pos (`Tuple []);
- body = mk ~pos:tm.pos (`Var "_");
- });
- })
- in
- (term, methods)
+ def = dst;
+ body = mk ~pos:tm.pos (`Var "_");
+ });
+ })
in
- let methods =
- List.fold_left
- (fun methods (k, v) -> Methods.add k (to_term v) methods)
- base_methods methods
+ let term =
+ match base with
+ | None -> mk ~pos:tm.pos (`Tuple [])
+ | Some tm -> to_term tm
in
- { t = Type.var ~pos:tm.pos (); term; methods }
+ List.fold_left
+ (fun term -> function
+ | `Ellipsis src -> replace_methods ~src:(to_term src) term
+ | `Method (name, tm) ->
+ {
+ term with
+ methods = Methods.add name (to_term tm) term.methods;
+ })
+ term methods
| term ->
let comments =
List.filter_map
diff --git a/src/tooling/parsed_json.ml b/src/tooling/parsed_json.ml
index 7d14757904..0efc3178f4 100644
--- a/src/tooling/parsed_json.ml
+++ b/src/tooling/parsed_json.ml
@@ -479,13 +479,9 @@ let rec to_ast_json ~to_json = function
("optional", `Bool optional);
("meth", `Assoc (json_of_invoke_meth ~to_json meth));
]
- | `Methods { base; methods } ->
+ | `Methods (base, methods) ->
let base, base_methods =
- match base with
- | `None -> (`Null, [])
- | `Term t -> (to_json t, [])
- | `Spread t ->
- (`Null, [`Assoc (ast_node ~typ:"ellipsis" [("value", to_json t)])])
+ match base with None -> (`Null, []) | Some t -> (to_json t, [])
in
ast_node ~typ:"methods"
[
@@ -493,10 +489,13 @@ let rec to_ast_json ~to_json = function
( "methods",
`Tuple
(List.map
- (fun (k, v) ->
- `Assoc
- (ast_node ~typ:"method"
- [("name", `String k); ("value", to_json v)]))
+ (function
+ | `Ellipsis v ->
+ `Assoc (ast_node ~typ:"ellipsis" [("value", to_json v)])
+ | `Method (k, v) ->
+ `Assoc
+ (ast_node ~typ:"method"
+ [("name", `String k); ("value", to_json v)]))
methods
@ base_methods) );
]
diff --git a/tests/language/record.liq b/tests/language/record.liq
index 5a43ff6222..e6f08ce83d 100644
--- a/tests/language/record.liq
+++ b/tests/language/record.liq
@@ -275,6 +275,14 @@ def f() =
y = x.{foo=123} - 3
test.equals("#{y}", "#{-2}")
+ x = {foo=123}
+ y = {gni="aabb"}
+ test.equals({...x, ...y}, {foo=123, gni="aabb"})
+ test.equals({...x, gna=3.14, ...y}, {foo=123, bla=3.14, gni="aabb"})
+ test.equals(
+ {...x, gna=3.14, ...y, foo="bar"}, {foo="bar", bla=3.14, gni="aabb"}
+ )
+
test.pass()
end