git.iko.soy/rowtype-yoga/purescm
on bytevector help sign in
Convert LetRec (#120)

* Drop DefineUncurriedFn/DefinedCurriedFn * Rename DefineValue to just Define * Convert LetRec * Add snapshot for mutually-recursive top level functions * Add snapshot for mutually-recursive data structures

commit87611f655e632b16730da160b9fc8003169a3b3c authorJordanMartinez <jordanalex.martinez@protonmail.com> dateMon 10 Apr 2023, 10:36 (4 years ago) parent3ba52b8
8 files changed+101−61
src/PureScript/Backend/Chez/Convert.purs+12−29 src/PureScript/Backend/Chez/Printer.purs+2−22 src/PureScript/Backend/Chez/Runtime.purs+5−4 src/PureScript/Backend/Chez/Syntax.purs+1−3 test-snapshots/src/snapshots-input/Snapshot.Constructor.purs+9 test-snapshots/src/snapshots-input/Snapshot.Let.purs+15 test-snapshots/src/snapshots-output/Snapshot.Constructor.ss+31−1 test-snapshots/src/snapshots-output/Snapshot.Let.ss+26−2
src/PureScript/Backend/Chez/Convert.purs+12−29
@@ -6,6 +6,7 @@ import Data.Argonaut as Json
66import Data.Array as Array
77import Data.Array.NonEmpty as NEA
88import Data.Array.NonEmpty as NonEmptyArray
9+import Data.Bifunctor (bimap)
910import Data.Char (toCharCode)
1011import Data.Int as Int
1112import Data.Maybe (Maybe(..))
@@ -88,9 +89,7 @@ codegenModule { name, bindings, imports, foreign: foreign_ } =
8889
8990definitionIdentifiers :: ChezDefinition -> Array String
9091definitionIdentifiers = case _ of
91− DefineValue i _ -> [ i ]
92− DefineCurriedFunction i _ _ -> [ i ]
93− DefineUncurriedFunction i _ _ -> [ i ]
92+ Define i _ -> [ i ]
9493 DefineRecordType i [ x ] ->
9594 [ recordTypeCurriedConstructor i
9695 , recordTypePredicate i
@@ -118,11 +117,8 @@ codegenTopLevelBindingGroup
118117 :: CodegenEnv
119118 -> BackendBindingGroup Ident NeutralExpr
120119 -> Array ChezDefinition
121−codegenTopLevelBindingGroup codegenEnv { recursive, bindings }
122− | recursive, Just bindings' <- NonEmptyArray.fromArray bindings =
123− [ DefineValue "rtlbg" $ S.Identifier "recursive-top-level-binding-group" ]
124− | otherwise =
125− Array.concatMap (codegenTopLevelBinding codegenEnv) bindings
120+codegenTopLevelBindingGroup codegenEnv { bindings } =
121+ Array.concatMap (codegenTopLevelBinding codegenEnv) bindings
126122
127123codegenTopLevelBinding
128124 :: CodegenEnv
@@ -130,25 +126,12 @@ codegenTopLevelBinding
130126 -> Array ChezDefinition
131127codegenTopLevelBinding codegenEnv (Tuple (Ident i) n) =
132128 case unwrap n of
133− Abs a e ->
134− [ DefineCurriedFunction
135− i
136− (uncurry toChezIdent <$> a)
137− (codegenExpr codegenEnv e)
138− ]
139− UncurriedAbs a e ->
140− [ DefineUncurriedFunction
141− i
142− (uncurry toChezIdent <$> a)
143− (codegenExpr codegenEnv e)
144− ]
145129 CtorDef _ _ _ ss ->
146130 case NonEmptyArray.fromArray ss of
147131 Nothing ->
148− [ DefineValue i (S.quote $ S.Identifier i)
149− , DefineUncurriedFunction
150− (S.recordTypePredicate i)
151− [ "v" ]
132+ [ Define i (S.quote $ S.Identifier i)
133+ , Define (S.recordTypePredicate i)
134+ $ S.mkUncurriedFn [ "v" ]
152135 $ S.eqQ (S.quote $ S.Identifier i) (S.Identifier "v")
153136 ]
154137 Just xs
@@ -156,13 +139,13 @@ codegenTopLevelBinding codegenEnv (Tuple (Ident i) n) =
156139 [ DefineRecordType i ss ]
157140 | otherwise ->
158141 [ DefineRecordType i ss
159− , DefineCurriedFunction i xs
142+ , Define i $ S.mkCurriedFn xs
160143 $ S.runUncurriedFn
161144 (S.Identifier $ S.recordTypeUncurriedConstructor i)
162145 (map S.Identifier ss)
163146 ]
164147 _ ->
165− [ DefineValue i $ codegenExpr codegenEnv n ]
148+ [ Define i $ codegenExpr codegenEnv n ]
166149
167150codegenExpr :: CodegenEnv -> NeutralExpr -> ChezExpr
168151codegenExpr codegenEnv@{ currentModule } s = case unwrap s of
@@ -209,9 +192,9 @@ codegenExpr codegenEnv@{ currentModule } s = case unwrap s of
209192 (map (codegenExpr codegenEnv <<< Tuple.snd) xs)
210193 CtorDef _ _ _ _ ->
211194 unsafeCrashWith "codegenExpr:CtorDef - handled by codegenTopLevelBinding!"
212−
213− LetRec _ _ _ ->
214− S.Identifier "let-rec"
195+ LetRec lvl bindings expr ->
196+ S.Let true (map (bimap (flip toChezIdent lvl <<< Just) (codegenExpr codegenEnv)) bindings) $
197+ codegenExpr codegenEnv expr
215198 Let _ _ _ _ ->
216199 codegenPureChain codegenEnv s
217200 Branch b o -> do
src/PureScript/Backend/Chez/Printer.purs+2−22
@@ -89,11 +89,7 @@ escapeIdentifiers lib = lib
8989 escapeLibRef libRef = libRef { identifiers = map escapeIdent libRef.identifiers }
9090
9191 escapeDefinition = case _ of
92− DefineValue i expr -> DefineValue (escapeIdent i) $ escapeExpr expr
93− DefineCurriedFunction i args expr ->
94− DefineCurriedFunction (escapeIdent i) (map escapeIdent args) $ escapeExpr expr
95− DefineUncurriedFunction i args expr ->
96− DefineUncurriedFunction (escapeIdent i) (map escapeIdent args) $ escapeExpr expr
92+ Define i expr -> Define (escapeIdent i) $ escapeExpr expr
9793 DefineRecordType i fields -> DefineRecordType (escapeIdent i) $ map escapeIdent fields
9894
9995 escapeExpr = case _ of
@@ -237,17 +233,9 @@ printNamedIndentedList firstLine body
237233
238234printDefinition :: ChezDefinition -> Doc Void
239235printDefinition = case _ of
240− DefineValue ident expr ->
236+ Define ident expr ->
241237 printNamedIndentedList (D.words [ D.text $ scmPrefixed "define", D.text ident ])
242238 $ printChezExpr expr
243− DefineCurriedFunction ident args expr ->
244− printNamedIndentedList (D.text (scmPrefixed "define ") <> D.text ident)
245− $ printCurriedAbs (NEA.toArray args) expr
246− DefineUncurriedFunction ident args expr ->
247− printNamedIndentedList (D.text (scmPrefixed "define ") <> D.text ident)
248− $ printNamedIndentedList
249− (D.text (scmPrefixed "lambda ") <> printList (D.words $ map D.text args))
250− (printChezExpr expr)
251239 DefineRecordType ident [ field ] ->
252240 printRecordDefinition
253241 ident
@@ -263,14 +251,6 @@ printDefinition = case _ of
263251 (recordTypePredicate ident)
264252 fields
265253
266−printCurriedAbs :: Prim.Array Prim.String -> ChezExpr -> Doc Void
267−printCurriedAbs args body = Array.foldr foldFn (printChezExpr body) args
268− where
269− foldFn next bodyOrRest =
270− printNamedIndentedList
271− (D.words [ D.text $ scmPrefixed "lambda", printList (D.text next) ])
272− bodyOrRest
273−
274254printChezExpr :: ChezExpr -> Doc Void
275255printChezExpr e = case e of
276256 Integer (LiteralDigit x) -> D.text x
src/PureScript/Backend/Chez/Runtime.purs+5−4
@@ -6,6 +6,7 @@ import Control.Monad.State (runState)
66import Control.Monad.State.Class (class MonadState, modify_)
77import Data.Array as Array
88import Data.Array.NonEmpty as NEA
9+import Data.Array.NonEmpty.Internal (NonEmptyArray(..))
910import Data.Maybe (Maybe(..))
1011import Data.Traversable (sequence)
1112import Data.Tuple (Tuple(..))
@@ -18,17 +19,17 @@ makeExportedFunction
1819 . Monad m
1920 => MonadState (Array ChezExport) m
2021 => String
21− -> Array String
22+ -> NonEmptyArray String
2223 -> ChezExpr
2324 -> m ChezDefinition
2425makeExportedFunction name args expr = do
2526 modify_ $ Array.cons $ ExportIdentifier name
26− pure $ DefineUncurriedFunction name args expr
27+ pure $ Define name $ S.mkCurriedFn args expr
2728
2829makeBooleanComparison
2930 :: forall m. Monad m => MonadState (Array ChezExport) m => String -> m ChezDefinition
3031makeBooleanComparison suffix =
31− makeExportedFunction ("boolean" <> suffix) [ "x", "y" ] $
32+ makeExportedFunction ("boolean" <> suffix) (NonEmptyArray [ "x", "y" ]) $
3233 S.List
3334 [ S.Identifier $ scmPrefixed "fx" <> suffix
3435 , S.List [ S.Identifier "boolean->integer", S.Identifier "x" ]
@@ -39,7 +40,7 @@ runtimeModule :: ChezLibrary
3940runtimeModule = do
4041 let
4142 Tuple definitions exports = flip runState [] $ sequence
42− [ pure $ DefineUncurriedFunction "boolean->integer" [ "x" ] $ S.List
43+ [ pure $ S.Define "boolean->integer" $ S.mkCurriedFn (pure "x") $ S.List
4344 [ S.Identifier $ scmPrefixed "if"
4445 , S.Identifier "x"
4546 , S.Integer $ S.LiteralDigit "1"
src/PureScript/Backend/Chez/Syntax.purs+1−3
@@ -75,9 +75,7 @@ type LibraryBody =
7575 }
7676
7777data ChezDefinition
78− = DefineValue String ChezExpr
79− | DefineCurriedFunction String (NonEmptyArray String) ChezExpr
80− | DefineUncurriedFunction String (Array String) ChezExpr
78+ = Define String ChezExpr
8179 | DefineRecordType String (Array String)
8280
8381newtype LiteralDigit = LiteralDigit String
test-snapshots/src/snapshots-input/Snapshot.Constructor.purs+9
@@ -5,3 +5,12 @@ data Maybe a = Just a | Nothing
55data Tree a
66 = Nil
77 | Node (Tree a) a (Tree a)
8+
9+-- recursive constructors
10+data Mutual1
11+ = Stop1
12+ | Continue1 Mutual2
13+
14+data Mutual2
15+ = Stop2
16+ | Continue2 Mutual1
test-snapshots/src/snapshots-input/Snapshot.Let.purs+15
@@ -11,3 +11,18 @@ letChain x =
1111 d = c * c
1212 in
1313 a + b + c + d
14+
15+letRecursive :: Int -> Int
16+letRecursive x
17+ | x == 0 = 0
18+ | otherwise = letRecursive (x - 1)
19+
20+isEven :: Int -> Boolean
21+isEven x
22+ | x == 0 = true
23+ | otherwise = isOdd (x - 1)
24+
25+isOdd :: Int -> Boolean
26+isOdd x
27+ | x == 1 = false
28+ | otherwise = isEven (x - 1)
test-snapshots/src/snapshots-output/Snapshot.Constructor.ss+31−1
@@ -3,6 +3,12 @@
33(library
44 (Snapshot.Constructor lib)
55 (export
6+ Continue1
7+ Continue1-value0
8+ Continue1?
9+ Continue2
10+ Continue2-value0
11+ Continue2?
612 Just
713 Just-value0
814 Just?
@@ -15,7 +21,11 @@
1521 Node-value2
1622 Node?
1723 Nothing
18− Nothing?)
24+ Nothing?
25+ Stop1
26+ Stop1?
27+ Stop2
28+ Stop2?)
1929 (import
2030 (prefix (chezscheme) scm:)
2131 (prefix (_Chez_Runtime lib) rt:))
@@ -36,6 +46,26 @@
3646 (scm:lambda (value2)
3747 (Node* value0 value1 value2)))))
3848
49+ (scm:define Stop1
50+ (scm:quote Stop1))
51+
52+ (scm:define Stop1?
53+ (scm:lambda (v)
54+ (scm:eq? (scm:quote Stop1) v)))
55+
56+ (scm:define-record-type (Continue1$ Continue1 Continue1?)
57+ (scm:fields (scm:immutable value0 Continue1-value0)))
58+
59+ (scm:define Stop2
60+ (scm:quote Stop2))
61+
62+ (scm:define Stop2?
63+ (scm:lambda (v)
64+ (scm:eq? (scm:quote Stop2) v)))
65+
66+ (scm:define-record-type (Continue2$ Continue2 Continue2?)
67+ (scm:fields (scm:immutable value0 Continue2-value0)))
68+
3969 (scm:define-record-type (Just$ Just Just?)
4070 (scm:fields (scm:immutable value0 Just-value0)))
4171
test-snapshots/src/snapshots-output/Snapshot.Let.ss+26−2
@@ -3,15 +3,39 @@
33(library
44 (Snapshot.Let lib)
55 (export
6− letChain)
6+ isEven
7+ isOdd
8+ letChain
9+ letRecursive)
710 (import
811 (prefix (chezscheme) scm:)
912 (prefix (_Chez_Runtime lib) rt:))
1013
14+ (scm:define letRecursive
15+ (scm:lambda (x0)
16+ (scm:cond
17+ [(scm:fx=? x0 0) 0]
18+ [scm:else (letRecursive (scm:fx- x0 1))])))
19+
1120 (scm:define letChain
1221 (scm:lambda (x0)
1322 (scm:let*
1423 ([a1 (scm:fx+ x0 x0)]
1524 [b2 (scm:fx+ a1 a1)]
1625 [c3 (scm:fx+ b2 b2)])
17− (scm:fx+ (scm:fx+ (scm:fx+ a1 b2) c3) (scm:fx* c3 c3))))))
26+ (scm:fx+ (scm:fx+ (scm:fx+ a1 b2) c3) (scm:fx* c3 c3)))))
27+
28+ (scm:define isOdd
29+ (scm:lambda (x0)
30+ (scm:cond
31+ [(scm:fx=? x0 1) #f]
32+ [scm:else (isEven (scm:fx- x0 1))])))
33+
34+ (scm:define isEven
35+ (scm:lambda (x0)
36+ (scm:cond
37+ [(scm:fx=? x0 0) #t]
38+ [scm:else (scm:let ([_1 (scm:fx- x0 1)])
39+ (scm:cond
40+ [(scm:fx=? _1 1) #f]
41+ [scm:else (isEven (scm:fx- _1 1))]))]))))