-
Notifications
You must be signed in to change notification settings - Fork 372
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
Pattern-matching compiler #1593
Pattern-matching compiler #1593
Conversation
2ae0d0c
to
ac61e7f
Compare
Veto. It's not that I'm opposed to this pattern matching, it's just that this is a big change that will take a while to review, and as a deep change, it should have two reviewers. (Then we'll have at least three people who still understand how the compiler works.) It does seem like an improvement, and this pattern matching stuff could really help with macros too. I wonder how this compares to the Scheme-style macros. |
Two reviews would definitely be nice, but the chances of getting them seem slim. |
Oh man, this looks awesome. I'll make some time to review this tomorrow. |
117346d
to
15c1436
Compare
15c1436
to
c39cba1
Compare
@gilch Sure enough, here we are two weeks later with no reviews. If you have any objections to the changes, then let's by all means discuss them, but a veto with no actual opposition to the changes defeats the purpose of the two-week policy, which is to allow uncontroversial PRs to be merged even when reviewers aren't available. |
Not objecting to the concept is different than approving this implementation of it. I'll consider rescinding my veto after I have reviewed it myself, if no-one else is planning to. (@vodik @kirbyfan64 @tuturto you three have been the most active lately, any takers?) If you feel the team is too much of a hindrance to be bothered with, we can't stop you from maintaining your own fork. But otherwise understand that we're all volunteers here. We're maintaining Hy without pay in our spare time. Hy is one of many priorities competing for our time and energy. |
I'm asking for objections to the implementation of it, not just the concept. The problem is not that the team is hindering me (or anyone else). The problem is that the team is often not there, because we're all volunteers who are maintaining Hy without pay in our spare time, and Hy is one of many priorities competing for our time and energy. That's why I pushed for the two-week policy, which largely solves the problem of non-availability of reviewers. To veto because nobody has the time to review a PR recreates the problem. I really don't want to fork, because that would fragment the already small core team. |
I'll have a look tonight |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks super-cool
if type(atom) not in _model_compilers: | ||
return | ||
# Compilation methods may mutate the atom, so copy it first. | ||
atom = copy.copy(atom) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not necessarily something that needs to be done now, but what would it require to make atoms immutable? I sort of thought that would be the case already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's #1542. Basically we'll just need to remove the remaining mutating code from the compiler.
hy/model_patterns.py
Outdated
some(lambda x: isinstance(x, group_type)) >> | ||
(lambda x: group_type(whole(parsers).parse(x)).replace(x, recursive=False))) | ||
|
||
def sb(*parsers): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sb
I couldn't parse before reading the definition down here. We don't want to use too long name, because typing it would get annoying, but is there better than sb
that isn't too long?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
square
or squareb
? brackets
is perhaps obvious, but people sometimes use that word to mean bracketing characters in general, including parentheses. Maybe sbrackets
or sqbrackets
or sqbrack
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
out of those, I like brackets
best. But this is nothing we need to solve if good name doesn't come easy. I just thought that since I really like the pattern matching rules we have now, we could have obvious names for them. Now new developer has to check the definition to understand what's going on (not that the code is long).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All right, I'll do a git filter-branch
to change it to brackets
.
Thanks! |
c39cba1
to
4e0c900
Compare
hy/compiler.py
Outdated
if entries[0] == "quote": | ||
@special(["quote", "quasiquote"], [FORM]) | ||
def compile_quote(self, expr, root, arg): | ||
if root == "quote": | ||
# Never allow unquoting | ||
level = float("inf") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably just be Inf
here to be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
4e0c900
to
6cc74ac
Compare
6cc74ac
to
667c4cf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work. I don't see any reason to block this. Most of my comments don't really have anything to do with the code, I think this is very reasonable.
Question is should we maybe make another small release before merging this, or just going for it?
@@ -30,7 +30,9 @@ Other Breaking Changes | |||
* `hy-repr` uses registered functions instead of methods | |||
* `HyKeyword` no longer inherits from the string type and has been | |||
made into its own object type. | |||
* `HySymbol` no longer inherits from `HyString`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
* `(except)` is no longer allowed. Use `(except [])` instead. | ||
* `(import [foo])` is no longer allowed. Use `(import foo)` instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to do this, maybe it makes sense to go ahead and remove the second level nesting of arrays: (import [foo bar baz])
now means from foo import bar, baz
, instead of the existing (import [foo [bar baz]])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a bad idea, but it can be done in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(defmacro a-set [] #{1 2}) | ||
(assert (= (a-set) #{1 2})) | ||
(defmacro a-none []) | ||
(assert (= (a-none) None))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just an observation, but maybe it makes sense to add another test for NotImplemented
. Its another special value that, while it works fine in Hy, we never test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean, testing a macro that returns NotImplemented
? It doesn't work (TypeError: Don't know how to wrap a <class 'NotImplementedType'> object to a HyObject
).
hy/compiler.py
Outdated
_decoratables += (ast.AsyncFunctionDef,) | ||
# _bad_roots are illegal at the top level. | ||
_bad_roots = tuple(ast_str(x) for x in ( | ||
"unquote", "unquote-splice", "unpack-mapping", "except")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to add return
, yield
, yield-from
and await
here?
Top level, these forms are currently accepted by the hy
compiler, but generate invalid AST and thus causes Python's compile
to crash with "SyntaxError: '...' outside function", which is completely detached from the source code.
Maybe it makes for a better user experience to catch it early.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is perhaps misleading. The detection for _bad_roots
doesn't distinguish between forms inside a function and forms at the top level; it just triggers for any attempt to use one of the given names as a special operator. except
is illegal at the top level in the sense that it isn't a true special operator; it's handled inside @special("try", …)
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made the comment more descriptive.
expression.pop(0) | ||
cond = self.compile(expression.pop(0)) | ||
body = self.compile(expression.pop(0)) | ||
@special("if*", [FORM, FORM, maybe(FORM)]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is cool. Nice work.
In the process, I've banned the syntax `(import [foo])` in favor of `(import foo)`.
I haven't bothered to refine the patterns for these since I intend to completely overhaul the comprehension forms in the near future.
667c4cf
to
9f454f0
Compare
I want to go for it. It'll be at least a few weeks till the next release, and I'll be running Hy master in the meantime, so at least I'll find any big new bugs if nobody else does. |
Okay. If you find something bad, you can just post an issue and I'll probably be able to make PR for a fix promptly. |
I'll open an issue with the other import syntax change suggestion then (and maybe try to implement it to see if I really understand how this works now) |
@Kodiologist What are the changes to funcparserlib that you're proposing? I haven't been developing funcparserlib for a few years, but I still maintain it and I'd like to see improvements in the library by the community in the form of pull requests. |
@vlasovskikh Oh, cool, good to talk to you. The change I'm proposing is to store the token that failed to match every time an alternation ( |
@Kodiologist I like the general idea of being able to list expected terminals or non-terminals. However it's a bit unclear to me how you propose to fix it. We can continue this discussion at https://github.com/vlasovskikh/funcparserlib. Could you file an issue with a simple example grammar, an example file to parse and the desired output on parse errors? Or maybe even a pull request with an implementation of your idea for finding expected tokens? :) |
(Currently, this PR depends on most of the small PRs I've posted recently. Once those PRs are merged, I can rebase out the corresponding commits.)(Done.)I've written a small module
hy.model_patterns
that uses funcparserlib to provide parser combinators for Hy model objects. I expect this library to be useful to Hy programmers, but its chief purpose is for the compiler. I've rewritten the compiler to parse special forms with these model patterns rather than by manipulating model trees by hand (closes #1573). While I'm at it, I've also done a lot of refactoring of the compiler, although unfortunately, it's so huge that there's still more refactoring work to be done. The compiler is about 400 lines shorter and is now finally below 2,000 lines. I haven't made Hy models immutable (#1542), but I've made some progress in that direction by removing a lot of mutating code.There's a catch, which is that error messages for special-form parse failures aren't very informative. They show where the parser stopped, but they don't say which tokens would be legal in the given position. I think I could patch funcparserlib to fix this, but its author (@vlasovskikh) seems to no longer be maintaining it, so we'd need to make our own fork.
Other thoughts for the future:
hy.model_patterns
could use some documentation and tests and perhaps a helper function or two for using model patterns in macros.