thrift_generator (thrift_generator v0.7.0)

View Source

Front end of the Thrift IDL generator: turns IDL files into tokens and an AST of #thrift_generator_node{} records.

The pipeline is tokens/1 -> ast/1; parse_file/1 and parse_string/1 wrap both steps. parse_file/1 appends a synthetic __file__ marker to the source, which the grammar consumes after the document's definitions; the AST document itself carries only headers and definitions — module naming and include resolution work from the paths the loader tracks.

Summary

Functions

Parses a token list into a document AST node.

CI gate: verifies the generated sources are up to date without writing. Runs the same pipeline as generate/3 and requires every artifact to already exist in OutDir with the exact content this input would produce. Returns ok, or {error, {stale, Paths}} with the drifted (missing or differing) files.

Deletes the generator's files from OutDir: every .erl and .hrl whose second line carries the Autogenerated by Thrift Generator banner. The banner — not the current IDL — decides, so files left behind by drifted inputs (a removed service, a deleted IDL file) are cleaned up too, and anything not carrying the banner is left alone. Returns the deleted paths, or {error, {delete, Path, Reason}} after the first failing removal.

Full pipeline: load (with includes), semantic analysis, code emission, write to OutDir.

Reads, lexes and parses an IDL file in one step.

Lexes and parses an IDL snippet given as text, without a file marker.

Reads and lexes an IDL file, appending a __file__ marker with the path as given.

Types

annotations()

-type annotations() :: #{binary() := true | binary()}.

ast_node()

-type ast_node() ::
          #thrift_generator_node{line :: non_neg_integer(),
                                 col :: non_neg_integer(),
                                 doc :: doc(),
                                 annotations :: erl_annotations(),
                                 payload :: term(),
                                 type_module :: module()}.

base_type()

-type base_type() :: bool | i8 | i16 | i32 | i64 | double | string | binary | uuid.

const_value()

-type const_value() ::
          {ref, Name :: binary()} |
          boolean() |
          integer() |
          float() |
          binary() |
          {list, [const_value()]} |
          {map, [{const_value(), const_value()}]}.

constant()

-type constant() ::
          #thrift_generator_constant{name :: constant_name(),
                                     type :: thrift_type(),
                                     value :: const_value()}.

constant_name()

-nominal constant_name() :: binary().

cpp_include()

-type cpp_include() :: #thrift_generator_cpp_include{path :: include_path()}.

doc()

-type doc() :: binary() | undefined.

document()

-type document() :: #thrift_generator_document{headers :: [ast_node()], definitions :: [ast_node()]}.

enum_()

-type enum_() :: #thrift_generator_enum{name :: enum_name(), values :: [enum_value()]}.

enum_name()

-nominal enum_name() :: binary().

enum_value()

-type enum_value() :: {Name :: binary(), Value :: integer() | undefined, annotations(), doc()}.

erl_annotations()

-type erl_annotations() :: #{atom() := true | binary()}.

exception_()

-type exception_() :: #thrift_generator_exception{name :: exception_name(), fields :: [ast_node()]}.

exception_name()

-nominal exception_name() :: binary().

field_()

-type field_() ::
          #thrift_generator_field{id :: integer() | undefined,
                                  required :: requiredness(),
                                  type :: thrift_type(),
                                  name :: field_name(),
                                  default :: const_value() | undefined}.

field_name()

-nominal field_name() :: binary().

function_()

-type function_() ::
          #thrift_generator_function{oneway :: boolean(),
                                     return_type :: thrift_type() | void,
                                     name :: function_name(),
                                     fields :: [ast_node()],
                                     throws :: [ast_node()]}.

function_name()

-nominal function_name() :: binary().

generate_opts()

-type generate_opts() ::
          #{repr => record | map | native,
            union_type => record | sum,
            set => list | sets | ordset,
            typedef_type => alias | nominal}.

include_()

-type include_() :: #thrift_generator_include{path :: include_path()}.

include_path()

-nominal include_path() :: binary().

loc()

-type loc() :: pos_integer() | {pos_integer(), pos_integer()}.

namespace_()

-type namespace_() :: #thrift_generator_namespace{scope :: namespace_scope(), name :: namespace_name()}.

namespace_name()

-nominal namespace_name() :: binary().

namespace_scope()

-nominal namespace_scope() :: binary().

node_payload()

-type node_payload() ::
          document() |
          include_() |
          cpp_include() |
          namespace_() |
          constant() |
          typedef() |
          enum_() |
          struct_() |
          union_def() |
          exception_() |
          service() |
          function_() |
          field_().

requiredness()

-type requiredness() :: required | optional | default.

service()

-type service() ::
          #thrift_generator_service{name :: service_name(),
                                    extends :: service_parent() | undefined,
                                    functions :: [ast_node()]}.

service_name()

-nominal service_name() :: binary().

service_parent()

-nominal service_parent() :: binary().

struct_()

-type struct_() :: #thrift_generator_struct{name :: struct_name(), fields :: [ast_node()]}.

struct_name()

-nominal struct_name() :: binary().

thrift_type()

-type thrift_type() ::
          {base, base_type(), annotations()} |
          type_ref() |
          {list, Element :: thrift_type(), annotations()} |
          {set, Element :: thrift_type(), annotations()} |
          {map, Key :: thrift_type(), Value :: thrift_type(), annotations()}.

token()

-type token() :: {atom(), loc()} | {atom(), loc(), term()}.

type_ref()

-type type_ref() :: {ref, Name :: binary(), annotations()}.

typedef()

-type typedef() :: #thrift_generator_typedef{name :: typedef_name(), type :: thrift_type()}.

typedef_name()

-nominal typedef_name() :: binary().

union_def()

-type union_def() :: #thrift_generator_union{name :: union_name(), fields :: [ast_node()]}.

union_name()

-nominal union_name() :: binary().

Functions

ast(Tokens)

-spec ast([token()]) -> {ok, ast_node()} | {error, term()}.

Parses a token list into a document AST node.

check(ThriftFile, OutDir, Opts)

-spec check(file:filename_all(), file:filename_all(), generate_opts()) ->
               ok | {error, {stale, [file:filename_all()]}} | {error, term()}.

CI gate: verifies the generated sources are up to date without writing. Runs the same pipeline as generate/3 and requires every artifact to already exist in OutDir with the exact content this input would produce. Returns ok, or {error, {stale, Paths}} with the drifted (missing or differing) files.

clean(OutDir)

-spec clean(file:filename_all()) -> {ok, [file:filename_all()]} | {error, term()}.

Deletes the generator's files from OutDir: every .erl and .hrl whose second line carries the Autogenerated by Thrift Generator banner. The banner — not the current IDL — decides, so files left behind by drifted inputs (a removed service, a deleted IDL file) are cleaned up too, and anything not carrying the banner is left alone. Returns the deleted paths, or {error, {delete, Path, Reason}} after the first failing removal.

generate(ThriftFile, OutDir, Opts)

-spec generate(file:filename_all(), file:filename_all(), generate_opts()) ->
                  {ok, [#{module := module(), path := file:filename_all(), hrl => file:filename_all()}]} |
                  {error, term()}.

Full pipeline: load (with includes), semantic analysis, code emission, write to OutDir.

Writes one <module>.erl per generated module (types, and client/server/handler per service) and a <mod>_types.hrl next to every types module. Files whose on-disk content already matches are left untouched, so regenerating an unchanged IDL does not churn mtimes (and recompiles).

Opts carries the invocation-wide axes; each applies only to definitions without an explicit annotation of its own: repr (record, the default, map or native) for structures and exceptions without erl.struct_type, union_type (record or sum) for unions without erl.union_type, set (list, the default, sets or ordset) for sets without erl.set, and typedef_type (alias, the default, or nominal) for typedefs without erl.type. A file-wide namespace default overrides the option for its file.

Returns the generated modules with their paths (and the include path when one was written).

parse_file(Filename)

-spec parse_file(file:filename_all()) -> {ok, ast_node()} | {error, term()}.

Reads, lexes and parses an IDL file in one step.

parse_string(Snippet)

-spec parse_string(string() | binary()) -> {ok, ast_node()} | {error, term()}.

Lexes and parses an IDL snippet given as text, without a file marker.

tokens(Filename)

-spec tokens(file:filename_all()) ->
                {ok, [token()], loc()} | {error, {loc(), module(), term()} | term(), loc()}.

Reads and lexes an IDL file, appending a __file__ marker with the path as given.