Skip to content

Commit

Permalink
last contextual tests & fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
k2d222 committed Jan 12, 2022
1 parent c5a2546 commit f83fb28
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 36 deletions.
24 changes: 12 additions & 12 deletions doc/contextual_checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,38 +27,38 @@
* No method with *override* keyword in a base class ✔
* Override methods have the *override* keyword ✔
* Override methods match the overriden method signature ✔
* If method returns something, all code paths lead to an assign to *result* before return or block ends
* No static override
* If method returns something, all code paths lead to an assign to *result* before return or block ends
* No static override

## Constructor

* No reserved keyword in params ✔
* Constructor name and class name are equal ✔
* Constructor parameters and class parameters are equal ✔
* Constructor calls the right super constructor if class is derived
* Constructor does not call any super constructor if class is base
* Constructor calls the right super constructor if class is derived
* Constructor does not call any super constructor if class is base

## Instructions

* Perform expression checks for Expr, Ite, Return and Assign
* --
* No reserved keyword declared in Block instructions ✔
* Can only Assign to idents, attributes or static attributes
* Cannot assign to *this* or *super*
* Can only Assign to idents, attributes or static attributes
* Cannot assign to *this* or *super*
* Assign lhs exists ✔
* Assign rhs is compatible with lhs ✔
* Expression in an Ite instruction is of type Integer
* Expression in an Ite instruction is of type Integer

## Expressions

* Call to new exists ✔
* Called method exists ✔
* Called method params are compatible with declaration ✔
* Called static method exists in static class
* Called static method params are compatible with declaration
* Called static method exists in static class
* Called static method params are compatible with declaration
* Params in new call are compatible with ctor ✔
* Numeric operators are used on Integer types
* StrCat is used on Strings
* Numeric operators are used on Integer types
* StrCat is used on Strings
* Identifiers are in scope ✔
* Attributes exist ✔
* Static Attributes exist
* Static Attributes exist
3 changes: 2 additions & 1 deletion lib/contextual.ml
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ let rec check_instr_block decls env (vars, li) =

(** Performs the following checks:
- Left-hand-side assign operand refers to either:
(a) An ident,
(a) An ident (not 'this' or 'super'),
(b) (recusively) an attribute of a variable, or
(c) A static attribute of a class.
- Right-hand-side assign operand is compatible with the target variable
Expand All @@ -195,6 +195,7 @@ and check_instr_assign decls env (lhs, rhs) =
let t1 = get_expr_type decls env lhs
in let t2 = get_expr_type decls env rhs
in let () = match lhs with
| Id "this" | Id "super" -> err (Printf.sprintf "cannot assign to 'this' or 'super'")
| Id _ | Attr _ | StaticAttr _ -> ()
| _ -> err (Printf.sprintf "cannot assign to an expression of type '%s'" t1)
in let () =
Expand Down
19 changes: 12 additions & 7 deletions progs/test.kat
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
{p1 : Integer
is
{p2 : Integer
is
p2 := 3;
}
p1 := p2;}
class Base() is {
def Base() is {}
}
class Derived() extends Base is {
def Derived(): Base() is {}
def test() is {
b: Base
d: Derived
is b := new Base();
}
}
{}
162 changes: 147 additions & 15 deletions test/context.ml
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,32 @@ let%test "override-methods-match-overriden-method-signature" =
&& expects_ctx_err (code "foo, bar : Integer, baz : Derived")
&& expects_ast (code "foo, bar : Integer, baz : Base")

(* TODO: non-void-code-paths-lead-to-assign-to-result *)

(* TODO: no-static-override *)
let%test "non-void-code-paths-lead-to-assign-to-result" =
let template = Printf.sprintf {|
class Point1() is {
def Point1() is {}
def test(): Integer is { %s } /* in methods */
def static test2(): Integer is { %s } /* in static methods */
}
{}
|}
in let t1 = template "result := 0;"
in let t2 = (Fn.flip template) "result := 0;"
in let tests_err = [
{| if 10 then result := 10; else {} |};
{| if 10 then {} else result := 20; |};
{| foo: Integer is foo := 10; |};
{| return; result := 10; |};
]
in let tests_ok = [
{| if 10 then result := 10; else result := 20; |};
{| foo: Integer is result := 10; |};
{| result:= 10; return; |};
]
in tests_err |> List.map ~f:t1 |> List.for_all ~f:expects_ctx_err
&& tests_err |> List.map ~f:t2 |> List.for_all ~f:expects_ctx_err
&& tests_ok |> List.map ~f:t1 |> List.for_all ~f:expects_ast
&& tests_ok |> List.map ~f:t2 |> List.for_all ~f:expects_ast

(* ----------------------- Constructors -------------------------- *)

Expand Down Expand Up @@ -280,8 +303,15 @@ let%test "constructor-calls-right-super-constructor-if-class-derived" =
&& expects_ctx_err (code {| Base("hello", 10, "world") |})
&& expects_ast (code {| Base("hello", 10, 20) |})

(* TODO: no-super-constructor-call-in-base-class *)

let%test "no-super-constructor-call-in-base-class" =
let code = Printf.sprintf {|
class Point1() is {
def Point1() %s is {}
}
{}
|}
in expects_ctx_err (code " : Foo()")
&& expects_ast (code "")

(* ----------------------- Instructions -------------------------- *)

Expand All @@ -295,9 +325,57 @@ let%test "no-reserved-keyword-declared-in-block-instructions" =
in List.for_all reserved ~f:(fun r -> expects_ctx_err (code r))
&& expects_ast (code "foo")

(* TODO: only-assign-to-idents-or-attribs *)

(* TODO: no-assign-to-this-or-super *)
let%test "only-assign-to-idents-or-attribs" =
let code = Printf.sprintf {|
class Point1(var s1: String) is {
def Point1(var s1: String) is {}
var i1: Integer
var static i2: Integer
def foo(): Integer := 10
}
{
s: String
i, j: Integer
p: Point1
is %s := %s;
}
|}
in let ok = [
("s", "\"hello\"");
("i", "10");
("Point1.i2", "10");
("p.i1", "10");
("p.s1", "\"hello\"");
("new Point1(\"hello\").i1", "10");
]
in let err = [
("\"foo\"", "\"hello\"");
("20", "10");
("20", "10");
("p.foo()", "10");
]
in err |> List.for_all ~f:(fun (a, b) -> expects_ctx_err (code a b))
&& ok |> List.for_all ~f:(fun (a, b) -> expects_ast (code a b))

let%test "no-assign-to-this-or-super" =
let code = Printf.sprintf {|
class Base() is {
def Base() is {}
}
class Derived() extends Base is {
def Derived(): Base() is {}
def test() is {
b: Base
d: Derived
is %s := %s;
}
}
{}
|}
in expects_ctx_err (code "this" "new Derived()")
&& expects_ctx_err (code "super" "new Base()")
&& expects_ast (code "d" "new Derived()")
&& expects_ast (code "b" "new Base()")

let%test "no-undeclared-variable" =
let code = Printf.sprintf {|
Expand Down Expand Up @@ -333,7 +411,14 @@ let%test "no-incompatible-assign-types" =
&& expects_ctx_err (code "p3" "p2")
&& expects_ast (code "p2" "p3")

(* TODO: ite-expression-type-is-integer *)
let%test "ite-expression-type-is-integer" =
let code = Printf.sprintf {|
{
if %s then {} else {}
}
|}
in expects_ctx_err (code "\"hello\"")
&& expects_ast (code "10")

(* ----------------------- Expressions -------------------------- *)

Expand Down Expand Up @@ -384,9 +469,39 @@ let%test "called-method-params-are-compatible-with-declaration" =
&& expects_ctx_err (code "10, 20, 30")
&& expects_ast (code "10, 20, \"hello\"")

(* TODO: static-method-call-exists *)
let%test "static-method-call-exists" =
let code = Printf.sprintf {|
class Point1() is {
def Point1() is {}
def static test1() is {}
}
{
Point1.%s();
}
|}
in expects_ctx_err (code "test2")
&& expects_ast (code "test1")

(* TODO: static-method-call-params-compatible *)
let%test "static-method-call-params-compatible" =
let code = Printf.sprintf {|
class Point1() is {
def Point1() is {}
def static test1(i1, i2: Integer, b: Base, d: Derived) is {}
}
class Base() is {
def Base() is {}
}
class Derived() extends Base is {
def Derived(): Base() is {}
}
{
Point1.test1(%s);
}
|}
in expects_ctx_err (code "10, 20, new Base()")
&& expects_ctx_err (code "10, 20, new Base(), new Base()")
&& expects_ast (code "10, 20, new Base(), new Derived()")
&& expects_ast (code "10, 20, new Derived(), new Derived()")

let%test "params-in-new-call-compatible-with-constructor" =
let code = Printf.sprintf {|
Expand All @@ -404,9 +519,15 @@ let%test "params-in-new-call-compatible-with-constructor" =
&& expects_ctx_err (code "10, 20, 30")
&& expects_ast (code "10, 20, \"hello\"")

(* TODO: numeric-operators-used-on-integers *)

(* TODO: string-operators-used-on-strings *)
let%test "operators-used-on-right-type" =
let code = Printf.sprintf {|
{ %s; }
|}
in let ops = [ "+"; "-"; "*"; "/"; "="; "<>"; "<"; ">"; ">="; "<=" ]
in ops |> List.for_all ~f:(fun op -> expects_ctx_err (code ("\"hello\" " ^ op ^ " 10")))
&& expects_ctx_err (code "10 & \"hello\"")
&& ops |> List.for_all ~f:(fun op -> expects_ast (code ("10" ^ op ^ "10")))
&& expects_ast (code "\"hello\" & \"world\"")

let%test "identifiers-are-in-scope" =
let code = Printf.sprintf {|
Expand Down Expand Up @@ -440,7 +561,18 @@ let%test "attributes-exist" =
in expects_ctx_err (code "foo")
&& expects_ast (code "attr")

(* TODO: static-attributes-exist *)
let%test "static-attributes-exist" =
let code = Printf.sprintf {|
class Point1() is {
def Point1() is {}
var static attr : Integer
}
{
Point1.%s := 5;
}
|}
in expects_ctx_err (code "foo")
&& expects_ast (code "attr")

(* ----------------------------------------------- *)

Expand Down
17 changes: 16 additions & 1 deletion test/parse.ml
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,19 @@ let%test "wrong-classbody" =
{ this.index := Point.incr(); this.hasClone := 0; }
}
{}
|}
|}

let%test "no-static-override" =
let code = Printf.sprintf {|
class Derived() is {
def Derived() is {}
def static test() is {}
}
class Base() extends Derived is {
def Base(): Derived() is {}
def static %s test() is {}
}
{}
|}
in expects_parse_err (code "override")
&& expects_ast (code "")

0 comments on commit f83fb28

Please sign in to comment.