Skip to content

Commit

Permalink
Merge pull request #16 from mbarbin/stdlib.arg
Browse files Browse the repository at this point in the history
Stdlib.arg
  • Loading branch information
mbarbin authored Nov 13, 2024
2 parents 7d7b1ed + 5b4fce3 commit c7ab7d4
Show file tree
Hide file tree
Showing 55 changed files with 2,164 additions and 199 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
"cmdlang",
"cmdliner",
"conv",
"groff",
"janestreet",
"odoc",
"opam",
"stdune",
"stringable"
]
}
}
16 changes: 16 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## 0.0.8 (unreleased)

### Added

- Add a new backend based on `stdlib.arg`.

### Changed

### Deprecated

### Fixed

### Removed

- Remove `Param.assoc`. We require now the `to_string` function found in `Enums`.

## 0.0.7 (2024-11-10)

### Removed
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ We initiated the library as part of another project where we are migrating some
- Convert `cmdlang` parsers at runtime into `cmdliner`, `core.command`, or `climate` parsers
- Packaged as separate helper libraries to keep dependencies isolated.

4. **Basic execution runner based on stdlib.arg**:
- A proof-of-concept execution engine implemented on top of `stdlib.arg`.

## Experimental Status

`cmdlang` is currently under construction and considered experimental. We are actively seeking feedback to validate our design and engage with other declarative command-line enthusiasts.
Expand Down
30 changes: 30 additions & 0 deletions cmdlang-stdlib-runner.opam
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
synopsis: "A basic execution runner for cmdlang based on stdlib.arg"
maintainer: ["Mathieu Barbin <[email protected]>"]
authors: ["Mathieu Barbin"]
license: "MIT"
homepage: "https://github.com/mbarbin/cmdlang"
doc: "https://mbarbin.github.io/cmdlang/"
bug-reports: "https://github.com/mbarbin/cmdlang/issues"
depends: [
"dune" {>= "3.16"}
"ocaml" {>= "4.14"}
"cmdlang" {= version}
"odoc" {with-doc}
]
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/mbarbin/cmdlang.git"
1 change: 1 addition & 0 deletions cmdlang-tests.opam
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ depends: [
"cmdlang-to-base" {= version}
"cmdlang-to-climate" {= version}
"cmdlang-to-cmdliner" {= version}
"cmdlang-stdlib-runner" {= version}
"cmdliner" {>= "1.3.0"}
"core" {>= "v0.17" & < "v0.18"}
"core_unix" {>= "v0.17" & < "v0.18"}
Expand Down
7 changes: 7 additions & 0 deletions doc/docs/explanation/future_plans.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ However, we have a good intuition that by reducing some of the expressiveness of
- [x] Develop a strategy for translating positional arguments in `core.command` (Completed: Aug 2024)
- [x] Implement left-to-right order enforcement for positional arguments when compiling to `core.command` (Completed: Aug 2024)

## Targeting stdlib.arg as a runner

We'd like to write a mini-compiler targeting `stdlib.arg` as a proof-of-concept showing that it is possible to implement an execution runner for cmdlang that reuses the parsing engine implemented in the standard library.

### Tasks
- [x] Implemented an execution engine for cmdlang based on `stdlib.arg` (Completed: Nov 2024)

## Generation of Complex Man Pages

Another area of focus is the generation of complex man pages. `cmdliner` has excellent support for these. Currently, we have added basic support for one-line summaries of help messages to get started. However, we believe we could reuse most of the design of `cmdliner` and add it as optional information to the specification language.
Expand Down
2 changes: 1 addition & 1 deletion doc/docs/tutorials/getting-started/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ let () =
Getting_started.cmd
~name:"my-calculator"
~version:"%%VERSION%%")
|> Stdlib.exit
|> exit
;;
```

Expand Down
2 changes: 1 addition & 1 deletion doc/docs/tutorials/getting-started/bin/main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ let () =
Getting_started.cmd
~name:"my-calculator"
~version:"%%VERSION%%")
|> Stdlib.exit
|> exit
;;
11 changes: 11 additions & 0 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@
(cmdlang
(= :version))))

(package
(name cmdlang-stdlib-runner)
(synopsis "A basic execution runner for cmdlang based on stdlib.arg")
(depends
(ocaml
(>= 4.14))
(cmdlang
(= :version))))

(package
(name cmdlang-tests)
(synopsis "Tests for cmdlang")
Expand Down Expand Up @@ -133,6 +142,8 @@
(= :version))
(cmdlang-to-cmdliner
(= :version))
(cmdlang-stdlib-runner
(= :version))
(cmdliner
(>= 1.3.0))
(core
Expand Down
10 changes: 3 additions & 7 deletions lib/cmdlang/src/command.ml
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,10 @@ module Param = struct
let bool = Ast.Param.Bool
let file = Ast.Param.File

let assoc ?docv choices =
match choices with
| [] -> invalid_arg "Command.Param.assoc"
| hd :: tl -> Ast.Param.Enum { docv; choices = hd :: tl }
;;

let enumerated (type a) ?docv (module M : Enumerated_stringable with type t = a) =
assoc ?docv (M.all |> List.map (fun m -> M.to_string m, m))
match M.all |> List.map (fun m -> M.to_string m, m) with
| [] -> invalid_arg "Command.Param.enumerated"
| hd :: tl -> Ast.Param.Enum { docv; choices = hd :: tl; to_string = M.to_string }
;;

let stringable (type a) ?docv (module M : Stringable with type t = a) =
Expand Down
8 changes: 7 additions & 1 deletion lib/cmdlang/src/command.mli
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ module type Enumerated_stringable = sig
type t

val all : t list

(** Due to the canonical string representation contract, cmdlang will assume
to be able to define an equality function between [t]s defined as such:
{[
let equal a b = phys_equal a b || String.equal (to_string a) (to_string b)
]} *)
val to_string : t -> string
end

Expand Down Expand Up @@ -116,7 +123,6 @@ module Param : sig

(** {1 Helpers} *)

val assoc : ?docv:string -> (string * 'a) list -> 'a t
val enumerated : ?docv:string -> (module Enumerated_stringable with type t = 'a) -> 'a t
val stringable : ?docv:string -> (module Stringable with type t = 'a) -> 'a t

Expand Down
17 changes: 14 additions & 3 deletions lib/cmdlang/test/test__command.ml
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
let%expect_test "Param.assoc" =
module Empty = struct
type t = |

let all = []

let to_string t =
match[@coverage off] t with
| (_ : t) -> .
;;
end

let%expect_test "Param.enumerated" =
let open Command.Std in
require_does_raise [%here] (fun () -> Param.assoc []);
[%expect {| (Invalid_argument Command.Param.assoc) |}];
require_does_raise [%here] (fun () -> Param.enumerated (module Empty));
[%expect {| (Invalid_argument Command.Param.enumerated) |}];
()
;;
9 changes: 8 additions & 1 deletion lib/cmdlang_ast/src/ast.ml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
type 'a parse = string -> ('a, [ `Msg of string ]) result
type 'a or_error_msg = ('a, [ `Msg of string ]) result
type 'a parse = string -> 'a or_error_msg
type 'a print = Format.formatter -> 'a -> unit

module Nonempty_list = struct
Expand All @@ -21,6 +22,7 @@ module Param = struct
| Enum :
{ docv : string option
; choices : (string * 'a) Nonempty_list.t
; to_string : 'a -> string
}
-> 'a t
| Comma_separated : 'a t -> 'a list t
Expand Down Expand Up @@ -124,4 +126,9 @@ module Command = struct
; subcommands : (string * 'a t) list
}
-> 'a t

let summary = function
| Make { summary; _ } -> summary
| Group { summary; _ } -> summary
;;
end
6 changes: 5 additions & 1 deletion lib/cmdlang_ast/src/ast.mli
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
[Cmdlang_ast] is exposed to allow extending the library with new backends or
to write analysis tools, etc. *)

type 'a parse := string -> ('a, [ `Msg of string ]) result
type 'a or_error_msg = ('a, [ `Msg of string ]) result
type 'a parse := string -> 'a or_error_msg
type 'a print := Format.formatter -> 'a -> unit

module Nonempty_list : sig
Expand All @@ -38,6 +39,7 @@ module Param : sig
| Enum :
{ docv : string option
; choices : (string * 'a) Nonempty_list.t
; to_string : 'a -> string
}
-> 'a t
| Comma_separated : 'a t -> 'a list t
Expand Down Expand Up @@ -141,4 +143,6 @@ module Command : sig
; subcommands : (string * 'a t) list
}
-> 'a t

val summary : _ t -> string
end
28 changes: 28 additions & 0 deletions lib/cmdlang_stdlib_runner/src/arg_runner.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
type 'a t =
| Value : 'a -> 'a t
| Map :
{ x : 'a t
; f : 'a -> 'b
}
-> 'b t
| Both : 'a t * 'b t -> ('a * 'b) t
| Apply :
{ f : ('a -> 'b) t
; x : 'a t
}
-> 'b t

let rec eval : type a. a t -> a =
fun (type a) (t : a t) : a ->
match t with
| Value a -> a
| Map { x; f } -> f (eval x)
| Both (a, b) ->
let a = eval a in
let b = eval b in
a, b
| Apply { f; x } ->
let f = eval f in
let x = eval x in
f x
;;
20 changes: 20 additions & 0 deletions lib/cmdlang_stdlib_runner/src/arg_runner.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(** Internal representation used to run a parser.
This is the final representation returned after all of the parsing phases
have completed, and is ready to run user code. *)

type 'a t =
| Value : 'a -> 'a t
| Map :
{ x : 'a t
; f : 'a -> 'b
}
-> 'b t
| Both : 'a t * 'b t -> ('a * 'b) t
| Apply :
{ f : ('a -> 'b) t
; x : 'a t
}
-> 'b t

val eval : 'a t -> 'a
Loading

0 comments on commit c7ab7d4

Please sign in to comment.