Search code examples
rascal

How to read/write a location from/to a json file with Rascal


We are using the lang::json::IO::writeJSON() function to serialize some data to a JSON file.

This worked great until we tried to store a method location. A location contains the start line and column between the < and > characters, which is apparently not a problem to write to a JSON file (it is written as a string, not attempting to parse anything).

The problem starts when you want to do use lang::json::IO::readJSON with a location stored as a string. Rascal tries to parse the string as an object, and fails.

eg:

rascal>map[str, loc] metrics = ();
map[str, loc]: ()
rascal>metrics["test"] = a;
map[str, loc]: ("test":|project:///rascal/bla.java|(0,0,<0,0>,<1,0>))
rascal>writeJSON(|file:///tmp/test.json|,metrics);
ok
rascal>metrics = readJSON(#map[str, loc], |file:///tmp/test.json|);
|std:///lang/json/IO.rsc|(925,2980,<30,0>,<58,160>): IO("could not parse URI:$.test")
        at *** somewhere ***(|std:///lang/json/IO.rsc|(925,2980,<30,0>,<58,160>))
        at readJSON(|std:///lang/json/IO.rsc|(3873,30,<58,128>,<58,158>))

Is there a better way to serialize/unserialize loc instances to a JSON file?

Appreciate your help with this!


Solution

  • A solution is to write the locations as JSon objects rather than strings, like so:

    writeJSON(|file:///tmp/test.json|,metrics, unpackedLocations=true);
    

    When reading back the file, the parser will see that it has to convert the object back to a Rascal Source location by interpreting the names of each field.

    rascal>l = |project://x/y/z|(10,10,<1,2>,<3,4>);
    loc: |project://x/y/z|(10,10,<1,2>,<3,4>)
    
    rascal>writeJSON(|home:///example.txt|, [l], unpackedLocations=true)
    ok
    
    rascal>println(readFile(|home:///example.txt|))
    [{"scheme":"project","authority":"x","path":"/y/z","offset":10,"length":10,"begin":[1,2],"end":[3,4]}]
    
    rascal>readJSON(#list[loc], |home:///example.txt|)
    list[loc]: [|file:///y/z|(10,10,<1,2>,<3,4>)]
    
    ok