Verified Commit 71629dd1 authored by Alberto Miranda's avatar Alberto Miranda ♨️
Browse files

Construct AST and extract its information

parent 9e193811
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ import sys

from rpcc.version import __version__ as rpcc_version
from rpcc.parser import Parser
from rpcc.transformers.cxx import Transformer as CppTransformer
from pathlib import Path


@@ -50,6 +51,7 @@ def main(args=None):
    # try:
    ast = Parser(args.rpc_proto_file).parse()
    print(ast.pretty())
    print(CppTransformer().transform(ast).pretty())

    # except Exception:
    #    return 1
+8 −16
Original line number Diff line number Diff line
@@ -3,37 +3,29 @@ from loguru import logger

GRAMMAR = r"""
    start           : ( rpc )+
                    | empty_statement
    rpc             : "rpc" rpc_name rpc_body
    rpc_name        : ident
    rpc_body        : "{" ( rpc_args | rpc_return | empty_statement )+ "};"
    rpc_args        : "arguments" rpc_args_body
    rpc_args_body   : "{" ( arg | empty_statement )+ "};"

    arg             : type ident ";"

    rpc             : "rpc" rpc_name "{" (rpc_args rpc_return | rpc_args | rpc_return) "}"
    rpc_name        : NAME
    rpc_args        : "arguments" "{" ( var | )+ "}"
    rpc_return      : "returns" "{" ( var | ) "}"
    var             : type NAME
    type            : "double"         -> double
                    | "float"          -> float
                    | "int32"          -> int32
                    | "uint32"         -> uint32
                    | "string"         -> string
                    | "exposed_buffer" -> exposed_buffer
    rpc_return      : "returns" rpc_return_body
    rpc_return_body : "{" ( arg | empty_statement ) "};"
    field_name      : ident
    ?ident          : CNAME
    empty_statement : ";"*
    COMMENT         : /#+[^\n]*/
    EOS             : ";"+

    %import common.CNAME
    %import common.CNAME -> NAME
    %import common.WS
    %ignore WS
    %ignore COMMENT
    %ignore ";"
"""


class Parser:

    def __init__(self, input_file: str):
        self.input_file = input_file
        self.parser = Lark(GRAMMAR, parser='lalr')

rpcc/rpc.py

0 → 100644
+29 −0
Original line number Diff line number Diff line
from typing import List, Any


class Argument:
    def __init__(self, argname: str, typename: str) -> None:
        self.argname = argname
        self.typename = typename

    def __repr__(self) -> str:
        return f"Argument(argname='{self.argname}', typename='{self.typename}')"


class ReturnVariable:
    def __init__(self, varname: str, typename: str) -> None:
        self.varname = varname
        self.typename = typename

    def __repr__(self) -> str:
        return f"ReturnVariable(argname='{self.varname}', typename='{self.typename}')"


class RemoteProcedure:
    def __init__(self, name: str, args: List[Argument], retval: ReturnVariable) -> None:
        self.name = name
        self.args = args
        self.retval = retval

    def __repr__(self) -> str:
        return f"RemoteProcedure(name='{self.name}', args={self.args}, retval={self.retval})"
+0 −0

Empty file added.

+95 −0
Original line number Diff line number Diff line
from typing import List, Tuple, Any

import lark
from lark import v_args, Discard
from loguru import logger

from rpcc.rpc import RemoteProcedure, Argument, ReturnVariable

fwdecls_template = (
    "// forward declarations of public input/output types for this RPC\n"
    "class input;\n"
    "class output;"
)

_cxx_type_map = {
    "double": "double",
    "float": "float",
    "int32": "int32_t",
    "uint32": "uint32_t",
    "string": "std::string",
    "exposed_buffer": "hermes::exposed_memory"
}


class Transformer(lark.Transformer):
    # variable names can be coverted directly into strings
    NAME = str

    # variables can be converted directly into tuples
    var = tuple

    def rpc_args(self, children: List[Tuple[str, str]]) -> List[Argument]:
        """
        Transform a list of tuples returned by Lark into a list of `rpc.Arguments`. The tuples are implicitly
        constructed by Lark by transforming all the `var` nodes in the AST that have this particular `rpc_args` node
        as a parent.

        :param children: A list of tuples describing the rpc arguments.
        :return: A list of `rpc.Arguments`
        """
        return [Argument(varname, typename) for (typename, varname) in children]

    @v_args(inline=True)
    def rpc_return(self, t: Tuple[str, str]) -> ReturnVariable:
        """
        Transform a tuple returned by Lark into a `ReturnVariable`. The tuple is implictly constructed by Lark by
        transforming the `var` node under this particular `rpc_return` node.

        :param t: A tuple describing the rpc return value
        :return: A `rpc.ReturnVariable`
        """
        (typename, varname) = t
        return ReturnVariable(varname, typename)

    @v_args(inline=True)
    def rpc(self, name: str, args: List[Argument], retval: ReturnVariable) -> RemoteProcedure:
        """
        Transform a `rpc` node from the AST into a `RemoteProcedure` object from a name, a list of `Argument`s and a
        `ReturnVariable`.

        :param name: A name for the remote procedure.
        :param args: A list of `Argument` describing the input arguments for the remote procedure.
        :param retval: A `ReturnValue` describing the remote procedure's return value.
        :return: A `RemoteProcedure` object describing the remote procedure.
        """
        return RemoteProcedure(name, args, retval)

    @v_args(inline=True)
    def rpc_name(self, name: str) -> str:
        """
        Transform a `rpc_name` node from the AST into its corresponding string. The string is extracted from the AST
        nodes' value.

        :param name: A string value from the `rpc_name` node.
        :return: A name for the remote procedure.
        """
        return name

    def double(self, _) -> str:
        return _cxx_type_map["double"]

    def float(self, _) -> str:
        return _cxx_type_map["float"]

    def int32(self, _) -> str:
        return _cxx_type_map["int32"]

    def uint32(self, _) -> str:
        return _cxx_type_map["uint32"]

    def string(self, _) -> str:
        return _cxx_type_map["string"]

    def exposed_buffer(self, _) -> str:
        return _cxx_type_map["exposed_buffer"]