libera/#sicl - IRC Chatlog
Search
3:08:40
beach
The past few days, I had very little inspiration. But today, I think I'll start implementing some of the AST transformations I have been thinking about.
3:08:52
beach
I want to canonicalize the DECLARATION-ASTs so that each one has a single declaration specifier in it. And I want each declaration specifier that concerns a variable name or a function name to contain a single such name.
3:08:57
beach
That way, I can shuffle them around for the next transformation, which is turning every LET*-AST into nested LET-ASTs, with correct association of the declarations.
3:09:28
beach
Then I want to turn each LET-AST into a FLET-AST so as to make it explicit that LET introduces an environment (that may be captured). I will also turn ((LAMBDA <lambda-list> <body>) <arguments>) into (FLET ((<name> <lambda-list> <body)) (<name> <arguments>)) to eliminate the special case of an application of a lambda expression.
3:09:38
beach
And I will turn (FUNCTION (LAMBDA <lambda-list> <body>)) into (FLET ((<name> <lambda-list> <body>)) (FUNCTION <name>)). All these unless I have forgotten some subtle difference in semantics, of course.
3:09:50
beach
And finally, I will turn FLET-ASTs into (nested?) LABELS-ASTs, which is possible since there is no longer any risk of variable capture at this point.
3:09:56
beach
All these transformations will simplify the AST evaluator, and also the conversion of the AST into HIR. I expect to implement environment capture (which must implemented anyway) to undo most of the transformations and merge environments when there is no capture.
3:10:00
beach
Another transformation I want to do is the one that heisig implemented at the CST level, namely turning nontrivial literals into MAKE-LOAD-FORM when the AST is created by the file compiler.
3:11:30
beach
Traversing an AST is a breeze, because Iconoclast defines the AST classes in a way that there is information on what slot readers and initargs each class has.
3:12:37
beach
I hope to do closure conversion on ASTs as well. I will then have to introduce some more AST classes, and I need to decide whether to define those in Iconoclast or in client code.
8:07:45
beach
Brucio-61: Not sure whether I mentioned this before, but when I parse (locally (declare (type integer f))), then :DECLARATION-SPECIFIER gets related to :ATOMIC-TYPE-SPECIFIER using the :ARGUMENT relation (just like :DECLARATION-SPECIFIER and :NAME), rather than (say) with the :TYPE-SPECIFIER relation.
8:09:24
beach
I know we have discussed this issue in the past, specifically in relation to what to do with declarations such as (DECLARE (FOO X))
8:19:54
beach
I guess I can implement the transformation of LET* to LET without taking type specifiers into account for now.
9:16:23
Brucio-61
beach: regarding canonicalizing: some time ago, i made builder as an example that does this. are interested in that way of doing it or do you prefer a different solution?
9:17:39
Brucio-61
the reason for using 6:ARGUMENT as the relation name is that i thought a uniform tree structure for declarations would help with uniform processing of declerations and also with non-standard declarations
9:19:00
Brucio-61
i think the processing included only transformations that can be done without an environment and only touched standard declaration specifiers but let me check
9:20:29
Brucio-61
parsing declaration specifiers "arguments" allows syntax checking and saves the client the work of selecting an appropriate parser based on the declaration kind
9:40:09
beach
Brucio-61: Aside from canonicalization, I'll just experiment and see what arguments are given to MAKE-NODE and RELATE for various situations, and I'll code accordingly.
9:41:17
Brucio-61
using 6:ARGUMENT is not set in stone but i didn't expect it to cause an issue. i can try both variants at some point
9:42:07
beach
As I recall, there are other assumptions I have made that may need to be modified later.
9:42:50
beach
But I can tell that I first need to work on type declarations and declarations with unknown type identifiers.
9:42:56
Brucio-61
i looked at the canonicalization example. the builder splits declaration nodes that contain multiple declaration specifiers and it provides a generic function 6SPLIT-DECLRATION-ARGUMENTS with an example method specialized to 6TYPE
9:43:42
Brucio-61
the generic function can be used to transform 6(type T x y) to 6(type T x) (type T y)
9:46:44
Brucio-61
i misread the code. it does process 6INLINE and 6DYNAMIC-EXTENT but 6TYPE needs a separate method because not all of its arguments name bindings
9:49:20
beach
What makes you say that not all arguments to a TYPE declaration specifier are bindings?
9:51:10
Brucio-61
i meant the typespec argument does not name a variable or function binding and should not contribute to the splitting into multiple declaration specifiers
9:51:44
Brucio-61
that is 6(ignore x y) becomes 6(ignore x) (ignore y) but 6(type t x) does not become 6(type t) (type x)
9:53:05
Brucio-61
yes, in the example, the generic function 6SPLIT-DECLARATION-ARGUMENTS has two methods: one for 6TYPE and one for everything else. that's probably an oversimplification but the approach should work
9:53:42
beach
Oh, I see. I took your description to mean that I would have to supply a method for TYPE. My bad.
9:55:09
beach
So let me get this straight. To use your code, I would have to first consult the environment to turn the unknown DECLARATION-ASTs into TYPE-ASTs or something else. Then what do I do to apply your code to Iconoclast ASTs?
9:55:30
Brucio-61
anyway, what is not handled is 6(declare (integer x)) since the example does not consider any environment
9:59:18
Brucio-61
i think you could write a 6MAKE-NODE method specialized to your builder and 6:DECLARATION-SPECIFIER that consults the environment and turns declaration specifier of unknown kinds into 6TYPE declaration specifiers
10:00:01
Brucio-61
that approach would handle unknown declaration specifiers first, then split declarations and declaration specifiers
10:01:39
Brucio-61
alternatively, you could restrict the 6SPLIT-DECLARATION-ARGUMENTS function to only apply to known declaration specifiers so that no splitting occurs for e.g. 6(integer x y) and handle unknown declaration specifiers entirely separately
10:02:31
Brucio-61
by separately i mean by post-processing the AST after the builder is done (or possibly in 6FINISH-NODE method)
10:03:09
beach
The way I have done it is to consult the environment in FINISH-NODE. I'll see whether your idea can be applied.
10:06:22
Brucio-61
i can try to combine the example with the iconoclast builder. may save time if i do it
10:07:16
beach
Nah, don't worry about it. I'll figure it out. I am not that thrilled about canonicalizing at MAKE-NODE time. But I might change my mind.
10:08:24
Brucio-61
i understand. i'm also worried that some roadblock might come up but if possible, it seems like the simplest solution to me since the transformation is mostly syntactical
10:12:06
Brucio-61
given a quick test, the example seems to work with the iconoclast builder. but printing the iconoclast tree fails. not sure whose "fault" it is
10:13:14
beach
I think you replace the DECLARATION-ASTS with DECLARATION-SPECIFIER-ASTs, no? Could that have something to do with it?
10:20:20
Brucio-61
the problem was just with iconoclast-print-tree after all. the version https://plaster.tymoon.eu/view/3961#3963 (most recent annotation of the past) builds an iconoclast ast and inspects it (since printing doesn't work)
10:30:27
beach
I am about to take a long-ish lunch break. Recently, I often get the feeling that I am going around in circles. I need to break that feeling or I won't get anything done.
10:32:33
Brucio-61
sorry to hear that. don't feel obligated to pursue the approach i suggested. i am probably biased by thinking the fact that the builder protocol can do such transformations independently of the "target" builder is cool
10:34:21
beach
Sure. I think I'll do what I often do which is write something myself, and if and when I realize that I could use something existing, I'll change and adapt the code.
10:35:30
beach
By the way, I think I discovered (no doubt not as the first person) an alternative way of writing a tree transformer application. As I recall, the traditional way is to have a function that takes function arguments for pre-processing and post-processing of nodes, yes?
10:36:57
beach
But with CLOS, the primary method can do just the traversal, and client code (specializing to a CLIENT class) can define an :AROUND method to do whatever processing is required, before calling CALL-NEXT-METHOD, after calling it, or changing the node entirely and calling the traversal routine recursively on the changed node.
10:39:21
Brucio-61
right, that's a pretty flexible approach. do you generally mutate nodes or build a fresh tree for the result?
10:43:42
beach
I could do CHANGE-CLASS and then make a recursive call, since I can't do CALL-NEXT-METHOD then.