Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor type inference in functions #523

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 37 additions & 62 deletions aas_core_codegen/cpp/verification/_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -1081,26 +1081,22 @@ def _transpile_class_invariant(
environment: intermediate_type_inference.Environment,
) -> Tuple[Optional[Stripped], Optional[Error]]:
"""Translate the invariant from the meta-model into a C++ condition."""
canonicalizer = intermediate_type_inference.Canonicalizer()
_ = canonicalizer.transform(invariant.body)

type_inferrer = intermediate_type_inference.Inferrer(
symbol_table=symbol_table,
environment=environment,
representation_map=canonicalizer.representation_map,
# fmt: off
type_map, inference_error = (
intermediate_type_inference.infer_for_invariant(
invariant=invariant,
environment=environment
)
)
# fmt: on

_ = type_inferrer.transform(invariant.body)
if inference_error is not None:
return None, inference_error

if len(type_inferrer.errors):
return None, Error(
invariant.parsed.node,
"Failed to infer the types in the invariant",
type_inferrer.errors,
)
assert type_map is not None

optional_inferrer = cpp_optionaling.Inferrer(
environment=environment, type_map=type_inferrer.type_map
environment=environment, type_map=type_map
)

_ = optional_inferrer.transform(invariant.body)
Expand All @@ -1114,7 +1110,7 @@ def _transpile_class_invariant(
)

transpiler = _ClassInvariantTranspiler(
type_map=type_inferrer.type_map,
type_map=type_map,
is_optional_map=optional_inferrer.is_optional_map,
environment=environment,
symbol_table=symbol_table,
Expand Down Expand Up @@ -2111,40 +2107,23 @@ def _generate_implementation_of_transpilable_verification(
base_environment: intermediate_type_inference.Environment,
) -> Tuple[Optional[Stripped], Optional[Error]]:
"""Transpile the verification to a function implementation."""
canonicalizer = intermediate_type_inference.Canonicalizer()
for node in verification.parsed.body:
_ = canonicalizer.transform(node)

environment = intermediate_type_inference.MutableEnvironment(
parent=base_environment
)
for arg in verification.arguments:
environment.set(
identifier=arg.name,
type_annotation=intermediate_type_inference.convert_type_annotation(
arg.type_annotation
),
# fmt: off
type_inference, inference_error = (
intermediate_type_inference.infer_for_verification(
verification=verification,
base_environment=base_environment
)

type_inferrer = intermediate_type_inference.Inferrer(
symbol_table=symbol_table,
environment=environment,
representation_map=canonicalizer.representation_map,
)
# fmt: on

for node in verification.parsed.body:
_ = type_inferrer.transform(node)
if inference_error is not None:
return None, inference_error

if len(type_inferrer.errors):
return None, Error(
verification.parsed.node,
f"Failed to infer the types "
f"in the verification function {verification.name!r}",
type_inferrer.errors,
)
assert type_inference is not None

optional_inferrer = cpp_optionaling.Inferrer(
environment=environment, type_map=type_inferrer.type_map
environment=type_inference.environment_with_args,
type_map=type_inference.type_map,
)
for node in verification.parsed.body:
_ = optional_inferrer.transform(node)
Expand All @@ -2158,9 +2137,9 @@ def _generate_implementation_of_transpilable_verification(
)

transpiler = _TranspilableVerificationTranspiler(
type_map=type_inferrer.type_map,
type_map=type_inference.type_map,
is_optional_map=optional_inferrer.is_optional_map,
environment=environment,
environment=type_inference.environment_with_args,
symbol_table=symbol_table,
verification=verification,
)
Expand Down Expand Up @@ -2398,26 +2377,22 @@ def _transpile_constrained_primitive_invariant(
constrained_primitive: intermediate.ConstrainedPrimitive,
) -> Tuple[Optional[Stripped], Optional[Error]]:
"""Translate the invariant from the meta-model into a C++ condition."""
canonicalizer = intermediate_type_inference.Canonicalizer()
_ = canonicalizer.transform(invariant.body)

type_inferrer = intermediate_type_inference.Inferrer(
symbol_table=symbol_table,
environment=environment,
representation_map=canonicalizer.representation_map,
# fmt: off
type_map, inference_error = (
intermediate_type_inference.infer_for_invariant(
invariant=invariant,
environment=environment
)
)
# fmt: on

_ = type_inferrer.transform(invariant.body)
if inference_error is not None:
return None, inference_error

if len(type_inferrer.errors):
return None, Error(
invariant.parsed.node,
"Failed to infer the types in the invariant",
type_inferrer.errors,
)
assert type_map is not None

optional_inferrer = cpp_optionaling.Inferrer(
environment=environment, type_map=type_inferrer.type_map
environment=environment, type_map=type_map
)

_ = optional_inferrer.transform(invariant.body)
Expand All @@ -2431,7 +2406,7 @@ def _transpile_constrained_primitive_invariant(
)

transpiler = _ConstrainedPrimitiveInvariantTranspiler(
type_map=type_inferrer.type_map,
type_map=type_map,
is_optional_map=optional_inferrer.is_optional_map,
environment=environment,
symbol_table=symbol_table,
Expand Down
77 changes: 23 additions & 54 deletions aas_core_codegen/csharp/verification/_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def __init__(self, defined_variables: Set[Identifier]) -> None:
"""
Initialize with the given values.

The ``initialized_variables`` are shared between different statement
The ``defined_variables`` are shared between different statement
transpilations. It is also mutated when assignments are transpiled. We need to
keep track of variables so that we know when we have to define them, and when
we can simply assign them a value, if they have been already defined.
Expand Down Expand Up @@ -427,41 +427,23 @@ def _transpile_transpilable_verification(
environment: intermediate_type_inference.Environment,
) -> Tuple[Optional[Stripped], Optional[Error]]:
"""Transpile a verification function."""
canonicalizer = intermediate_type_inference.Canonicalizer()
for node in verification.parsed.body:
_ = canonicalizer.transform(node)

environment_with_args = intermediate_type_inference.MutableEnvironment(
parent=environment
)
for arg in verification.arguments:
environment_with_args.set(
identifier=arg.name,
type_annotation=intermediate_type_inference.convert_type_annotation(
arg.type_annotation
),
# fmt: off
type_inference, error = (
intermediate_type_inference.infer_for_verification(
verification=verification,
base_environment=environment
)

type_inferrer = intermediate_type_inference.Inferrer(
symbol_table=symbol_table,
environment=environment_with_args,
representation_map=canonicalizer.representation_map,
)
# fmt: on

for node in verification.parsed.body:
_ = type_inferrer.transform(node)
if error is not None:
return None, error

if len(type_inferrer.errors):
return None, Error(
verification.parsed.node,
f"Failed to infer the types "
f"in the verification function {verification.name!r}",
type_inferrer.errors,
)
assert type_inference is not None

transpiler = _TranspilableVerificationTranspiler(
type_map=type_inferrer.type_map,
environment=environment_with_args,
type_map=type_inference.type_map,
environment=type_inference.environment_with_args,
symbol_table=symbol_table,
verification=verification,
)
Expand Down Expand Up @@ -598,35 +580,22 @@ def _transpile_invariant(
environment: intermediate_type_inference.Environment,
) -> Tuple[Optional[Stripped], Optional[Error]]:
"""Translate the invariant from the meta-model into C# code."""
# NOTE (mristin, 2021-10-24):
# We manually transpile the invariant from our custom syntax without additional
# semantic analysis in the :py:mod:`aas_core_codegen.intermediate` layer.
#
# While this might seem repetitive ("unDRY"), we are still not sure about
# the appropriate abstraction. After we implement the code generation for a couple
# of languages, we hope to have a much better understanding about the necessary
# abstractions.

canonicalizer = intermediate_type_inference.Canonicalizer()
_ = canonicalizer.transform(invariant.body)

type_inferrer = intermediate_type_inference.Inferrer(
symbol_table=symbol_table,
environment=environment,
representation_map=canonicalizer.representation_map,
# fmt: off
type_map, inference_error = (
intermediate_type_inference.infer_for_invariant(
invariant=invariant,
environment=environment
)
)
# fmt: on

_ = type_inferrer.transform(invariant.body)
if inference_error is not None:
return None, inference_error

if len(type_inferrer.errors):
return None, Error(
invariant.parsed.node,
"Failed to infer the types in the invariant",
type_inferrer.errors,
)
assert type_map is not None

transpiler = _InvariantTranspiler(
type_map=type_inferrer.type_map,
type_map=type_map,
environment=environment,
symbol_table=symbol_table,
)
Expand Down
71 changes: 25 additions & 46 deletions aas_core_codegen/golang/verification/_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,40 +485,23 @@ def _transpile_transpilable_verification(
environment: intermediate_type_inference.Environment,
) -> Tuple[Optional[Stripped], Optional[Error]]:
"""Transpile a verification function."""
canonicalizer = intermediate_type_inference.Canonicalizer()
for node in verification.parsed.body:
_ = canonicalizer.transform(node)

environment_with_args = intermediate_type_inference.MutableEnvironment(
parent=environment
)
for arg in verification.arguments:
environment_with_args.set(
identifier=arg.name,
type_annotation=intermediate_type_inference.convert_type_annotation(
arg.type_annotation
),
# fmt: off
type_inference, error = (
intermediate_type_inference.infer_for_verification(
verification=verification,
base_environment=environment
)

type_inferrer = intermediate_type_inference.Inferrer(
symbol_table=symbol_table,
environment=environment_with_args,
representation_map=canonicalizer.representation_map,
)
# fmt: on

for node in verification.parsed.body:
_ = type_inferrer.transform(node)
if error is not None:
return None, error

if len(type_inferrer.errors):
return None, Error(
verification.parsed.node,
f"Failed to infer the types "
f"in the verification function {verification.name!r}",
type_inferrer.errors,
)
assert type_inference is not None

pointer_inferrer = golang_pointering.Inferrer(
environment=environment_with_args, type_map=type_inferrer.type_map
environment=type_inference.environment_with_args,
type_map=type_inference.type_map,
)

for node in verification.parsed.body:
Expand All @@ -533,9 +516,9 @@ def _transpile_transpilable_verification(
)

transpiler = _TranspilableVerificationTranspiler(
type_map=type_inferrer.type_map,
type_map=type_inference.type_map,
is_pointer_map=pointer_inferrer.is_pointer_map,
environment=environment_with_args,
environment=type_inference.environment_with_args,
symbol_table=symbol_table,
verification=verification,
)
Expand Down Expand Up @@ -693,26 +676,22 @@ def _transpile_invariant(
environment: intermediate_type_inference.Environment,
) -> Tuple[Optional[Stripped], Optional[Error]]:
"""Translate the invariant from the meta-model into Golang code."""
canonicalizer = intermediate_type_inference.Canonicalizer()
_ = canonicalizer.transform(invariant.body)

type_inferrer = intermediate_type_inference.Inferrer(
symbol_table=symbol_table,
environment=environment,
representation_map=canonicalizer.representation_map,
# fmt: off
type_map, inference_error = (
intermediate_type_inference.infer_for_invariant(
invariant=invariant,
environment=environment
)
)
# fmt: on

_ = type_inferrer.transform(invariant.body)
if inference_error is not None:
return None, inference_error

if len(type_inferrer.errors):
return None, Error(
invariant.parsed.node,
"Failed to infer the types in the invariant",
type_inferrer.errors,
)
assert type_map is not None

pointer_inferrer = golang_pointering.Inferrer(
environment=environment, type_map=type_inferrer.type_map
environment=environment, type_map=type_map
)

_ = pointer_inferrer.transform(invariant.body)
Expand All @@ -725,7 +704,7 @@ def _transpile_invariant(
)

transpiler = _InvariantTranspiler(
type_map=type_inferrer.type_map,
type_map=type_map,
is_pointer_map=pointer_inferrer.is_pointer_map,
environment=environment,
symbol_table=symbol_table,
Expand Down
Loading
Loading