Add menhir support (#42)
Adds the menhir stanza which desugars into a Rule.t with Support for: * ocamlyacc like use * modular parsers with --base * passing extra flags Also add tests and documentation.
This commit is contained in:
parent
4c3036b3cc
commit
3e3d92c9e5
|
@ -501,7 +501,6 @@ dependencies. See the [[User actions][actions section]] for more details.
|
|||
(deps (<name>.mll))
|
||||
(action (chdir ${ROOT} (run ${bin:ocamllex} -q -o ${<})))))
|
||||
#+end_src
|
||||
|
||||
**** ocamlyacc
|
||||
|
||||
=(ocamlyacc (<names>))= is essentially a shorthand for:
|
||||
|
@ -513,6 +512,32 @@ dependencies. See the [[User actions][actions section]] for more details.
|
|||
(action (chdir ${ROOT} (run ${bin:ocamlyacc} ${<})))))
|
||||
#+end_src
|
||||
|
||||
**** menhir
|
||||
|
||||
The basic form for defining menhir parsers (analogous to ocamlyacc):
|
||||
|
||||
#+begin_src scheme
|
||||
(menhir
|
||||
((modules (<parser1> <parser2> ...))))
|
||||
#+end_src
|
||||
|
||||
Modular parsers (--base flag) can be defined by adding the =merge_into= option.
|
||||
With this option, a single parser named =base_name= is generated.
|
||||
|
||||
#+begin_src scheme
|
||||
(menhir
|
||||
((merge_into <base_name>)
|
||||
(modules (<parser1> <parser2> ...))))
|
||||
#+end_src
|
||||
|
||||
Extra flags can be passed to menhir using the =flags= option:
|
||||
|
||||
#+begin_src scheme
|
||||
(menhir
|
||||
((flags (<option1> <option2> ...))
|
||||
(modules (<parser1> <parser2> ...))))
|
||||
#+end_src
|
||||
|
||||
**** alias
|
||||
|
||||
The =alias= stanza lets you add dependencies to an alias, or specify
|
||||
|
|
|
@ -678,6 +678,59 @@ module Rule = struct
|
|||
let ocamlyacc_vjs = ocamlyacc_v1
|
||||
end
|
||||
|
||||
module Menhir = struct
|
||||
type t =
|
||||
{ base : string option
|
||||
; flags : String_with_vars.t list
|
||||
; modules: string list
|
||||
}
|
||||
|
||||
let v1 =
|
||||
record
|
||||
(field_o "merge_into" string >>= fun base ->
|
||||
field "flags" (list String_with_vars.t) ~default:[] >>= fun flags ->
|
||||
field "modules" (list string) >>= fun modules ->
|
||||
return
|
||||
{ base
|
||||
; flags
|
||||
; modules
|
||||
}
|
||||
)
|
||||
|
||||
let v1_to_rule t =
|
||||
let str s = String_with_vars.of_string s in
|
||||
let targets n = [n ^ ".ml"; n ^ ".mli"] in
|
||||
match t.base with
|
||||
| None ->
|
||||
List.map t.modules ~f:(fun name ->
|
||||
let src = name ^ ".mly" in
|
||||
{ Rule.
|
||||
targets = targets name
|
||||
; deps = [Dep_conf.File (str src)]
|
||||
; action =
|
||||
Chdir
|
||||
(str "${ROOT}",
|
||||
Run (str "${bin:menhir}",
|
||||
t.flags @ [str "${<}"]))
|
||||
})
|
||||
| Some base ->
|
||||
let mly m = str (m ^ ".mly") in
|
||||
[{ Rule.
|
||||
targets = targets base
|
||||
; deps = List.map ~f:(fun m -> Dep_conf.File (mly m)) t.modules
|
||||
; action =
|
||||
Chdir
|
||||
(str "${ROOT}",
|
||||
Run (str "${bin:menhir}",
|
||||
[ str "--base"
|
||||
; str base
|
||||
]
|
||||
@ t.flags
|
||||
@ (List.map ~f:mly t.modules))
|
||||
)
|
||||
}]
|
||||
end
|
||||
|
||||
module Provides = struct
|
||||
type t =
|
||||
{ name : string
|
||||
|
@ -752,6 +805,7 @@ module Stanza = struct
|
|||
; cstr "rule" (Rule.v1 @> nil) (fun x -> [Rule x])
|
||||
; cstr "ocamllex" (list string @> nil) (fun x -> rules (Rule.ocamllex_v1 x))
|
||||
; cstr "ocamlyacc" (list string @> nil) (fun x -> rules (Rule.ocamlyacc_v1 x))
|
||||
; cstr "menhir" (Menhir.v1 @> nil) (fun x -> rules (Menhir.v1_to_rule x))
|
||||
; cstr "install" (Install_conf.v1 @> nil) (fun x -> [Install x])
|
||||
; cstr "alias" (Alias_conf.v1 @> nil) (fun x -> [Alias x])
|
||||
(* Just for validation and error messages *)
|
||||
|
|
|
@ -26,6 +26,14 @@
|
|||
(run ${exe:run.exe} --
|
||||
${bin:jbuilder} build -j1 @install --root . --debug-dependency-path)))))
|
||||
|
||||
(alias
|
||||
((name runtest)
|
||||
(deps ((files_recursively_in workspaces/menhir)))
|
||||
(action
|
||||
(chdir workspaces/menhir
|
||||
(run ${exe:run.exe} --
|
||||
${bin:jbuilder} build -j1 test.exe --root . --debug-dependency-path)))))
|
||||
|
||||
;; This test define an installed "plop" with a "plop.ca-marche-pas"
|
||||
;; sub-package which depend on a library that doesn't exist.
|
||||
;;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
(jbuild_version 1)
|
||||
|
||||
(ocamllex (lexer1 lexer2))
|
||||
|
||||
(menhir
|
||||
((modules (test_menhir1))))
|
||||
|
||||
(menhir
|
||||
((merge_into test_base)
|
||||
(flags (--explain))
|
||||
(modules (tokens parser))))
|
||||
|
||||
(executables
|
||||
((names (test))))
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
open Test_menhir1
|
||||
}
|
||||
|
||||
rule lex = parse
|
||||
| 'c' { TOKEN 'c' }
|
||||
| eof { EOF }
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
open Test_base
|
||||
}
|
||||
|
||||
rule lex = parse
|
||||
| 'c' { TOKEN 'c' }
|
||||
| eof { EOF }
|
|
@ -0,0 +1,7 @@
|
|||
%start <char list> main
|
||||
|
||||
%%
|
||||
|
||||
main:
|
||||
| c = TOKEN EOF { [c] }
|
||||
| c = TOKEN xs = main { c :: xs }
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
let s = "foo bar baz"
|
||||
|
||||
let () =
|
||||
let lex1 = Lexing.from_string s in
|
||||
let lex2 = Lexing.from_string s in
|
||||
ignore (Test_menhir1.main Lexer1.lex lex1);
|
||||
ignore (Test_base.main Lexer2.lex lex2)
|
|
@ -0,0 +1,10 @@
|
|||
%token <char> TOKEN
|
||||
%token EOF
|
||||
|
||||
%start <char list> main
|
||||
|
||||
%%
|
||||
|
||||
main:
|
||||
| c = TOKEN EOF { [c] }
|
||||
| c = TOKEN xs = main { c :: xs }
|
|
@ -0,0 +1,5 @@
|
|||
%token <char> TOKEN
|
||||
%token EOF
|
||||
|
||||
%%
|
||||
|
Loading…
Reference in New Issue