rhombus-prototype
rhombus-prototype copied to clipboard
Odd scoping/visibility for the `parse_syntax_class` in `space.enforest`
Consider this code:
space.enforest myspace:
space_path myspace
meta_namespace myspace_meta:
parse_syntax_class Parsed
// works fine
fun parse_1(stx):
let '$(parsed :: Parsed)' = stx
parsed
// does not work; Parsed is not visible as a syntax class
fun parse_2('$(parsed :: Parsed)'):
parsed
I would have expected both parse_1 and parse_2 to compile, but it looks like the Parsed syntax class is not bound early enough for parse_2 (the same issue also presents itself trying to define a syntax class that uses Parsed).
I think this is essentially the same problem as
class Posn(x, y):
export zero
fun zero() :: Posn:
Posn(0, 0)
where we currently have to write
class Posn(x, y):
export zero
fun zero() :: Posn:
~name: Posn.zero
Posn(0, 0)
The problem boils down to sometimes wanting definitions within the class or other namespace-like body to be able to bind or influence later clause forms, and sometimes not.
There could be a clause form that groups definitions that cannot influence later clauses, and so the definitions could be delayed as done above manually. Maybe a definitions class, space, etc., clause form?
Or we could maybe delay definition and expression forms by default, as opposed to nestable-declaration forms that might expand to a mixture of clauses and definition forms. But I'm not sure it works to make that kind of distinction.
The problem boils down to sometimes wanting definitions within the class or other namespace-like body to be able to bind or influence later clause forms, and sometimes not.
Oh, so, to make sure I get this right, the issue you're showing with class is that the annotation (and the static information it imparts) could depend on clauses in the class body, so all those clauses have to be processed before you can define that annotation; and then the issue with space.enforest is similarly that other meta_namespace clauses could influence how the parse_syntax_class is defined?
Or we could maybe delay definition and expression forms by default, as opposed to nestable-declaration forms that might expand to a mixture of clauses and definition forms. But I'm not sure it works to make that kind of distinction.
If I follow what you're getting at, that sounds attractive. Specifically, since class_clause macros are distinct from ordinary defn macros (and defn macros can't expand to more class clauses, I assume), it should be possible to collect all of the primitive clauses in the class body before trying to expand any definitions or expressions within it. And then we could define some nuanced handling of those clauses (e.g. expanding binding, annotation, etc. early so that you can have the binding and annotation forms in-scope when expanding definitions).
I came across another issue that's at least superficially related, but seems more likely to be an actual bug:
#lang rhombus/and_meta
space.enforest myspace:
space_path myspace
meta_namespace myspace_meta:
parse_syntax_class Parsed
meta:
import rhombus open
namespace foo:
export alias 'Parsed':
'myspace_meta.Parsed'
fun bar('$(_ :: foo.Parsed)'): // error: "Parsed: identifier not provided by foo"
#void
Commit 0356d254e0c6f4891647051441d203d5965a9ec1 addresses just the alias bug.
Or we could maybe delay definition and expression forms by default
Delaying all definitions doesn't seem to work out. Delaying definitions and expressions that appear at the end of the block (with no declarations or clauses afterward) works out. It's a subtle distinction, but it seems to be a good compromise. I'll post a PR.
Is #693 enough of an improvement to close this issue?