Why does using a variable as a function parameter cause a type mismatch error in a later function call? - nushell

def make-list [val?: string] {
["f1" "f2"]
}
def use-list [list: list] {
$list | each { |it| $it + "!" }
}
let $val = "abc"
let $l = (make-list $val)
use-list $l
In this code, I have two functions, one to make a list, and another to consume that list. For the purposes of this MRE, make-list returns a simple hard-coded list, and use-list prints each element with an exclamation mark added to the end.
If this script executes correctly, it should print a list with two elements "f1!" and "f2!".
make-list has an optional parameter. In the code above, I create a $val variable, then pass that into make-list, and store the result of the pipeline to $l. Executing $l | describe instead of use-list $l prints list<string>, so I'm confident that $l is indeed a list.
The code above throws the following compile error:
Error: nu::parser::type_mismatch (link)
× Type mismatch.
╭─[/.../test.nu:10:1]
10 │ let $l = (make-list $val)
11 │ use-list $l
· ─┬
· ╰── expected List(Any), found String
╰────
However, I can modify the let $l ... line to allow the script to compile and execute correctly. Both of these options will allow the script to compile and returns the expected result.
The parameter for make-list can be removed (because the parameter is optional).
let $l = (make-list)
The parameter for make-list can be replaced by a string literal
let $l = (make-list "abc")
I don't understand why using a variable as a parameter call is suddenly causing a type issue with the use-list function call. What am I doing wrong here?
As an interesting side note, and this might explain the "...found String" part of the error message, if I change the make-list parameter to an int:
def make-list [val?: int] {
["f1" "f2"]
}
# ...
let $val = 3
let $l = (make-list $val)
use-list $l
It will fail to compile with the same kind of error, but the "found" type will reflect the updated parameter type.
Error: nu::parser::type_mismatch (link)
× Type mismatch.
╭─[/.../test.nu:10:1]
10 │ let $l = (make-list $val)
11 │ use-list $l
· ─┬
· ╰── expected List(Any), found Int
╰────
Tested using Nushell version 0.74.0 and 0.75.0 on Arch Linux and Windows 11, respectively.

Something seems to "go wrong" with the variable binding. Your scenario does work if the literal string is being evaluated in a subexpression before it is being bound:
let $val = ("abc")
# or
let $val = do { "abc" }
Even a seemingly useless type casting later on does the trick:
let $val = "abc"
let $l = (make-list ($val | into string))
This is also consistent with other types. Adapting your int example:
def make-list [val?: int] { … }
…
let $val = 123 # fails
let $val = (123) # works
Likewise, having a do closure, or type-casting using into int, do work as well.
Not of importance, however, is the syntax of the variable binding. With the $ sign omitted, all examples from above still work or fail under the same circumstances, e.g.:
let val = "abc" # fails
let val = ("abc") # works
As expected, using let l = instead of let $l = also yields the same results.

Related

How to assign object to ref

This code fails to compile:
var s: ref string = nil
s = ref "hi"
echo s
The error is (2, 9) Error: type expected, but got: "hi". I've tried putting ref and ptr in front and back of the string, tried to find some example in the documentation, but failed.
var s: ref string
new(s)
s[] = "hi"
echo s[]
Declare
Allocate new object
Assign to dereferenced string
Echo final string in dereferenced form
Note that echo s[] is needed because ref string does not implement $ operator, and cannot be converted to string by echo.
Not entirely sure why you want to do this. But first you need to create your ref type, then assign the value to a string. Something like this:
var s: ref string = nil
echo s.repr
new s
s[] = "hi"
echo s[]
echo s.repr
Will output something like this:
nil
hi
ref 0x7f7d4bbcf050 --> 0x7f7d4bbd2090"hi"
But as I said, not sure why you'd want this. Strings are already a reference type. As long as you pass them as mutable to a procedure you will be able to modify the underlying data:
var s: string = ""
s = "hi"
echo s
echo s.repr
proc test(x: string) =
echo x.repr
proc testM(x: var string) =
echo x.repr
x[1] = 'o'
test s
testM s
echo s
echo s.repr
Will output something like:
hi
0x7f5fc2807060"hi"
0x7f5fc2807060"hi"
0x7f5fc2807060"hi"
ho
0x7f5fc2807060"ho"

How to parse the Redis RESP bulk string using nom?

I need use nom to parse a RESP request/reply. When I come to bulk-string, such as
"$6\r\nfoobar\r\n"
or
$-1\r\n
First, I write functions to extract the len from the data.
named!(signed_digits<&str, (Option<&str>, &str)>,
pair!(
opt!(alt!(tag!("+") | tag!("-"))),
nom::digit
)
);
named!(signed_integer<&str, i64>,
map_res!(recognize!(signed_digits), FromStr::from_str)
);
named!(get_len_in_bulk_string<&str, i64>,
do_parse!(
tag!("$") >>
len: signed_integer >>
tag!("\r\n") >>
(len)
)
);
Then I get the raw string according to the len:
named!(parse_bulk_string<&str, Record>,
map_res!(gen_len_in_bulk_string, |n|{
if n < 0 {
Record::BulkString(None)
} else {
Record::BulkString(Some(take!(n)))
}
})
);
But I get a compile error:
Record::BulkString(Some(take!(n)))
^ missing tokens in macro arguments
How can I get the raw string according the len which is extracted from the text before? It seems like I cannot use take! in my own closure.
Macros like take! need an "implicit" argument in the first position: the string to be parsed. Usually you don't see it, because it is passed implicitly when it's nested inside another nom macro.
However, here, you're "calling" it directly, so it needs this argument explicitly.
Instead you could do something like this:
named!(get_bulk_string<&str, &str>,
do_parse!(
tag!("$") >>
len: signed_integer >>
string: take!(len) >>
tag!("\r\n") >>
(string)
)
);
Of course, this ignores the -1 case, which you can handle with a switch:
named!(get_bulk_string<&str, Option<&str>>,
do_parse!(
tag!("$") >>
string: switch!(signed_integer,
-1 => map!(take!(0), |_| None) |
_ => map!(take!(42), |s| Some(s))
) >>
tag!("\r\n") >>
(string)
)
);

Subsetting Blocks (or Callables in general)

This question was originally posted by lookatme in the Perl6 IRC channel. The original intention is to constrain a Callable by using subsets or any other possible way. It works in signatures, however this:
subset WalkCb of Callable where *.signature ~~ :(Int $a);
my WalkCb $x = sub (Int $a) { return $a; };
returns
«Type check failed in assignment to $x; expected WalkCb but got Sub (sub (Int $a) { #`(Sub...)␤ in block <unit> at <tmp> line 1␤␤»
Other variants of the declaration return similar messages. What would be the correct syntax?
A where constraint can take a block (lambda) or a statement.
… where { $_ == 42 }; # block
… where * == 42; # lambda
… where $_ == 42; # statement
The thing is that ~~ doesn't participate in the creation of WhateverCode lambdas (*)
So what you are really doing is creating a lambda of *.signature inside of a larger where statement (not lambda).
constant $lambda = *.signature;
subset WalkCb of Callable where $lambda ~~ :(Int $);
Which will of course never return True as the lambda has a signature of :(;; $ is raw)
So instead just write the statement form. (using implicit $_)
subset WalkCb of Callable where .signature ~~ :(Int $);
my WalkCb $x = sub (Int $a) { return $a }
say $x(42); # 42␤
It appears the WhateverCode parsing messes up in this case. So if you specify a block in the where:
subset WalkCb of Callable where { .signature ~~ :(Int $) }
my WalkCb $x = sub (Int $a) { return $a; }
it appears to work as expected. Also note that I removed the ; at the end of the lines, as a } at the end of a line is also the end of a statement. And that I removed the "a" from the signature: the name of of positional parameters in signature smartmatching is ignored.

OCaml: Issue manipulating string read from file

I am trying to read a file, line by line in OCaml. Each line in the file represents a string I want to parse, in the correct format expected by the Parsing tool. I am saving each line in a list structure.
I an finding an issue parsing the string contained in each element of the list. I am using OCamllex and Menhir as parsing tools.
If I try to use print_string to print the contents of the list at every element, I get the correct file contents.
If I try to pass a string that I defined within the program to the function, then I get the desired output.
However, if I try to parse the string which I have just read from the file, I get an error: Fatal error: exception Failure ("lexing empty token")
Note: that all of this has been tested against the same string.
Here is a snippet of the code:
let parse_mon m = Parser.monitor Lexer.token (from_string m)
let parse_and_print (mon: string)=
print_endline (print_monitor (parse_mon mon) 0)
let get_file_contents file =
let m_list = ref [] in
let read_contents = open_in file in
try
while true; do
m_list := input_line read_contents :: !m_list
done; !m_list
with End_of_file -> close_in read_contents; List.rev !m_list
let rec print_file_contents cont_list = match cont_list with
| [] -> ()
| m::ms -> parse_and_print m
let pt = print_file_contents (get_file_contents filename)
Ocamllex throws an exception Failure "lexing: empty token" when a text in the stream doesn't match any scanner pattern. Therefore, you will need to match with "catch-all" patterns such as ., _, or eof.
{ }
rule scan = parse
| "hello" as w { print_string w; scan lexbuf }
(* need these two for catch-all *)
| _ as c { print_char c; scan lexbuf }
| eof { exit 0 }
Without seeing your grammar and file I can only offer a wild guess: Could it be that the file contains an empty line at the end? Depending on the .mll that might result in the error you see. The reason being that get_file appends new lines to the front of the list and print_file_contents only looks at the head of that list.
I agree with kne, hard to say without seeing the file, but what you can do is trying to isolate the line that causes the trouble by doing :
let rec print_file_contents cont_list =
match cont_list with
| [] -> ()
| m::ms ->
try parse_and_print m
with Failure _ -> print_string m

Groovy script in JMeter: error "expecting anything but ''\n''; got it anyway # line..." when contains closure that uses GString interpolation

I have this groovy script that defines a closure that works properly.
escape = { str ->
str.collect{ ch ->
def escaped = ch
switch (ch) {
case "\"" : escaped = "\\\"" ; break
// other cases omitted for simplicity
}
escaped
}.join()
}
assert escape("\"") == "\\\"" //Sucess
But when I add another closure that uses some GString interpolation to the script.
escape = { str ->
//Same as above
}
dummy = {
aStr = "abc"
"123${aStr}456"
}
//Compilation fails
I get the error
javax.script.ScriptException: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
Script650.groovy: 7: expecting anything but ''\n''; got it anyway # line 7, column 39.
case "\"" : escaped = "\\"" ; break
^
1 error
Even if the added closure was commented.
escape = { str ->
//Same as above
}
/*dummy = {
aStr = "abc"
"123${aStr}456"
}*/
//Compilation fails
Still fails! What gives?

Resources