File: comment_annotater_c.ml

package info (click to toggle)
coccinelle 1.0.8.deb-5
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 26,148 kB
  • sloc: ml: 136,392; ansic: 23,594; sh: 2,189; makefile: 2,157; perl: 1,576; lisp: 840; python: 823; awk: 70; csh: 12
file content (138 lines) | stat: -rw-r--r-- 4,645 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
(* Yoann Padioleau
 *
 * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
 * Copyright (C) 2009, University of Urbana Champaign.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License (GPL)
 * version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * file license.txt for more details.
 *)

open Common

module T = Token_c


(*****************************************************************************)
(* Prelude *)
(*****************************************************************************)

(* A trimmed down version of my comment_annotater of CComment. In CComment
 * I was also trying to associate the comment to the relevant entity, not
 * just the closest token (e.g. a function comment is not placed next to the
 * identifier of the function but before its return type or storage).
 *)


(*****************************************************************************)
(* Helpers *)
(*****************************************************************************)

let is_comment_or_space_or_stuff tok =
  Token_helpers.is_not_in_ast tok && Token_helpers.is_origin tok

(* coupling with token_helpers.is_not_in_ast, and of course with tokens_c.ml *)
let convert_relevant_tokens x =
  assert (Token_helpers.is_origin x);

  match x with
  | Parser_c.TCommentSpace info ->
      Token_c.TCommentSpace, (Ast_c.parse_info_of_info info)
  | Parser_c.TCommentNewline info ->
      Token_c.TCommentNewline, (Ast_c.parse_info_of_info info)

  | Parser_c.TComment info ->
      Token_c.TComment, (Ast_c.parse_info_of_info info)

  (* the passed tokens because of our limited handling of cpp *)
  | Parser_c.TCommentCpp(cppcommentkind, info) ->
      Token_c.TCommentCpp cppcommentkind, (Ast_c.parse_info_of_info info)

  | _ -> raise (Impossible 61)


(*****************************************************************************)
(* Main entry *)
(*****************************************************************************)

(* right now we just add comment-like and origin-tok tokens,
 * as explained in token_c.ml.
 *
 * This simplified comment_annotater (compared to CComment) is really
 * simple as the tokens and the Ast_c.info in the asts actually share
 * the same refs.
 * So, modifying fields in the tokens will also modify the info in
 * the ast. Sometimes side effects simplify programming ...
 * We use similar tricks in unparse_c.ml. So really the asts argument
 * is not needed.
 *
 * ex: C1 C2 T1 T2 C3 C4 T3 C5 T4.
 *  => infoT1(-C1C2,+), infoT2(-,+C3C4), infoT3(-C3C4,+C5), infoT4(-C5,+)
 *)

(*
let (agglomerate_either:
 ('a, 'a) Common.either list -> ('a list, 'a list) Common.either list) = fun xs ->
  raise Todo

let (span_and_pack:
 ('a -> ('a, 'a) Common.either) -> 'a list ->
      ('a list, 'a list) Common.either list) = fun f_either xs ->
  let xs' = List.map f_either xs in
  agglomerate_either xs'
*)


(* the asts is not really used, we do all via side effect on the tokens,
 * which share the info reference with the elements in the ast.
 *)
let annotate_program toks asts =
   (* Common.exclude_but_keep_attached gather all comments before a
    * token and then associates to this token those comments. Note that
    * if reverse the list of tokens then this function can also be used
    * to gather all the comments after a token :)
    *)

   (* before phase *)
   let toks_with_before =
     Common.exclude_but_keep_attached is_comment_or_space_or_stuff
       toks
   in

  (* after phase. trick: reverse the tokens and reuse previous func *)
   let toks_with_after =
     List.fold_left (* comes out reversed *)
       (function prev -> function (x,l) -> (x,List.rev l) :: prev) []
       (Common.exclude_but_keep_attached is_comment_or_space_or_stuff
          (List.rev toks))
   in

  (* merge *)
   assert(List.length toks_with_after = List.length toks_with_before);

  List.iter2 (fun (t1, before) (t2, after) ->

    assert(t1 = t2);

    let before' = before +> List.map convert_relevant_tokens in
    let after' = after  +> List.map convert_relevant_tokens in

    let info = Token_helpers.info_of_tok t1 in
    info.Ast_c.comments_tag :=
      { Ast_c.mbefore = before';
        Ast_c.mafter = after';
        mbefore2 = [];
        mafter2 = [];
      };

    )
    toks_with_before toks_with_after;
   (* modified via side effect. I return it just to have a
    * clean signature.
    *)
   asts