2 * Copyright (c) 2016, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
10 (** Typed and positioned syntax tree
12 * A positioned tree which may know information about the type of the node.
14 * Types come from the typed ast.
15 * type annotations are available on all:
22 * TODO: Enable type annotations on:
23 * - tast hints (aka type annotations):
24 * - hint -> ty: Decl_hint.hint, Decl_env
27 * - explicit type args on call
31 * - tparam constraints
42 module SourceText
= Full_fidelity_positioned_syntax.SourceText
43 module Token
= Full_fidelity_positioned_token
44 module Trivia
= Full_fidelity_positioned_trivia
45 module SyntaxKind
= Full_fidelity_syntax_kind
46 module TokenKind
= Full_fidelity_token_kind
47 module SyntaxWithToken
= Full_fidelity_syntax.WithToken
(Token
)
51 Converts from full fidelity positions (which use a different indexing scheme
52 from typed ast positions) to json where:
53 - all indexes are 0 based
54 - start columns are inclusive
55 - end columns are exclusive
57 let pos_to_zero_indexed_json t
=
58 let line_start, char_start
, line_end
, char_end
= Pos.destruct_range t
in
59 let fn = Pos.filename t
in
61 "filename", Hh_json.JSON_String
fn;
62 "start", Hh_json.JSON_Object
[
63 "line", Hh_json.int_
(line_start - 1);
64 "column", Hh_json.int_
(char_start
- 1)
66 "end", Hh_json.JSON_Object
[
67 "line", Hh_json.int_
(line_end
- 1);
68 "column", Hh_json.int_ char_end
73 (* placeholder definitions *)
74 type absolute
= Pos.absolute
75 let show_absolute _
= "<absolute>"
76 let pp_absolute _ _
= Printf.printf
"%s\n" "<asbolute>"
79 source_text
: SourceText.t
;
80 offset
: int; (* Beginning of first trivia *)
82 width
: int; (* Width of node, not counting trivia *)
84 tys
: Tast_type_collector.collected_type list
;
89 SourceText.relative_pos
90 (SourceText.file_path
value.source_text
)
91 value.source_text
value.offset
92 (value.offset
+ value.width
)
97 (["position", pos_to_zero_indexed_json value.position
98 ] @ match value.tys
with
101 let json_tys = Tast_type_collector.collected_types_to_json tys
in
102 [("types", JSON_Array
json_tys)])
105 module PositionedSyntaxValue
= Full_fidelity_positioned_syntax.PositionedSyntaxValue
107 let positioned_value_to_typed
108 (position: Pos.absolute
)
109 (types
: Tast_type_collector.collected_type list
)
110 (value: PositionedSyntaxValue.t
): Value.t
=
112 Value.source_text
= PositionedSyntaxValue.source_text
value;
113 offset
= PositionedSyntaxValue.start_offset
value;
114 leading_width
= PositionedSyntaxValue.leading_width
value;
115 width
= PositionedSyntaxValue.width
value;
116 trailing_width
= PositionedSyntaxValue.trailing_width
value;
121 module TypedSyntax
= SyntaxWithToken.WithSyntaxValue
(Value
)
123 module TypedValueBuilder
= struct
124 let value_from_children _ _ _ _
=
127 let value_from_token _
=
130 let value_from_syntax _
=
135 include TypedSyntax.WithValueBuilder
(TypedValueBuilder
)
138 let source_text node
=
139 (value node
).Value.source_text
141 let leading_width node
=
142 (value node
).Value.leading_width
145 (value node
).Value.width
147 let trailing_width node
=
148 (value node
).Value.trailing_width
150 let full_width node
=
151 (leading_width node
) + (width node
) + (trailing_width node
)
153 let leading_start_offset node
=
154 (value node
).Value.offset
156 let leading_end_offset node
=
157 let w = (leading_width node
) - 1 in
158 let w = if w < 0 then 0 else w in
159 (leading_start_offset node
) + w
161 let start_offset node
=
162 (leading_start_offset node
) + (leading_width node
)
164 let end_offset node
=
165 let w = (width node
) - 1 in
166 let w = if w < 0 then 0 else w in
167 (start_offset node
) + w
169 let trailing_start_offset node
=
170 (leading_start_offset node
) + (leading_width node
) + (width node
)
172 let trailing_end_offset node
=
173 let w = (full_width node
) - 1 in
174 let w = if w < 0 then 0 else w in
175 (leading_start_offset node
) + w
177 let leading_start_position node
=
178 SourceText.offset_to_position
(source_text node
) (leading_start_offset node
)
180 let leading_end_position node
=
181 SourceText.offset_to_position
(source_text node
) (leading_end_offset node
)
183 let start_position node
=
184 SourceText.offset_to_position
(source_text node
) (start_offset node
)
186 let end_position node
=
187 SourceText.offset_to_position
(source_text node
) (end_offset node
)
189 let trailing_start_position node
=
190 SourceText.offset_to_position
(source_text node
) (trailing_start_offset node
)
192 let trailing_end_position node
=
193 SourceText.offset_to_position
(source_text node
) (trailing_end_offset node
)
195 let leading_span node
=
196 ((leading_start_position node
), (leading_end_position node
))
199 ((start_position node
), (end_position node
))
201 let trailing_span node
=
202 ((trailing_start_position node
), (trailing_end_position node
))
205 ((leading_start_position node
), (trailing_end_position node
))
209 (source_text node
) (leading_start_offset node
) (full_width node
)
211 let leading_text node
=
214 (leading_start_offset node
)
217 let trailing_text node
=
219 (source_text node
) ((end_offset node
) + 1) (trailing_width node
)
222 SourceText.sub
(source_text node
) (start_offset node
) (width node
)
224 let extract_text node
=
227 (* Takes a node and an offset; produces the descent through the parse tree
229 let parentage node
position =
230 let rec aux nodes
position acc
=
234 let width = full_width h
in
235 if position < width then
236 aux (children h
) position (h
:: acc
)
238 aux t
(position - width) acc
in
239 aux [node
] position []
241 let is_in_body node
position =
242 let rec aux parents
=
246 if is_compound_statement h1
then
250 is_methodish_declaration h2
|| is_function_declaration h2
|| aux t1
253 let parents = parentage node
position in
256 let position (_file
: Relative_path.t
) (node
: t
) =
257 Some
(Value.position node
.value)
259 let offset node
= Some
(start_offset node
)