diff --git a/compiler/src/Generate/JavaScript.hs b/compiler/src/Generate/JavaScript.hs index 5688cb90..4ab080b2 100644 --- a/compiler/src/Generate/JavaScript.hs +++ b/compiler/src/Generate/JavaScript.hs @@ -298,7 +298,7 @@ generateCycle mode argLookup (Opt.Global home _) names values functions = JS.Block [ JS.Block $ map (generateCycleFunc mode argLookup home) functions , JS.Block $ map (generateSafeCycle mode argLookup home) values - , case map (generateRealCycle home) values of + , case map (generateRealCycle mode argLookup home) values of [] -> JS.EmptyStmt @@ -350,16 +350,21 @@ generateSafeCycle mode argLookup home (name, expr) = Expr.codeToStmtList (Expr.generate mode argLookup expr) -generateRealCycle :: ModuleName.Canonical -> (Name.Name, expr) -> JS.Stmt -generateRealCycle home (name, _) = +generateRealCycle :: Mode.Mode -> FnArgLookup -> ModuleName.Canonical -> (Name.Name, Opt.Expr) -> JS.Stmt +generateRealCycle mode argLookup home (name, code) = let safeName = JsName.fromCycle home name realName = JsName.fromGlobal home name + directFnName = JsName.fromGlobalDirectFn home name in JS.Block [ JS.Var realName (JS.Call (JS.Ref safeName) []) , JS.ExprStmt $ JS.Assign (JS.LRef safeName) $ JS.Function Nothing [] [ JS.Return (JS.Ref realName) ] + , JS.Var directFnName + (JS.Function Nothing (error "TODO args") + (Expr.codeToStmtList (Expr.generate mode argLookup (error "TODO call with our args and generated args"))) + ) ] @@ -643,7 +648,7 @@ makeArgLookup graph home name = Just (Opt.Link global) -> case Map.lookup global graph of - Just (Opt.Cycle names _ defs _) -> + Just (Opt.Cycle names values defs _) -> case List.find (\d -> defName d == name) defs of Just (Opt.Def _ (Opt.Function args _)) -> Just (length args) @@ -652,7 +657,20 @@ makeArgLookup graph home name = Just (length args) _ -> - error (show names) + case List.find (\(valueName,_) -> valueName == name) values of + Just (_, Opt.VarGlobal (Opt.Global home_ name_)) -> + makeArgLookup graph home_ name_ + + Just (_, Opt.Call (Opt.VarGlobal (Opt.Global home_ name_)) args) -> + case makeArgLookup graph home_ name_ of + Just otherFn -> + Just (otherFn - length args) + + Nothing -> + error (show names) + + _ -> + error (show names) _ -> Nothing diff --git a/test/Test/JsOutput.hs b/test/Test/JsOutput.hs index 3af00000..4a142a8d 100644 --- a/test/Test/JsOutput.hs +++ b/test/Test/JsOutput.hs @@ -100,6 +100,104 @@ suite = expectTextContains jsOutput "n1 = 0" expectTextContains jsOutput "n2 = $author$project$Main$N2$(0, 0)" + Nothing -> + crash "JS output could not be read." + , scope "direct function calls - mutual recursion" $ do + project <- io $ Lamdera.Relative.requireDir "test/direct-fn-calls-mutual-recursion" + let + elmHome = project ++ "/elm-home" + elmStuff = project ++ "/elm-stuff" + + maybeJsOutput <- io $ do + rmdir elmHome + rmdir elmStuff + + Test.Helpers.withElmHome elmHome $ + Ext.Common.withProjectRoot project $ + Make.run ["src/Main.elm"] $ + Make.Flags + { _debug = False + , _optimize = True + , _output = Just (Make.JS "elm-stuff/tmp.js") + , _report = Nothing + , _docs = Nothing + , _noWire = True + , _optimizeLegible = False + } + + fileContents <- readUtf8Text $ elmStuff ++ "/tmp.js" + + rmdir elmHome + rmdir elmStuff + + pure fileContents + + case maybeJsOutput of + Just jsOutput -> + do + expectTextContains jsOutput "$Main$a2 = function (n) {" + expectTextContains jsOutput "$Main$cyclic$a1() {" + expectTextContains jsOutput "$Main$a1 =" + expectTextContains jsOutput "$Main$cyclic$a1 = function () {" + expectTextContains jsOutput "$Main$a1(1)" + expectTextContains jsOutput "$Main$a2(1)" + + expectTextContains jsOutput "$Main$b2$ = function (m, n) {" + expectTextContains jsOutput "$Main$cyclic$b1()" + expectTextContains jsOutput "$Main$b2 = F2(" + expectTextContains jsOutput "$Main$cyclic$b1() {" + expectTextContains jsOutput "$Main$b1 =" + expectTextContains jsOutput "$Main$b1$ = function (" + expectTextContains jsOutput "$Main$cyclic$b1 = function () {" + expectTextContains jsOutput "$Main$b1$(1, 1)" + expectTextContains jsOutput "$Main$b2$(1, 1)" + + Nothing -> + crash "JS output could not be read." + , scope "direct function calls - mutual recursion with partial application" $ do + project <- io $ Lamdera.Relative.requireDir "test/direct-fn-calls-mutual-recursion-partial-application" + let + elmHome = project ++ "/elm-home" + elmStuff = project ++ "/elm-stuff" + + maybeJsOutput <- io $ do + rmdir elmHome + rmdir elmStuff + + Test.Helpers.withElmHome elmHome $ + Ext.Common.withProjectRoot project $ + Make.run ["src/Main.elm"] $ + Make.Flags + { _debug = False + , _optimize = True + , _output = Just (Make.JS "elm-stuff/tmp.js") + , _report = Nothing + , _docs = Nothing + , _noWire = True + , _optimizeLegible = False + } + + fileContents <- readUtf8Text $ elmStuff ++ "/tmp.js" + + rmdir elmHome + rmdir elmStuff + + pure fileContents + + case maybeJsOutput of + Just jsOutput -> + do + expectTextContains jsOutput "$Main$a2$ = function (x1, x2, x3, x4, x5) {" + expectTextContains jsOutput "$Main$a2 = F5" + expectTextContains jsOutput "$Main$cyclic$a1() {" + expectTextContains jsOutput "$Main$a2, 1, 2);" + expectTextContains jsOutput "$Main$a1 =" + expectTextContains jsOutput "$Main$cyclic$a1 = function () {" + expectTextContains jsOutput "$Main$a1$ = function (" + expectTextContains jsOutput "$Main$a2(1, 2, " + expectTextContains jsOutput "$Main$a1$(3, 4, 5)" + expectTextContains jsOutput "$Main$a2$(1, 2, 3, 4, 5)" + Nothing -> crash "JS output could not be read." ] diff --git a/test/direct-fn-calls-mutual-recursion-partial-application/.gitignore b/test/direct-fn-calls-mutual-recursion-partial-application/.gitignore new file mode 100644 index 00000000..77c73c65 --- /dev/null +++ b/test/direct-fn-calls-mutual-recursion-partial-application/.gitignore @@ -0,0 +1,2 @@ +elm-stuff +*.js diff --git a/test/direct-fn-calls-mutual-recursion-partial-application/elm.json b/test/direct-fn-calls-mutual-recursion-partial-application/elm.json new file mode 100644 index 00000000..f9ee9ed9 --- /dev/null +++ b/test/direct-fn-calls-mutual-recursion-partial-application/elm.json @@ -0,0 +1,29 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0", + "elm/http": "2.0.0", + "elm/json": "1.1.3", + "elm/url": "1.0.0", + "lamdera/codecs": "1.0.0", + "lamdera/core": "1.0.0" + }, + "indirect": { + "elm/bytes": "1.0.8", + "elm/file": "1.0.5", + "elm/time": "1.0.0", + "elm/virtual-dom": "1.0.3" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/test/direct-fn-calls-mutual-recursion-partial-application/src/Main.elm b/test/direct-fn-calls-mutual-recursion-partial-application/src/Main.elm new file mode 100644 index 00000000..8c9dd647 --- /dev/null +++ b/test/direct-fn-calls-mutual-recursion-partial-application/src/Main.elm @@ -0,0 +1,25 @@ +module Main exposing (main) + +import Html exposing (Html) + + +main : Html msg +main = + Html.div [] + [ Html.text (a1 3 4 5) + , Html.text (a2 1 2 3 4 5) + ] + + +a1 : Int -> Int -> Int -> String +a1 = + a2 1 2 + + +a2 : Int -> Int -> Int -> Int -> Int -> String +a2 x1 x2 x3 x4 x5 = + if True then + "done" + + else + a1 3 4 5 diff --git a/test/direct-fn-calls-mutual-recursion/.gitignore b/test/direct-fn-calls-mutual-recursion/.gitignore new file mode 100644 index 00000000..77c73c65 --- /dev/null +++ b/test/direct-fn-calls-mutual-recursion/.gitignore @@ -0,0 +1,2 @@ +elm-stuff +*.js diff --git a/test/direct-fn-calls-mutual-recursion/elm.json b/test/direct-fn-calls-mutual-recursion/elm.json new file mode 100644 index 00000000..f9ee9ed9 --- /dev/null +++ b/test/direct-fn-calls-mutual-recursion/elm.json @@ -0,0 +1,29 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0", + "elm/http": "2.0.0", + "elm/json": "1.1.3", + "elm/url": "1.0.0", + "lamdera/codecs": "1.0.0", + "lamdera/core": "1.0.0" + }, + "indirect": { + "elm/bytes": "1.0.8", + "elm/file": "1.0.5", + "elm/time": "1.0.0", + "elm/virtual-dom": "1.0.3" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/test/direct-fn-calls-mutual-recursion/src/Main.elm b/test/direct-fn-calls-mutual-recursion/src/Main.elm new file mode 100644 index 00000000..da814b38 --- /dev/null +++ b/test/direct-fn-calls-mutual-recursion/src/Main.elm @@ -0,0 +1,41 @@ +module Main exposing (main) + +import Html exposing (Html) + + +main : Html msg +main = + Html.div [] + [ Html.text (a1 1) + , Html.text (a2 1) + , Html.text (b1 1 1) + , Html.text (b2 1 1) + ] + + +a1 : Int -> String +a1 = + a2 + + +a2 : Int -> String +a2 n = + if n > 0 then + a1 (n - 1) + + else + "done" + + +b1 : Int -> Int -> String +b1 = + b2 + + +b2 : Int -> Int -> String +b2 m n = + if n > 0 then + b1 (m - 1) (n - 1) + + else + "done"