// // // 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.