@@ -181,6 +181,12 @@ function Base.push!(node::SyntaxNode, child::SyntaxNode)
181
181
push! (args, child)
182
182
end
183
183
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
+
184
190
# -------------------------------------------------------------------------------
185
191
# Tree utilities
186
192
@@ -251,193 +257,3 @@ function highlight(code::String, node, path::Int...; color=(40,40,70))
251
257
print (stdout , code[q: end ])
252
258
end
253
259
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