yarp 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -0
- data/CONTRIBUTING.md +4 -0
- data/{Makefile.in → Makefile} +5 -4
- data/README.md +6 -3
- data/config.yml +83 -274
- data/docs/build_system.md +4 -15
- data/docs/building.md +1 -5
- data/docs/encoding.md +1 -0
- data/docs/{extension.md → ruby_api.md} +6 -3
- data/docs/serialization.md +71 -24
- data/ext/yarp/api_node.c +173 -585
- data/ext/yarp/extconf.rb +15 -10
- data/ext/yarp/extension.c +4 -2
- data/ext/yarp/extension.h +1 -1
- data/include/yarp/ast.h +167 -306
- data/include/yarp/defines.h +5 -15
- data/include/yarp/enc/yp_encoding.h +1 -0
- data/include/yarp/unescape.h +1 -1
- data/include/yarp/util/yp_buffer.h +9 -0
- data/include/yarp/util/yp_constant_pool.h +3 -0
- data/include/yarp/util/yp_list.h +7 -7
- data/include/yarp/util/yp_newline_list.h +4 -0
- data/include/yarp/util/yp_state_stack.h +1 -1
- data/include/yarp/util/yp_string.h +5 -1
- data/include/yarp/version.h +2 -3
- data/include/yarp.h +4 -2
- data/lib/yarp/ffi.rb +226 -0
- data/lib/yarp/lex_compat.rb +16 -2
- data/lib/yarp/node.rb +594 -1437
- data/lib/yarp/ripper_compat.rb +3 -3
- data/lib/yarp/serialize.rb +312 -149
- data/lib/yarp.rb +167 -2
- data/src/enc/yp_unicode.c +9 -0
- data/src/node.c +92 -250
- data/src/prettyprint.c +81 -206
- data/src/serialize.c +124 -149
- data/src/unescape.c +29 -35
- data/src/util/yp_buffer.c +18 -0
- data/src/util/yp_list.c +7 -16
- data/src/util/yp_state_stack.c +0 -6
- data/src/util/yp_string.c +8 -17
- data/src/yarp.c +444 -717
- data/yarp.gemspec +5 -5
- metadata +6 -6
- data/config.h.in +0 -25
- data/configure +0 -4487
data/lib/yarp.rb
CHANGED
@@ -7,7 +7,7 @@ module YARP
|
|
7
7
|
class Source
|
8
8
|
attr_reader :source, :offsets
|
9
9
|
|
10
|
-
def initialize(source, offsets)
|
10
|
+
def initialize(source, offsets = compute_offsets(source))
|
11
11
|
@source = source
|
12
12
|
@offsets = offsets
|
13
13
|
end
|
@@ -23,6 +23,14 @@ module YARP
|
|
23
23
|
def column(value)
|
24
24
|
value - offsets[line(value) - 1]
|
25
25
|
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def compute_offsets(code)
|
30
|
+
offsets = [0]
|
31
|
+
code.b.scan("\n") { offsets << $~.end(0) }
|
32
|
+
offsets
|
33
|
+
end
|
26
34
|
end
|
27
35
|
|
28
36
|
# This represents a location in the source.
|
@@ -101,6 +109,8 @@ module YARP
|
|
101
109
|
|
102
110
|
# This represents a comment that was encountered during parsing.
|
103
111
|
class Comment
|
112
|
+
TYPES = [:inline, :embdoc, :__END__]
|
113
|
+
|
104
114
|
attr_reader :type, :location
|
105
115
|
|
106
116
|
def initialize(type, location)
|
@@ -279,6 +289,11 @@ module YARP
|
|
279
289
|
end
|
280
290
|
end
|
281
291
|
|
292
|
+
# Slice the location of the node from the source.
|
293
|
+
def slice
|
294
|
+
location.slice
|
295
|
+
end
|
296
|
+
|
282
297
|
def pretty_print(q)
|
283
298
|
q.group do
|
284
299
|
q.text(self.class.name.split("::").last)
|
@@ -306,6 +321,152 @@ module YARP
|
|
306
321
|
# This module is used for testing and debugging and is not meant to be used by
|
307
322
|
# consumers of this library.
|
308
323
|
module Debug
|
324
|
+
class ISeq
|
325
|
+
attr_reader :parts
|
326
|
+
|
327
|
+
def initialize(parts)
|
328
|
+
@parts = parts
|
329
|
+
end
|
330
|
+
|
331
|
+
def type
|
332
|
+
parts[0]
|
333
|
+
end
|
334
|
+
|
335
|
+
def local_table
|
336
|
+
parts[10]
|
337
|
+
end
|
338
|
+
|
339
|
+
def instructions
|
340
|
+
parts[13]
|
341
|
+
end
|
342
|
+
|
343
|
+
def each_child
|
344
|
+
instructions.each do |instruction|
|
345
|
+
# Only look at arrays. Other instructions are line numbers or
|
346
|
+
# tracepoint events.
|
347
|
+
next unless instruction.is_a?(Array)
|
348
|
+
|
349
|
+
instruction.each do |opnd|
|
350
|
+
# Only look at arrays. Other operands are literals.
|
351
|
+
next unless opnd.is_a?(Array)
|
352
|
+
|
353
|
+
# Only look at instruction sequences. Other operands are literals.
|
354
|
+
next unless opnd[0] == "YARVInstructionSequence/SimpleDataFormat"
|
355
|
+
|
356
|
+
yield ISeq.new(opnd)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
# For the given source, compiles with CRuby and returns a list of all of the
|
363
|
+
# sets of local variables that were encountered.
|
364
|
+
def self.cruby_locals(source)
|
365
|
+
verbose = $VERBOSE
|
366
|
+
$VERBOSE = nil
|
367
|
+
|
368
|
+
begin
|
369
|
+
locals = []
|
370
|
+
stack = [ISeq.new(RubyVM::InstructionSequence.compile(source).to_a)]
|
371
|
+
|
372
|
+
while (iseq = stack.pop)
|
373
|
+
if iseq.type != :once
|
374
|
+
names = iseq.local_table
|
375
|
+
|
376
|
+
# CRuby will push on a special local variable when there are keyword
|
377
|
+
# arguments. We get rid of that here.
|
378
|
+
names = names.grep_v(Integer)
|
379
|
+
|
380
|
+
# TODO: We don't support numbered local variables yet, so we get rid
|
381
|
+
# of those here.
|
382
|
+
names = names.grep_v(/^_\d$/)
|
383
|
+
|
384
|
+
# For some reason, CRuby occasionally pushes this special local
|
385
|
+
# variable when there are splat arguments. We get rid of that here.
|
386
|
+
names = names.grep_v(:"#arg_rest")
|
387
|
+
|
388
|
+
# Now push them onto the list of locals.
|
389
|
+
locals << names
|
390
|
+
end
|
391
|
+
|
392
|
+
iseq.each_child { |child| stack << child }
|
393
|
+
end
|
394
|
+
|
395
|
+
locals
|
396
|
+
ensure
|
397
|
+
$VERBOSE = verbose
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
# For the given source, parses with YARP and returns a list of all of the
|
402
|
+
# sets of local variables that were encountered.
|
403
|
+
def self.yarp_locals(source)
|
404
|
+
locals = []
|
405
|
+
stack = [YARP.parse(source).value]
|
406
|
+
|
407
|
+
while (node = stack.pop)
|
408
|
+
case node
|
409
|
+
when BlockNode, DefNode, LambdaNode
|
410
|
+
names = node.locals
|
411
|
+
|
412
|
+
params = node.parameters
|
413
|
+
params = params&.parameters unless node.is_a?(DefNode)
|
414
|
+
|
415
|
+
# YARP places parameters in the same order that they appear in the
|
416
|
+
# source. CRuby places them in the order that they need to appear
|
417
|
+
# according to their own internal calling convention. We mimic that
|
418
|
+
# order here so that we can compare properly.
|
419
|
+
if params
|
420
|
+
sorted = [
|
421
|
+
*params.requireds.grep(RequiredParameterNode).map(&:constant_id),
|
422
|
+
*params.optionals.map(&:constant_id),
|
423
|
+
*((params.rest.name ? params.rest.name.to_sym : :*) if params.rest && params.rest.operator != ","),
|
424
|
+
*params.posts.grep(RequiredParameterNode).map(&:constant_id),
|
425
|
+
*params.keywords.reject(&:value).map { |param| param.name.chomp(":").to_sym },
|
426
|
+
*params.keywords.select(&:value).map { |param| param.name.chomp(":").to_sym }
|
427
|
+
]
|
428
|
+
|
429
|
+
# TODO: When we get a ... parameter, we should be pushing * and &
|
430
|
+
# onto the local list. We don't do that yet, so we need to add them
|
431
|
+
# in here.
|
432
|
+
if params.keyword_rest.is_a?(ForwardingParameterNode)
|
433
|
+
sorted.push(:*, :&, :"...")
|
434
|
+
end
|
435
|
+
|
436
|
+
# Recurse down the parameter tree to find any destructured
|
437
|
+
# parameters and add them after the other parameters.
|
438
|
+
param_stack = params.requireds.concat(params.posts).grep(RequiredDestructuredParameterNode).reverse
|
439
|
+
while (param = param_stack.pop)
|
440
|
+
case param
|
441
|
+
when RequiredDestructuredParameterNode
|
442
|
+
param_stack.concat(param.parameters.reverse)
|
443
|
+
when RequiredParameterNode
|
444
|
+
sorted << param.constant_id
|
445
|
+
when SplatNode
|
446
|
+
sorted << param.expression.constant_id if param.expression
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
names = sorted.concat(names - sorted)
|
451
|
+
end
|
452
|
+
|
453
|
+
locals << names
|
454
|
+
when ClassNode, ModuleNode, ProgramNode, SingletonClassNode
|
455
|
+
locals << node.locals
|
456
|
+
when ForNode
|
457
|
+
locals << []
|
458
|
+
when PostExecutionNode
|
459
|
+
locals.push([], [])
|
460
|
+
when InterpolatedRegularExpressionNode
|
461
|
+
locals << [] if node.once?
|
462
|
+
end
|
463
|
+
|
464
|
+
stack.concat(node.child_nodes.compact)
|
465
|
+
end
|
466
|
+
|
467
|
+
locals
|
468
|
+
end
|
469
|
+
|
309
470
|
def self.newlines(source)
|
310
471
|
YARP.parse(source).source.offsets
|
311
472
|
end
|
@@ -327,4 +488,8 @@ require_relative "yarp/ripper_compat"
|
|
327
488
|
require_relative "yarp/serialize"
|
328
489
|
require_relative "yarp/pack"
|
329
490
|
|
330
|
-
|
491
|
+
if RUBY_ENGINE == "ruby" and !ENV["YARP_FFI_BACKEND"]
|
492
|
+
require "yarp/yarp"
|
493
|
+
else
|
494
|
+
require "yarp/ffi"
|
495
|
+
end
|
data/src/enc/yp_unicode.c
CHANGED
@@ -2318,3 +2318,12 @@ yp_encoding_t yp_encoding_utf_8 = {
|
|
2318
2318
|
.isupper_char = yp_encoding_utf_8_isupper_char,
|
2319
2319
|
.multibyte = true
|
2320
2320
|
};
|
2321
|
+
|
2322
|
+
yp_encoding_t yp_encoding_utf8_mac = {
|
2323
|
+
.name = "utf8-mac",
|
2324
|
+
.char_width = yp_encoding_utf_8_char_width,
|
2325
|
+
.alnum_char = yp_encoding_utf_8_alnum_char,
|
2326
|
+
.alpha_char = yp_encoding_utf_8_alpha_char,
|
2327
|
+
.isupper_char = yp_encoding_utf_8_isupper_char,
|
2328
|
+
.multibyte = true
|
2329
|
+
};
|