Skip to content

Commit

Permalink
Merge pull request #214 from mransan/wip-typecheck-services
Browse files Browse the repository at this point in the history
typecheck and codegen for services
  • Loading branch information
c-cube authored Nov 27, 2023
2 parents a405e83 + c1c8392 commit 0b43d5f
Show file tree
Hide file tree
Showing 60 changed files with 1,887 additions and 276 deletions.
733 changes: 661 additions & 72 deletions benchs/benchs.ml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions benchs/dune
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(executable
(name benchs)
(ocamlopt_flags :standard -inline 100)
(foreign_stubs (language c) (flags :standard -std=c99 -O2) (names stubs))
(libraries ocaml-protoc benchmark))

(rule
Expand Down
1 change: 1 addition & 0 deletions benchs/foo.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ message Store {
message Company {
string name = 1;
repeated Store stores = 2;
repeated Company subsidiaries = 3;
}
80 changes: 80 additions & 0 deletions benchs/stubs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@

#include <caml/alloc.h>
#include <caml/memory.h>
#include <caml/mlvalues.h>
#include <stdbool.h>
#include <stdint.h>

inline int pbrt_varint_size(int64_t i) {
int n = 0;
while (1) {
n++;
int64_t cur = i & 0x7f;
if (cur == i)
break;
i = i >> 7;
}
return n;
}

// number of bytes for i
CAMLprim value caml_pbrt_varint_size(int64_t i) {
int res = pbrt_varint_size(i);
return Val_int(res);
}

CAMLprim value caml_pbrt_varint_size_byte(value v_i) {
CAMLparam1(v_i);

int64_t i = Int64_val(v_i);
int res = pbrt_varint_size(i);
CAMLreturn(Val_int(res));
}

// write i at str[idx…]
inline void pbrt_varint(unsigned char *str, int64_t i) {
while (true) {
int64_t cur = i & 0x7f;
if (cur == i) {
*str = (unsigned char)cur;
break;
} else {
*str = (unsigned char)(cur | 0x80);
i = i >> 7;
++str;
}
}
}

// let[@inline] varint (i : int64) (e : t) : unit =
// let n_bytes = varint_size i in
// let start = reserve_n e n_bytes in
//
// let i = ref i in
// for j = 0 to n_bytes - 1 do
// let cur = Int64.(logand !i 0x7fL) in
// if j = n_bytes - 1 then
// Bytes.set e.b (start + j) (Char.unsafe_chr Int64.(to_int cur))
// else (
// Bytes.set e.b (start + j)
// (Char.unsafe_chr Int64.(to_int (logor 0x80L cur)));
// i := Int64.shift_right_logical !i 7
// )
// done

// write `i` starting at `idx`
CAMLprim value caml_pbrt_varint(value _str, intnat idx, int64_t i) {
CAMLparam1(_str);
char *str = Bytes_val(_str);
pbrt_varint(str + idx, i);
CAMLreturn(Val_unit);
}

CAMLprim value caml_pbrt_varint_bytes(value _str, value _idx, value _i) {
CAMLparam3(_str, _idx, _i);
char *str = Bytes_val(_str);
int idx = Int_val(_idx);
int64_t i = Int64_val(_idx);
pbrt_varint(str + idx, i);
CAMLreturn(Val_unit);
}
16 changes: 12 additions & 4 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
(generate_opam_files true)
(version 2.4)

(maintainers "Maxime Ransan <[email protected]>")
(authors "Maxime Ransan <[email protected]>")
(maintainers "Maxime Ransan <[email protected]>" "Simon Cruanes")
(authors "Maxime Ransan <[email protected]>" "Simon Cruanes")
(source (github mransan/ocaml-protoc))
(license MIT)

Expand All @@ -20,7 +20,7 @@
(package
(name pbrt)
(synopsis "Runtime library for Protobuf tooling")
(depends
(depends
stdlib-shims
(odoc :with-doc)
(ocaml (>= 4.03)))
Expand All @@ -29,11 +29,19 @@
(package
(name pbrt_yojson)
(synopsis "Runtime library for ocaml-protoc to support JSON encoding/decoding")
(depends
(depends
(ocaml (>= 4.03))
(odoc :with-doc)
(yojson (>= 1.6))
base64)
(tags (protobuf encode decode)))

(package
(name pbrt_services)
(synopsis "Runtime library for ocaml-protoc to support RPC services")
(depends
(ocaml (>= 4.03))
(pbrt (= :version))
(pbrt_yojson (= :version)))
(tags (protobuf encode decode services rpc)))

4 changes: 2 additions & 2 deletions ocaml-protoc.opam
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
opam-version: "2.0"
version: "2.4"
synopsis: "Pure OCaml compiler for .proto files"
maintainer: ["Maxime Ransan <[email protected]>"]
authors: ["Maxime Ransan <[email protected]>"]
maintainer: ["Maxime Ransan <[email protected]>" "Simon Cruanes"]
authors: ["Maxime Ransan <[email protected]>" "Simon Cruanes"]
license: "MIT"
tags: ["protoc" "protobuf" "codegen"]
homepage: "https://github.com/mransan/ocaml-protoc"
Expand Down
4 changes: 2 additions & 2 deletions pbrt.opam
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
opam-version: "2.0"
version: "2.4"
synopsis: "Runtime library for Protobuf tooling"
maintainer: ["Maxime Ransan <[email protected]>"]
authors: ["Maxime Ransan <[email protected]>"]
maintainer: ["Maxime Ransan <[email protected]>" "Simon Cruanes"]
authors: ["Maxime Ransan <[email protected]>" "Simon Cruanes"]
license: "MIT"
tags: ["protobuf" "encode" "decode"]
homepage: "https://github.com/mransan/ocaml-protoc"
Expand Down
31 changes: 31 additions & 0 deletions pbrt_services.opam
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
version: "2.4"
synopsis: "Runtime library for ocaml-protoc to support RPC services"
maintainer: ["Maxime Ransan <[email protected]>" "Simon Cruanes"]
authors: ["Maxime Ransan <[email protected]>" "Simon Cruanes"]
license: "MIT"
tags: ["protobuf" "encode" "decode" "services" "rpc"]
homepage: "https://github.com/mransan/ocaml-protoc"
bug-reports: "https://github.com/mransan/ocaml-protoc/issues"
depends: [
"dune" {>= "2.0"}
"ocaml" {>= "4.03"}
"pbrt" {= version}
"pbrt_yojson" {= version}
]
build: [
["dune" "subst"] {pinned}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/mransan/ocaml-protoc.git"
4 changes: 2 additions & 2 deletions pbrt_yojson.opam
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ opam-version: "2.0"
version: "2.4"
synopsis:
"Runtime library for ocaml-protoc to support JSON encoding/decoding"
maintainer: ["Maxime Ransan <[email protected]>"]
authors: ["Maxime Ransan <[email protected]>"]
maintainer: ["Maxime Ransan <[email protected]>" "Simon Cruanes"]
authors: ["Maxime Ransan <[email protected]>" "Simon Cruanes"]
license: "MIT"
tags: ["protobuf" "encode" "decode"]
homepage: "https://github.com/mransan/ocaml-protoc"
Expand Down
4 changes: 2 additions & 2 deletions src/compilerlib/dune
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
(synopsis "Compiler library for ocaml-protoc, to turn .proto files into OCaml code")
(wrapped true)
(modules pb_codegen_all pb_codegen_backend pb_codegen_decode_binary pb_codegen_decode_bs
pb_codegen_decode_yojson pb_codegen_default pb_codegen_encode_binary
pb_codegen_decode_yojson pb_codegen_default pb_codegen_make pb_codegen_encode_binary
pb_codegen_encode_bs pb_codegen_encode_yojson pb_codegen_formatting
pb_codegen_ocaml_type pb_codegen_pp pb_codegen_plugin pb_codegen_types
pb_codegen_ocaml_type pb_codegen_pp pb_codegen_plugin pb_codegen_types pb_codegen_services
pb_codegen_util pb_exception pb_field_type pb_location pb_logger pb_option
pb_parsing pb_parsing_lexer pb_parsing_parser pb_parsing_parse_tree
pb_parsing_util pb_typing_graph pb_typing pb_typing_recursion
Expand Down
48 changes: 40 additions & 8 deletions src/compilerlib/pb_codegen_all.ml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
(*
The MIT License (MIT)
Copyright (c) 2016 Maxime Ransan <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
Expand All @@ -29,6 +29,7 @@ module F = Pb_codegen_formatting
module Plugin = Pb_codegen_plugin

type codegen_f = Plugin.codegen_f
type codegen_service_f = Ot.service -> F.scope -> unit

type ocaml_mod = {
ml: F.scope;
Expand Down Expand Up @@ -88,16 +89,32 @@ let generate_for_all_types (ocaml_types : Ot.type_ list list) (sc : F.scope)
())
ocaml_types

let generate_for_all_services (services : Ot.service list) (sc : F.scope)
(f : codegen_service_f) ocamldoc_title : unit =
(match ocamldoc_title with
| None -> ()
| Some ocamldoc_title ->
F.empty_line sc;
F.linep sc "(** {2 %s} *)" ocamldoc_title;
F.empty_line sc);

List.iter (fun (service : Ot.service) -> f service sc) services

let generate_type_and_default (self : ocaml_mod) ocaml_types : unit =
generate_for_all_types ocaml_types self.ml Pb_codegen_types.gen_struct None;
generate_for_all_types ocaml_types self.ml Pb_codegen_default.gen_struct None;

generate_for_all_types ocaml_types self.mli Pb_codegen_types.gen_sig
(Some Pb_codegen_types.ocamldoc_title);
generate_for_all_types ocaml_types self.mli Pb_codegen_default.gen_sig
(Some Pb_codegen_default.ocamldoc_title);
()

let generate_make (self : ocaml_mod) ocaml_types : unit =
generate_for_all_types ocaml_types self.ml Pb_codegen_make.gen_struct
(Some Pb_codegen_make.ocamldoc_title);
generate_for_all_types ocaml_types self.mli Pb_codegen_make.gen_sig
(Some Pb_codegen_make.ocamldoc_title)

let generate_mutable_records (self : ocaml_mod) ocaml_types : unit =
let ocaml_types = List.flatten ocaml_types in
List.iter
Expand All @@ -111,6 +128,17 @@ let generate_mutable_records (self : ocaml_mod) ocaml_types : unit =
| _ -> ())
ocaml_types

let generate_service_struct service sc : unit =
Pb_codegen_services.gen_service_struct service sc

let generate_service_sig service sc : unit =
Pb_codegen_services.gen_service_sig service sc

let generate_services (self : ocaml_mod) services : unit =
generate_for_all_services services self.ml generate_service_struct None;
generate_for_all_services services self.mli generate_service_sig
(Some "Services")

let generate_plugin (self : ocaml_mod) ocaml_types (p : Plugin.t) : unit =
let (module P) = p in
F.line self.ml "[@@@ocaml.warning \"-27-30-39\"]";
Expand All @@ -119,11 +147,15 @@ let generate_plugin (self : ocaml_mod) ocaml_types (p : Plugin.t) : unit =
generate_for_all_types ocaml_types self.mli P.gen_sig (Some P.ocamldoc_title);
()

let codegen ocaml_types ~proto_file_options ~proto_file_name
(plugins : Plugin.t list) : ocaml_mod =
let codegen (proto : Ot.proto) ~generate_make:gen_make ~proto_file_options
~proto_file_name (plugins : Plugin.t list) : ocaml_mod =
let self = new_ocaml_mod ~proto_file_options ~proto_file_name () in
generate_type_and_default self ocaml_types;
generate_type_and_default self proto.proto_types;
if List.exists Pb_codegen_plugin.requires_mutable_records plugins then
generate_mutable_records self ocaml_types;
List.iter (generate_plugin self ocaml_types) plugins;
generate_mutable_records self proto.proto_types;
if gen_make then generate_make self proto.proto_types;
List.iter (generate_plugin self proto.proto_types) plugins;

(* services come last, they need binary and json *)
generate_services self proto.proto_services;
self
3 changes: 2 additions & 1 deletion src/compilerlib/pb_codegen_all.mli
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ type ocaml_mod = {
}

val codegen :
Ot.type_ list list ->
Ot.proto ->
generate_make:bool ->
proto_file_options:Pb_option.set ->
proto_file_name:string ->
Plugin.t list ->
Expand Down
Loading

0 comments on commit 0b43d5f

Please sign in to comment.