///|
async test {
  let source = @fs.read_file("test.txt").text()
  let source = remove_block_line(source)
  let (impls, _) = @parser.parse_string(source)
  let directives = impls.map(extract_directive)
  let patches = generate_patch(directives)
  @basic.show_loc.protect(String, fn() {
    // println(impls.to_json().stringify(indent=2))
    @json.inspect(directives.to_json(), content=[
      ["Type", { "name": "SharedArrayBuffer", "hole": "2:1-3:23" }],
      [
        "Constructor",
        {
          "ty": "SharedArrayBuffer",
          "arguments": {
            "length": [
              "Optional",
              {
                "name": "length",
                "ty": ["Constr", { "type": "LongIdent::Ident", "0": "Int" }, []],
              },
            ],
            "max_byte_length": [
              "Optional",
              {
                "name": "max_byte_length",
                "ty": ["Constr", { "type": "LongIdent::Ident", "0": "Int" }, []],
              },
            ],
          },
          "throws": [],
          "hole": "7:3-10:4",
        },
      ],
      [
        "Getter",
        {
          "name": "byteLength",
          "ty": "SharedArrayBuffer",
          "result": ["Constr", { "type": "LongIdent::Ident", "0": "Int" }, []],
          "throws": [],
          "hole": "15:3-15:45",
        },
      ],
      [
        "Getter",
        {
          "name": "growable",
          "ty": "SharedArrayBuffer",
          "result": ["Constr", { "type": "LongIdent::Ident", "0": "Bool" }, []],
          "throws": [],
          "hole": "20:3-20:43",
        },
      ],
      [
        "Getter",
        {
          "name": "maxByteLength",
          "ty": "SharedArrayBuffer",
          "result": ["Constr", { "type": "LongIdent::Ident", "0": "Int" }, []],
          "throws": [],
          "hole": "25:3-25:48",
        },
      ],
      [
        "Method",
        {
          "name": "grow",
          "ty": "SharedArrayBuffer",
          "arguments": {
            "new_size": [
              "Positional",
              {
                "name": "new_size",
                "ty": ["Constr", { "type": "LongIdent::Ident", "0": "Int" }, []],
              },
            ],
            "loc": [
              "Labeled",
              {
                "name": "loc",
                "ty": [
                  "Constr",
                  { "type": "LongIdent::Ident", "0": "SourceLoc" },
                  [],
                ],
              },
            ],
          },
          "result": ["Constr", { "type": "LongIdent::Ident", "0": "Unit" }, []],
          "throws": ["TypeError", "RangeError"],
          "hole": "36:3-38:5",
          "source_loc": "loc",
        },
      ],
      [
        "Method",
        {
          "name": "slice",
          "ty": "SharedArrayBuffer",
          "arguments": {
            "start": [
              "Optional",
              {
                "name": "start",
                "ty": ["Constr", { "type": "LongIdent::Ident", "0": "Int" }, []],
              },
            ],
            "end": [
              "Optional",
              {
                "name": "end",
                "ty": ["Constr", { "type": "LongIdent::Ident", "0": "Int" }, []],
              },
            ],
            "loc": [
              "Labeled",
              {
                "name": "loc",
                "ty": [
                  "Constr",
                  { "type": "LongIdent::Ident", "0": "SourceLoc" },
                  [],
                ],
              },
            ],
          },
          "result": ["Constr", { "type": "LongIdent::Ident", "0": "Self" }, []],
          "throws": ["RangeError"],
          "hole": "50:3-57:5",
          "source_loc": "loc",
        },
      ],
      ["Generated", { "hole": "60:1-64:103" }],
      ["Generated", { "hole": "66:1-69:37" }],
      ["Generated", { "hole": "71:1-74:36" }],
      ["Generated", { "hole": "76:1-79:40" }],
      ["Generated", { "hole": "81:1-86:63" }],
      ["Generated", { "hole": "88:1-94:81" }],
    ])
    @json.inspect(patches, content=[
      [
        "Replace", "2:1-3:23", " #webgen.ty\n struct SharedArrayBuffer @Yoorkin/jmop.Object",
      ],
      [
        "Replace", "7:3-10:4", "ffi_SharedArrayBuffer_new(@Yoorkin/jmop.Optional::from_option(length), @Yoorkin/jmop.Optional::from_option(max_byte_length))",
      ],
      [
        "Append", "#webgen.generated\nextern \"js\" fn ffi_SharedArrayBuffer_new(length : @Yoorkin/jmop.Optional[Int], max_byte_length : @Yoorkin/jmop.Optional[Int]) -> SharedArrayBuffer = \n    \"(length, max_byte_length) => new SharedArrayBuffer(length, max_byte_length)\" ",
      ],
      ["Replace", "15:3-15:45", "ffi_SharedArrayBuffer_get_byteLength(self)"],
      [
        "Append", "#webgen.generated\nextern \"js\" fn ffi_SharedArrayBuffer_get_byteLength(ins : SharedArrayBuffer) -> Int\n  = \"(ins) => ins.byteLength\" ",
      ],
      ["Replace", "20:3-20:43", "ffi_SharedArrayBuffer_get_growable(self)"],
      [
        "Append", "#webgen.generated\nextern \"js\" fn ffi_SharedArrayBuffer_get_growable(ins : SharedArrayBuffer) -> Bool\n  = \"(ins) => ins.growable\" ",
      ],
      ["Replace", "25:3-25:48", "ffi_SharedArrayBuffer_get_maxByteLength(self)"],
      [
        "Append", "#webgen.generated\nextern \"js\" fn ffi_SharedArrayBuffer_get_maxByteLength(ins : SharedArrayBuffer) -> Int\n  = \"(ins) => ins.maxByteLength\" ",
      ],
      [
        "Replace", "36:3-38:5", "@Yoorkin/jmop.convert_error(loc, fn(){ffi_SharedArrayBuffer_grow(self, new_size, loc)})",
      ],
      [
        "Append", "#webgen.generated\nextern \"js\" fn ffi_SharedArrayBuffer_grow(ins : SharedArrayBuffer, new_size : Int, loc : SourceLoc) -> Unit =\n   \"(self,new_size, loc) => self.grow(new_size, loc)\" ",
      ],
      [
        "Replace", "50:3-57:5", "@Yoorkin/jmop.convert_error(loc, fn(){ffi_SharedArrayBuffer_slice(self, @Yoorkin/jmop.Optional::from_option(start), @Yoorkin/jmop.Optional::from_option(end), loc)})",
      ],
      [
        "Append", "#webgen.generated\nextern \"js\" fn ffi_SharedArrayBuffer_slice(ins : SharedArrayBuffer, start : @Yoorkin/jmop.Optional[Int], end : @Yoorkin/jmop.Optional[Int], loc : SourceLoc) -> SharedArrayBuffer =\n   \"(self,start, end, loc) => self.slice(start, end, loc)\" ",
      ],
      ["Remove", "60:1-64:103"],
      ["Remove", "66:1-69:37"],
      ["Remove", "71:1-74:36"],
      ["Remove", "76:1-79:40"],
      ["Remove", "81:1-86:63"],
      ["Remove", "88:1-94:81"],
    ])
  })
  let result = apply_patch0(source, patches)
  inspect(
    result,
    content=(
      #|/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer
      #| #webgen.ty
      #| struct SharedArrayBuffer @Yoorkin/jmop.Object
      #|
      #|#webgen.constructor
      #|pub fn SharedArrayBuffer::new(length? : Int, max_byte_length? : Int) -> Self {
      #|  ffi_SharedArrayBuffer_new(@Yoorkin/jmop.Optional::from_option(length), @Yoorkin/jmop.Optional::from_option(max_byte_length))
      #|}
      #|
      #|#webgen.getter
      #|pub fn SharedArrayBuffer::get_byte_length(self : Self) -> Int {
      #|  ffi_SharedArrayBuffer_get_byteLength(self)
      #|}
      #|
      #|#webgen.getter
      #|pub fn SharedArrayBuffer::is_growable(self : Self) -> Bool {
      #|  ffi_SharedArrayBuffer_get_growable(self)
      #|}
      #|
      #|#webgen.getter
      #|pub fn SharedArrayBuffer::get_max_byte_length(self : Self) -> Int {
      #|  ffi_SharedArrayBuffer_get_maxByteLength(self)
      #|}
      #|
      #|#webgen.method
      #|#webgen.throws("TypeError", "RangeError")
      #|#callsite(autofill(loc))
      #|pub fn SharedArrayBuffer::grow(
      #|  self : Self,
      #|  new_size : Int,
      #|  loc~ : SourceLoc,
      #|) -> Unit raise Error {
      #|  @Yoorkin/jmop.convert_error(loc, fn(){ffi_SharedArrayBuffer_grow(self, new_size, loc)})
      #|}
      #|
      #|#webgen.method
      #|#webgen.throws("RangeError")
      #|#callsite(autofill(loc))
      #|pub fn SharedArrayBuffer::slice(
      #|  self : Self,
      #|  start? : Int,
      #|  end? : Int,
      #|  loc~ : SourceLoc,
      #|) -> Self raise Error {
      #|  @Yoorkin/jmop.convert_error(loc, fn(){ffi_SharedArrayBuffer_slice(self, @Yoorkin/jmop.Optional::from_option(start), @Yoorkin/jmop.Optional::from_option(end), loc)})
      #|}
      #|
      #|
      #|
      #|
      #|
      #|
      #|
      #|
      #|
      #|
      #|
      #|
      #|
      #|#webgen.generated
      #|extern "js" fn ffi_SharedArrayBuffer_new(length : @Yoorkin/jmop.Optional[Int], max_byte_length : @Yoorkin/jmop.Optional[Int]) -> SharedArrayBuffer = 
      #|    "(length, max_byte_length) => new SharedArrayBuffer(length, max_byte_length)" 
      #|#webgen.generated
      #|extern "js" fn ffi_SharedArrayBuffer_get_byteLength(ins : SharedArrayBuffer) -> Int
      #|  = "(ins) => ins.byteLength" 
      #|#webgen.generated
      #|extern "js" fn ffi_SharedArrayBuffer_get_growable(ins : SharedArrayBuffer) -> Bool
      #|  = "(ins) => ins.growable" 
      #|#webgen.generated
      #|extern "js" fn ffi_SharedArrayBuffer_get_maxByteLength(ins : SharedArrayBuffer) -> Int
      #|  = "(ins) => ins.maxByteLength" 
      #|#webgen.generated
      #|extern "js" fn ffi_SharedArrayBuffer_grow(ins : SharedArrayBuffer, new_size : Int, loc : SourceLoc) -> Unit =
      #|   "(self,new_size, loc) => self.grow(new_size, loc)" 
      #|#webgen.generated
      #|extern "js" fn ffi_SharedArrayBuffer_slice(ins : SharedArrayBuffer, start : @Yoorkin/jmop.Optional[Int], end : @Yoorkin/jmop.Optional[Int], loc : SourceLoc) -> SharedArrayBuffer =
      #|   "(self,start, end, loc) => self.slice(start, end, loc)" 
    ),
  )
}