Source code for bluebase.lp.parser

from bluebase.core import (
    Value,
    Domain,
    BoolDomain,
    IntDomain,
    FloatDomain,
    StringDomain,
    Comp,
    Ast,
    AstTable,
    AstAttr,
    AstCond,
    AstAssign,
    AstDefine,
    AstSelect,
    AstInsert,
    AstDelete,
    AstUpdate,
    AstCreateTable,
    AstCreateIndex,
    AstDropTable,
    AstDropIndex,
    AstShowTables,
    AstDescribeTable,
    AstDumpTable,
    AstExit,
    assignment,
)

from .error import (
    LpUnexpectedEndOfInputError,
    LpUnexpectedTokenError,
    LpUnexpectedKeywordError,
    LpUnexpectedCompError,
    LpUnknownStatementError,
)
from .type import LpToken


__all__ = (
    'LpParser',
)


[docs] class LpParser: """ A parser that converts input tokens into an `AST <bluebase.core.ast>`. Attributes: tokens: the input tokens position: the current position """ tokens: list[LpToken] position: int def __repr__(self) -> str: # pragma: no cover return "LpParser()" def __init__(self, tokens: list[LpToken]) -> None: self.tokens = tokens self.position = 0
[docs] @assignment def peek(self) -> LpToken | None: """ Return the token at the current position. Hint: If the current position is out of bounds, return ``None``. """ raise NotImplementedError
[docs] @assignment def consume(self, tag: str | None = None) -> LpToken: """ Consume the token at the current position and advance. If tag is specified, consume only a token with the matching tag. Raises: LpUnexpectedEndOfInputError: if there are no more tokens LpUnexpectedTokenError: if the token tag does not match Hint: Use `peek`. """ raise NotImplementedError
[docs] @assignment def match_tag(self, tag: str) -> bool: """ Match the token tag at the current position and advance on success. Hint: Use `peek`. """ raise NotImplementedError
[docs] @assignment def match_keyword(self, keyword: str) -> bool: """ Match a ``WORD`` with the given keyword and advance on success. Hint: Use `peek`. """ raise NotImplementedError
[docs] @assignment def expect_keyword(self, keyword: str) -> None: """ Consume a ``WORD`` matching the given keyword. Raises: LpUnexpectedKeywordError: if the token value does not match Hint: Use `consume`. """ raise NotImplementedError
[docs] @assignment def parse_table(self) -> AstTable: """ Parse a ``table``. .. rubric:: Grammar :: table : WORD | WORD "AS" WORD Hint: Consume the ``WORD`` for the table name. If the ``"AS"`` keyword matches, consume the ``WORD`` for the alias. """ raise NotImplementedError
[docs] @assignment def parse_tables(self) -> list[AstTable]: """ Parse a ``tables``. .. rubric:: Grammar :: tables : table | tables COMMA table Hint: Use `parse_table` to parse each ``table``. Whenever a ``COMMA`` is matched, parse another ``table``. """ raise NotImplementedError
[docs] @assignment def parse_attr(self) -> AstAttr: """ Parse a ``attr``. .. rubric:: Grammar :: attr : WORD | WORD DOT WORD Hint: First, consume a ``WORD``. If a ``DOT`` matches, consume another ``WORD`` and return an `~bluebase.core.ast.AstAttr` with a table name. If there is no ``DOT``, return an `~bluebase.core.ast.AstAttr` without a table name. """ raise NotImplementedError
[docs] @assignment def parse_attrs(self) -> list[AstAttr]: """ Parse a ``attrs``. .. rubric:: Grammar :: attrs : attr | attrs COMMA attr Hint: Use `parse_attr` to parse each ``attr``. Whenever a ``COMMA`` is matched, parse another ``attr``. """ raise NotImplementedError
[docs] @assignment def parse_value(self) -> Value: """ Parse a ``value``. .. rubric:: Grammar :: value : FLOAT | INT | BOOL | STRING Raises: LpUnexpectedTokenError: if the token tag is invalid Hint: Consume a token and return the value based on its tag. Note that when parsing a ``STRING``, strip the surrounding quotes. """ raise NotImplementedError
[docs] @assignment def parse_values(self) -> tuple[Value, ...]: """ Parse a ``values``. .. rubric:: Grammar :: values : value | values COMMA value Hint: Use `parse_value` to parse each ``value``. Whenever a ``COMMA`` is matched, parse another ``value``. """ raise NotImplementedError
[docs] @assignment def parse_hand(self) -> AstAttr | Value: """ Parse a ``hand``. .. rubric:: Grammar :: hand : attr | value Raises: LpUnexpectedEndOfInputError: if there are no more tokens Hint: First, peek a token. If the token is a ``WORD``, parse an ``attr``. Otherwise, parse a ``value``. """ raise NotImplementedError
[docs] @assignment def parse_cond(self) -> AstCond: """ Parse a ``cond``. .. rubric:: Grammar :: cond : attr COMP hand Hint: First, parse the left ``attr``, then consume a ``COMP``, and then parse the right ``hand``. """ raise NotImplementedError
[docs] @assignment def parse_conds(self) -> list[AstCond]: """ Parse a ``conds``. .. rubric:: Grammar :: conds : cond | conds "AND" cond Hint: Use `parse_cond` to parse each ``cond``. Whenever a ``"AND"`` is matched, parse another ``cond``. """ raise NotImplementedError
[docs] @assignment def parse_assign(self) -> AstAssign: """ Parse a ``assign``. .. rubric:: Grammar :: assign : attr COMP hand Raises: LpUnexpectedCompError: if the comparison operator is not ``'='`` Hint: First, parse the left ``attr``, then consume a ``COMP``, and then parse the right ``hand``. If the comparison operator is not ``'='``, raise an error. """ raise NotImplementedError
[docs] @assignment def parse_assigns(self) -> list[AstAssign]: """ Parse a ``assigns``. .. rubric:: Grammar :: assigns : assign | assigns COMMA assign Hint: Use `parse_assign` to parse each ``assign``. Whenever a ``COMMA`` is matched, parse another ``assign``. """ raise NotImplementedError
[docs] @assignment def parse_domain(self) -> Domain: """ Parse a ``domain``. .. rubric:: Grammar :: domain : BOOL | INT | FLOAT | STRING LP INT RP Raises: LpUnexpectedKeywordError: if the token value is not a valid domain Hint: Consume a ``WORD`` and return the domain based on its value. If the token value is ``"STRING"``, consume a ``LP``, then consume an ``INT``, and then consume a ``RP`` and return a `~bluebase.core.domain.StringDomain` with the length. """ raise NotImplementedError
[docs] @assignment def parse_define(self) -> AstDefine: """ Parse a ``define``. .. rubric:: Grammar :: define : attr domain Hint: First, parse the ``attr``, then parse the ``domain``. """ raise NotImplementedError
[docs] @assignment def parse_defines(self) -> list[AstDefine]: """ Parse a ``defines``. .. rubric:: Grammar :: defines : define | defines COMMA define Hint: Use `parse_define` to parse each ``define``. Whenever a ``COMMA`` is matched, parse another ``define``. """ raise NotImplementedError
[docs] @assignment def parse_where_clause(self) -> list[AstCond]: """ Parse a ``where_clause``. .. rubric:: Grammar :: where_clause : | "WHERE" conds Hint: If the ``"WHERE"`` keyword matches, parse the ``conds``. Otherwise, return an empty list. """ raise NotImplementedError
[docs] @assignment def parse_select_statement(self) -> AstSelect: """ Parse a ``select_statement``. .. rubric:: Grammar :: select_statement : "SELECT" attrs "FROM" tables where_clause SC Hint: Don't forget to consume a ``SC`` at the end. """ raise NotImplementedError
[docs] @assignment def parse_insert_statement(self) -> AstInsert: """ Parse a ``insert_statement``. .. rubric:: Grammar :: insert_statement : "INSERT" "INTO" table "VALUES" LP values RP SC Hint: Don't forget to consume a ``SC`` at the end. """ raise NotImplementedError
[docs] @assignment def parse_delete_statement(self) -> AstDelete: """ Parse a ``delete_statement``. .. rubric:: Grammar :: delete_statement : "DELETE" "FROM" table where_clause SC Hint: Don't forget to consume a ``SC`` at the end. """ raise NotImplementedError
[docs] @assignment def parse_update_statement(self) -> AstUpdate: """ Parse a ``update_statement``. .. rubric:: Grammar :: update_statement : "UPDATE" table "SET" assigns where_clause SC Hint: Don't forget to consume a ``SC`` at the end. """ raise NotImplementedError
[docs] @assignment def parse_create_statement(self) -> AstCreateTable | AstCreateIndex: """ Parse a ``create_statement``. .. rubric:: Grammar :: create_statement : "CREATE" "TABLE" create_table_body SC | "CREATE" "INDEX" create_index_body SC Raises: LpUnknownStatementError: if the statement is unknown Hint: After matching the ``"CREATE"`` keyword, consume a ``WORD`` and match the statement. Don't forget to consume a ``SC`` at the end. """ raise NotImplementedError
[docs] @assignment def parse_create_table_body(self) -> AstCreateTable: """ Parse a ``create_table_body``. .. rubric:: Grammar :: create_table_body : table LP defines RP Hint: Note that ``"CREATE"`` and ``"TABLE"`` keywords are already consumed. """ raise NotImplementedError
[docs] @assignment def parse_create_index_body(self) -> AstCreateIndex: """ Parse a ``create_index_body``. .. rubric:: Grammar :: create_index_body : attr "OF" table Hint: Note that ``"CREATE"`` and ``"INDEX"`` keywords are already consumed. """ raise NotImplementedError
[docs] @assignment def parse_drop_statement(self) -> AstDropTable | AstDropIndex: """ Parse a ``drop_statement``. .. rubric:: Grammar :: drop_statement : "DROP" "TABLE" drop_table_body SC | "DROP" "INDEX" drop_index_body SC Raises: LpUnknownStatementError: if the statement is unknown Hint: After matching the ``"DROP"`` keyword, consume a ``WORD`` and match the statement. Don't forget to consume a ``SC`` at the end. """ raise NotImplementedError
[docs] @assignment def parse_drop_table_body(self) -> AstDropTable: """ Parse a ``drop_table_body``. .. rubric:: Grammar :: drop_table_body : table Hint: Note that ``"DROP"`` and ``"TABLE"`` keywords are already consumed. """ raise NotImplementedError
[docs] @assignment def parse_drop_index_body(self) -> AstDropIndex: """ Parse a ``drop_index_body``. .. rubric:: Grammar :: drop_index_body : attr "OF" table Hint: Note that ``"DROP"`` and ``"INDEX"`` keywords are already consumed. """ raise NotImplementedError
[docs] @assignment def parse_show_tables_statement(self) -> AstShowTables: """ Parse a ``show_tables_statement``. .. rubric:: Grammar :: show_tables_statement : "SHOW" "TABLES" SC Hint: Don't forget to consume a ``SC`` at the end. """ raise NotImplementedError
[docs] @assignment def parse_describe_table_statement(self) -> AstDescribeTable: """ Parse a ``describe_table_statement``. .. rubric:: Grammar :: describe_table_statement : "DESCRIBE" "TABLE" table SC Hint: Don't forget to consume a ``SC`` at the end. """ raise NotImplementedError
[docs] @assignment def parse_dump_table_statement(self) -> AstDumpTable: """ Parse a ``dump_table_statement``. .. rubric:: Grammar :: dump_table_statement : "DUMP" "TABLE" table SC Hint: Don't forget to consume a ``SC`` at the end. """ raise NotImplementedError
[docs] @assignment def parse_exit_statement(self) -> AstExit: """ Parse a ``exit_statement``. .. rubric:: Grammar :: exit_statement : "EXIT" SC Hint: Don't forget to consume a ``SC`` at the end. """ raise NotImplementedError
[docs] def parse(self) -> Ast: """ Parse the input tokens into an `AST <bluebase.core.ast>`. Raises: LpUnexpectedEndOfInputError: if there are no more tokens LpUnexpectedTokenError: if the first token is not a ``WORD`` LpUnknownStatementError: if the statement is unknown """ token = self.peek() if token is None: raise LpUnexpectedEndOfInputError if token.tag != 'WORD': raise LpUnexpectedTokenError( token=token.value, got=token.tag, expected='WORD', ) statement = token.value.upper() match statement: case 'SELECT': return self.parse_select_statement() case 'INSERT': return self.parse_insert_statement() case 'DELETE': return self.parse_delete_statement() case 'UPDATE': return self.parse_update_statement() case 'CREATE': return self.parse_create_statement() case 'DROP': return self.parse_drop_statement() case 'SHOW': return self.parse_show_tables_statement() case 'DESCRIBE': return self.parse_describe_table_statement() case 'DUMP': return self.parse_dump_table_statement() case 'EXIT': return self.parse_exit_statement() case _: raise LpUnknownStatementError(statement=statement)