diff --git a/phasm/compiler.py b/phasm/compiler.py index 2d51456..ccebcdc 100644 --- a/phasm/compiler.py +++ b/phasm/compiler.py @@ -39,6 +39,16 @@ INSTANCES = { 'a=f32': stdlib_types.f32_eq_equals, 'a=f64': stdlib_types.f64_eq_equals, }, + type3classes.Eq.operators['!=']: { + 'a=u8': stdlib_types.u8_eq_not_equals, + 'a=u32': stdlib_types.u32_eq_not_equals, + 'a=u64': stdlib_types.u64_eq_not_equals, + 'a=i8': stdlib_types.i8_eq_not_equals, + 'a=i32': stdlib_types.i32_eq_not_equals, + 'a=i64': stdlib_types.i64_eq_not_equals, + 'a=f32': stdlib_types.f32_eq_not_equals, + 'a=f64': stdlib_types.f64_eq_not_equals, + }, type3classes.Floating.methods['sqrt']: { 'a=f32': stdlib_types.f32_floating_sqrt, 'a=f64': stdlib_types.f64_floating_sqrt, diff --git a/phasm/parser.py b/phasm/parser.py index 73fc1da..af9f425 100644 --- a/phasm/parser.py +++ b/phasm/parser.py @@ -408,6 +408,8 @@ class OurVisitor: operator = '>' elif isinstance(node.ops[0], ast.Eq): operator = '==' + elif isinstance(node.ops[0], ast.NotEq): + operator = '!=' elif isinstance(node.ops[0], ast.Lt): operator = '<' else: diff --git a/phasm/stdlib/types.py b/phasm/stdlib/types.py index 5189d0d..2bb5310 100644 --- a/phasm/stdlib/types.py +++ b/phasm/stdlib/types.py @@ -119,30 +119,60 @@ def __i64_intnum_abs__(g: Generator, x: i64) -> i64: return i64('return') +## ### +## class Eq def u8_eq_equals(g: Generator) -> None: - g.add_statement('i32.eq') + g.i32.eq() def u32_eq_equals(g: Generator) -> None: - g.add_statement('i32.eq') + g.i32.eq() def u64_eq_equals(g: Generator) -> None: - g.add_statement('i64.eq') + g.i64.eq() def i8_eq_equals(g: Generator) -> None: - g.add_statement('i32.eq') + g.i32.eq() def i32_eq_equals(g: Generator) -> None: - g.add_statement('i32.eq') + g.i32.eq() def i64_eq_equals(g: Generator) -> None: - g.add_statement('i64.eq') + g.i64.eq() def f32_eq_equals(g: Generator) -> None: - g.add_statement('f32.eq') + g.f32.eq() def f64_eq_equals(g: Generator) -> None: - g.add_statement('f64.eq') + g.f64.eq() + +def u8_eq_not_equals(g: Generator) -> None: + g.i32.ne() + +def u32_eq_not_equals(g: Generator) -> None: + g.i32.ne() + +def u64_eq_not_equals(g: Generator) -> None: + g.i64.ne() + +def i8_eq_not_equals(g: Generator) -> None: + g.i32.ne() + +def i32_eq_not_equals(g: Generator) -> None: + g.i32.ne() + +def i64_eq_not_equals(g: Generator) -> None: + g.i64.ne() + +def f32_eq_not_equals(g: Generator) -> None: + g.f32.ne() + +def f64_eq_not_equals(g: Generator) -> None: + g.f64.ne() + + +## ### +## class Fractional def f32_fractional_div(g: Generator) -> None: g.add_statement('f32.div') @@ -156,6 +186,9 @@ def f32_floating_sqrt(g: Generator) -> None: def f64_floating_sqrt(g: Generator) -> None: g.add_statement('f64.sqrt') +## ### +## class Integral + def u32_integral_div(g: Generator) -> None: g.add_statement('i32.div_u') @@ -168,6 +201,9 @@ def i32_integral_div(g: Generator) -> None: def i64_integral_div(g: Generator) -> None: g.add_statement('i64.div_s') +## ### +## class NatNum + def u32_natnum_add(g: Generator) -> None: g.add_statement('i32.add') @@ -222,6 +258,9 @@ def f32_natnum_mul(g: Generator) -> None: def f64_natnum_mul(g: Generator) -> None: g.add_statement('f64.mul') +## ### +## class IntNum + def i32_intnum_abs(g: Generator) -> None: g.add_statement('call $stdlib.types.__i32_intnum_abs__') diff --git a/phasm/type3/typeclasses.py b/phasm/type3/typeclasses.py index 29166a4..fc184e9 100644 --- a/phasm/type3/typeclasses.py +++ b/phasm/type3/typeclasses.py @@ -95,6 +95,7 @@ class Type3Class: Eq = Type3Class('Eq', ['a'], methods={}, operators={ '==': 'a -> a -> bool', + '!=': 'a -> a -> bool', }) NatNum = Type3Class('NatNum', ['a'], methods={}, operators={ diff --git a/tests/integration/test_lang/test_eq.py b/tests/integration/test_lang/test_eq.py index 16bbdf1..b432fb1 100644 --- a/tests/integration/test_lang/test_eq.py +++ b/tests/integration/test_lang/test_eq.py @@ -99,3 +99,85 @@ def testEntry() -> bool: result = Suite(code_py).run_code() assert False is result.returned_value + +@pytest.mark.integration_test +def test_not_equals_not_implemented(): + code_py = """ +class Foo: + val: i32 + +@exported +def testEntry(x: Foo, y: Foo) -> Foo: + return x != y +""" + + with pytest.raises(Type3Exception, match='Foo does not implement the Eq type class'): + Suite(code_py).run_code() + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', INT_TYPES) +def test_not_equals_int_same(type_): + code_py = f""" +CONSTANT0: {type_} = 10 + +CONSTANT1: {type_} = 10 + +@exported +def testEntry() -> bool: + return CONSTANT0 != CONSTANT1 +""" + + result = Suite(code_py).run_code() + + assert False is result.returned_value + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', INT_TYPES) +def test_not_equals_int_different(type_): + code_py = f""" +CONSTANT0: {type_} = 10 + +CONSTANT1: {type_} = 3 + +@exported +def testEntry() -> bool: + return CONSTANT0 != CONSTANT1 +""" + + result = Suite(code_py).run_code() + + assert True is result.returned_value + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', FLOAT_TYPES) +def test_not_equals_float_same(type_): + code_py = f""" +CONSTANT0: {type_} = 10.125 + +CONSTANT1: {type_} = 10.125 + +@exported +def testEntry() -> bool: + return CONSTANT0 != CONSTANT1 +""" + + result = Suite(code_py).run_code() + + assert False is result.returned_value + +@pytest.mark.integration_test +@pytest.mark.parametrize('type_', FLOAT_TYPES) +def test_not_equals_float_different(type_): + code_py = f""" +CONSTANT0: {type_} = 10.32 + +CONSTANT1: {type_} = 10.33 + +@exported +def testEntry() -> bool: + return CONSTANT0 != CONSTANT1 +""" + + result = Suite(code_py).run_code() + + assert True is result.returned_value