view pygments_lexer_pseudocode2/algpseudocode.py @ 56:661461fb4dfc

Make the "py-name" rules parameterized: allow to provide the token type. For this to work the implemting function must be global, because the access to the class is not yet possible at construction time. So consistently make some previons LexBase members module globals. Make some LexBase members module globals consistently.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 27 Apr 2026 12:37:27 +0200
parents 39151225fb84
children e8f4af9e20a8
line wrap: on
line source


# -*- coding: utf-8 -*-
# :-
# SPDX-FileCopyrightText: © 2026 Franz Glasner
# SPDX-License-Identifier: MIT
# :-
r"""A pseudocode lexer along the lines of CTAN's algpseudocode or
algpseudocodex.

"""

__all__ = ["AlgPseudocodeLexer",
           "AlgPseudocodeLexer_DE", "AlgPseudocodeLexer_FR"]


import re

from pygments.lexer import include, bygroups
from pygments.token import (Comment, Keyword, Name, Text, Whitespace)

#
# Relative imports do not work with pygments.lexers.load_lexer_from_file()
# in all of our supported Python releases.
#
from pygments_lexer_pseudocode2.bases import LexBase


class AlgPseudocodeLexer(LexBase):

    """A pseudocode lexer along the lines of CTAN's algpseudocode or
    algpseudocodex.

    Some ideas (e.g. strings) are borrowed from Pygment's Python lexer.

    """

    name = "AlgPseudocode"
    aliases = ["algpseudocode", "algpseudo"]
    filenames = ["*.algpseudo", "*.algpseudocode"]
    mimetypes = []
    flags = re.MULTILINE

    LANG = "en"
    TRANSLATIONS = {
        "PROG": "PROGRAM",
        "PROGRAM": "PROGRAM",
        "ALGO": "ALGORITHM",
        "ALGORITHM": "ALGORITHM",
        "PROC": "PROCEDURE",
        "PROCEDURE": "PROCEDURE",
        "FUNC": "FUNCTION",
        "FUNCTION": "FUNCTION",
        "FN": "FUNCTION",
        "CLASS": "CLASS",
    }
    SYMBOLS = {
        "REMARK": "▷",  # U+25B7: Unicode 1.0 (Arrows)
        "Remark": "▷",
        "remark": "▷",
        "REM": "▷",
        "Rem": "▷",
        "rem": "▷",
        "R": "▷",
        "r": "▷",
        "BLOCK": "┃",   # U+2503: Unicode 1.0 (Bow Drawing)
        "Block": "┃",
        "block": "┃",
    }

    def op_translate(toktype):

        def _op_translate(lexer, match, ctx=None):
            kw = match.group().upper()
            yield match.start(), toktype, lexer.TRANSLATIONS.get(kw, kw)

        return _op_translate

    def op_symbol(toktype):

        def _op_symbol(lexer, match, ctx=None):
            kw = match.group()
            yield match.start(), toktype, lexer.SYMBOLS.get(kw, kw)

        return _op_symbol

    tokens = {
        "root": [
            (r"\n", Whitespace),
            (r"/\*", Comment.Multiline, "multiline-nested-comment"),
            (r"//.*$", Comment.Single),
            (r"(?:\\)(REMARK|Remark|remark|REM|Rem|rem|R|r)\b(.*)$",
             bygroups(op_symbol(Comment.Single), Comment.Single)),
            (r"(?:\\)(BLOCK|Block|block)\b(.*)$",
             bygroups(op_symbol(Text), Text)),
            (r"\\\n", Text),
            (r"(?i)\\("
             r"(?:prog(?:ram)?)"
             r"|(?:algo(?:rithm)?)"
             r"|(?:proc(?:edure)?)"
             r"|(?:func(?:tion)?|(?:fn))"
             r"|(?:class)"
             r")(\s*)(\{)",
             bygroups(op_translate(Keyword), Whitespace, Name.Entity),
             "entity-name"),
            include("expr"),
            (r"\s+", Text),
        ],
        "entity-name": [       # may be multiline
            (r"[^\\}]+", Name.Entity),
            (r"\\\}", Name.Entity),
            (r"\\", Name.Entity),
            (r"\}", Name.Entity, "#pop"),
        ],
        "expr": [
            include("py-strings"),
            include("py-numbers"),
            include("py-name"),
        ]
    }


class AlgPseudocodeLexer_DE(AlgPseudocodeLexer):

    name = "AlgPseudocodeDE"
    aliases = ["algpseudocode-de", "algpseudo-de"]
    filenames = ["*.algpseudo-de", "*.algpseudocode-de"]

    LANG = "de"
    TRANSLATIONS = AlgPseudocodeLexer.TRANSLATIONS.copy()
    TRANSLATIONS.update({
        "PROG": "PROGRAMM",
        "PROGRAM": "PROGRAMM",
        "ALGO": "ALGORITHMUS",
        "ALGORITHM": "ALGORITHMUS",
        "PROC": "PROZEDUR",
        "PROCEDURE": "PROZEDUR",
        "FUNC": "FUNKTION",
        "FUNCTION": "FUNKTION",
        "FN": "FUNKTION",
        "CLASS": "KLASSE",
    })


class AlgPseudocodeLexer_FR(AlgPseudocodeLexer):

    name = "AlgPseudocodeFR"
    aliases = ["algpseudocode-fr", "algpseudo-fr"]
    filenames = ["*.algpseudo-fr", "*.algpseudocode-fr"]

    LANG = "de"
    TRANSLATIONS = AlgPseudocodeLexer.TRANSLATIONS.copy()
    TRANSLATIONS.update({
        "PROG": "PROGRAMME",
        "PROGRAM": "PROGRAMME",
        "ALGO": "ALGORITHME",
        "ALGORITHM": "ALGORITHME",
        "PROC": "PROCÉDURE",
        "PROCEDURE": "PROCÉDURE",
        "FUNC": "FONCTION",
        "FUNCTION": "FOUNCTION",
        "FN": "FONCTION",
        "CLASS": "CLASSE",
    })