Skip to content

Weird error with custom parsehooks #103

@sonicsmooth

Description

@sonicsmooth

I just posted this on nim forum too.

Using jsony 1.1.6
Nim 2.2.0 in Windows, 2.3.1 in ubuntu WSL

I'm trying to parse pairs of ints like (10,20) in json by using a custom parser and object variants. Eventually I want to do (1.23. 3.14), or ($var1, $var2), etc., so it should support ints, floats, and strings. Everything should be in double quotes so it's json compliant. There is a parsehook for JVal variant type which can hold int, float, or string, and another parsehook for JPoint. The JPoint is a pair of JVals. The JShape is either two JPoints, or a seq of JPoints.

The error occurs when creating a JShape and is thrown from jsony.nim proc parseObjectInner[T](s: string, i: var int, v: var T) = where it assigns v = v2 (line 390 in the version I have)

Here are some strange observations:

  • If I simplify the JVal type to just one int member, the problem goes away.
  • The problem comes back if I add any other member in JVal; it doesn't have to be a variant to fail
  • Within parseObjectInner I can echo v2.typeof and get seq[JPoint] which is correct, and I can echo v2 which displays the @[...] sequence, but if I echo v2.len then compiler fails with type mismatch: v2 is ShapeKind.
  • This weirdness occurs even if JVal type has one int member and the program works overall.
  • I have tried various versions of this, both with and without quotes, trying to parse my own seq[int] in another parsehook, etc., and this weird nil access always appears when the json becomes a real object like skLine, skPolyLine, etc. Just parsing a seq of JPoints seems to work.

Why can't I get this to work?
Thanks

import std/[json, strutils]
import jsony



type
  VarKind = enum vkInt, vkFloat, vkString
  JVal = object
    case kind: VarKind
    of vkInt: intVal: int
    of vkFloat: floatVal: float
    of vkString: strVal: string

  JPoint = object of RootObj
    x, y: JVal

  ShapeKind = enum skLine, skPolyLine
  JShape = object
    case kind: ShapeKind
    of skLine:
      pt0: JPoint
      pt1: JPoint
    of skPolyLine:
      pts: seq[JPoint]

proc parseHook(s: string, i: var int, val: var JVal) =
  # Only parse ints for now to keep it simple
  var x: int
  parseHook(s, i, x)
  val = JVal(kind: vkInt, intVal: x)
  echo "created jval: ", val

proc parseHook(s: string, i: var int, val: var JPoint) =
  # Parse (x, y)
  echo "Parsing JPoint at index ", i
  var x, y: JVal
  eatChar(s, i, '"')
  eatChar(s, i, '(')
  parseHook(s, i, x)
  eatChar(s, i, ',')
  parseHook(s, i, y)
  eatChar(s, i, ')')
  eatChar(s, i, '"')
  val = JPoint(x: x, y: y)


try:
  # OK
  echo "Doing JPoint"
  echo """ "(1, 2)" """.fromJson(JPoint)
  echo ""

  # OK
  echo "Doing seq of JPoints"
  echo """ ["(1, 2)", "(3, 4)"]  """.fromJson(seq[JPoint])
  echo ""

  # OK
  echo "Doing JShape with line"
  echo """{"kind": "skLine", "pt0": "(1, 2)", "pt1": "(3, 4)"}""".fromJson(JShape)
  echo ""

  # Error: SIGSEGV: Illegal storage access. (Attempt to read from nil?)
  echo "doing JShape with polyline"
  echo """{"kind": "skPolyLine", "pts": ["(1, 2)", "(3, 4)"]}""".fromJson(JShape)
  echo ""

except Exception as e:
  echo e.msg
  echo e.getStackTrace()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions