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

Unhelpful error message: "<unknown>:0:0: error: invalid type (see macro at x:y)" #36

Closed
BitPuffin opened this issue Apr 14, 2015 · 7 comments

Comments

@BitPuffin
Copy link

This code:

(import macros)
(import cstdio)
(import introspection)

(using-namespace std.macros
  (def def-type-macro (macro extern (new linkage old)
    (qq using-namespace std.macros
      (def (uq new) (macro (uq linkage) (void)
        (qq uq (uq old))))))))

(def-type-macro cstring extern (p (const char)))

(def main (fn extern-c void (void)
  (def a-string (var auto (cstring) "Yo dude"))
  (printf "string: %s\n" a-string)))

Is probably incorrect somehow. But it's hard to tell why when the compiler reports:

% dalec def-type-alias.dt
<unknown>:0:0: error: invalid type (see macro at 9:9)
def-type-alias.dt:15:23: error: variable not in scope: 'a-string'

I know that (cstring) is probably the part that is giving an invalid type, and that it's on that line. However it would be helpful if the compiler told me what the invalid type actually turned out to be, instead of telling me to look at the macro. Because I can't figure it out, hehe.

@tomhrr
Copy link
Owner

tomhrr commented Apr 14, 2015

I'm not sure of the best way to fix this, yet. The --print-expansions option makes it a bit easier to see the problem:

test.dt:14:27: expansion: (cstring) -> (uq (p (const char))) 

and should help more generally. However, the obvious thing to do as a result (remove one of the uqs) yields the following:

test.dt:14:27: expansion: (cstring) -> ((p (const char)))

since qq always returns a list, and the new parameter is itself a list. This expansion fails, because a type represented by a list must have an atom in the first position. One way to get around this is to insert a superfluous do, since type parsing skips over it. The last qq line thus becomes:

(qq do (uq old))

which in turn will compile successfully. An alternative approach is to extract the list-node from old at the beginning of the macro, and use the uql form to expand it:

(using-namespace std.macros
  (def def-type-macro (macro extern (new linkage old)
    (setv old (@:@ old list-node))
    (qq using-namespace std.macros
    (def (uq new) (macro (uq linkage) (void)
      (qq (uql old))))))))

These aren't fixes for the core problem, though. One option is to make qq remove any outer pairs of parentheses, but that could have unintended consequences. Another is to tighten expansion validation. Any suggestions/input would be appreciated.

@BitPuffin
Copy link
Author

I'll try these workarounds out when I get home to my macbook.

As for suggestions I think I would probably ellide excess parenthesis always so that (((((a))))) = a. That's what I intend to do with my programming language. So the idea was that every thing in the language is a certain thing (called a container in my language) and a single element container could simply be represented as typing just the value you want in the container.

So 1 would be the same as writing (1) or ((((((((1)))))))). I think that would make sense for this language as well probably?

In this case ((p (const char))) would be the same as writing (p (const char)).

I'm not sure what the best thing would be for Dale though, as I don't have a very intimate knowledge of it yet.

This would also allow you to optionally write in a more consistent way when declaring types. Like you could say (int8) instead of int8.

However I just realized that this doesn't work well with lisp syntax since (a) is a form invocation but a is not. In my language () a would be an invocation of a and a or (a) would just be the value. So hmm, I'm not sure what to do. Maybe tighten expansion validation in the compiler. Because it seems like making qq have stranger behavior would be the wrong decision I think since it's not the library's job to work around strange things in the language if the language can solve it. IMHO.

EDIT:

Actually I think the best of all solution is to just have a quote macro. Because in other Lisps you use quasi quote any time you want to do things to a list. But you can also just quote values.

'(hello there dale)
`(hello there ,dale)
`a ; doesn't really make sense
'a ; makes perfect sense

So the body of the internal macro would be:

(quote (uq old))

I think?

Either way if we can get that working then def-type-macro would work with both lists and just plain types like

(def-type-macro string (p (const char)))
(def-type-macro id size)

You could also just redesign the behaviour of qq so that any time you want a list you have to manually put a list after the qq. So:

(qq foo "hello")

Becomes

(qq (foo "hello"))

That was the default behaviour I expected from qq anyway so I was confused when it required me to give it an atom.

@tomhrr
Copy link
Owner

tomhrr commented Apr 15, 2015

I think changing it as per your last suggestion (i.e. no implicit parentheses) is probably the best way to go, so I'll try that out and see how it goes.

@BitPuffin
Copy link
Author

I agree, I suppose there will be a lot of ripples to refactor when doing that, but it should be fairly easy to automate. Looking forward to testing it out :)

@tomhrr
Copy link
Owner

tomhrr commented Apr 16, 2015

I ended up adding quote (as q) instead. Changing qq such that it didn't add implicit parentheses was likely to cause confusion with forms like (qq foo hello). If (qq foo) yielded foo, and (qq (foo hello)) yielded (foo hello), then by extension, (qq foo hello) would splice foo and hello into the parent form, which is rarely likely to be what was intended by the author. Thanks for all the suggestions.

@tomhrr tomhrr closed this as completed Apr 16, 2015
@tomhrr tomhrr reopened this Apr 16, 2015
@tomhrr
Copy link
Owner

tomhrr commented Apr 16, 2015

That still leaves the unhelpful error message, though, so this will stay open for the time being.

@tomhrr
Copy link
Owner

tomhrr commented Apr 18, 2015

The error messages produced on compiling the original program are now:

test.dt:9:13: error: invalid type (see macro at 14:27)
test.dt:15:25: error: variable not in scope: 'a-string'

Filenames are preserved by the q form, and qq sets position information on its return node, so error messages should be a bit more reasonable now. This will be closed for now, but any further feedback as to error messages/positions/etc. is appreciated.

@tomhrr tomhrr closed this as completed Apr 18, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants