kapusta 0.1.0 → 0.1.2
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/README.md +10 -2
- data/examples/accumulator.kap +1 -1
- data/examples/anagram.kap +3 -3
- data/examples/binary-search.kap +2 -2
- data/examples/block-sort.kap +1 -1
- data/examples/blocks-and-kwargs.kap +20 -0
- data/examples/calc.kap +1 -1
- data/examples/counter.kap +1 -1
- data/examples/doto.kap +1 -1
- data/examples/even-squares.kap +1 -1
- data/examples/exceptions.kap +2 -2
- data/examples/files.kap +13 -0
- data/examples/greet.kap +1 -1
- data/examples/inheritance.kap +13 -0
- data/examples/kwargs.kap +1 -1
- data/examples/match.kap +3 -3
- data/examples/module-header.kap +2 -1
- data/examples/palindrome.kap +3 -3
- data/examples/pangram.kap +2 -2
- data/examples/pcall.kap +6 -6
- data/examples/pipeline.kap +4 -1
- data/examples/points.kap +1 -1
- data/examples/record.kap +1 -1
- data/examples/regex.kap +3 -1
- data/examples/ruby-eval.kap +1 -1
- data/examples/safe-lookup.kap +2 -2
- data/examples/scopes.kap +4 -4
- data/examples/threading.kap +28 -0
- data/examples/tset.kap +2 -2
- data/examples/two-sum.kap +3 -3
- data/kapusta.gemspec +4 -0
- data/lib/kapusta/ast.rb +16 -4
- data/lib/kapusta/cli.rb +8 -2
- data/lib/kapusta/compiler/runtime.rb +26 -247
- data/lib/kapusta/formatter.rb +262 -110
- data/lib/kapusta/reader.rb +51 -24
- data/lib/kapusta/version.rb +1 -1
- data/spec/cli_spec.rb +15 -0
- data/spec/examples_spec.rb +25 -0
- data/spec/formatter_spec.rb +114 -5
- metadata +9 -2
|
@@ -63,12 +63,29 @@ module Kapusta
|
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
RUBY
|
|
66
|
-
stringify: <<~RUBY.chomp,
|
|
66
|
+
stringify: <<~'RUBY'.chomp,
|
|
67
67
|
def __kap_stringify(value)
|
|
68
|
+
render = nil
|
|
69
|
+
render = lambda do |item|
|
|
70
|
+
case item
|
|
71
|
+
when nil then 'nil'
|
|
72
|
+
when true then 'true'
|
|
73
|
+
when false then 'false'
|
|
74
|
+
when String, Symbol then item.inspect
|
|
75
|
+
when Array
|
|
76
|
+
"[#{item.map { |child| render.call(child) }.join(', ')}]"
|
|
77
|
+
when Hash
|
|
78
|
+
"{#{item.map { |key, child| "#{render.call(key)}=>#{render.call(child)}" }.join(', ')}}"
|
|
79
|
+
else
|
|
80
|
+
item.inspect
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
68
84
|
case value
|
|
69
85
|
when nil then 'nil'
|
|
70
86
|
when true then 'true'
|
|
71
87
|
when false then 'false'
|
|
88
|
+
when Array, Hash then render.call(value)
|
|
72
89
|
else value.to_s
|
|
73
90
|
end
|
|
74
91
|
end
|
|
@@ -327,257 +344,19 @@ module Kapusta
|
|
|
327
344
|
seen[name] = true
|
|
328
345
|
end
|
|
329
346
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
if block
|
|
334
|
-
kwargs ? callee.call(*positional, **kwargs, &block) : callee.call(*positional, &block)
|
|
335
|
-
else
|
|
336
|
-
kwargs ? callee.call(*positional, **kwargs) : callee.call(*positional)
|
|
337
|
-
end
|
|
338
|
-
end
|
|
339
|
-
|
|
340
|
-
def send_call(receiver, method_name, positional, kwargs = nil, block = nil)
|
|
341
|
-
if block
|
|
342
|
-
if kwargs
|
|
343
|
-
receiver.public_send(method_name, *positional, **kwargs,
|
|
344
|
-
&block)
|
|
345
|
-
else
|
|
346
|
-
receiver.public_send(method_name, *positional, &block)
|
|
347
|
-
end
|
|
348
|
-
elsif kwargs
|
|
349
|
-
receiver.public_send(method_name, *positional,
|
|
350
|
-
**kwargs)
|
|
351
|
-
else
|
|
352
|
-
receiver.public_send(method_name, *positional)
|
|
353
|
-
end
|
|
354
|
-
end
|
|
355
|
-
|
|
356
|
-
def invoke_self(receiver, method_name, positional, kwargs = nil, block = nil)
|
|
357
|
-
if block
|
|
358
|
-
if kwargs
|
|
359
|
-
receiver.send(method_name, *positional, **kwargs,
|
|
360
|
-
&block)
|
|
361
|
-
else
|
|
362
|
-
receiver.send(method_name, *positional, &block)
|
|
363
|
-
end
|
|
364
|
-
else
|
|
365
|
-
kwargs ? receiver.send(method_name, *positional, **kwargs) : receiver.send(method_name, *positional)
|
|
366
|
-
end
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
def stringify(value)
|
|
370
|
-
case value
|
|
371
|
-
when nil then 'nil'
|
|
372
|
-
when true then 'true'
|
|
373
|
-
when false then 'false'
|
|
374
|
-
else value.to_s
|
|
375
|
-
end
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
def print_values(*values)
|
|
379
|
-
$stdout.puts(values.map { |value| stringify(value) }.join("\t"))
|
|
380
|
-
nil
|
|
381
|
-
end
|
|
382
|
-
|
|
383
|
-
def concat(values)
|
|
384
|
-
values.map { |value| stringify(value) }.join
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
def get_path(obj, keys)
|
|
388
|
-
keys.reduce(obj) { |acc, key| acc[key] }
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
def qget_path(obj, keys)
|
|
392
|
-
keys.each do |key|
|
|
393
|
-
return nil if obj.nil?
|
|
394
|
-
|
|
395
|
-
obj = obj[key]
|
|
396
|
-
end
|
|
397
|
-
obj
|
|
398
|
-
end
|
|
399
|
-
|
|
400
|
-
def set_path(obj, keys, value)
|
|
401
|
-
target = obj
|
|
402
|
-
keys[0...-1].each { |key| target = target[key] }
|
|
403
|
-
target[keys.last] = value
|
|
404
|
-
end
|
|
405
|
-
|
|
406
|
-
def method_path_value(base, segments)
|
|
407
|
-
segments.reduce(base) { |obj, segment| obj.public_send(Kapusta.kebab_to_snake(segment).to_sym) }
|
|
408
|
-
end
|
|
409
|
-
|
|
410
|
-
def set_method_path(base, segments, value)
|
|
411
|
-
target = base
|
|
412
|
-
segments[0...-1].each do |segment|
|
|
413
|
-
target = target.public_send(Kapusta.kebab_to_snake(segment).to_sym)
|
|
414
|
-
end
|
|
415
|
-
setter = "#{Kapusta.kebab_to_snake(segments.last)}="
|
|
416
|
-
target.public_send(setter.to_sym, value)
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
def current_class_scope(receiver)
|
|
420
|
-
receiver.is_a?(Module) ? receiver : receiver.class
|
|
421
|
-
end
|
|
422
|
-
|
|
423
|
-
def get_ivar(receiver, name)
|
|
424
|
-
receiver.instance_variable_get("@#{Kapusta.kebab_to_snake(name)}")
|
|
425
|
-
end
|
|
426
|
-
|
|
427
|
-
def set_ivar(receiver, name, value)
|
|
428
|
-
receiver.instance_variable_set("@#{Kapusta.kebab_to_snake(name)}", value)
|
|
429
|
-
end
|
|
430
|
-
|
|
431
|
-
def get_cvar(receiver, name)
|
|
432
|
-
current_class_scope(receiver).class_variable_get("@@#{Kapusta.kebab_to_snake(name)}")
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
def set_cvar(receiver, name, value)
|
|
436
|
-
current_class_scope(receiver).class_variable_set("@@#{Kapusta.kebab_to_snake(name)}", value)
|
|
347
|
+
HELPER_SOURCES.each_value do |source|
|
|
348
|
+
module_eval(source, __FILE__, __LINE__)
|
|
437
349
|
end
|
|
438
350
|
|
|
439
|
-
|
|
440
|
-
Kernel.eval("$#{Kapusta.kebab_to_snake(name)}", binding, __FILE__, __LINE__) # $stderr
|
|
441
|
-
end
|
|
351
|
+
helper_methods = []
|
|
442
352
|
|
|
443
|
-
|
|
444
|
-
|
|
353
|
+
HELPER_SOURCES.each_key do |name|
|
|
354
|
+
helper_method = :"__kap_#{name}"
|
|
355
|
+
define_singleton_method(name, instance_method(helper_method))
|
|
356
|
+
helper_methods << helper_method
|
|
445
357
|
end
|
|
446
358
|
|
|
447
|
-
|
|
448
|
-
segments = path.split('.')
|
|
449
|
-
last = segments.pop
|
|
450
|
-
scope = holder.is_a?(Module) ? holder : Object
|
|
451
|
-
segments.each do |segment|
|
|
452
|
-
scope =
|
|
453
|
-
if scope.const_defined?(segment, false)
|
|
454
|
-
scope.const_get(segment, false)
|
|
455
|
-
else
|
|
456
|
-
mod = Module.new
|
|
457
|
-
scope.const_set(segment, mod)
|
|
458
|
-
mod
|
|
459
|
-
end
|
|
460
|
-
end
|
|
461
|
-
if scope.const_defined?(last, false)
|
|
462
|
-
scope.const_get(last, false)
|
|
463
|
-
else
|
|
464
|
-
mod = Module.new
|
|
465
|
-
scope.const_set(last, mod)
|
|
466
|
-
mod
|
|
467
|
-
end
|
|
468
|
-
end
|
|
469
|
-
|
|
470
|
-
def ensure_class(holder, path, super_class)
|
|
471
|
-
segments = path.split('.')
|
|
472
|
-
last = segments.pop
|
|
473
|
-
scope = holder.is_a?(Module) ? holder : Object
|
|
474
|
-
segments.each do |segment|
|
|
475
|
-
scope =
|
|
476
|
-
if scope.const_defined?(segment, false)
|
|
477
|
-
scope.const_get(segment, false)
|
|
478
|
-
else
|
|
479
|
-
mod = Module.new
|
|
480
|
-
scope.const_set(segment, mod)
|
|
481
|
-
mod
|
|
482
|
-
end
|
|
483
|
-
end
|
|
484
|
-
if scope.const_defined?(last, false)
|
|
485
|
-
scope.const_get(last, false)
|
|
486
|
-
else
|
|
487
|
-
klass = Class.new(super_class)
|
|
488
|
-
scope.const_set(last, klass)
|
|
489
|
-
klass
|
|
490
|
-
end
|
|
491
|
-
end
|
|
492
|
-
|
|
493
|
-
def destructure(pattern, value)
|
|
494
|
-
bindings = {}
|
|
495
|
-
destructure_into(pattern, value, bindings)
|
|
496
|
-
bindings
|
|
497
|
-
end
|
|
498
|
-
|
|
499
|
-
def destructure_into(pattern, value, bindings)
|
|
500
|
-
case pattern[0]
|
|
501
|
-
when :sym
|
|
502
|
-
name = pattern[1]
|
|
503
|
-
bindings[name] = value unless name == '_'
|
|
504
|
-
when :vec
|
|
505
|
-
items = pattern[1]
|
|
506
|
-
rest_idx = items.index { |item| item.is_a?(Array) && item[0] == :rest }
|
|
507
|
-
if rest_idx
|
|
508
|
-
before = items[0...rest_idx]
|
|
509
|
-
rest_pattern = items[rest_idx][1]
|
|
510
|
-
before.each_with_index do |item, i|
|
|
511
|
-
destructure_into(item, value ? value[i] : nil, bindings)
|
|
512
|
-
end
|
|
513
|
-
rest_value = value ? (value[rest_idx..] || []) : []
|
|
514
|
-
destructure_into(rest_pattern, rest_value, bindings)
|
|
515
|
-
else
|
|
516
|
-
items.each_with_index do |item, i|
|
|
517
|
-
destructure_into(item, value ? value[i] : nil, bindings)
|
|
518
|
-
end
|
|
519
|
-
end
|
|
520
|
-
when :hash
|
|
521
|
-
pattern[1].each do |key, subpattern|
|
|
522
|
-
destructure_into(subpattern, value ? value[key] : nil, bindings)
|
|
523
|
-
end
|
|
524
|
-
when :ignore
|
|
525
|
-
nil
|
|
526
|
-
else
|
|
527
|
-
raise "unknown destructure pattern: #{pattern.inspect}"
|
|
528
|
-
end
|
|
529
|
-
end
|
|
530
|
-
|
|
531
|
-
def match_pattern(pattern, value)
|
|
532
|
-
bindings = {}
|
|
533
|
-
[match_pattern_into(pattern, value, bindings), bindings]
|
|
534
|
-
end
|
|
535
|
-
|
|
536
|
-
def match_pattern_into(pattern, value, bindings)
|
|
537
|
-
case pattern[0]
|
|
538
|
-
when :sym
|
|
539
|
-
name = pattern[1]
|
|
540
|
-
bindings[name] = value unless name == '_'
|
|
541
|
-
true
|
|
542
|
-
when :vec
|
|
543
|
-
return false unless value.is_a?(Array) || value.respond_to?(:to_ary)
|
|
544
|
-
|
|
545
|
-
array = value.is_a?(Array) ? value : value.to_ary
|
|
546
|
-
items = pattern[1]
|
|
547
|
-
rest_idx = items.index { |item| item.is_a?(Array) && item[0] == :rest }
|
|
548
|
-
if rest_idx
|
|
549
|
-
before = items[0...rest_idx]
|
|
550
|
-
rest_pattern = items[rest_idx][1]
|
|
551
|
-
return false if array.length < before.length
|
|
552
|
-
|
|
553
|
-
before.each_with_index do |item, i|
|
|
554
|
-
return false unless match_pattern_into(item, array[i], bindings)
|
|
555
|
-
end
|
|
556
|
-
match_pattern_into(rest_pattern, array[rest_idx..], bindings)
|
|
557
|
-
else
|
|
558
|
-
return false unless array.length == items.length
|
|
559
|
-
|
|
560
|
-
items.each_with_index do |item, i|
|
|
561
|
-
return false unless match_pattern_into(item, array[i], bindings)
|
|
562
|
-
end
|
|
563
|
-
true
|
|
564
|
-
end
|
|
565
|
-
when :hash
|
|
566
|
-
return false unless value.is_a?(Hash)
|
|
567
|
-
|
|
568
|
-
pattern[1].each do |key, subpattern|
|
|
569
|
-
return false unless value.key?(key)
|
|
570
|
-
return false unless match_pattern_into(subpattern, value[key], bindings)
|
|
571
|
-
end
|
|
572
|
-
true
|
|
573
|
-
when :lit
|
|
574
|
-
value == pattern[1]
|
|
575
|
-
when :nil
|
|
576
|
-
value.nil?
|
|
577
|
-
else
|
|
578
|
-
raise "bad pattern: #{pattern.inspect}"
|
|
579
|
-
end
|
|
580
|
-
end
|
|
359
|
+
send(:private, *helper_methods)
|
|
581
360
|
end
|
|
582
361
|
end
|
|
583
362
|
end
|