2024-04-22 13:00:06 -07:00
|
|
|
"""
|
|
|
|
Data structuers for expressions and goals
|
|
|
|
"""
|
2024-06-04 23:53:02 -07:00
|
|
|
from dataclasses import dataclass, field
|
2024-10-20 09:52:12 -07:00
|
|
|
from typing import Optional, TypeAlias
|
2024-04-22 13:00:06 -07:00
|
|
|
|
2024-10-20 09:52:12 -07:00
|
|
|
Expr: TypeAlias = str
|
2024-04-22 13:00:06 -07:00
|
|
|
|
|
|
|
def parse_expr(payload: dict) -> Expr:
|
2024-10-20 09:52:12 -07:00
|
|
|
"""
|
|
|
|
:meta private:
|
|
|
|
"""
|
2024-04-22 13:00:06 -07:00
|
|
|
return payload["pp"]
|
|
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
|
|
class Variable:
|
|
|
|
t: Expr
|
|
|
|
v: Optional[Expr] = None
|
|
|
|
name: Optional[str] = None
|
|
|
|
|
|
|
|
@staticmethod
|
2024-05-21 22:15:45 -07:00
|
|
|
def parse(payload: dict):
|
2024-04-22 13:00:06 -07:00
|
|
|
name = payload.get("userName")
|
|
|
|
t = parse_expr(payload["type"])
|
|
|
|
v = payload.get("value")
|
|
|
|
if v:
|
|
|
|
v = parse_expr(v)
|
|
|
|
return Variable(t, v, name)
|
|
|
|
|
|
|
|
def __str__(self):
|
2024-10-20 09:52:12 -07:00
|
|
|
"""
|
|
|
|
:meta public:
|
|
|
|
"""
|
2024-04-22 13:00:06 -07:00
|
|
|
result = self.name if self.name else "_"
|
|
|
|
result += f" : {self.t}"
|
|
|
|
if self.v:
|
2024-04-22 13:32:29 -07:00
|
|
|
result += f" := {self.v}"
|
2024-04-22 13:00:06 -07:00
|
|
|
return result
|
|
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
|
|
class Goal:
|
|
|
|
variables: list[Variable]
|
|
|
|
target: Expr
|
2024-06-04 23:53:02 -07:00
|
|
|
sibling_dep: list[int] = field(default_factory=lambda: [])
|
2024-04-22 13:00:06 -07:00
|
|
|
name: Optional[str] = None
|
2024-04-22 13:32:29 -07:00
|
|
|
is_conversion: bool = False
|
2024-04-22 13:00:06 -07:00
|
|
|
|
|
|
|
@staticmethod
|
2024-05-21 22:15:45 -07:00
|
|
|
def sentence(target: Expr):
|
2024-10-20 09:52:12 -07:00
|
|
|
"""
|
|
|
|
:meta public:
|
|
|
|
"""
|
2024-04-22 13:00:06 -07:00
|
|
|
return Goal(variables=[], target=target)
|
|
|
|
|
|
|
|
@staticmethod
|
2024-06-04 23:53:02 -07:00
|
|
|
def parse(payload: dict, sibling_map: dict[str, int]):
|
2024-04-22 13:00:06 -07:00
|
|
|
name = payload.get("userName")
|
2024-04-22 22:38:20 -07:00
|
|
|
variables = [Variable.parse(v) for v in payload["vars"]]
|
2024-04-22 13:00:06 -07:00
|
|
|
target = parse_expr(payload["target"])
|
2024-04-22 13:32:29 -07:00
|
|
|
is_conversion = payload["isConversion"]
|
2024-06-04 23:53:02 -07:00
|
|
|
|
|
|
|
dependents = payload["target"]["dependentMVars"]
|
|
|
|
sibling_dep = [sibling_map[d] for d in dependents if d in sibling_map]
|
|
|
|
|
|
|
|
return Goal(variables, target, sibling_dep, name, is_conversion)
|
2024-04-22 13:00:06 -07:00
|
|
|
|
|
|
|
def __str__(self):
|
2024-10-20 09:52:12 -07:00
|
|
|
"""
|
|
|
|
:meta public:
|
|
|
|
"""
|
2024-04-22 13:32:29 -07:00
|
|
|
front = "|" if self.is_conversion else "⊢"
|
2024-04-22 13:00:06 -07:00
|
|
|
return "\n".join(str(v) for v in self.variables) + \
|
2024-04-22 13:32:29 -07:00
|
|
|
f"\n{front} {self.target}"
|
2024-04-22 13:00:06 -07:00
|
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
|
|
class GoalState:
|
|
|
|
state_id: int
|
|
|
|
goals: list[Goal]
|
|
|
|
|
2024-05-17 19:52:00 -07:00
|
|
|
_sentinel: list[int]
|
|
|
|
|
|
|
|
def __del__(self):
|
|
|
|
self._sentinel.append(self.state_id)
|
|
|
|
|
2024-04-22 13:00:06 -07:00
|
|
|
@property
|
|
|
|
def is_solved(self) -> bool:
|
2024-04-22 22:38:20 -07:00
|
|
|
"""
|
|
|
|
WARNING: Does not handle dormant goals.
|
2024-10-20 09:52:12 -07:00
|
|
|
|
|
|
|
:meta public:
|
2024-04-22 22:38:20 -07:00
|
|
|
"""
|
2024-04-22 13:00:06 -07:00
|
|
|
return not self.goals
|
2024-04-22 13:11:28 -07:00
|
|
|
|
2024-04-22 22:38:20 -07:00
|
|
|
@staticmethod
|
2024-09-09 19:28:35 -07:00
|
|
|
def parse_inner(state_id: int, goals: list, _sentinel: list[int]):
|
2024-12-11 17:00:25 -08:00
|
|
|
assert _sentinel is not None
|
2024-09-13 17:14:20 -07:00
|
|
|
goal_names = { g["name"]: i for i, g in enumerate(goals) }
|
|
|
|
goals = [Goal.parse(g, goal_names) for g in goals]
|
2024-05-17 19:52:00 -07:00
|
|
|
return GoalState(state_id, goals, _sentinel)
|
2024-09-09 19:28:35 -07:00
|
|
|
@staticmethod
|
|
|
|
def parse(payload: dict, _sentinel: list[int]):
|
|
|
|
return GoalState.parse_inner(payload["nextStateId"], payload["goals"], _sentinel)
|
2024-04-22 22:38:20 -07:00
|
|
|
|
2024-06-03 21:52:43 -07:00
|
|
|
def __str__(self):
|
2024-10-20 09:52:12 -07:00
|
|
|
"""
|
|
|
|
:meta public:
|
|
|
|
"""
|
2024-06-03 21:52:43 -07:00
|
|
|
return "\n".join([str(g) for g in self.goals])
|
|
|
|
|
2024-04-22 13:11:28 -07:00
|
|
|
@dataclass(frozen=True)
|
|
|
|
class TacticHave:
|
2024-10-12 16:20:55 -07:00
|
|
|
"""
|
|
|
|
The `have` tactic, equivalent to
|
|
|
|
```lean
|
|
|
|
have {binder_name} : {branch} := ...
|
|
|
|
```
|
|
|
|
"""
|
|
|
|
branch: str
|
|
|
|
binder_name: Optional[str] = None
|
|
|
|
@dataclass(frozen=True)
|
|
|
|
class TacticLet:
|
|
|
|
"""
|
2024-10-20 09:52:12 -07:00
|
|
|
The `let` tactic, equivalent to
|
2024-10-12 16:20:55 -07:00
|
|
|
```lean
|
|
|
|
let {binder_name} : {branch} := ...
|
|
|
|
```
|
|
|
|
"""
|
2024-04-22 13:11:28 -07:00
|
|
|
branch: str
|
2024-10-02 11:09:58 -07:00
|
|
|
binder_name: Optional[str] = None
|
2024-04-22 22:38:20 -07:00
|
|
|
@dataclass(frozen=True)
|
|
|
|
class TacticCalc:
|
2024-10-12 16:20:55 -07:00
|
|
|
"""
|
|
|
|
The `calc` tactic, equivalent to
|
|
|
|
```lean
|
|
|
|
calc {step} := ...
|
|
|
|
```
|
|
|
|
You can use `_` in the step.
|
|
|
|
"""
|
2024-04-22 22:38:20 -07:00
|
|
|
step: str
|
2024-10-12 16:20:55 -07:00
|
|
|
@dataclass(frozen=True)
|
|
|
|
class TacticExpr:
|
|
|
|
"""
|
|
|
|
Assigns an expression to the current goal
|
|
|
|
"""
|
|
|
|
expr: str
|
2024-04-22 13:11:28 -07:00
|
|
|
|
2024-10-20 09:52:12 -07:00
|
|
|
Tactic: TypeAlias = str | TacticHave | TacticLet | TacticCalc | TacticExpr
|