//
//
// The Nimrod Compiler
// (c) Copyright 2008 Andreas Rumpf
//
// See the file "copying.txt", included in this
// distribution, for details about the copyright.
//
unit treetab;
// Implements a table from trees to trees. Does structural equavilent checking.
interface
{$include 'config.inc'}
uses
nsystem, nhashes, ast, astalgo, types;
function NodeTableGet(const t: TNodeTable; key: PNode): int;
procedure NodeTablePut(var t: TNodeTable; key: PNode; val: int);
function NodeTableTestOrSet(var t: TNodeTable; key: PNode; val: int): int;
implementation
function hashTree(n: PNode): THash;
var
i: int;
begin
result := 0;
if n = nil then exit;
result := ord(n.kind);
case n.kind of
nkEmpty, nkNilLit, nkType: begin end;
nkIdent: result := concHash(result, n.ident.h);
nkSym: result := concHash(result, n.sym.name.h);
nkCharLit..nkInt64Lit: begin
if (n.intVal >= low(int)) and (n.intVal <= high(int)) then
result := concHash(result, int(n.intVal));
end;
nkFloatLit..nkFloat64Lit: begin
if (n.floatVal >= -1000000.0) and (n.floatVal <= 1000000.0) then
result := concHash(result, toInt(n.floatVal));
end;
nkStrLit..nkTripleStrLit:
result := concHash(result, GetHashStr(n.strVal));
else begin
for i := 0 to sonsLen(n)-1 do
result := concHash(result, hashTree(n.sons[i]));
end
end
end;
function TreesEquivalent(a, b: PNode): Boolean;
var
i: int;
begin
result := false;
if a = b then begin
result := true
end
else if (a <> nil) and (b <> nil) and (a.kind = b.kind) then begin
case a.kind of
nkEmpty, nkNilLit, nkType: result := true;
nkSym:
result := a.sym.id = b.sym.id;
nkIdent:
result := a.ident.id = b.ident.id;
nkCharLit..nkInt64Lit:
result := a.intVal = b.intVal;
nkFloatLit..nkFloat64Lit:
result := a.floatVal = b.floatVal;
nkStrLit..nkTripleStrLit:
result := a.strVal = b.strVal;
else if sonsLen(a) = sonsLen(b) then begin
for i := 0 to sonsLen(a)-1 do
if not TreesEquivalent(a.sons[i], b.sons[i]) then exit;
result := true
end
end;
if result then result := sameTypeOrNil(a.typ, b.typ);
end
end;
function NodeTableRawGet(const t: TNodeTable; k: THash; key: PNode): int;
var
h: THash;
begin
h := k and high(t.data);
while t.data[h].key <> nil do begin
if (t.data[h].h = k) and TreesEquivalent(t.data[h].key, key) then begin
result := h; exit
end;
h := nextTry(h, high(t.data))
end;
result := -1
end;
function NodeTableGet(const t: TNodeTable; key: PNode): int;
var
index: int;
begin
index := NodeTableRawGet(t, hashTree(key), key);
if index >= 0 then result := t.data[index].val
else result := low(int)
end;
procedure NodeTableRawInsert(var data: TNodePairSeq; k: THash;
key: PNode; val: int);
var
h: THash;
begin
h := k and high(data);
while data[h].key <> nil do h := nextTry(h, high(data));
assert(data[h].key = nil);
data[h].h := k;
data[h].key := key;
data[h].val := val;
end;
procedure NodeTablePut(var t: TNodeTable; key: PNode; val: int);
var
index, i: int;
n: TNodePairSeq;
k: THash;
begin
k := hashTree(key);
index := NodeTableRawGet(t, k, key);
if index >= 0 then begin
assert(t.data[index].key <> nil);
t.data[index].val := val
end
else begin
if mustRehash(length(t.data), t.counter) then begin
{@ignore}
setLength(n, length(t.data) * growthFactor);
fillChar(n[0], length(n)*sizeof(n[0]), 0);
{@emit
newSeq(n, length(t.data) * growthFactor); }
for i := 0 to high(t.data) do
if t.data[i].key <> nil then
NodeTableRawInsert(n, t.data[i].h, t.data[i].key, t.data[i].val);
{@ignore}
t.data := n;
{@emit
swap(t.data, n);
}
end;
NodeTableRawInsert(t.data, k, key, val);
inc(t.counter)
end;
end;
function NodeTableTestOrSet(var t: TNodeTable; key: PNode; val: int): int;
var
index, i: int;
n: TNodePairSeq;
k: THash;
begin
k := hashTree(key);
index := NodeTableRawGet(t, k, key);
if index >= 0 then begin
assert(t.data[index].key <> nil);
result := t.data[index].val
end
else begin
if mustRehash(length(t.data), t.counter) then begin
{@ignore}
setLength(n, length(t.data) * growthFactor);
fillChar(n[0], length(n)*sizeof(n[0]), 0);
{@emit
newSeq(n, length(t.data) * growthFactor); }
for i := 0 to high(t.data) do
if t.data[i].key <> nil then
NodeTableRawInsert(n, t.data[i].h, t.data[i].key, t.data[i].val);
{@ignore}
t.data := n;
{@emit
swap(t.data, n);
}
end;
NodeTableRawInsert(t.data, k, key, val);
result := val;
inc(t.counter)
end;
end;
end.