Closed LarsAsplund closed 9 years ago
Initial commit (e49773cca18744007c139f1c1d53dec5b485b9eb) done. Help me find relevant use cases which the parser can't handle.
It does not handle side-effects such as: check_relation(list.pop() = 1)
Yes, you're right. I will add that to the examples. The straight forward solution in this case is
list_head = list.pop(); check_relation(list_head = 1);
A bit against one of the objectives to allow the users to write their relation in plain text but still much better than no support at all. Another solution for the integer and equality case is to use check_equal. I think that there are solutions to handle impure functions without work-arounds but I will have to think about that some more. Not sure they are worth the effort.
Instead of transforming
check_relation(list.pop = 1);
to
check_relation(list.pop = 1, auto_msg => string with to_string(list.pop) and to_string(1));
one could do something like
check_relation("list.pop = 1", relation => "=", left => representation(list.pop), right => representation(1));
The first string "list.pop = 1" is just there to maintain code readability. representation is a function that is needed for each type to compare. Functions for standard types can be provided with VUnit while a user would have to provide them for custom types (but no to_string or relational operator functions have to be defined)
Representation returns a record containing both the string representation of the input as well as an order number representing the input value's order in the set of possible values provided by the data type. This order is then used by the check function to do the actual relation check. The order number is of a type that already has all relation operators defined. What type(s) to use is up for discussion but let's assume integer for the sake of simplicity. A custom type like a record cash_t containing a dollars and a cents field (naturals) could have its order calculated by doing dollars*100 + cents.
In this way we can support any type and the relation is only evaluated once to handle impure functions.
But there are issues to be solved:
Given that the use of impure functions isn't very common (a search over 2162 OpenCores VHDL files found 436 function definition out of which 6 were impure. None of these impure functions would return with a different value when called a second time.), users will hopefully use them correctly most of the time, and if they don't the check will still spot errors correctly but give a misleading message, I don't think this other solution is worth the effort. Also, the type safety issue would affect all checks and probably be a more common source of mistakes.
I agree it is not worth the effort.
Investigate if it is possible to have a check looking something like this
check( );
that would, through preprocessor support, expand into something like this
check( , " check failed! Left is " & to_string() & ". Right is " & to_string() & ".");
As long as the user has defined the relation operator and to_string() for the types returned by the two expressions (or this is already part of the VHDL standard) VUnit could provide intelligent error messaging for a common check use case regardless of the types involved in the relation.