adds Nim's AST to/from NIF

This commit is contained in:
demotomohiro
2025-10-24 06:09:33 +09:00
parent cfefd1d95b
commit e9127b2567
9 changed files with 2638 additions and 0 deletions

1829
compiler/icnif/enum2nif.nim Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
import "../../dist/nimony/src/lib" / [nifstreams]
let
symIdTag* = registerTag("symId")
symTag* = registerTag("s")
typeIdTag* = registerTag("typeId")
typeTag* = registerTag("t")
sonsTag* = registerTag("sons")

View File

@@ -0,0 +1,283 @@
import std / [assertions, tables]
import "../../dist/nimony/src/lib" / [bitabs, nifreader, nifstreams, nifcursors]
import ".." / [ast, idents, lineinfos, options, modules, modulegraphs, msgs, pathutils]
import enum2nif, icniftags
type
DecodeContext = object
graph: ModuleGraph
symbols: Table[int, PSym]
types: Table[int, PType]
proc nodeKind(n: Cursor): TNodeKind {.inline.} =
assert n.kind == ParLe
pool.tags[n.tagId].parseNodeKind()
proc expect(n: Cursor; k: set[NifKind]) =
if n.kind notin k:
when defined(debug):
writeStackTrace()
quit "[NIF decoder] expected: " & $k & " but got: " & $n.kind & toString n
proc expect(n: Cursor; k: NifKind) {.inline.} =
expect n, {k}
proc incExpect(n: var Cursor; k: set[NifKind]) =
inc n
expect n, k
proc incExpect(n: var Cursor; k: NifKind) {.inline.} =
incExpect n, {k}
proc skipParRi(n: var Cursor) =
expect n, {ParRi}
inc n
proc expectTag(n: Cursor; tagId: TagId) =
if n.kind == ParLe and n.tagId == tagId:
discard
else:
when defined(debug):
writeStackTrace()
if n.kind != ParLe:
quit "[NIF decoder] expected: ParLe but got: " & $n.kind & toString n
else:
quit "[NIF decoder] expected: " & pool.tags[tagId] & " but got: " & pool.tags[n.tagId] & toString n
proc incExpectTag(n: var Cursor; tagId: TagId) =
inc n
expectTag(n, tagId)
when false:
proc expectTag(n: Cursor; tag: string) =
let id = pool.tags.getKeyId(tag)
if id == TagId(0):
when defined(debug):
writeStackTrace()
quit "[NIF decoder] expected: " & tag & " but doesn't exist" & toString n
else:
expectTag(n, id)
proc fromNifSymbol(c: var DecodeContext; n: var Cursor): PSym
proc fromNifType(c: var DecodeContext; n: var Cursor): PType
proc fromNif(c: var DecodeContext; n: var Cursor): PNode
proc fromNifSymDef(c: var DecodeContext; n: var Cursor): PSym =
expectTag n, symIdTag
incExpect n, IntLit
let id = pool.integers[n.intId]
incExpect n, Ident
let ident = c.graph.cache.getIdent(pool.strings[n.litId])
incExpect n, IntLit
let itemId = pool.integers[n.intId].int32
incExpect n, ParLe
let kind = parseSymKind(pool.tags[n.tagId])
# TODO: add kind specific data
inc n
skipParRi n
expect n, {Ident, DotToken}
let flags = if n.kind == Ident: pool.strings[n.litId].parseSymFlags else: {}
inc n
var position = if kind == skModule:
expect n, StringLit
let path = pool.strings[n.litId].AbsoluteFile
fileInfoIdx(c.graph.config, path).int
else:
expect n, IntLit
pool.integers[n.intId]
incExpect n, IntLit
let disamb = pool.integers[n.intId].int32
inc n
result = PSym(itemId: ItemId(module: 0, item: itemId),
kind: kind,
name: ident,
flags: flags,
position: position,
disamb: disamb)
# PNode, PSym or PType type fields in PSym can have cycles.
# Add PSym to `c.symbols` before parsing these fields so that
# they can refer this PSym.
assert id notin c.symbols
c.symbols[id] = result
result.typ = c.fromNifType n
result.setOwner(c.fromNifSymbol n)
expect n, Ident
result.loc.k = pool.strings[n.litId].parseLocKind()
incExpect n, StringLit
result.loc.snippet.add pool.strings[n.litId]
inc n
skipParRi n
proc fromNifTypeDef(c: var DecodeContext; n: var Cursor): PType =
expectTag n, typeIdTag
incExpect n, IntLit
let id = pool.integers[n.intId]
incExpect n, IntLit
let itemId = pool.integers[n.intId].int32
incExpect n, Ident
let kind = parseTypeKind(pool.strings[n.litId])
incExpect n, {Ident, DotToken}
let flags = if n.kind == Ident: pool.strings[n.litId].parseTypeFlags else: {}
inc n
result = PType(itemId: ItemId(module: 0, item: itemId),
kind: kind,
flags: flags)
assert id notin c.types
c.types[id] = result
expect n, {DotToken, ParLe}
if n.kind == DotToken:
inc n
else:
expectTag n, sonsTag
inc n
while n.kind != ParRi:
result.addAllowNil c.fromNifType n
inc n
result.n = c.fromNif n
result.setOwner c.fromNifSymbol n
result.sym = c.fromNifSymbol n
skipParRi n
proc fromNifNodeFlags(n: var Cursor): set[TNodeFlag] =
if n.kind == DotToken:
result = {}
inc n
elif n.kind == Ident:
result = parseNodeFlags(pool.strings[n.litId])
inc n
else:
assert false, "expected Node flag but got " & $n.kind
proc fromNifSymbol(c: var DecodeContext; n: var Cursor): PSym =
if n.kind == DotToken:
result = nil
inc n
else:
expect n, ParLe
if n.tagId == symIdTag:
result = c.fromNifSymDef n
elif n.tagId == symTag:
incExpect n, IntLit
result = c.symbols[pool.integers[n.intId]]
inc n
skipParRi n
else:
assert false, "expected symbol tag but got " & pool.tags[n.tagId]
proc fromNifType(c: var DecodeContext; n: var Cursor): PType =
if n.kind == DotToken:
result = nil
inc n
else:
expect n, ParLe
if n.tagId == typeIdTag:
result = c.fromNifTypeDef n
elif n.tagId == typeTag:
incExpect n, IntLit
result = c.types[pool.integers[n.intId]]
inc n
skipParRi n
else:
assert false, "expected type tag but got " & pool.tags[n.tagId]
template withNode(c: var DecodeContext; n: var Cursor; result: PNode; kind: TNodeKind; body: untyped) =
incExpect n, {DotToken, Ident}
let flags = fromNifNodeFlags n
result = newNode(kind)
result.flags = flags
result.typ = c.fromNifType n
body
skipParRi n
proc fromNif(c: var DecodeContext; n: var Cursor): PNode =
result = nil
case n.kind:
of DotToken:
result = nil
inc n
of ParLe:
let kind = n.nodeKind
case kind:
of nkEmpty:
result = newNode(nkEmpty)
inc n
skipParRi n
of nkIdent:
incExpect n, Ident
result = newIdentNode(c.graph.cache.getIdent(pool.strings[n.litId]), unknownLineInfo)
inc n
skipParRi n
of nkSym:
c.withNode n, result, kind:
result.sym = c.fromNifSymbol n
of nkCharLit:
c.withNode n, result, kind:
expect n, CharLit
result.intVal = n.charLit.int
inc n
of nkIntLit .. nkInt64Lit:
c.withNode n, result, kind:
expect n, IntLit
result.intVal = pool.integers[n.intId]
inc n
of nkUIntLit .. nkUInt64Lit:
c.withNode n, result, kind:
expect n, UIntLit
result.intVal = cast[BiggestInt](pool.uintegers[n.uintId])
inc n
of nkFloatLit .. nkFloat128Lit:
c.withNode n, result, kind:
expect n, FloatLit
result.floatVal = pool.floats[n.floatId]
inc n
of nkStrLit .. nkTripleStrLit:
c.withNode n, result, kind:
expect n, StringLit
result.strVal = pool.strings[n.litId]
inc n
of nkNilLit:
c.withNode n, result, kind:
discard
of nkNone:
assert false, "Unknown tag " & pool.tags[n.tagId]
else:
c.withNode n, result, kind:
while n.kind != ParRi:
result.add c.fromNif n
else:
assert false, "Not yet implemented " & $n.kind
proc loadNif(stream: var Stream; graph: ModuleGraph): PNode =
discard processDirectives(stream.r)
var buf = fromStream(stream)
var n = beginRead(buf)
var c = DecodeContext(graph: graph)
result = fromNif(c, n)
endRead(buf)
proc loadNifFile*(infile: AbsoluteFile; graph: ModuleGraph): PNode =
var stream = nifstreams.open(infile.string)
result = loadNif(stream, graph)
stream.close
proc loadNifFromBuffer*(strbuf: sink string; graph: ModuleGraph): PNode =
var stream = nifstreams.openFromBuffer(strbuf)
result = loadNif(stream, graph)
when isMainModule:
import std/cmdline
if paramCount() > 0:
var graph = newModuleGraph(newIdentCache(), newConfigRef())
var node = loadNifFile(paramStr(1).toAbsolute(toAbsoluteDir(".")), graph)
debug(node)

View File

@@ -0,0 +1,177 @@
import std / [assertions, sets]
import ".." / [ast, idents, lineinfos, msgs, options]
import "../../dist/nimony/src/lib" / [bitabs, nifstreams, nifcursors, lineinfos]
import enum2nif, icniftags
type
EncodeContext = object
conf: ConfigRef
decodedSyms: HashSet[PSym]
decodedTypes: HashSet[PType]
dest: TokenBuf
proc initEncodeContext(conf: ConfigRef): EncodeContext =
result = EncodeContext(conf: conf,
dest: createTokenBuf())
template buildTree(dest: var TokenBuf; tag: TagId; body: untyped) =
dest.addParLe tag
body
dest.addParRi
template buildTree(dest: var TokenBuf; tag: string; body: untyped) =
buildTree dest, pool.tags.getOrIncl(tag), body
proc writeFlags[E](dest: var TokenBuf; flags: set[E]) =
var flagsAsIdent = ""
genFlags(flags, flagsAsIdent)
if flagsAsIdent.len > 0:
dest.addIdent flagsAsIdent
else:
dest.addDotToken
proc toNif(c: var EncodeContext; sym: PSym)
proc toNif(c: var EncodeContext; typ: PType)
proc toNif(c: var EncodeContext; n: PNode)
proc toNifDef(c: var EncodeContext; sym: PSym) =
c.dest.buildTree symIdTag:
c.dest.addIntLit sym.id
c.dest.addIdent sym.name.s
c.dest.addIntLit sym.itemId.item
c.dest.buildTree sym.kind.toNifTag:
# TODO: add kind specific data
discard
c.dest.writeFlags sym.flags
if sym.kind == skModule:
# position is module's FileIndex but it cannot be directly encoded
# as the uniqueness of it can broke
# if any import/include statements are changed.
let path = toFullPath(c.conf, sym.position.FileIndex)
c.dest.addStrLit path
else:
c.dest.addIntLit sym.position
c.dest.addIntLit sym.disamb
c.toNif sym.typ
c.toNif sym.owner
c.dest.addIdent toNifTag(sym.loc.k)
c.dest.addStrLit sym.loc.snippet
proc toNifDef(c: var EncodeContext; typ: PType) =
c.dest.buildTree typeIdTag:
c.dest.addIntLit typ.id
c.dest.addIntLit typ.itemId.item
c.dest.addIdent toNifTag(typ.kind)
c.dest.writeFlags typ.flags
# following PType or PSym type field can have cycles but this proc should not called recursively
# as c.decodedTypes prevents it.
if typ.len == 0:
c.dest.addDotToken
else:
c.dest.buildTree sonsTag:
for ch in typ.kids:
c.toNif ch
c.toNif typ.n
c.toNif typ.owner
c.toNif typ.sym
#include nifencodertypes
proc toNif(c: var EncodeContext; sym: PSym) =
if sym == nil:
c.dest.addDotToken()
else:
if not c.decodedSyms.containsOrIncl(sym):
c.toNifDef sym
else:
c.dest.buildTree symTag:
c.dest.addIntLit sym.id
proc toNif(c: var EncodeContext; typ: PType) =
if typ == nil:
c.dest.addDotToken()
else:
if not c.decodedTypes.containsOrIncl(typ):
c.toNifDef typ
else:
c.dest.buildTree typeTag:
c.dest.addIntLit typ.id
proc writeNodeFlags(dest: var TokenBuf; flags: set[TNodeFlag]) {.inline.} =
writeFlags dest, flags
template withNode(c: var EncodeContext; n: PNode; body: untyped) =
c.dest.addParLe pool.tags.getOrIncl(toNifTag(n.kind))
writeNodeFlags(c.dest, n.flags)
c.toNif n.typ
body
c.dest.addParRi
proc toNif(c: var EncodeContext; n: PNode) =
if n == nil:
c.dest.addDotToken
else:
case n.kind:
of nkEmpty:
c.dest.addParLe pool.tags.getOrIncl(toNifTag(nkEmpty))
c.dest.addParRi
of nkIdent:
c.dest.addParLe pool.tags.getOrIncl(toNifTag(nkIdent))
c.dest.addIdent n.ident.s
c.dest.addParRi
of nkSym:
when false:
echo "nkSym: ", n.sym.name.s
if n.sym.kind == skModule:
echo "position = ", n.sym.position
debug(n.sym)
var o = n.sym.owner
for i in 0 .. 20:
if o == nil:
break
echo "owner ", i, ":"
if o.kind == skModule:
echo "position = ", o.position
debug(o)
o = o.owner
# PNode.typ and PNode.sym.typ are different in `int` nkSym Node in following statement:
# type TestInt = int
c.withNode n:
c.toNif n.sym
of nkCharLit:
c.withNode n:
c.dest.add charToken(n.intVal.char, NoLineInfo)
of nkIntLit .. nkInt64Lit:
c.withNode n:
c.dest.addIntLit n.intVal
of nkUIntLit .. nkUInt64Lit:
c.withNode n:
c.dest.addUIntLit cast[BiggestUInt](n.intVal)
of nkFloatLit .. nkFloat128Lit:
c.withNode n:
c.dest.add floatToken(pool.floats.getOrIncl(n.floatVal), NoLineInfo)
of nkStrLit .. nkTripleStrLit:
c.withNode n:
c.dest.addStrLit n.strVal
of nkNilLit:
c.withNode n:
discard
else:
assert n.len > 0, $n.kind
c.withNode(n):
for i in 0 ..< n.len:
c.toNif n[i]
proc saveNif(c: var EncodeContext; n: PNode): string =
toNif c, n
result = "(.nif24)\n" & toString(c.dest)
proc saveNifFile*(module: PSym; n: PNode; conf: ConfigRef) =
let outfile = module.name.s & ".nif"
var c = initEncodeContext(conf)
writeFile outfile, saveNif(c, n)
proc saveNifToBuffer*(n: PNode; conf: ConfigRef): string =
var c = initEncodeContext(conf)
result = saveNif(c, n)

View File

@@ -0,0 +1,271 @@
import std/assertions
import "../../compiler/icnif" / [nifencoder, nifdecoder]
import "../../compiler" / [idents, ast, astalgo, options, pathutils, modulegraphs, modules, msgs, pipelines, syntaxes, sem, llstream, lineinfos]
# This test generates PNode by semchecks test code.
# Then it is used to test icnif/nifencoder and nifdecoder.
const TestCodeDir = currentSourcePath().AbsoluteFile.splitFile().dir / RelativeDir"testcode"
proc newConfigRefForTest(): ConfigRef =
var conf = newConfigRef()
conf.setDefaultLibpath()
conf.searchPaths.add(conf.libpath)
excl(conf.notes, hintProcessing)
excl(conf.mainPackageNotes, hintProcessing)
result = conf
proc newModuleGraphForSem(cache: IdentCache; conf: ConfigRef): ModuleGraph =
var graph = newModuleGraph(cache, conf)
graph.setPipeLinePass(SemPass)
graph.compilePipelineSystemModule()
result = graph
proc sem(graph: ModuleGraph; path: AbsoluteFile): PNode =
result = nil
let fileIdx = fileInfoIdx(graph.config, path)
var module = newModule(graph, fileIdx)
registerModule(graph, module)
var idgen = idGeneratorFromModule(module)
let ctx = preparePContext(graph, module, idgen)
var stream = llStreamOpen(path, fmRead)
if stream == nil:
rawMessage(graph.config, errCannotOpenFile, path.string)
return nil
var p: Parser = default(Parser)
syntaxes.openParser(p, fileIdx, stream, graph.cache, graph.config)
checkFirstLineIndentation(p)
block processCode:
if graph.stopCompile(): break processCode
var n = parseTopLevelStmt(p)
if n.kind == nkEmpty: break processCode
# read everything, no streaming possible
var sl = newNodeI(nkStmtList, n.info)
sl.add n
while true:
var n = parseTopLevelStmt(p)
if n.kind == nkEmpty: break
sl.add n
var semNode = semWithPContext(ctx, sl)
return semNode
type
# Nim's AST has cycles that causes infinite recursive loop in eql procs.
# this is used to prevent that happen.
EqlContext = object
nodeStack: seq[PNode]
symStack: seq[PSym]
typStack: seq[PType]
confX, confY: ConfigRef # used to print the line info when there is a mismatch
# and get path from FileIndex
# Compare PType, PSym and PNode but ignores fields nifencoder and nifdecoder doesn't support
# `x` is generated by sem.nim and `y` is decoded by icnif/nifdecoder.
proc eql(x, y: PNode; c: var EqlContext): bool
proc eql(x, y: PType; c: var EqlContext): bool
proc eql(x, y: TLoc): bool =
if x.k != y.k:
echo "loc kind mismatch: ", x.k, "/", y.k
result = false
elif x.snippet != y.snippet:
echo "loc snippet mismatch: ", x.snippet, "/", y.snippet
result = false
else:
result = true
proc eqlSymPos(x, y: PSym; c: EqlContext): bool =
if x.kind == skModule:
let xpath = c.confX.toFullPath(x.position.FileIndex)
let ypath = c.confY.toFullPath(y.position.FileIndex)
if xpath != ypath:
echo "symbol position mismatch: ", xpath, "/", ypath
result = false
else:
result = true
elif x.position != y.position:
echo "symbol position mismatch: ", x.position, "/", y.position
result = false
else:
result = true
proc eql(x, y: PSym; c: var EqlContext): bool =
if x == nil and y == nil:
result = true
elif x == nil or y == nil:
echo "symbol is missing"
result = false
elif x.name.s != y.name.s:
echo "symbol name mismatch: ", x.name.s, "/", y.name.s
result = false
elif x.itemId.item != y.itemId.item:
echo "symbol itemId.item mismatch: ", x.itemId.item, "/", y.itemId.item
result = false
elif x.kind != y.kind:
echo "symbol kind mismatch: ", x.kind, "/", y.kind
result = false
elif x.flags != y.flags:
echo "symbol flag mismatch: ", x.flags, "/", y.flags
result = false
elif not eqlSymPos(x, y, c):
result = false
elif x.disamb != y.disamb:
echo "symbol disamb mismatch: ", x.disamb, "/", y.disamb
result = false
elif not eql(x.loc, y.loc):
echo "symbol.loc mismatch"
result = false
else:
if c.symStack.len != 0:
for i in countDown(c.symStack.len - 1, 0):
if x == c.symStack[i]:
return true
c.symStack.add x
if not eql(x.typ, y.typ, c):
echo "symbol type mismatch:"
result = false
elif not eql(x.owner, y.owner, c):
echo "Symbol owner mismatch:"
debug(x.owner)
debug(y.owner)
result = false
else:
result = true
discard c.symStack.pop
proc eql(x, y: PType; c: var EqlContext): bool =
if x == nil and y == nil:
result = true
elif x == nil or y == nil:
echo "type is missing"
result = false
elif x.itemId.item != y.itemId.item:
echo "type itemId.item mismatch: ", x.itemId.item, "/", y.itemId.item
result = false
elif x.kind != y.kind:
echo "type kind mismatch: ", x.kind, "/", y.kind
result = false
elif x.flags != y.flags:
echo "type flag mismatch: ", x.flags, "/", y.flags
result = false
else:
if c.typStack.len != 0:
for i in countDown(c.typStack.len - 1, 0):
if x == c.typStack[i]:
# echo "cycle is detected in PType"
return true
c.typStack.add x
if not eql(x.n, y.n, c):
echo "type.n mismatch"
debug(x.n)
debug(y.n)
result = false
elif not eql(x.owner, y.owner, c):
echo "type owner mismatch: "
debug(x.owner)
debug(y.owner)
result = false
elif not eql(x.sym, y.sym, c):
echo "type sym mismatch:"
debug(x.sym)
debug(y.sym)
result = false
elif x.kidsLen != y.kidsLen:
echo "type kidsLen mismatch"
result = false
else:
result = true
for i in 0 ..< x.kidsLen:
if not eql(x[i], y[i], c):
echo "type kids mismatch: "
debug(x[i])
debug(y[i])
result = false
break
discard c.typStack.pop
proc eql(x, y: PNode; c: var EqlContext): bool =
if x == nil and y == nil:
result = true
elif x == nil or y == nil:
result = false
elif x.kind != y.kind:
echo "node kind mismatch: ", x.kind, "/", y.kind
result = false
elif x.flags != y.flags:
echo "node flag mismatch: ", x.flags, "/", y.flags
debug(x)
debug(y)
result = false
elif x.safeLen == y.safeLen:
if c.nodeStack.len != 0:
for i in countDown(c.nodeStack.len - 1, 0):
if x == c.nodeStack[i]:
# echo "cycle is detected in PNode"
return true
c.nodeStack.add x
if not eql(x.typ, y.typ, c):
echo "PNode type mismatch at ", `$`(c.confX, x.info), ":"
debug(x)
debug(y)
debug(x.typ)
debug(y.typ)
result = false
else:
case x.kind:
of nkIdent:
# these idents are generated from different IdentCache
result = x.ident.s == y.ident.s
if not result:
echo "PNode identifier mismatch: ", `$`(c.confX, x.info), x.ident.s, "/", y.ident.s
of nkSym:
result = eql(x.sym, y.sym, c)
if not result:
echo "Symbol mismatch:"
debug(x.sym)
debug(y.sym)
debug(x.sym.typ)
debug(y.sym.typ)
of nkCharLit .. nkTripleStrLit:
result = sameValue(x, y)
else:
result = true
for i in 0 ..< x.safeLen:
if not eql(x[i], y[i], c):
result = false
break
discard c.nodeStack.pop
else:
echo "node length mismatch"
debug(x)
debug(y)
result = false
proc testNifEncDec(graph: ModuleGraph; src: string) =
let fullPath = TestCodeDir / RelativeFile(src)
let n = sem(graph, fullPath)
#debug(n)
let nif = saveNifToBuffer(n, graph.config)
#echo nif
# Don't reuse the ModuleGraph used for semcheck when load NIF.
var graphForLoad = newModuleGraph(newIdentCache(), newConfigRefForTest())
let n2 = loadNifFromBuffer(nif, graphForLoad)
#debug(n2)
var c = EqlContext(confX: graph.config, confY: graphForLoad.config)
assert eql(n, n2, c)
var conf = newConfigRefForTest()
var cache = newIdentCache()
var graph = newModuleGraphForSem(cache, conf)
testNifEncDec(graph, "modtest1.nim")
testNifEncDec(graph, "modtestliterals.nim")
testNifEncDec(graph, "modtesttypesections.nim")
testNifEncDec(graph, "modtestpragmas.nim")

View File

@@ -0,0 +1,2 @@
var x* = 123
var y = x

View File

@@ -0,0 +1,29 @@
var strlit = "test string"
var rstrlit = r"test\t raw"
var triplestrlit = """Triple
string
literal
"""
var charlit = 'a'
var intlit1 = 123456
var intlit2 = -123456
var int8litH = 127'i8
var int8litL = -128'i8
var int16litH = 32767'i16
var int16litL = -32768'i16
var int32litH = 2147483647'i32
var int32litL = -2147483648'i32
var int64litH = 9223372036854775807'i64
var int64litL = -9223372036854775808'i64
var uintlitH = 18446744073709551615'u
var uint8litH = 255'u8
var uint16litH = 65535'u16
var uint32litH = 4294967295'u32
var uint64litH = 18446744073709551615'u64
var floatlit = 1.25
var float32lit = 1.25'f32
var float64lit = 1.25'f64
var nillit: ptr int = nil

View File

@@ -0,0 +1,3 @@
#var exportcTest {.exportc.}: int
var importcTest {.importc.}: int
#var y* {.importc, header: "test.h".}: int

View File

@@ -0,0 +1,36 @@
type
TestInt = int
TestEnum = enum
X
Y
TestDistinct = distinct int
TestObject = object
x*: int
y: int
TestObject2* = object
x: TestObject
TestRefInt = ref int
TestPtrInt = ptr int
TestRefObj = ref object
x: int
TestPtrObj = ptr object
x: int
var x: TestInt
var testEnum: TestEnum
var testEnum1 = X
var testDistinct: TestDistinct
var testObject: TestObject
var testObject2*: TestObject2
var testRefInt: TestRefInt = nil
var testRefInt2: ref int = nil
var testPtrInt: TestPtrInt = nil
var testPtrInt2: ptr int = nil
var testRefObj: TestRefObj = nil
var testPtrObj: TestPtrObj = nil