Commit 42b52151 authored by Michael Hanus 's avatar Michael Hanus

Add caching for form names to speed up compiler larger web applications

parent 71e13b1e
......@@ -36,6 +36,9 @@ logic variables in the source programs, are sequentially numbered
when a form is generated. This allows a simple identification
of the corresponding values submitted by the client.
curry2cgi
---------
The auxiliary program `curry2cgi` is used to transform a
Curry program containing forms into an executable.
`curry2cgi` collects all operations defining forms in a program
......@@ -56,3 +59,11 @@ to be compiled. Thus, the operation `HTML.CGI.Exec.printMainPage`
is responsible to generate the initial HTML page or, if a form
is submitted, invoke the corresponding event handler defined
in the form.
If some imported modules also contain HTML forms, the names
of these imported modules must be passed to `curry2cgi`
(via the option `--include`) so that their names are known
to the generated main program. In this case, `curry2cgi` also
collects the forms in the provided imported modules.
To speed up this process for larger applications, `curry2cgi`
caches the form names of a module `M` in file `.curry/M.htmlforms`.
\ No newline at end of file
......@@ -21,7 +21,7 @@ A form inside a web page must be defined as a
myForm :: HtmlFormDef String
myForm = formDefWithID "Module.myForm" readData viewData
The first argument of a form definition is the qualified name
The first argument of a form definition must be the qualified name
of the operation (this will be checked by `curry2cgi`).
The second argument is an IO action to read some data
used in the form, and the third argument is the actual view
......
......@@ -26,6 +26,15 @@ import System.CurryPath ( stripCurrySuffix )
import ExtractForms ( extractFormsInProg, showQName )
------------------------------------------------------------------------
banner :: String
banner = unlines [bannerLine,bannerText,bannerLine]
where
bannerText = "Compile Curry programs with HTML forms to CGI executables " ++
"(Version of 06/03/20)"
bannerLine = take (length bannerText) (repeat '=')
main :: IO ()
main = do
args <- getArgs
......@@ -169,7 +178,7 @@ processOptions argv = do
[] -> error $ "Name of main module missing!"
_ -> error $ "Please provide only one main module!"
where
printUsage = putStrLn usageText
printUsage = putStrLn (banner ++ "\n" ++ usageText)
-- Usage text
usageText :: String
......@@ -182,6 +191,9 @@ options =
[ Option "h?" ["help"]
(NoArg (\opts -> opts { optHelp = True }))
"print help and exit"
, Option "q" ["quiet"]
(NoArg (\opts -> opts { optVerb = 0 }))
"run quietly (no output, only exit code)"
, Option "v" ["verb"]
(OptArg (maybe (checkVerb 2) (safeReadNat checkVerb)) "<n>")
"verbosity level:\n0: quiet (same as `-q')\n1: show status messages (default)\n2: show intermediate results (same as `-v')\n3: show all details"
......
......@@ -2,26 +2,52 @@
--- Compute infos about all `HtmlFormDef` operations occurring in a module.
---
--- @author Michael Hanus
--- @version October 2019
--- @version March 2020
------------------------------------------------------------------------------
module ExtractForms ( extractFormsInProg, showQName )
where
import FilePath ( (</>) )
import Directory ( doesFileExist, getModificationTime )
import FilePath ( (</>), (<.>) )
import List ( intercalate, partition )
import System ( exitWith, getArgs, getPID, system )
import AbstractCurry.Files
import AbstractCurry.Select
import AbstractCurry.Types
import HTML.Base
import System.CurryPath ( stripCurrySuffix )
import System.CurryPath ( inCurrySubdir, lookupModuleSourceInLoadPath
, stripCurrySuffix )
-- The cache file for storing qualified form names of a module w.r.t.
-- a directory.
formCacheFile :: String -> String -> String
formCacheFile mdir mname = inCurrySubdir (mdir </> mname) <.> "htmlforms"
--- Extract and check all forms defined in a Curry module (their argument).
--- Extract and check all forms defined in a Curry module (third argument).
--- Returns the qualified names of the exported forms.
extractFormsInProg :: Int -> String -> String -> IO [QName]
extractFormsInProg verb curryroot mname = do
extractFormsInProg verb curryroot mname =
lookupModuleSourceInLoadPath mname >>=
maybe (error $ "Module '" ++ mname ++ "' not found in load path!")
extractWithFormCache
where
extractWithFormCache (mdir,mfile) = do
let formfile = formCacheFile mdir mname
ffexists <- doesFileExist formfile
if not ffexists
then readFormsInProg verb curryroot mname formfile
else do
ctime <- getModificationTime mfile
ftime <- getModificationTime formfile
if ctime>ftime
then readFormsInProg verb curryroot mname formfile
else do
when (verb>1) $ putStrLn $ "Reading file '" ++ formfile ++ "'"
readFile formfile >>= return . read
readFormsInProg :: Int -> String -> String -> String -> IO [QName]
readFormsInProg verb curryroot mname formfile = do
unless (verb==0) $ putStrLn $
"Extracting and checking forms contained in module '" ++ mname ++ "'..."
when (verb>1) $ putStr $ "Reading module '" ++ mname ++ "'..."
......@@ -31,9 +57,12 @@ extractFormsInProg verb curryroot mname = do
unless (null privatenames) $ putStrLn $
"WARNING: Private form operations found (and not translated):\n" ++
unwords (map snd privatenames)
unless (verb==0) $ putStrLn $
unless (verb==0 || null formnames) $ putStrLn $
"Form operations found: " ++ unwords (map snd formnames)
unless (null formnames) $ checkFormIDsInProg verb curryroot mname formnames
when (verb>1) $ putStrLn $ "Writing form names to '" ++ formfile ++ "'"
-- store form names in form cache file:
catch (writeFile formfile (show formnames)) (const done)
return formnames
--- Extract public and private form definitions from a program.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment