Skip to content

Commit

Permalink
Return abstract errors in Golang (#490)
Browse files Browse the repository at this point in the history
We returned a concrete error pointer in the generated Golang code, which
can cause various bugs, see [this page in Golang documentation].

Instead, we generate the code such that only abstract `error`'s are
returned.

[this page in Golang documentation]: https://go.dev/doc/faq#nil_error
  • Loading branch information
mristin authored May 16, 2024
1 parent 3b20999 commit 6e15812
Show file tree
Hide file tree
Showing 2 changed files with 5,380 additions and 4,185 deletions.
123 changes: 68 additions & 55 deletions aas_core_codegen/golang/jsonization/_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
INDENT2 as II,
INDENT3 as III,
INDENT4 as IIII,
INDENT5 as IIIII,
)


Expand All @@ -37,7 +38,7 @@ def _generate_bool_from_jsonable() -> Stripped:
// Parse `jsonable` as a boolean, or return an error.
func boolFromJsonable(
{I}jsonable interface{{}},
) (result bool, err *DeserializationError) {{
) (result bool, err error) {{
{I}if jsonable == nil {{
{II}err = newDeserializationError(
{III}"Expected a boolean, but got null",
Expand Down Expand Up @@ -67,7 +68,7 @@ def _generate_int64_from_jsonable() -> Stripped:
// Parse `jsonable` as a 64-bit integer, or return an error.
func int64FromJsonable(
{I}jsonable interface{{}},
) (result int64, err *DeserializationError) {{
) (result int64, err error) {{
{I}if jsonable == nil {{
{II}err = newDeserializationError(
{III}"Expected an integer number, but got null",
Expand Down Expand Up @@ -133,7 +134,7 @@ def _generate_float64_from_jsonable() -> Stripped:
// Parse `jsonable` as a 64-bit float, or return an error.
func float64FromJsonable(
{I}jsonable interface{{}},
) (result float64, err *DeserializationError) {{
) (result float64, err error) {{
{I}if jsonable == nil {{
{II}err = newDeserializationError(
{III}"Expected a number, but got null",
Expand Down Expand Up @@ -165,9 +166,9 @@ def _generate_string_from_jsonable() -> Stripped:
// Parse `jsonable` as a string, or return an error.
func stringFromJsonable(
{I}jsonable interface{{}},
) (result string, error *DeserializationError) {{
) (result string, err error) {{
{I}if jsonable == nil {{
{II}error = newDeserializationError(
{II}err = newDeserializationError(
{III}"Expected a string, but got null",
{II})
{II}return
Expand All @@ -178,7 +179,7 @@ def _generate_string_from_jsonable() -> Stripped:
{I}if ok {{
{II}return
{I}}} else {{
{II}error = newDeserializationError(
{II}err = newDeserializationError(
{III}fmt.Sprintf("Expected a boolean, but got %T", jsonable),
{II})
{II}return
Expand All @@ -194,7 +195,7 @@ def _generate_bytes_from_jsonable() -> Stripped:
// Parse `jsonable` as a byte array, or return an error.
func bytesFromJsonable(
{I}jsonable interface{{}},
) (result []byte, err *DeserializationError) {{
) (result []byte, err error) {{
{I}if jsonable == nil {{
{II}err = newDeserializationError(
{III}"Expected a base64-encoded string, but got null",
Expand Down Expand Up @@ -250,7 +251,7 @@ def _generate_enumeration_from_jsonable(
// or return an error.
func {function_name}(
{I}jsonable interface{{}},
) (result aastypes.{enum_name}, err *DeserializationError) {{
) (result aastypes.{enum_name}, err error) {{
{I}if jsonable == nil {{
{II}err = newDeserializationError(
{III}"Expected a string representation of {enum_name}, " +
Expand Down Expand Up @@ -360,7 +361,7 @@ def _generate_class_from_map(cls: intermediate.ClassUnion) -> Stripped:
{I}m map[string]interface{{}},
) (
{I}result aastypes.{interface_name},
{I}err *DeserializationError,
{I}err error,
) {{
{I}var modelTypeAny interface{{}}
{I}var ok bool
Expand Down Expand Up @@ -452,7 +453,7 @@ def _generate_class_from_jsonable(cls: intermediate.ClassUnion) -> Stripped:
{I}jsonable interface{{}},
) (
{I}result aastypes.{interface_name},
{I}err *DeserializationError,
{I}err error,
) {{
{I}{indent_but_first_line(body, I)}
}}"""
Expand Down Expand Up @@ -579,11 +580,13 @@ def _generate_deserialization_switch_statement(
{I}v,
)
if err != nil {{
{I}err.Path.PrependName(
{II}&aasreporting.NameSegment{{
{III}Name: {json_prop_literal},
{II}}},
{I})
{I}if deseriaErr, ok := err.(*DeserializationError); ok {{
{II}deseriaErr.Path.PrependName(
{III}&aasreporting.NameSegment{{
{IIII}Name: {json_prop_literal},
{III}}},
{II})
{I}}}
{I}return
}}
{prop_var} = &parsed"""
Expand All @@ -601,11 +604,13 @@ def _generate_deserialization_switch_statement(
{I}v,
)
if err != nil {{
{I}err.Path.PrependName(
{II}&aasreporting.NameSegment{{
{III}Name: {json_prop_literal},
{II}}},
{I})
{I}if deseriaErr, ok := err.(*DeserializationError); ok {{
{II}deseriaErr.Path.PrependName(
{III}&aasreporting.NameSegment{{
{IIII}Name: {json_prop_literal},
{III}}},
{II})
{I}}}
{I}return
}}"""
)
Expand Down Expand Up @@ -636,19 +641,21 @@ def _generate_deserialization_switch_statement(
f"""\
jsonableArray, ok := v.([]interface{{}})
if !ok {{
{I}err = newDeserializationError(
{I}deseriaErr := newDeserializationError(
{II}fmt.Sprintf(
{III}"Expected an array, but got %T",
{III}v,
{II}),
{I})
{I}err.Path.PrependName(
{I}deseriaErr.Path.PrependName(
{II}&aasreporting.NameSegment{{
{III}Name: {json_prop_literal},
{II}}},
{I})
{I}err = deseriaErr
{I}return
}}
Expand All @@ -662,17 +669,19 @@ def _generate_deserialization_switch_statement(
{II}itemJsonable,
{I})
{I}if err != nil {{
{II}err.Path.PrependIndex(
{III}&aasreporting.IndexSegment{{
{IIII}Index: i,
{III}}},
{II})
{II}err.Path.PrependName(
{III}&aasreporting.NameSegment{{
{IIII}Name: {json_prop_literal},
{III}}},
{II})
{II}if deseriaErr, ok := err.(*DeserializationError); ok {{
{III}deseriaErr.Path.PrependIndex(
{IIII}&aasreporting.IndexSegment{{
{IIIII}Index: i,
{IIII}}},
{III})
{III}deseriaErr.Path.PrependName(
{IIII}&aasreporting.NameSegment{{
{IIIII}Name: {json_prop_literal},
{IIII}}},
{III})
{II}}}
{II}return
{I}}}
Expand Down Expand Up @@ -927,7 +936,7 @@ def _generate_concrete_class_from_map_without_dispatch(
{I}m map[string]interface{{}},
) (
{I}result aastypes.{interface_name},
{I}err *DeserializationError,
{I}err error,
) {{
{I}{indent_but_first_line(body, I)}
}}"""
Expand All @@ -946,7 +955,7 @@ def _generate_int64_to_jsonable() -> Stripped:
// Try to cast `that` to a float64, or return an error.
func int64ToJsonable(
{I}that int64,
) (result float64, err *SerializationError) {{
) (result float64, err error) {{
{I}if that > 9007199254740991 || that < -9007199254740991 {{
{II}err = newSerializationError(
{III}fmt.Sprintf(
Expand All @@ -970,7 +979,7 @@ def _generate_bytes_to_jsonable() -> Stripped:
// Encode `bytes` to a base64 string.
func bytesToJsonable(
{I}bytes []byte,
) (result string, err *SerializationError) {{
) (result string, err error) {{
{I}if bytes == nil {{
{II}err = newSerializationError(
{III}"Expected an array of bytes, but got nil",
Expand Down Expand Up @@ -1005,7 +1014,7 @@ def _generate_enumeration_to_jsonable(
// Serialize `that` to a string, or return an error.
func {function_name}(
{I}that aastypes.{enum_name},
) (result string, err *SerializationError) {{
) (result string, err error) {{
{I}var ok bool
{I}result, ok = aasstringification.{enum_to_str}(
{II}that,
Expand Down Expand Up @@ -1239,17 +1248,19 @@ def _generate_cls_to_map(cls: intermediate.ConcreteClass) -> Stripped:
{I}var jsonable interface{{}}
{I}jsonable, err = {indent_but_first_line(serialize_expr, I)}
{I}if err != nil {{
{II}err.Path.PrependIndex(
{III}&aasreporting.IndexSegment{{
{IIII}Index: i,
{III}}},
{II})
{II}err.Path.PrependName(
{III}&aasreporting.NameSegment{{
{IIII}Name: {prop_literal},
{III}}},
{II})
{II}if seriaErr, ok := err.(*SerializationError); ok {{
{III}seriaErr.Path.PrependIndex(
{IIII}&aasreporting.IndexSegment{{
{IIIII}Index: i,
{IIII}}},
{III})
{III}seriaErr.Path.PrependName(
{IIII}&aasreporting.NameSegment{{
{IIIII}Name: {prop_literal},
{IIII}}},
{III})
{II}}}
{II}return
{I}}}
Expand Down Expand Up @@ -1296,11 +1307,13 @@ def _generate_cls_to_map(cls: intermediate.ConcreteClass) -> Stripped:
var {prop_jsonable_var} interface{{}}
{prop_jsonable_var}, err = {serialize_expr}
if err != nil {{
{I}err.Path.PrependName(
{II}&aasreporting.NameSegment{{
{III}Name: {prop_literal},
{II}}},
{I})
{I}if seriaErr, ok := err.(*SerializationError); ok {{
{II}seriaErr.Path.PrependName(
{III}&aasreporting.NameSegment{{
{IIII}Name: {prop_literal},
{III}}},
{II})
{I}}}
{I}return
}}
Expand Down Expand Up @@ -1350,7 +1363,7 @@ def _generate_cls_to_map(cls: intermediate.ConcreteClass) -> Stripped:
// [{to_jsonable}].
func {function_name}(
{I}that aastypes.{interface_name},
) (result map[string]interface{{}}, err *SerializationError) {{
) (result map[string]interface{{}}, err error) {{
{I}{indent_but_first_line(body, I)}
}}"""
)
Expand Down Expand Up @@ -1409,7 +1422,7 @@ def _generate_to_jsonable(symbol_table: intermediate.SymbolTable) -> Stripped:
// or an error if some value could not be converted.
func ToJsonable(
{I}that aastypes.IClass,
) (result map[string]interface{{}}, err *SerializationError) {{
) (result map[string]interface{{}}, err error) {{
{I}{indent_but_first_line(switch_statement, I)}
{I}return
}}"""
Expand Down
Loading

0 comments on commit 6e15812

Please sign in to comment.