//
//
// The Nimrod Compiler
// (c) Copyright 2009 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
//
unit lookups;
// This module implements lookup helpers.
interface
uses
nsystem, ast, astalgo, idents, semdata, types, msgs, options, rodread,
rnimsyn;
{$include 'config.inc'}
type
TOverloadIterMode = (oimDone, oimNoQualifier, oimSelfModule, oimOtherModule,
oimSymChoice);
TOverloadIter = record
stackPtr: int;
it: TIdentIter;
m: PSym;
mode: TOverloadIterMode;
end;
function getSymRepr(s: PSym): string;
procedure CloseScope(var tab: TSymTab);
procedure AddSym(var t: TStrTable; n: PSym);
procedure addDecl(c: PContext; sym: PSym);
procedure addDeclAt(c: PContext; sym: PSym; at: Natural);
procedure addOverloadableSymAt(c: PContext; fn: PSym; at: Natural);
procedure addInterfaceDecl(c: PContext; sym: PSym);
procedure addInterfaceOverloadableSymAt(c: PContext; sym: PSym; at: int);
function lookUp(c: PContext; n: PNode): PSym;
// Looks up a symbol. Generates an error in case of nil.
function QualifiedLookUp(c: PContext; n: PNode; ambiguousCheck: bool): PSym;
function InitOverloadIter(out o: TOverloadIter; c: PContext; n: PNode): PSym;
function nextOverloadIter(var o: TOverloadIter; c: PContext; n: PNode): PSym;
implementation
function getSymRepr(s: PSym): string;
begin
case s.kind of
skProc, skMethod, skConverter, skIterator: result := getProcHeader(s);
else result := s.name.s
end
end;
procedure CloseScope(var tab: TSymTab);
var
it: TTabIter;
s: PSym;
begin
// check if all symbols have been used and defined:
if (tab.tos > length(tab.stack)) then InternalError('CloseScope');
s := InitTabIter(it, tab.stack[tab.tos-1]);
while s <> nil do begin
if sfForward in s.flags then
liMessage(s.info, errImplOfXexpected, getSymRepr(s))
else if ([sfUsed, sfInInterface] * s.flags = []) and
(optHints in s.options) then // BUGFIX: check options in s!
if not (s.kind in [skForVar, skParam, skMethod, skUnknown]) then
liMessage(s.info, hintXDeclaredButNotUsed, getSymRepr(s));
s := NextIter(it, tab.stack[tab.tos-1]);
end;
astalgo.rawCloseScope(tab);
end;
procedure AddSym(var t: TStrTable; n: PSym);
begin
if StrTableIncl(t, n) then liMessage(n.info, errAttemptToRedefine, n.name.s);
end;
procedure addDecl(c: PContext; sym: PSym);
begin
if SymTabAddUnique(c.tab, sym) = Failure then
liMessage(sym.info, errAttemptToRedefine, sym.Name.s);
end;
procedure addDeclAt(c: PContext; sym: PSym; at: Natural);
begin
if SymTabAddUniqueAt(c.tab, sym, at) = Failure then
liMessage(sym.info, errAttemptToRedefine, sym.Name.s);
end;
procedure addOverloadableSymAt(c: PContext; fn: PSym; at: Natural);
var
check: PSym;
begin
if not (fn.kind in OverloadableSyms) then
InternalError(fn.info, 'addOverloadableSymAt');
check := StrTableGet(c.tab.stack[at], fn.name);
if (check <> nil) and not (check.Kind in OverloadableSyms) then
liMessage(fn.info, errAttemptToRedefine, fn.Name.s);
SymTabAddAt(c.tab, fn, at);
end;
procedure AddInterfaceDeclAux(c: PContext; sym: PSym);
begin
if (sfInInterface in sym.flags) then begin
// add to interface:
if c.module = nil then InternalError(sym.info, 'AddInterfaceDeclAux');
StrTableAdd(c.module.tab, sym);
end;
if getCurrOwner().kind = skModule then
include(sym.flags, sfGlobal)
end;
procedure addInterfaceDecl(c: PContext; sym: PSym);
begin // it adds the symbol to the interface if appropriate
addDecl(c, sym);
AddInterfaceDeclAux(c, sym);
end;
procedure addInterfaceOverloadableSymAt(c: PContext; sym: PSym; at: int);
begin // it adds the symbol to the interface if appropriate
addOverloadableSymAt(c, sym, at);
AddInterfaceDeclAux(c, sym);
end;
function lookUp(c: PContext; n: PNode): PSym;
// Looks up a symbol. Generates an error in case of nil.
begin
case n.kind of
nkAccQuoted: result := lookup(c, n.sons[0]);
nkSym: begin (*
result := SymtabGet(c.Tab, n.sym.name);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s); *)
result := n.sym;
end;
nkIdent: begin
result := SymtabGet(c.Tab, n.ident);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.ident.s);
end
else InternalError(n.info, 'lookUp');
end;
if IntSetContains(c.AmbiguousSymbols, result.id) then
liMessage(n.info, errUseQualifier, result.name.s);
if result.kind = skStub then loadStub(result);
end;
function QualifiedLookUp(c: PContext; n: PNode; ambiguousCheck: bool): PSym;
var
m: PSym;
ident: PIdent;
begin
case n.kind of
nkIdent: begin
result := SymtabGet(c.Tab, n.ident);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.ident.s)
else if ambiguousCheck
and IntSetContains(c.AmbiguousSymbols, result.id) then
liMessage(n.info, errUseQualifier, n.ident.s)
end;
nkSym: begin (*
result := SymtabGet(c.Tab, n.sym.name);
if result = nil then
liMessage(n.info, errUndeclaredIdentifier, n.sym.name.s)
else *)
result := n.sym;
if ambiguousCheck and IntSetContains(c.AmbiguousSymbols, result.id) then
liMessage(n.info, errUseQualifier, n.sym.name.s)
end;
nkDotExpr: begin
result := nil;
m := qualifiedLookUp(c, n.sons[0], false);
if (m <> nil) and (m.kind = skModule) then begin
ident := nil;
if (n.sons[1].kind = nkIdent) then
ident := n.sons[1].ident
else if (n.sons[1].kind = nkAccQuoted)
and (n.sons[1].sons[0].kind = nkIdent) then
ident := n.sons[1].sons[0].ident;
if ident <> nil then begin
if m = c.module then
// a module may access its private members:
result := StrTableGet(c.tab.stack[ModuleTablePos], ident)
else
result := StrTableGet(m.tab, ident);
if result = nil then
liMessage(n.sons[1].info, errUndeclaredIdentifier, ident.s)
end
else
liMessage(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]));
end
end;
nkAccQuoted: result := QualifiedLookup(c, n.sons[0], ambiguousCheck);
else begin
result := nil;
//liMessage(n.info, errIdentifierExpected, '')
end;
end;
if (result <> nil) and (result.kind = skStub) then loadStub(result);
end;
function InitOverloadIter(out o: TOverloadIter; c: PContext; n: PNode): PSym;
var
ident: PIdent;
begin
result := nil;
case n.kind of
nkIdent: begin
o.stackPtr := c.tab.tos;
o.mode := oimNoQualifier;
while (result = nil) do begin
dec(o.stackPtr);
if o.stackPtr < 0 then break;
result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident);
end;
end;
nkSym: begin
result := n.sym;
o.mode := oimDone;
(*
o.stackPtr := c.tab.tos;
o.mode := oimNoQualifier;
while (result = nil) do begin
dec(o.stackPtr);
if o.stackPtr < 0 then break;
result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.sym.name);
end; *)
end;
nkDotExpr: begin
o.mode := oimOtherModule;
o.m := qualifiedLookUp(c, n.sons[0], false);
if (o.m <> nil) and (o.m.kind = skModule) then begin
ident := nil;
if (n.sons[1].kind = nkIdent) then
ident := n.sons[1].ident
else if (n.sons[1].kind = nkAccQuoted)
and (n.sons[1].sons[0].kind = nkIdent) then
ident := n.sons[1].sons[0].ident;
if ident <> nil then begin
if o.m = c.module then begin
// a module may access its private members:
result := InitIdentIter(o.it, c.tab.stack[ModuleTablePos], ident);
o.mode := oimSelfModule;
end
else
result := InitIdentIter(o.it, o.m.tab, ident);
end
else
liMessage(n.sons[1].info, errIdentifierExpected,
renderTree(n.sons[1]));
end
end;
nkAccQuoted: result := InitOverloadIter(o, c, n.sons[0]);
nkSymChoice: begin
o.mode := oimSymChoice;
result := n.sons[0].sym;
o.stackPtr := 1
end;
else begin end
end;
if (result <> nil) and (result.kind = skStub) then loadStub(result);
end;
function nextOverloadIter(var o: TOverloadIter; c: PContext; n: PNode): PSym;
begin
case o.mode of
oimDone: result := nil;
oimNoQualifier: begin
if n.kind = nkAccQuoted then
result := nextOverloadIter(o, c, n.sons[0]) // BUGFIX
else if o.stackPtr >= 0 then begin
result := nextIdentIter(o.it, c.tab.stack[o.stackPtr]);
while (result = nil) do begin
dec(o.stackPtr);
if o.stackPtr < 0 then break;
result := InitIdentIter(o.it, c.tab.stack[o.stackPtr], o.it.name);
// BUGFIX: o.it.name <-> n.ident
end
end
else result := nil;
end;
oimSelfModule: result := nextIdentIter(o.it, c.tab.stack[ModuleTablePos]);
oimOtherModule: result := nextIdentIter(o.it, o.m.tab);
oimSymChoice: begin
if o.stackPtr < sonsLen(n) then begin
result := n.sons[o.stackPtr].sym;
inc(o.stackPtr);
end
else
result := nil
end;
end;
if (result <> nil) and (result.kind = skStub) then loadStub(result);
end;
end.