summaryrefslogtreecommitdiff
path: root/src/typing.ml
diff options
context:
space:
mode:
Diffstat (limited to 'src/typing.ml')
-rw-r--r--src/typing.ml177
1 files changed, 122 insertions, 55 deletions
diff --git a/src/typing.ml b/src/typing.ml
index c76c042..7a76b69 100644
--- a/src/typing.ml
+++ b/src/typing.ml
@@ -48,25 +48,25 @@ and texpr_desc =
| TEThis
| TEIdent of ident
| TEAssign of texpression * texpression
- | TECallFun of ident * texpression list (* changé : te -> ident *)
+ | TECallFun of ident * (texpression * bool) list * bool (* changé : te -> ident *)
(* calls to non-virtual methods are compiled using TECallFun, with the object cons'ed at
the begining of the arguments expression list *)
- | TECallVirtual of texpression * int * int * texpression list (* object * index in vtable * arguments *)
+ (* for each argument, bool is is argument passed by reference ? *)
+ (* final bool : is returned value a reference ? *)
+ | TECallVirtual of texpression * int * (texpression * bool) list * bool
+ (* object * index in vtable * arguments * is return value a reference? *)
| TEUnary of unop * texpression
| TEBinary of texpression * binop * texpression
| TEMember of texpression * int (* object * position of member *)
- | TENew of tcls * tproto option * texpression list
+ | TEPointerCast of texpression * int (* object * position of member *)
+ | TENew of tcls * ident * (texpression * bool) list
and tstr_expression =
| TSEExpr of texpression
| TSEStr of string
-and tstatement = {
- ts_loc: loc;
- ts_desc: ts_desc;
- }
-and ts_desc =
+and tstatement =
| TSEmpty
| TSExpr of texpression
| TSIf of texpression * tstatement * tstatement
@@ -74,18 +74,15 @@ and ts_desc =
| TSFor of texpression list * texpression option * texpression list * tstatement
| TSBlock of tblock
| TSReturn of texpression option
- | TSDeclare of type_ref * ident
+ | TSDeclare of typ * ident
| TSDeclareAssignExpr of type_ref * ident * texpression
- | TSDeclareAssignConstructor of typ * ident * tproto option * tident * texpression list (* a faire *)
-(* Type of variable, variable name, constructor class name, constructor arguments *)
+ | TSDeclareAssignConstructor of tcls * ident * ident * (texpression * bool) list
+(* Class name of variable, variable name, constructor name, constructor arguments *)
| TSWriteCout of tstr_expression list
and tblock = tstatement list
and tproto = {
- tp_virtual : (int * int) option; (* only used for class methods ; if none then not virtual,
- if some then gives the index of the method in the vtable (same for all classes
- of the hierarchy that have that method) *)
- tp_loc : loc;
+ tp_virtual : (tcls_hier * int) option; (* only used for class methods ; if none then not virtual *)
tp_name : ident;
tp_unique_ident : ident; (* label de la fonction dans le code assembleur *)
tp_class : tident option; (* p_class = none : standalone function *)
@@ -96,7 +93,7 @@ and tproto = {
and tcls_supers = tcls_hier list
and tcls_hier = {
h_class : tident;
- h_pos : int;
+ mutable h_pos : int;
mutable h_vtable : (int * tproto) list; (* only to be muted during class definition parsing *)
h_supers : tcls_supers
}
@@ -130,6 +127,7 @@ type tdeclaration =
type tprogram = {
prog_decls : tdeclaration list;
prog_env : env;
+ prog_main : ident;
}
(* Quelques fonctions utiles : *)
@@ -183,10 +181,45 @@ let rec subtype env a b = match a, b with
let c = get_c env i in
let rec find_in_hier h =
h.h_class = j ||
- (List.exists find_in_hier h.h_supers)
+ (List.length (List.filter find_in_hier h.h_supers) = 1)
in find_in_hier c.tc_hier
| _ -> false
+let relative_class_position env i j =
+ let c = get_c env i in
+ let rec find_in_hier h =
+ h.h_class = j ||
+ (List.length (List.filter find_in_hier h.h_supers) = 1)
+ and get_in_hier h =
+ if h.h_class = j
+ then h.h_pos
+ else match List.filter find_in_hier h.h_supers with
+ | [a] -> get_in_hier a
+ | _ -> assert false
+ in get_in_hier c.tc_hier
+
+let rec upcast env exp dt = (* présupposé : exp.type_expr <= dt *)
+ match exp.type_expr, dt with
+ | (T_Int, _, _), T_Int -> exp
+ | (T_Void, _, _), T_Void -> exp
+ | (Typenull, _, _), TPoint(_) -> exp
+ | (TClass(i), a, b), TClass(j) when a||b ->
+ begin match relative_class_position env i j with
+ | 0 -> exp
+ | pos ->
+ { type_expr = (TClass(j), false, true); te_loc = exp.te_loc;
+ te_desc = TEMember(exp, pos) }
+ end
+ | (TPoint(TClass(i)), a, b), TPoint(TClass(j)) ->
+ begin match relative_class_position env i j with
+ | 0 -> exp
+ | pos ->
+ { type_expr = (TPoint(TClass(j)), false, true); te_loc = exp.te_loc;
+ te_desc = TEPointerCast(exp, pos) }
+ end
+ | (TPoint(ka), _, _), TPoint(kb) -> exp
+ | _ -> assert false
+
let type_size env t = match t with
| T_Int | Typenull | TPoint(_) -> 4
| T_Void -> 0
@@ -314,7 +347,7 @@ and compute_type env e =
ty_assert (num ty1) "Cannot assign to non-numeric type (pointer type is numeric)";
ty_assert (subtype env.b_pe ty2 ty1) "Incompatible types in assign";
(* type num et ref compatibles ?*)
- (TEAssign (te1,te2) ),(ty1,false,false)
+ (TEAssign (te1,upcast env.b_pe te2 ty1) ),(ty1,false,false)
| EUnary (op,e) -> let te,(ty,b1,b2) = get_expr0 env e in
(match op with
| PreIncr | PostIncr | PreDecr | PostDecr ->
@@ -339,14 +372,17 @@ and compute_type env e =
| Equal | NotEqual ->
ty_assert ((subtype env.b_pe ty1 ty2) || (subtype env.b_pe ty2 ty1))
"Can only apply == or != to two values of compatible type";
- ty_assert (num ty1) "Can only apply == or != to pointers"
+ ty_assert (num ty1) "Can only apply == or != to pointers";
+ let te1 = if subtype env.b_pe ty1 ty2 then upcast env.b_pe te1 ty2 else te1 in
+ let te2 = if subtype env.b_pe ty2 ty1 then upcast env.b_pe te2 ty1 else te2 in
+ TEBinary(te1,op,te2),(T_Int,false,false)
| Lt | Le | Gt | Ge
| Add | Sub | Mul | Div | Modulo
| Land | Lor ->
ty_assert (ty1 = T_Int) "Left operand of binop is not integer";
- ty_assert (ty2 = T_Int) "Right operand of binop is not integer"
- ); (* vérifs *)
- TEBinary(te1,op,te2),(T_Int,false,false)
+ ty_assert (ty2 = T_Int) "Right operand of binop is not integer";
+ TEBinary(te1,op,te2),(T_Int,false,false)
+ )
| ECall (e,e_list) ->
let args_values = List.map (get_expr0 env) e_list in
let args_types = List.map (fun (e, (t, r, l)) -> t, r||l) args_values in
@@ -357,8 +393,12 @@ and compute_type env e =
begin match env.b_class with
| None -> None, closest_proto env.b_pe args_types funs
| Some k ->
- begin try Some e_this_not_ptr,
- closest_proto env.b_pe args_types (find_protos_in_class env.b_pe k.tc_name i)
+ begin try
+ let proto = closest_proto env.b_pe args_types (find_protos_in_class env.b_pe k.tc_name i) in
+ let upcasted = if proto.tp_virtual = None then e_this_not_ptr
+ else upcast env.b_pe e_this_not_ptr
+ (TClass (match proto.tp_class with | None -> assert false | Some k -> k)) in
+ Some upcasted, proto
with NoCorrespondingPrototype ->
None, closest_proto env.b_pe args_types funs
end
@@ -367,7 +407,11 @@ and compute_type env e =
let e = type_expr env e in
begin match e.type_expr with
| TClass(k), a, b when a || b ->
- Some e, closest_proto env.b_pe args_types (find_protos_in_class env.b_pe k i)
+ let proto = closest_proto env.b_pe args_types (find_protos_in_class env.b_pe k i) in
+ let upcasted = if proto.tp_virtual = None then e
+ else upcast env.b_pe e
+ (TClass (match proto.tp_class with | None -> assert false | Some k -> k)) in
+ Some upcasted, proto
| _ -> ty_error "Invalid argument type for method call (not a class, or not a lvalue)"
end
| EQIdent(c, i) ->
@@ -375,22 +419,27 @@ and compute_type env e =
| Some k ->
let sc = try find_cls_superclass env.b_pe k.tc_name c
with Not_found -> ty_error (c ^ " is no superclass of current class " ^ k.tc_name) in
- Some e_this_not_ptr,
- closest_proto env.b_pe args_types (find_protos_in_class env.b_pe sc.h_class i)
+ let proto = closest_proto env.b_pe args_types (find_protos_in_class env.b_pe sc.h_class i) in
+ let upcasted = if proto.tp_virtual = None
+ then upcast env.b_pe e_this_not_ptr (TClass(c))
+ else upcast env.b_pe e_this_not_ptr
+ (TClass (match proto.tp_class with | None -> assert false | Some k -> k)) in
+ Some upcasted, proto
| None -> ty_error "Qualified identifier in a function belonging to no class."
end
| _ -> ty_error "Calling something that is neither a function nor a method") in
let l_te = List.map fst args_values in
+ let l_te = List.map2 (fun k ((ty, r), _) -> upcast env.b_pe k ty, r) l_te tproto.tp_args in
let ty,b = match tproto.tp_ret_type with
| None -> ty_error "Constructor cannot be called as function"
| Some (ty,b) -> ty,b in
begin match tproto.tp_virtual, obj with
| None, None ->
- TECallFun(tproto.tp_unique_ident,l_te),(ty,b,false)
+ TECallFun(tproto.tp_unique_ident,l_te,b),(ty,b,false)
| None, Some(obj)->
- TECallFun(tproto.tp_unique_ident,obj::l_te),(ty,b,false)
- | Some(idx), Some(obj) ->
- TECallVirtual(obj, fst idx, snd idx, l_te),(ty,b,false)
+ TECallFun(tproto.tp_unique_ident,(obj, true)::l_te,b),(ty,b,false)
+ | Some(hier, idx), Some(obj) ->
+ TECallVirtual(upcast env.b_pe obj (TClass hier.h_class), idx, l_te,b),(ty,b,false)
| _ -> ty_error "(should not happen) Virtual function applied to no object..."
end
| EMember (e, id) ->
@@ -409,14 +458,13 @@ and compute_type env e =
let args_types = List.map (fun (e, (t, r, l)) -> t, r||l) args_values in
let candidates = List.filter (fun p -> p.tp_ret_type = None) c.tc_methods in
begin match candidates with
- | [] ->
- ty_assert (args = []) "Only default constructor exists and it has 0 arguments";
- TENew(c, None, []), (TPoint(TClass(cls_name)), false, false)
+ | [] -> assert false (* default constructor should always be in list *)
| _ ->
let p = closest_proto env.b_pe args_types candidates in
(* closest_proto makes sure the prototypes match, no problem here *)
let l_te = List.map fst args_values in
- TENew(c, Some p, l_te), (TPoint(TClass(cls_name)), false, false)
+ let l_te = List.map2 (fun k ((ty, r), _) -> upcast env.b_pe k ty, r) l_te p.tp_args in
+ TENew(c, p.tp_unique_ident, l_te), (TPoint(TClass(cls_name)), false, false)
end
| EThis ->
begin match env.b_class with
@@ -428,9 +476,7 @@ and compute_type env e =
(* Statements *)
let rec type_stm ret_type env s =
- err_add_loc s.s_loc (fun () ->
- let d, ty = compute_type_stm ret_type env s in
- { ts_loc = s.s_loc; ts_desc = d }, ty)
+ err_add_loc s.s_loc (fun () -> compute_type_stm ret_type env s)
and compute_type_stm ret_type env s = match s.s_desc with (* statement -> ts_desc,stm_type *)
| SEmpty -> TSEmpty,env
@@ -470,9 +516,10 @@ and compute_type_stm ret_type env s = match s.s_desc with (* statement -> ts_des
(* pq while n'est pas dans les règles données ? *)
| SDeclare(vt,i) -> let ty,b = build_type_or_ref vt in
ty_assert (bf env.b_pe ty) "Malformed type";
+ ty_assert (not b) "Reference must be assigned at declaration";
ty_assert (not (Smap.mem i env.b_locals) ) "Variable redefinition";
let env0 = { env with b_locals = Smap.add i (ty,b) env.b_locals } in
- TSDeclare( (ty,b) ,i) , env0
+ TSDeclare( ty ,i) , env0
| SDeclareAssignExpr(vt,i,e) -> let ty,b = build_type_or_ref vt in
ty_assert (bf env.b_pe ty) "Malformed type";
ty_assert (not (Smap.mem i env.b_locals)) "Variable redefinition";
@@ -480,7 +527,7 @@ and compute_type_stm ret_type env s = match s.s_desc with (* statement -> ts_des
ty_assert (if b then r || l else true) "Can only assigne lvalue/reference to reference type var";
ty_assert (subtype env.b_pe tye ty) "Invalid data type for assign.";
let env0 = { env with b_locals = Smap.add i (ty,b) env.b_locals } in
- TSDeclareAssignExpr( (ty,b) ,i,te) , env0
+ TSDeclareAssignExpr( (ty,b) ,i,upcast env.b_pe te ty) , env0
| SDeclareAssignConstructor(vt,i,ti,e_l) ->
let ty, b = build_type_or_ref vt in
ty_assert (bf env.b_pe ty) "Malformed type";
@@ -492,15 +539,14 @@ and compute_type_stm ret_type env s = match s.s_desc with (* statement -> ts_des
let args_types = List.map (fun (e, (t, r, l)) -> t, r||l) args_values in
let candidates = List.filter (fun p -> p.tp_ret_type = None) c.tc_methods in
begin match candidates with
- | [] ->
- ty_assert (e_l = []) "Only default constructor exists and it has 0 arguments";
- TSDeclareAssignConstructor(ty, i, None, ti, []), env
+ | [] -> assert false (* ... *)
| _ ->
let p = closest_proto env.b_pe args_types candidates in
(* closest_proto makes sure the prototypes match, no problem here *)
let l_te = List.map fst args_values in
+ let l_te = List.map2 (fun k ((ty, r), _) -> upcast env.b_pe k ty, r) l_te p.tp_args in
let env0 = { env with b_locals = Smap.add i (ty,b) env.b_locals } in
- TSDeclareAssignConstructor(ty, i, Some p, ti, l_te), env0
+ TSDeclareAssignConstructor(c, i, p.tp_unique_ident, l_te), env0
end
| SWriteCout(str_e_list) ->
let args =
@@ -559,7 +605,6 @@ let get_fun env p b = (* p : proto b : block -> tp, tb, env2*)
(* Add to env *)
let tproto = {
- tp_loc = p.p_loc ;
tp_name = name ;
tp_unique_ident = name ^ (tproto_unique_number());
tp_class = None ;
@@ -649,22 +694,19 @@ let compute_tclass env c =
| None ->
List.fold_left (fun f (i, p) ->
if (p.tp_name = proto.p_name && (List.map fst p.tp_args) = (List.map fst args))
- then Some (i, s)
+ then Some (s, i)
else f) None s.h_vtable
in let super = match check_in_super hier with
| None -> if virt then
(* allocate new spot in vtable of this object *)
- Some (List.fold_left (fun n (x, _) -> max n (x+4)) 0 hier.h_vtable, hier)
+ Some (hier, List.fold_left (fun n (x, _) -> max n (x+4)) 0 hier.h_vtable)
else None
| Some k -> Some k
in
(* Build proto *)
let tproto =
- { tp_virtual = (match super with
- | Some(i, c) -> Some(c.h_pos, i)
- | None -> None);
- tp_loc = proto.p_loc;
+ { tp_virtual = super;
tp_name = proto.p_name;
tp_unique_ident = proto.p_name ^ (tproto_unique_number()) ;
tp_class = Some(cls_name);
@@ -674,12 +716,36 @@ let compute_tclass env c =
(* Add to vtable *)
begin match super with
| None -> ()
- | Some (i, c) ->
+ | Some (c, i) ->
c.h_vtable <- (i, tproto)::(List.remove_assoc i c.h_vtable)
end;
tproto) in
(mem, mem_u), m::meth
) ((Smap.empty, used), []) c.c_members in
+ (* make sure class has default constructor *)
+ let meth =
+ if List.exists (fun p -> p.tp_ret_type = None && p.tp_name = cls_name) meth
+ then meth
+ else
+ { tp_virtual = None;
+ tp_name = cls_name;
+ tp_unique_ident = cls_name ^ "0";
+ tp_class = Some cls_name;
+ tp_ret_type = None;
+ tp_args = [] }::meth
+ in
+ (* if vtable is empty, remove it *)
+ let mem, mem_u =
+ if hier.h_vtable = [] then
+ let rec mv_h h =
+ h.h_pos <- h.h_pos - 4;
+ List.iter mv_h h.h_supers
+ in
+ List.iter mv_h hier.h_supers;
+ Smap.map (fun (ty, pos) -> (ty, pos-4)) mem, mem_u - 4
+ else
+ mem, mem_u
+ in
{ tc_name = cls_name;
tc_size = mem_u;
tc_hier = hier;
@@ -751,11 +817,12 @@ let prog p =
([],{ e_globals = Smap.empty; e_funs = []; e_classes = Smap.empty })
p
) in
- ty_assert (List.exists
+ let p = try List.find
(fun tp -> tp.tp_class = None && tp.tp_name = "main"
&& tp.tp_args = [] && tp.tp_ret_type = Some (T_Int,false))
- env.e_funs) "No 'int main()' function defined in program...";
- { prog_decls = List.rev decls; prog_env = env }
+ env.e_funs
+ with Not_found -> ty_error "No correct main function in program." in
+ { prog_decls = List.rev decls; prog_env = env; prog_main = p.tp_unique_ident }