Project

General

Profile

« Previous | Next » 

Revision 5538b7ac

Added by Xavier Thirioux about 11 years ago

Added declaration/definition of stateless/stateful nodes.
The 'function' keyword is for stateless nodes only,
the 'node' keyword is any kind of node.
Improves compilation and paves the way for more optimizations.

View differences:

src/c_backend.ml
504 504
    self
505 505

  
506 506
let print_stateless_prototype fmt (name, inputs, outputs) =
507
match outputs with
508
(* DOESN'T WORK FOR ARRAYS
509
  | [o] -> fprintf fmt "%a (@[<v>%a@])"
510
    (pp_c_type name) o.var_type
511
    (Utils.fprintf_list ~sep:",@ " pp_c_var) inputs
512
*)  
513
  | _ -> fprintf fmt "void %s (@[<v>@[%a%t@]@,@[%a@]@,@])"
507
  fprintf fmt "void %s (@[<v>@[%a%t@]@,@[%a@]@,@])"
514 508
    name
515 509
    (Utils.fprintf_list ~sep:",@ " pp_c_decl_input_var) inputs
516 510
    (Utils.pp_final_char_if_non_empty ",@ " inputs) 
......
530 524
(*                         Header Printing functions                                        *)
531 525
(********************************************************************************************)
532 526

  
533
(* Removed because of "open" constructs. No more extern functions *)
534
(*
535
let print_prototype fmt decl =
536
  match decl.top_decl_desc with
537
    | ImportedFun m -> (
538
        fprintf fmt "extern %a;@,"
539
	  print_stateless_prototype 
540
	  (m.fun_id, m.fun_inputs, m.fun_outputs)
541
    )
542
    | ImportedNode m -> (
543
      if m.nodei_stateless then (* It's a function not a node *)
544
        fprintf fmt "extern %a;@,"
545
	  print_stateless_prototype 
546
	  (m.nodei_id, m.nodei_inputs, m.nodei_outputs)
547
      else (
548
	let static = List.filter (fun v -> v.var_dec_const) m.nodei_inputs in
549
        fprintf fmt "extern %a;@,"
550
	  print_alloc_prototype (m.nodei_id, static);
551
	fprintf fmt "extern %a;@,"
552
	  (print_reset_prototype "self") (m.nodei_id, static);
553
	fprintf fmt "extern %a;@,"
554
	  (print_step_prototype "self") (m.nodei_id, m.nodei_inputs, m.nodei_outputs);
555
      )
556
    )
557
    | _ -> () (* We don't do anything here *)
558
      *)
559 527

  
560 528
let print_import_standard fmt =
561 529
  fprintf fmt "#include \"%s/include/lustrec/arrow.h\"@.@." Version.prefix
562 530

  
563
let print_prototype fmt decl =
531
let print_import_prototype fmt decl =
564 532
  match decl.top_decl_desc with
565 533
  | Open m -> fprintf fmt "#include \"%s.h\"@," m
566 534
  | _ -> () (* We don't do anything here *)
......
575 543
    ()
576 544

  
577 545
let print_machine_struct fmt m =
578
  if m.mname.node_id != arrow_id
579
  then (
580
    (* We don't print arrow function *)
581
    (* Define struct *)
582
    fprintf fmt "@[%a {@[%a%a%t@]};@]@."
583
      pp_machine_memtype_name m.mname.node_id
584
      pp_registers_struct m
585
      (Utils.fprintf_list ~sep:"; " pp_c_decl_instance_var) m.minstances
586
      (Utils.pp_final_char_if_non_empty "; " m.minstances)
587
  )
546
  if fst (get_stateless_status m) then
547
    begin
548
    end
549
  else
550
    begin
551
      (* Define struct *)
552
      fprintf fmt "@[%a {@[%a%a%t@]};@]@."
553
	pp_machine_memtype_name m.mname.node_id
554
	pp_registers_struct m
555
	(Utils.fprintf_list ~sep:"; " pp_c_decl_instance_var) m.minstances
556
	(Utils.pp_final_char_if_non_empty "; " m.minstances)
557
    end
588 558

  
589
(*
590
let pp_static_array_instance fmt m (v, m) =
591
 fprintf fmt "%s" (mk_addr_var m v)
592
*)
593 559
let print_static_declare_instance attr fmt (i, (m, static)) =
594 560
  fprintf fmt "%a(%s, %a%t%s)"
595 561
    pp_machine_static_declare_name (node_name m)
......
655 621
    pp_machine_static_link_name m.mname.node_id
656 622

  
657 623
let print_machine_decl fmt m =
658
  if m.mname.node_id <> arrow_id
659
  then (
660
    (* We don't print arrow function *)
661
    (* Static allocation *)
662
    if !Options.static_mem
663
    then (
664
      fprintf fmt "%a@.%a@.%a@."
665
	print_static_declare_macro m
666
	print_static_link_macro m
667
	print_static_alloc_macro m
668
    )
669
    else ( 
670
    (* Dynamic allocation *)
624
  if fst (get_stateless_status m) then
625
    begin
626
      (* Print specification if any *)
627
      (match m.mspec with
628
      | None -> ()
629
      | Some spec -> 
630
	pp_acsl_spec m.mstep.step_outputs fmt spec
631
      );
671 632
      fprintf fmt "extern %a;@.@."
672
	print_alloc_prototype (m.mname.node_id, m.mstatic)
673
    );
674
    let self = mk_self m in
675
    fprintf fmt "extern %a;@.@."
676
      (print_reset_prototype self) (m.mname.node_id, m.mstatic);
677
    (* Print specification if any *)
678
    (match m.mspec with
633
	print_stateless_prototype
634
	(m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs)
635
    end
636
  else
637
    begin
638
      (* Static allocation *)
639
      if !Options.static_mem
640
      then (
641
	fprintf fmt "%a@.%a@.%a@."
642
	  print_static_declare_macro m
643
	  print_static_link_macro m
644
	  print_static_alloc_macro m
645
      )
646
      else ( 
647
        (* Dynamic allocation *)
648
	fprintf fmt "extern %a;@.@."
649
	  print_alloc_prototype (m.mname.node_id, m.mstatic)
650
      );
651
      let self = mk_self m in
652
      fprintf fmt "extern %a;@.@."
653
	(print_reset_prototype self) (m.mname.node_id, m.mstatic);
654
      (* Print specification if any *)
655
      (match m.mspec with
679 656
      | None -> ()
680 657
      | Some spec -> 
681 658
	pp_acsl_spec m.mstep.step_outputs fmt spec
682
    );
683
    fprintf fmt "extern %a;@.@."
684
      (print_step_prototype self)
685
      (m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs)
686
  )
659
      );
660
      fprintf fmt "extern %a;@.@."
661
	(print_step_prototype self)
662
	(m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs)
663
    end
687 664

  
688 665

  
689 666
(********************************************************************************************)
......
722 699
    (Utils.fprintf_list ~sep:"" print_alloc_array) array_mem
723 700
    (Utils.fprintf_list ~sep:"" print_alloc_instance) m.minstances
724 701

  
702
let print_stateless_code fmt m =
703
  let self = "__ERROR__" in
704
  if not (!Options.ansi && is_generic_node { top_decl_desc = Node m.mname; top_decl_loc = Location.dummy_loc })
705
  then
706
    (* C99 code *)
707
    fprintf fmt "@[<v 2>%a {@,%a%t@,%a%a%t%t@]@,}@.@."
708
      print_stateless_prototype (m.mname.node_id, m.mstep.step_inputs, m.mstep.step_outputs)
709
      (* locals *)
710
      (Utils.fprintf_list ~sep:";@," pp_c_decl_local_var) m.mstep.step_locals
711
      (Utils.pp_final_char_if_non_empty ";@," m.mstep.step_locals)
712
      (* check assertions *)
713
      (pp_c_checks self) m
714
      (* instrs *)
715
      (Utils.fprintf_list ~sep:"@," (pp_machine_instr m self)) m.mstep.step_instrs
716
      (Utils.pp_newline_if_non_empty m.mstep.step_instrs)
717
      (fun fmt -> fprintf fmt "return;")
718
  else
719
    (* C90 code *)
720
    let (gen_locals, base_locals) = List.partition (fun v -> Types.is_generic_type v.var_type) m.mstep.step_locals in
721
    let gen_calls = List.map (fun e -> let (id, _, _) = call_of_expr e in mk_call_var_decl e.expr_loc id) m.mname.node_gencalls in
722
    fprintf fmt "@[<v 2>%a {@,%a%t@,%a%a%t%t@]@,}@.@."
723
      print_stateless_prototype (m.mname.node_id, (m.mstep.step_inputs@gen_locals@gen_calls), m.mstep.step_outputs)
724
      (* locals *)
725
      (Utils.fprintf_list ~sep:";@," pp_c_decl_local_var) base_locals
726
      (Utils.pp_final_char_if_non_empty ";" base_locals)
727
      (* check assertions *)
728
      (pp_c_checks self) m
729
      (* instrs *)
730
      (Utils.fprintf_list ~sep:"@," (pp_machine_instr m self)) m.mstep.step_instrs
731
      (Utils.pp_newline_if_non_empty m.mstep.step_instrs)
732
      (fun fmt -> fprintf fmt "return;")
733

  
725 734
let print_step_code fmt m self =
726 735
  if not (!Options.ansi && is_generic_node { top_decl_desc = Node m.mname; top_decl_loc = Location.dummy_loc })
727 736
  then
......
758 767
      (fun fmt -> fprintf fmt "return;")
759 768

  
760 769
let print_machine fmt m =
761
  if m.mname.node_id <> arrow_id
762
  then (
763
  (* We don't print arrow function *)
764
  (* Alloc function, only if non static mode *)
765
    if (not !Options.static_mem) then  
766
      (
767
	fprintf fmt "@[<v 2>%a {@,%a@]@,}@.@."
768
	  print_alloc_prototype (m.mname.node_id, m.mstatic)
769
	  print_alloc_code m;
770
      );
771
    let self = mk_self m in
772
    (* Reset function *)
773
    fprintf fmt "@[<v 2>%a {@,%a%treturn;@]@,}@.@."
774
      (print_reset_prototype self) (m.mname.node_id, m.mstatic)
775
      (Utils.fprintf_list ~sep:"@," (pp_machine_instr m self)) m.minit
776
      (Utils.pp_newline_if_non_empty m.minit);
777
    (* Step function *)
778
    print_step_code fmt m self
779
  )
770
  if fst (get_stateless_status m) then
771
    begin
772
      (* Step function *)
773
      print_stateless_code fmt m
774
    end
775
  else
776
    begin
777
      (* Alloc function, only if non static mode *)
778
      if (not !Options.static_mem) then  
779
	(
780
	  fprintf fmt "@[<v 2>%a {@,%a@]@,}@.@."
781
	    print_alloc_prototype (m.mname.node_id, m.mstatic)
782
	    print_alloc_code m;
783
	);
784
      let self = mk_self m in
785
      (* Reset function *)
786
      fprintf fmt "@[<v 2>%a {@,%a%treturn;@]@,}@.@."
787
	(print_reset_prototype self) (m.mname.node_id, m.mstatic)
788
	(Utils.fprintf_list ~sep:"@," (pp_machine_instr m self)) m.minit
789
	(Utils.pp_newline_if_non_empty m.minit);
790
      (* Step function *)
791
      print_step_code fmt m self
792
    end
780 793

  
781 794
(********************************************************************************************)
782 795
(*                         Main related functions                                           *)
......
972 985
  (* Print the prototype of imported nodes *)
973 986
  fprintf source_fmt "/* Imported nodes declarations */@.";
974 987
  fprintf source_fmt "@[<v>";
975
  List.iter (print_prototype source_fmt) prog;
988
  List.iter (print_import_prototype source_fmt) prog;
976 989
  fprintf source_fmt "@]@.";
977 990
  (* Print consts *)
978 991
  fprintf source_fmt "/* Global constants (definitions) */@.";
src/corelang.ml
104 104
     mutable node_checks: Dimension.dim_expr list;
105 105
     node_asserts: assert_t list; 
106 106
     node_eqs: eq list;
107
     node_dec_stateless: bool;
107
     mutable node_dec_stateless: bool;
108 108
     mutable node_stateless: bool option;
109 109
     node_spec: LustreSpec.node_annot option;
110 110
     node_annot: LustreSpec.expr_annot option;
......
145 145
  | No_main_specified
146 146
  | Unbound_symbol of ident
147 147
  | Already_bound_symbol of ident
148
  | Stateful of ident
149 148

  
150 149
exception Error of Location.t * error
151 150

  
......
262 261
  | ImportedNode nd -> true
263 262
  | _ -> assert false
264 263

  
265
let rec is_stateless_expr expr =
266
  match expr.expr_desc with
267
  | Expr_const _ 
268
  | Expr_ident _ -> true
269
  | Expr_tuple el
270
  | Expr_array el -> List.for_all is_stateless_expr el
271
  | Expr_access (e1, _)
272
  | Expr_power (e1, _) -> is_stateless_expr e1
273
  | Expr_ite (c, t, e) -> is_stateless_expr c && is_stateless_expr t && is_stateless_expr e
274
  | Expr_arrow (e1, e2)
275
  | Expr_fby (e1, e2) -> is_stateless_expr e1 && is_stateless_expr e2
276
  | Expr_pre e' -> is_stateless_expr e'
277
  | Expr_when (e', i, l)-> is_stateless_expr e'
278
  | Expr_merge (i, hl) -> List.for_all (fun (t, h) -> is_stateless_expr h) hl 
279
  | Expr_appl (i, e', i') ->
280
    is_stateless_expr e' &&
281
      (Basic_library.is_internal_fun i || check_stateless_node (node_from_name i))
282
  | Expr_uclock _
283
  | Expr_dclock _
284
  | Expr_phclock _ -> assert false
285
and compute_stateless_node nd =
286
 List.for_all (fun eq -> is_stateless_expr eq.eq_rhs) nd.node_eqs
287
and check_stateless_node td =
288
  match td.top_decl_desc with 
289
  | Node nd         -> (
290
    match nd.node_stateless with
291
    | None     -> 
292
      begin
293
	let stateless = compute_stateless_node nd in
294
	nd.node_stateless <- Some (false && stateless);
295
	if nd.node_dec_stateless && (not stateless)
296
	then raise (Error (td.top_decl_loc, Stateful nd.node_id))
297
	else stateless
298
      end
299
    | Some stl -> stl)
300
  | ImportedNode nd -> nd.nodei_stateless
301
  | _ -> true
302 264

  
303 265
(* alias and type definition table *)
304 266
let type_table =
......
766 728
    fprintf fmt
767 729
      "%s is already defined.@."
768 730
      sym
769
  | Stateful nd ->
770
    fprintf fmt
771
      "node %s is declared stateless, but it is stateful.@."
772
      nd
773 731

  
774 732
(* filling node table with internal functions *)
775 733
let vdecls_of_typ_ck cpt ty =
src/corelang.mli
97 97
     mutable node_checks: Dimension.dim_expr list;
98 98
     node_asserts: assert_t list; 
99 99
     node_eqs: eq list;
100
     node_dec_stateless: bool;
100
     mutable node_dec_stateless: bool;
101 101
     mutable node_stateless: bool option;
102 102
     node_spec: LustreSpec.node_annot option;
103 103
     node_annot: LustreSpec.expr_annot option;}
......
153 153
  | No_main_specified
154 154
  | Unbound_symbol of ident
155 155
  | Already_bound_symbol of ident
156
  | Stateful of ident
157 156

  
158 157
exception Error of Location.t * error
159 158

  
......
175 174
val node_inputs: top_decl -> var_decl list
176 175
val node_from_name: ident -> top_decl
177 176
val is_generic_node: top_decl -> bool
178
val check_stateless_node: top_decl -> bool
179 177
val is_imported_node: top_decl -> bool
180 178

  
181 179
val consts_table: (ident, const_desc) Hashtbl.t
......
207 205

  
208 206
val sort_handlers : (label * 'a) list -> (label * 'a) list
209 207

  
210
val is_stateless_expr: expr -> bool
211 208
val is_eq_expr: expr -> expr -> bool
212 209

  
213 210
val pp_error :  Format.formatter -> error -> unit
src/machine_code.ml
124 124
    (Utils.fprintf_list ~sep:"@ " pp_instr) m.minit
125 125
    pp_step m.mstep
126 126

  
127
(* Returns the declared stateless status and the computed one. *)
128
let get_stateless_status m =
129
 (m.mname.node_dec_stateless, Utils.desome m.mname.node_stateless)
130

  
127 131
let is_output m id =
128 132
  List.exists (fun o -> o.var_id = id.var_id) m.mstep.step_outputs
129 133

  
......
200 204
  fun caller callee tag ->
201 205
    begin
202 206
      let o =
203
	if Corelang.check_stateless_node callee then
207
	if Stateless.check_node callee then
204 208
	  node_name callee
205 209
	else
206 210
	  Printf.sprintf "ni_%d" (incr cpt; !cpt) in
......
364 368
      NodeDep.filter_static_inputs (node_inputs node_f) el in 
365 369
    let o = new_instance node node_f eq.eq_rhs.expr_tag in
366 370
    (m,
367
     (if check_stateless_node node_f then si else MReset o :: si),
371
     (if Stateless.check_node node_f then si else MReset o :: si),
368 372
     (if Basic_library.is_internal_fun f then j else Utils.IMap.add o call_f j),
369 373
     d,
370 374
     reset_instance node args o r eq.eq_rhs.expr_clock @
......
436 440
    mname = nd;
437 441
    mmemory = ISet.elements m;
438 442
    mcalls = mmap;
439
    minstances = List.filter (fun (_, (n,_)) -> not (check_stateless_node n)) mmap;
443
    minstances = List.filter (fun (_, (n,_)) -> not (Stateless.check_node n)) mmap;
440 444
    minit = init;
441 445
    mstatic = List.filter (fun v -> v.var_dec_const) nd.node_inputs;
442 446
    mstep = {
......
461 465
let translate_prog decls = 
462 466
  let nodes = get_nodes decls in 
463 467
   (* What to do with Imported/Sensor/Actuators ? *)
464
   arrow_machine ::  List.map translate_decl nodes
468
   (*arrow_machine ::*)  List.map translate_decl nodes
465 469

  
466 470
let get_machine_opt name machines =  
467 471
  List.fold_left 
src/main_lustre_compiler.ml
33 33
let check_stateless_decls decls =
34 34
  report ~level:1 (fun fmt -> fprintf fmt ".. checking stateless/stateful status@,@?");
35 35
  try
36
    List.iter (fun td -> ignore (Corelang.check_stateless_node td)) decls
37
  with (Corelang.Error (loc, err)) as exc ->
36
    Stateless.check_prog decls
37
  with (Stateless.Error (loc, err)) as exc ->
38 38
    Format.eprintf "Stateless status error at loc %a: %a@]@."
39 39
      Location.pp_loc loc
40
      Corelang.pp_error err;
40
      Stateless.pp_error err;
41 41
    raise exc
42 42

  
43 43
let type_decls env decls =  
......
208 208
      Typing.uneval_prog_generics prog;
209 209
      (* checking clocks compatibility with computed clocks*)
210 210
      Clock_calculus.check_env_compat header declared_clocks_env computed_clocks_env;
211
      Clock_calculus.uneval_prog_generics prog
211
      Clock_calculus.uneval_prog_generics prog;
212
      (* checking stateless status compatibility *)
213
      Stateless.check_compat header
212 214
    with Sys_error _ -> ( 
213 215
      (* Printing lusi file is necessary *)
214 216
      report ~level:1 
......
229 231
      Format.eprintf "Clock mismatch between computed clock and declared clock in lustre interface file: %a@]@."
230 232
	Clocks.pp_error err;
231 233
      raise exc
234
    | Stateless.Error (loc, err) as exc ->
235
      Format.eprintf "Stateless status mismatch between defined status and declared status in lustre interface file: %a@]@."
236
	Stateless.pp_error err;
237
      raise exc
232 238
  in
233 239

  
234 240
  (* Computes and stores generic calls for each node,
src/parser_lustre.mly
46 46
  try
47 47
    match (Hashtbl.find hashtbl name).top_decl_desc, value.top_decl_desc with
48 48
    | Node _        , ImportedNode _ when own
49
                        ->
50
       Hashtbl.add hashtbl name value
49
                        -> ()
51 50
    | ImportedNode _, _ ->
52 51
       Hashtbl.add hashtbl name value
53 52
    | Node _        , _ -> 
src/printers.ml
286 286
  match decl.top_decl_desc with
287 287
  | Node nd ->  
288 288
    fprintf fmt 
289
      "@[<v>node %s (%a) returns (%a);@ @]@ "
289
      "@[<v>%s %s (%a) returns (%a);@ @]@ "
290
      (if Stateless.check_node decl then "function" else "node")
290 291
      nd.node_id
291 292
      pp_node_args nd.node_inputs
292 293
      pp_node_args nd.node_outputs
src/stateless.ml
1
(* ----------------------------------------------------------------------------
2
 * SchedMCore - A MultiCore Scheduling Framework
3
 * Copyright (C) 2009-2011, ONERA, Toulouse, FRANCE - LIFL, Lille, FRANCE
4
 *
5
 * This file is part of Prelude
6
 *
7
 * Prelude is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public License
9
 * as published by the Free Software Foundation ; either version 2 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * Prelude is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY ; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this program ; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20
 * USA
21
 *---------------------------------------------------------------------------- *)
22
open Corelang
23

  
24
type error =
25
| Stateful_kwd of ident
26
| Stateful_imp of ident
27

  
28
exception Error of Location.t * error
29

  
30
let rec check_expr expr =
31
  match expr.expr_desc with
32
  | Expr_const _ 
33
  | Expr_ident _ -> true
34
  | Expr_tuple el
35
  | Expr_array el -> List.for_all check_expr el
36
  | Expr_access (e1, _)
37
  | Expr_power (e1, _) -> check_expr e1
38
  | Expr_ite (c, t, e) -> check_expr c && check_expr t && check_expr e
39
  | Expr_arrow _
40
  | Expr_fby _
41
  | Expr_pre _ -> false
42
  | Expr_when (e', i, l)-> check_expr e'
43
  | Expr_merge (i, hl) -> List.for_all (fun (t, h) -> check_expr h) hl 
44
  | Expr_appl (i, e', i') ->
45
    check_expr e' &&
46
      (Basic_library.is_internal_fun i || check_node (node_from_name i))
47
  | Expr_uclock _
48
  | Expr_dclock _
49
  | Expr_phclock _ -> assert false
50
and compute_node nd =
51
 List.for_all (fun eq -> check_expr eq.eq_rhs) nd.node_eqs
52
and check_node td =
53
  match td.top_decl_desc with 
54
  | Node nd         -> (
55
    match nd.node_stateless with
56
    | None     -> 
57
      begin
58
	let stateless = compute_node nd in
59
	nd.node_stateless <- Some stateless;
60
	if nd.node_dec_stateless && (not stateless)
61
	then raise (Error (td.top_decl_loc, Stateful_kwd nd.node_id))
62
	else (nd.node_dec_stateless <- stateless; stateless)
63
      end
64
    | Some stl -> stl)
65
  | ImportedNode nd -> nd.nodei_stateless
66
  | _ -> true
67

  
68
let check_prog decls =
69
  List.iter (fun td -> ignore (check_node td)) decls
70

  
71
let check_compat_decl decl =
72
 match decl.top_decl_desc with
73
 | ImportedNode nd ->
74
   let td = Corelang.node_from_name nd.nodei_id in
75
   (match td.top_decl_desc with
76
   | Node nd' -> let stateless = check_node td in
77
		 if nd.nodei_stateless && (not stateless)
78
		 then raise (Error (td.top_decl_loc, Stateful_imp nd.nodei_id))
79
		 else nd'.node_dec_stateless <- nd.nodei_stateless
80
   | _        -> assert false)
81
 | Node _          -> assert false
82
 | _               -> ()
83

  
84
let check_compat header =
85
  List.iter check_compat_decl header
86

  
87
let pp_error fmt err =
88
  match err with
89
  | Stateful_kwd nd ->
90
    Format.fprintf fmt
91
      "node %s should be stateless but is actually stateful.@."
92
      nd
93
  | Stateful_imp nd ->
94
    Format.fprintf fmt
95
      "node %s is declared stateless but is actually stateful.@."
96
      nd
97

  
98
(* Local Variables: *)
99
(* compile-command:"make -C .." *)
100
(* End: *)

Also available in: Unified diff