Skip to content

Commit

Permalink
static methods (+ bug in example)
Browse files Browse the repository at this point in the history
  • Loading branch information
mathis committed Dec 31, 2021
1 parent 93466fd commit b1bc5a8
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 50 deletions.
2 changes: 1 addition & 1 deletion doc/contextual_checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* No duplicate static attribute declaration
* No duplicate instance attribute declaration
* No duplicate instance method declaration
* (**Missing**) No duplicate static method declaration
* No duplicate static method declaration
* Herited class exists
* No cycle in inheritance graph

Expand Down
4 changes: 2 additions & 2 deletions lib/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ type ctorDecl = {

type methodDecl = {
name: string;
static: bool;
override: bool;
params: param list;
retType: string option;
Expand All @@ -59,7 +58,8 @@ type methodDecl = {

type classBody = {
ctor: ctorDecl;
methods: methodDecl list;
staticMethods: methodDecl list;
instMethods: methodDecl list;
staticAttrs: param list;
instAttrs: param list;
}
Expand Down
61 changes: 42 additions & 19 deletions lib/astmanip.ml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ let rec ancestors decls decl =
with a given name. *)

let rec find_method_opt decls name decl =
List.find_opt (fun (meth: methodDecl) -> meth.name = name) decl.body.methods
List.find_opt (fun (meth: methodDecl) -> meth.name = name) decl.body.instMethods
|> Optmanip.or_else (fun () ->
match decl.superclass with
| None -> None
Expand All @@ -40,35 +40,58 @@ let rec find_method_opt decls name decl =

(** Get the type of an attribute in a class declaration. *)

let rec get_attr_opt attrName decl =
let rec get_inst_attr_opt attrName decl =
let pred (attr: param) =
if attr.name = attrName then Some(attr.className) else None
in let pred2 (attr: ctorParam) =
if attr.name = attrName then Some(attr.className) else None
in
List.find_map pred decl.body.instAttrs
|> Optmanip.or_else (fun () ->
List.find_map pred decl.body.staticAttrs
)
|> Optmanip.or_else (fun () ->
List.find_map pred2 decl.ctorParams
)
in List.find_map pred decl.body.instAttrs
|> Optmanip.or_else (fun () ->
List.find_map pred2 decl.ctorParams
)

(** Get the type of an attribute in a class declaration.
@raise Not_found if the class has no such attribute. *)

let get_attr attrName decl =
get_attr_opt attrName decl
let get_inst_attr attrName decl =
get_inst_attr_opt attrName decl
|> Optmanip.get_or_else (fun () ->
Printf.eprintf "[ERR] get_attr '%s' failed\n" attrName;
Printf.eprintf "[ERR] get_inst_attr '%s' failed\n" attrName;
raise Not_found
)

(** Get the type of a static attribute in a class declaration. *)

let rec get_static_attr_opt attrName decl =
let pred (attr: param) =
if attr.name = attrName then Some(attr.className) else None
in List.find_map pred decl.body.staticAttrs

(** Get the type of a static attribute in a class declaration.
@raise Not_found if the class has no such attribute. *)

let get_static_attr attrName decl =
get_static_attr_opt attrName decl
|> Optmanip.get_or_else (fun () ->
Printf.eprintf "[ERR] get_static_attr '%s' failed\n" attrName;
raise Not_found
)

(** Get the type of a method in a class declaration.
Note: procedures have the special type 'Void' *)

let get_method_type methName decl =
decl.body.methods
let get_inst_method_type methName decl =
decl.body.instMethods
|> List.find_map (fun (meth: methodDecl) ->
if meth.name = methName then meth.retType else None
)
|> Optmanip.get_or("Void")

(** Get the type of a static method in a class declaration.
Note: procedures have the special type 'Void' *)

let get_static_method_type methName decl =
decl.body.staticMethods
|> List.find_map (fun (meth: methodDecl) ->
if meth.name = methName then meth.retType else None
)
Expand All @@ -86,23 +109,23 @@ let get_expr_type decls env expr =

| Attr(e, attrName) ->
let decl = find_class decls (r_get e)
in get_attr attrName decl
in get_inst_attr attrName decl

| StaticAttr(className, attrName) ->
let decl = find_class decls className
in get_attr attrName decl
in get_static_attr attrName decl

| List l ->
let last = List.hd (List.rev l)
in r_get last

| Call(caller, name, _args) ->
let decl = find_class decls (r_get caller)
in get_method_type name decl
in get_inst_method_type name decl

| StaticCall(className, name, _args) ->
let decl = find_class decls className
in get_method_type name decl
in get_static_method_type name decl

| New(className, _args) -> className

Expand Down
36 changes: 23 additions & 13 deletions lib/contextual.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ exception Contextual_error of string
@raise Contextual_error if a check fails. *)

let check_no_dup decl =
let methods = decl.body.methods |> List.map (fun (m: methodDecl) -> m.name)
let instMethods = decl.body.instMethods |> List.map (fun (m: methodDecl) -> m.name)
in let staticMethods = decl.body.staticMethods |> List.map (fun (m: methodDecl) -> m.name)
in let staticAttrs = decl.body.staticAttrs |> List.map (fun (a: param) -> a.name)
in let instAttrs = decl.body.instAttrs |> List.map (fun (a: param) -> a.name)

Expand All @@ -19,9 +20,10 @@ let check_no_dup decl =
then raise @@ Contextual_error (Printf.sprintf "multiple definition %s of '%s' in class '%s'" t e decl.name)
else check t r

in check "method" methods;
check "static attribute" staticAttrs;
check "instance attribute" instAttrs
in check "method" instMethods;
check "static method" staticMethods;
check "attribute" instAttrs;
check "static attribute" staticAttrs

(** Check that each class declaration extends a declared class, if any.
@raise Contextual_error if a check fails. *)
Expand Down Expand Up @@ -90,8 +92,8 @@ let check_overrides decls decl =
in match decl.superclass with
| Some(super) ->
let superDecl = find_class decls super
in List.iter (check_super_method superDecl) decl.body.methods
| None -> List.iter check_base_method decl.body.methods
in List.iter (check_super_method superDecl) decl.body.instMethods
| None -> List.iter check_base_method decl.body.instMethods

(** Checks that id is in scope.
@raise Contextual_error if a check fails. *)
Expand All @@ -110,10 +112,9 @@ let rec check_method_calls _env _expr _instr =

(** Performs the following checks:
- All code paths lead to either:
(a) A return, or
(a) A return instruction, or
(b) an assign to the implicit 'result' variable.
- All return instructions have a type compatible with the return type
- All assigns to result have a type compatible with the return type *)
- All return instructions have a type compatible with the return type *)

let check_returns decls env retType instr =

Expand Down Expand Up @@ -292,7 +293,7 @@ and check_expr_attr decls env (e, name) =
check_expr decls env e;
let t = get_expr_type decls env e
in let decl = find_class decls t
in let attr = get_attr_opt name decl
in let attr = get_inst_attr_opt name decl
in if Option.is_none attr
then raise @@ Contextual_error (Printf.sprintf "no attribute named '%s' in class '%s'" name t)

Expand All @@ -301,7 +302,7 @@ and check_expr_attr decls env (e, name) =

and check_expr_static_attr decls (t, name) =
let decl = find_class decls t
in let attr = get_attr_opt name decl
in let attr = get_static_attr_opt name decl
in if Option.is_none attr
then raise @@ Contextual_error (Printf.sprintf "no static attribute named '%s' in class '%s'" name t)

Expand All @@ -320,7 +321,15 @@ and check_expr decls env expr =

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

let check_method decls env meth =
let check_static_method decls env meth =
check_no_reserved_var meth.params;
let env = make_method_env env meth
in check_instr decls env meth.body;
match meth.retType with
| Some(ret) -> check_returns decls env ret meth.body
| None -> check_no_return meth.body

let check_instance_method decls env meth =
check_no_reserved_var meth.params;
let env = make_method_env env meth
in check_instr decls env meth.body;
Expand All @@ -338,7 +347,8 @@ let check_decl decls decl =
check_overrides decls decl;
check_no_dup decl;
let env = make_class_env decl
in List.iter (check_method decls env) decl.body.methods
in List.iter (check_instance_method decls env) decl.body.instMethods;
List.iter (check_static_method decls []) decl.body.staticMethods
end

let check_decls decls =
Expand Down
28 changes: 16 additions & 12 deletions lib/parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,27 @@
open Ast

type classBodyElt =
| Method of Ast.methodDecl
| StaticMethod of Ast.methodDecl
| InstMethod of Ast.methodDecl
| Ctor of Ast.ctorDecl
| StaticAttrib of Ast.param list
| InstAttrib of Ast.param list

let split_body_elts l =

let rec r_partition l (lm, lc, ls, li) =
let rec r_partition l (lsm, lim, lc, lsa, lia) =
match l with
| [] -> (lm, lc, ls, li)
| [] -> (lsm, lim, lc, lsa, lia)
| e::r ->
let res = (match e with
| Method m -> (m::lm, lc, ls, li)
| Ctor c -> (lm, c::lc, ls, li)
| StaticAttrib s -> (lm, lc, s@ls, li)
| InstAttrib i -> (lm, lc, ls, i@li))
| StaticMethod m -> (m::lsm, lim, lc, lsa, lia)
| InstMethod m -> (lsm, m::lim, lc, lsa, lia)
| Ctor c -> (lsm, lim, c::lc, lsa, lia)
| StaticAttrib s -> (lsm, lim, lc, s@lsa, lia)
| InstAttrib i -> (lsm, lim, lc, lsa, i@lia))
in r_partition r res

in r_partition l ([], [], [], [])
in r_partition l ([], [], [], [], [])
%}

(* Class Keywords *)
Expand Down Expand Up @@ -71,9 +73,9 @@ classDecl:

classBody:
LCURLY l = list(classBodyElement) RCURLY {
let (lm, lc, ls, li) = split_body_elts l
let (lsm, lim, lc, lsa, lia) = split_body_elts l
in let ctor = List.hd lc (* TODO: make sure there is only one ctor *)
in { methods=lm; ctor; staticAttrs=ls; instAttrs=li }
in { staticMethods=lsm; instMethods=lim; ctor; staticAttrs=lsa; instAttrs=lia }
}

classBodyElement:
Expand All @@ -83,10 +85,12 @@ classBodyElement:

methodDecl:
| DEF static = boption(STATIC) override = boption(OVERRIDE) name = ID params = paramList retType = option(preceded(COLON, CLASSNAME)) IS body = instrBlock {
Method({ name; static; override; params; retType; body; })
let ctor args = if static then StaticMethod args else InstMethod args
in ctor({ name; override; params; retType; body; })
}
| DEF static = boption(STATIC) override = boption(OVERRIDE) name = ID params = paramList COLON retType = CLASSNAME ASSIGN e = expr {
Method({ name; static; override; params; retType=Some(retType); body=Return(e); })
let ctor args = if static then StaticMethod args else InstMethod args
in ctor({ name; override; params; retType=Some(retType); body=Return(e); })
}

ctorDecl:
Expand Down
6 changes: 3 additions & 3 deletions progs/ex1.kat
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ class CouleurFactory() is {
CouleurFactory.theNoir := new Couleur(1);
CouleurFactory.theGris := new Couleur(2);
}
def blanc() : Couleur := CouleurFactory.theBlanc
def noir() : Couleur := CouleurFactory.theNoir
def gris() : Couleur := CouleurFactory.theGris
def static blanc() : Couleur := CouleurFactory.theBlanc
def static noir() : Couleur := CouleurFactory.theNoir
def static gris() : Couleur := CouleurFactory.theGris
}

/* ci-dessous on ne met pas var devant x et y sinon ca definirait deux
Expand Down

0 comments on commit b1bc5a8

Please sign in to comment.