From de8b01e84160c4d6495d2e8e2fcba396a865db5d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 12 Feb 2025 12:44:57 +0100 Subject: [PATCH] NIFC: follow scopes for precise typing information (#518) * NIFC: follow scopes for precise typing information * NIFC: (addr arr) must produce &arr.a --- src/lib/programs.nim | 67 ----------------------------------------- src/nifc/codegen.nim | 10 +++++- src/nifc/genexprs.nim | 15 ++++++++- src/nifc/genstmts.nim | 2 ++ src/nifc/nifc_model.nim | 14 +++++++++ src/nifc/typenav.nim | 6 ++++ 6 files changed, 45 insertions(+), 69 deletions(-) delete mode 100644 src/lib/programs.nim diff --git a/src/lib/programs.nim b/src/lib/programs.nim deleted file mode 100644 index 06a28a0e..00000000 --- a/src/lib/programs.nim +++ /dev/null @@ -1,67 +0,0 @@ -# Nif library -# (c) Copyright 2024 Andreas Rumpf -# -# See the file "license.txt", included in this -# distribution, for details about the copyright. - -## A "program" is a set of NIF files. - -import std / [tables, os] -import nifreader - -type - DefMode = enum - Undef, Unfinished, FromFile, FromMem - Definition = object - m: DefMode - n: RestorePoint - Module = object - r: Reader - Program* = object - modules: Table[string, Module] - syms: Table[string, Definition] - thisModule: string - nifdir: string - -proc extractModuleSuffix(p: Program; name: string): string = - var i = name.len - 1 - while i >= 0: - if name[i] == '.': - return name.substr(i+1) - dec i - return p.thisModule - -proc fatal*(msg: string) = - quit msg - -proc loadModule(p: var Program; suffix: string) = - if not p.modules.hasKey(suffix): - let nifFile = p.nifdir / (suffix & ".nif") - var r = nifreader.open(nifFile) - r.trackDefs = true - let res = processDirectives(r) - if res != Success: - fatal($res & " invalid file: " & nifFile) - p.modules[suffix] = Module(r: r) - -proc wasLoaded*(n: RestorePoint): bool {.inline.} = - result = n.success - -proc loadSym*(p: var Program; name: string): RestorePoint = - let d = p.syms.getOrDefault(name) - if d.m == Undef: - let suffix = extractModuleSuffix(p, name) - if suffix == p.thisModule: - # no attached reader! - result = default(RestorePoint) - else: - loadModule p, suffix - let r = addr p.modules[suffix].r - let old = savePos(r[]) - let rp = nifreader.jumpTo(r[], name) - if success(rp): - result = rp - restore(r[], old) - else: - result = default(RestorePoint) - p.syms[name] = Definition(m: FromFile, n: result) diff --git a/src/nifc/codegen.nim b/src/nifc/codegen.nim index e0ef3d2b..9da9bed5 100644 --- a/src/nifc/codegen.nim +++ b/src/nifc/codegen.nim @@ -290,7 +290,9 @@ proc genParamPragmas(c: var GeneratedCode; n: var Cursor) = proc genParam(c: var GeneratedCode; n: var Cursor) = var d = takeParamDecl(n) if d.name.kind == SymbolDef: - let name = mangle(pool.syms[d.name.symId]) + let lit = d.name.symId + c.m.registerLocal(lit, d.typ) + let name = mangle(pool.syms[lit]) genType c, d.typ, name genParamPragmas c, d.pragmas else: @@ -416,6 +418,7 @@ proc genVarDecl(c: var GeneratedCode; n: var Cursor; vk: VarKind; toExtern = fal var d = takeVarDecl(n) if d.name.kind == SymbolDef: let lit = d.name.symId + c.m.registerLocal(lit, d.typ) let name = mangle(pool.syms[lit]) let beforeDecl = c.code.len if toExtern: @@ -450,6 +453,7 @@ include genstmts proc genProcDecl(c: var GeneratedCode; n: var Cursor; isExtern: bool) = + c.m.openScope() let signatureBegin = c.code.len var prc = takeProcDecl(n) @@ -546,6 +550,7 @@ proc genProcDecl(c: var GeneratedCode; n: var Cursor; isExtern: bool) = c.add CurlyRi if isSelectAny in flags: genRoutineGuardEnd(c) + c.m.closeScope() proc genInclude(c: var GeneratedCode; n: var Cursor) = inc n @@ -641,6 +646,7 @@ proc generateCode*(s: var State, inp, outp: string; flags: set[GenFlag]) = var m = load(inp) m.config = s.config var c = initGeneratedCode(m, flags) + c.m.openScope() var co = TypeOrder() traverseTypes(c.m, co) @@ -685,3 +691,5 @@ proc generateCode*(s: var State, inp, outp: string; flags: set[GenFlag]) = for x in items(c.headerFile): write h, c.tokens[x] h.close() + + c.m.closeScope() diff --git a/src/nifc/genexprs.nim b/src/nifc/genexprs.nim index 97b9d581..39e9f3a6 100644 --- a/src/nifc/genexprs.nim +++ b/src/nifc/genexprs.nim @@ -181,6 +181,18 @@ proc suffixConv(c: var GeneratedCode; value, suffix: Cursor) = genx c, value c.add ParRi +proc genAddr(c: var GeneratedCode; n: var Cursor) = + # If we take the address of an array expression, add the `.a` field access. + inc n + let arrType = getType(c.m, n) + c.add ParLe + c.add "&" + genx c, n + if arrType.typeKind == ArrayT and not c.m.isImportC(arrType): + c.add ".a" + c.add ParRi + skipParRi n + proc genx(c: var GeneratedCode; n: var Cursor) = case n.exprKind of NoExpr: @@ -268,7 +280,8 @@ proc genx(c: var GeneratedCode; n: var Cursor) = genx c, n c.add ParRi skipParRi n - of AddrC: unOp c, n, "&" + of AddrC: + genAddr c, n of SizeofC: c.add "sizeof" c.add ParLe diff --git a/src/nifc/genstmts.nim b/src/nifc/genstmts.nim index 47be8a70..ed0b243d 100644 --- a/src/nifc/genstmts.nim +++ b/src/nifc/genstmts.nim @@ -100,10 +100,12 @@ proc genTryCpp(c: var GeneratedCode; n: var Cursor) = proc genScope(c: var GeneratedCode; n: var Cursor) = c.add CurlyLe inc n + c.m.openScope() while n.kind != ParRi: c.genStmt n skipParRi n c.add CurlyRi + c.m.closeScope() proc genBranchValue(c: var GeneratedCode; n: var Cursor) = if n.kind in {IntLit, UIntLit, CharLit, Symbol} or n.exprKind in {TrueC, FalseC}: diff --git a/src/nifc/nifc_model.nim b/src/nifc/nifc_model.nim index 97810219..3f16df36 100644 --- a/src/nifc/nifc_model.nim +++ b/src/nifc/nifc_model.nim @@ -17,6 +17,10 @@ type pos*: int kind*: NifcSym + TypeScope* {.acyclic.} = ref object + locals*: Table[SymId, Cursor] + parent*: TypeScope + Module* = object src*: TokenBuf types*: seq[int] @@ -25,12 +29,22 @@ type config*: ConfigRef mem*: seq[TokenBuf] # for intermediate results such as computed types builtinTypes*: Table[string, Cursor] + current*: TypeScope proc bug*(msg: string) {.noreturn.} = when defined(debug): writeStackTrace() quit "BUG: " & msg +proc registerLocal*(c: var Module; s: SymId; typ: Cursor) = + c.current.locals[s] = typ + +proc openScope*(c: var Module) = + c.current = TypeScope(locals: initTable[SymId, Cursor](), parent: c.current) + +proc closeScope*(c: var Module) = + c.current = c.current.parent + proc skipParRi*(n: var Cursor) = # XXX: Give NIFC some better error reporting. if n.kind == ParRi: diff --git a/src/nifc/typenav.nim b/src/nifc/typenav.nim index d23db56e..13a8dbd2 100644 --- a/src/nifc/typenav.nim +++ b/src/nifc/typenav.nim @@ -27,6 +27,12 @@ proc getType*(m: var Module; n: Cursor): Cursor = of DotToken, Ident, SymbolDef: result = createIntegralType(m, "(err)") of Symbol: + var it {.cursor.} = m.current + while it != nil: + let res = it.locals.getOrDefault(n.symId) + if not cursorIsNil(res): + return res + it = it.parent let d = m.defs.getOrDefault(n.symId) if d.pos != 0: result = getType(m, m.src.cursorAt(d.pos))