Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement field visibility #345

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions src/hastur.nim
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ type
proc toCommand(cat: Category): string =
case cat
of Basics: "m"
of Normal, Tracked: "c"
of Normal, Tracked: "c --silentMake"

proc execNimony(cmd: string; cat: Category): (string, int) =
result = execLocal("nimony", toCommand(cat) & " " & cmd)
Expand All @@ -157,6 +157,15 @@ proc generatedFile(orig, ext: string): string =
let name = modnames.moduleSuffix(orig, [])
result = "nifcache" / name.addFileExt(ext)

proc removeMakeErrors(output: string): string =
result = output.strip
for prefix in ["FAILURE:", "make:"]:
let lastLine = rfind(result, '\n')
if lastLine >= 0 and lastLine + prefix.len < result.len and
result[lastLine + 1 .. lastLine + prefix.len] == prefix:
result = result[0 .. lastLine].strip
else: break

proc testFile(c: var TestCounters; file: string; overwrite: bool; cat: Category) =
inc c.total
var nimonycmd = (if cat == Basics: "--noSystem " else: "") & "--isMain"
Expand All @@ -169,11 +178,12 @@ proc testFile(c: var TestCounters; file: string; overwrite: bool; cat: Category)
var expectedExitCode = 0
if msgs.fileExists():
let msgSpec = readFile(msgs).strip
let success = msgSpec == compilerOutput.strip
let strippedOutput = removeMakeErrors(compilerOutput)
let success = msgSpec == strippedOutput
if not success:
if overwrite:
writeFile(msgs, compilerOutput)
failure c, file, msgSpec, compilerOutput
writeFile(msgs, strippedOutput)
failure c, file, msgSpec, strippedOutput
expectedExitCode = if msgSpec.contains(ErrorKeyword): 1 else: 0
if compilerExitCode != expectedExitCode:
failure c, file, "compiler exitcode " & $expectedExitCode, compilerOutput & "\nexitcode " & $compilerExitCode
Expand Down Expand Up @@ -415,6 +425,7 @@ proc handleCmdLine =

case primaryCmd
of "all":
buildNimsem()
buildNimony()
buildNifc()
buildGear3()
Expand Down
6 changes: 4 additions & 2 deletions src/nimony/deps.nim
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ proc generateMakefile(c: DepContext; commandLineArgs: string): string =
result = "nifcache" / c.rootNode.files[0].modname & ".makefile"
writeFile result, s

proc buildGraph*(config: sink NifConfig; project: string; compat, forceRebuild: bool;
proc buildGraph*(config: sink NifConfig; project: string; compat, forceRebuild, silentMake: bool;
commandLineArgs: string; moduleFlags: set[ModuleFlag]; cmd: Command) =
let nifler = findTool("nifler")

Expand All @@ -333,6 +333,8 @@ proc buildGraph*(config: sink NifConfig; project: string; compat, forceRebuild:
when defined(windows):
putEnv("CC", "gcc")
putEnv("CXX", "g++")
exec "make" & (if forceRebuild: " -B" else: "") & " -f " & quoteShell(makeFilename)
exec "make" & (if silentMake: " -s" else: "") &
(if forceRebuild: " -B" else: "") &
" -f " & quoteShell(makeFilename)
if cmd == DoRun:
exec exeFile(c.rootNode.files[0])
9 changes: 7 additions & 2 deletions src/nimony/nimony.nim
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Options:
--isMain passed module is the main module of a project
--noSystem do not auto-import `system.nim`
--bits:N `int` has N bits; possible values: 64, 32, 16
--silentMake suppresses make output
--version show the version
--help show this help
"""
Expand Down Expand Up @@ -62,6 +63,7 @@ proc handleCmdLine() =
var cmd = Command.None
var forceRebuild = false
var compat = false
var silentMake = false
var useEnv = true
var doRun = false
var moduleFlags: set[ModuleFlag] = {}
Expand Down Expand Up @@ -110,6 +112,9 @@ proc handleCmdLine() =
of "32": config.bits = 32
of "16": config.bits = 16
else: quit "invalid value for --bits"
of "silentmake":
silentMake = true
forwardArg = false
of "ischild":
# undocumented command line option, by design
isChild = true
Expand Down Expand Up @@ -148,8 +153,8 @@ proc handleCmdLine() =
requiresTool "nimsem", "src/nimony/nimsem.nim", forceRebuild
requiresTool "gear3", "src/gear3/gear3.nim", forceRebuild
requiresTool "nifc", "src/nifc/nifc.nim", forceRebuild
buildGraph config, args[0], compat, forceRebuild, commandLineArgs, moduleFlags,
(if doRun: DoRun else: DoCompile)
buildGraph config, args[0], compat, forceRebuild, silentMake,
commandLineArgs, moduleFlags, (if doRun: DoRun else: DoCompile)

when isMainModule:
handleCmdLine()
73 changes: 65 additions & 8 deletions src/nimony/sem.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1349,7 +1349,15 @@ proc semCall(c: var SemContext; it: var Item; source: TransformedCallSource = Re
else:
resolveOverloads c, it, cs

proc findObjField(t: Cursor; name: StrId; level = 0): ObjField =
proc genericRootSym(td: TypeDecl): SymId =
result = td.name.symId
if td.typevars.typeKind == InvokeT:
var root = td.typevars
inc root
assert root.kind == Symbol
result = root.symId

proc findObjFieldAux(t: Cursor; name: StrId; level = 0): ObjField =
assert t == "object"
var n = t
inc n # skip `(object` token
Expand All @@ -1360,9 +1368,10 @@ proc findObjField(t: Cursor; name: StrId; level = 0): ObjField =
if n.kind == SymbolDef and sameIdent(n.symId, name):
let symId = n.symId
inc n # skip name
let exported = n.kind != DotToken
skip n # export marker
skip n # pragmas
return ObjField(sym: symId, level: level, typ: n)
return ObjField(sym: symId, level: level, typ: n, exported: exported, rootOwner: SymId(0))
skip n # skip name
skip n # export marker
skip n # pragmas
Expand All @@ -1377,11 +1386,44 @@ proc findObjField(t: Cursor; name: StrId; level = 0): ObjField =
if baseType.typeKind == InvokeT:
inc baseType # get to root symbol
if baseType.kind == Symbol:
result = findObjField(objtypeImpl(baseType.symId), name, level+1)
let decl = getTypeSection(baseType.symId)
var objType = decl.body
# emulate objtypeImpl
if objType.typeKind in {RefT, PtrT}:
inc objType
result = findObjFieldAux(objType, name, level+1)
if result.level == level+1:
result.rootOwner = genericRootSym(decl)
else:
# maybe error
result = ObjField(level: -1)

proc findObjFieldConsiderVis(c: var SemContext; decl: TypeDecl; name: StrId; info: PackedLineInfo): ObjField =
var impl = decl.body
# emulate objtypeImpl
if impl.typeKind in {RefT, PtrT}:
inc impl
result = findObjFieldAux(impl, name)
if result.level == 0:
result.rootOwner = genericRootSym(decl)
if result.level >= 0:
# check visibility
var visible = false
if result.exported:
visible = true
else:
let owner = result.rootOwner
if owner == SymId(0):
visible = true
else:
let ownerModule = extractModule(pool.syms[owner])
# safe to get this from line info?
let currentModule = moduleSuffix(getFile(info), c.g.config.paths)
visible = ownerModule == "" or currentModule == "" or ownerModule == currentModule
if not visible:
# treat as undeclared
result = ObjField(level: -1)

proc findModuleSymbol(n: Cursor): SymId =
result = SymId(0)
if n.kind == Symbol:
Expand Down Expand Up @@ -1432,9 +1474,13 @@ proc tryBuiltinDot(c: var SemContext; it: var Item; lhs: Item; fieldName: StrId;
if root.typeKind == InvokeT:
inc root
if root.kind == Symbol:
let objType = objtypeImpl(root.symId)
let decl = getTypeSection(root.symId)
var objType = decl.body
# emulate objtypeImpl
if objType.typeKind in {RefT, PtrT}:
inc objType
if objType.typeKind == ObjectT:
let field = findObjField(objType, fieldName)
let field = findObjFieldConsiderVis(c, decl, fieldName, info)
if field.level >= 0:
c.dest.add symToken(field.sym, info)
c.dest.add intToken(pool.integers.getOrIncl(field.level), info)
Expand Down Expand Up @@ -1767,7 +1813,10 @@ proc semObjectType(c: var SemContext; n: var Cursor) =
takeToken c, n
else:
# object fields:
let oldScopeKind = c.currentScope.kind
withNewScope c:
# copy toplevel scope status for exported fields
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait ... what? Why?

c.currentScope.kind = oldScopeKind
while n.substructureKind == FldS:
semLocal(c, n, FldY)
wantParRi c, n
Expand Down Expand Up @@ -3273,8 +3322,11 @@ proc semTypeSection(c: var SemContext; n: var Cursor) =
takeToken c, n
isGeneric = false
else:
let oldScopeKind = c.currentScope.kind
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

openScope c
semGenericParams c, n
# copy toplevel scope status for exported fields
c.currentScope.kind = oldScopeKind
isGeneric = true

semTypePragmas c, n, beforeExportMarker
Expand Down Expand Up @@ -3606,13 +3658,18 @@ proc semObjConstr(c: var SemContext, it: var Item) =
inc it.n
it.typ = semLocalType(c, it.n)
c.dest.shrink exprStart
var decl = default(TypeDecl)
var objType = it.typ
if objType.typeKind in {RefT, PtrT}:
inc objType
if objType.typeKind == InvokeT:
inc objType
if objType.kind == Symbol:
objType = objtypeImpl(objType.symId)
decl = getTypeSection(objType.symId)
objType = decl.body
# emulate objtypeImpl
if objType.typeKind in {RefT, PtrT}:
inc objType
if objType.typeKind != ObjectT:
c.buildErr info, "expected object type for object constructor"
return
Expand Down Expand Up @@ -3641,9 +3698,9 @@ proc semObjConstr(c: var SemContext, it: var Item) =
# level is not known but not used either, set it to 0:
field = ObjField(sym: sym, typ: asLocal(res.decl).typ, level: 0)
else:
field = findObjField(objType, fieldName)
field = findObjFieldConsiderVis(c, decl, fieldName, info)
else:
field = findObjField(objType, fieldName)
field = findObjFieldConsiderVis(c, decl, fieldName, info)
if field.level >= 0:
if field.sym in setFieldPositions:
c.buildErr fieldInfo, "field already set: " & pool.strings[fieldName]
Expand Down
2 changes: 2 additions & 0 deletions src/nimony/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ type
sym*: SymId
level*: int # inheritance level
typ*: TypeCursor
exported*: bool
rootOwner*: SymId # generic root of owner type

SemPhase* = enum
SemcheckTopLevelSyms,
Expand Down
13 changes: 13 additions & 0 deletions tests/nimony/modules/deps/mfieldvis.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
type Foo* = object
public*: int
private: int

type Generic*[T] = object
public*: T
private: T

proc getPrivate*(x: Foo): int = x.private
proc getPrivate*[T](x: Generic[T]): T = x.private

template getPrivateTempl*(x: Foo): int = x.private
template getPrivateTempl*[T](x: Generic[T]): T = T(x.private)
4 changes: 4 additions & 0 deletions tests/nimony/modules/tfieldviserr.msgs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
tests/nimony/modules/tfieldviserr.nim(3, 15) Error: undeclared field: private
tests/nimony/modules/tfieldviserr.nim(4, 12) Error: undeclared identifier
tests/nimony/modules/tfieldviserr.nim(6, 28) Error: undeclared field: private
tests/nimony/modules/tfieldviserr.nim(7, 16) Error: undeclared identifier
21 changes: 21 additions & 0 deletions tests/nimony/modules/tfieldviserr.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import deps/mfieldvis

var foo = Foo(private: 123)
discard foo.private

var generic = Generic[int](private: 123)
discard generic.private

when false: # compiles and should compile but cannot test yet
var foo = Foo(public: 123)
discard getPrivate(foo)
discard getPrivateTempl(foo)

var generic = Generic[int](public: 123)
discard getPrivate(foo)
discard getPrivateTempl(foo)

template resem() =
foo = Foo(public: 123)
generic = Generic[int](public: 123)
resem()
Loading