def test_while_statement(): prog = dsl_parse( "( (defvar x (un val foobar) 0) " " (defvar y (un val foobar) 10) " " (while (apply < x 10) -2 ( (set y (apply + y 1)) (set x (apply + x 1)) y) ))" ) assert evaluate(base_env(), prog) == 20 prog = dsl_parse( "( (defvar x (un val foobar) 0) " " (defvar y (un val foobar) 10) " " (while (apply < x -4) -2 ( (set y (apply + y 1)) (set x (apply + x 1)) y) ))" ) assert evaluate(base_env(), prog) == -2 prog = dsl_parse( "( (defvar x (un val foobar) 0) " " (defvar y (un val foobar) 10) " " (while (apply < x -4) -2 ((defvar z (un val foobar) 10) " " ( (set y (apply + y 1)) (set x (apply + x 1)) y) )) z)" ) with pytest.raises(BindingUndefinedError): evaluate(base_env(), prog) prog = dsl_parse( "( (defvar x (un val foobar) 0) " " (defvar y (un val foobar) 10) " " (while (apply < x -4) -2 ((defvar z (un val foobar) 10) " " ( (defvar 1 (un val foobar) 10) (set y (apply + y 1)) (set x (apply + x 1)) y) )) q)" ) with pytest.raises(BindingUndefinedError): evaluate(base_env(), prog)
def test_defining_functions(): prog = dsl_parse( "( (defun add-3 (un val int) ((x (un val int))) (apply + x 3)) (apply add-3 7) )" ) assert evaluate(base_env(), prog) == 10 prog = dsl_parse( "( (defvar x (un val foobar) 0) " "(set x 1000) " "(defun add-3 (un val int) ((x (un val int))) (apply + x 3))" "(apply add-3 7))") assert evaluate(base_env(), prog) == 10 prog = dsl_parse( "( (defvar x (un val foobar) 0) " "(set x 1000) " "(defun add-3 (un val int) ((x (un val int))) (apply + x 3))" "(apply add-3 7) x)") assert evaluate(base_env(), prog) == 1000 prog = dsl_parse( "( (defvar x (un val foobar) 0) " "(set x 1000) " "(defun add-3 (un val int) ((x (un val int))) (apply + x 3))" "(apply add-3 x))") assert evaluate(base_env(), prog) == 1003 prog = dsl_parse( "( (defun add-3 (un val int) ((x (un val int))) (apply + x 3)) " "(defun add-4 (un val int) ((x (un val int))) (apply add-3 (apply + x 1)))" "(apply add-4 6) )") assert evaluate(base_env(), prog) == 10
def test_working_with_files(): prog = dsl_parse("(" "(defvar f (lin val file) (apply fopen 123))" ")") with pytest.raises(tc_err.UnusedLinVariableError): ATC.type_check(base_tcheck_env(), prog, descope=True) prog = dsl_parse("(" "(defvar f (lin val file) (apply fopen 123))" "(apply fclose f)" ")") ATC.type_check(base_tcheck_env(), prog, descope=True) prog = dsl_parse("(" "(defvar f (lin val file) (apply fopen 123))" "(scope (defvar fref (un ref (lin val file)) (mkref f))" " (apply fwrite fref 100)" ")" "(apply fclose f)" ")") ATC.type_check(base_tcheck_env(), prog, descope=True) prog = dsl_parse("(" "(defvar f (lin val file) (apply fopen 123))" "(scope (defvar fref (un ref (lin val file)) (mkref f))" " (apply fwrite fref 100)" ")" "(apply fclose f)" ")") ATC.type_check(base_tcheck_env(), prog, descope=True)
def test_ref_borrow3(): prog = dsl_parse("( (defvar x (lin val int) 3)" " (defvar xref (un ref (lin val int)) (mkref x))" " (defvar xref2 (un ref (lin val int)) xref)" ")") with pytest.raises(tc_err.UnusedLinVariableError): ATC.type_check(base_tcheck_env(), prog, descope=True)
def test_fun(): prog = dsl_parse("((defvar x (un val int) 3)" "(defun foo (un val bool) ((y (un val bool))) y )" "(apply foo x)" "x)") with pytest.raises(tc_err.TypeMismatchError): ATC.type_check(base_tcheck_env(), prog)
def test_reference_borrows(): prog = dsl_parse("(" "(defvar x (un val int) 3)" "(defvar xref (un ref (un val int)) (mkref x))" "x" ")") with pytest.raises(tc_err.LinAffineVariableReuseError): ATC.type_check(base_tcheck_env(), prog)
def test_ref_fun(): prog = dsl_parse( "((defvar x (un val int) 3)" "(defvar xref (un ref (un val int)) (mkref x)) " "(defun foo (un val unit) ((y (un ref (un val int)))) (setrefval y (apply + (deref y) 1)))) )" "(apply foo xref)" "x)") ATC.type_check(base_tcheck_env(), prog)
def test_ref_fun(): prog = dsl_parse( "((defvar x (un val int) 3)" "(defvar xref (un ref (un val int)) (mkref x)) " "(defun foo (un val int) ((y (un ref (un val int)))) (setrefval y (apply + (deref y) 1)))" "(apply foo xref)" "x)") assert evaluate(base_env(), prog) == 4
def test_reference_borrow_under_scope(): prog = dsl_parse("(" "(defvar x (un val int) 3)" "(scope " " (defvar xref (un ref (un val int)) (mkref x))" ")" "x" ")") ATC.type_check(base_tcheck_env(), prog)
def test_reference(): prog = dsl_parse("(" "(defvar x (un val int) 0)" "(defvar xref (un ref (un val int)) (mkref x))" "xref" ")") env = base_tcheck_env() T = ATC.type_check(env, prog) assert isinstance(T, dslT.RefType) assert T.referenced_type() == lang.T_INT
def test_env_copy_works(): prog = dsl_parse("( " " (defvar x (un val int) 0) " " (defvar y (un val int) 0) " " (while (apply < x 3) 0 ((set x (apply + x 1)) x))" ")") env = base_tcheck_env() ATC.type_check(env, prog, descope=False) env_cp = deepcopy_env(env) assert env == env_cp
def test_affine_variables(): # An affine value can be used once prog = dsl_parse("((defvar x (aff val int) 3) x)") env = base_tcheck_env() ret_type = ATC.type_check(env, prog) assert dslT.Tmod.less_restrictive(lang.T_INT.tmod, ret_type.tmod) # ...but not twice prog = dsl_parse("((defvar x (aff val int) 3) x x)") env = base_tcheck_env() with pytest.raises(tc_err.LinAffineVariableReuseError): ATC.type_check(env, prog) # Can't circumvent this through use of variables either... prog = dsl_parse( "((defvar x (aff val int) 3) (defvar y (aff val int) x) x)") env = base_tcheck_env() with pytest.raises(tc_err.LinAffineVariableReuseError): ATC.type_check(env, prog)
def test_if_statement(): prog = dsl_parse("( if true 10 12 )") assert evaluate(base_env(), prog) == 10 prog = dsl_parse( "( (defvar x (un val foobar) 0) " " (set x 1000) " " (defun add-3 (un val int) ((x (un val int))) (apply + x 3))" " (if (apply = 3 3) (apply add-3 x) (apply add-3 (apply add-3 x)))" ")") assert evaluate(base_env(), prog) == 1003 prog = dsl_parse( "( (defvar x (un val foobar) 0) " " (set x 1000) " " (defun add-3 (un val int) ((x (un val int))) (apply + x 3))" " (if (apply = 3 4) (apply add-3 x) (apply add-3 (apply add-3 x)))" ")") assert evaluate(base_env(), prog) == 1006 prog = dsl_parse( "( (defvar x (lin val foobar) 0) " " (set x 1000) " " (defun add-3 (un val int) ((x (un val int))) (apply + x 3))" " (if (apply = 3 4) " "((defvar z (un val foobar) 10) (apply add-3 x)) " "(apply add-3 (apply add-3 z)))" ")") with pytest.raises(BindingUndefinedError): evaluate(base_env(), prog) prog = dsl_parse( "( (defvar x (aff val foobar) 0) " " (set x 1000) " " (defun add-3 (un val int) ((x (un val int))) (apply + x 3))" " (if (apply = 3 4) " "(apply add-3 x) " "((defvar z (un val foobar) 10) (apply add-3 (apply add-3 z)))) z" ")") with pytest.raises(BindingUndefinedError): evaluate(base_env(), prog)
def test_file_stuff(): prog = dsl_parse(""" ( (defvar f _ (apply fopen 3)) (scope (defvar fref _ (mkref f)) (apply fwrite fref 33) ) (apply fclose f) ) """) evaluate(base_env(), prog)
def test_unrestricted_variables(): # Declaring an unrestricted value works... prog = dsl_parse("(defvar x (un val int) 3)") env = base_tcheck_env() ret_type = ATC.type_check(env, prog) assert ret_type == lang.T_UNIT assert env.get_bind_val('x') == dslT.tparse(dsl_parse("(un val int)")) # But you're not allowed to defvar a name twice, even with same type prog = dsl_parse("((defvar x (un val int) 3) (defvar x (un val int) 4))") env = base_tcheck_env() with pytest.raises(tc_err.BindingRedefinitionError): ATC.type_check(env, prog) # Unrestricted values can be used multiple times prog = dsl_parse("((defvar x (un val int) 3) x x)") env = base_tcheck_env() ret_type = ATC.type_check(env, prog) assert ret_type == lang.T_INT # Can turn an unrestricted value into an affine one prog = dsl_parse("((defvar x (aff val int) 3))") env = base_tcheck_env() ret_type = ATC.type_check(env, prog) assert ret_type == lang.T_UNIT # But you can't make an affine value unrestricted prog = dsl_parse("((defvar x (aff val int) 3) (defvar y (un val int) x))") env = base_tcheck_env() with pytest.raises(tc_err.TypeMismatchError): ATC.type_check(env, prog)
def test_recursive_fun(): prog = dsl_parse( "(" "(defun fib (un val int) ((n (un val int))) " " (defvar ret (un val int) 0) " " (if (apply = 0 n) (set ret 0) " " (if (apply = 1 n) (set ret 1) " " (set ret (apply + (apply fib (apply - n 1)) (apply fib (apply - n 2)) ))))" " ret" ")" "(apply fib 0))") assert evaluate(base_env(), prog) == 0 prog = dsl_parse( "(" "(defun fib (un val int) ((n (un val int))) " " (defvar ret (un val int) 0) " " (if (apply = 0 n) " " (set ret 0) " " (if (apply = 1 n) " " (set ret 1) " " (set ret (apply + (apply fib (apply - n 1)) (apply fib (apply - n 2)) ))))" " ret" ")" "(apply fib 2))") assert evaluate(base_env(), prog) == 1 prog = dsl_parse( "(" "(defun fib (un val int) ((n (un val int))) " " (defvar ret (un val int) 0) " " (if (apply = 0 n) " " (set ret 0) " " (if (apply = 1 n) " " (set ret 1) " " (set ret (apply + (apply fib (apply - n 1)) (apply fib (apply - n 2)) ))))" " ret" ")" "(apply fib 4))") assert evaluate(base_env(), prog) == 3
def test_recursive_fun(): prog = dsl_parse( "(" "(defun fib (un val int) ((n (un val int))) " " (defvar ret (un val int) 0) " " (if (apply = 0 n) (set ret 0) " " (if (apply = 1 n) (set ret 1) " " (set ret (apply + (apply fib (apply - n 1)) (apply fib (apply - n 2)) ))))" " ret" ")" "(apply fib 0)" ")") ATC.type_check(base_tcheck_env(), prog)
def test_linear_variables(): ################ # Linear stuff # ################ # Linear variables must be used *exactly* once, so just declaring it won't work prog = dsl_parse("((defvar x (lin val int) 3))") env = base_tcheck_env() with pytest.raises(tc_err.UnusedLinVariableError): # We have to make sure that the type-checker knows top-level environment will be descoped ATC.type_check(env, prog, descope=True) # But declaring and then using it actually will prog = dsl_parse("((defvar x (lin val int) 3) (apply + 42 x))") env = base_tcheck_env() ATC.type_check(env, prog, descope=True) # Declaring and then using it twice, on the other hand, is a big no-no prog = dsl_parse( "((defvar x (lin val int) 3) (apply + 42 x) (apply + 42 x))") env = base_tcheck_env() with pytest.raises(tc_err.LinAffineVariableReuseError): ATC.type_check(env, prog, descope=True)
def test_calling_functions(): prog = dsl_parse("(apply + 3 4)") assert evaluate(base_env(), prog) == 7 prog = dsl_parse("(apply <= 5 4)") assert evaluate(base_env(), prog) == False
def test_var_access(): prog = dsl_parse("( (defvar x (lin val footype) 0) (set x 3) x )") assert evaluate(base_env(), prog) == 3 prog = dsl_parse("( (defvar x (aff val footype) 0) (set x 4) (set x 3) 3)") assert evaluate(base_env(), prog) == 3
def test_define_variable(): prog = dsl_parse("(defvar x (un val footype) 3)") assert evaluate(base_env(), prog) is None prog = dsl_parse("((defvar x (un val footype) 3) x)") assert evaluate(base_env(), prog) == 3
def test_while(): prog = dsl_parse( "((defvar x (un val int) 0) (while (apply < x 3) -2 ((set x (apply + x 1)) x)))" ) ATC.type_check(base_tcheck_env(), prog, descope=False)
def test_nonexistent_ref(): prog = dsl_parse( "((defvar x (lin val int) 3) (defvar badref (un ref (un val int)) (mkref y))))" ) with pytest.raises(tc_err.BindingUndefinedError): ATC.type_check(base_tcheck_env(), prog)
def test_seq_eval(): prog = dsl_parse("(true 3)") assert evaluate(base_env(), prog) == 3
def test_nested_fun(): prog = dsl_parse( "( (defun add-3 (un val int) ((x (un val int))) (apply + x 3)) " "(defun add-4 (un val int) ((x (un val int))) (apply add-3 (apply + x 1)))" "(apply add-4 6) )") ATC.type_check(base_tcheck_env(), prog)
def test_reference_no_effect(): prog = dsl_parse("(" "(defvar x (un val int) 0)" "(mkref x)" ")") env = base_tcheck_env() with pytest.raises(tc_err.ReferenceNoEffectError): ATC.type_check(env, prog)
def test_scope_descopes(): prog = dsl_parse("(3" "(scope (defvar x (lin val int) 3)))" ")") with pytest.raises(tc_err.UnusedLinVariableError): ATC.type_check(base_tcheck_env(), prog)
def test_if_lin3(): prog = dsl_parse( "((defvar x (lin val int) 3) (if true (3) (apply + x 2)))") with pytest.raises(tc_err.EnvironmentMismatchError): ATC.type_check(base_tcheck_env(), prog)
def test_ref(): prog = dsl_parse("((defvar x (un val int) 3)" "(defvar xref (un ref (un val int)) (mkref x)) " "(setrefval xref (apply + (deref xref) 1))" "x)") assert evaluate(base_env(), prog) == 4
def test_ref_borrow4(): prog = dsl_parse("( (defvar x (lin val int) 3)" " (scope (defvar xref (un ref (lin val int)) (mkref x))" " (defvar xref2 (un ref (lin val int)) xref))" "(apply + 3 x))") ATC.type_check(base_tcheck_env(), prog)