summary refs log blame commit diff stats
path: root/nim/importer.pas
blob: a1ed5797812c0d4c50dd342a4c8552f361e157ab (plain) (tree)
1
2
3
4
5
6
7
8
9







                                                    
              


                                                         















                                                                         


                                                                             

                                                                     
























                                                               
                                  
                 
     

                                                                             
                                                   

                                                            
                                                        
                                                  
                                          

                                               



                                                 
                  
                                               

                                              













                                                                        

         

                                   
                                                                      






                                                                 
                                                                            


                                                                  
                                      

                                                 

                                                      
                                                                         
                                                            

                                                  

                                                       















                                                       

                                                  
                                                                             

                                                  








                                                  
            
     
              
                                     

                                  

                                                          


                                                                






                                                
            

              
                        

                                




                                                              
    
//
//
//           The Nimrod Compiler
//        (c) Copyright 2008 Andreas Rumpf
//
//    See the file "copying.txt", included in this
//    distribution, for details about the copyright.
//
unit importer;

// This module implements the symbol importing mechanism.

interface

{$include 'config.inc'}

uses
  nsystem, charsets, strutils, nos,
  ast, astalgo, msgs, options, idents, rodread, lookups, semdata, passes;

function evalImport(c: PContext; n: PNode): PNode;
function evalFrom(c: PContext; n: PNode): PNode;
procedure importAllSymbols(c: PContext; fromMod: PSym);

function getModuleFile(n: PNode): string;

implementation

function findModule(const info: TLineInfo; const modulename: string): string;
// returns path to module
begin
  result := options.FindFile(AddFileExt(modulename, nimExt));
  if result = '' then liMessage(info, errCannotOpenFile, modulename);
end;

function getModuleFile(n: PNode): string;
begin
  case n.kind of
    nkStrLit, nkRStrLit, nkTripleStrLit: begin
      result := findModule(n.info, UnixToNativePath(n.strVal));
    end;
    nkIdent: begin
      result := findModule(n.info, n.ident.s);
    end;
    nkSym: begin
      result := findModule(n.info, n.sym.name.s);
    end;
    else begin
      internalError(n.info, 'getModuleFile()');
      result := '';
    end
  end
end;

procedure rawImportSymbol(c: PContext; s: PSym);
var
  check, copy, e: PSym;
  j: int;
  etyp: PType; // enumeration type
  it: TIdentIter;
begin
  // This does not handle stubs, because otherwise loading on demand would be
  // basically pointless. So importing stubs is fine here!
  copy := s; // do not copy symbols when importing!
  // check if we have already a symbol of the same name:
  check := StrTableGet(c.tab.stack[importTablePos], s.name);
  if (check <> nil) and (check.id <> copy.id) then begin
    if not (s.kind in OverloadableSyms) then begin
      // s and check need to be qualified:
      IntSetIncl(c.AmbiguousSymbols, copy.id);
      IntSetIncl(c.AmbiguousSymbols, check.id);
    end
  end;
  StrTableAdd(c.tab.stack[importTablePos], copy);
  if s.kind = skType then begin
    etyp := s.typ;
    if etyp.kind in [tyBool, tyEnum] then begin
      for j := 0 to sonsLen(etyp.n)-1 do begin
        e := etyp.n.sons[j].sym;
        if (e.Kind <> skEnumField) then
          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!
        check := InitIdentIter(it, c.tab.stack[importTablePos], e.name);
        while check <> nil do begin
          if check.id = e.id then begin e := nil; break end;
          check := NextIdentIter(it, c.tab.stack[importTablePos]);
        end;
        if e <> nil then rawImportSymbol(c, e);
        //check := StrTableGet(c.tab.stack[importTablePos], e.name);
        //if (check = nil) or (check.id <> e.id) then
        //  rawImportSymbol(c, e)
      end
    end
  end
  else if s.kind = skConverter then
    addConverter(c, s); // rodgen assures that converters are no stubs
end;

procedure importSymbol(c: PContext; ident: PNode; fromMod: PSym);
var
  s, e: PSym;
  it: TIdentIter;
begin
  if (ident.kind <> nkIdent) then InternalError(ident.info, 'importSymbol');
  s := StrTableGet(fromMod.tab, ident.ident);
  if s = nil then
    liMessage(ident.info, errUndeclaredIdentifier, ident.ident.s);
  if s.kind = skStub then loadStub(s);
  if not (s.Kind in ExportableSymKinds) then
    InternalError(ident.info, 'importSymbol: 2');
  // for an enumeration we have to add all identifiers
  case s.Kind of
    skProc, skMethod, skIterator, skMacro, skTemplate, skConverter: begin
      // for a overloadable syms add all overloaded routines
      e := InitIdentIter(it, fromMod.tab, s.name);
      while e <> nil do begin
        if (e.name.id <> s.Name.id) then
          InternalError(ident.info, 'importSymbol: 3');
        rawImportSymbol(c, e);
        e := NextIdentIter(it, fromMod.tab);
      end
    end;
    else rawImportSymbol(c, s)
  end
end;

procedure importAllSymbols(c: PContext; fromMod: PSym);
var
  i: TTabIter;
  s: PSym;
begin
  s := InitTabIter(i, fromMod.tab);
  while s <> nil do begin
    if s.kind <> skModule then begin
      if s.kind <> skEnumField then begin
        if not (s.Kind in ExportableSymKinds) then
          InternalError(s.info, 'importAllSymbols: ' + symKindToStr[s.kind]);
        rawImportSymbol(c, s); // this is correct!
      end
    end;
    s := NextIter(i, fromMod.tab)
  end
end;

function evalImport(c: PContext; n: PNode): PNode;
var
  m: PSym;
  i: int;
  f: string;
begin
  result := n;
  for i := 0 to sonsLen(n)-1 do begin
    f := getModuleFile(n.sons[i]);
    m := gImportModule(f);
    if sfDeprecated in m.flags then
      liMessage(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);
  end;
end;

function evalFrom(c: PContext; n: PNode): PNode;
var
  m: PSym;
  i: int;
  f: string;
begin
  result := n;
  checkMinSonsLen(n, 2);
  f := getModuleFile(n.sons[0]);
  m := gImportModule(f);
  n.sons[0] := newSymNode(m);
  addDecl(c, m); // add symbol to symbol table of module
  for i := 1 to sonsLen(n)-1 do importSymbol(c, n.sons[i], m);
end;

end.