Skip to content

Commit

Permalink
Finished implementation of "piqi getopt" command; added tests and exa…
Browse files Browse the repository at this point in the history
…mples.
  • Loading branch information
alavrik committed Jan 13, 2011
1 parent 31c01b5 commit 2e16c51
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 90 deletions.
2 changes: 2 additions & 0 deletions examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ test_complex:
./test_piqi addressbook.proto
./test_piq addressbook

./test_getopt


clean:
rm -f *.pb *.wire *.json *.proto* addressbook.*
92 changes: 92 additions & 0 deletions examples/test_getopt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/bin/sh

set -ex

#
# pretty-printing args as Piq AST
#

piqi getopt # empty input
piqi getopt -- # empty input

piqi getopt -- foo
piqi getopt -- 10 -20 30.0 -0.inf 0.nan '"foo\r"' '"\xff"' -fum [ -foo bar [] ] -baz


#
# converting args to Piq objects
#
# NOTE: converting to encodings other than Piq (controlled by -t parameter) is
# tested as a part of "piqi convert" testing as they share the same
# functionality
#

# built-in types

piqi getopt --piqtype bool -- true
piqi getopt --piqtype int -- -10
piqi getopt --piqtype float -- -0.inf

piqi getopt --piqtype string -- foo # parsing words as strings
piqi getopt --piqtype string -- foo\ bar
piqi getopt --piqtype string -- '"\tfoo\x20\u0045"'
piqi getopt --piqtype string -- "привет"
piqi getopt --piqtype binary -- '"\x00ab\tcd\xff\xfe"'

piqi getopt --piqtype piq-word -- foo-bar
piqi getopt --piqtype piq-any -- 10 -20 30.0 -0.inf 0.nan '"foo\r"' '"\xff"' -fum [ -foo bar [] ] -baz
#NOTE: piq-text is not supported

# complex types

piqi getopt --piqtype complex/t -- [ .re 0 .im 0 ]
piqi getopt --piqtype complex/t -- .re 0 .im 0
piqi getopt --piqtype complex/t -- -re 0 -im 0
piqi getopt --piqtype complex/t -- 0 0
piqi getopt --piqtype complex/foo -- []
piqi getopt --piqtype complex/foo -- [ ]
piqi getopt --piqtype complex/foo --add-defaults -- [ ]

piqi getopt --piqtype def/r -- -i 0 -flag
piqi getopt --piqtype def/r -- -i 0 -flag
piqi getopt --piqtype def/r -- -i 0 -flag

piqi getopt --piqtype def/int-list -- []
piqi getopt --piqtype def/int-list -- [ 1 2 3 4 5 ]
piqi getopt --piqtype def/int-list -- 1 2 3 4 5
piqi getopt --piqtype def/int-list-list -- [ [] [ 1 2 3 ] ]
piqi getopt --piqtype def/int-list-list -- [] [ 1 2 3 ]

piqi getopt --piqtype record-variant-list/r -- -a 0 -b 1
piqi getopt --piqtype record-variant-list/l -- -a 0 -b 1
piqi getopt --piqtype record-variant-list/v -- -a 0
piqi getopt --piqtype record-variant-list/v -- -b 1

piqi getopt --piqtype person/person -- \
-name "J. Random Hacker" \
-id 0 \
-email "[email protected]" \
-phone [ -number "(111) 123 45 67" ] \
-phone [ \
-number "(222) 123 45 67" \
-mobile \
] \
-phone [ \
-number "(333) 123 45 67" \
-work \
]

piqi getopt --piqtype person/person -- \
.name "Joe User" \
.id 1 \
.phone [ "(444) 123 45 67" ] \
.phone [ "(555) 123 45 67" .work ]


piqi getopt --piqtype function/bar-input -- [ 10 ]
piqi getopt --piqtype function/bar-output -- 1
piqi getopt --piqtype function/bar-error -- 100.0

piqi getopt --piqtype function/baz-input -- []
piqi getopt --piqtype function/baz-input --add-defaults -- []

8 changes: 2 additions & 6 deletions piqi/piq.ml
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ let read_piq_ast piq_parser :T.ast =
| None -> raise EOF


let piqobj_of_ast ?piqtype ast :Piqobj.obj =
Piqobj_of_piq.parse_typed_obj ast ?piqtype


let default_piqtype = ref None


Expand Down Expand Up @@ -100,12 +96,12 @@ let rec load_piq_obj piq_parser :obj =
| `typename x ->
error x "invalid piq object"
| `typed _ ->
let obj = piqobj_of_ast ast in
let obj = Piqobj_of_piq.parse_typed_obj ast in
Typed_piqobj obj
| _ ->
match !default_piqtype with
| Some piqtype ->
let obj = piqobj_of_ast ~piqtype ast in
let obj = Piqobj_of_piq.parse_obj piqtype ast in
Piqobj obj
| None ->
error ast "type of object is unknown"
Expand Down
49 changes: 24 additions & 25 deletions piqi/piq_parser.ml
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,17 @@ let make_any ast =
Piqloc.addrefret ast res


let check_name loc n =
let check_name n =
(* XXX: this should refer to piq rather than piqi name *)
if Piqi_name.is_valid_name n ~allow:"."
then ()
else error_at loc ("invalid name: " ^ quote n)
else error n ("invalid name: " ^ quote n)


let check_typename loc n =
let check_typename n =
if Piqi_name.is_valid_typename n ~allow:"."
then ()
else error_at loc ("invalid type name: " ^ quote n)
else error n ("invalid type name: " ^ quote n)


let piq_addrefret dst (src:T.ast) =
Expand Down Expand Up @@ -127,52 +127,50 @@ let piq_reference f x =
else piq_addrefret x res


let make_named loc n v :T.ast =
check_name loc n;
let make_named n v :T.ast =
check_name n;
match v with
| None -> `name n
| Some v ->
let res = T.Named#{name = n; value = v} in
Piqloc.addloc loc res;
Piqloc.addref n res;
`named res


let make_typed loc n v :T.ast =
check_typename loc n;
let make_typed n v :T.ast =
check_typename n;
match v with
| None -> `typename n
| Some v ->
let res = T.Typed#{typename = n; value = make_any v} in
Piqloc.addloc loc res;
Piqloc.addref n res;
`typed res


let make_named_or_typed c loc n v =
Piqloc.addloc loc n;
let make_named_or_typed c name n v =
Piqloc.addref name n;
let res =
match c with
| "." -> make_named loc n v
| ":" -> make_typed loc n v
| "." -> make_named n v
| ":" -> make_typed n v
| _ -> assert false
in
Piqloc.addlocret loc res
Piqloc.addrefret name res


(* TODO: adjust locations according to the name component's offset *)
let expand_name obj c n v =
if not (String.contains n '.') && not (String.contains n ':')
let expand_name obj c name value =
if not (String.contains name '.') && not (String.contains name ':')
then obj
else
let loc = Piqloc.find n in (* TODO: optimize *)
let rec aux = function
| [c; n] ->
make_named_or_typed c loc n v
make_named_or_typed c name n value
| c::n::t ->
let v = aux t in
make_named_or_typed c loc n (Some v)
make_named_or_typed c name n (Some v)
| _ -> assert false
in
aux (tokenize_name c n)
aux (tokenize_name c name)


let expand_obj_names (obj :T.ast) :T.ast =
Expand Down Expand Up @@ -391,7 +389,7 @@ let read_next ?(expand_abbr=true) (fname, lexstream) =
let text = parse_text line text in
Piqloc.addloc text_loc text;
Piqloc.addret (`text text)
| L.EOF -> error "unexpected end of file"
| L.EOF -> error "unexpected end of input"

(* TODO, XXX: move this functionality to the lexer *)
(* join adjacent text lines *)
Expand Down Expand Up @@ -485,7 +483,7 @@ let read_next ?(expand_abbr=true) (fname, lexstream) =
(* cut the first character which is '.' or ':' *)
let n = String.sub s 1 (String.length s - 1) in
Piqloc.addloc loc n;
let res = make_f loc n (parse_named_part ()) in
let res = make_f n (parse_named_part ()) in
(*
let res = expand_obj_names res in
*)
Expand All @@ -497,7 +495,8 @@ let read_next ?(expand_abbr=true) (fname, lexstream) =
(* name delimiters *)
| L.Word s when s.[0] = '.' || s.[0] = ':' -> (* other name or type *)
None
| L.Rbr | L.Rpar -> (* closing parenthesis or bracket *)
| L.Rbr | L.Rpar (* closing parenthesis or bracket *)
| L.EOF -> (* end of input *)
None
(* something else *)
| _ ->
Expand Down
96 changes: 52 additions & 44 deletions piqi/piqi_convert.ml
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,20 @@ let speclist = Main.common_speclist @
]


let find_piqtype typename =
if not (Piqi_name.is_valid_typename typename)
then
piqi_error ("invalid type name: " ^ typename);

try Piqi_db.find_piqtype typename
with Not_found ->
piqi_error ("unknown type: " ^ typename)


let get_piqtype typename =
if typename = "piqi" (* special case *)
then !Piqi.piqi_def (* return Piqi type from embedded self-definition *)
else (
if not (Piqi_name.is_valid_typename typename)
then
piqi_error ("invalid type name: " ^ typename);

try Piqi_db.find_piqtype typename
with Not_found ->
piqi_error ("unknown type: " ^ typename)
)
else find_piqtype typename


let do_load_piqi fname =
Expand Down Expand Up @@ -135,15 +137,15 @@ let make_reader load_f input_param =
(fun () -> load_f input_param)


let init_json_writer enc =
let init_json_writer () =
Piqi_json.init ();
(* XXX: We need to resolve all defaults before converting to JSON
* since it is a dynamic encoding *)
flag_add_defaults := true;
()


let init_json_reader enc =
let init_json_reader () =
Piqi_json.init ();
if !typename <> ""
then
Expand All @@ -152,34 +154,34 @@ let init_json_reader enc =
else ()


let get_reader = function
| "pb" when !typename = "" ->
piqi_error "--piqtype parameter must be specified for \"pb\" input encoding"
| "pb" ->
let piqtype = get_piqtype !typename in
let wireobj = Piq.open_pb !ifile in
make_reader (load_pb piqtype) wireobj
| "json" | "piq-json" ->
init_json_reader ();
let json_parser = Piqi_json.open_json !ifile in
make_reader Piq.load_json_obj json_parser
| _ when !typename <> "" ->
piqi_error "--piqtype parameter is applicable only to \"pb\" or \"json\" input encodings"
| "piq" ->
let piq_parser = Piq.open_piq !ifile in
make_reader Piq.load_piq_obj piq_parser
| "piqi" ->
make_reader load_piqi !ifile
| "wire" ->
let buf = Piq.open_wire !ifile in
make_reader Piq.load_wire_obj buf
| _ ->
piqi_error "unknown input encoding"


let get_writer input_encoding =
let is_piqi_input = (input_encoding = "piqi") in
match !output_encoding with
let make_reader input_encoding =
match input_encoding with
| "pb" when !typename = "" ->
piqi_error "--piqtype parameter must be specified for \"pb\" input encoding"
| "pb" ->
let piqtype = get_piqtype !typename in
let wireobj = Piq.open_pb !ifile in
make_reader (load_pb piqtype) wireobj
| "json" | "piq-json" ->
init_json_reader ();
let json_parser = Piqi_json.open_json !ifile in
make_reader Piq.load_json_obj json_parser
| _ when !typename <> "" ->
piqi_error "--piqtype parameter is applicable only to \"pb\" or \"json\" input encodings"
| "piq" ->
let piq_parser = Piq.open_piq !ifile in
make_reader Piq.load_piq_obj piq_parser
| "piqi" ->
make_reader load_piqi !ifile
| "wire" ->
let buf = Piq.open_wire !ifile in
make_reader Piq.load_wire_obj buf
| _ ->
piqi_error "unknown input encoding"


let make_writer ?(is_piqi_input=false) output_encoding =
match output_encoding with
| "" (* default output encoding is "piq" *)
| "piq" -> Piq.write_piq
| "wire" -> Piq.write_wire
Expand All @@ -188,10 +190,10 @@ let get_writer input_encoding =
Piq.write_json is_piqi_input
| "piq-json" ->
init_json_writer ();
output_encoding := "json";
Piq.write_piq_json
| "pb" -> write_pb is_piqi_input
| _ -> piqi_error "unknown output encoding"
| _ ->
piqi_error "unknown output encoding"


let seen = ref [] (* the list of seen elements *)
Expand Down Expand Up @@ -289,14 +291,20 @@ let convert_file () =
else Piqi_file.get_extension !ifile
in
validate_options input_encoding;
let reader = get_reader input_encoding in
let writer = get_writer input_encoding in
let reader = make_reader input_encoding in
let is_piqi_input = (input_encoding = "piqi") in
let writer = make_writer !output_encoding ~is_piqi_input in
(* open output file *)
let ofile =
match !ofile with
| "" when !output_encoding = "" -> "" (* print "piq" to stdout by default *)
| "" when !ifile <> "" && !ifile <> "-" ->
!ifile ^ "." ^ !output_encoding
let output_extension =
match !output_encoding with
| "piq-json" -> "json"
| x -> x
in
!ifile ^ "." ^ output_extension
| x -> x
in
let och = Main.open_output ofile in
Expand Down
Loading

0 comments on commit 2e16c51

Please sign in to comment.