-
Notifications
You must be signed in to change notification settings - Fork 11
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
execute macro actions in phase 1 #240
Open
gelisam
wants to merge
15
commits into
main
Choose a base branch
from
gelisam/in-later-phase
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
b2a5c06
execute macro actions in phase 1
gelisam a706a10
one more inEarlierPhase was missing
gelisam 7392b3c
with-unknown-type examples
gelisam d1d4335
generalize alts
gelisam 7411b64
list all the Problems where the macro is valid
gelisam 083837e
Pattern, TypePattern, vs PolyProblem prims
gelisam 62c1a0e
rename TypePattern ctors to match ConstructorPatternF
gelisam e6e1d81
fork job at the phase of the output
gelisam 0d88fb6
WIP toy.kl
gelisam a73bac6
WIP the-type
samuel-gelineau-at-well-dot 6fd4d06
new Problem: type constructor
samuel-gelineau-at-well-dot d141285
rename ConstructorPattern to match TypePattern
samuel-gelineau-at-well-dot 5bcc813
remove unused evalErrorText
samuel-gelineau-at-well-dot 0f2f598
[WIP] drop ShortShow
samuel-gelineau-at-well-dot f21e777
[WIP]
samuel-gelineau-at-well-dot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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'm afraid I have opened a can of worms.
First, without this
inEarlierPhase
, the Macro actions which precede(type-case ...)
execute in phase 1 while the Macro actions which follow it execute in phase 0. So something needs to be fixed.Unfortunately, adding this
inEarlierPhase
is not the correct solution, because when the macro returns a Syntax object after the(type-case ...)
, that Syntax is expanded in phase 1 instead of phase 0. For example,returns
(mkT)
as expected, butFails with
Unknown: <mkT>
becausemkT
is only bound in phase 0, not in phase 1. This seems relatively easy to fix: instead of forking the job in an earlier phase, fork a job which executes the Macro action in an earlier phase and then returns the Syntax in the current phase.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 second, more important problem occurs when
type-case
matches on(T)
. Since the Macro action now executes in phase 1, typeT
, which is only bound in phase 0, is not found. The solution seems simple: just look up T in the later phase, right? Well... what aboutelse
? If we look upelse
in the later phase, then it is nowelse
which is not found!This makes sense: type-pattern is a Problem, so it should be possible to write macros which expand to a type-pattern. Since the body of
my-macro
is in phase 1, those macros should be from phase 2, and so shouldelse
. So type-case is in a difficult situation where it encounters identifiers and it does not know in which phase it should expand them.I think the solution is, sadly, to reject the syntax
In favor of a dedicated phase 2 macro which specifies that its argument is a type from phase 0.
or perhaps
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.
Or maybe
datatype
should bind the type-pattern macros at a different phase? That is,should bind a
Maybe
macro at phase 0 which expects to be run in the type Problem at phase 0, and aMaybe
macro at phase 1 which expects to be run in the type-pattern Problem at phase 1.One obvious problem with this idea is that if I then try to make
Maybe
available in the macro definition:I now have two conflicting
Maybe
macros at phase 1: the one which expects to run in the type-pattern Problem at phase 1, and the shifted one which expects to run in the type Problem at phase 1. Maybe it's time to implement the strategy we discussed, where multiple macros are allowed to have the same name, as long as all but one indicate that they do not expect to be called in that context (#241)?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.
Instead of giving a new meaning to
the
orquote
, I am currently implementing a new primitive macro calledtype-constructor
, used like this: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 worms continue to come out of the can.
A datatype is uniquely identified by a module, a phase, and their true name (a String). But when we
(import "either-datatype.kl")
, we don't add that true name to the bindings of that phase. We add the primitive type macro namedEither
to the bindings of that phase. The name of the datatype is not necessarily the same as the name of the macro, because of scopes and shadowing. For example,will define two datatypes, whose true names are
Either
andEither0
respectively. And since the secondEither
shadows the first, after importing that module the primitive type macro namedEither
now refers to the datatype whose true name isEither0
.Anyway, for that reason,
(type-constructor Either a b)
should not simply look up the datatype namedEither
, because the true name for that datatype might beEither0
. Instead, it must use the nameEither
, and find that it refers to a primitive type macro.A primitive type macro happens to be represented by the data constructor
EPrimTypeMacro
, but there is nothing in the Klister codebase which ever matches on a data constructor ofEValue
, so it would be weird fortype-constructor
to look up theEValue
forEither
, check if it is anEPrimTypeMacro
, and then find the true name from that somehow. Instead, macros are always expanded (expandOneForm
is the one function which does match on theEValue
data constructors in order to accomplish this).What does a type macro expand to? While we usually think of a macro as a function which produces a Syntax object, it is actually only user macros which expand to Syntax objects. Primitive macros have the side-effect of filling in ("linking") the mortise (e.g. a
TypePatternPtr
) at which the macro is expanded with a tenon (e.g. aTypePattern
).Primitive type macros, in particular, can either be expanded to fill a type mortise or a type-pattern mortise. In this case, a type-pattern mortise makes more sense.
This means that
(type-constructor Either a b)
is a phase 0 type-pattern would work by expanding(Either a b)
in phase 0 type-pattern. I don't like the idea of(Either a b)
being a valid type-pattern, it is too error-prone because matching on(Either a b)
will work some of the time (when"either-datatype.kl"
and(shift "either-datatype.kl" 1)
are both imported), whereas at other time it will mysteriously fail (whenEither
refers to a different type at phase 0 and phase 1... which it does) and thetype-constructor
wrapper will be needed.Which means that the final worm coming out the can is that I should create a new Problem, the type-constructor Problem. The type-pattern
(type-constructor Either a b)
at phase 1 will expandEither
at phase 0 in the type-constructor Problem, obtaining the true name, and then using it to construct aTypePattern
.Phew, what an adventure!