brintos

brintos / linux-shallow public Read only

0
0
Text · 12.3 KiB · dbd3fcf Raw
511 lines · python
1#!/usr/bin/env python32# ex: set filetype=python:3 4"""Define and implement the Abstract Syntax Tree for the XDR language."""5 6import sys7from typing import List8from dataclasses import dataclass9 10from lark import ast_utils, Transformer11from lark.tree import Meta12 13this_module = sys.modules[__name__]14 15excluded_apis = []16header_name = "none"17public_apis = []18enums = set()19structs = set()20pass_by_reference = set()21 22 23@dataclass24class _XdrAst(ast_utils.Ast):25    """Base class for the XDR abstract syntax tree"""26 27 28@dataclass29class _XdrIdentifier(_XdrAst):30    """Corresponds to 'identifier' in the XDR language grammar"""31 32    symbol: str33 34 35@dataclass36class _XdrValue(_XdrAst):37    """Corresponds to 'value' in the XDR language grammar"""38 39    value: str40 41 42@dataclass43class _XdrConstantValue(_XdrAst):44    """Corresponds to 'constant' in the XDR language grammar"""45 46    value: int47 48 49@dataclass50class _XdrTypeSpecifier(_XdrAst):51    """Corresponds to 'type_specifier' in the XDR language grammar"""52 53    type_name: str54    c_classifier: str55 56 57@dataclass58class _XdrDefinedType(_XdrTypeSpecifier):59    """Corresponds to a type defined by the input specification"""60 61 62@dataclass63class _XdrBuiltInType(_XdrTypeSpecifier):64    """Corresponds to a built-in XDR type"""65 66 67@dataclass68class _XdrDeclaration(_XdrAst):69    """Base class of XDR type declarations"""70 71 72@dataclass73class _XdrFixedLengthOpaque(_XdrDeclaration):74    """A fixed-length opaque declaration"""75 76    name: str77    size: str78    template: str = "fixed_length_opaque"79 80 81@dataclass82class _XdrVariableLengthOpaque(_XdrDeclaration):83    """A variable-length opaque declaration"""84 85    name: str86    maxsize: str87    template: str = "variable_length_opaque"88 89 90@dataclass91class _XdrVariableLengthString(_XdrDeclaration):92    """A (NUL-terminated) variable-length string declaration"""93 94    name: str95    maxsize: str96    template: str = "variable_length_string"97 98 99@dataclass100class _XdrFixedLengthArray(_XdrDeclaration):101    """A fixed-length array declaration"""102 103    name: str104    spec: _XdrTypeSpecifier105    size: str106    template: str = "fixed_length_array"107 108 109@dataclass110class _XdrVariableLengthArray(_XdrDeclaration):111    """A variable-length array declaration"""112 113    name: str114    spec: _XdrTypeSpecifier115    maxsize: str116    template: str = "variable_length_array"117 118 119@dataclass120class _XdrOptionalData(_XdrDeclaration):121    """An 'optional_data' declaration"""122 123    name: str124    spec: _XdrTypeSpecifier125    template: str = "optional_data"126 127 128@dataclass129class _XdrBasic(_XdrDeclaration):130    """A 'basic' declaration"""131 132    name: str133    spec: _XdrTypeSpecifier134    template: str = "basic"135 136 137@dataclass138class _XdrVoid(_XdrDeclaration):139    """A void declaration"""140 141    template: str = "void"142 143 144@dataclass145class _XdrConstant(_XdrAst):146    """Corresponds to 'constant_def' in the grammar"""147 148    name: str149    value: str150 151 152@dataclass153class _XdrEnumerator(_XdrAst):154    """An 'identifier = value' enumerator"""155 156    name: str157    value: str158 159 160@dataclass161class _XdrEnum(_XdrAst):162    """An XDR enum definition"""163 164    name: str165    minimum: int166    maximum: int167    enumerators: List[_XdrEnumerator]168 169 170@dataclass171class _XdrStruct(_XdrAst):172    """An XDR struct definition"""173 174    name: str175    fields: List[_XdrDeclaration]176 177 178@dataclass179class _XdrPointer(_XdrAst):180    """An XDR pointer definition"""181 182    name: str183    fields: List[_XdrDeclaration]184 185 186@dataclass187class _XdrTypedef(_XdrAst):188    """An XDR typedef"""189 190    declaration: _XdrDeclaration191 192 193@dataclass194class _XdrCaseSpec(_XdrAst):195    """One case in an XDR union"""196 197    values: List[str]198    arm: _XdrDeclaration199    template: str = "case_spec"200 201 202@dataclass203class _XdrDefaultSpec(_XdrAst):204    """Default case in an XDR union"""205 206    arm: _XdrDeclaration207    template: str = "default_spec"208 209 210@dataclass211class _XdrUnion(_XdrAst):212    """An XDR union"""213 214    name: str215    discriminant: _XdrDeclaration216    cases: List[_XdrCaseSpec]217    default: _XdrDeclaration218 219 220@dataclass221class _RpcProcedure(_XdrAst):222    """RPC procedure definition"""223 224    name: str225    number: str226    argument: _XdrTypeSpecifier227    result: _XdrTypeSpecifier228 229 230@dataclass231class _RpcVersion(_XdrAst):232    """RPC version definition"""233 234    name: str235    number: str236    procedures: List[_RpcProcedure]237 238 239@dataclass240class _RpcProgram(_XdrAst):241    """RPC program definition"""242 243    name: str244    number: str245    versions: List[_RpcVersion]246 247 248@dataclass249class _Pragma(_XdrAst):250    """Empty class for pragma directives"""251 252 253@dataclass254class Definition(_XdrAst, ast_utils.WithMeta):255    """Corresponds to 'definition' in the grammar"""256 257    meta: Meta258    value: _XdrAst259 260 261@dataclass262class Specification(_XdrAst, ast_utils.AsList):263    """Corresponds to 'specification' in the grammar"""264 265    definitions: List[Definition]266 267 268class ParseToAst(Transformer):269    """Functions that transform productions into AST nodes"""270 271    def identifier(self, children):272        """Instantiate one _XdrIdentifier object"""273        return _XdrIdentifier(children[0].value)274 275    def value(self, children):276        """Instantiate one _XdrValue object"""277        if isinstance(children[0], _XdrIdentifier):278            return _XdrValue(children[0].symbol)279        return _XdrValue(children[0].children[0].value)280 281    def constant(self, children):282        """Instantiate one _XdrConstantValue object"""283        match children[0].data:284            case "decimal_constant":285                value = int(children[0].children[0].value, base=10)286            case "hexadecimal_constant":287                value = int(children[0].children[0].value, base=16)288            case "octal_constant":289                value = int(children[0].children[0].value, base=8)290        return _XdrConstantValue(value)291 292    def type_specifier(self, children):293        """Instantiate one type_specifier object"""294        c_classifier = ""295        if isinstance(children[0], _XdrIdentifier):296            name = children[0].symbol297            if name in enums:298                c_classifier = "enum "299            if name in structs:300                c_classifier = "struct "301            return _XdrDefinedType(302                type_name=name,303                c_classifier=c_classifier,304            )305 306        token = children[0].data307        return _XdrBuiltInType(308            type_name=token.value,309            c_classifier=c_classifier,310        )311 312    def constant_def(self, children):313        """Instantiate one _XdrConstant object"""314        name = children[0].symbol315        value = children[1].value316        return _XdrConstant(name, value)317 318    # cel: Python can compute a min() and max() for the enumerator values319    #      so that the generated code can perform proper range checking.320    def enum(self, children):321        """Instantiate one _XdrEnum object"""322        enum_name = children[0].symbol323        enums.add(enum_name)324 325        i = 0326        enumerators = []327        body = children[1]328        while i < len(body.children):329            name = body.children[i].symbol330            value = body.children[i + 1].value331            enumerators.append(_XdrEnumerator(name, value))332            i = i + 2333 334        return _XdrEnum(enum_name, 0, 0, enumerators)335 336    def fixed_length_opaque(self, children):337        """Instantiate one _XdrFixedLengthOpaque declaration object"""338        name = children[0].symbol339        size = children[1].value340 341        return _XdrFixedLengthOpaque(name, size)342 343    def variable_length_opaque(self, children):344        """Instantiate one _XdrVariableLengthOpaque declaration object"""345        name = children[0].symbol346        if children[1] is not None:347            maxsize = children[1].value348        else:349            maxsize = "0"350 351        return _XdrVariableLengthOpaque(name, maxsize)352 353    def variable_length_string(self, children):354        """Instantiate one _XdrVariableLengthString declaration object"""355        name = children[0].symbol356        if children[1] is not None:357            maxsize = children[1].value358        else:359            maxsize = "0"360 361        return _XdrVariableLengthString(name, maxsize)362 363    def fixed_length_array(self, children):364        """Instantiate one _XdrFixedLengthArray declaration object"""365        spec = children[0]366        name = children[1].symbol367        size = children[2].value368 369        return _XdrFixedLengthArray(name, spec, size)370 371    def variable_length_array(self, children):372        """Instantiate one _XdrVariableLengthArray declaration object"""373        spec = children[0]374        name = children[1].symbol375        if children[2] is not None:376            maxsize = children[2].value377        else:378            maxsize = "0"379 380        return _XdrVariableLengthArray(name, spec, maxsize)381 382    def optional_data(self, children):383        """Instantiate one _XdrOptionalData declaration object"""384        spec = children[0]385        name = children[1].symbol386        structs.add(name)387        pass_by_reference.add(name)388 389        return _XdrOptionalData(name, spec)390 391    def basic(self, children):392        """Instantiate one _XdrBasic object"""393        spec = children[0]394        name = children[1].symbol395 396        return _XdrBasic(name, spec)397 398    def void(self, children):399        """Instantiate one _XdrVoid declaration object"""400 401        return _XdrVoid()402 403    def struct(self, children):404        """Instantiate one _XdrStruct object"""405        name = children[0].symbol406        structs.add(name)407        pass_by_reference.add(name)408        fields = children[1].children409 410        last_field = fields[-1]411        if (412            isinstance(last_field, _XdrOptionalData)413            and name == last_field.spec.type_name414        ):415            return _XdrPointer(name, fields)416 417        return _XdrStruct(name, fields)418 419    def typedef(self, children):420        """Instantiate one _XdrTypedef object"""421        new_type = children[0]422        if isinstance(new_type, _XdrBasic) and isinstance(423            new_type.spec, _XdrDefinedType424        ):425            if new_type.spec.type_name in pass_by_reference:426                pass_by_reference.add(new_type.name)427 428        return _XdrTypedef(new_type)429 430    def case_spec(self, children):431        """Instantiate one _XdrCaseSpec object"""432        values = []433        for item in children[0:-1]:434            values.append(item.value)435        arm = children[-1]436 437        return _XdrCaseSpec(values, arm)438 439    def default_spec(self, children):440        """Instantiate one _XdrDefaultSpec object"""441        arm = children[0]442 443        return _XdrDefaultSpec(arm)444 445    def union(self, children):446        """Instantiate one _XdrUnion object"""447        name = children[0].symbol448        structs.add(name)449        pass_by_reference.add(name)450 451        body = children[1]452        discriminant = body.children[0].children[0]453        cases = body.children[1:-1]454        default = body.children[-1]455 456        return _XdrUnion(name, discriminant, cases, default)457 458    def procedure_def(self, children):459        """Instantiate one _RpcProcedure object"""460        result = children[0]461        name = children[1].symbol462        argument = children[2]463        number = children[3].value464 465        return _RpcProcedure(name, number, argument, result)466 467    def version_def(self, children):468        """Instantiate one _RpcVersion object"""469        name = children[0].symbol470        number = children[-1].value471        procedures = children[1:-1]472 473        return _RpcVersion(name, number, procedures)474 475    def program_def(self, children):476        """Instantiate one _RpcProgram object"""477        name = children[0].symbol478        number = children[-1].value479        versions = children[1:-1]480 481        return _RpcProgram(name, number, versions)482 483    def pragma_def(self, children):484        """Instantiate one _Pragma object"""485        directive = children[0].children[0].data486        match directive:487            case "exclude_directive":488                excluded_apis.append(children[1].symbol)489            case "header_directive":490                global header_name491                header_name = children[1].symbol492            case "public_directive":493                public_apis.append(children[1].symbol)494            case _:495                raise NotImplementedError("Directive not supported")496        return _Pragma()497 498 499transformer = ast_utils.create_transformer(this_module, ParseToAst())500 501 502def transform_parse_tree(parse_tree):503    """Transform productions into an abstract syntax tree"""504 505    return transformer.transform(parse_tree)506 507 508def get_header_name() -> str:509    """Return header name set by pragma header directive"""510    return header_name511