Commit 09927427 authored by Michael Hanus's avatar Michael Hanus
Browse files

currypp restructured

parent ef3f1a84
This directory contains some documention for the Curry preprocessor:
manual.tex:
A short description to be included in the main manual of the Curry system.
\section{CurryPP: A Preprocessor for Curry Programs}
The Curry preprocessor \ccode{currypp}
\index{Curry preprocessor}\index{preprocessor}
implements
various transformations on Curry source programs.
It supports some experimental language extensions
that might become part of the standard parser of Curry
in some future version.
Currently, the Curry preprocessor
supports the following extensions that will be described below in more detail:
\begin{description}
\item[Integrated code:]
This extension allows to integrate
code written in some other language into Curry programs,
like regular expressions, format specifications (\ccode{printf}),
HTML and XML code.
\item[Sequential rules:]
If this feature is used, all rules in a Curry module are
interpreted as sequential, i.e., a rule is only applied
if all previous rules defining the same operation are not applicable.
The idea of sequential rules are described in \cite{AntoyHanus14}.
\item[Default rules:]
If this feature is used, one can add a default rule
to operations defined in a Curry module.
This provides a similar power than sequential rules
but with a better operational behavior.
The idea of default rules are described in \cite{AntoyHanus16PADL}.
\end{description}
The preprocessor is an executable named \ccode{currypp},
which is stored in the directory \code{\cyshome/bin}.
In order to apply the preprocessor when loading a Curry source
program into \CYS, one has to add an option line
at the beginning of the source program.
For instance, in order to use default rules in a Curry program,
one has to put the line
\begin{curry}
{-# OPTIONS_CYMAKE -F --pgmF=currypp --optF=defaultrules #-}
\end{curry}
at the beginning of the program.
This option tells the \CYS front end to process the Curry source program
with \code{currypp} before actually parsing the source text.
The option \ccode{defaultrules} has to be replaced by
\ccode{seqrules} if the sequential rule matching should be replaced.
To support integrated code, one has to set the option
\ccode{foreigncode} (which can also be combined with
either \ccode{defaultrules} or \ccode{seqrules}.
If one wants to see the result of the transformation, one can
also set the option \ccode{-o}. This has the effect that the
transformed source program is stored in the file
\code{Prog.curry.CURRYPP} if the name of the original program
is \code{Prog.curry}.
For instance, in order to use integrated code and default rules
in a module and store the transformed program,
one has to put the line
\begin{curry}
{-# OPTIONS_CYMAKE -F --pgmF=currypp --optF=foreigncode --optF=defaultrules --optF=-o #-}
\end{curry}
at the beginning of the program.
\subsection{Integrated Code}
Integrated code is enclosed in at least two back ticks and ticks
in a Curry program. The number of starting back ticks and ending ticks
must be always identical.
After the initial back ticks, there must be an identifier
specifying the kind of integrated code,
e.g., \code{regexp} or \code{html} (see below).
For instance, if one uses regular expressions (see below for more details),
the following expressions are valid in source programs:
\begin{curry}
s ``regex (a|(bc*))+''
s ````regex aba*c''''
\end{curry}
The Curry preprocessor transforms these code pieces into regular
Curry expressions. The next sections describe the currently
supported foreign languages.
\subsubsection{Regular Expressions}
TODO
\subsubsection{Format Specifications}
TODO
\subsubsection{HTML Code}
TODO
\subsubsection{XML Expressions}
TODO
\subsection{Sequential Rules}
TODO
\subsection{Default Rules}
TODO
% LocalWords: preprocessor
{-# OPTIONS_CYMAKE -F --pgmF=currypp --optF=--foreigncode #-}
{-# OPTIONS_CYMAKE -F --pgmF=currypp --optF=foreigncode #-}
------------------------------------------------------------------------------
--- This program contains some examples for integrated code to support
--- regular expression matching.
--- The syntax of regular expression is similar to
--- The syntax of regular expressions is similar to
--- POSIX extended regular expressions
------------------------------------------------------------------------------
......
#!/bin/sh
# script to test the current set of test examples
CURRYBIN="../../../../bin"
# use the right Curry system for the tests:
PATH=$CURRYBIN:$PATH
export PATH
# test for basic language features
ALLTESTS="testFormat"
# clean up before
$CURRYBIN/cleancurry
# execute all unit tests:
echo "Executing unit tests for Curry code integrator..."
$CURRYBIN/currytest test*.curry
{-# OPTIONS_CYMAKE -F --pgmF=currypp --optF=foreigncode #-}
------------------------------------------------------------------------------
--- This program contains some tests for integrated code to format strings.
---
--- The format specification C specification for `printf` formatting.
--- This specification may be found at
--- <http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html>
------------------------------------------------------------------------------
import Assertion
import Format -- required in the pre-processed program
-- Format a string and an integer:
ex1 :: String -> Int -> String
ex1 name age = ``format "Hello %s. Age %i!",name,age''
test1 = assertEqual "ex1" (ex1 "World" 42) "Hello World. Age 42!"
-- Various integer formats:
test2 = assertEqual "intsigned" ``format "%+i",42'' "+42"
test3 = assertEqual "int5" ``format "%.5i",42'' "00042"
test4 = assertEqual "intsigned5" ``format "%+.5d",42'' "+00042"
test5 = assertEqual "intfixedsigned5" ``format "%+10.5i",42'' " +00042"
-- Integer and character formatting:
test6 = assertEqual "intfixedsignedchar"
(let c='%' in ``format "%+5d%c",42,c'')
" +42%"
-- Format a string with a given width and maximal length:
test7 = assertEqual "stringlength"
(let s = "Hello!" in ``format "This is a string: %08.4s",s'')
"This is a string: Hell"
-- Format with passing expressions:
ex8 :: Int -> Int -> String
ex8 n1 n2 = ``format "The sum of %+.5d and %+5i is %+6i.\n",n1,n2,n1+n2''
test9 = assertEqual "intexp" (ex8 42 2143)
"The sum of +00042 and +2143 is +2185.\n"
-- Format a float with a given width and precision:
test10 = assertEqual "floatfixprec3"
(let f = 3.14159 in ``format "%+8.3f",f'')
" +3.142"
-- Format a float with an exponent:
test11 = assertEqual "floatexp"
(let f = 314.159 in ``format "% .4E",f'')
" 3.1416E+02"
{-# OPTIONS_CYMAKE -F --pgmF=currypp --optF=foreigncode #-}
------------------------------------------------------------------------------
--- This program contains tests for integrated code to support
--- easy writing of HTML code in Curry programs.
------------------------------------------------------------------------------
import Assertion
import HTML
htmlTest1 :: String -> [HtmlExp]
htmlTest1 name = ``html
<html>
<head>
<title>Simple Test
<body>
<h1>Hello {name}!</h1>
<p>
Bye!
<p>Bye!
<h2>{reverse name}
Bye!''
htmlDoc1 :: [HtmlExp]
htmlDoc1 =
[HtmlStruct "html" []
[HtmlStruct "head" []
[HtmlStruct "title" [] [HtmlText "Simple Test\n"]],
HtmlStruct "body" []
[HtmlStruct "h1" []
[HtmlText "Hello ", HtmlText "Joe", HtmlText "!"],
HtmlStruct "p" [] [HtmlText "Bye!\n"],
HtmlStruct "p" [] [HtmlText "Bye!\n"],
HtmlStruct "h2" []
[HtmlText "eoJ", HtmlText "\n"],
HtmlText "Bye!"]]]
test1 = assertEqual "Html code" (htmlTest1 "Joe") htmlDoc1
{-# OPTIONS_CYMAKE -F --pgmF=currypp --optF=foreigncode #-}
------------------------------------------------------------------------------
--- This program contains some tests for integrated code to support
--- regular expression matching.
--- The syntax of regular expressions is similar to
--- POSIX extended regular expressions
------------------------------------------------------------------------------
import Assertion
import RegExp -- required in the pre-processed program
test1 = assertTrue "abc" ("abc" ``regex abc'')
test2 = assertTrue "aba*c" ("abaaaaaaaaaaaaac" ````regex aba*c'''')
test3 = assertTrue "(a|(bc*))+" ("aabcccaba" ``regex (a|(bc*))+'')
test4 = assertTrue "[:alpha:] 1" ("a" ``regex [:alpha:]'')
test5 = assertTrue "[:alpha:] 2" (not ("4" ``regex [:alpha:]''))
test6 = assertTrue "[:alpha:]* 1" ("Abc" ``regex [:alpha:]*'')
test7 = assertTrue "[:alpha:]* 2" (not ("ab9c" ``regex [:alpha:]*''))
test8 = assertTrue "[a-z]+ 1" ("abc" ``regex [a-z]+'')
test9 = assertTrue "[a-z]+ 2" (not ("Abc" ``regex [a-z]+''))
-- Examples with parameterized regular expressions:
pregexp1 :: [a] -> a -> a -> Bool
pregexp1 s v1 v2 = s ``regex [<v1>-<v2>]*''
test10 = assertTrue "para a-c 1" (pregexp1 "abccba" 'a' 'c')
test11 = assertTrue "para a-c 2" (not (pregexp1 "abcdcba" 'a' 'c'))
pregexp2 :: [a] -> a -> a -> Bool
pregexp2 s v1 v2 = s ``regex (<v1>|<v2>)*''
test12 = assertTrue "para (0|1)* 1" (pregexp2 [0,1,1,0,0] 0 1)
test13 = assertTrue "para (0|1)* 2" (not (pregexp2 [0,1,2,0,0] 0 1))
-- A regular expression containing a complex Curry expression:
test14 = assertTrue "complexexp" ("a" ``regex <((\x -\> x) 'a')>'')
-- Email address matching:
isEmail :: String -> Bool
isEmail s = s ``regex
[a-zA-Z0-9]([a-zA-Z0-9\._])*
@
[a-zA-Z0-9][a-zA-Z0-9\-]*\.
([:alnum:][a-zA-Z0-9\-]*\.)*
[a-zA-Z]{2,4}''
test20 = assertTrue "Email1" (isEmail "pakcs@curry-language.org")
test21 = assertTrue "Email2" (not (isEmail "pa%kcs@curry-language.org"))
Supports Markdown
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