Skip to content

Instantly share code, notes, and snippets.

@smondet
Last active December 6, 2017 22:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smondet/876345dbde7405a86b432d6fbd2c2e7b to your computer and use it in GitHub Desktop.
Save smondet/876345dbde7405a86b432d6fbd2c2e7b to your computer and use it in GitHub Desktop.

EDSL Usage Examples

The following examples show gradually complex uses of the EDSL.

Exec

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.

Exec with Comment

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.

Failure with Comment

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`]

Call a command with C-Strings

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

C-String Compilation Failure

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"]

Playing with the output of a command

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

Feeding a string to a command's stdin

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

Comparing byte-arrays, using conditionals

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

@smondet
Copy link
Author

smondet commented Dec 6, 2017

genspio-godot

@smondet
Copy link
Author

smondet commented Dec 6, 2017

genspio-godot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment