@@ -132,6 +132,8 @@ enum OpBuiltin implements Op {
132132 };
133133}
134134
135+ enum ExtensionCallJsonForm { positional, singleArgObject, multiArgsObject }
136+
135137sealed class Expr {
136138 const Expr ();
137139
@@ -194,15 +196,65 @@ sealed class Expr {
194196 ),
195197 OpBuiltin .set => ExprSet .fromJson (value as List <Object ?>),
196198 OpBuiltin .record => ExprRecord .fromJson (value as Map <String , Object ?>),
197- final OpExtension op => ExprExtensionCall (
198- fn: op.name,
199- args: (value as List <Object ?>)
200- .map ((el) => Expr .fromJson (el as Map <String , Object ?>))
201- .toList (),
202- ),
199+ final OpExtension op => _extensionCallFromJson (op.name, value),
203200 };
204201 }
205202
203+ static List <Expr > _extensionArgsFromList (String fn, List <Object ?> json) {
204+ return json.map ((element) {
205+ if (element is ! Map <String , Object ?>) {
206+ throw FormatException (
207+ 'Invalid extension call argument for $fn : $element ' ,
208+ );
209+ }
210+ return Expr .fromJson (element);
211+ }).toList ();
212+ }
213+
214+ static (List <Expr >, ExtensionCallJsonForm ) _extensionArgsFromJson (
215+ String fn,
216+ Object ? json,
217+ ) {
218+ if (json is List <Object ?>) {
219+ return (
220+ _extensionArgsFromList (fn, json),
221+ ExtensionCallJsonForm .positional,
222+ );
223+ }
224+ if (json is Map <String , Object ?>) {
225+ if (json.containsKey ('arg' )) {
226+ final singleArg = json['arg' ];
227+ if (singleArg is ! Map <String , Object ?>) {
228+ throw FormatException (
229+ 'Invalid extension call argument for $fn : $singleArg ' ,
230+ );
231+ }
232+ return (
233+ [Expr .fromJson (singleArg)],
234+ ExtensionCallJsonForm .singleArgObject,
235+ );
236+ }
237+ if (json.containsKey ('args' )) {
238+ final multiArgs = json['args' ];
239+ if (multiArgs is ! List <Object ?>) {
240+ throw FormatException (
241+ 'Invalid extension call arguments for $fn : $multiArgs ' ,
242+ );
243+ }
244+ return (
245+ _extensionArgsFromList (fn, multiArgs),
246+ ExtensionCallJsonForm .multiArgsObject,
247+ );
248+ }
249+ }
250+ throw FormatException ('Invalid extension call arguments for $fn : $json ' );
251+ }
252+
253+ static ExprExtensionCall _extensionCallFromJson (String fn, Object ? json) {
254+ final (args, form) = _extensionArgsFromJson (fn, json);
255+ return ExprExtensionCall (fn: fn, args: args, jsonForm: form);
256+ }
257+
206258 factory Expr .fromProto (pb.Expr proto) {
207259 return switch (proto.whichExpr ()) {
208260 pb.Expr_Expr .value => ExprValue .fromProto (proto.value),
@@ -343,12 +395,13 @@ sealed class Expr {
343395 const factory Expr .extensionCall ({
344396 required String fn,
345397 required List <Expr > args,
398+ ExtensionCallJsonForm jsonForm,
346399 }) = ExprExtensionCall ;
347400
348- operator + (Expr rhs) => add (rhs);
349- operator - (Expr rhs) => subtract (rhs);
350- operator * (Expr rhs) => multiply (rhs);
351- operator - () => negate ();
401+ Expr operator + (Expr rhs) => add (rhs);
402+ Expr operator - (Expr rhs) => subtract (rhs);
403+ Expr operator * (Expr rhs) => multiply (rhs);
404+ Expr operator - () => negate ();
352405
353406 Op get op;
354407
@@ -366,7 +419,11 @@ sealed class Expr {
366419}
367420
368421final class ExprExtensionCall extends Expr {
369- const ExprExtensionCall ({required this .fn, required this .args});
422+ const ExprExtensionCall ({
423+ required this .fn,
424+ required this .args,
425+ this .jsonForm = ExtensionCallJsonForm .positional,
426+ });
370427
371428 factory ExprExtensionCall .fromProto (pb.ExprExtensionCall proto) {
372429 return ExprExtensionCall (
@@ -377,6 +434,7 @@ final class ExprExtensionCall extends Expr {
377434
378435 final String fn;
379436 final List <Expr > args;
437+ final ExtensionCallJsonForm jsonForm;
380438
381439 @override
382440 OpExtension get op => OpExtension (fn);
@@ -389,8 +447,14 @@ final class ExprExtensionCall extends Expr {
389447 visitor.visitExtensionCall (this , arg);
390448
391449 @override
392- List <Map <String , Object ?>> valueToJson () =>
393- args.map ((arg) => arg.toJson ()).toList ();
450+ Object ? valueToJson () {
451+ final positionalJson = args.map ((arg) => arg.toJson ()).toList ();
452+ return switch (jsonForm) {
453+ ExtensionCallJsonForm .positional => positionalJson,
454+ ExtensionCallJsonForm .singleArgObject => {'arg' : positionalJson.first},
455+ ExtensionCallJsonForm .multiArgsObject => {'args' : positionalJson},
456+ };
457+ }
394458
395459 @override
396460 pb.Expr toProto () => pb.Expr (
@@ -405,10 +469,11 @@ final class ExprExtensionCall extends Expr {
405469 identical (this , other) ||
406470 other is ExprExtensionCall &&
407471 fn == other.fn &&
472+ jsonForm == other.jsonForm &&
408473 const ListEquality <Expr >().equals (args, other.args);
409474
410475 @override
411- int get hashCode => Object .hashAll ([fn, ...args]);
476+ int get hashCode => Object .hashAll ([fn, jsonForm, ...args]);
412477
413478 @override
414479 String toString () => '$fn (${args .join (', ' )})' ;
@@ -1349,7 +1414,7 @@ final class ExprGetTag extends Expr {
13491414 factory ExprGetTag .fromJson (Map <String , Object ?> json) {
13501415 return ExprGetTag (
13511416 left: Expr .fromJson (json['left' ] as Map <String , Object ?>),
1352- tag: Expr .fromJson (json['tag ' ] as Map <String , Object ?>),
1417+ tag: Expr .fromJson (json['right ' ] as Map <String , Object ?>),
13531418 );
13541419 }
13551420
@@ -1381,7 +1446,7 @@ final class ExprGetTag extends Expr {
13811446 @override
13821447 Map <String , Object ?> valueToJson () => {
13831448 'left' : left.toJson (),
1384- 'tag ' : tag.toJson (),
1449+ 'right ' : tag.toJson (),
13851450 };
13861451
13871452 @override
@@ -1402,7 +1467,7 @@ final class ExprHasTag extends Expr {
14021467 factory ExprHasTag .fromJson (Map <String , Object ?> json) {
14031468 return ExprHasTag (
14041469 left: Expr .fromJson (json['left' ] as Map <String , Object ?>),
1405- tag: Expr .fromJson (json['tag ' ] as Map <String , Object ?>),
1470+ tag: Expr .fromJson (json['right ' ] as Map <String , Object ?>),
14061471 );
14071472 }
14081473
@@ -1434,7 +1499,7 @@ final class ExprHasTag extends Expr {
14341499 @override
14351500 Map <String , Object ?> valueToJson () => {
14361501 'left' : left.toJson (),
1437- 'tag ' : tag.toJson (),
1502+ 'right ' : tag.toJson (),
14381503 };
14391504
14401505 @override
@@ -1453,9 +1518,20 @@ final class ExprLike extends Expr {
14531518 const ExprLike ({required this .left, required this .pattern});
14541519
14551520 factory ExprLike .fromJson (Map <String , Object ?> json) {
1521+ CedarPattern parsePattern (Object ? raw) {
1522+ if (raw is String ) {
1523+ return CedarPattern .parse (raw);
1524+ }
1525+ if (raw is List ) {
1526+ final components = List <Object ?>.from (raw);
1527+ return CedarPattern .from (components, jsonForm: components);
1528+ }
1529+ throw FormatException ('Invalid pattern value: $raw ' );
1530+ }
1531+
14561532 return ExprLike (
14571533 left: Expr .fromJson (json['left' ] as Map <String , Object ?>),
1458- pattern: CedarPattern . parse (json['pattern' ] as String ),
1534+ pattern: parsePattern (json['pattern' ]),
14591535 );
14601536 }
14611537
@@ -1487,7 +1563,7 @@ final class ExprLike extends Expr {
14871563 @override
14881564 Map <String , Object ?> valueToJson () => {
14891565 'left' : left.toJson (),
1490- 'pattern' : pattern.toString (),
1566+ 'pattern' : pattern.toJson (),
14911567 };
14921568
14931569 @override
0 commit comments