The following examples show gradually complex uses of the EDSL.
Simple call to the exec
construct.
Genspio.EDSL.(
exec ["ls"; "-la"]
)
Pretty-printed:
(exec (byte-array-to-c-string (string "ls"))
(byte-array-to-c-string (string "-la")))
Running it succeeds.
Adding comments with the %%%
operator, we can see them in the compiled output.
Genspio.EDSL.(
"This is a very simple command" %%%
exec ["ls"; "-la"]
)
Pretty-printed:
(comment "This is a very simple command"
(exec (byte-array-to-c-string (string "ls"))
(byte-array-to-c-string (string "-la"))))
Compiled to POSIX (122 bytes):
export genspio_trap_2_26685=$$
trap 'exit 78' USR2
{ { ':' 'This is a very simple command' ; } ; { 'ls' '-la' ; } ; }
Running it succeeds.
When an expression is wrapped with “comments” they also appear in error messages (compilation and run-time) as “the comment stack.”
Genspio.EDSL.(
"This is a very simple comment" %%% seq [
exec ["ls"; "-la"];
"This comment provides a more precise pseudo-location" %%% seq [
(* Here we use the `fail` EDSL facility: *)
fail "asserting False ☺";
];
]
)
Running it fails; returns 78.
Standard error:
Error: asserting False ☺; Comment-stack:
[`This comment provides a more precise pseudo-location`,
`This is a very simple comment`]
The call
construct is a more general version of exec
that can take any EDSL string. As with exec
the string will be checked for C-String compatibilty, hence the calls to byte-array-to-c-string
in the pretty-printed output.
Genspio.EDSL.(
call [
string "echo";
string_concat [string "foo"; string "bar"]; (* A concatenation at run-time. *)
]
)
Pretty-printed:
(exec (byte-array-to-c-string (string "echo"))
(c-string-concat
(list (byte-array-to-c-string (string "foo"))
(byte-array-to-c-string (string "bar")))))
Running it succeeds.
Standard output:
foobar
When a string literal cannot be converted to a “C-String” the compiler tries to catch the error at compile-time.
Genspio.EDSL.(
"A sequence that will fail" %%% seq [
call [string "ls"; string "foo\x00bar"]; (* A string containing `NUL` *)
]
)
Compilation fails with:
Error: String literal is not a valid/escapable C-string: "foo\000bar".; Code:
(exec (byte-array-to-c-string (string "ls"))
(byte-array-to-c-string …;
Comment-backtrace: ["A sequence that will fail"]
Here we use the constructs:
val output_as_string : unit t -> byte_array t
val to_c_string: byte_array t -> c_string t
val (||>) : unit t -> unit t -> unit t
We use let (s : …) = …
to show the types; we see then that we need to “cast”
the output to a C-String with to_c_string
in order to pass it to call
.
Indeed, commands can output arbitrary byte-arrays but Unix commands
only accept NUL
-terminated strings.
We then “pipe” the output to another exec
call with ||>
(which is
a 2-argument shortcut for EDSL.pipe
).
Genspio.EDSL.(
let (s : byte_array t) = output_as_string (exec ["cat"; "README.md"]) in
call [string "printf"; string "%s"; to_c_string s] ||> exec ["wc"; "-l"];
)
Pretty-printed:
(pipe:
(exec (byte-array-to-c-string (string "printf"))
(byte-array-to-c-string (string "%s"))
(byte-array-to-c-string
(as-string
(exec (byte-array-to-c-string (string "cat"))
(byte-array-to-c-string (string "README.md"))))))
|
(exec (byte-array-to-c-string (string "wc"))
(byte-array-to-c-string (string "-l"))))
Running it succeeds.
Standard output:
175
The operator >>
puts any byte-array into the stdin
of any unit t
expression.
Genspio.EDSL.(
(* Let's see wether `wc -l` is fine with a NUL in the middle of a “line:” *)
byte_array "one\ntwo\nth\000ree\n" >> exec ["wc"; "-l"];
)
Pretty-printed:
((string "one\ntwo\nth\000ree\n") >>
(exec (byte-array-to-c-string (string "wc"))
(byte-array-to-c-string (string "-l"))))
Running it succeeds.
Standard output:
3
We show that byte-array >> cat
is not changing anything and we try if_seq
; a version of EDSL.if_then_else
more practical for sequences/imperative code.
Genspio.EDSL.(
(* With a 🐱: *)
let original = byte_array "one\ntwo\nth\000ree\n" in
let full_cycle = original >> exec ["cat"] |> output_as_string in
if_seq
Byte_array.(full_cycle =$= original)
~t:[
exec ["echo"; "They are the same"];
]
~e:[
exec ["echo"; "They are NOT the same"];
]
)
Pretty-printed:
(if
(string-eq
(as-string
((string "one\ntwo\nth\000ree\n") >>
(exec (byte-array-to-c-string (string "cat")))))
(string "one\ntwo\nth\000ree\n"))
then: (seq
(exec (byte-array-to-c-string (string "echo"))
(byte-array-to-c-string (string "They are the same"))))
else: (seq
(exec (byte-array-to-c-string (string "echo"))
(byte-array-to-c-string (string "They are NOT the same")))))
Running it succeeds.
Standard output:
They are the same