Improved architecture

This commit is contained in:
Denis Merigoux 2020-03-07 16:52:31 -08:00
parent 12cee7627b
commit 56bc45db9d
16 changed files with 206 additions and 81 deletions

View File

@ -1,6 +1,6 @@
(lang dune 1.10)
(name lawspec)
(version 1.0.2)
(version 0.1)
(generate_opam_files true)
(source (uri git+https://gitlab.inria.fr/verifisc/lawspec.git))
@ -22,6 +22,7 @@
(ANSITerminal (>= 0.8.2))
(sedlex (>= 2.1))
(menhirLib (>= 20200211))
(dune-build-info (>= 2.0.1))
(dune (and :build ))
)
)

View File

@ -11,7 +11,7 @@ authors: ["Denis Merigoux"]
bug-reports: "https://gitlab.inria.fr/verifisc/lawspec/issues"
homepage: "https://gitlab.inria.fr/verifisc/lawspec"
license: "Apache2"
version: "1.0.2"
version: "0.1"
dev-repo: "git+https://gitlab.inria.fr/verifisc/lawspec.git"
synopsis: "Low-level language for tax code specification"
description: """
@ -23,5 +23,6 @@ depends: [
"ANSITerminal" {>= "0.8.2"}
"sedlex" {>= "2.1"}
"menhirLib" {>= "20200211"}
"dune-build-info" {>= "2.0.1"}
"dune" {build}
]

View File

@ -1,9 +1,6 @@
(include_subdirs unqualified)
(executable
(name main)
(public_name lawspec)
(package lawspec)
(libraries ANSITerminal sedlex menhirLib re)
(preprocess (pps sedlex.ppx))
)
(name main)
(package lawspec)
(public_name lawspec)
(libraries lawspec)
(preprocess (pps sedlex.ppx)))

View File

@ -22,19 +22,67 @@ let source_files : string list ref = ref []
(** Prints debug information *)
let debug_flag = ref false
let parse_cli_args () =
(* Code block to retrieve and parse command-line arguments. *)
let speclist = Arg.align [
("--debug", Arg.Set debug_flag,
" Prints debugging information");
]
in let usage_msg =
"Parser and compiler for Lawspec."
in
let anon_func (file: string) : unit =
source_files := file::!source_files
in Arg.parse speclist anon_func usage_msg
open Cmdliner
let files = Arg.(non_empty & pos_all file [] & info [] ~docv:"FILES" ~doc:"Lawspec files to be compiled")
let debug = Arg.(value & flag & info [ "debug"; "d" ] ~doc:"Prints debug information")
let backend =
Arg.(
required
& opt (some string) None
& info [ "backend"; "b" ] ~docv:"BACKEND"
~doc:"Backend selection: TeX")
let output =
Arg.(
required
& opt (some string) None
& info [ "output"; "o" ] ~docv:"OUTPUT"
~doc:
"$(i, OUTPUT) is the file that will contain the extracted function (for compiler \
backends)")
let lawspec_t f =
Term.(const f $ files $ debug $ backend $ output)
let info =
let doc =
"Compiler for Lawspec, a specification language for tax and social benefits computation rules."
in
let man =
[
`S Manpage.s_description;
`P
"The M language is used by the DGFiP to encode the rules describing the computation of the \
French income tax. An M program consists in several *.m files in no particular order. \
$(tname) will parse all the rules contained in those files that correspond to a \
particular application tag. Then, it will extract from this set of rules an \
user-specified function, than can be interpreted with a command-line prompt or compiled \
to a function in the language of your choice.";
`S Manpage.s_authors;
`P "Denis Merigoux <denis.merigoux@inria.fr>";
`S Manpage.s_examples;
`P "Typical usage:";
`Pre "lawspec -b LaTeX file.lsp";
`S Manpage.s_bugs;
`P "Please file bug reports at https://gitlab.inria.fr/verifisc/lawspec/issues";
]
in
let exits =
Term.default_exits
@ [
Term.exit_info ~doc:"on parsing error." 1;
Term.exit_info ~doc:"on typechecking error." 2;
]
in
Term.info "lawspec"
~version:
( match Build_info.V1.version () with
| None -> "n/a"
| Some v -> Build_info.V1.Version.to_string v )
~doc ~exits ~man
(**{1 Terminal formatting }*)

53
src/lawspec/driver.ml Normal file
View File

@ -0,0 +1,53 @@
(*
This file is part of the Lawspec compiler, a specification language for tax and social benefits
computation rules.
Copyright (C) 2019 Inria, contributor: Denis Merigoux <denis.merigoux@inria.fr>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*)
open Cli
(** Entry function for the executable. Returns a negative number in case of error. *)
let driver
(source_files : string list)
(debug: bool)
(_backend: string)
(_output_file : string)
: int =
Cli.debug_flag := debug;
Cli.debug_print "Reading files...";
let program = ref [] in
List.iter (fun source_file ->
let input = open_in source_file in
Cli.debug_print (Printf.sprintf "Parsing %s" source_file);
let lexbuf = Sedlex_menhir.create_lexbuf ~file:(Filename.basename source_file) (Sedlexing.Utf8.from_channel input) in
try
Parse_utils.current_file := source_file;
let commands = Sedlex_menhir.sedlex_with_menhir Lexer.lexer Parser.source_file lexbuf in
program := commands::!program;
close_in input
with
| Errors.LexingError msg | Errors.ParsingError msg ->
error_print msg
| Sedlex_menhir.ParseError msg -> begin
error_print
(Printf.sprintf "Parser error: %s" msg);
close_in input;
exit (-1)
end
) source_files;
exit 0
let main () =
Cmdliner.Term.exit @@ Cmdliner.Term.eval (Cli.lawspec_t driver, Cli.info)

7
src/lawspec/dune Normal file
View File

@ -0,0 +1,7 @@
(include_subdirs unqualified)
(library
(public_name lawspec)
(libraries ANSITerminal sedlex menhirLib re cmdliner dune-build-info)
(preprocess (pps sedlex.ppx))
)

View File

@ -0,0 +1,37 @@
(*
This file is part of the Lawspec compiler, a specification language for tax and social benefits
computation rules.
Copyright (C) 2020 Inria, contributor: Denis Merigoux <denis.merigoux@inria.fr>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*)
(**
This modules weaves the source code and the legislative text together into a document
that law professionals can understand.
*)
module A = Ast
module P = Printf
let source_file_item_to_latex (i: A.source_file_item) : string =
match i with
| A.LawCode c -> P.sprintf "\\subsection{%s}" c
| A.LawText t -> t
| A.LawArticle a -> P.sprintf "\\paragraph{%s}" a
| A.CodeBlock -> "code"
let ast_to_latex (file : A.source_file) : string =
String.concat "\n\n" (List.map (fun i ->
source_file_item_to_latex i
) file )

View File

@ -16,4 +16,10 @@
limitations under the License.
*)
type source_file = unit
type source_file_item =
| LawCode of string
| LawArticle of string
| LawText of string
| CodeBlock
type source_file = source_file_item list

View File

@ -30,6 +30,7 @@ let rec lex_code lexbuf =
| '\n' -> update lexbuf ; new_line lexbuf; lex_code lexbuf
| ' ' | '\t' -> update lexbuf; lex_code lexbuf
| "*/" -> update lexbuf; is_code:= false; lex_law lexbuf
| "code" -> update lexbuf; CODE
| any -> update lexbuf; lex_code lexbuf
| _ -> raise_ParseError lexbuf
@ -39,6 +40,15 @@ and lex_law lexbuf =
| '\n' -> update lexbuf ; new_line lexbuf; lex_law lexbuf
| "/*" -> update lexbuf; is_code := true; lex_code lexbuf
| eof -> update lexbuf ; EOF
| "@@", Star white_space, Star (Compl '@'), Star white_space, "@@" ->
let extract_code_title =
R.regexp "@@\\s*([^#]*)\\s*@@"
in
let title = R.get_substring
(R.exec ~rex:extract_code_title (Sedlexing.Utf8.lexeme buf))
1
in
update lexbuf; LAW_CODE title
| "@", Star white_space, Star (Compl '@'), Star white_space, "@" ->
let extract_article_title =
R.regexp "@\\s*([^#]*)\\s*@"
@ -47,8 +57,9 @@ and lex_law lexbuf =
(R.exec ~rex:extract_article_title (Sedlexing.Utf8.lexeme buf))
1
in
update lexbuf; ARTICLE title
| any -> update lexbuf; lex_law lexbuf
update lexbuf; LAW_ARTICLE title
| Plus (Compl ('@' | '/' | '\n')) ->
update lexbuf; LAW_TEXT (Sedlexing.Utf8.lexeme buf)
| _ -> raise_ParseError lexbuf
let lexer lexbuf =

View File

@ -17,12 +17,14 @@
*)
%{
(** Module generated automaticcaly by Menhir, the parser generator *)
open Ast
%}
%token EOF
%token<string> ARTICLE
%token<string> LAW_ARTICLE
%token<string> LAW_CODE
%token<string> LAW_TEXT
%token CODE
%type <Ast.source_file> source_file
@ -31,8 +33,11 @@
%%
source_file_item:
| title = ARTICLE { Cli.debug_print title }
| title = LAW_ARTICLE { LawArticle title }
| code = LAW_CODE { LawCode code }
| text = LAW_TEXT { LawText text }
| CODE { CodeBlock }
source_file:
| source_file_item source_file { }
| EOF { }
| i = source_file_item f = source_file { i::f }
| EOF { [] }

View File

@ -1,49 +1,2 @@
(*
This file is part of the Lawspec compiler, a specification language for tax and social benefits
computation rules.
Copyright (C) 2019 Inria, contributor: Denis Merigoux <denis.merigoux@inria.fr>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*)
open Cli
(** Entry function for the executable. Returns a negative number in case of error. *)
let main () : int =
parse_cli_args ();
Cli.debug_print "Reading files...";
let program = ref [] in
List.iter (fun source_file ->
let input = open_in source_file in
Cli.debug_print (Printf.sprintf "Parsing %s" source_file);
let lexbuf = Sedlex_menhir.create_lexbuf ~file:(Filename.basename source_file) (Sedlexing.Utf8.from_channel input) in
try
Parse_utils.current_file := source_file;
let commands = Sedlex_menhir.sedlex_with_menhir Lexer.lexer Parser.source_file lexbuf in
program := commands::!program;
close_in input
with
| Errors.LexingError msg | Errors.ParsingError msg ->
error_print msg
| Sedlex_menhir.ParseError msg -> begin
error_print
(Printf.sprintf "Parser error: %s" msg);
close_in input;
exit (-1)
end
) !source_files;
exit 0
let _ =
source_files := ["test/simple.lsp"];
main ()
Lawspec.Driver.main ()

View File

@ -1,10 +1,16 @@
@@ Code de la sécurité sociale @@
@ Article L521-3 @
Blablabla
Blablabla, etc
dfl
1)
/*
code keyword
code
*/