Skip to content

Commit

Permalink
Merge pull request #329 from atopile/mawildoer/assertion-debugging
Browse files Browse the repository at this point in the history
Add more debug information to assertions
  • Loading branch information
mawildoer committed Apr 30, 2024
2 parents acb113c + 7a43e8a commit 0bf2f7d
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 19 deletions.
65 changes: 48 additions & 17 deletions src/atopile/assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
from rich.table import Table
from scipy.optimize import minimize

from atopile import address, config, errors, instance_methods, loop_soup, telemetry, expressions
from atopile.front_end import (
Assertion,
Assignment,
Expression,
RangedValue,
lofty,
from atopile import (
address,
config,
errors,
expressions,
instance_methods,
loop_soup,
parse_utils,
telemetry,
)
from atopile.front_end import Assertion, Assignment, Expression, RangedValue, lofty

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -75,11 +78,15 @@ def generate_assertion_report(build_ctx: config.BuildContext):
a = assertion.lhs(context)
b = assertion.rhs(context)
except errors.AtoError as e:
raise ErrorComputingAssertion(f"Exception computing assertion: {str(e)}") from e
raise ErrorComputingAssertion(
f"Exception computing assertion: {str(e)}"
) from e

assert isinstance(a, RangedValue)
assert isinstance(b, RangedValue)
numeric = a.pretty_str() + " " + assertion.operator + " " + b.pretty_str()
numeric = (
a.pretty_str() + " " + assertion.operator + " " + b.pretty_str()
)
if _do_op(a, assertion.operator, b):
log.debug(
textwrap.dedent(f"""
Expand Down Expand Up @@ -249,6 +256,24 @@ def solve_assertions(build_ctx: config.BuildContext):
"""
)

msg += "\n\nVariables:\n"
for v in group_vars:
msg += f" {v}\n"
assignment_origin = instance_methods.get_assignments(v)[0].src_ctx
msg += f" (^ assigned {parse_utils.format_src_info(assignment_origin)})\n\n"

if constants:
msg += "\n\nConstants:\n"
for c, v in constants.items():
msg += f" {c} = {v}\n"

msg += "\n\nAssertions:\n"
for a in assertions:
if hasattr(a, "src_ctx") and a.src_ctx:
msg += f" {parse_utils.reconstruct(a.src_ctx)}\n"
else:
msg += " Unknown Source\n"

if (
len(assertions) == 1
and hasattr(assertions[0], "src_ctx")
Expand All @@ -259,18 +284,22 @@ def solve_assertions(build_ctx: config.BuildContext):
title=title,
message=msg,
)
else:
raise errors.AtoError(
msg,
title=title,
)

raise errors.AtoError(
msg,
title=title,
)

# Here we're attempting to shuffle the values into eseries
result_means = [
(result.x[i * 2] + result.x[i * 2 + 1]) / 2 for i in range(len(group_vars))
(result.x[i * 2] + result.x[i * 2 + 1]) / 2
for i in range(len(group_vars))
]
for r_vals in itertools.product(
*[eseries.find_nearest_few(eseries.E96, x_val) for x_val in result_means],
*[
eseries.find_nearest_few(eseries.E96, x_val)
for x_val in result_means
],
repeat=1,
):
final_values = [
Expand Down Expand Up @@ -330,7 +359,9 @@ def simplify_expressions(entry_addr: address.AddrStr):
instance = lofty.get_instance(instance_addr)
for assignment_key, assignment in instance.assignments.items():
if assignment and assignment[0].value is not None:
context[address.add_instance(instance_addr, assignment_key)] = assignment[0].value
context[address.add_instance(instance_addr, assignment_key)] = (
assignment[0].value
)

# Simplify the expressions
simplified = expressions.simplify_expression_pool(context)
Expand Down
47 changes: 45 additions & 2 deletions src/atopile/parse_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
from pathlib import Path

from antlr4 import InputStream, ParserRuleContext, Token
from antlr4 import InputStream, ParserRuleContext, ParseTreeVisitor, Token


def get_src_info_from_token(token: Token) -> tuple[str, int, int]:
Expand All @@ -12,8 +12,51 @@ def get_src_info_from_token(token: Token) -> tuple[str, int, int]:
return input_stream.name, token.line, token.column


def get_src_info_from_ctx(ctx: ParserRuleContext) -> tuple[str | Path, int, int, int]:
def get_src_info_from_ctx(ctx: ParserRuleContext) -> tuple[str | Path, int, int, int, int]:
"""Get the source path, line, and column from a context"""
token: Token = ctx.start
_, stop_line, stop_char = get_src_info_from_token(ctx.stop)
return *get_src_info_from_token(token), stop_line, stop_char


def format_src_info(ctx: ParserRuleContext) -> str:
"""Format the source path, line, and column"""
src, start_line, start_col, _, _ = get_src_info_from_ctx(ctx)
return f"{src}:{start_line}:{start_col}"


# FIXME: I hate this pattern
# It should instead at least return a list of tokens
# for processing in a regular for loop
class _Reconstructor(ParseTreeVisitor):
def __init__(self) -> None:
super().__init__()
self.txt = ""
self.last_line = None
self.last_col = None

def visitTerminal(self, node) -> str:
symbol: Token = node.getSymbol()

if self.last_line is None:
self.last_line = symbol.line
self.last_col = symbol.start

if symbol.line > self.last_line:
self.txt += "\n" * (symbol.line - self.last_line)
self.last_col = 0

self.txt += " " * (symbol.start - self.last_col - 1)

self.last_line = symbol.line
self.last_col = symbol.stop

self.txt += node.getText()
return super().visitTerminal(node)


def reconstruct(ctx: ParserRuleContext) -> str:
"""Reconstruct the source code from a parse tree"""
reco = _Reconstructor()
reco.visit(ctx)
return reco.txt
24 changes: 24 additions & 0 deletions tests/test_parse_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest

import atopile
import atopile.parse
import atopile.parse_utils


def _parser(src: str):
input = atopile.parse.InputStream(src)
input.name = "test"
return atopile.parse.make_parser(input)


@pytest.mark.parametrize(
"txt",
[
"a = 1",
"assert 1 within 2",
"b = 1kV +/- 10% + (2V - 1V)",
]
)
def test_reconstructor_simple_stmt(txt: str):
"""Ensure we can faithfully re-construct the source code from a parse tree"""
assert atopile.parse_utils.reconstruct(_parser(txt).simple_stmt()) == txt

0 comments on commit 0bf2f7d

Please sign in to comment.