Table of Contents
Command line programs often require some outputs to describe the program actions, or some file reading and writing operations which take no explicit place in the program return result. Such things are called side effects. They are not present in the pure functional languages, but can be of significant use in command line programs and scripts.
Some of the functions presented in Command Line Library produce side
effects. For example, the input
function and all
echo
functions. These functions are focused on the
communication, and side effects control is their secondary task. There
are two functions with a primary role of controlling the side effects:
return
and aside
.
Function / Type and Description
return
('1 * '2 -> '2)
Evaluate both arguments, dispose
the 1st result and return 2nd one.
aside
('1 * ('1 -> '2) -> '1)
Apply 2nd arg. to
1st, dispose result and return 1st arg:
aside(x,fn) == fn(x).return(x)
Function return
has two arguments. It evaluates both in
the given order, and returns the second one. The first one is assumed to
have a side effect role, and its value is discarded.
It may be missleading to consider this function in a usual form
return(x,y)
, because it is usually used in a different way.
It is designed to be used to provide a post-processing, or to finalize
some processing, which performed some side-effects. It is used, almost
exclusively, in the form ...exp... .return(y)
, where
expression ...exp...
is evaluated and discarded, and then
y
is evaluated and returned.
"Good morning!"
return( "Good afternoon!" ) .
Good afternoon!
The function return
is useful after a file writing,
directory traversing and some other side-effecting operations, when
there is no need to preserve or return the specific results. For
example, the following expression does some processing and then disposes
the current result and returns message “OK” as a confirmation that
program has finished:
... some processing ...echoTxt('--------\n')
.return( "OK" ) .
...whatever the processing output is...
--------
OK
"Good morning!"
echoLn()
.echoTxt( '-------------------\n' )
.return( "Good afternoon!" ) .
Good morning!
-------------------
Good afternoon!
Function return
is not always the best solution, because
it discards not only the result of the first argument but also may
discard an error report, so please use it with care.
Function aside
is similar to return
- it
evaluates two arguments in the given order, but then returns the first
one and discards the second one. It assumes that the current result is
still needed, but performs some intermediate processing. It is typically
used to create a report on the current progress or result state, like in
the following example:
"Good morning!"
aside(\x:
."Before saying: \"" + x + "\", bring a cup of coffee first!").echoLn()
( )
Before saying: "Good morning!", bring a cup of coffee first!
Good morning!
In some simple cases it is often sufficient (and better) to use
echo
functions (the echoFn
in the previous
example), but if the reporting includes a file creation or a database
update, then aside
is a much better solution.
Function aside
can be used to prepare some temporary
resources for the processing or to perform a cleaning after the
processing. For example, consider the following code:
... begin ...aside(\x: ... create some tmp files ... )
.
... processing ...aside(\x: ... delete tmp files ... )
. ... finalize ...
After discussing the list processing, now we have a broader picture of usual programming techniques in functional programming languages. The computation flow is implicitly controlled by some higher order functions and by the processed data itself. This approach is general and flexible enough to support solving virtually any problem. However, in some cases, the creation and handling of additional lists burdens the computation without real need.
This is why Wafl core library includes some so called iterative functions. Iterative functions are used as a tool for controlling the iterative computation, but based on integers and conditions, rather than on sequences.
Function / Type and Description
iterate
('1 * Int * Int * ('1 * Int -> '1) -> '1)
Left associative folding of specified integers range:
iterate(zero,2,4,fn) = fn(fn(fn(zero,2),3),4)
= zero.fn(2).fn(3).fn(4)
= (2..4).foldl(fn,zero)
iterateBy
('1 * Int * Int * Int * ('1 * Int -> '1) -> '1)
Left associative folding of specified integers range by step:
iterateBy(zero,2,6,2,fn) = fn(fn(fn(zero,2),4),6)
= zero.fn(2).fn(4).fn(6)
= [2,4,6].foldl(fn,zero)
repeatUntil
('1 * ('1 -> '1) * ('1 -> Bool) -> '1)
Repeat the function evaluation until the condition is reached:
repeatUntil(x,fn,cond) =
if cond(x) then x
else fn(x).repeatUntil(fn,cond)
Function iterate(zero,from,to,fn)
computes a left
associative folding of the specified integer range. It is functionally
equivalent to imperative for-loop, like the next one in C++:
auto result = zero;
for( int i=from; i<=to; i++ )
= fn( result, i );
result return result;
Function iterate(zero,from,to,fn)
is equivalent to
expression (from..to).foldl(fn,zero)
, but provides the
computation without creation of the list (from..to)
, so it
is more efficient. If the range is in the decreasing order, then the
negative step is used:
{#iterate( '#', 1, 10, \s,x: s + '-' + x.asString() ),
iterate( '#', 10, 1, \s,x: s + '-' + x.asString() ),
1..10).map(sum(1,_)),
(1..10).map(fact)
(
#}where {
sum(n,m) = iterate( 0, n, m, operator+ );
fact(n) = iterate( 1, 1, n, operator* );
}
{# '#-1-2-3-4-5-6-7-8-9-10', '#-10-9-8-7-6-5-4-3-2-1', [1, 3, 6, 10, 15, 21, 28, 36, 45, 55], [1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800] #}
Function iterateBy(zero,from,to,step,fn)
is a more
general form of the iterate
. When iterate
is
used, the step is always 1 or -1. With iterateBy
the step
may be any integer.
{#iterateBy( '#', 1, 10, 2, \s,x: s + '-' + x.asString() ),
iterateBy( '#', 10, 1, -3, \s,x: s + '-' + x.asString() )
#}
{# '#-1-3-5-7-9', '#-10-7-4-1' #}
Function repeatUntil(x,fn,cond)
provides the iteration
control based on the given condition. It repeats iterative
transformation of x
until the condition is met. Again, it
may be useful to describe that in imperative manner:
auto result = x;
while(!cond(c))
= fn(x);
x return x;
In the next example the given number is multiplied by itself until the result is greater or equal to 1000:
2..10).map( enlarge )
(where {
enlarge(n) = n.repeatUntil(
*(n,_),
operator>=(_,1000)
operator;
)}
[1024, 2187, 1024, 3125, 1296, 2401, 4096, 6561, 1000]
Function / Type and Description
fileRead
(String -> String)
Read complete file to a
string.
fileReadPart
(String * Int * Int -> String)
Read a part of
the file, from given 0-based position and with given length in bytes:
fileReadPart( fname, pos, bytelen )
fileSize
(String -> Int)
Returns the file size.
The fileRead(filepath)
function reads the file and
returns its contents as a string. The complete file is read, regardless
the size. This approach should not be used for very large files, due to
the high memory usage.
For very large files, the
fileReadPart(filepath,pos,bytelen)
function should be used.
It reads a file part, beginning form the given position (in bytes) and
of the given length.
To determine a file size, the fileSize(filepath)
function can be used.
fileRead( 'src/txt/en/title.md' )
# Wafl Tutorial
*Wafl* is a strongly typed functional programming language, with implicit type inference. It was initially designed as an experimental application of FP languages in Web development. However, few years later, Wafl became a simple and very fast scripting language, with a simple and efficient interface to databases.
Wafl Tutorial presents the language constructions, command line interpreter usage, elements of the core library and a lot of examples.
Welcome to *Wafl*!
*Saša Malkov*
fileReadPart( 'src/txt/en/title.md', 100, 100 )
inference. It was initially designed as an experimental application of FP languages in Web developme
fileSize( 'src/txt/en/title.md' )
516
Function / Type and Description
fileWrite
(String * String -> String)
Write string to a
file and truncate old content:
fileWrite( fname, content )
fileWriteAppend
(String * String -> String)
Write string to a
file by appending to the file end.
fileWriteAppend( fname, content )
fileWriteTo
(String * String -> String)
Write string to a
file and truncate old content:
fileWriteTo( content, fname )
fileWriteAppendTo
(String * String -> String)
Write string to a
file by appending to the file end.
fileWriteAppendTo( content, fname )
The function fileWrite(filename,s)
writes the given
string s
to the file and discards the old file contents, if
any. The fileWriteTo(s,filename)
does the same, only with
the changed order of the arguments. It is good to have both functions,
because of the dot-syntax.
The functions fileWriteAppend
and
fileWriteAppendTo
have the same arguments, but appends the
given string s
to the file end, and do not discard the
previous file contents.
Each of the functions returns the written string s
as a
result.
{#fileWrite( "tmp.txt", "One sentence. " ),
fileWrite( "tmp.txt", "Another sentence. " )
#}
{# 'One sentence. ', 'Another sentence. ' #}
fileRead( 'tmp.txt' )
Another sentence.
{#fileWrite( "tmp.txt", "One sentence. " ),
fileWriteAppend( "tmp.txt", "Another sentence. " )
#}
{# 'One sentence. ', 'Another sentence. ' #}
fileRead( 'tmp.txt' )
One sentence. Another sentence.
Function / Type and Description
fileExists
(String -> Bool)
Check if exists a file with the
given name.
fileOrDirExists
(String -> Bool)
Check if exists a file or a
directory with the given name.
fileDelete
(String -> Bool)
Delete a file.
fileNewTempName
( -> String)
Get a new temporary file name.
The functions fileExists
and
fileOrDirExists
check and return if there is a file or
directory with the given name.
The fileExists
checks only the files and if it returns
true
, then there is a file with the given name. It can be
used to check before reading or deleting a file.
{#fileExists( 'tmp.txt' ),
fileExists( 'tmp2.txt' ),
fileDelete( 'tmp.txt' ),
fileExists( 'tmp.txt' )
#}
{# true, false, true, false #}
The fileOrDirExists
checks only both the files and
directories and if it returns true
, then there is a file or
a directory with the given name. It can be used to check before creating
a file or a directory.
The function fileNewTempName()
returns a candidate name
for a new temporary file. The filename is located in the temporary files
directory, which depends on the platform.
Function / Type and Description
dirCreate
(String -> Bool)
Create a directory.
dirDelete
(String -> Bool)
Delete a directory, if it is
empty
dirExists
(String -> Bool)
Check if exists a directory
with the given name.
dirFiles
(String -> List[String])
Creates a list of all
files satisfying the given filter.
dirSubdirs
(String -> List[String])
Creates a list of all
subdirectories satisfying the given filter.
The functions dirFiles(filter)
and
dirSubdirs(filter)
return lists of files and directories
that satisfy the given filter. Returned paths are relative to the
working directory.
"Directories:\n "
+ dirSubdirs( '*' ).strJoin('\n ')
+ "\nFiles:\n "
+ dirFiles( '*' ).strJoin('\n ')
Directories:
.vscode
bld
code
design
resources
src
Files:
bldall.cmd
bldsite.cmd
pandocHtml.cmd
pandocPdf.cmd
prepmd.cmd
site.cmd
test.wafl
todo.notes.txt
Tutorial - Site Version.lnk
Tutorial - Standalone Version.lnk
WaflTutorial.md
The function dirExists
is similar to
fileExists
and fileOrDirExists
, but it checks
only if a directory exists with the specified name. It can be used
before creating, deleting or traversing a directory.
Regex support in Wafl uses ECMAScript regular expressions syntax, as defined and implemented in C++ standard library from C++11.
By default, all quantifiers are greedy (they take as many characters as possible). This can be overridden to ungreedy (to take as few characters as possible) by adding a question mark (?) after the quantifier.
Function / Type and Description
regexMatch
(String * String -> Bool)
Check if a string
matches given regular expression.
regexMatchI
(String * String -> Bool)
Check if a string
matches given regular expression. Ignore letter case.
Regex matching functions regexMatch(s,r)
and
regexMatchI(s,r)
check if the given string s
matches the given regular expression r
. The matching is
performed on the whole string s
.
{#regexMatch("ab.*AB"),
s.regexMatch(".*ab.*AB.*"),
s.regexMatch(".*ab.*cd.*"),
s.regexMatch(".*AB.*ab.*"),
s.regexMatchI(".*AB.*ab.*")
s.
#}where {
s = "abcabcABCABC";
}
{# false, true, false, false, true #}
Function / Type and Description
regexPos
(String * String -> Int)
Find the first regex
matching position in the given string.
regexPosI
(String * String -> Int)
Find the first regex
matching position in the given string. Ignore case.
regexPosAll
(String * String -> List[Int])
Find all regex
matching positions in the given string.
regexPosAllI
(String * String -> List[Int])
Find all regex
matching positions in the given string. Ignore case.
Regex functions regexPos(s,r)
and
regexPosI(s,r)
look for the first position of a substring
of the given string s
that matches the given regular
expression r
.
{#regexPos("ab.*AB"),
s.regexPos("ab.*cd"),
s.regexPos("AB.*ab"),
s.regexPosI("AB.*ab")
s.
#}where {
s = "abcabcABCABC";
}
{# 0, -1, -1, 0 #}
Regex functions regexPosAll(s,r)
and
regexPosAllI(s,r)
look for the starting positions of all
substrings of the given string s
that match the given
regular expression r
.
{#regexPosAll("ab.*AB"),
s.regexPosAll("ab.*cd"),
s.regexPosAll("AB.*ab"),
s.regexPosAllI("AB.*ab"),
s.regexPosAllI("AB.*?ab"),
s.regexPosAllI("a.*c"),
s.regexPosAllI("a.*?c")
s.
#}where {
s = "abcabcABCABC";
}
{# [0], [], [], [0], [0, 6], [0], [0, 3, 6, 9] #}
Function / Type and Description
regexReplace
(String * String * String -> String)
Replace all
matching of a regex with the given string.
regexReplaceI
(String * String * String -> String)
Replace all
matching of a regex with the given string. Ignore case.
Regex functions regexReplace(s,r,x)
and
regexReplaceI(s,r,x)
look for the positions of all
substrings that match the given regular expression r
, and
replace them with the given string x
.
{#regexReplace("ab.*AB", "#"),
s.regexReplace("ab.*?AB", "#"),
s.regexReplace("ab.*cd", "#"),
s.regexReplace("AB.*ab", "#"),
s.regexReplaceI("AB.*ab", "#"),
s.regexReplaceI("AB.*?ab", "#"),
s.regexReplaceI("a.*c", "#"),
s.regexReplaceI("a.*?c", "#")
s.
#}where {
s = "abcabcABCABC";
}
{# '#C', '#CABC', 'abcabcABCABC', 'abcabcABCABC', '#C', '#c#C', '#', '####' #}
Function / Type and Description
regexSearch
(String * String -> List[String])
Search for the
regex matching in the given string.
regexSearchI
(String * String -> List[String])
Search for the
regex matching in the given string. Ignore letter case.
regexSearchAll
(String * String -> List[List[String]])
Search
for all regex matchings in the given string.
regexSearchAllI
(String * String -> List[List[String]])
Search
for all regex matchings in the given string. Ignore letter case.
Regex search functions regexSearch(s,r)
and
regexSearchI(s,r)
look for the first substrings of the
given string s
that matches the given regular expression
r
, and return all matched sub-elements. The returned value
is a list of strings. The first element is the complete matched
substring, and the following elements correspond to the regular
expression sub-patterns.
The following example searches for patterns
<name>=<n>
:
{#regexSearch("([a-z]+)\\s*=\\s*([0-9]+)")
s.
#}where {
s = "a=12 ;bcd = 24; ef =354";
}
{# ['a=12', 'a', '12'] #}
The first element of the returned list is the first matched
substring. The second element is the corresponding name
part, and the third one is the corresponding n
part of the
matched substring.
The functions regexSearchAll
and
regexSearchAllI
do the same thing, but for all matching
substrings. Thus, the result is not single list, but a list of the
string lists - a list for each matched substring:
{#regexSearchAll("([a-z]+)\\s*=\\s*([0-9]+)")
s.
#}where {
s = "a=12 ;bcd = 24; ef =354";
}
{# [['a=12', 'a', '12'], ['bcd = 24', 'bcd', '24'], ['ef =354', 'ef', '354']] #}
Functions for command line support are specific for command line Wafl interpreter. They are usually not available in other versions. The main purpose is to support the terminal read and write operations.
Command line program interpreter supports the command line program arguments. There are some functions and special operator for working with command line arguments:
Function / Type and Description
$*
List[String]
List of command line arguments.
$#
Int
A number of command line arguments.
$ A
(Int -> String)
Return a command line argument:
$1 = cmdLineArgs()[1]
cmdLineArgs
( -> List[String])
Return a list of command line
arguments.
cmdLineArgsCount
( -> Int)
Return a number of command line
arguments.
The ‘$*
’ constant is used to get the list of all command
line arguments. The synonym, in a form of a function, is the function
cmdLineArgs()
. For example, if a program is started using
the following command:
clwafl program.wafl a b c "abcde"
Both $*
and cmdLineArgs()
will return:
['program.wafl', 'a', 'b', 'c', 'abcde']
The number of argument can be computed as the size of the command
line arguments list (size($*)
) or by using the constant
$#
, or its synonym function
cmdLineArgsCount()
.
Command line programs return an integer code to the caller (operating system or an application). If everything is ok, console programs are expected to return zero. In case of an error, programs return some program specific positive values.
Function cmdSetExitCode(s,code)
sets the program exit
code to the given code
and returns s
.
Function / Type and Description
cmdSetExitCode
('1 * Int -> '1)
Set program exit code to second
argument and return the first one.
if $# > 1
then $1
else "No argument" .cmdSetExitCode(1)
No argument
Command line output is handled by echo functions.
Function / Type and Description
echo
('1 -> '1)
Write the argument’s string
representation to the console and return the argument:
echo(x) == echoTxt( x, x.asString() )
echoLn
('1 -> '1)
Write the argument’s string
representation and new line to the console and return the argument:
echoLn(x) == echoTxt( x, x.asString() + '\n' )
echoTxt
('1 * String -> '1)
Write the second argument to
the console and return the first argument.
echoFn
('1 * ('1 -> String) -> '1)
Apply the
function to the 1st arg. and write the result to the console:
echoFn( x, fn ) == echoTxt( x, fn(x) )
Each of the echo functions outputs something to standard console output and returns its first argument.
The echo(x)
function outputs the given value
x
converted to a string, and returns the original value
x
. The echoLn(x)
does the similar, but outputs
a new line symbol at the end.
"This is a string"
echo()
.echoLn() .
This is a stringThis is a string
This is a string
The functions echoTxt
and echoFn
write some
other strings to the command line output, but return the first argument
in the same way as echo
and echoLn
. The
echoTxt(x,s)
writes s
and returns
x
. The echoFn(x,fn)
writes fn(x)
and returns x
:
"This is a string"
echoTxt("Output from echoTxt\n")
.echoFn(\x: 'Output "' + x + '" from echoFn\n' ) .
Output from echoTxt
Output "This is a string" from echoFn
This is a string
Function / Type and Description
input
(String -> String)
Write a string to the
console, wait for input and return it.
The input(s)
function writes the given string
s
to the command line output, waits for the user to enter a
line to the console, and returns the entered string.
"Hello "
+ input( "What is your name? " )
+ "!"
What is your name? Marvin Hello Marvin!
Function / Type and Description
cmdExecute
(String -> String)
Execute the command in the
active console and return the result.
cmdShellExecute
(String -> String)
Open new shell, execute the
command in it and return the result.
cmdLastError
( -> Int)
Get integer code of last command
status.
The functions cmdExecute(cmd)
and
cmdShellExecute(cmd)
execute the given shell command string
and return the results. The difference between the two is that
cmdExecute
uses the current shell, while
cmdShellExecute
opens a new shell. In some cases they may
return different results, depending on the shell and specific
commands.
The function cmdLastError()
returns the exit code of the
last executed shell command. As usual, if everything is ok, it returns
zero.
Wafl library HTTP and Web functions are organized in two parts:
Function / Type and Description
httpGetSize
(String -> Int)
Get WWW content length using
HTTP/HTTPS HEADER method.
httpGet
(String -> String)
Get WWW content using
HTTP/HTTPS GET method.
httpGet_callback
(String * (Int * Int -> Int) -> String)
Get
WWW content using HTTP/HTTPS GET method, with progress callback
The httpGet(uri)
function sends a GET
HTTP
request with a given uri
, waits for a response and returns
the response content. It can be used for both HTTP and HTTPS
requests.
httpGet( 'http://www.informatics.rs/~smalkov/wafl/index.html' )
size() .
0
The httpGetSize(uri)
function sends a
HEADER
HTTP request with a given uri
, waits
for a response and returns the reported response content size. It can be
used for both HTTP and HTTPS requests. If a server does not react on
HEADER request, the function returns -1. If a server reacts on the
request but returns an invalid header or a header with no content size
data, the function returns -2.
httpGetSize( 'http://www.informatics.rs/~smalkov/wafl/index.html' )
-1
The httpGet_callback(uri,fn)
function sends a
GET
HTTP request with a given uri
, uses the
fn
function of type (Int * Int -> Int)
to
handle intermediate callbacks, waits for a response and returns the
reported response content. The result value should be the same as in the
case of the httpGet
. The fn(received,expected)
can perform some intermediate processing, like progress reporting. The
received
argument is the count of the total received bytes,
and expected
argument is the count of the total expected
bytes. The expected
should be the same as the result of the
httpGetSize(uri)
, and can be a negative value if the server
does not provide the expected size.
httpGet_callback(
'http://www.informatics.rs/~smalkov/wafl/index.html',
\r,t: t.echoTxt( r.asString() + ' / ' + t.asString() + '\n')
)size() .
0
httpGet_callback(
'http://poincare.matf.bg.ac.rs/~smalkov/images/h2.png',
\r,t: t.echoTxt( r.asString() + ' / ' + t.asString() + '\n')
)size() .
1161 / 7024
5397 / 7024
7024 / 7024
7024
Function / Type and Description
Form
( -> Map[String][String])
Get form variable
set.
FormValue
(String -> String)
Get value of a given form
variable.
Session
( -> Map[String][String])
Get session variable
set.
SessionValue
(String -> String)
Get value of a given session
variable.
Service
( -> Map[String][String])
Get service variable
set.
ServiceValue
(String -> String)
Get value of a given service
variable.
The functions Form()
, Session()
and
Service()
return the corresponding web variable sets - the
current form content received from a client, the current set of session
variables and the current service configuration. The functions
FormValue(varname)
, SessionValue(varname)
and
ServiceValue(varname)
return the value of a variable with
the given variable name.
Function / Type and Description
httpHost
( -> String)
Get HTTP host for current
request.
httpPathInfo
( -> String)
Get HTTP path info for current
request.
httpScript
( -> String)
Get HTTP script for current
request.
The functions httpHost()
, httpPathInfo()
and httpScript()
return the corresponding parts of the
currently processed URI.
Function / Type and Description
ask
(String -> Map[String][String])
Ask a question
by sending the given page content to the client. Returns the next
client’s request.
answerAction
( -> String)
Automatic action URI generator for
forms in questions.
The functions ask(pageContent)
sends the given page
content to the client and waits for the returned answer. All the links
and the form actions on the page, that begin with a relative link
generated by answerAction()
, will represent the alternative
answers for the given page and will return to this specific
function. The answerAction()
will return a result that
identifies the specific current program evaluation, so the program may
be continued after an appropriate answer is received from the
client.
Wafl has two functions for exporting Wafl values to JSON.
Function / Type and Description
toJSON
('1 -> String)
Converts a value to a string in
JSON format.
toFmtJSON
('1 -> String)
Converts a value to a string in
pretty JSON format.
Both functions are applicable to any Wafl value type. Function
toJSON(x)
converts the value x
to JSON format
in as compact form as possible. This is nice if the exported string has
to be processed by a machine.
Function toFmtJSON(x)
is essentially doing the same
thing, but it exports the value in a nicer formatted JSON format. This
is better if the exported string has to be processed by humans.
1..5).map(\n:{
(: n,
n: 's'+n$,
s: {# n, 's'+n$ #}
t
}) .toJSON()
[{'n':1,'s':'s1','t':[1,'s1']},{'n':2,'s':'s2','t':[2,'s2']},{'n':3,'s':'s3','t':[3,'s3']},{'n':4,'s':'s4','t':[4,'s4']},{'n':5,'s':'s5','t':[5,'s5']}]
1..5).map(\n:{
(: n,
n: 's'+n$,
s: {# n, 's'+n$ #}
t
}) .toFmtJSON()
[ {
'n': 1,
's': 's1',
't': [
1,
's1'
]
}, {
'n': 2,
's': 's2',
't': [
2,
's2'
]
}, {
'n': 3,
's': 's3',
't': [
3,
's3'
]
}, {
'n': 4,
's': 's4',
't': [
4,
's4'
]
}, {
'n': 5,
's': 's5',
't': [
5,
's5'
]
} ]
Function / Type and Description
cmdWafl
(String * List[String] -> String)
Run Wafl
program file in a command line shell with given arguments and returns
the result. All arguments are passed to Wafl program. No arguments apply
to interpreter. The output is redirected to the caller’s output
stream.
cmdWaflSrc
(String * List[String] -> String)
Run Wafl
program source in a command line shell with given arguments and returns
the result. All arguments are passed to Wafl program. No arguments apply
to interpreter. The output is redirected to the caller’s output
stream.
cmdWaflX
(String * RecordX[]['1] -> String)
Run Wafl
program file in a command line shell with given options and returns the
result. Options are specified as a record fields:
cmdLineArgs - the list of command line arguments to pass
to the program (List[String]);
coutFile - the full filename of the output redirection file;
if '*null*' is specified, output is discarded;
if empty string is specified (default),
the caller's output stream is used .
These functions do the evaluation of Wafl programs. The
cmdWafl(prgpath,args)
evaluates a Wafl program in the given
file. The cmdWaflSrc(src,args)
evaluates the Wafl program
written in the string. Both function send the given arguments as command
line arguments to the evaluated program, and return the programs output
and result as a return value.
cmdWaflSrc('2+3',[])
5
"A controlled error:\n"
+ cmdWaflSrc( 'an error',[])
A controlled error:
--- Loading from command line
Parser error
Unexpected text at the end of the file! [err 1201:6]
Line 1: an error
___/
--- End loading from command line
Each Wafl program evaluation is performed in a separate evaluation environment but in the same process. That means that the most of the errors will not propagate to the caller-program, but if the memory usage becomes too high or the process fails, then it will have consequences on the caller-program.
It is even possible that such an evaluated program evaluates another Wafl program:
cmdWaflSrc( 'cmdWaflSrc("2+3",[])',[])
5