|
| 1 | +"""Pygments lexer for Lambda Discipline, mirroring src/syntax/token.rs.""" |
| 2 | + |
| 3 | +from collections.abc import Iterable, Iterator |
| 4 | +from typing import Any |
| 5 | + |
| 6 | +from pygments.lexer import RegexLexer |
| 7 | +from pygments.token import ( |
| 8 | + Comment, |
| 9 | + Keyword, |
| 10 | + Name, |
| 11 | + Number, |
| 12 | + Operator, |
| 13 | + Punctuation, |
| 14 | + String, |
| 15 | + Text, |
| 16 | + Whitespace, |
| 17 | +) |
| 18 | + |
| 19 | +IDENT = r"[A-Za-z_][A-Za-z0-9_']*" |
| 20 | + |
| 21 | + |
| 22 | +class LbdLexer(RegexLexer): |
| 23 | + name = "Lambda Discipline" |
| 24 | + aliases = ["lbd"] # noqa: RUF012 |
| 25 | + filenames = ["*.lbd"] # noqa: RUF012 |
| 26 | + |
| 27 | + def __init__(self, builtins: Iterable[str] = (), **options: Any) -> None: |
| 28 | + super().__init__(**options) # type: ignore |
| 29 | + self.builtins = set(builtins) |
| 30 | + |
| 31 | + tokens = { # noqa: RUF012 |
| 32 | + "root": [ |
| 33 | + (r"\s+", Whitespace), |
| 34 | + (r"--.*?$", Comment.Single), |
| 35 | + (r'"([^"\\]|\\.)*"', String), |
| 36 | + (r"-?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?", Number), |
| 37 | + (r"(use|let|in)\b", Keyword), |
| 38 | + (r"\\|λ", Keyword.Declaration), |
| 39 | + # A definition: a name at the start of a line followed by `:` or `=`. |
| 40 | + (rf"^{IDENT}(?=\s*[:=])", Name.Function), |
| 41 | + (r"(Number|String|Bool|Unit|List)\b", Keyword.Type), |
| 42 | + (IDENT, Name), |
| 43 | + (r"->|=|:", Operator), |
| 44 | + (r"[()\[\],.<>]", Punctuation), |
| 45 | + (r".", Text), |
| 46 | + ] |
| 47 | + } |
| 48 | + |
| 49 | + def get_tokens_unprocessed( |
| 50 | + self, text: str, stack: Iterable[str] = ("root",) |
| 51 | + ) -> Iterator[tuple[int, Any, str]]: |
| 52 | + for index, token, value in super().get_tokens_unprocessed(text, stack): |
| 53 | + if token is Name and value in self.builtins: |
| 54 | + token = Name.Builtin |
| 55 | + yield index, token, value |
0 commit comments