summary refs log tree commit diff stats
path: root/compiler/importer.nim
blob: 86511f228ae527b7f05aae1f615f90f352313aa1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#
#
#           The Nimrod Compiler
#        (c) Copyright 2012 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# This module implements the symbol importing mechanism.

import 
  intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
  semdata, passes

proc evalImport*(c: PContext, n: PNode): PNode
proc evalFrom*(c: PContext, n: PNode): PNode
proc importAllSymbols*(c: PContext, fromMod: PSym)

proc getModuleName*(n: PNode): string =
  # This returns a short relative module name without the nim extension
  # e.g. like "system", "importer" or "somepath/module"
  # The proc won't perform any checks that the path is actually valid
  case n.kind
  of nkStrLit, nkRStrLit, nkTripleStrLit:
    result = UnixToNativePath(n.strVal)
  of nkIdent:
    result = n.ident.s
  of nkSym:
    result = n.sym.name.s
  else:
    internalError(n.info, "getModuleName")
    result = ""

proc checkModuleName*(n: PNode): string =
  # This returns the full canonical path for a given module import
  var modulename = n.getModuleName
  result = findModule(modulename)
  if result.len == 0:
    Fatal(n.info, errCannotOpenFile, modulename)

proc rawImportSymbol(c: PContext, s: PSym) = 
  # This does not handle stubs, because otherwise loading on demand would be
  # pointless in practice. So importing stubs is fine here!
  var copy = s # do not copy symbols when importing!
  # check if we have already a symbol of the same name:
  var check = StrTableGet(c.tab.stack[importTablePos], s.name)
  if (check != nil) and (check.id != copy.id): 
    if not (s.kind in OverloadableSyms): 
      # s and check need to be qualified:
      Incl(c.AmbiguousSymbols, copy.id)
      Incl(c.AmbiguousSymbols, check.id)
  StrTableAdd(c.tab.stack[importTablePos], copy)
  if s.kind == skType: 
    var etyp = s.typ
    if etyp.kind in {tyBool, tyEnum}: 
      for j in countup(0, sonsLen(etyp.n) - 1): 
        var e = etyp.n.sons[j].sym
        if (e.Kind != skEnumField): 
          InternalError(s.info, "rawImportSymbol") 
          # BUGFIX: because of aliases for enums the symbol may already
          # have been put into the symbol table
          # BUGFIX: but only iff they are the same symbols!
        var it: TIdentIter 
        check = InitIdentIter(it, c.tab.stack[importTablePos], e.name)
        while check != nil: 
          if check.id == e.id: 
            e = nil
            break 
          check = NextIdentIter(it, c.tab.stack[importTablePos])
        if e != nil: 
          rawImportSymbol(c, e)
  elif s.kind == skConverter: 
    addConverter(c, s)        # rodgen assures that converters are no stubs
  
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = 
  let ident = lookups.considerAcc(n)
  let s = StrTableGet(fromMod.tab, ident)
  if s == nil: GlobalError(n.info, errUndeclaredIdentifier, ident.s)
  if s.kind == skStub: loadStub(s)
  if s.Kind notin ExportableSymKinds:
    InternalError(n.info, "importSymbol: 2")
  # for an enumeration we have to add all identifiers
  case s.Kind
  of skProc, skMethod, skIterator, skMacro, skTemplate, skConverter:
    # for a overloadable syms add all overloaded routines
    var it: TIdentIter
    var e = InitIdentIter(it, fromMod.tab, s.name)
    while e != nil:
      if e.name.id != s.Name.id: InternalError(n.info, "importSymbol: 3")
      rawImportSymbol(c, e)
      e = NextIdentIter(it, fromMod.tab)
  else: rawImportSymbol(c, s)
  
proc importAllSymbols(c: PContext, fromMod: PSym) = 
  var i: TTabIter
  var s = InitTabIter(i, fromMod.tab)
  while s != nil: 
    if s.kind != skModule: 
      if s.kind != skEnumField: 
        if not (s.Kind in ExportableSymKinds): 
          InternalError(s.info, "importAllSymbols: " & $s.kind)
        rawImportSymbol(c, s) # this is correct!
    s = NextIter(i, fromMod.tab)

proc evalImport(c: PContext, n: PNode): PNode = 
  result = n
  for i in countup(0, sonsLen(n) - 1): 
    var f = checkModuleName(n.sons[i])
    var m = gImportModule(f)
    if sfDeprecated in m.flags: 
      Message(n.sons[i].info, warnDeprecated, m.name.s) 
    # ``addDecl`` needs to be done before ``importAllSymbols``!
    addDecl(c, m)             # add symbol to symbol table of module
    importAllSymbols(c, m)

proc evalFrom(c: PContext, n: PNode): PNode = 
  result = n
  checkMinSonsLen(n, 2)
  var f = checkModuleName(n.sons[0])
  var m = gImportModule(f)
  n.sons[0] = newSymNode(m)
  addDecl(c, m)               # add symbol to symbol table of module
  for i in countup(1, sonsLen(n) - 1): importSymbol(c, n.sons[i], m)