Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion lib/Language/PureScript/Backend/Lua/Linker/Foreign.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ module Language.PureScript.Backend.Lua.Linker.Foreign

import Control.Monad.Combinators.NonEmpty qualified as NE
import Control.Monad.Trans.Except (except, throwE)
import Data.Char qualified as Char
import Data.DList (DList)
import Data.DList qualified as DL
import Data.String qualified as String
import Data.Text qualified as Text
import Language.PureScript.Backend.Lua.Key (Key)
import Language.PureScript.Backend.Lua.Key qualified as Key
import Language.PureScript.Backend.Lua.Name qualified as Name
import Path (Abs, Dir, File, Path, toFilePath, (</>))
import Path qualified
import Path.IO qualified as Path
Expand Down Expand Up @@ -54,7 +56,7 @@ parseForeignSource foreigns path = runExceptT do
Left err → throwE $ ForeignErrorParse filePath err
Right parsed → do
let header = guarded (not . Text.null) (Text.strip (unlines headerLines))
pure $ Source header parsed
pure $ Source header (fmap fixDataIntToStringAsGlobalLeak parsed)
where
isReturn ∷ Text → Bool
isReturn = Text.isPrefixOf "return"
Expand Down Expand Up @@ -116,6 +118,43 @@ valueParser = char '(' *> go 0 DL.empty <* MP.space
char ∷ Char → Parser ()
char c = MP.char c *> MP.space

fixDataIntToStringAsGlobalLeak ∷ (Key, Text) → (Key, Text)
fixDataIntToStringAsGlobalLeak (key, value)
| Key.toSafeName key == Name.unsafeName "toStringAs"
, hasKnownContext linesOfValue =
(key, Text.intercalate "\n" (fmap patchLine linesOfValue))
| otherwise = (key, value)
where
linesOfValue = Text.lines value

hasKnownContext ls =
any (("math.floor" `Text.isInfixOf`) . normalizeSpaces) ls
&& any (("table.insert" `Text.isInfixOf`) . normalizeSpaces) ls
&& any hasReturnFunctionArg ls

hasReturnFunctionArg line =
let compact = normalizeSpaces line
in "return" `Text.isPrefixOf` compact
&& "function(i)" `Text.isSuffixOf` compact

patchLine line
| Just indent <- parseFloorAssignment line =
indent <> "local n = floor(i)"
| otherwise = line

parseFloorAssignment line = do
let indent = Text.takeWhile Char.isSpace line
stripped = Text.strip line
guard (not ("local " `Text.isPrefixOf` stripped))
(lhs, rhsWithEq) <- Just (Text.breakOn "=" stripped)
guard (not (Text.null rhsWithEq))
guard (Text.strip lhs == "n")
let rhs = Text.strip (Text.drop 1 rhsWithEq)
guard (rhs == "floor(i)")
pure indent

normalizeSpaces = Text.filter (not . Char.isSpace)

--------------------------------------------------------------------------------
-- Errors ----------------------------------------------------------------------

Expand Down
20 changes: 20 additions & 0 deletions test/Language/PureScript/Backend/Lua/Linker/Foreign/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ rawExports =
baz = (function(unused)
return zoo
end),
toStringAs = (function(radix)
return function(i)
local floor, insert = math.floor, table.insert
n = floor(i)
insert({}, n)
return n
end
end),
[ "if"]= (function() return "if" end),
}
|]
Expand All @@ -75,6 +83,18 @@ parsedExports =
(unsafeKey "foo", "42")
:| [ (unsafeKey "bar", "\"ok\"")
, (unsafeKey "baz", "function(unused)\n return zoo\n end")
,
( unsafeKey "toStringAs"
,
"function(radix)\n"
<> " return function(i)\n"
<> " local floor, insert = math.floor, table.insert\n"
<> " local n = floor(i)\n"
<> " insert({}, n)\n"
<> " return n\n"
<> " end\n"
<> " end"
)
, (KeyReserved "if", "function() return \"if\" end")
]

Expand Down