How to for-loop in MOE SVL function? - moe-svl

In MOE SVL, I keep trying to create a basic for-loop by following the Control Flow documentation:
#svl
global function main []
for a = 10, 6, -1 loop
pr a;
endloop
endfunction
When I run the script:
moebatch -load for_loop.svl -exec "main[]"
I get the error:
ERROR: failed to load '/home/sean/svl_test/for_loop.svl'
'/home/sean/svl_test/for_loop.svl' line 5: 'a' is undefined
Error evaluating expression 'main[]'
'main' is undefined
How am I supposed to define a in the loop?

When executing commands from the SVL REPL you don't need to declare variables. Therefore, when writing a loop in the prompt like this:
for a = 10, 6, -1 loop pr a; endloop
The interpreter does not complain. If you write the same loop in a function within a script however, each variable needs to be declare first. The declaration can be inside the loop but must be before its first reference:
#svl
local function main []
local a;
for a = 10, 6, -1 loop
local b = 2;
pr [a, a-b];
endloop
endfunction
When you write a script in SVL there are two types of scripts:
Load scripts
These are scripts you load to extent the available functions within MOE. All functions declared as global can be called either from the REPL or within other functions in other scripts. For example if you write a script called add3script.svl like this:
#svl
global function add3 [a,b,c]
return a + b + c;
endfunction
You can load this functions into MOE (GUI or moebatch) and call it. To use it in moebatch directly you can do:
moebatch -load add3script.svl -exec "pr add3[1,2,3]"
This command will lunch the terminal version of MOE, load the SVL script add3script.svl which makes the add3 function available because it is set to global. Then we execute the command pr add3[1,2,3] which prints 6 and then moebatch quits. You can also launch moebatch to bring up the REPL and load the script:
moebatch -load add3script.svl
On the REPL the add3 function is now available. To load a script in the GUI version of MOE you can click MOE | File | Open then navigate to the add3script.svl and choose from the 'Action' dropdown on the File/Open panel 'Load SVL File'. Then click OK. Now add3 is available in the SVL command prompt in the GUI version of MOE.
An SVL script can contain multiple global and local functions but when loaded only the global functions can be used from outside the script. For example if we change add3script.svl to this:
#svl
local function printResult value
pr value;
endfunction
global function add3 [a,b,c]
printResult [a + b + c];
endfunction
global function mul3 [a,b,c]
printResult [a * b * c];
endfunction
You can use add3 and mul3 when loaded like mentioned above but printResult can only be called from within add3script.svl.
Run scripts
Instead of loading a script to make its functions available to use outside the script a script can be also be executed (or run). This allows to execute for example a workflow which is self contained within the script. This could be useful to write a GUI application. By default when an SVL script is executed as a run file the interpreter looks for a function called main and executes its instructions (helloworld.svl):
#svl
local function main []
pr 'Hello World!';
endfunction
This script could be executed from the terminal like this:
moebatch -run helloworld.svl
This prints 'Hello World!' and terminates. If another function then main should be executed a special instruction can be added:
#svl
#set main 'altmain'
local function gettext []
return 'Alt main text';
endfunction
local function altmain []
pr gettext[];
endfunction
local function main []
pr 'Hello World!';
endfunction
If you run this script it will print 'Alt main text' since the main function is set to altmain which calls the local function gettext.
To run such functions within GUI MOE you can simply double click on the SVL script.

It is not possible to define a in the loop declaration, as one might expect from C++ or Python. Instead, a local variable must be defined before the loop can be executed:
#svl
global function main []
local a;
for a = 10, 6, -1 loop
pr a;
endloop
endfunction
This is counter-intuitive, because loop code in the documentation does not do this, because it is only inside of functions that variables must be declared before usage. In the global scope, for example when executing code in the MOE SVL REPL, the looping variable does not need to be declared beforehand.

Related

Start a child process in COBOL

How to start a child process in GnuCOBOL?
In Node.js, we can use either spawn or exec to start child processes:
var proc = require("child_process").spawn("ls", ["-l"]);
proc.stdout.on("data", function (chunk) {
console.log(chunk);
});
// or
var proc = require("child_process").exec("ls -l"], function (err, stdout, stderr) {
...
});
Both of the examples above run ls -l (list the files and directories). How can the same thing be achieved in COBOL?
Use a common COBOL extension which is supported since years in GnuCOBOL (formerly OpenCOBOL), too:
CALL 'SYSTEM' USING whatever END-CALL
This works with 'cobcrun', too and can be useful if you need a COBOL process with a separate environment (EXTERNAL items, ACCEPT x FROM y / SET ENVIRONMENT y TO x) or runtime configuration (for example via cobcrun -c different.cfg OTHERMAIN).
Your original sample may look like (without the option to use pipes which would be a different question):
CALL 'SYSTEM' USING 'ls -l >dirlist'
ON EXCEPTION
CALL 'SYSTEM' USING 'dir >dirlist'
END-CALL
END-CALL
Afterwards you can read the dirlist as a normal line sequential file.
Simon
BTW: Given your sample you may look for CALL 'C$LISTDIR'.

add output of a script to a number in lua

I have a shell script in Linux which outputs 10.
I want to write a script in lua, which adds 5 to my output of shell script. How can I use output of my shell script?
This is what I have tried -
print(5 + tonumber(os.execute('./sample')))
This is the output -
10
lua: temp.lua:2: bad argument #2 to 'tonumber' (number expected, got string)
stack traceback:
[C]: in function 'tonumber'
temp.lua:2: in main chunk
[C]: in ?
As #Etan Reisner said, os.execute is returning multiple values, however, the exit code is not the first return value. Therefore, you'll have to stuff the values into variables:
local ok, reason, exitcode = os.execute("./sample")
if ok and reason == "exit" then
print(5 + exitcode)
else
-- The process failed or was terminated by a signal
end
By the way, if you want to return the new value as exit code, you can do so using os.exit:
os.exit(5 + exitcode)
Edit: As you have clarified via a comment, you are looking to read the output (stdout) of the process, not its return value. In this case, io.popen is the function you need:
local file = io.popen("./sample")
local value = file:read("*a")
print(5 + tonumber(value))
Note, however, that io.popen is not available on every plattform

Call a function on terminating/exiting a lua script (an atexit()/cleaning function)

Question: Is there a way to call a function when the lua script is terminated by either the system or a program which has started the script (e.g. a C program)? An atexit()/cleaning function for lua.
The situation: a external C program (call it PROG) manages a lua script (call it SCRIPT) and calls its functions, the lua script uses a separated library (.so, cal it LIB) which reserves resources which should be freed when the lua script exits. The lua script is managed (and thus terminated) by PROG which i can not alter. SCRIPT should notify LIB when it is terminated.
How can this be done?
Note: i'm fairly new to lua so please also explain your answer, much appreciated :)
I'm on Linux using Lua 5.3.1
Currently this seem to work:
a = {__gc = function() print'exit function from LIB called' end}
setmetatable(a,a)
Check out http://lua-users.org/lists/lua-l/2001-08/msg00265.html
You may need to run lua_runprotected call to prevent a stack under flow problem.

Assign bash output to variable in .lua script

I would like to assign output of a bash command to a variable in .lua script. Is it possible?
For instance, something similar to:
var = `ps uax | grep myprocess`
Yes, you need to use io.popen for this.
io.popen (prog [, mode])
Starts program prog in a separated process and returns a file handle that you can use to read data from this program (if mode is "r", the default) or to write data to this program (if mode is "w").
This function is system dependent and is not available on all platforms.
Also see How to execute an external command?.
io.popen calls a command but returns a file object so you can read the output of the command, if the second argument is 'r', but you can also pass input to a command with a second argument of 'w'. Unfortunately, you don't get a io.popen2, and you don't get the return code.

Getting return status AND program output

I need to use Lua to run a binary program that may write something in its stdout and also returns a status code (also known as "exit status").
I searched the web and couldn't find something that does what I need. However I found out that in Lua:
os.execute() returns the status code
io.popen() returns a file handler that can be used to read process output
However I need both. Writing a wrapper function that runs both functions behind the scene is not an option because of process overhead and possibly changes in result on consecutive runs. I need to write a function like this:
function run(binpath)
...
return output,exitcode
end
Does anyone has an idea how this problem can be solved?
PS. the target system rung Linux.
With Lua 5.2 I can do the following and it works
-- This will open the file
local file = io.popen('dmesg')
-- This will read all of the output, as always
local output = file:read('*all')
-- This will get a table with some return stuff
-- rc[1] will be true, false or nil
-- rc[3] will be the signal
local rc = {file:close()}
I hope this helps!
I can't use Lua 5.2, I use this helper function.
function execute_command(command)
local tmpfile = '/tmp/lua_execute_tmp_file'
local exit = os.execute(command .. ' > ' .. tmpfile .. ' 2> ' .. tmpfile .. '.err')
local stdout_file = io.open(tmpfile)
local stdout = stdout_file:read("*all")
local stderr_file = io.open(tmpfile .. '.err')
local stderr = stderr_file:read("*all")
stdout_file:close()
stderr_file:close()
return exit, stdout, stderr
end
This is how I do it.
local process = io.popen('command; echo $?') -- echo return code of last run command
local lastline
for line in process:lines() do
lastline = line
end
print(lastline) -- the return code is the last line of output
If the last line has fixed length you can read it directly using file:seek("end", -offset), offset should be the length of the last line in bytes.
This functionality is provided in C by pclose.
Upon successful return, pclose() shall return the termination status
of the command language interpreter.
The interpreter returns the termination status of its child.
But Lua doesn't do this right (io.close always returns true). I haven't dug into these threads but some people are complaining about this brain damage.
http://lua-users.org/lists/lua-l/2004-05/msg00005.html
http://lua-users.org/lists/lua-l/2011-02/msg00387.html
If you're running this code on Win32 or in a POSIX environment, you could try this Lua extension: http://code.google.com/p/lua-ex-api/
Alternatively, you could write a small shell script (assuming bash or similar is available) that:
executes the correct executable, capturing the exit code into a shell variable,
prints a newline and terminal character/string onto standard out
prints the shell variables value (the exit code) onto standard out
Then, capture all the output of io.popen and parse backward.
Full disclosure: I'm not a Lua developer.
yes , your are right that os.execute() has returns and it's very simple if you understand how to run your command with and with out lua
you also may want to know how many variables it returns , and it might take a while , but i think you can try
local a, b, c, d, e=os.execute(-what ever your command is-)
for my example a is an first returned argument , b is the second returned argument , and etc.. i think i answered your question right, based off of what you are asking.

Resources