pfultz2/ZLang — pull request #1 by Y-Less (2013-12-06 12:36:05+00:00)
Title: Better error detection and reporting.

The previous code seemed well tested in the case of macros existing, but not in the case of them not existing. The "ZLANG_NIL" macro seemed to be aimed at detecting this, but the order of concatenation meant that it was never actually generated. This code, after attempting to find a valid namespace, adds code to detect if the resulting namespace is actually valid. If it is "_NIL" or "_OOB" (extended from just "NIL" for the case where "NIL" is actually a valid namespace) then "TRY_QUALIFY" returns an error message instead of the fully qualified macro. GCC reports this as:

error: ZLANG__NAMESPACE__Yeah undeclared

Which will hopefully narrow down the problem once in-scope namespaces are examined.

Additionally, "Z_ZLANG_FIND_9" was replaced with "Z_ZLANG_DOMAIN" (chosen to maintain line lengths), again a detection for problems - in this case too many domains. This will give the same compiler error, but inspection of the pre-processor results won't:

`
#include "zlang.h"

#define NS1_PRINT(n) print(#n)
#define ZLANG_NS1_Print (NS1_PRINT)

main()
{
#define ZLANG_USE (NS1, NS2, NS3, NS4, NS5, NS6, NS7, NS8, NS9, NS0)

$(Print hi);
$(Print hi there);
$(Print hi there how are you?);

$(Yeah you);

#undef ZLANG_USE

#define ZLANG_USE (NS1, NS2)

$(Print hi);
$(Print hi there);
$(Print hi there how are you?);

$(Yeah you);

#undef ZLANG_USE

$(Print hi);
$(Print hi there);
$(Print hi there how are you?);

$(Yeah you);
}

`

Gives:

`
# 1 "z1.c"
# 1 ""
# 1 ""
# 1 "z1.c"
# 1 "zlang.h" 1
# 2 "z1.c" 2

main()
{

print("hi");
print("hi there");
print("hi there how are you?");

Z_ZLANG_ERROR_TOO_MANY(ZLANG__NAMESPACE__Yeah you);

print("hi");
print("hi there");
print("hi there how are you?");

Z_ZLANG_ERROR_NOT_FOUND(ZLANG__NAMESPACE__Yeah you);

Z_ZLANG_ERROR_NOT_FOUND(ZLANG__NAMESPACE__Print hi);
Z_ZLANG_ERROR_NOT_FOUND(ZLANG__NAMESPACE__Print hi there);
Z_ZLANG_ERROR_NOT_FOUND(ZLANG__NAMESPACE__Print hi there how are you?);

Z_ZLANG_ERROR_NOT_FOUND(ZLANG__NAMESPACE__Yeah you);
}
`

Errors:

`
z1.c: In function "main":
z1.c:14:2: error: "ZLANG__NAMESPACE__Yeah" undeclared (first use in this function)
z1.c:14:2: note: each undeclared identifier is reported only once for each function it appears in
z1.c:14:2: error: expected ")" before "you"
z1.c:24:2: error: expected ")" before "you"
z1.c:28:2: error: "ZLANG__NAMESPACE__Print" undeclared (first use in this function)
z1.c:28:2: error: expected ")" before "hi"
z1.c:29:2: error: expected ")" before "hi"
z1.c:30:2: error: expected ")" before "hi"
z1.c:32:2: error: expected ")" before "you"
`

Previously compiling with "-E" would give multiple errors, as would regular compiling; however, the latter errors were far less useful than these new errors (though I admit even they could be improved);

`
z1.c: In function "main":
z1.c:14:1: error: pasting ")" and "_" does not give a valid preprocessing token
z1.c:14:1: error: macro "Z_ZLANG_PRIMITIVE_INVOKE" requires 2 arguments, but only 1 given
z1.c:14:2: error: "Z_ZLANG_PRIMITIVE_INVOKE" undeclared (first use in this function)
z1.c:14:2: note: each undeclared identifier is reported only once for each function it appears in
z1.c:24:1: error: macro "Z_ZLANG_PRIMITIVE_INVOKE" requires 2 arguments, but only 1 given
z1.c:28:1: error: macro "Z_ZLANG_PRIMITIVE_INVOKE" requires 2 arguments, but only 1 given
z1.c:29:1: error: macro "Z_ZLANG_PRIMITIVE_INVOKE" requires 2 arguments, but only 1 given
z1.c:30:1: error: macro "Z_ZLANG_PRIMITIVE_INVOKE" requires 2 arguments, but only 1 given
z1.c:32:1: error: macro "Z_ZLANG_PRIMITIVE_INVOKE" requires 2 arguments, but only 1 given
`

There is one minor downside to this code. The detection of "ZLANG__NIL" and "ZLANG__OOB" uses "Z_ZLANG_IS_PAREN". The result is that if you were to do:

`
#define NS1_PRINT(n) print(#n)
#define ZLANG_NS1_Print (NS1_PRINT)
#define ZLANG_NS1 (SOMETHING)
`

That will actually break the whole of the "NS1" namespace. So, in short, don't do that!