How to understand tcl's return - tcl

I wanted to get the number of parameters of a proc from tcl and didn't want it to be printed in tclsh, so I used return
When I execute the following statement in the c environment
string tclCmd = "info args " + tclProcName + ";return";
Tcl_Eval(interp, tclCmd.c_str());
string res = Tcl_GetStringResult(interp);
The result of the execution is not printed in tclsh, but at the same time it is not possible to get the correct value
So I tried to write it like this:
string tclCmd = "info args " + tclProcName;
Tcl_Eval(interp, tclCmd.c_str());
string res = Tcl_GetStringResult(interp);
Tcl_Eval(interp, "return");
This works, but I don't understand why it doesn't print out immediately when Tcl_Eval is executed, and the return statement is still valid afterwards

The return command is not helpful at all there. It triggers an exception condition that comes out of Tcl_Eval as a return code of TCL_RETURN instead of TCL_OK (that is converted by the outer structure of a procedure, if that is relevant). Instead, you should call Tcl_ResetResult(interp); after you have finished with the return value (or have taken another reference to it) to put things back to how they were before your command implementation was invoked.

Related

How to remove duplicate results from a cts:uris when distinct values does not work

I have the following code that returns an array of array of results I try to use distinct-values to remove duplicates and it does nothing I have tried also removing using looping functions by comparing values with no success.
I have tried converting to "xs anyAtomicType" and using distinct values
I have tried putting in json array and extracting the sub-array
I have tried tokenizing, xdmp quote, string-before/after and many others
declare function local:verify-user-uri($dir as xs:string)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds
};
I get back duplicated result in form of:
/users/123-343-/profile.xml
/users/122-222-/profile.xml
/users/123-343-/profile.xml
/users/122-222-/profile.xml
/users/123-343-/profile.xml
/users/122-222-/profile.xml
I am expecting:
/users/123-343-/profile.xml
/users/122-222-/profile.xml
Is it possible that you have simply invoked this function 3 times and didn't realize it?
You have declared $dir to be a single xs:string. If your $dir happened to be a sequence of strings of the same directory, or if you otherwise invoked the function 3 times with the directory variable.
It can easily happen with function mapping enabled (default behavior). https://docs.marklogic.com/guide/xquery/enhanced#id_55459
There are a couple of things that you can do as a diagnostic:
1.) Remove the explicit type on the $dir parameter in the function:
declare function local:verify-user-uri($dir)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds
};
do you get an error executing cts:uris() that looks like this:
[1.0-ml] XDMP-ARGTYPE: )err:XPT0004) cts:uris(("/users/", "/users/", "/users/"), ()) -- arg1 is not of type xs:string?
2.) try disabling function mapping by adding the following to the prolog:
declare option xdmp:mapping "false";
and see if you then get an invalid coercion error like:
[1.0-ml] XDMP-AS (err:XPTY0004) $dir as xs:string -- Invalid coersion ("/users/", "/users/", "/users/") as xs:string
3.) You could also add something to the end of the sequence of values returned from the function to indicate how many times it has executed:
declare function local:verify-user-uri($dir as xs:string)
{
for $each in cts:uris($dir, ())
let $uIds := (for $d in $each
where contains($d, "/profile.xml")
return $d)
return $uIds, "#"
};
And see how many times you see "#" in the result. If more than one, you are invoking the function multiple times.
Next to the good suggestions from Mads, I notice a couple of other things about your code:
It doesn't make sense to iterate over $each as it contains one uri only. Keep in mind that a FLWOR statement ends with a return, which tells what should be the result per item
Beware that the first arg to cts:uris only marks a start, not an end. If you feed in /aaa/, you also get back /bbb/ etc, though not vice versa.
To be honest, I think you are looking for cts:uri-match() instead, which would reduce your function to a one-liner:
declare function local:verify-user-uri($dir as xs:string) {
cts:uri-match($dir || "*/profile.xml")
};
HTH!
PS: I do recommend always disabling function mapping as Mads recommends. It can prevent a lot of confusion.

How do I pass objects to functions in ooRexx?

I'm a long-time mainframe Rexx programmer who is trying out objects in ooRexx. The results are surprising. For example, here is a program:
#!/usr/bin/rexx
a = .number~new(3.14)
say "a =" a
say "a~val =" a~val
call say_number a
exit 0
say_number:
procedure
parse arg num
say "In say_number"
say "num =" num
say "num~val =" num~val
return
::class number public
::attribute val get public
::method init ; expose val ; use arg val
::method new ; expose val ; use arg val
::method string ; return "'"self~val"'"
The result is:
> number
a = '3.14'
a~val = 3.14
In say_number
num = '3.14'
18 *-* say "num~val =" num~val
8 *-* call say_number a
REX0097E: Error 97 running /home/tony/bin/.scripts/number line 18: Object method not found
REX0476E: Error 97.1: Object "'3.14'" does not understand message "VAL"
It appears that the object is being resolved to its string value before it's passed to the say_number function. Weird! Am I missing something obvious?
Well, that didn't take long. I changed parse to use in the function, and everything worked as expected. Per the Reference manual:
USE ARG retrieves the argument objects provided in a program, routine,
function, or method and assigns them to variables or message term
assignments.
PARSE assigns data from various sources to one or more variables
according to the rules of parsing. ... If you specify UPPER, the
strings to be parsed are translated to uppercase before parsing. If
you specify LOWER, the strings are translated to lowercase. Otherwise
no translation takes place.
Presumably PARSE converts the arguments to a string so that it can change case as requested (or defaulted).

How to implement a basic Lua function in Conky?

I am trying to add a function to my Conky which prints the length of a string for debug purposes. The code, inside a file called test.lua, is pretty trivial:
function test(word)
return string.len(word)
end
...and I load it like this. In my conky.config section I have:
lua_load = '/home/xvlaze/test.lua',
lua_draw_hook_pre = 'test'
...in the conky.text section I have:
${lua test "fooo"}
...where test is the name of the function and fooo the string to test.
The expected result should be a printed 4 in Conky, but instead of that I get:
conky: llua_do_call: function conky_test execution failed: /home/xvlaze/test.lua:2: attempt to index a nil value (local 'string')
conky: llua_getstring: function conky_test didn't return a string, result discarded
I have browsed through the documentation, but I can't find anything. Does anybody know where the failure is?
Several guidances on how to implement functions in Conky:
First of all: YOU MUST USE conky_ BEFORE YOUR FUNCTION'S NAME.
Otherwise, you will get the following error when running your Conky:
attempt to call a nil value
Secondly: YOU MUST ALWAYS RETURN A VALUE.
I don't mind repeating it - it is crucial. Otherwise, you will get:
function foobar didn't return a string, result discarded
function_result
...in your terminal, and your Conky will be left empty of values related to your extra code. Nothing will be printed regarding your function.
Last but not least: YOU MUST ALWAYS CALL YOUR FUNCTION LIKE:
lua_load = '/path/to/function.lua',
-- Whatever content...
${lua function_name function_parameter1 function_parameterN} -- In case you use more than one parameter.
In summary, a dummy function template could be:
MAIN FILE (conky.conf):
conky.config = {
-- Whatever content... Lua styled comments.
lua_load = '/path/to/function.lua',
}
conky.text = [[
# Whatever content... In this section comments are started with '#'!
${lua function_name parameter}
]]
FUNCTION FILE:
function conky_function_name(parameter)
-- Whatever content... Remember this is Lua, not conky.text syntax. Always use '--' comments!
return whatever -- No return, no party. A function MUST always return something!
end

error: can't perform indexing operations for <unknown type> type when sourcing

With this code, saved as test.m
function test()
x = 1;
endfunction
I get the following error message when sourcing it via source(test.m) in the GUI:
>> clear
>> source (test.m)
x = 1
error: can't perform indexing operations for <unknown type> type
error: evaluating argument list element number 1
>>
Calling the function test via >> test works fine, but I'd like to know what I'm doing wrong here.
Progress:
calling just test, in the right dir seems to do it, but then what are we sourcing for?
If you run
source(test.m)
the interpreter tries to evaluate the "." subscript on the variable "test" (which is a function in your case) and then call source with the result.
What you want is to call the function source with the string "test.m" so you have to use quotes:
source ("test.m")
or don't use () in which case all arguments are passed as strings:
source test.m

File listing in custom autocomplete for Vim

I'm using the Utl plugin for Vim and I'm looking for a method of creating a custom autocomplete function to generate a link to an id tag within the file. The format I want to use is:
:CommandName <file> <id tag in file>
I'd like the function to act like the standard directory completion for the first argument. For the second argument I'd like it to search the file specified in the first argument for all strings beginning with "id=" and return the values.
I've copied a similar function out of the main Utl package, but I've yet to get close to making it work, it currently looks like this:
fu! CompleteArgs(dummy_argLead, cmdLine, dummy_cursorPos)
" Split cmdLine to figure out how many arguments have been provided by user
" so far. If Using argument keepempty=1 for split will provide empty last
" arg in case of a new arg is about to begin or an non empty last argument
" in case of an incomplete last argument. So can just remove the last arg.
exe "echo \"cmdline:\" \"".a:cmdLine."\""
let utlArgs=split(a:cmdLine, '\s\+', 1)
execute "echo" string(utlArgs)
echo "echo" "test complete"
"remove the function name
call remove(utlArgs, -1)
" 1st arg to complete
if len(utlArgs)==1
return string(glob("*"))
endi
" 2nd arg to complete
if len(utlArgs)==2
"insert code here
endif
endfun
Has anyone got any ideas?
You can try out frawor. If you install it code will be the following:
execute frawor#Setup('0.0', {'#/fwc': '0.2',
\ '#/commands': '0.0',})
" No need to write bang here: above command will forbid script to be sourced
" twice, see :h frawor#Reload for how it can be updated.
function s:F.cmdfunc(file, tag)
" It will be called when the command launches. Alternatively you can replace
" `s:F.cmdfunc' in the below command.add call with a string you already had
" before. Note that you will have to replace s: in function names with <SID>
" and s:* variables will be just unaccessible.
endfunction
function s:F.gettags(file)
" This assumes that format is the same as used in ~/.vim/doc/tags. Note that
" if there may be any spaces, then you must escape them.
return map(readfile(a:file), 'matchstr(v:val, "\\v^.{-}\\t")[:-2]')
endfunction
" This replaces direct :command call, see :h frawor-f-command.add
call s:_f.command.add('CommandName', s:F.cmdfunc,
\{ 'nargs': '+',
\'complete': ['path in*F.gettags(#<)']})
While answering a very similar question, I have written a
complete function that determines the number of a command argument to
complete. Below is a version of that function, adapted to your case.
command! -nargs=* -complete=custom,FooComplete Foo echo [<f-args>]
function! FooComplete(arg, line, pos)
let l = split(a:line[:a:pos-1], '\%(\%(\%(^\|[^\\]\)\\\)\#<!\s\)\+', 1)
let n = len(l) - index(l, 'Foo') - 1
if n == 1
return string(glob('*'))
endif
return "1\n2\n3" " Replace this with appropriate id-completion logic.
endfunction
The function properly handles escaped whitespace (as a part of an
argument, not a separator) and whitespace before the command name.
Note that whitespace characters in suggestion candidates should be
escaped, otherwise a single argument would be treated by Vim as two
arguments.