From 0657214aa3deb6fdae78c6f4cbf13ab113f1253e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Thu, 25 Jul 2019 12:51:48 +0200 Subject: [PATCH 1/7] Create tokenizer for float type --- smnp/token/tokenizer.py | 2 ++ smnp/token/tokenizers/float.py | 25 +++++++++++++++++++++++++ smnp/token/type.py | 1 + 3 files changed, 28 insertions(+) create mode 100644 smnp/token/tokenizers/float.py diff --git a/smnp/token/tokenizer.py b/smnp/token/tokenizer.py index 277badb..e00b772 100644 --- a/smnp/token/tokenizer.py +++ b/smnp/token/tokenizer.py @@ -2,6 +2,7 @@ from smnp.error.syntax import SyntaxException from smnp.token.model import TokenList from smnp.token.tokenizers.bool import boolTokenizer from smnp.token.tokenizers.comment import commentTokenizer +from smnp.token.tokenizers.float import floatTokenizer from smnp.token.tokenizers.identifier import identifierTokenizer from smnp.token.tokenizers.keyword import typeTokenizer from smnp.token.tokenizers.note import noteTokenizer @@ -41,6 +42,7 @@ tokenizers = ( defaultTokenizer(TokenType.DOT), # Types + separated(floatTokenizer), mapValue(separated(regexPatternTokenizer(TokenType.INTEGER, r'\d')), int), stringTokenizer, noteTokenizer, diff --git a/smnp/token/tokenizers/float.py b/smnp/token/tokenizers/float.py new file mode 100644 index 0000000..6f05557 --- /dev/null +++ b/smnp/token/tokenizers/float.py @@ -0,0 +1,25 @@ +from smnp.token.model import Token +from smnp.token.tools import regexPatternTokenizer, keywordTokenizer +from smnp.token.type import TokenType + + +def floatTokenizer(input, current, line): + consumedChars = 0 + value = "" + consumed, token = regexPatternTokenizer(TokenType.INTEGER, r'\d')(input, current, line) + if consumed > 0: + consumedChars += consumed + value += token.value + consumed, token = keywordTokenizer(TokenType.DOT, ".")(input, current+consumedChars, line) + if consumed > 0: + consumedChars += consumed + value += token.value + consumed, token = regexPatternTokenizer(TokenType.INTEGER, r'\d')(input, current+consumedChars, line) + if consumed > 0: + consumedChars += consumed + value += token.value + print(value) + return (consumedChars, Token(TokenType.FLOAT, float(value), (current, line), value)) + + + return (0, None) \ No newline at end of file diff --git a/smnp/token/type.py b/smnp/token/type.py index c14d1c5..1812993 100644 --- a/smnp/token/type.py +++ b/smnp/token/type.py @@ -30,6 +30,7 @@ class TokenType(Enum): NOT = 'not' INTEGER = 'integer' STRING = 'string' + FLOAT = 'float' NOTE = 'note' BOOL = 'bool' TYPE = 'type' From 6222dccaac8b71d5e9447b73b95fc20c75a6dca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Thu, 25 Jul 2019 13:02:33 +0200 Subject: [PATCH 2/7] Improve float type tokenizer --- smnp/token/tokenizers/float.py | 30 +++++++++++------------------- smnp/token/tools.py | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/smnp/token/tokenizers/float.py b/smnp/token/tokenizers/float.py index 6f05557..3c3b5f1 100644 --- a/smnp/token/tokenizers/float.py +++ b/smnp/token/tokenizers/float.py @@ -1,25 +1,17 @@ from smnp.token.model import Token -from smnp.token.tools import regexPatternTokenizer, keywordTokenizer +from smnp.token.tools import regexPatternTokenizer, keywordTokenizer, allOf from smnp.token.type import TokenType -def floatTokenizer(input, current, line): - consumedChars = 0 - value = "" - consumed, token = regexPatternTokenizer(TokenType.INTEGER, r'\d')(input, current, line) - if consumed > 0: - consumedChars += consumed - value += token.value - consumed, token = keywordTokenizer(TokenType.DOT, ".")(input, current+consumedChars, line) - if consumed > 0: - consumedChars += consumed - value += token.value - consumed, token = regexPatternTokenizer(TokenType.INTEGER, r'\d')(input, current+consumedChars, line) - if consumed > 0: - consumedChars += consumed - value += token.value - print(value) - return (consumedChars, Token(TokenType.FLOAT, float(value), (current, line), value)) +def createToken(pos, beforeDot, dot, afterDot): + rawValue = f"{beforeDot.value}.{afterDot.value}" + value = float(rawValue) + return Token(TokenType.FLOAT, value, pos, rawValue) - return (0, None) \ No newline at end of file +floatTokenizer = allOf( + regexPatternTokenizer(TokenType.INTEGER, r'\d'), + keywordTokenizer(None, "."), + regexPatternTokenizer(TokenType.INTEGER, r'\d'), + createToken=createToken +) diff --git a/smnp/token/tools.py b/smnp/token/tools.py index 297a278..dfce11f 100644 --- a/smnp/token/tools.py +++ b/smnp/token/tools.py @@ -61,3 +61,19 @@ def mapValue(tokenizer, mapper): return (0, None) return tokenize + +def allOf(*tokenizers, createToken): + def combinedTokenizer(input, current, line): + consumedChars = 0 + tokens = [] + for tokenizer in tokenizers: + consumed, token = tokenizer(input, current+consumedChars, line) + if consumed > 0: + consumedChars += consumed + tokens.append(token) + else: + return (0, None) + + return (consumedChars, createToken((current, line), *tokens)) + + return combinedTokenizer \ No newline at end of file From 6dc503ba86108b32d62ad823d7678d90fa8347f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Thu, 25 Jul 2019 13:07:53 +0200 Subject: [PATCH 3/7] Enable parsing float types --- smnp/ast/node/atom.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/smnp/ast/node/atom.py b/smnp/ast/node/atom.py index 95eda19..6b09afa 100644 --- a/smnp/ast/node/atom.py +++ b/smnp/ast/node/atom.py @@ -27,6 +27,10 @@ class IntegerLiteral(Atom): pass +class FloatLiteral(Atom): + pass + + class StringLiteral(Atom): pass @@ -47,6 +51,10 @@ def IntegerParser(input): return Parser.terminal(TokenType.INTEGER, createNode=IntegerLiteral.withValue)(input) +def FloatParser(input): + return Parser.terminal(TokenType.FLOAT, createNode=FloatLiteral.withValue)(input) + + def StringParser(input): return Parser.terminal(TokenType.STRING, createNode=StringLiteral.withValue)(input) @@ -66,6 +74,7 @@ def TypeLiteralParser(input): def LiteralParser(input): return Parser.oneOf( IntegerParser, + FloatParser, StringParser, NoteParser, BoolParser, From b126f838247b3bb6a8089629284e1b76a763affc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Thu, 25 Jul 2019 13:37:31 +0200 Subject: [PATCH 4/7] Enable basic support for evaluating float types --- smnp/runtime/evaluators/atom.py | 4 +++- smnp/runtime/evaluators/float.py | 9 +++++++++ smnp/runtime/evaluators/minus.py | 6 +++++- smnp/runtime/evaluators/power.py | 9 +++++---- smnp/runtime/evaluators/product.py | 26 ++++++++++++++++++++------ smnp/runtime/evaluators/relation.py | 2 +- smnp/runtime/evaluators/sum.py | 23 ++++++++++++++++------- smnp/type/model.py | 5 +++++ 8 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 smnp/runtime/evaluators/float.py diff --git a/smnp/runtime/evaluators/atom.py b/smnp/runtime/evaluators/atom.py index 0be1822..7918900 100644 --- a/smnp/runtime/evaluators/atom.py +++ b/smnp/runtime/evaluators/atom.py @@ -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.list import List from smnp.ast.node.map import Map from smnp.error.runtime import RuntimeException from smnp.runtime.evaluator import Evaluator from smnp.runtime.evaluators.expression import expressionEvaluator +from smnp.runtime.evaluators.float import FloatEvaluator from smnp.runtime.evaluators.iterable import abstractIterableEvaluator from smnp.runtime.tools.error import updatePos from smnp.type.model import Type @@ -85,6 +86,7 @@ class AtomEvaluator(Evaluator): return Evaluator.oneOf( Evaluator.forNodes(StringEvaluator.evaluate, StringLiteral), Evaluator.forNodes(IntegerEvaluator.evaluate, IntegerLiteral), + Evaluator.forNodes(FloatEvaluator.evaluate, FloatLiteral), Evaluator.forNodes(NoteEvaluator.evaluate, NoteLiteral), Evaluator.forNodes(BoolEvaluator.evaluate, BoolLiteral), Evaluator.forNodes(TypeEvaluator.evaluate, TypeLiteral), diff --git a/smnp/runtime/evaluators/float.py b/smnp/runtime/evaluators/float.py new file mode 100644 index 0000000..7a1c05b --- /dev/null +++ b/smnp/runtime/evaluators/float.py @@ -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) \ No newline at end of file diff --git a/smnp/runtime/evaluators/minus.py b/smnp/runtime/evaluators/minus.py index 5c20118..d844b44 100644 --- a/smnp/runtime/evaluators/minus.py +++ b/smnp/runtime/evaluators/minus.py @@ -11,6 +11,7 @@ class MinusEvaluator(Evaluator): try: return { Type.INTEGER: cls.evaluateForInteger, + Type.FLOAT: cls.evaluateForFloat, Type.STRING: cls.evaluateForString, Type.LIST: cls.evaluateForList }[value.type](value.value) @@ -19,9 +20,12 @@ class MinusEvaluator(Evaluator): @classmethod def evaluateForInteger(cls, value): - return Type.integer(-value) + @classmethod + def evaluateForFloat(cls, value): + return Type.float(-value) + @classmethod def evaluateForString(cls, value): return Type.string(value[::-1]) diff --git a/smnp/runtime/evaluators/power.py b/smnp/runtime/evaluators/power.py index 7168d48..5d9abb9 100644 --- a/smnp/runtime/evaluators/power.py +++ b/smnp/runtime/evaluators/power.py @@ -10,11 +10,12 @@ class PowerEvaluator(Evaluator): def evaluator(cls, node, environment): left = expressionEvaluator(doAssert=True)(node.left, environment).value right = expressionEvaluator(doAssert=True)(node.right, environment).value + supportedTypes = [Type.INTEGER, Type.FLOAT] - if left.type != Type.INTEGER: - raise RuntimeException( f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.left.pos) + 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) - if right.type != Type.INTEGER: - raise RuntimeException( f"Operator '{node.operator.value}' is supported only by {Type.INTEGER.name.lower()} type", node.right.pos) + if not right.type in supportedTypes: + 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)) \ No newline at end of file diff --git a/smnp/runtime/evaluators/product.py b/smnp/runtime/evaluators/product.py index ecf513f..6cabbf0 100644 --- a/smnp/runtime/evaluators/product.py +++ b/smnp/runtime/evaluators/product.py @@ -10,22 +10,36 @@ class ProductEvaluator(Evaluator): def evaluator(cls, node, environment): left = expressionEvaluator(doAssert=True)(node.left, 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) + 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( - 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 == "*": - return Type.integer(int(left.value * right.value)) + return getProperTypeProvider(left.value * right.value) if node.operator.value == "/": if right.value == 0: 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") + +def getProperTypeProvider(value): + return { + int: lambda v: Type.integer(v), + float: lambda v: Type.float(v) + }[type(value)](value) + diff --git a/smnp/runtime/evaluators/relation.py b/smnp/runtime/evaluators/relation.py index fb0de94..020c733 100644 --- a/smnp/runtime/evaluators/relation.py +++ b/smnp/runtime/evaluators/relation.py @@ -29,7 +29,7 @@ class RelationEvaluator(Evaluator): @classmethod 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 == ">": return Type.bool(left.value > right.value) diff --git a/smnp/runtime/evaluators/sum.py b/smnp/runtime/evaluators/sum.py index 1f1bdcd..d19d9f0 100644 --- a/smnp/runtime/evaluators/sum.py +++ b/smnp/runtime/evaluators/sum.py @@ -11,8 +11,8 @@ class SumEvaluator(Evaluator): left = expressionEvaluator(doAssert=True)(node.left, environment).value right = expressionEvaluator(doAssert=True)(node.right, environment).value - if left.type == right.type == Type.INTEGER: - return cls.integerEvaluator(left, node.operator, right) + if left.type in [Type.INTEGER, Type.FLOAT] and right.type in [Type.INTEGER, Type.FLOAT]: + return cls.numberEvaluator(left, node.operator, right) if left.type == right.type == Type.STRING: return cls.stringEvaluator(left, node.operator, right) @@ -23,15 +23,17 @@ class SumEvaluator(Evaluator): if left.type == right.type == Type.MAP: 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 - def integerEvaluator(cls, left, operator, right): + def numberEvaluator(cls, left, operator, right): if operator.value == "+": - return Type.integer(left.value + right.value) + return getProperTypeProvider(left.value + right.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") @@ -63,4 +65,11 @@ class SumEvaluator(Evaluator): if operator.value == "-": raise RuntimeException(f"Operator {operator.value} is not supported by map types", operator.pos) - raise RuntimeError("This line should never be reached") \ No newline at end of file + 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) diff --git a/smnp/type/model.py b/smnp/type/model.py index 8e757b9..926a8e4 100644 --- a/smnp/type/model.py +++ b/smnp/type/model.py @@ -8,6 +8,7 @@ from smnp.type.value import Value class Type(Enum): INTEGER = (int, lambda x: str(x)) + FLOAT = (float, lambda x: str(x)) STRING = (str, lambda x: 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()) + '}') @@ -25,6 +26,10 @@ class Type(Enum): def integer(value): return Value(Type.INTEGER, value, {}) + @staticmethod + def float(value): + return Value(Type.FLOAT, value, {}) + @staticmethod def string(value): return Value(Type.STRING, value, { From c9a3fc070b781511c8eae23c423f6adaaaade610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Fri, 26 Jul 2019 20:59:41 +0200 Subject: [PATCH 5/7] Add Integer function to convert strings and floats to integers --- smnp/module/__init__.py | 6 +++--- smnp/module/integer/__init__.py | 4 ++++ smnp/module/integer/function/__init__.py | 0 smnp/module/integer/function/integer.py | 25 ++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 smnp/module/integer/__init__.py create mode 100644 smnp/module/integer/function/__init__.py create mode 100644 smnp/module/integer/function/integer.py diff --git a/smnp/module/__init__.py b/smnp/module/__init__.py index 4ea9f27..76e9e63 100644 --- a/smnp/module/__init__.py +++ b/smnp/module/__init__.py @@ -1,4 +1,4 @@ -from smnp.module import system, mic, note, iterable, sound, synth, string, util +from smnp.module import system, mic, note, iterable, sound, synth, string, util, integer -functions = [ *system.functions, *mic.functions, *note.functions, *iterable.functions, *sound.functions, *synth.functions, *string.functions, *util.functions ] -methods = [ *system.methods, *mic.methods, *note.methods, *iterable.methods, *sound.methods, *synth.methods, *string.methods, *util.methods ] \ No newline at end of file +functions = [ *system.functions, *mic.functions, *note.functions, *iterable.functions, *sound.functions, *synth.functions, *string.functions, *util.functions, *integer.functions ] +methods = [ *system.methods, *mic.methods, *note.methods, *iterable.methods, *sound.methods, *synth.methods, *string.methods, *util.methods, *integer.methods ] \ No newline at end of file diff --git a/smnp/module/integer/__init__.py b/smnp/module/integer/__init__.py new file mode 100644 index 0000000..f67126b --- /dev/null +++ b/smnp/module/integer/__init__.py @@ -0,0 +1,4 @@ +from smnp.module.integer.function import integer + +functions = [ integer.function ] +methods = [] \ No newline at end of file diff --git a/smnp/module/integer/function/__init__.py b/smnp/module/integer/function/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/smnp/module/integer/function/integer.py b/smnp/module/integer/function/integer.py new file mode 100644 index 0000000..36647ca --- /dev/null +++ b/smnp/module/integer/function/integer.py @@ -0,0 +1,25 @@ +from smnp.function.model import CombinedFunction, Function +from smnp.function.signature import signature +from smnp.type.model import Type +from smnp.type.signature.matcher.type import ofType + +_signature1 = signature(ofType(Type.FLOAT)) +def _function1(env, value): + return Type.integer(int(value.value)) + + +_signature2 = signature(ofType(Type.STRING)) +def _function2(env, value): + return Type.integer(int(value.value)) + + +_signature3 = signature(ofType(Type.INTEGER)) +def _function3(env, value): + return value + +function = CombinedFunction( + 'Integer', + Function(_signature1, _function1), + Function(_signature2, _function2), + Function(_signature3, _function3), +) \ No newline at end of file From d802c58eeef6660574de1461d32069c6d69c9041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Sat, 27 Jul 2019 12:48:17 +0200 Subject: [PATCH 6/7] Add Float function to convert strings and integers to floats --- smnp/module/__init__.py | 6 +++--- smnp/module/float/__init__.py | 4 ++++ smnp/module/float/function/__init__.py | 0 smnp/module/float/function/float.py | 26 ++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 smnp/module/float/__init__.py create mode 100644 smnp/module/float/function/__init__.py create mode 100644 smnp/module/float/function/float.py diff --git a/smnp/module/__init__.py b/smnp/module/__init__.py index 76e9e63..d058565 100644 --- a/smnp/module/__init__.py +++ b/smnp/module/__init__.py @@ -1,4 +1,4 @@ -from smnp.module import system, mic, note, iterable, sound, synth, string, util, integer +from smnp.module import system, mic, note, iterable, sound, synth, string, util, integer, float -functions = [ *system.functions, *mic.functions, *note.functions, *iterable.functions, *sound.functions, *synth.functions, *string.functions, *util.functions, *integer.functions ] -methods = [ *system.methods, *mic.methods, *note.methods, *iterable.methods, *sound.methods, *synth.methods, *string.methods, *util.methods, *integer.methods ] \ No newline at end of file +functions = [ *system.functions, *mic.functions, *note.functions, *iterable.functions, *sound.functions, *synth.functions, *string.functions, *util.functions, *integer.functions, *float.functions ] +methods = [ *system.methods, *mic.methods, *note.methods, *iterable.methods, *sound.methods, *synth.methods, *string.methods, *util.methods, *integer.methods, *float.methods ] \ No newline at end of file diff --git a/smnp/module/float/__init__.py b/smnp/module/float/__init__.py new file mode 100644 index 0000000..aeb143b --- /dev/null +++ b/smnp/module/float/__init__.py @@ -0,0 +1,4 @@ +from smnp.module.float.function import float + +functions = [ float.function ] +methods = [] \ No newline at end of file diff --git a/smnp/module/float/function/__init__.py b/smnp/module/float/function/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/smnp/module/float/function/float.py b/smnp/module/float/function/float.py new file mode 100644 index 0000000..df080af --- /dev/null +++ b/smnp/module/float/function/float.py @@ -0,0 +1,26 @@ +from smnp.function.model import CombinedFunction, Function +from smnp.function.signature import signature +from smnp.type.model import Type +from smnp.type.signature.matcher.type import ofType + +_signature1 = signature(ofType(Type.INTEGER)) +def _function1(env, value): + return Type.float(float(value.value)) + + +_signature2 = signature(ofType(Type.STRING)) +def _function2(env, value): + return Type.float(float(value.value)) + + +_signature3 = signature(ofType(Type.FLOAT)) +def _function3(env, value): + return value + + +function = CombinedFunction( + 'Float', + Function(_signature1, _function1), + Function(_signature2, _function2), + Function(_signature3, _function3), +) \ No newline at end of file From 70687ddc028eb4a29ad697a27e7f384bee19537e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Sat, 27 Jul 2019 12:52:30 +0200 Subject: [PATCH 7/7] Fix relation operators between floats and integers --- smnp/runtime/evaluators/relation.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/smnp/runtime/evaluators/relation.py b/smnp/runtime/evaluators/relation.py index 020c733..9eeb905 100644 --- a/smnp/runtime/evaluators/relation.py +++ b/smnp/runtime/evaluators/relation.py @@ -21,10 +21,16 @@ class RelationEvaluator(Evaluator): @classmethod def equalOperatorEvaluator(cls, left, operator, right): + if left.type in [Type.INTEGER, Type.FLOAT] and right.type in [Type.INTEGER, Type.FLOAT]: + return Type.bool(left.value == right.value) + return Type.bool(left.type == right.type and left.value == right.value) @classmethod def notEqualOperatorEvaluator(cls, left, operator, right): + if left.type in [Type.INTEGER, Type.FLOAT] and right.type in [Type.INTEGER, Type.FLOAT]: + return Type.bool(left.value != right.value) + return Type.bool(left.type != right.type or left.value != right.value) @classmethod @@ -40,7 +46,7 @@ class RelationEvaluator(Evaluator): return Type.bool(left.value < right.value) if operator.value == "<=": - return Type.bool(left.value < right.value) + return Type.bool(left.value <= right.value) raise RuntimeException(f"Operator {operator.value} is not supported by {left.type.name.lower()} and {right.type.name.lower()} types", operator.pos)