mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-08 22:13:29 +00:00
progress
This commit is contained in:
@@ -555,7 +555,7 @@ proc cursorFromIndexEntry(c: var DecodeContext; module: int32; entry: NifIndexEn
|
||||
|
||||
proc moduleId(c: var DecodeContext; suffix: string): int32 =
|
||||
# We don't know the "real" FileIndex due to our mapping to a short "Module suffix"
|
||||
# This is not a problem, we use negative `ItemId.module` values here and then
|
||||
# This is not a problem, we use negative `ItemId.module` values here and then
|
||||
# there is no interference with in-memory-modules. Modulegraphs.nim already uses -1
|
||||
# so we start at -2 here.
|
||||
result = c.moduleIds.getOrDefault(suffix)
|
||||
@@ -573,7 +573,7 @@ proc getOffset(c: var DecodeContext; module: int32; nifName: string): NifIndexEn
|
||||
let ii = addr c.mods[index].index
|
||||
result = ii.public.getOrDefault(nifName)
|
||||
if result.offset == 0:
|
||||
result = ii.private.getOrDefault(nifName)
|
||||
result = ii.private.getOrDefault(nifName)
|
||||
if result.offset == 0:
|
||||
raiseAssert "symbol has no offset: " & nifName
|
||||
|
||||
@@ -702,7 +702,7 @@ proc loadType*(c: var DecodeContext; t: PType) =
|
||||
|
||||
t.typeInst = loadTypeStub(c, n)
|
||||
t.n = loadNode(c, n)
|
||||
t.setOwner loadSymStub(c, n)
|
||||
t.setOwner loadSymStub(c, n)
|
||||
t.sym = loadSymStub(c, n)
|
||||
loadLoc c, n, t.loc
|
||||
|
||||
@@ -810,8 +810,7 @@ proc loadNode(c: var DecodeContext; n: var Cursor): PNode =
|
||||
skipParRi n
|
||||
of nkSym:
|
||||
c.withNode n, result, kind:
|
||||
#result.sym = c.fromNifSymbol n
|
||||
discard
|
||||
result.sym = c.loadSymStub n
|
||||
of nkCharLit:
|
||||
c.withNode n, result, kind:
|
||||
expect n, CharLit
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
import std/[assertions, math, tables]
|
||||
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)
|
||||
# Make PNode from sem pass assigned to graph.systemModule.ast
|
||||
let oldCmd = graph.config.cmd
|
||||
graph.config.cmd = cmdIdeTools
|
||||
graph.compilePipelineSystemModule()
|
||||
graph.config.cmd = oldCmd
|
||||
result = graph
|
||||
|
||||
proc getSystemNif(graph: ModuleGraph): seq[string] =
|
||||
result = newSeqOfCap[string](graph.ifaces.len)
|
||||
for i, iface in graph.ifaces.mpairs:
|
||||
if iface.module != nil:
|
||||
let n = iface.module.ast
|
||||
assert n != nil
|
||||
# if nil is not assigned, it generates large NIF
|
||||
iface.module.ast = nil
|
||||
result.add saveNifToBuffer(n, graph.config, iface.module)
|
||||
#writeFile(iface.module.name.s & ".nif", result[^1])
|
||||
|
||||
proc sem(graph: ModuleGraph; path: AbsoluteFile): (PNode, PSym) =
|
||||
result = (nil, 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, 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
|
||||
|
||||
result = (semWithPContext(ctx, sl), module)
|
||||
|
||||
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]
|
||||
checkedSyms: Table[ItemId, PSym] # used to check if each PSym has unique ItemId
|
||||
# and also prevents inifinite loop
|
||||
checkedTypes: Table[ItemId, PType]# used like checkedSyms
|
||||
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 eqlFileIndex(x, y: int; c: EqlContext): bool =
|
||||
let xpath = c.confX.toFullPath(x.FileIndex)
|
||||
let ypath = c.confY.toFullPath(y.FileIndex)
|
||||
if xpath != ypath:
|
||||
echo "file index mismatch: ", xpath, "/", ypath
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc eql(x, y: TLineInfo; c: EqlContext): bool =
|
||||
# If parent PNode has a valid line info but it's child doesn't have one,
|
||||
# cannot translate such a tree to NIF.
|
||||
# Because in NIF, if a child node doesn't have line info,
|
||||
# nifstream assign the parent's line info to it.
|
||||
# So cannot have child node without line info if parent has a valid line info.
|
||||
if x == unknownLineInfo:
|
||||
result = true
|
||||
elif x.line != y.line:
|
||||
echo "line number mismatch: ", x.line, "/", y.line
|
||||
result = false
|
||||
elif x.col != y.col:
|
||||
echo "column number mismatch: ", x.col, "/", y.col
|
||||
result = false
|
||||
elif not eqlFileIndex(x.fileIndex.int, y.fileIndex.int, c):
|
||||
echo "file in line info mismatch"
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc eqlSymPos(x, y: PSym; c: EqlContext): bool =
|
||||
if x.kind == skModule:
|
||||
result = eqlFileIndex(x.position, y.position, c)
|
||||
elif x.position != y.position:
|
||||
echo "symbol position mismatch: ", x.position, "/", y.position
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
|
||||
proc eqlItemId(x, y: ItemId; c: EqlContext): bool =
|
||||
if x.item != y.item:
|
||||
echo "itemId.item mismatch: ", x.item, "/", y.item
|
||||
result = false
|
||||
elif not eqlFileIndex(x.module, y.module, c):
|
||||
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 not eqlItemId(x.itemId, y.itemId, c):
|
||||
echo "symbol itemId mismatch"
|
||||
result = false
|
||||
elif c.checkedSyms.hasKeyOrPut(y.itemId, y):
|
||||
if c.checkedSyms[y.itemId] == y:
|
||||
result = true
|
||||
else:
|
||||
echo "detected duplicated symbol ItemId:"
|
||||
debug(x)
|
||||
debug(c.checkedSyms[y.itemId])
|
||||
debug(y)
|
||||
result = false
|
||||
elif x.name.s != y.name.s:
|
||||
echo "symbol name mismatch: ", x.name.s, "/", y.name.s
|
||||
result = false
|
||||
elif x.kind != y.kind:
|
||||
echo "symbol kind mismatch: ", x.kind, "/", y.kind
|
||||
result = false
|
||||
elif x.magic != y.magic:
|
||||
echo "symbol magic mismatch: ", x.magic, "/", y.magic
|
||||
result = false
|
||||
elif x.kind != skPackage and not eql(x.info, y.info, c):
|
||||
# fileIndex of info of skPackage is just a path of first semchecked module in the package
|
||||
echo "symbol line info mismatch"
|
||||
result = false
|
||||
elif x.kind != skModule and x.flags != y.flags:
|
||||
# TODO: check the flag of skModule
|
||||
echo "symbol flag mismatch: ", x.flags, "/", y.flags
|
||||
result = false
|
||||
elif x.options != y.options:
|
||||
echo "symbol options mismatch: ", x.options, "/", y.options
|
||||
result = false
|
||||
elif not eqlSymPos(x, y, c):
|
||||
result = false
|
||||
elif x.offset != y.offset:
|
||||
echo "symbol offset mismatch: ", x.offset, "/", y.offset
|
||||
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 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
|
||||
elif not eql(x.ast, y.ast, c):
|
||||
echo "symbol ast mismatch"
|
||||
result = false
|
||||
elif not eql(x.constraint, y.constraint, c):
|
||||
echo "symbol constraint mismatch"
|
||||
result = false
|
||||
elif not eql(x.instantiatedFrom, y.instantiatedFrom, c):
|
||||
echo "symbol instantiatedFrom mismatch"
|
||||
result = false
|
||||
else:
|
||||
if x.kind in {skLet, skVar, skField, skForVar}:
|
||||
if not eql(x.guard, y.guard, c):
|
||||
echo "symbol guard mismatch"
|
||||
result = false
|
||||
elif x.bitsize != y.bitsize:
|
||||
echo "symbol bitsize mismatch: ", x.bitsize, "/", y.bitsize
|
||||
result = false
|
||||
elif x.alignment != y.alignment:
|
||||
echo "symbol alignment mismatch: ", x.alignment, "/", y.alignment
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
else:
|
||||
result = true
|
||||
|
||||
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 not eqlItemId(x.itemId, y.itemId, c):
|
||||
echo "type itemId mismatch"
|
||||
result = false
|
||||
elif c.checkedTypes.hasKeyOrPut(y.itemId, y):
|
||||
result = true
|
||||
#[
|
||||
if c.checkedTypes[y.itemId] == y:
|
||||
result = true
|
||||
else:
|
||||
echo "detected duplicated type ItemId:"
|
||||
debug(x)
|
||||
debug(c.checkedTypes[y.itemId])
|
||||
debug(y)
|
||||
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 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
|
||||
|
||||
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, " at ", `$`(c.confX, x.info)
|
||||
debug(x)
|
||||
debug(y)
|
||||
result = false
|
||||
elif not eql(x.info, y. info, c):
|
||||
echo "node lineinfo mismatch at ", `$`(c.confX, x.info)
|
||||
debug(x)
|
||||
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)
|
||||
if y.sym == nil:
|
||||
echo "y.sym = nil"
|
||||
else:
|
||||
debug(y.sym)
|
||||
debug(x.sym.typ)
|
||||
debug(y.sym.typ)
|
||||
of nkCharLit .. nkUInt64Lit, nkStrLit .. nkTripleStrLit:
|
||||
result = sameValue(x, y)
|
||||
of nkFloatLit .. nkFloat128Lit:
|
||||
# want to know if x and y are identical float value.
|
||||
# so x == y doesn't work if both x and y are NaN or x == 0 and y == -0.
|
||||
let xc = classify(x.floatVal)
|
||||
let yc = classify(y.floatVal)
|
||||
if xc == yc:
|
||||
if xc in {fcNormal, fcSubnormal}:
|
||||
if x.floatVal != y.floatVal:
|
||||
echo "float literal mismatch: ", x.floatVal, "/", y.floatVal
|
||||
result = false
|
||||
else:
|
||||
result = true
|
||||
else:
|
||||
result = true
|
||||
else:
|
||||
echo "float literal mismatch: ", xc, "/", yc
|
||||
result = false
|
||||
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; systemNif: openArray[string]) =
|
||||
let fullPath = TestCodeDir / RelativeFile(src)
|
||||
let (n, module) = sem(graph, fullPath)
|
||||
assert n != nil, "failed to sem " & $fullPath
|
||||
assert module.owner.kind == skPackage
|
||||
|
||||
#debug(n)
|
||||
let nif = saveNifToBuffer(n, graph.config, module)
|
||||
#echo nif
|
||||
#echo "NIF size of ", src, ": ", nif.len
|
||||
#writeFile(src & ".nif", nif)
|
||||
|
||||
# Don't reuse the ModuleGraph used for semcheck when load NIF.
|
||||
var graphForLoad = newModuleGraph(newIdentCache(), newConfigRefForTest())
|
||||
var prog = NifProgram()
|
||||
for sysNif in systemNif:
|
||||
discard loadNifFromBuffer(sysNif, graphForLoad, prog)
|
||||
let n2 = loadNifFromBuffer(nif, graphForLoad, prog)
|
||||
#debug(n2)
|
||||
var c = EqlContext(confX: graph.config, confY: graphForLoad.config)
|
||||
assert eql(n, n2, c), "test failed: " & $fullPath
|
||||
|
||||
var conf = newConfigRefForTest()
|
||||
var cache = newIdentCache()
|
||||
var graph = newModuleGraphForSem(cache, conf)
|
||||
let systemNif = getSystemNif(graph)
|
||||
testNifEncDec(graph, "modtest1.nim", systemNif)
|
||||
testNifEncDec(graph, "modtestliterals.nim", systemNif)
|
||||
testNifEncDec(graph, "modtesttypesections.nim", systemNif)
|
||||
#testNifEncDec(graph, "modtestpragmas.nim", systemNif)
|
||||
testNifEncDec(graph, "modtestprocs.nim", systemNif)
|
||||
#testNifEncDec(graph, "modteststatements.nim", systemNif)
|
||||
#testNifEncDec(graph, "modtestgenerics.nim", systemNif)
|
||||
#testNifEncDec(graph, "modtestexprs.nim", systemNif)
|
||||
Reference in New Issue
Block a user