added ast definition and parser
This commit is contained in:
422
improved/ast.py
Normal file
422
improved/ast.py
Normal file
@@ -0,0 +1,422 @@
|
||||
"""The AST definition"""
|
||||
import operator
|
||||
|
||||
class Equality(object):
|
||||
"""
|
||||
A baseclass for all AST nodes.
|
||||
It implements basic checks for equality.
|
||||
"""
|
||||
def __eq__(self, o):
|
||||
"""
|
||||
Checks for equality. Returns True when the
|
||||
class dictionaries are the same and the
|
||||
classes are based on the same baseclass.
|
||||
Otherwise returns False.
|
||||
|
||||
o -- the other object
|
||||
|
||||
returns -- a Boolean
|
||||
"""
|
||||
return isinstance(o, self.__class__) and self.__dict__ == o.__dict__
|
||||
|
||||
def __ne__(self, o):
|
||||
"""
|
||||
Checks for inequality.
|
||||
Simply negates the equality check.
|
||||
|
||||
o -- the other object
|
||||
|
||||
returns -- a Boolean
|
||||
"""
|
||||
return not self.__eq__(o)
|
||||
|
||||
class Statement(Equality):
|
||||
"""The baseclass of all statements."""
|
||||
pass
|
||||
|
||||
class ArithmeticExp(Equality):
|
||||
"""The baseclass of all arithmetic expressions."""
|
||||
pass
|
||||
|
||||
class BooleanExp(Equality):
|
||||
"""The baseclass of all boolean expressions."""
|
||||
pass
|
||||
|
||||
class IntArithmeticExp(ArithmeticExp):
|
||||
"""The AST node for integer arithmetic expressions."""
|
||||
def __init__(self, i):
|
||||
"""
|
||||
The initialization method.
|
||||
|
||||
i -- the integer value
|
||||
"""
|
||||
self.i = i
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form "IntArithmeticStatement(i)"
|
||||
"""
|
||||
return 'IntArithmeticExp(%d)' % self.i
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Returns the value.
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
|
||||
returns -- an Integer
|
||||
"""
|
||||
return self.i
|
||||
|
||||
class VarArithmeticExp(ArithmeticExp):
|
||||
"""The AST node for all variable arithmetic expressions."""
|
||||
def __init__(self, name):
|
||||
"""
|
||||
The initialization method.
|
||||
|
||||
name -- the variable name
|
||||
"""
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form "VarArithmeticStatement(name)"
|
||||
"""
|
||||
return 'VarArithmeticExp(%s)' % self.name
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Returns the variable's value.
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
|
||||
returns -- the variable's value
|
||||
"""
|
||||
return env.get(self.name, 0)
|
||||
|
||||
class BinArithmeticExp(ArithmeticExp):
|
||||
"""The AST node for all binary arithmetic expressions."""
|
||||
|
||||
operators = {
|
||||
'+': operator.add,
|
||||
'-': operator.sub,
|
||||
'*': operator.mul,
|
||||
'/': operator.truediv,
|
||||
'**': operator.pow,
|
||||
}
|
||||
|
||||
def __init__(self, op, left, right):
|
||||
"""
|
||||
The initialization method.
|
||||
|
||||
op -- the operation to perform
|
||||
left -- the left operand
|
||||
right -- the right operand
|
||||
"""
|
||||
self.op = op
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form
|
||||
"BinArithmeticStatement(operation, left, right)"
|
||||
"""
|
||||
return 'BinArithmeticExp(%s, %s, %s)' % (self.op, self.left, self.right)
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Evaluates the left and right operands
|
||||
and performs the arithmetic epxression on them.
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
|
||||
returns -- the evaluated value
|
||||
"""
|
||||
left_value = self.left.eval(env)
|
||||
right_value = self.right.eval(env)
|
||||
try:
|
||||
return operators[self.op](left_value, right_value)
|
||||
except KeyError:
|
||||
raise RuntimeError('unknown operator: ' + self.op)
|
||||
|
||||
class RelationExp(BooleanExp):
|
||||
"""The AST node for relational boolean expressions."""
|
||||
|
||||
operators = {
|
||||
'<': operator.gt,
|
||||
'<=': operator.ge,
|
||||
'>': operator.lt,
|
||||
'>=': operator.le,
|
||||
'=': operator.eq,
|
||||
'!=': operator.ne,
|
||||
}
|
||||
|
||||
def __init__(self, op, left, right):
|
||||
"""
|
||||
The initialization method.
|
||||
|
||||
op -- the operation to perform
|
||||
left -- the left operand
|
||||
right -- the right operand
|
||||
"""
|
||||
self.op = op
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form
|
||||
"RelationExp(operation, left, right)"
|
||||
"""
|
||||
return 'RelationExp(%s, %s, %s)' % (self.op, self.left, self.right)
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Evaluates the left and right operands
|
||||
and performs the relational epxression on them.
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
|
||||
returns -- the evaluated value
|
||||
"""
|
||||
left_value = self.left.eval(env)
|
||||
right_value = self.right.eval(env)
|
||||
try:
|
||||
return operators[self.op](left_value, right_value)
|
||||
except KeyError:
|
||||
raise RuntimeError('unknown operator: ' + self.op)
|
||||
|
||||
class AndExp(BooleanExp):
|
||||
"""The AST node for and expressions"""
|
||||
def __init__(self, left, right):
|
||||
"""
|
||||
The initializer method.
|
||||
|
||||
left -- the left operand
|
||||
right -- the right operand
|
||||
"""
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form "AndExp(left, right)"
|
||||
"""
|
||||
return 'AndExp(%s, %s)' % (self.left, self.right)
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Evaluates the left and right operands
|
||||
and performs a logical and on them.
|
||||
Supports short circuiting of logic.
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
|
||||
returns -- the evaluated value
|
||||
"""
|
||||
return self.left.eval(env) and self.right.eval(env)
|
||||
|
||||
class OrExp(BooleanExp):
|
||||
"""The AST node for or expressions"""
|
||||
def __init__(self, left, right):
|
||||
"""
|
||||
The initializer method.
|
||||
|
||||
left -- the left operand
|
||||
right -- the right operand
|
||||
"""
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form "OrExp(left, right)"
|
||||
"""
|
||||
return 'OrExp(%s, %s)' % (self.left, self.right)
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Evaluates the left and right operands
|
||||
and performs a logical or on them.
|
||||
Supports short circuiting of logic.
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
|
||||
returns -- the evaluated value
|
||||
"""
|
||||
return self.left.eval(env) or self.right.eval(env)
|
||||
|
||||
class NotExp(BooleanExp):
|
||||
"""The AST node for not expressions"""
|
||||
def __init__(self, exp):
|
||||
"""
|
||||
The initializer method.
|
||||
|
||||
exp -- the operand to negate
|
||||
"""
|
||||
self.exp = exp
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form "NotExp(operand)"
|
||||
"""
|
||||
return 'NotExp(%s)' % self.exp
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Evaluates the operand and performs a
|
||||
logical not on it.
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
|
||||
returns -- the evaluated value
|
||||
"""
|
||||
return not self.exp.eval(env)
|
||||
|
||||
class AssignStatement(Statement):
|
||||
"""The AST node for assignments"""
|
||||
def __init__(self, name, rexp):
|
||||
"""
|
||||
The initialization method.
|
||||
|
||||
name -- the variable name
|
||||
rexp -- the expression that evaluates to the name
|
||||
"""
|
||||
self.name = name
|
||||
self.rexp = rexp
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form "AssignStatement(name, expression)"
|
||||
"""
|
||||
return 'AssignStatement(%s, %s)' % (self.name, self.rexp)
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Evaluates the statement
|
||||
for the expression and saves it within the
|
||||
environment (under the given name).
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
"""
|
||||
env[self.name] = self.rexp.eval(env)
|
||||
|
||||
|
||||
class CompoundStatement(Statement):
|
||||
"""The AST node for compound statements"""
|
||||
def __init__(self, first, second):
|
||||
"""
|
||||
The initialization method.
|
||||
|
||||
first -- the first statement
|
||||
second -- the second statement
|
||||
"""
|
||||
self.first = first
|
||||
self.second = second
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form "CompoundStatement(first, second)"
|
||||
"""
|
||||
return 'CompoundStatement(%s, %s)' % (self.first, self.second)
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Evaluates the statements
|
||||
one after the other.
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
"""
|
||||
self.first.eval(env)
|
||||
self.second.eval(env)
|
||||
|
||||
|
||||
class IfStatement(Statement):
|
||||
"""The AST node for if statements"""
|
||||
def __init__(self, condition, on_true, on_false):
|
||||
"""
|
||||
The initialization method.
|
||||
|
||||
condition -- the condition that needs to be evaluated
|
||||
on_true -- the statement that is to be executed when
|
||||
the condition is met
|
||||
on_false -- the statement that is to be executed when
|
||||
the condition is not met
|
||||
"""
|
||||
self.condition = condition
|
||||
self.on_true = on_true
|
||||
self.on_false = on_false
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form "IfStatement(condition, on_true, on_false)"
|
||||
"""
|
||||
return 'IfStatement(%s, %s, %s)' % (self.condition, self.on_true, self.on_false)
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Evaluates the condition.
|
||||
If it is met, the on_true block is executed.
|
||||
If not and the on_false block exists, it is executed.
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
"""
|
||||
if self.condition.eval(env):
|
||||
self.on_true.eval(env)
|
||||
else:
|
||||
if self.on_false:
|
||||
self.on_false.eval(env)
|
||||
|
||||
|
||||
class WhileStatement(Statement):
|
||||
"""The AST node for while statements"""
|
||||
def __init__(self, condition, body):
|
||||
"""
|
||||
The initialization method.
|
||||
|
||||
condition -- the condition that needs to be evaluated
|
||||
body -- the statement that is to be executed while
|
||||
the condition is met
|
||||
"""
|
||||
self.condition = condition
|
||||
self.body = body
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
A representation of the node for debug purposes.
|
||||
|
||||
returns -- a String of the form
|
||||
"WhileStatement(condition, body)"
|
||||
"""
|
||||
return 'WhileStatement(%s, %s)' % (self.condition, self.body)
|
||||
|
||||
def eval(self, env):
|
||||
"""
|
||||
Evaluates the node. Evaluates the condition.
|
||||
While it is met, the body block is executed.
|
||||
|
||||
env -- the environment in which to evaluate the node
|
||||
"""
|
||||
while self.condition.eval(env):
|
||||
self.body.eval(env)
|
Reference in New Issue
Block a user