Skip to content

Enable shorter JsLIGO syntax for nested record updates

Nicolas Phan requested to merge jsligo_nested_record_update into dev

Motivation and Context

Description

When a record p contains a record a which contains b etc. Updating a sub-sub-sub-field can be cumbersome, currently it goes like :

let p = {...p, a:{...p.a, b:{...p.a.b, c:"Before"}}};

A shorter but equivalent syntax is :

p.a.b.c = "After";

Which is already supported by the parser but rejected by abstractor.

This MR enable this new writing, abstracting it into an AST equivalent to the former writing.

Sanity check

As a first sanity check, the two writings :

let p = {...p, a:{...p.a, b:{...p.a.b, c:"Before"}}};
p.a.b.c = "After";

Give the same AST Imperative (ligo print ast-imperative ...) :

let mut p = { p with a = { p.a with b = { p.a.b with c = "Before" } } }[@@private] in
{
p := { p with a = { p.a with b = { p.a.b with c = "After" } } };
...
}

Remaining work

This is still a draft, remaining work is :

  • Add tests, and find a test strategy to ensure the two writing are indeed equivalent
  • Handle the Component case (c.f. TODO in code)
  • Handle the empty list case in path_acc_out, i.e. make it a nelist (c.f. TODO in code)
  • Handle the "impossible case" where sub-expression is neither EProj nor EVar (c.f. TODO in code)
  • Deal with locations proprely
  • Deal with passing of attributes

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Performance improvement (non-breaking change that improves performance)
  • None (change with no changelog)

Changelog

For a contract with the new syntax for record update

type storage = int;
type parameter = int;

type user = {
  id       : int,
  name     : string
};

const user1 : user = {
  id : 24,
  name : "User1",
};

const main = (_action: parameter, store: storage) : [ list<operation> , storage ] => {
  let p = user1;
  p.id = 42; // Record field update
  return [list([]), store]
};

Before

> ligo compile contract 'contract.jsligo' 
File "contract.jsligo", line 17, characters 2-11:
 16 |   let p = user1;
 17 |   p.id = 42; // Record field update
 18 |   return [

Not supported assignment.

After

> ligo compile contract 'contract.jsligo' 
{ parameter int ; storage int ; code { CDR ; NIL operation ; PAIR } }

Checklist:

  • Changes follow the existing coding style (use dune @fmt to check).
  • Tests for the changes have been added (for bug fixes / feature).
  • Documentation has been updated.
  • Changelog description has been added (if appropriate).
  • Start titles under ## Changelog section with #### (if appropriate).
  • There is no image or uploaded file in changelog
  • Examples in changed behaviour have been added to the changelog (for breaking change / feature).
Edited by Nicolas Phan

Merge request reports