This local function can be accessed outside the scope, any explanation? - function

for i = 1, 20 do --Create a loop
if i < 10 then
local function LessThan10()
return i
end
end
end
print(LessThan10())
Surprisingly, eventhough LessThan10 was inside a conditional statement and it was a local function(actually it's not the function, it's the variable). Somehow, I could still print out the answer
This is pretty interesting (I checked in Zerobrane, LessThan10 is a local function)
EDIT : Well I guess it's my interpreter problem, I changed the interpreter and this thing errors.

Tested in Lua 5.0 interpreter:
Lua 5.0.3 Copyright (C) 1994-2006 Tecgraf, PUC-Rio
> for i = 1, 20 do --Create a loop
>> if i < 10 then
>> local function LessThan10()
>> return i
>> end
>> end
>> end
> print(LessThan10())
stdin:1: attempt to call global `LessThan10' (a nil value)
stack traceback:
stdin:1: in main chunk
[C]: ?
I also can't believe this is / was valid code as local variables are only visible within the block they are declared at.
If you are using a custom Lua interpreter you should further investigate on it, seems pretty interesting though.

I tested this and it only worked on Lua 5.0 and 5.1
I tested it again on Lua 5.3 and it no longer works
My zerobrane reset my lua version to 5.0 for no reason, well, sorry if this question disappointed you.

Related

How do external functions return data in Regina Rexx?

I've installed the Regina Rexx package (version 3.9.1) in Cygwin on Windows 10. To test it out, I wrote the following code:
caller:
#!/usr/bin/rexx
x = 'callee'() ; say 'callee returned' x ; exit
callee:
#!/usr/bin/rexx
say 'In callee' ; return 42
When I invoke caller, I expect to see:
> ./caller
In callee
callee returned 42
And in fact, this is exactly what I do see when both execs are in my current directory. However, when I move them to a different directory in $PATH and invoke caller, I see:
> ./caller
caller returned In callee
This was ... unexpected. If there's an explanation of the behavior in the Regina Rexx manual, I'm not seeing it. Am I missing something? Thanks.
It turns out that Rexx execs can be used as external functions only if they reside in a directory mentioned in the REGINA_MACROS variable, like so:
export REGINA_MACROS="${HOME}/subdir:/maybe/somewhere/else"
Without this, the called routine is treated as just another executable. The return value is all stdout lines with a space delimiter between them. Any stderr output is sent to the screen (or redirected) as usual.

When defining a variable in a julia function, I get an error about an undefined variable on that line

Problem
I'm writing a Julia script, and in the function there is a while loop. Inside the while loop there is a variable. That line is throwing errors about the variable being undefined when in fact that is the very line defining the variable.
The code
The error is on line 65
function cleanTexLoop(fileName::String)
f = open(fileName, "r")
while ! eof(f)
line = readline(f), <-- line 65
#line = sentenceFilter(line)
println(line)
end
close(f)
end
The function opens a file which IS getting passed into a loop. The loop runs until the end of file. While looping the file is read line by line. Each time it is read the line is stored in variable line and the file advances. In the proper version, that one line (66) isn't commented out, however for debugging it is. line is then taken as input into a filter which modifies the line before storing it again as line. The final version of this script will have four filters, but for now, I'd be happy to get this to run with just zero filters.
(Note that a user has kindly pointed out the comma that after hours of looking at the code continued to allude me. I'm waiting for that user to write up an answer)
The error message
cleanTexLoop("test.tex")
ERROR: UndefVarError: line not defined
Stacktrace:
[1] cleanTexLoop(::String) at /home/nero/myScripts/latexCleaner.jl:65
[2] macro expansion at ./REPL.jl:97 [inlined]
[3] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at > ./event.jl:73
Previous working version
I had previous written another version of this which works in entirety, however I needed to make some substantial changes to its structure in order to better suit future plans. Note that some of the names aren't up to the normal naming convention. Namely, I use "!" when no variables are actually being changed.
function CleanTexLoop(fileName::String,regX::String,sub::String)
f = open(fileName, "r")
while ! eof(f)
println(applySub!(f,regX,sub))
end
close(f)
end
function applySub!(file::IOStream,regX::String,sub::String)
return replace(
readline(file),
Base.Regex(regX),
Base.SubstitutionString(sub)
)
end
A simple loop which demonstrates why this should work
x = 0
while x < 4
y = x
println(y)
x = x+1
end
As expected, this prints zero to one, and is, as far as I can tell, representative of what I am doing. In both cases I am passing some variable into the loop which, through some action, defines another variable inside the loop which is then printed. Why this works, and the other doesn't is beyond me.
What I've seen on Google.
From looking this problem up, it appears as if this problem arrises when defining variables outside of a loop, or similar environment, as a result of them failing to be passed into the environment. However, this isn't what's happening in my case. In my case the variable is being defined for the first time.
As mentioned in the comments, the problem was an errant comma.

Perl issues regarding mysql:Can't locate object method "connect" and Can't use string ("") as a HASH

I'm currently trying to run NERVE a vaccine development program that is made up of Perl scripts and have trouble getting it to run properly. I've downloaded and installed all prerequisites but every time I reach the mysql step of the code, it crashes, and an error message says: Can't locate object method "connect" via package "Mysql" (perhaps you forgot to load "Mysql"?) at ./NERVE line 340, line 5. I took a look at the code and changed "use mysql" to "use DBI" and "use DBD:mysql" but then I get the error: Can't use string ("") as a HASH ref while "strict refs" in use at /usr/local/lib/perl/5.14.2/DBI.pm line 604, line 5.
I would appreciate if anyone could look the code over for the mysql section and give me advice on how to fix it so I can run the program properly. I tried emailing the developers but no response so I'm hoping you guys can help me.
Below is the perl code for NERVE for the mysql section.
use mysql;
$db=Mysql->connect("$host","$database","$user","$password");
if(!$db || (!$host || !$database || !$user || !$password)){
print "\nAttention: mysql connection parameters are missing or not correct!\n";
print "I need you to specify: host, database, user, password;\n";
print "You can do it now typing them right in that order and separeted only by comma;\n";
print "For example:localhost,Pathogens,sandro,xvzhs\n";
print "So, your Mysql connection settings are (type q to quit):";
while (!($db && $mysql =~ /,/) & $mysql ne "q"){
chomp($mysql = <STDIN>);
die "Ok,let's quit this work! Call me when your mind is clearer about Mysql parameters! Bye :-)\n" if $mysql eq "q";
($host,$database,$user,$password) = split (',',$mysql);
$db=Mysql->connect("$host","$database","$user","$password");
last if($db && $mysql =~ /,/);
print "\nMysql connection settings still not correct!\n";
print "Remember: host, database, user, password, separeted only by comma.\n";
print "For example:localhost,Pathogens,sandro,xvzhs\n";
print "Please, try again:";
}
print "Ok, Mysql connection to \"$database\" database was successful!\n";
}
The error message is correct. You are attempting to use a module named , but you never loaded it. Change
use mysql;
to
use Mysql;
to use that module. In the comments, you mention that results in
Can't locate Mysql.pm in #INC
Unless you have reason to believe the module is installed, that indicates it needs to be installed[1]
That module used to be part of the DBD-mysql distribution, but it's obsolete. It's so ancient it was removed from DBD some years ago. To obtain it, you will need to downgrade your DBD-mysql distribution to version 3.0008.
That's pretty awful thing to do. The script should have DBI instead.
cjm points
since the Mysql.pm in 3.0008 is just a compatibility layer using DBI under the hood, you should be able to install Mysql.pm & Mysql/Statement.pm from that old dist along with a current DBD-mysql.
So if you extract Mysql.pm from the distro I linked above as /usr/lib/perl5/Mysql.pm and Mysql/Statement.pm as /usr/lib/perl5/Mysql/Statement.pm, you should have an easy pain-free solution.
In newer versions of Perl, the error message has been improved. It now reads as follows:
Can't locate Mysql.pm in #INC (you may need to install the Mysql module)

How to interrupt Tcl_eval

I have a small shell application that embeds Tcl 8.4 to execute some set of Tcl code. The Tcl interpreter is initialized using Tcl_CreateInterp. Everything is very simple:
user types Tcl command
the command gets passed to Tcl_Eval for evaluation
repeat
Q: Is there any way to interrupt a very long Tcl_Eval command? I can process a 'Ctrl+C' signal, but how to interrupt Tcl_Eval?
Tcl doesn't set signal handlers by default (except for SIGPIPE, which you probably don't care about at all) so you need to use an extension to the language to get the functionality you desire.
By far the simplest way to do this is to use the signal command from the TclX package (or from the Expect package, but that's rather more intrusive in other ways):
package require Tclx
# Make Ctrl+C generate an error
signal error SIGINT
Just evaluate a script containing those in the same interpreter before using Tcl_Eval() to start running the code you want to be able to interrupt; a Ctrl+C will cause that Tcl_Eval() to return TCL_ERROR. (There are other things you can do — such as running an arbitrary Tcl command which can trap back into your C code — but that's the simplest.)
If you're on Windows, the TWAPI package can do something equivalent apparently.
Here's a demonstration of it in action in an interactive session!
bash$ tclsh8.6
% package require Tclx
8.4
% signal error SIGINT
% puts [list [catch {
while 1 {incr i}
} a b] $a $b $errorInfo $errorCode]
^C1 {can't read "i": no such variableSIGINT signal received} {-code 1 -level 0 -errorstack {INNER push1} -errorcode {POSIX SIG SIGINT} -errorinfo {can't read "i": no such variableSIGINT signal received
while executing
"incr i"} -errorline 2} {can't read "i": no such variableSIGINT signal received
while executing
"incr i"} {POSIX SIG SIGINT}
%
Note also that this can leave the interpreter in a somewhat-odd state; the error message is a little bit odd (and in fact that would be a bug, but I'm not sure what in). It's probably more elegant to do it like this (in 8.6):
% try {
while 1 {incr i}
} trap {POSIX SIG SIGINT} -> {
puts "interrupt"
}
^Cinterrupt
%
Another way to solve this problem would be to fork your tcl interpreter into a separate process and driving the stdin and stdout of the tcl interpreter from your main process. Then, in the main process, you can intercept Ctrl-C and use it to kill the process of your forked tcl interpreter and to refork a new tcl interpreter.
With this solution the tcl interpreter will never lock up on your main program. However, its really annoying to add c-function extension if they need them to run in the main process because you need to use inter-process communication to invoke functions.
I have a similar problem I was trying to solve, where I start the TCL interpret in a worker thread. Except, there's really no clean way to kill a worker thread because it leave allocated memory in an uncleaned up state, leading to memory leaks. So really the only way to fix this problem is to use a process model instead or to just keep quitting and restarting your application. Given the amount of time it takes to go with process solution I just decided to stick with threads and fix the problem one of these days to get the ctrl-c to work in a separate process, rather than leaking memory everytime i kill a thread. and potential destabilizing and crashing my program.
UPDATE:
My conclusion is that Tcl Arrays are not normal variables and you can't use Tcl_GetVar2Ex to read "tmp" variable after Eval and tmp doesn't show up under "info globals". So to get around this I decided to directly call the Tcl-Library API rather than Eval shortcut to build a dictionary object to return.
Tcl_Obj* dict_obj = Tcl_NewDictObj ();
if (!dict_obj) {
return TCL_ERROR;
}
Tcl_DictObjPut (
interp,
dict_obj,
Tcl_NewStringObj ("key1", -1),
Tcl_NewStringObj ("value1", -1)
);
Tcl_DictObjPut (
interp,
dict_obj,
Tcl_NewStringObj ("key2", -1),
Tcl_NewStringObj ("value2", -1)
);
Tcl_SetObjResult(interp, dict_obj);

How do I create a simple Octave distributable without installing Octave

The Octave documentation on this subject is both intimidating and sparse.
I did not know where else to document the solution I found, so I am posting here. I apologize if that's inappropriate, but I want to help the next guy.
The following solution is for a simple windows distributable.
Use Case:
A solution is developed in Octave 3.2.4, and needs to be distributed to end-users with few computer skills. Installing and explaining Octave is impossible, the solution must be "one-click" or "brain-dead-simple."
Known Issues:
imread fails in 3.2.4 because file_in_path.m is wrong. You will need to update the file file_in_path.m to the following (just replace it):
function name=file_in_path(p,file)
idx=[1 findstr(p,pathsep) length(p)+1];
for i=1:length(idx)-1
if idx(i+1)-idx(i)<=1
dir=strcat(pwd,"/");
else
dir=p(idx(i)+1:idx(i+1)-1);
end
name = fullfile(dir, file);
fid = fopen(name,"r");
if fid >= 0
fclose(fid);
return
end
end
fid = fopen(file,"r");
if fid >= 0,
fclose(fid);
name=file;
return
end
name=[];
Solution: Create a distributable exe using mkoctfile, and package this exe with the core Octave files, and other .oct and .m files as necessary.
Step 1: Create a stand-alone executable.
You can see code that works here:
http://www.gnu.org/software/octave/doc/interpreter/Standalone-Programs.html
Particularly the file "embedded.cc".
I have simplified that file as follows:
#include <iostream>
#include <octave/oct.h>
#include <octave/octave.h>
#include <octave/parse.h>
int
main (int argc, char *argvc[])
{
string_vector argv (2);
argv(0) = "embedded";
argv(1) = "-q";
octave_main (2, argv.c_str_vec(), 1);
octave_value_list in = octave_value (argvc[1]);
octave_value_list out = feval ("your_custom_m_file", in);
if (!error_state && out.length () > 0)
{
}
else
{
std::cout << "invalid\n";
}
return 0;
}
Build this file with the command
mkoctfile --link-stand-alone embedded.cc -o embedded
It may throw warnings, but as long as it throws no errors, you should be fine. The file embedded.exe will be built, and can be run. The only issue is that it will lack all the goodies that make octave awesome. You will have to provide those.
Step 2: Create a distribution folder
You will need to create a copy of many of the Octave files. I suggest a directory specifically for this. At a minimum, you will need a copy of all or most of the DLLs in \bin. Additionally, place your distributable executable in this directory.
Step 3: Other files whack-a-mole
You will now need to find out what other files will be necessary to run your .m script. You can simplify this step by copying \oct\i686-pc-mingw32*.oct and \share\octave\3.2.4\m\*\*.m to the distribution directory, although this will be overkill, and will not actually prevent the whack-a-mole step.
Now, you must play whack-a-mole or the time-honored tradition of "where my includes be at, yo?"
Open a cmd prompt and navigate to your distribution folder.
Get rid of any useful PATH strings. Your customers won't have them.
Attempt to run the program embedded.exe. You will get an error such as the following:
embedded.exe
error: `max' undefined near line 83 column 22
error: evaluating argument list element number 1
error: evaluating argument list element number 1
error: called from:
error: T:\sms\Development\research\c2\disttest\strcat.m at line 83, column 3
error: T:\sms\Development\research\c2\disttest\file_in_path.m at line 5, column 10
error: T:\sms\Development\research\c2\disttest\imread.m at line 50, column 6
A Search in your Octave installation for "max". It will either be a .oct or a .m file. In this case, it is a .oct file, max.oct. Copy it to your distribution directory.
B You search for something obvious like "min", and get no results. This is because the Loadable Function "min" is in the .oct file "max.oct". Make a copy of max.oct, and rename it to min.oct. It will work now. How do you know where the functions are? I'm not sure. Most of them are in obvious places like "max.oct" for min, and "fft2.oct" for "ifft2.oct". Good luck with all that.
Repeat until your executable runs.
Just to add that if you want to run a script instead of an m function, then the line of the embedded.cc:
octave_value_list out = feval ("your_custom_m_file", in);
should be:
octave_value_list out = feval ("your_custom_m_script");
Also use 'which' to find where the missing functions are packed. For example for the min function:
octave:22> which min
min is a function from the file C:\Octave\Octave3.6.2_gcc4.6.2\lib\octave\3.6.2\oct\i686-pc-mingw32\max.oct
Something I found when linking my custom m file into an Octave standalone:
Needed #include <octave/toplev.h>
Replace return 0; (as above) with clean_up_and_exit(0);
Without these steps my program repeatedly crashed on exit.
Run mkoctfile --link-stand-alone embedded.cc -o embedded
from the octave solution and not from a batch file.
Just saved you half day (-;
In the above solution in bullet 4 B:
B You search for something obvious like "min", and get no results.
This is because the Loadable Function "min" is in the .oct file
"max.oct". Make a copy of max.oct, and rename it to min.oct. It will
work now.
This might not work if some function is being called from #folder function.m and also to avoid unnecessary duplicated files, just add the following code somewhere in your m file outside #folder
autoload ("min", "max.oct");
Likewise, it can be removed via
autoload ("min", "max.oct", "remove");
Ensure that the path to max.oct is provided here.
The above understanding is based on a file PKG_ADD and PKG_DEL in the communications package located at \Octave-4.0.1\lib\octave\packages\communications-1.2.1\i686-w64-mingw32-api-v50+\
Check out Stratego Octave Compiler.
(I've not tested it yet, but plan to do so in the next few days.)
I had that very same requirement (one-click, brain-dead-simple), so I made a setup that contained only curl.exe, the batch file below, an exe which was a .bat in disguise (simply calling the batch file below) and the .vbs script below (not writen by me). And of course my m-file.
This will download Octave 4.2.1 as a portable program (32 bit, otherwise we'dd have to download again if the system turns out to be 32 bit), unpack using the vbs script, move the contents to the same folder as the batch file and run it in GUI mode. Every next time the same script is called, it will only check if octave.bat is still there.
Of course this results in a huge waste of disk space, downloading the 280MB zip, which unpacks to over 1GB (which I make even worse by not deleting the zip afterwards), and you're stuck with a cmd window that is not easy to hide.
But it does offer the simplest solution I could find. It is also less likely to break in the future (either with an update of your own, or an update from Octave). Some glorious day, mkoktfile will actually be easy to use and will solve dependencies on its own, but until that day this remains the least headache-inducing solution I could find. And aspirins are more expensive than someone else's disk space.
::this file will test if the octave portable is downloaded and unpacked
#ECHO OFF
SET my_m_file=your_mfile.m
SET name_of_this_script=run_me.bat
::if the file exists, skip to the actual running.
IF EXIST "octave.bat" goto OctaveIsExtracted
IF EXIST "octave-4.2.1-w32.zip" goto OctaveIsDownloaded
ECHO The runtime (Octave portable 4.2.1) will now be downloaded.
ECHO This may take a long time, as it is about 280MB.
ECHO .
ECHO If this download restarts multiple times, you can manually download the octave-4.2.1-w32.zip from the GNU website. Make sure to unpack the contents.
::if this errors, you can uncomment the line with archive.org (which doesn't report total size during download)
curl http://ftp.gnu.org/gnu/octave/windows/octave-4.2.1-w32.zip > octave-4.2.1-w32.zip
::curl http://web.archive.org/web/20170827205614/https://ftp.gnu.org/gnu/octave/windows/octave-4.2.1-w32.zip > octave-4.2.1-w32.zip
:OctaveIsDownloaded
::check to see if the file size is the correct size to assume a successful download
::if the file size is incorrect, delete the file, restart this script to attempt a new download
::file size should be 293570269 bytes
call :filesize octave-4.2.1-w32.zip
IF /I "%size%" GEQ "293560000" goto OctaveIsDownloadedSuccessfully
del octave-4.2.1-w32.zip
::start new instance and exit and release this one
start %name_of_this_script%
exit
:OctaveIsDownloadedSuccessfully
IF EXIST "octave.bat" goto OctaveIsExtracted
::unzip and move those contents to the current folder
ECHO Unzipping octave portable, this may take a moment.
cscript //B j_unzip.vbs octave-4.2.1-w32.zip
SET src_folder=octave-4.2.1
SET tar_folder=%cd%
for /f %%a IN ('dir "%src_folder%" /b') do move %src_folder%\%%a %tar_folder%
pause
:OctaveIsExtracted
octave.bat %my_m_file%
goto :eof
:filesize
set size=%~z1
exit /b 0
And j_unzip.vbs
' j_unzip.vbs
'
' UnZip a file script
'
' By Justin Godden 2010
'
' It's a mess, I know!!!
'
' Dim ArgObj, var1, var2
Set ArgObj = WScript.Arguments
If (Wscript.Arguments.Count > 0) Then
var1 = ArgObj(0)
Else
var1 = ""
End if
If var1 = "" then
strFileZIP = "example.zip"
Else
strFileZIP = var1
End if
'The location of the zip file.
REM Set WshShell = CreateObject("Wscript.Shell")
REM CurDir = WshShell.ExpandEnvironmentStrings("%%cd%%")
Dim sCurPath
sCurPath = CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(".")
strZipFile = sCurPath & "\" & strFileZIP
'The folder the contents should be extracted to.
outFolder = sCurPath
'original line: outFolder = sCurPath & "\"
WScript.Echo ( "Extracting file " & strFileZIP)
Set objShell = CreateObject( "Shell.Application" )
Set objSource = objShell.NameSpace(strZipFile).Items()
Set objTarget = objShell.NameSpace(outFolder)
intOptions = 256
objTarget.CopyHere objSource, intOptions
WScript.Echo ( "Extracted." )