423 lines
12 KiB
Python
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)
|