forked from erlang/otp
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement brackets and escape expressions
This introduces two new AST nodes 'code' and 'escape'. The first one represents an abstract syntax tree with possible "escaped" holes in it. Its lexical form is of <| Expr |>, where Expr is any Erlang expression or the new 'escape' AST node `Expr. An escape expression is only valid in the context of a code expression, if one is found in the "top level" code (not nested in brackets), erl_lint fails with the error 'escaped_out_of_scope'. Each new bracket expression level has its own fresh symbol table, unbound variables errors are ignored in staged code. % Will compile, even if X is not bound. 1> <| X |>. {var, 1, 'X'} 2> <| begin X = 1, `(<| X + 2 |>) end |>. {block,1, [{match,1,{var,1,'X'},{integer,1,1}}, {op,1,'+',{var,1,'X'},{integer,1,2}}]} You can also pattern match over code expressions: 3> <| `X + `Y |> = <| 1 + 2 + 3 |>. {op,1,'+', {op,1,'+',{integer,1,1},{integer,1,2}}, {integer,1,3}} 4> X. {op,1,'+',{integer,1,1},{integer,1,2}} 5> Y. {integer,1,3}
- Loading branch information
Showing
10 changed files
with
358 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
b734fc4
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 most serious problem with this approach, in my opinion, is that it tightly couples the definition of the programming language Erlang with the de facto (and very ad hoc) syntax tree representation of its library. Meaning that anyone wanting to make a conforming Erlang implementation would have to implement these bracket expressions as you have defined them, mapping them to the "abstract format", and anyone wanting to document Erlang the language will have to include the abstract format in that spec.
There are also some pretty big limitations with the implementation as it is. You can only use expressions within the brackets. If you want to work with code snippets such as function definitions, export declarations, macro definitions, or standalone clauses with no surrounding "case", there is no way to do that.
I suspect that the pattern matching is also not flexible enough. I haven't studied your code that deeply, but it looks like you're not considering things like line numbers (you probably don't want to fail the match just because one bracket expression was on a different line than the pattern it got matched against) or alternative forms of what you want to think of as "the same" AST.
Metavariables are another limitation. You will only be able to have metavariables where you could have an arbitrary expression, and not e.g.
<| fun foo/
X |>. You'll also not be able to use metavariables for sequences of things, like a collection of clauses as in
<| case foo() ofX end |>
. See my presentation on Merl (or the documentation) for a summary of the different kinds of metavariables needed. (Simon Thompson did similar things with their DSL for writing Wrangler refactorings.)As you see, there are a number of things that should be addressed if one wants to have a feature like this as part of the language itself. That's really why I avoided that route, and made the Merl library instead. But if all problems can be solved, I wouldn't mind having something like MetaML (or better) in the Erlang language.
b734fc4
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 don't understand the first part: making code brackets for both construction and pattern-matching means we never need again to see bare syntax trees, and thus that reimplementation of Erlang can change it, as long as people recompile their code. I wouldn't dare not recompiling either if I was using macros and fancy parse transforms.
I explained in some mail on erlang-questions that yes, you would be able to use metavariables (
<| case
Arg ofClauses end |>`), collections of clauses (`<|clauses| `Cl1;
Cs |>), line numbers (
<|(Line)| 1 + 1 |>`), etc. Note that this is a first try at it and thus isn't finished.I read the presentation on Merl and the very fact that you use macros and strings is just sad to me, we would have ended up with something way much better through finishing this.
b734fc4
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'll try to get back to your other remarks later, but please note that although you may think it "sad", I wrote Merl to solve some real problems for a real world product without making major changes to the OTP platform itself. If macros, strings and parse transforms are all you can work with, that's what you get.
b734fc4
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.
Of course! The only person it is making sad is that nondescript contributor who can't refrain from mentioning cheese names in his test cases.