I'm making a package, where I have to get a symbol's value by its name in a sub, while the symbol is defined outside the sub.
Here is the simplified code, it works as expected:
#! /usr/bin/env perl6
sub dump_value($symbol) {
say ::("$symbol")
}
# usage:
my $x = 10;
dump_value('$x');
# expected output: 10
# actual output: 10
Then I put the 'dump_value' in a standalone file as below:
# somelib.pm6
unit module somelib;
sub dump_value($symbol) is export {
say ::("$symbol")
}
# client.pl6
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 10;
dump_value('$x');
The compiler complained:
No such symbol '$x'
in sub dump_value at xxx/somelib.pm6 (somelib) line 3
in block <unit> at ./client.pl6 line 8
Following are some experiments. None of them succeeded.
say ::("MY::$symbol")
say ::("OUR::$symbol")
say ::("OUTER::$symbol")
say ::("CLIENT::$symbol")
...
So how to fix the code?
UPDATE:
Thank you! CALLERS::($symbol) solved my original problem. But in a bit more complex situation, the complier complained again:
# somelib.pm6
unit module somelib;
sub dump_value(#symbols) is export {
# output: 6
say CALLERS::('$x');
# error: No such symbol 'CALLERS::$x'
say #symbols.map({ CALLERS::($^id) } )
}
# client.pl6
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 6;
my $y = 8;
dump_value(<$x $y>);
UPDATE AGAIN:
use OUTER::CALLERS::($^id).
UPDATE AGAIN AND AGAIN:
After I put the 'dump_value' in another sub, it didn't work any more!
# somelib.pm6
unit module somelib;
sub dump_value(#symbols) is export {
say #symbols.map({ OUTER::CALLERS::($^id) } )
}
sub wrapped_dump_value(#symbols) is export {
dump_value(#symbols)
}
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 6;
my $y = 8;
# ouput: (6 8)
dump_value(<$x $y>);
# error: No such symbol 'OUTER::CALLERS::$x'
wrapped_dump_value(<$x $y>);
According to the documentation:
An initial :: doesn't imply global. Here as part of the interpolation
syntax it doesn't even imply package. After the interpolation of the
::() component, the indirect name is looked up exactly as if it had
been there in the original source code, with priority given first to
leading pseudo-package names, then to names in the lexical scope
(searching scopes outwards, ending at CORE).
So when you write say ::("$symbol") in dump_value() in the somelib package, it will first lookup $symbol in the current scope, which has value '$x' then try to look up $x (also in the current scope), but the variable $x is defined in the caller's lexical scope, so you get the No such symbol '$x' error.
You can refer to the caller's lexical symbol given by the value of $symbol using either:
CALLER::MY::($symbol); # lexical symbols from the immediate caller's lexical scope
or
CALLERS::($symbol); # Dynamic symbols in any caller's lexical scope
see the package documentation page.
Couple of things:
use lib ".";
use somelib;
our $x = 10; # You need to export the value into the global scope
dump_value('$x');
Then, use the global scope:
unit module somelib;
sub dump_value($symbol) is export {
say GLOBAL::("$symbol")
}
Related
How to pass function argument by reference in the circom circuit language?
I'm trying to do the following:
pragma circom 2.0.0;
function increment(foo) {
foo++;
}
template MyTemplate() {
signal input a;
signal output b;
var foo;
foo = 0;
increment(foo);
log(foo);
// ...
}
component main = MyTemplate();
I expect log(pos) to output 1, but I'm getting 0. Is there a certain way I need to pass pos into increment so that it can modify the variable by reference?
I decided to use the C preprocessor to generate circom code, so now I have:
main.circom:
cpp -P maintpl.circom > main.circom
in my Makefile
and
#define increment(foo) foo++
in my circom code.
I am trying to instrument a user-space program using systemtap, Linux 4.2.0-42-generic #49~14.04.1-Ubuntu SMP; stap --version says: "Systemtap translator/driver (version 2.3/0.158, Debian version 2.3-1ubuntu1.4 (trusty))"
So I first tried getting a list of all callable functions, with:
stap -L 'process("/home/username/pathone/subpathtwo/subpaththree/subpathfour/subpathFive/subpathsix/subpathSeven/subpatheight/myprogramab").function("*").call' 2>&1 | tee /tmp/stap
This worked - however, note that the absolute path to my program is massive. So from the /tmp/stap file, I read some probes of interest, however, they are even longer, such as:
process("/home/username/pathone/subpathtwo/subpaththree/subpathfour/subpathFive/subpathsix/subpathSeven/subpatheight/myprogramab").function("DoSomething#/home/username/pathone/subpathtwo/subpaththree/subpathfour/subpathFive/src/BasicTestCodeFileInterface.cpp:201").call
... and as this is very difficult to read/unreadable for me, I wanted to do something to split this line into more readable pieces. The first thing I thought of was using variables, so I tried this test.stp script:
#!/usr/bin/env stap
global exepath = "/home/username/pathone/subpathtwo/subpaththree/subpathfour/subpathFive/subpathsix/subpathSeven/subpatheight/myprogramab"
global srcpath = "/home/username/pathone/subpathtwo/subpaththree/subpathfour/subpathFive/src"
probe begin {
printf("%s\n", exepath)
exit() # must have; else probe end runs only upon Ctrl-C
}
probe end {
newstr = "DoSomething#" . srcpath # concatenate strings
printf("%s\n", newstr)
}
This works, I can run sudo stap /path/to/test.stp, and I get the two strings printed.
However, when I try to use these strings in probes, they fail:
Writing a probe like this:
probe process(exepath).function("DoSomething#".srcpath."/BasicTestCodeFileInterface.cpp:201").call { ...
... fails with: parse error: expected literal string or number; saw: identifier 'exepath' ....
Trying to put the "process" part in a variable:
global tproc = process("/home/username/pathone/subpathtwo/subpaththree/subpathfour/subpathFive/subpathsix/subpathSeven/subpatheight/myprogramab")
... fails with parse error: expected literal string or number; saw: identifier 'process' ....
So, what options do I have, to somehow shorten the probe lines in a script?
Your best bet is probably to use macros:
#define part1 %( "/path/part/1" %)
#define part2 %( "/part/2" %)
probe process(#part1 #part2).function("...") { }
Note no explicit concatenation operator between the (macros that expand to) string literals. The parser will auto-concatenate them, just as in C.
TL:DR; I can't declare variables inside a hotkey as local, which means temp and index are globally accessible.
I recently discovered that local variables cannot be declared as local from within a hotkey or if they are used as parameters within a for-loop.
^j::
local temp = Hello, world! ; Error: This line does not contain a recognized action
Return
SampleFunction() {
for local temp in myArray { ; Error: Variable name contains an illegal character
; do stuff
}
}
This becomes an issue with #warn enabled. Unless I remember to use unique variable names for each of my for loops, I run into the following error:
Warning: This local variable has same name as a global variable. (Specifically: index)
For example:
#warn
^j::
index = 42 ; This *index* variable is global
Return
UnrelatedFunction() {
for index in myArray { ; This *index* variable is local
MsgBox % myArray[index]
}
}
In particular this becomes a problem when using imports, as variables from my own scripts often conflict with variables from my imported scripts.
Ideally, I would be able to put a local declaration before any for-loops, but as shown earlier, I'm not able to do this within hotkeys.
Is it possible to declare a variable as local from within a hotkey?
I implement my hotkeys with functions. Variables within functions have by default local scope unless they are declared global
F1::alpha(10,10)
F2::alpha(20,30)
F3::beta()
alpha(x,y)
{
myvar := x*2 + y
}
beta()
{
myvar := 47
}
This code compiles perfect:
if ( args.Length() > 0 ) {
if ( args[0]->IsString() ) {
String::Utf8Value szQMN( args[0]->ToString() ) ;
printf( "(cc)>>>> qmn is [%s].\n", (const char*)(* szQMN) ) ;
} ;
} ;
But this one does not :
if ( args.Length() > 0 ) {
if ( args[0]->IsString() ) {
String::Utf8Value szQMN( args[0]->ToString() ) ; // <<<< (A)
} ;
} ;
printf( "(cc)>>>> qmn is [%s].\n", (const char*)(* szQMN) ) ; // <<<< (B)
Error says : "error C2065: 'szQMN' : undeclared identifier" on line (B)
This means to me that the sentence marked (A) is a definition at the same time as an assignement, right ?
And compiler decides it is "conditionally" defined as it is within two "IF's" ?
My question is : how to move the declaration out of the two "IF's" ?
In this way I also can give it a defalut value ... in case a IF fails.
If I write this line out of the two "IF's"
String::Utf8Value szQMN ("") ;
... then I get the error :
cannot convert argument 1 from 'const char [1]' to 'v8::Handle<v8::Value>'
Any ideas?
This means to me that the sentence marked (A) is a definition at the same time as an assignement, right?
Technically it is a constructor call that creates a variable and initializes it.
Also note that automatic variables exist only until the end of the scope (usually a block inside {} brackets). That is why your second code example does not compile.
if (condition)
{
int x = 5;
}
x = 6; // error, x does not exist anymore
My question is : how to move the declaration out of the two "IF's"?
String::Utf8Value szQMN ("");
This is a constructor call of the class String::Utf8Value class. From the error message it takes a parameter of type v8::Handle<v8::Value>. Without knowing what this is I cannot give you an answer how to call it. You wanted to pass "" which is of type const char* or const char[1] and the compiler is telling you that it does not take that parameter.
Edit:
From the link that DeepBlackDwarf provided in the comment, this is how you create a Utf8Value from a string:
std::string something("hello world");
Handle<Value> something_else = String::New( something.c_str() );
So in your case you would do:
String::Utf8Value szQMN (String::New(""));
the definition in the IF's loop is only works in this loop.
So in the (B) sentence,the definition has already been expired.
If you need to use the var both in the IF's loop and outside,you can declare a global variability by this sentence :
extern String::Utf8Value szQMN( args[0]->ToString() ) ;
i am getting the following error when i am trying to run my 1st Perl script:
[id=0 # 0] : IP address "3.3.3.3" corresponds to device "core".
Thread 1 terminated abnormally: Not a CODE reference at ./dev_ithread.pl line 23.
[id=0 # 1] : IP address "5.5.5.5" corresponds to device "border".
Thread 2 terminated abnormally: Not a CODE reference at ./dev_ithread.pl line 23.
and here is what i have written so far
#!/usr/bin/perl
use strict ;
use warnings ;
use diagnostics ;
use threads ;
use Config ;
$Config{useithreads} || die("\n---> Please recompile Perl with \<ithreads\> included. \n") ;
# IP parameterization of network elements.
my %device_ip = (
"core" => "3.3.3.3",
"border" => "5.5.5.5",
) ;
# Initialize devices' pool of threads.
my $index = 0 ;
my #device_thread = () ;
while( my ($key, $value) = each %device_ip )
{
push( #device_thread, threads->new(\&thread_job($key, $device_ip{$key}, $index))->join ) ; $index = $index+1 ;
}
# Worker thread subroutine.
sub thread_job
{
my ($device, $ip, $index) = #_ ;
my $ithread = threads->tid() ;
print "[id=$ithread # $index] : IP address \"$ip\" corresponds to device \"$device\". \n" ;
}
i would be thankful, if someone could help me overcome this problem.
thank you.
The first argument to threads->new() must be a code reference or the name of a function. You are executing the function and try to take a code reference of the result (which is most likely a true value since that is what print returns), hence the error. I guess your call should be like this:
threads->new(\&thread_job, $key, $device_ip{$key}, $index)->join
\&thread_job($key, $device_ip{$key}, $index) doesn't do what you think it does: it runs thread_job(...) immediately, then produces a reference to its result. threads->new then tries to execute that reference inside the new thread, which doesn't work because it's not a reference to a sub.
You probably want to say sub { thread_job($key, $device_ip{$key}, $index) } instead. (Or #musiKk's version.)