Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve "key not found" error messages for string/symbol keys #3409

Merged
merged 8 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions M2/Macaulay2/d/binding.d
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,9 @@ export NewOfFromE := Expr(NewOfFromS);
export InverseS := makeProtectedSymbolClosure("InverseMethod");
export InverseE := Expr(InverseS);

export RobustPrintS := makeProtectedSymbolClosure("RobustPrintMethod");
export RobustPrintE := Expr(RobustPrintS);

export StopIterationS := makeProtectedSymbolClosure("StopIteration");
export StopIterationE := Expr(StopIterationS);

Expand Down
2 changes: 2 additions & 0 deletions M2/Macaulay2/d/evaluate.d
Original file line number Diff line number Diff line change
Expand Up @@ -2092,6 +2092,8 @@ AssignQuotedElemFun = assignquotedelemfun; -- what is this for? never used

export notFun(a:Expr):Expr := if a == True then False else if a == False then True else unarymethod(a,notS);

-- evaluate.d depends on hashtables.dd, so we use a pointer
-- to evaluate methods in hashtables.dd before it is defined.
applyEEEpointer = applyEEE;

nullify(c:Code):Expr := (
Expand Down
76 changes: 32 additions & 44 deletions M2/Macaulay2/d/hashtables.dd
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use classes;

header "#include <cassert>";

-- applyEEE is not defined until evaluate.d,
-- so we use a pointer and populate it later.
dummyapplyEEE(g:Expr,e0:Expr,e1:Expr):Expr := g;
export applyEEEpointer := dummyapplyEEE;

Expand Down Expand Up @@ -311,6 +313,17 @@ export copy(o:HashTable,newClass:HashTable,newParent:HashTable,newMutable:bool):
export copy(o:HashTable,newClass:HashTable,newMutable:bool):HashTable := copy(o,newClass,o.parent,newMutable);
-----------------------------------------------------------------------------

lookup(object:HashTable, key:Expr):Expr; -- forward declaration

KeyNotFound(object:string, key:Expr):Expr := (
-- TODO: implement a similar trick to call synonym(object)
msg := "key not found in " + object;
see := lookup(Class(key), RobustPrintE);
if see != notfoundE then
when applyEEEpointer(see, toExpr(msg), key)
is str:stringCell do msg = str.v else nothing;
buildErrorPacket(msg));

export lookup1(object:HashTable,key:Expr,keyhash:hash_t):Expr := (
-- warning: can return notfoundE, which should not be given to the user
res := notfoundE;
Expand All @@ -327,53 +340,28 @@ export lookup1(object:HashTable,key:Expr,keyhash:hash_t):Expr := (
if lockit then unlock(object.mutex);
res);
export lookup1(object:HashTable,key:Expr):Expr := lookup1(object,key,hash(key));

-- lookup a key in the hash table and either return the value or an error packet if not found
export lookup1force(object:HashTable,key:Expr,keyhash:hash_t):Expr := (
lockit := object.Mutable && !object.beingInitialized;
if lockit then lockRead(object.mutex);
keymod := int(keyhash & (length(object.table)-1));
bucket := object.table.keymod;
while bucket != bucket.next do (
if bucket.key == key || bucket.hash == keyhash && equal(bucket.key,key)==True then (
res := bucket.value;
if lockit then unlock(object.mutex);
return res);
bucket = bucket.next;
);
if lockit then unlock(object.mutex);
buildErrorPacket("key not found in hash table"));
result := lookup1(object, key, keyhash);
if result != notfoundE then result
else KeyNotFound("hash table", key));
export lookup1force(object:HashTable,key:Expr):Expr := lookup1force(object,key,hash(key));

-- query a key in the hash table and report whether it is found or not
export lookup1Q(object:HashTable,key:Expr,keyhash:hash_t):bool := (
lockit := object.Mutable && !object.beingInitialized;
if lockit then lockRead(object.mutex);
keymod := int(keyhash & (length(object.table)-1));
bucket := object.table.keymod;
while bucket != bucket.next do (
if bucket.key == key || bucket.hash == keyhash && equal(bucket.key,key)==True then (
if lockit then unlock(object.mutex);
return true);
bucket = bucket.next;
);
if lockit then unlock(object.mutex);
false);
result := lookup1(object, key, keyhash);
if result != notfoundE then true else false);
export lookup1Q(object:HashTable,key:Expr):bool := lookup1Q(object,key,hash(key));

-- lookup a key in the hash table or its parent until it is found, otherwise return null
export lookup(object:HashTable,key:Expr,keyhash:hash_t):Expr := (
while true do (
lockit := object.Mutable && !object.beingInitialized;
if lockit then lockRead(object.mutex);
keymod := int(keyhash & (length(object.table)-1));
bucket := object.table.keymod;
while bucket != bucket.next do (
if bucket.key == key || bucket.hash == keyhash && equal(bucket.key,key)==True then (
res := bucket.value;
if lockit then unlock(object.mutex);
return res);
bucket = bucket.next;
);
if lockit then unlock(object.mutex);
if object == thingClass then break;
object = object.parent;
);
nullE);
while true do (
result := lookup1(object, key, keyhash);
if result != notfoundE then return result;
if object == thingClass then break;
object = object.parent);
nullE);
export lookup(object:HashTable,key:Expr):Expr := lookup(object,key,hash(key));
export lookup(object:HashTable,key:SymbolClosure):Expr := (
lookup(object,Expr(key),key.symbol.hash)
Expand Down Expand Up @@ -813,7 +801,7 @@ export subvalue(left:Expr,right:Expr):Expr := (
if !f.isopen then return buildErrorPacket("database closed");
when dbmfetch(f.handle,key.v)
is a:string do Expr(stringCell(a))
else buildErrorPacket("encountered missing value"))
else KeyNotFound("database", right))
else buildErrorPacket("expected a string as key to database"))
-- # typical value: symbol #, List, ZZ, Thing
-- # typical value: symbol #, BasicList, ZZ, Thing
Expand All @@ -828,7 +816,7 @@ export subvalue(left:Expr,right:Expr):Expr := (
d := dc.dictionary;
when lookup(s.v,d.symboltable)
is x:Symbol do Expr(SymbolClosure(if x.thread then threadFrame else dc.frame,x))
else buildErrorPacket("key not found in dictionary")
else KeyNotFound("dictionary", right)
)
else buildErrorPacket("expected key for dictionary to be a string")
)
Expand Down
7 changes: 7 additions & 0 deletions M2/Macaulay2/m2/robust.m2
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ silentRobustStringWithClass = (wid,sec,y) -> (
part2 := concatenate(" (of class ", silentRobustString(wid//2, sec,class y), ")");
part1 := silentRobustString(wid - width part2,sec, y);
concatenate(part1, part2));

Thing.RobustPrintMethod = (msg, obj) -> (
output := silentRobustNetWithClass(60, 5, 3, obj);
if width output > 28 or height output != 1 or depth output != 0
then toString stack { msg | ":", "\t" | output }
else concatenate { msg, ": ", toString output })

hush := false
commentGuardString := "--"
commentGuardNet := raise(horizontalJoin commentGuardString,-1)
Expand Down