Files
IMProved/improved/ast.py
2015-07-08 16:38:49 +02:00

423 lines
12 KiB
Python

"""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 self.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.lt,
'<=': operator.le,
'>': operator.gt,
'>=': operator.ge,
'=': 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 self.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)