thrift_generator_semantic (thrift_generator v0.7.0)

View Source

Semantic analysis: turns documents loaded by thrift_generator_loader into the validated #tg_model{} IR consumed by the code emitter.

The pass numbers enum members and implicit field ids, resolves constant and enum references, merges inherited service functions and validates the result: duplicate names and field ids, union field requiredness, oneway function shapes, throw clauses pointing at exceptions, unresolved type references, typedef cycles and constant type mismatches. All errors are collected as {File, Loc, Message} triples before failing, where Loc is a line number or a {Line, Column} pair (whatever the error site knows).

Summary

Functions

Analyzes loaded documents (root first, as returned by the loader) into a model, or returns every validation error found.

Analyzes with invocation-wide options. Each axis applies only to definitions without an explicit annotation: repr (record, the default, map or native) is the representation for structures and exceptions without erl.struct_type, union_type (record or sum) is the union representation for unions without erl.union_type, set (list, the default, sets or ordset) is the set implementation for sets without erl.set, and typedef_type (alias, the default, or nominal) is the typedef flavor for typedefs without erl.type. A file-wide namespace default (erl.set, erl.union_type on the namespace header) overrides the option for its file.

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_semantic_opts()

-type generate_semantic_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() :: non_neg_integer() | {non_neg_integer(), non_neg_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.

sem_error()

-type sem_error() :: {File :: binary(), Loc :: loc(), Message :: binary()}.

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()}.

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

analyze(Loaded)

-spec analyze([#tg_loaded{name :: binary(),
                          prefix :: binary(),
                          path :: binary(),
                          includes :: [binary()],
                          doc :: ast_node()}]) ->
                 {ok,
                  #tg_model{root :: binary(),
                            modules ::
                                [#tg_module{name :: binary(),
                                            prefix :: binary(),
                                            path :: binary(),
                                            includes :: [binary()],
                                            structs ::
                                                [#tg_struct{kind :: struct | union | exception,
                                                            name :: binary(),
                                                            fields ::
                                                                [#tg_field{id :: integer(),
                                                                           required :: requiredness(),
                                                                           type :: thrift_type(),
                                                                           name :: binary(),
                                                                           default ::
                                                                               const_value() | undefined,
                                                                           doc :: doc()}],
                                                            erl :: erl_annotations(),
                                                            doc :: doc(),
                                                            line :: non_neg_integer(),
                                                            col :: non_neg_integer()}],
                                            enums ::
                                                [#tg_enum{name :: binary(),
                                                          values :: [{integer(), binary()}],
                                                          doc :: doc(),
                                                          line :: non_neg_integer(),
                                                          col :: non_neg_integer()}],
                                            typedefs ::
                                                [#tg_typedef{name :: binary(),
                                                             type :: thrift_type(),
                                                             erl :: erl_annotations(),
                                                             doc :: doc(),
                                                             line :: non_neg_integer(),
                                                             col :: non_neg_integer()}],
                                            consts ::
                                                [#tg_const{name :: binary(),
                                                           type :: thrift_type(),
                                                           value :: const_value(),
                                                           doc :: doc(),
                                                           line :: non_neg_integer(),
                                                           col :: non_neg_integer()}],
                                            services ::
                                                [#tg_service{name :: binary(),
                                                             extends :: binary() | undefined,
                                                             functions ::
                                                                 [#tg_function{name :: binary(),
                                                                               oneway :: boolean(),
                                                                               return_type ::
                                                                                   thrift_type() | void,
                                                                               params ::
                                                                                   [#tg_field{id ::
                                                                                                  integer(),
                                                                                              required ::
                                                                                                  requiredness(),
                                                                                              type ::
                                                                                                  thrift_type(),
                                                                                              name ::
                                                                                                  binary(),
                                                                                              default ::
                                                                                                  const_value() |
                                                                                                  undefined,
                                                                                              doc ::
                                                                                                  doc()}],
                                                                               throws ::
                                                                                   [#tg_field{id ::
                                                                                                  integer(),
                                                                                              required ::
                                                                                                  requiredness(),
                                                                                              type ::
                                                                                                  thrift_type(),
                                                                                              name ::
                                                                                                  binary(),
                                                                                              default ::
                                                                                                  const_value() |
                                                                                                  undefined,
                                                                                              doc ::
                                                                                                  doc()}],
                                                                               doc :: doc()}],
                                                             doc :: doc(),
                                                             line :: non_neg_integer(),
                                                             col :: non_neg_integer()}]}]}} |
                 {error, [sem_error()]}.

Analyzes loaded documents (root first, as returned by the loader) into a model, or returns every validation error found.

analyze/2

-spec analyze([#tg_loaded{name :: binary(),
                          prefix :: binary(),
                          path :: binary(),
                          includes :: [binary()],
                          doc :: ast_node()}],
              generate_semantic_opts()) ->
                 {ok,
                  #tg_model{root :: binary(),
                            modules ::
                                [#tg_module{name :: binary(),
                                            prefix :: binary(),
                                            path :: binary(),
                                            includes :: [binary()],
                                            structs ::
                                                [#tg_struct{kind :: struct | union | exception,
                                                            name :: binary(),
                                                            fields ::
                                                                [#tg_field{id :: integer(),
                                                                           required :: requiredness(),
                                                                           type :: thrift_type(),
                                                                           name :: binary(),
                                                                           default ::
                                                                               const_value() | undefined,
                                                                           doc :: doc()}],
                                                            erl :: erl_annotations(),
                                                            doc :: doc(),
                                                            line :: non_neg_integer(),
                                                            col :: non_neg_integer()}],
                                            enums ::
                                                [#tg_enum{name :: binary(),
                                                          values :: [{integer(), binary()}],
                                                          doc :: doc(),
                                                          line :: non_neg_integer(),
                                                          col :: non_neg_integer()}],
                                            typedefs ::
                                                [#tg_typedef{name :: binary(),
                                                             type :: thrift_type(),
                                                             erl :: erl_annotations(),
                                                             doc :: doc(),
                                                             line :: non_neg_integer(),
                                                             col :: non_neg_integer()}],
                                            consts ::
                                                [#tg_const{name :: binary(),
                                                           type :: thrift_type(),
                                                           value :: const_value(),
                                                           doc :: doc(),
                                                           line :: non_neg_integer(),
                                                           col :: non_neg_integer()}],
                                            services ::
                                                [#tg_service{name :: binary(),
                                                             extends :: binary() | undefined,
                                                             functions ::
                                                                 [#tg_function{name :: binary(),
                                                                               oneway :: boolean(),
                                                                               return_type ::
                                                                                   thrift_type() | void,
                                                                               params ::
                                                                                   [#tg_field{id ::
                                                                                                  integer(),
                                                                                              required ::
                                                                                                  requiredness(),
                                                                                              type ::
                                                                                                  thrift_type(),
                                                                                              name ::
                                                                                                  binary(),
                                                                                              default ::
                                                                                                  const_value() |
                                                                                                  undefined,
                                                                                              doc ::
                                                                                                  doc()}],
                                                                               throws ::
                                                                                   [#tg_field{id ::
                                                                                                  integer(),
                                                                                              required ::
                                                                                                  requiredness(),
                                                                                              type ::
                                                                                                  thrift_type(),
                                                                                              name ::
                                                                                                  binary(),
                                                                                              default ::
                                                                                                  const_value() |
                                                                                                  undefined,
                                                                                              doc ::
                                                                                                  doc()}],
                                                                               doc :: doc()}],
                                                             doc :: doc(),
                                                             line :: non_neg_integer(),
                                                             col :: non_neg_integer()}]}]}} |
                 {error, [sem_error()]}.

Analyzes with invocation-wide options. Each axis applies only to definitions without an explicit annotation: repr (record, the default, map or native) is the representation for structures and exceptions without erl.struct_type, union_type (record or sum) is the union representation for unions without erl.union_type, set (list, the default, sets or ordset) is the set implementation for sets without erl.set, and typedef_type (alias, the default, or nominal) is the typedef flavor for typedefs without erl.type. A file-wide namespace default (erl.set, erl.union_type on the namespace header) overrides the option for its file.