@@ -181,6 +181,12 @@ function Base.push!(node::SyntaxNode, child::SyntaxNode)
181181 push! (args, child)
182182end
183183
184+ function build_tree (:: Type{SyntaxNode} , stream:: ParseStream ; filename= nothing , kws... )
185+ green_tree = build_tree (GreenNode, stream; kws... )
186+ source = SourceFile (sourcetext (stream), filename= filename)
187+ SyntaxNode (source, green_tree, first_byte (stream))
188+ end
189+
184190# -------------------------------------------------------------------------------
185191# Tree utilities
186192
@@ -251,193 +257,3 @@ function highlight(code::String, node, path::Int...; color=(40,40,70))
251257 print (stdout , code[q: end ])
252258end
253259
254-
255- # -------------------------------------------------------------------------------
256- # Conversion to Base.Expr
257-
258- function is_eventually_call (ex)
259- return Meta. isexpr (ex, :call ) || (Meta. isexpr (ex, (:where , :(:: ))) &&
260- is_eventually_call (ex. args[1 ]))
261- end
262-
263- function _to_expr (node:: SyntaxNode , iteration_spec= false )
264- if ! haschildren (node)
265- if node. val isa Union{Int128,UInt128,BigInt}
266- # Ignore the values of large integers and convert them back to
267- # symbolic/textural form for compatibility with the Expr
268- # representation of these.
269- str = replace (sourcetext (node), ' _' => " " )
270- headsym = :macrocall
271- k = kind (node)
272- macname = node. val isa Int128 ? Symbol (" @int128_str" ) :
273- node. val isa UInt128 ? Symbol (" @uint128_str" ) :
274- Symbol (" @big_str" )
275- return Expr (:macrocall , GlobalRef (Core, macname), nothing , str)
276- else
277- return node. val
278- end
279- end
280- headstr = untokenize (head (node), include_flag_suff= false )
281- headsym = ! isnothing (headstr) ? Symbol (headstr) :
282- error (" Can't untokenize head of kind $(kind (node)) " )
283- node_args = children (node)
284- args = Vector {Any} (undef, length (node_args))
285- if headsym == :for && length (node_args) == 2
286- args[1 ] = _to_expr (node_args[1 ], true )
287- args[2 ] = _to_expr (node_args[2 ], false )
288- else
289- map! (_to_expr, args, node_args)
290- end
291- # Julia's standard `Expr` ASTs have children stored in a canonical
292- # order which is often not always source order. We permute the children
293- # here as necessary to get the canonical order.
294- if is_infix (node. raw)
295- args[2 ], args[1 ] = args[1 ], args[2 ]
296- end
297- loc = source_location (LineNumberNode, node. source, node. position)
298- # Convert elements
299- if headsym == :macrocall
300- insert! (args, 2 , loc)
301- elseif headsym in (:call , :ref )
302- # Move parameters block to args[2]
303- if length (args) > 1 && Meta. isexpr (args[end ], :parameters )
304- insert! (args, 2 , args[end ])
305- pop! (args)
306- end
307- elseif headsym in (:tuple , :parameters , :vect )
308- # Move parameters blocks to args[1]
309- if length (args) > 1 && Meta. isexpr (args[end ], :parameters )
310- pushfirst! (args, args[end ])
311- pop! (args)
312- end
313- elseif headsym == :try
314- # Try children in source order:
315- # try_block catch_var catch_block else_block finally_block
316- # Expr ordering:
317- # try_block catch_var catch_block [finally_block] [else_block]
318- catch_ = nothing
319- if has_flags (node, TRY_CATCH_AFTER_FINALLY_FLAG)
320- catch_ = pop! (args)
321- catch_var = pop! (args)
322- end
323- finally_ = pop! (args)
324- else_ = pop! (args)
325- if has_flags (node, TRY_CATCH_AFTER_FINALLY_FLAG)
326- pop! (args)
327- pop! (args)
328- push! (args, catch_var)
329- push! (args, catch_)
330- end
331- # At this point args is
332- # [try_block catch_var catch_block]
333- if finally_ != = false
334- push! (args, finally_)
335- end
336- if else_ != = false
337- push! (args, else_)
338- end
339- elseif headsym == :filter
340- pushfirst! (args, last (args))
341- pop! (args)
342- elseif headsym == :flatten
343- # The order of nodes inside the generators in Julia's flatten AST
344- # is noncontiguous in the source text, so need to reconstruct
345- # Julia's AST here from our alternative `flatten` expression.
346- gen = Expr (:generator , args[1 ], args[end ])
347- for i in length (args)- 1 : - 1 : 2
348- gen = Expr (:flatten , Expr (:generator , gen, args[i]))
349- end
350- return gen
351- elseif headsym in (:nrow , :ncat )
352- # For lack of a better place, the dimension argument to nrow/ncat
353- # is stored in the flags
354- pushfirst! (args, numeric_flags (flags (node)))
355- elseif headsym == :typed_ncat
356- insert! (args, 2 , numeric_flags (flags (node)))
357- elseif headsym == :string && length (args) > 1
358- # Julia string literals may be interspersed with trivia in two situations:
359- # 1. Triple quoted string indentation is trivia
360- # 2. An \ before newline removes the newline and any following indentation
361- #
362- # Such trivia is eagerly removed by the reference parser, so here we
363- # concatenate adjacent string chunks together for compatibility.
364- #
365- # TODO : Manage the non-interpolation cases with String and CmdString
366- # kinds instead?
367- args2 = Vector {Any} ()
368- i = 1
369- while i <= length (args)
370- if args[i] isa String && i < length (args) && args[i+ 1 ] isa String
371- buf = IOBuffer ()
372- while i <= length (args) && args[i] isa String
373- write (buf, args[i])
374- i += 1
375- end
376- push! (args2, String (take! (buf)))
377- else
378- push! (args2, args[i])
379- i += 1
380- end
381- end
382- args = args2
383- if length (args2) == 1 && args2[1 ] isa String
384- # If there's a single string remaining after joining we unwrap to
385- # give a string literal.
386- # """\n a\n b""" ==> "a\nb"
387- return args2[1 ]
388- end
389- # elseif headsym == :string && length(args) == 1 && version <= (1,5)
390- # Strip string from interpolations in 1.5 and lower to preserve
391- # "hi$("ho")" ==> (string "hi" "ho")
392- elseif headsym == :(= )
393- if is_eventually_call (args[1 ]) && ! iteration_spec
394- if Meta. isexpr (args[2 ], :block )
395- pushfirst! (args[2 ]. args, loc)
396- else
397- # Add block for short form function locations
398- args[2 ] = Expr (:block , loc, args[2 ])
399- end
400- end
401- elseif headsym == :(-> )
402- if Meta. isexpr (args[2 ], :block )
403- pushfirst! (args[2 ]. args, loc)
404- else
405- # Add block for source locations
406- args[2 ] = Expr (:block , loc, args[2 ])
407- end
408- elseif headsym == :function
409- if length (args) > 1 && Meta. isexpr (args[1 ], :tuple )
410- # Convert to weird Expr forms for long-form anonymous functions.
411- #
412- # (function (tuple (... xs)) body) ==> (function (... xs) body)
413- if length (args[1 ]. args) == 1 && Meta. isexpr (args[1 ]. args[1 ], :... )
414- # function (xs...) \n body end
415- args[1 ] = args[1 ]. args[1 ]
416- end
417- end
418- end
419- if headsym == :inert || (headsym == :quote && length (args) == 1 &&
420- ! (a1 = only (args); a1 isa Expr || a1 isa QuoteNode ||
421- a1 isa Bool # <- compat hack, Julia 1.4+
422- ))
423- return QuoteNode (only (args))
424- else
425- return Expr (headsym, args... )
426- end
427- end
428-
429- Base. Expr (node:: SyntaxNode ) = _to_expr (node)
430-
431-
432- # -------------------------------------------------------------------------------
433-
434- function build_tree (:: Type{SyntaxNode} , stream:: ParseStream ; filename= nothing , kws... )
435- green_tree = build_tree (GreenNode, stream; kws... )
436- source = SourceFile (sourcetext (stream), filename= filename)
437- SyntaxNode (source, green_tree, first_byte (stream))
438- end
439-
440- function build_tree (:: Type{Expr} , stream:: ParseStream ; kws... )
441- Expr (build_tree (SyntaxNode, stream; kws... ))
442- end
443-
0 commit comments