Enable basic support for evaluating float types

This commit is contained in:
Bartłomiej Pluta
2019-07-25 13:37:31 +02:00
parent 6dc503ba86
commit b126f83824
8 changed files with 64 additions and 20 deletions

View File

@@ -1,10 +1,11 @@
from smnp.ast.node.atom import StringLiteral, IntegerLiteral, NoteLiteral, BoolLiteral, TypeLiteral from smnp.ast.node.atom import StringLiteral, IntegerLiteral, NoteLiteral, BoolLiteral, TypeLiteral, FloatLiteral
from smnp.ast.node.identifier import Identifier from smnp.ast.node.identifier import Identifier
from smnp.ast.node.list import List from smnp.ast.node.list import List
from smnp.ast.node.map import Map from smnp.ast.node.map import Map
from smnp.error.runtime import RuntimeException from smnp.error.runtime import RuntimeException
from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluator import Evaluator
from smnp.runtime.evaluators.expression import expressionEvaluator from smnp.runtime.evaluators.expression import expressionEvaluator
from smnp.runtime.evaluators.float import FloatEvaluator
from smnp.runtime.evaluators.iterable import abstractIterableEvaluator from smnp.runtime.evaluators.iterable import abstractIterableEvaluator
from smnp.runtime.tools.error import updatePos from smnp.runtime.tools.error import updatePos
from smnp.type.model import Type from smnp.type.model import Type
@@ -85,6 +86,7 @@ class AtomEvaluator(Evaluator):
return Evaluator.oneOf( return Evaluator.oneOf(
Evaluator.forNodes(StringEvaluator.evaluate, StringLiteral), Evaluator.forNodes(StringEvaluator.evaluate, StringLiteral),
Evaluator.forNodes(IntegerEvaluator.evaluate, IntegerLiteral), Evaluator.forNodes(IntegerEvaluator.evaluate, IntegerLiteral),
Evaluator.forNodes(FloatEvaluator.evaluate, FloatLiteral),
Evaluator.forNodes(NoteEvaluator.evaluate, NoteLiteral), Evaluator.forNodes(NoteEvaluator.evaluate, NoteLiteral),
Evaluator.forNodes(BoolEvaluator.evaluate, BoolLiteral), Evaluator.forNodes(BoolEvaluator.evaluate, BoolLiteral),
Evaluator.forNodes(TypeEvaluator.evaluate, TypeLiteral), Evaluator.forNodes(TypeEvaluator.evaluate, TypeLiteral),

View File

@@ -0,0 +1,9 @@
from smnp.runtime.evaluator import Evaluator
from smnp.type.model import Type
class FloatEvaluator(Evaluator):
@classmethod
def evaluator(cls, node, environment):
return Type.float(node.value)

View File

@@ -11,6 +11,7 @@ class MinusEvaluator(Evaluator):
try: try:
return { return {
Type.INTEGER: cls.evaluateForInteger, Type.INTEGER: cls.evaluateForInteger,
Type.FLOAT: cls.evaluateForFloat,
Type.STRING: cls.evaluateForString, Type.STRING: cls.evaluateForString,
Type.LIST: cls.evaluateForList Type.LIST: cls.evaluateForList
}[value.type](value.value) }[value.type](value.value)
@@ -19,9 +20,12 @@ class MinusEvaluator(Evaluator):
@classmethod @classmethod
def evaluateForInteger(cls, value): def evaluateForInteger(cls, value):
return Type.integer(-value) return Type.integer(-value)
@classmethod
def evaluateForFloat(cls, value):
return Type.float(-value)
@classmethod @classmethod
def evaluateForString(cls, value): def evaluateForString(cls, value):
return Type.string(value[::-1]) return Type.string(value[::-1])

View File

@@ -10,11 +10,12 @@ class PowerEvaluator(Evaluator):
def evaluator(cls, node, environment): def evaluator(cls, node, environment):
left = expressionEvaluator(doAssert=True)(node.left, environment).value left = expressionEvaluator(doAssert=True)(node.left, environment).value
right = expressionEvaluator(doAssert=True)(node.right, environment).value right = expressionEvaluator(doAssert=True)(node.right, environment).value
supportedTypes = [Type.INTEGER, Type.FLOAT]
if left.type != Type.INTEGER: if not left.type in supportedTypes:
raise RuntimeException( f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.left.pos) raise RuntimeException(f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.left.pos)
if right.type != Type.INTEGER: if not right.type in supportedTypes:
raise RuntimeException( f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.right.pos) raise RuntimeException(f"Operator '{node.operator.value}' is supported only by {[t.name.lower() for t in supportedTypes]} type", node.right.pos)
return Type.integer(int(left.value ** right.value)) return Type.integer(int(left.value ** right.value))

View File

@@ -10,22 +10,36 @@ class ProductEvaluator(Evaluator):
def evaluator(cls, node, environment): def evaluator(cls, node, environment):
left = expressionEvaluator(doAssert=True)(node.left, environment).value left = expressionEvaluator(doAssert=True)(node.left, environment).value
right = expressionEvaluator(doAssert=True)(node.right, environment).value right = expressionEvaluator(doAssert=True)(node.right, environment).value
supportedTypes = [Type.INTEGER, Type.FLOAT]
if left.type != Type.INTEGER: if not left.type in supportedTypes:
raise RuntimeException( raise RuntimeException(
f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.left.pos) f"Operator '{node.operator.value}' is supported only by {[t.name.lower() for t in supportedTypes]} type", node.left.pos)
if right.type != Type.INTEGER: if not right.type in supportedTypes:
raise RuntimeException( raise RuntimeException(
f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.right.pos) f"Operator '{node.operator.value}' is supported only by {[t.name.lower() for t in supportedTypes]} type", node.right.pos)
if node.operator.value == "*": if node.operator.value == "*":
return Type.integer(int(left.value * right.value)) return getProperTypeProvider(left.value * right.value)
if node.operator.value == "/": if node.operator.value == "/":
if right.value == 0: if right.value == 0:
raise RuntimeException("Attempt to divide by 0", node.right.pos) raise RuntimeException("Attempt to divide by 0", node.right.pos)
return Type.integer(int(left.value / right.value))
value = left.value / right.value
if left.type == right.type == Type.INTEGER and int(value) == value:
return Type.integer(int(value))
return getProperTypeProvider(value)
raise RuntimeError("This line should never be reached") raise RuntimeError("This line should never be reached")
def getProperTypeProvider(value):
return {
int: lambda v: Type.integer(v),
float: lambda v: Type.float(v)
}[type(value)](value)

View File

@@ -29,7 +29,7 @@ class RelationEvaluator(Evaluator):
@classmethod @classmethod
def otherRelationOperatorsEvaluator(cls, left, operator, right): def otherRelationOperatorsEvaluator(cls, left, operator, right):
if left.type == right.type == Type.INTEGER: if left.type in [Type.INTEGER, Type.FLOAT] and right.type in [Type.INTEGER, Type.FLOAT]:
if operator.value == ">": if operator.value == ">":
return Type.bool(left.value > right.value) return Type.bool(left.value > right.value)

View File

@@ -11,8 +11,8 @@ class SumEvaluator(Evaluator):
left = expressionEvaluator(doAssert=True)(node.left, environment).value left = expressionEvaluator(doAssert=True)(node.left, environment).value
right = expressionEvaluator(doAssert=True)(node.right, environment).value right = expressionEvaluator(doAssert=True)(node.right, environment).value
if left.type == right.type == Type.INTEGER: if left.type in [Type.INTEGER, Type.FLOAT] and right.type in [Type.INTEGER, Type.FLOAT]:
return cls.integerEvaluator(left, node.operator, right) return cls.numberEvaluator(left, node.operator, right)
if left.type == right.type == Type.STRING: if left.type == right.type == Type.STRING:
return cls.stringEvaluator(left, node.operator, right) return cls.stringEvaluator(left, node.operator, right)
@@ -23,15 +23,17 @@ class SumEvaluator(Evaluator):
if left.type == right.type == Type.MAP: if left.type == right.type == Type.MAP:
return cls.mapEvaluator(left, node.operator, right) return cls.mapEvaluator(left, node.operator, right)
raise RuntimeException(f"Operator {node.operator.value} is not supported by {left.type.name.lower()} and {right.type.name.lower()} types", node.operator.pos) raise RuntimeException(
f"Operator {node.operator.value} is not supported by {left.type.name.lower()} and {right.type.name.lower()} types",
node.operator.pos)
@classmethod @classmethod
def integerEvaluator(cls, left, operator, right): def numberEvaluator(cls, left, operator, right):
if operator.value == "+": if operator.value == "+":
return Type.integer(left.value + right.value) return getProperTypeProvider(left.value + right.value)
if operator.value == "-": if operator.value == "-":
return Type.integer(left.value - right.value) return getProperTypeProvider(left.value - right.value)
raise RuntimeError("This line should never be reached") raise RuntimeError("This line should never be reached")
@@ -63,4 +65,11 @@ class SumEvaluator(Evaluator):
if operator.value == "-": if operator.value == "-":
raise RuntimeException(f"Operator {operator.value} is not supported by map types", operator.pos) raise RuntimeException(f"Operator {operator.value} is not supported by map types", operator.pos)
raise RuntimeError("This line should never be reached") raise RuntimeError("This line should never be reached")
def getProperTypeProvider(value):
return {
int: lambda v: Type.integer(v),
float: lambda v: Type.float(v)
}[type(value)](value)

View File

@@ -8,6 +8,7 @@ from smnp.type.value import Value
class Type(Enum): class Type(Enum):
INTEGER = (int, lambda x: str(x)) INTEGER = (int, lambda x: str(x))
FLOAT = (float, lambda x: str(x))
STRING = (str, lambda x: x) STRING = (str, lambda x: x)
LIST = (list, lambda x: f"[{', '.join([e.stringify() for e in x])}]") LIST = (list, lambda x: f"[{', '.join([e.stringify() for e in x])}]")
MAP = (dict, lambda x: '{' + ', '.join(f"'{k.stringify()}' -> '{v.stringify()}'" for k, v in x.items()) + '}') MAP = (dict, lambda x: '{' + ', '.join(f"'{k.stringify()}' -> '{v.stringify()}'" for k, v in x.items()) + '}')
@@ -25,6 +26,10 @@ class Type(Enum):
def integer(value): def integer(value):
return Value(Type.INTEGER, value, {}) return Value(Type.INTEGER, value, {})
@staticmethod
def float(value):
return Value(Type.FLOAT, value, {})
@staticmethod @staticmethod
def string(value): def string(value):
return Value(Type.STRING, value, { return Value(Type.STRING, value, {