Example #1
0
def _block(stream: TokenStream) -> expr.Expr:
    """
    block ::= { stmt }
    """
    log.debug(f"Parsing block from token {stream.peek()}")
    if stream.peek().kind not in first["stmt"]:
        return expr.Pass()
    left = _stmt(stream)
    log.debug(f"Starting block with {left}")
    while stream.peek().kind in first["stmt"]:
        right = _stmt(stream)
        log.debug(f"Adding statement to block: {right}")
        left = expr.Seq(left, right)
    return left
Example #2
0
def require(stream: TokenStream, category: TokenCat, desc: str = "", consume=False):
    """Requires the next token in the stream to match a specified category.
    Consumes and discards it if consume==True.
    """
    if stream.peek().kind != category:
        raise InputError(f"Expecting {desc or category}, but saw {stream.peek()} instead")
    if consume:
        stream.take()
    return
Example #3
0
def _stmt(stream: TokenStream) -> expr.Expr:
    """
    stmt ::= exp ['=' exp]
    """
    left = _expr(stream)
    if stream.peek().kind is TokenCat.EQUALS:
        stream.take()
        right = _expr(stream)
        return expr.Equals(left, right)
    else:
        return left
Example #4
0
def _stmt(stream: TokenStream) -> expr.Expr:
    """
    #  stmt ::=  assign | loop | ifstmt | printstmt
    assignment ::= IDENT '=' expression ';'
    """
    if stream.peek().kind is TokenCat.WHILE:
        return _while(stream)
    if stream.peek().kind is TokenCat.IF:
        return _if(stream)
    if stream.peek().kind is TokenCat.PRINT:
        return _print(stream)
    if stream.peek().kind is not TokenCat.VAR:
        raise InputError(
            f"Expecting identifier at beginning of assignment, got {stream.peek()}"
        )
    target = expr.Var(stream.take().value)
    if stream.peek().kind is not TokenCat.ASSIGN:
        raise InputError(f"Expecting assignment symbol, got {stream.peek()}")
    stream.take()  # Discard token
    value = _expr(stream)
    if stream.peek().kind is not TokenCat.SEMI:
        raise InputError(
            f"Expecting semicolon after assignment, got {stream.peek()}")
    stream.take()  # Discard token
    return expr.Assign(target, value)
Example #5
0
def _stmt(stream: TokenStream) -> expr.Expr:
    """
    stmt ::= exp ['=' exp]
    """
    left = _expr(stream)
    if stream.peek().kind is TokenCat.ASSIGN:
        if not isinstance(left, expr.Var):
            raise InputError("Can only assign to a variable")
        stream.take()
        right = _expr(stream)
        return expr.Assign(left, right)
    else:
        return left
Example #6
0
def _if(stream: TokenStream) -> expr.If:
    require(stream, TokenCat.IF, consume=True)
    cond = _rel(stream)
    require(stream, TokenCat.THEN, consume=True)
    then_block = _block(stream)
    if stream.peek().kind == TokenCat.ELSE:
        require(stream, TokenCat.ELSE, consume=True)
        else_block = _block(stream)
        result = expr.If(cond, then_block, else_block)
    else:
        result = expr.If(cond, then_block, elsepart=expr.Pass())
    require(stream, TokenCat.FI, consume=True)
    return result
Example #7
0
def _term(stream: TokenStream) -> expr.Expr:
    """term ::= primary { ('*'|'/')  primary }"""
    left = _secondary(stream)
    log.debug(f"term starts with {left}")
    while stream.peek().value in ["*", "/"]:
        op = stream.take()
        right = _secondary(stream)
        if op.value == "*":
            left = expr.Times(left, right)
        elif op.value == "/":
            left = expr.Div(left, right)
        else:
            raise InputError(f"Expecting multiplicative op, got {op}")
    return left
Example #8
0
def _secondary(stream: TokenStream) -> expr.Expr:
    """term ::= secondary { ('^'|'|')  secondary }"""
    left = _primary(stream)
    log.debug(f"term starts with {left}")
    while stream.peek().value in ["^", "|"]:
        op = stream.take()
        right = _primary(stream)
        if op.value == "^":
            left = expr.Raise(left, right)
        elif op.value == "|":
            left = expr.Root(left, right)
        else:
            raise InputError(f"Expecting Exponential op, got {op}")
    return left
Example #9
0
def _expr(stream: TokenStream) -> expr.Expr:
    """
    expr ::= term { ('+'|'-') term }
    """
    log.debug(f"parsing sum starting from token {stream.peek()}")
    left = _term(stream)
    log.debug(f"sum begins with {left}")
    while stream.peek().value in ["+", "-"]:
        op = stream.take()
        log.debug(f"expr addition op {op}")
        right = _term(stream)
        if op.value == "+":
            left = expr.Plus(left, right)
        elif op.value == "-":
            left = expr.Minus(left, right)
        else:
            raise InputError(f"What's that op? {op}")
    return left