mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-06 13:07:48 +00:00
308 lines
9.3 KiB
ObjectPascal
308 lines
9.3 KiB
ObjectPascal
//
|
|
//
|
|
// 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.
|