Multiply entities beyond necessity even more (force better build parallelism)
[hiphop-php.git] / hphp / hack / src / parser / full_fidelity_editable_syntax.ml
blob351227654a6b30cbc71e74aad337ab3ba8fa4eab
1 (*
2 * Copyright (c) 2016, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 (** Editable syntax tree
12 * Every token and trivia in the tree knows its text. Therefore we can add
13 * new nodes without having to back them with a source text.
16 module Token = Full_fidelity_editable_token
17 module Trivia = Full_fidelity_editable_trivia
18 module SyntaxKind = Full_fidelity_syntax_kind
19 module TokenKind = Full_fidelity_token_kind
20 module SyntaxWithToken = Full_fidelity_syntax.WithToken (Token)
22 (**
23 * Ironically, an editable syntax tree needs even less per-node information
24 * than the "positioned" syntax tree, which needs to know the width of the node.
25 **)
27 module Value = struct
28 type t = NoValue [@@deriving show]
30 let to_json _value = Hh_json.(JSON_Object [])
31 end
33 module EditableSyntax = SyntaxWithToken.WithSyntaxValue (Value)
35 module EditableValueBuilder = struct
36 let value_from_children _ _ _ _ = Value.NoValue
38 let value_from_token _ = Value.NoValue
40 let value_from_syntax _ = Value.NoValue
41 end
43 include EditableSyntax
44 include EditableSyntax.WithValueBuilder (EditableValueBuilder)
46 let text node =
47 let buffer = Buffer.create 100 in
48 let aux token = Buffer.add_string buffer (Token.full_text token) in
49 List.iter aux (all_tokens node);
50 Buffer.contents buffer
52 let extract_text node = Some (text node)
54 let width node = String.length (text node)
56 (* Takes a node and an offset; produces the descent through the parse tree
57 to that position. *)
58 let parentage root position =
59 let rec aux nodes position acc =
60 match nodes with
61 | [] -> acc
62 | h :: t ->
63 let width = String.length @@ text h in
64 if position < width then
65 aux (children h) position (h :: acc)
66 else
67 aux t (position - width) acc
69 aux [root] position []
71 let leading_trivia node =
72 let token = leading_token node in
73 match token with
74 | None -> []
75 | Some t -> Token.leading t
77 let leading_width node =
78 leading_trivia node |> List.fold_left (fun sum t -> sum + Trivia.width t) 0
80 let trailing_trivia node =
81 let token = trailing_token node in
82 match token with
83 | None -> []
84 | Some t -> Token.trailing t
86 let trailing_width node =
87 trailing_trivia node |> List.fold_left (fun sum t -> sum + Trivia.width t) 0
89 let full_width node = leading_width node + width node + trailing_width node
91 let is_in_body node position =
92 let rec aux = function
93 | [] -> false
94 | h1 :: t1 when not (is_compound_statement h1) -> aux t1
95 | [_h1] -> false
96 | _h1 :: (h2 :: _ as t1) ->
97 is_methodish_declaration h2 || is_function_declaration h2 || aux t1
99 aux (parentage node position)
101 (* This function takes a parse tree and renders it in the GraphViz DOT
102 language; this is a small domain-specific language for visualizing graphs.
103 You can use www.webgraphviz.com to render it in a browser, or the "dot"
104 command line tool to turn DOT text into image files.
106 Edge labels can make the graph hard to read, so they can be enabled or
107 disabled as you like.
109 Use hh_parse --full-fidelity-dot or --full-fidelity-dot-edges to parse
110 a Hack file and display it in DOT form.
112 TODO: There's nothing here that's unique to editable trees; this could
113 be auto-generated as part of full_fidelity_syntax.ml.
115 let to_dot node with_labels =
116 (* returns new current_id, accumulator *)
117 let rec aux node current_id parent_id edge_label acc =
118 let kind = SyntaxKind.to_string (kind node) in
119 let new_id = current_id + 1 in
120 let label =
121 if with_labels then
122 Printf.sprintf " [label=\"%s\"]" edge_label
123 else
126 let new_edge = Printf.sprintf " %d -> %d%s" parent_id current_id label in
127 match node.syntax with
128 | Token t ->
129 (* TODO: Trivia *)
130 let kind = TokenKind.to_string (Token.kind t) in
131 let new_node = Printf.sprintf " %d [label=\"%s\"];" current_id kind in
132 let new_acc = new_edge :: new_node :: acc in
133 (new_id, new_acc)
134 | SyntaxList x ->
135 let new_node = Printf.sprintf " %d [label=\"%s\"];" current_id kind in
136 let new_acc = new_edge :: new_node :: acc in
137 let folder (c, a) n = aux n c current_id "" a in
138 List.fold_left folder (new_id, new_acc) x
139 | _ ->
140 let folder (c, a) n l = aux n c current_id l a in
141 let new_node = Printf.sprintf " %d [label=\"%s\"];" current_id kind in
142 let new_acc = new_edge :: new_node :: acc in
143 List.fold_left2
144 folder
145 (new_id, new_acc)
146 (children node)
147 (children_names node)
149 let (_, acc) =
150 aux node 1001 1000 "" [" 1000 [label=\"root\"]"; "digraph {"]
152 let acc = "}" :: acc in
153 String.concat "\n" (List.rev acc)
155 let offset _ = None
157 let position _ _ = None
159 let to_json ?with_value:_ node =
160 let version = Full_fidelity_schema.full_fidelity_schema_version_number in
161 let tree = EditableSyntax.to_json node in
162 Hh_json.JSON_Object
163 [("parse_tree", tree); ("version", Hh_json.JSON_String version)]
165 let rust_parse _ _ = failwith "not implemented"
167 let rust_parse_with_coroutine_sc _ _ = failwith "not implemented"
169 let rust_parse_with_decl_mode_sc _ _ = failwith "not implemented"
171 let rust_parse_with_verify_sc _ _ = failwith "not implemented"
173 let rust_parser_errors _ _ _ = failwith "not implemented"