summary refs log tree commit diff stats
path: root/compiler/importer.nim
blob: f9637791549a094f2d35f141160dc1af3266c491 (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
126
127
128
129
130
#
#
#           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:
    LocalError(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 s.kind notin 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} and sfPure notin s.flags: 
      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)
  else:
    # rodgen assures that converters and patterns are no stubs
    if s.kind == skConverter: addConverter(c, s)
    if hasPattern(s): addPattern(c, s)
  
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = 
  let ident = lookups.considerAcc(n)
  let s = StrTableGet(fromMod.tab, ident)
  if s == nil:
    LocalError(n.info, errUndeclaredIdentifier, ident.s)
  else:
    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])
    if f.len > 0:
      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])
  if f.len > 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)