feat(cli): update highlighter with new nodes

This commit is contained in:
2026-06-02 12:29:39 +02:00
parent 35ceda99aa
commit d70137775f
4 changed files with 52 additions and 49 deletions

View File

@@ -53,5 +53,6 @@ span {
&.keyword { &.keyword {
color: rgb(211, 72, 9); color: rgb(211, 72, 9);
pointer-events: none;
} }
} }

View File

@@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Generic, Optional, Protocol, TextIO, TypeVar from typing import Generic, Optional, Protocol, TextIO, TypeVar
@@ -8,6 +9,7 @@ import midas.ast.midas as m
import midas.ast.python as p import midas.ast.python as p
from midas.ast.location import Location from midas.ast.location import Location
from midas.checker.diagnostic import Diagnostic from midas.checker.diagnostic import Diagnostic
from midas.lexer.token import Token
H = TypeVar("H", bound="Highlighter", contravariant=True) H = TypeVar("H", bound="Highlighter", contravariant=True)
@@ -22,6 +24,15 @@ class Locatable(Protocol):
def location(self) -> Optional[Location]: ... def location(self) -> Optional[Location]: ...
@dataclass(frozen=True)
class LocatableToken:
token: Token
@property
def location(self) -> Location:
return self.token.get_location()
class Highlighter(ABC): class Highlighter(ABC):
BASE_CSS_PATH: Path = Path(__file__).parent / "highlight.css" BASE_CSS_PATH: Path = Path(__file__).parent / "highlight.css"
EXTRA_CSS_PATH: Optional[Path] = None EXTRA_CSS_PATH: Optional[Path] = None
@@ -206,34 +217,22 @@ class PythonHighlighter(
def visit_ternary_expr(self, expr: p.TernaryExpr) -> None: ... def visit_ternary_expr(self, expr: p.TernaryExpr) -> None: ...
class MidasHighlighter(Highlighter, m.Stmt.Visitor[None], m.Expr.Visitor[None]): class MidasHighlighter(
Highlighter, m.Stmt.Visitor[None], m.Expr.Visitor[None], m.Type.Visitor[None]
):
EXTRA_CSS_PATH: Optional[Path] = Path(__file__).parent / "hl_midas.css" EXTRA_CSS_PATH: Optional[Path] = Path(__file__).parent / "hl_midas.css"
def highlight(self, node: Highlightable[MidasHighlighter]): def highlight(self, node: Highlightable[MidasHighlighter]):
node.accept(self) node.accept(self)
def visit_simple_type_stmt(self, stmt: m.SimpleTypeStmt) -> None: def visit_type_stmt(self, stmt: m.TypeStmt) -> None:
self.wrap(stmt, "simple-type") self.wrap(stmt, "type-stmt")
if stmt.template is not None: self.wrap(LocatableToken(stmt.name), "type-name")
stmt.template.accept(self) stmt.type.accept(self)
stmt.base.accept(self)
if stmt.constraint is not None:
self.wrap(stmt.constraint, "constraint")
stmt.constraint.accept(self)
def visit_complex_type_stmt(self, stmt: m.ComplexTypeStmt) -> None:
self.wrap(stmt, "complex-type")
if stmt.template is not None:
stmt.template.accept(self)
for prop in stmt.properties:
prop.accept(self)
def visit_property_stmt(self, stmt: m.PropertyStmt) -> None: def visit_property_stmt(self, stmt: m.PropertyStmt) -> None:
self.wrap(stmt, "property") self.wrap(stmt, "property")
stmt.type.accept(self) stmt.type.accept(self)
if stmt.constraint is not None:
self.wrap(stmt.constraint, "constraint")
stmt.constraint.accept(self)
def visit_extend_stmt(self, stmt: m.ExtendStmt) -> None: def visit_extend_stmt(self, stmt: m.ExtendStmt) -> None:
self.wrap(stmt, "extend") self.wrap(stmt, "extend")
@@ -243,17 +242,16 @@ class MidasHighlighter(Highlighter, m.Stmt.Visitor[None], m.Expr.Visitor[None]):
def visit_op_stmt(self, stmt: m.OpStmt) -> None: def visit_op_stmt(self, stmt: m.OpStmt) -> None:
self.wrap(stmt, "op") self.wrap(stmt, "op")
self.wrap(LocatableToken(stmt.name), "op-name")
stmt.operand.accept(self) stmt.operand.accept(self)
stmt.result.accept(self) stmt.result.accept(self)
def visit_predicate_stmt(self, stmt: m.PredicateStmt) -> None: def visit_predicate_stmt(self, stmt: m.PredicateStmt) -> None:
self.wrap(stmt, "predicate") self.wrap(stmt, "predicate")
self.wrap(LocatableToken(stmt.name), "predicate-name")
stmt.type.accept(self) stmt.type.accept(self)
stmt.condition.accept(self) stmt.condition.accept(self)
def visit_simple_type_expr(self, expr: m.SimpleTypeExpr) -> None:
self.wrap(expr, "simple-type-expr")
def visit_logical_expr(self, expr: m.LogicalExpr) -> None: def visit_logical_expr(self, expr: m.LogicalExpr) -> None:
self.wrap(expr, "logical-expr") self.wrap(expr, "logical-expr")
expr.left.accept(self) expr.left.accept(self)
@@ -282,14 +280,29 @@ class MidasHighlighter(Highlighter, m.Stmt.Visitor[None], m.Expr.Visitor[None]):
def visit_wildcard_expr(self, expr: m.WildcardExpr) -> None: ... def visit_wildcard_expr(self, expr: m.WildcardExpr) -> None: ...
def visit_template_expr(self, expr: m.TemplateExpr) -> None: def visit_named_type(self, type: m.NamedType) -> None:
self.wrap(expr, "template") self.wrap(type, "named-type")
expr.type.accept(self)
def visit_type_expr(self, expr: m.TypeExpr) -> None: def visit_generic_type(self, type: m.GenericType) -> None:
self.wrap(expr, "type") self.wrap(type, "generic-type")
if expr.template is not None: type.type.accept(self)
expr.template.accept(self) for param in type.params:
param.accept(self)
def visit_constraint_type(self, type: m.ConstraintType) -> None:
self.wrap(type, "constraint-type")
type.type.accept(self)
type.constraint.accept(self)
def visit_union_type(self, type: m.UnionType) -> None:
self.wrap(type, "union-type")
for type_ in type.types:
type_.accept(self)
def visit_complex_type(self, type: m.ComplexType) -> None:
self.wrap(type, "complex-type")
for prop in type.properties:
prop.accept(self)
class DiagnosticsHighlighter(Highlighter): class DiagnosticsHighlighter(Highlighter):

View File

@@ -5,12 +5,12 @@ span {
font-style: italic; font-style: italic;
} }
&.simple-type { &.named-type,
--col: 108, 233, 108; &.generic-type,
} &.constraint-type,
&.union-type,
&.complex-type { &.complex-type {
--col: 233, 206, 108; --col: 150, 150, 150;
} }
&.constraint { &.constraint {
@@ -33,10 +33,6 @@ span {
--col: 193, 108, 233; --col: 193, 108, 233;
} }
&.simple-type-expr {
--col: 150, 150, 150;
}
&.logical-expr, &.logical-expr,
&.binary-expr, &.binary-expr,
&.unary-expr, &.unary-expr,
@@ -48,7 +44,9 @@ span {
--col: 163, 117, 71; --col: 163, 117, 71;
} }
&.type { &.type-name,
&.op-name,
&.predicate-name {
--col: 200, 200, 200; --col: 200, 200, 200;
font-weight: bold; font-weight: bold;
} }

View File

@@ -1,7 +1,6 @@
import ast import ast
import json import json
import logging import logging
from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Optional, TextIO, get_args from typing import Optional, TextIO, get_args
@@ -9,7 +8,6 @@ import click
import midas.ast.midas as m import midas.ast.midas as m
import midas.ast.python as p import midas.ast.python as p
from midas.ast.location import Location
from midas.ast.printer import MidasAstPrinter, PythonAstPrinter from midas.ast.printer import MidasAstPrinter, PythonAstPrinter
from midas.checker.checker import Checker from midas.checker.checker import Checker
from midas.checker.diagnostic import Diagnostic from midas.checker.diagnostic import Diagnostic
@@ -17,6 +15,7 @@ from midas.checker.types import Type
from midas.cli.highlighter import ( from midas.cli.highlighter import (
DiagnosticsHighlighter, DiagnosticsHighlighter,
Highlighter, Highlighter,
LocatableToken,
MidasHighlighter, MidasHighlighter,
PythonHighlighter, PythonHighlighter,
) )
@@ -142,14 +141,6 @@ def highlight_midas(source: str, path: str) -> Highlighter:
for err in parser.errors: for err in parser.errors:
print(err.get_report()) print(err.get_report())
@dataclass(frozen=True)
class LocatableToken:
token: Token
@property
def location(self) -> Location:
return self.token.get_location()
for stmt in stmts: for stmt in stmts:
highlighter.highlight(stmt) highlighter.highlight(stmt)
for token in tokens: for token in tokens: