Previously the inserted test for whether the last argument in the conflicting arity case of an 'fn' expression used the App record type, leading to thunkification within the expression. These instances are being replaced with the SimpleOpCps record type to avoid this. Note that using this record type is correct given the definition of a simple operator.
In a move clearly indicating that I blatantly copied the documentation for simple_op.clj from if.clj, the file-level documentation incorrectly gave information on the IfCps, IfSrs, and IfTriv record types instead of the SimpleOpCps, SimpleOpSrs, and SimpleOpTriv record types. Ooops.
Co-opting the recently-added feature for CTCO which uses the 'recur' form appropriately instead of explicit, named function application, the 'recurify' macro takes an arbitrary Clojure expression (as accepted by ctco) and inserts the 'recur' form appropriately.
The previous definition omitted the "arity" parameter, leading to a very confusing error.
Previously the Recur record type was defined in its own file, recur.clj. With the advent of the "unrecurify" transformation, which converts the 'recur' form into a function application, and the "recurify" tranformation which does the reverse, the App and Recur record types came to depend on each other in the implementations for unrecurify and recurify, respectively. To avoid cyclic load dependencies, the definition for the Recur record type was pushed into app.clj, the same file in which the definition for the App record type resides. This seemed the most logical thing to do, as 'recur' is something of a special form of function application. It should be noted that this did not resolve the mutual reference between App and Recur, and so there is the diry, awful (but necessary) hack of forward declaration of a function which creates the Recur record type in app.clj. An alternative solution to this problem is to simple eliminate the 'recur' form as a separate record type and to represent it as an ordinary function application with a distinguished operator. This would, however, complicate the implementation of the compiler passes for the App record type and violate the philosophy of representing the core language forms via their own record types.
Adding arity information to recurify transformation to prevent erroneously converting function calls to the same overloaded function with a different arity. See previous commit for further details on the now-solved issue.
Implementing the recurify function provided by PRecurify for all relevant CTCO expressions. However, the given implementations are incorrect. At present they pass the name of the current function and whether the expression is in tail position, and replaces all tail-position function applications using that name with the 'recur' form. However, Clojure introduces the wrinkle in that overloaded functions may not use recur to call the current function with a different arity. That is, a given overloaded version of a function may only recur to itself. Thus the current implementation of PRecurify will incorrectly insert the 'recur' form for calls to a different overloaded version of the same function. For example, consider the following expression: (defn foo ([x] (foo x 1)) ([x y] (+ x y))) Given the current implementation for PRecurify, this would be transformed into this: (defn foo ([x] (recur x 1)) ([x y] (+ x y))) Attempting to evaluate this would result in an "incorrect number of arguments to recur" error. Seeing as though we're in the business of correctness-preserving transformations and not incorrectness-introducing ones, this is a bad thing. The solution to this problem is to pass an additional argument to the recurify function of PRecurify denoting the arity of the current function body and only replace function applications when they have the same name as the current function, are in tail position, _and_ pass the same number of arguments as the current function body accepts.
Previously names for 'fn' expressions were added during CPS, as that was the first point that having a name was necessary. However, the unrecurify function implemented by PUnRecurify is run before the CPS transformation and requires an available name for every 'fn' expression. To this end, support was added to the parser for named 'fn' expressions where only anonymous 'fn' expressions were accepted before. Additionally, 'fn' expressions without a name are now given an assigned name in the parser.
Previously used the very simple extend-group macro to condense multiple calls to extend into one. This was well and great, but required implementations to be expressed as maps. The extend-multi macro has a much better name and allows for use of the same syntax as used to implement protocols in defrecord. Also replacing all instances of extend-group with extend-multi.
Adding the appropriate grammar forms for the current language supported by CTCO. Also updating the example given to be the tail-recursive, acumulator-passing-style version of factorial displaying the (as of now) most recent transformations to the code.