feat(cli): dump environment after compile

This commit is contained in:
2026-05-31 18:44:41 +02:00
parent 1a1b0e8e15
commit 893e1ba190
4 changed files with 64 additions and 2 deletions

View File

@@ -273,7 +273,7 @@ class Checker(
def visit_return_stmt(self, stmt: p.ReturnStmt) -> None:
type: Type = stmt.value.accept(self) if stmt.value is not None else UnitType()
self.env.return_types.add(type)
self.env.return_types.append(type)
raise ReturnException()
def visit_binary_expr(self, expr: p.BinaryExpr) -> Type:

View File

@@ -15,7 +15,11 @@ class Environment:
def __init__(self, enclosing: Optional[Environment] = None) -> None:
self.enclosing: Optional[Environment] = enclosing
self.values: dict[str, Type] = {}
self.return_types: set[Type] = set()
self.return_types: list[Type] = []
self._children: list[Environment] = []
if enclosing is not None:
enclosing._children.append(self)
def define(self, name: str, value: Type) -> None:
"""Define a variable in this environment
@@ -129,3 +133,10 @@ class Environment:
if self.enclosing is None:
return self.values
return self.enclosing.flat_dict() | self.values
def dump(self) -> dict:
return {
"values": self.values,
"return_types": self.return_types,
"children": [child.dump() for child in self._children],
}

View File

@@ -1,4 +1,5 @@
import ast
import json
import logging
from dataclasses import dataclass
from pathlib import Path
@@ -18,6 +19,7 @@ from midas.lexer.token import Token, TokenType
from midas.parser.midas import MidasParser
from midas.parser.python import PythonParser
from midas.resolver.resolver import Resolver
from midas.utils import UniversalJSONDumper
@click.group()
@@ -40,6 +42,15 @@ def compile(file: TextIO):
for diagnostic in diagnostics:
print(diagnostic)
print(
json.dumps(
UniversalJSONDumper.dump(
checker.global_env, [("Environment", "_children")]
),
indent=4,
)
)
@midas.group()
def utils():

40
midas/utils.py Normal file
View File

@@ -0,0 +1,40 @@
from typing import Any, Optional
class UniversalJSONDumper:
@classmethod
def dump(
cls, obj: Any, include_keys: Optional[list[str | tuple[str, str]]] = None
) -> Any:
if include_keys is None:
include_keys = []
return cls._dump(obj, include_keys, [])
@classmethod
def _dump(
cls, obj: Any, include_keys: list[str | tuple[str, str]], visited: list[Any]
) -> Any:
if obj in visited:
return None
match obj:
case str() | int() | float() | None:
return obj
case list() | set() | tuple():
return [cls._dump(child, include_keys, visited) for child in obj]
case dict():
return {
str(k): cls._dump(v, include_keys, visited) for k, v in obj.items()
}
case object():
visited.append(obj)
return {
"_type": obj.__class__.__name__,
} | {
k: cls._dump(v, include_keys, visited)
for k, v in obj.__dict__.items()
if not k.startswith("_")
or k in include_keys
or (obj.__class__.__name__, k) in include_keys
}
case _:
raise ValueError(f"Unsupported value: {obj}")