mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-09 22:43:34 +00:00
adds Nim's AST to/from NIF
This commit is contained in:
1829
compiler/icnif/enum2nif.nim
Normal file
1829
compiler/icnif/enum2nif.nim
Normal file
File diff suppressed because it is too large
Load Diff
8
compiler/icnif/icniftags.nim
Normal file
8
compiler/icnif/icniftags.nim
Normal 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")
|
||||
283
compiler/icnif/nifdecoder.nim
Normal file
283
compiler/icnif/nifdecoder.nim
Normal 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)
|
||||
177
compiler/icnif/nifencoder.nim
Normal file
177
compiler/icnif/nifencoder.nim
Normal 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)
|
||||
271
tests/icnif/tencode_node2node.nim
Normal file
271
tests/icnif/tencode_node2node.nim
Normal 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")
|
||||
2
tests/icnif/testcode/modtest1.nim
Normal file
2
tests/icnif/testcode/modtest1.nim
Normal file
@@ -0,0 +1,2 @@
|
||||
var x* = 123
|
||||
var y = x
|
||||
29
tests/icnif/testcode/modtestliterals.nim
Normal file
29
tests/icnif/testcode/modtestliterals.nim
Normal 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
|
||||
3
tests/icnif/testcode/modtestpragmas.nim
Normal file
3
tests/icnif/testcode/modtestpragmas.nim
Normal file
@@ -0,0 +1,3 @@
|
||||
#var exportcTest {.exportc.}: int
|
||||
var importcTest {.importc.}: int
|
||||
#var y* {.importc, header: "test.h".}: int
|
||||
36
tests/icnif/testcode/modtesttypesections.nim
Normal file
36
tests/icnif/testcode/modtesttypesections.nim
Normal 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
|
||||
Reference in New Issue
Block a user