kenma 0.1.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 +7 -0
- data/.github/workflows/kenma.yml +23 -0
- data/.github/workflows/main.yml +18 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/Gemfile +12 -0
- data/README.md +119 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/bundle_install_all.sh +9 -0
- data/kenma.gemspec +33 -0
- data/lib/kenma/iteration.rb +53 -0
- data/lib/kenma/macro/basic.rb +64 -0
- data/lib/kenma/macro/frozen_constant.rb +18 -0
- data/lib/kenma/macro/frozen_string_literal.rb +16 -0
- data/lib/kenma/macro/macro_function.rb +65 -0
- data/lib/kenma/macro/macro_node.rb +15 -0
- data/lib/kenma/macro/macro_pattern.rb +107 -0
- data/lib/kenma/macro/use_macro.rb +44 -0
- data/lib/kenma/macroable.rb +22 -0
- data/lib/kenma/node_converter.rb +79 -0
- data/lib/kenma/pre_processor.rb +28 -0
- data/lib/kenma/refine/nodable.rb +39 -0
- data/lib/kenma/refine/node_iteration.rb +31 -0
- data/lib/kenma/refine/node_to_a.rb +67 -0
- data/lib/kenma/refine/source.rb +31 -0
- data/lib/kenma/version.rb +5 -0
- data/lib/kenma.rb +21 -0
- data/rake_spec_all.sh +6 -0
- data/sample/chaining_comparison_operators_macro.rb +56 -0
- data/sample/debug_macro.rb +24 -0
- data/sample/multi_using_macro.rb +26 -0
- data/sample/shorthand_hash_literal_macro.rb +24 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4ede02761e159c70e342821d38b8cea9d672e09b7c92ce66b9c21d20933e2b0a
|
4
|
+
data.tar.gz: 7a905f6782bc2189df6568ee2ea4c69a5ac5a2ca09da7b49b007094053d0bb1d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bc4f726c242c41f70d66496585bfe5eac8b79426887e1806f17783f7b714e762e0da817fbcbc5d8d49390c58429b587cb07cebe993bae8058a5874ca91f32aa7
|
7
|
+
data.tar.gz: f21744fcc6f3dddef6c7768277b0fb9fb45607c43d06328162ee27bb5c9159c8fbb7506db2bd0c36583fca5b3b3b3fd88a5b155d039a2256097fa3e0e7e81a62
|
@@ -0,0 +1,23 @@
|
|
1
|
+
name: Ruby CI
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
|
10
|
+
strategy:
|
11
|
+
matrix:
|
12
|
+
ruby-version: [2.6.4, 2.7.0, 2.7.2, 3.0.1]
|
13
|
+
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v2
|
16
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
17
|
+
uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: ${{ matrix.ruby-version }}
|
20
|
+
- name: Install dependencies
|
21
|
+
run: bundle install
|
22
|
+
- name: Run tests
|
23
|
+
run: bundle exec rake
|
@@ -0,0 +1,18 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on: [push,pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
steps:
|
9
|
+
- uses: actions/checkout@v2
|
10
|
+
- name: Set up Ruby
|
11
|
+
uses: ruby/setup-ruby@v1
|
12
|
+
with:
|
13
|
+
ruby-version: 3.0.1
|
14
|
+
- name: Run the default task
|
15
|
+
run: |
|
16
|
+
gem install bundler -v 2.2.15
|
17
|
+
bundle install
|
18
|
+
bundle exec rake
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in kenma.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
gem "rake", "~> 13.0"
|
9
|
+
|
10
|
+
gem "rspec", "~> 3.0"
|
11
|
+
gem "super_diff"
|
12
|
+
gem "rensei", github: "osyo-manga/gem-rensei", branch: :master
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
[](https://github.com/osyo-manga/gem-kenma/actions/workflows/kenma.yml)
|
2
|
+
|
3
|
+
# Kenma
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'kenma'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install kenma
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### Macro function
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require "kenma"
|
27
|
+
|
28
|
+
using Kenma::Refine::Source
|
29
|
+
|
30
|
+
# Define Macro module
|
31
|
+
module CatMacro
|
32
|
+
using Kenma::Macroable
|
33
|
+
|
34
|
+
# Define Macro function
|
35
|
+
# Macro function is
|
36
|
+
# input -> RubyVM::AST::Node
|
37
|
+
# output -> RubyVM::AST::Node
|
38
|
+
def cat!(num = ast { 1 })
|
39
|
+
# ast return AST::Node in block
|
40
|
+
# $num is bind variable `num`
|
41
|
+
ast { "にゃーん" * $num }
|
42
|
+
end
|
43
|
+
macro_function :cat!
|
44
|
+
end
|
45
|
+
|
46
|
+
body = proc {
|
47
|
+
use_macro! CatMacro
|
48
|
+
puts cat!
|
49
|
+
puts cat!(3)
|
50
|
+
}
|
51
|
+
# Apply Macro functions
|
52
|
+
puts Kenma.compile_of(body).source
|
53
|
+
# => begin puts(("にゃーん" * 1)); puts(("にゃーん" * 3)); end
|
54
|
+
```
|
55
|
+
|
56
|
+
### Macro defines
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
require "kenma"
|
60
|
+
|
61
|
+
using Kenma::Refine::Source
|
62
|
+
using Kenma::Refine::Nodable
|
63
|
+
|
64
|
+
# Macro module
|
65
|
+
# defined macros in
|
66
|
+
# priority is
|
67
|
+
# node macro > function macro > pattern macro
|
68
|
+
module MyMacro
|
69
|
+
using Kenma::Macroable
|
70
|
+
|
71
|
+
# Node macro
|
72
|
+
# Replace the AST of a specific node with the AST of the return value
|
73
|
+
def frozen_string(str_node, parent_node)
|
74
|
+
ast { $str_node.freeze }
|
75
|
+
end
|
76
|
+
macro_node :STR, :frozen_string
|
77
|
+
|
78
|
+
# Function macro
|
79
|
+
# Replace the AST from which the function is called with the AST of the return value
|
80
|
+
def cat!(num_not = ast { 1 })
|
81
|
+
ast { "にゃーん" * $num_not }
|
82
|
+
end
|
83
|
+
macro_function :cat!
|
84
|
+
|
85
|
+
# Pattern macro
|
86
|
+
# Replace the AST that matches the pattern with the AST of the return value
|
87
|
+
def frozen(node, name:, value:)
|
88
|
+
ast { $name = $value.freeze }
|
89
|
+
end
|
90
|
+
macro_pattern pat { $name = $value }, :frozen
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
body = proc {
|
95
|
+
use_macro! MyMacro
|
96
|
+
|
97
|
+
"にゃーん" # => "にゃーん".freeze
|
98
|
+
|
99
|
+
puts cat! # => puts "にゃーん"
|
100
|
+
puts cat!(3) # => puts "にゃーん" * 3
|
101
|
+
|
102
|
+
value = [1, 2, 3] # => value = [1, 2, 3].freeze
|
103
|
+
}
|
104
|
+
|
105
|
+
result = Kenma.compile_of(body)
|
106
|
+
puts result.source
|
107
|
+
# => begin "にゃーん".freeze(); puts(("にゃーん" * 1)); puts(("にゃーん" * 3)); (value = [1, 2, 3].freeze()); end
|
108
|
+
```
|
109
|
+
|
110
|
+
|
111
|
+
## Development
|
112
|
+
|
113
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
114
|
+
|
115
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
116
|
+
|
117
|
+
## Contributing
|
118
|
+
|
119
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/osyo-manga/gem-kenma.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "kenma"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require "irb"
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/bin/bash -ex
|
2
|
+
RBENV_VERSION=2.6.4 bundle install
|
3
|
+
RBENV_VERSION=2.7.0 bundle install
|
4
|
+
RBENV_VERSION=2.7.2 bundle install
|
5
|
+
RBENV_VERSION=2.7.3 bundle install
|
6
|
+
RBENV_VERSION=2.7.4 bundle install
|
7
|
+
RBENV_VERSION=3.0.0 bundle install
|
8
|
+
RBENV_VERSION=3.0.1 bundle install
|
9
|
+
RBENV_VERSION=3.1.0-dev bundle install
|
data/kenma.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/kenma/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "kenma"
|
7
|
+
spec.version = Kenma::VERSION
|
8
|
+
spec.authors = ["manga_osyo"]
|
9
|
+
spec.email = ["manga.osyo@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "AST Macro in Ruby"
|
12
|
+
spec.description = "AST Macro in Ruby"
|
13
|
+
spec.homepage = "https://github.com/osyo-manga/gem-kenma"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
|
16
|
+
|
17
|
+
# Specify which files should be added to the gem when it is released.
|
18
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
19
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
20
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
21
|
+
end
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
# Uncomment to register a new dependency of your gem
|
27
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
28
|
+
|
29
|
+
# For more information and examples about making a new gem, checkout our
|
30
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
31
|
+
|
32
|
+
spec.add_dependency "rensei", "~> 0.2.0"
|
33
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./refine/nodable.rb"
|
4
|
+
|
5
|
+
module Kenma
|
6
|
+
module Iteration
|
7
|
+
using Kenma::Refine::Nodable
|
8
|
+
|
9
|
+
KENMA_ITERATION_MACRO_EMPTY_NODE = Object.new.freeze
|
10
|
+
private_constant :KENMA_ITERATION_MACRO_EMPTY_NODE
|
11
|
+
|
12
|
+
module_function
|
13
|
+
|
14
|
+
def each_node(node, &block)
|
15
|
+
return Enumerator.new { |y|
|
16
|
+
each_node(node) { |node|
|
17
|
+
y << node
|
18
|
+
}
|
19
|
+
} unless block
|
20
|
+
return node unless node.node?
|
21
|
+
|
22
|
+
node.children.map { |node|
|
23
|
+
each_node(node) { |child| block.call(child, node) }
|
24
|
+
}
|
25
|
+
block.call(node) if block
|
26
|
+
end
|
27
|
+
|
28
|
+
def convert_node(node, parent = nil, &block)
|
29
|
+
return node unless node.node?
|
30
|
+
|
31
|
+
children = node.children
|
32
|
+
converted_children = children
|
33
|
+
.map { |child| convert_node(child, node) { |node, parent| block.call(node, parent) || KENMA_ITERATION_MACRO_EMPTY_NODE } }
|
34
|
+
.reject { |it| KENMA_ITERATION_MACRO_EMPTY_NODE == it }
|
35
|
+
|
36
|
+
if converted_children == children
|
37
|
+
node
|
38
|
+
else
|
39
|
+
[node.type, converted_children]
|
40
|
+
end.then { |node| block.call(node, parent) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def find_convert_node(node, pat, &block)
|
44
|
+
convert_node(node) { |node|
|
45
|
+
if result = pat === node
|
46
|
+
block.call(node, **result)
|
47
|
+
else
|
48
|
+
node
|
49
|
+
end
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../macroable.rb"
|
4
|
+
|
5
|
+
module Kenma
|
6
|
+
module Macro
|
7
|
+
module Basic
|
8
|
+
using Kenma::Macroable
|
9
|
+
using Kenma::Refine::Source
|
10
|
+
using Kenma::Refine::Nodable
|
11
|
+
|
12
|
+
def symbolify!(args)
|
13
|
+
[:LIT, [args.source.to_sym]]
|
14
|
+
end
|
15
|
+
macro_function :symbolify!
|
16
|
+
|
17
|
+
def stringify!(args)
|
18
|
+
if args.respond_to?(:source)
|
19
|
+
[:STR, [args.source]]
|
20
|
+
else
|
21
|
+
[:STR, [args.to_s]]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
macro_function :stringify!
|
25
|
+
|
26
|
+
def unstringify!(args)
|
27
|
+
RubyVM::AbstractSyntaxTree.parse(bind.eval(args.source)).children.last
|
28
|
+
end
|
29
|
+
macro_function :unstringify!
|
30
|
+
|
31
|
+
def node_bind!(args)
|
32
|
+
bind.eval(args.source)
|
33
|
+
end
|
34
|
+
macro_function :node_bind!
|
35
|
+
|
36
|
+
def eval!(args)
|
37
|
+
data = bind.eval(args.source)
|
38
|
+
RubyVM::AbstractSyntaxTree.parse(data.inspect).children.last
|
39
|
+
end
|
40
|
+
macro_function :eval!
|
41
|
+
|
42
|
+
# $node
|
43
|
+
def NODE_GVAR(node, parent)
|
44
|
+
name = node.children.first.to_s.delete_prefix("$").to_sym
|
45
|
+
if bind.local_variable_defined?(name)
|
46
|
+
bind.local_variable_get(name)
|
47
|
+
else
|
48
|
+
node
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# $left = right
|
53
|
+
def NODE_GASGN(node, parent)
|
54
|
+
left, right = node.children
|
55
|
+
name = left.to_s.delete_prefix("$").to_sym
|
56
|
+
if bind.local_variable_defined?(name)
|
57
|
+
[:GASGN, [bind.local_variable_get(name), right]]
|
58
|
+
else
|
59
|
+
node
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../macroable.rb"
|
4
|
+
require_relative "./macro_node.rb"
|
5
|
+
|
6
|
+
module Kenma
|
7
|
+
module Macro
|
8
|
+
module FrozenConstant
|
9
|
+
using Kenma::Macroable
|
10
|
+
|
11
|
+
def _frozen_constant_decl(node, parent)
|
12
|
+
left, right = node.children
|
13
|
+
ast { $left = $right.freeze }
|
14
|
+
end
|
15
|
+
macro_node :CDECL, :_frozen_constant_decl
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../macroable.rb"
|
4
|
+
|
5
|
+
module Kenma
|
6
|
+
module Macro
|
7
|
+
module FrozenStringLiteral
|
8
|
+
using Kenma::Macroable
|
9
|
+
|
10
|
+
def frozen_string(node, parent)
|
11
|
+
ast { $node.freeze }
|
12
|
+
end
|
13
|
+
macro_node :STR, :frozen_string
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../macroable.rb"
|
4
|
+
require_relative "./macro_node.rb"
|
5
|
+
|
6
|
+
module Kenma
|
7
|
+
module Macroable
|
8
|
+
refine Module do
|
9
|
+
def macro_function(name)
|
10
|
+
macro_functions << name
|
11
|
+
module_function name
|
12
|
+
extend Kenma::Macroable
|
13
|
+
end
|
14
|
+
|
15
|
+
def macro_functions
|
16
|
+
@macro_functions ||= []
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Macro
|
22
|
+
module MacroFunction
|
23
|
+
using Kenma::Macroable
|
24
|
+
using Kenma::Refine::Source
|
25
|
+
|
26
|
+
using Module.new {
|
27
|
+
refine MacroFunction do
|
28
|
+
using Kenma::Macroable
|
29
|
+
def macro_functions
|
30
|
+
singleton_class.ancestors.grep(Kenma::Macroable).map(&:macro_functions).inject([], &:+)
|
31
|
+
end
|
32
|
+
|
33
|
+
def send_macro_function(method_name, args, &block)
|
34
|
+
converted_args = compile(args)
|
35
|
+
send(method_name, *converted_args&.children&.compact, &block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
}
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def _FCALL_send_macro_function(node, parent)
|
43
|
+
return node if parent&.type == :ITER
|
44
|
+
method_name, args = node.children
|
45
|
+
if macro_functions.include?(method_name)
|
46
|
+
send_macro_function(method_name, args)
|
47
|
+
else
|
48
|
+
node
|
49
|
+
end
|
50
|
+
end
|
51
|
+
macro_node :FCALL, :_FCALL_send_macro_function
|
52
|
+
|
53
|
+
def _ITER_send_macro_function(node, parent)
|
54
|
+
fcall, scope = node.children
|
55
|
+
method_name, args = fcall.children
|
56
|
+
if macro_functions.include?(method_name)
|
57
|
+
send_macro_function(method_name, args) { scope }
|
58
|
+
else
|
59
|
+
node
|
60
|
+
end
|
61
|
+
end
|
62
|
+
macro_node :ITER, :_ITER_send_macro_function
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../macroable.rb"
|
4
|
+
|
5
|
+
module Kenma
|
6
|
+
module Macroable
|
7
|
+
refine Module do
|
8
|
+
def macro_node(node_type, name)
|
9
|
+
define_method("NODE_#{node_type}") { |node, parent|
|
10
|
+
send(name, node, parent)
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../macroable.rb"
|
4
|
+
require_relative "./macro_node.rb"
|
5
|
+
|
6
|
+
module Kenma
|
7
|
+
using Kenma::Refine::Nodable
|
8
|
+
|
9
|
+
class PatternCapture < Struct.new(:pat_node)
|
10
|
+
def initialize(pat_node)
|
11
|
+
self.pat_node = pat_node
|
12
|
+
end
|
13
|
+
|
14
|
+
def match(node)
|
15
|
+
_match(node, pat_node)
|
16
|
+
end
|
17
|
+
alias_method :===, :match
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def _match(node, pat)
|
22
|
+
return {} if node == pat
|
23
|
+
return nil if node.nil? || pat.nil?
|
24
|
+
return nil if !node.node? || !pat.node?
|
25
|
+
|
26
|
+
if pat.type == :GASGN && node.type.to_s =~ /ASGN|CDECL/
|
27
|
+
match_result = _match(node.children.last, pat.children.last)
|
28
|
+
if match_result
|
29
|
+
tag = pat.children.first.to_s.delete_prefix("$").to_sym
|
30
|
+
{ tag => node.children.first }.merge(_match(node.children.last, pat.children.last))
|
31
|
+
else
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
elsif pat.type == :GVAR
|
35
|
+
tag = pat.children.first.to_s.delete_prefix("$").to_sym
|
36
|
+
{ tag => node }
|
37
|
+
# Add Support: pat { [*$node] } === ast { [a, b, c] } # => { node: [a, b, c] }
|
38
|
+
# Not Support: pat { [$first, *$node] } === ast { [a, b, c] } # => nil
|
39
|
+
elsif pat.type === :SPLAT && pat.children.first.type == :GVAR
|
40
|
+
tag = pat.children.first.children.first.to_s.delete_prefix("$").to_sym
|
41
|
+
{ tag => node }
|
42
|
+
elsif node.type == pat.type && node.children.size == pat.children.size
|
43
|
+
node.children.zip(pat.children).inject({}) { |result, (src, pat)|
|
44
|
+
if match_result = _match(src, pat)
|
45
|
+
result.merge(match_result)
|
46
|
+
else
|
47
|
+
break nil
|
48
|
+
end
|
49
|
+
}
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module Macroable
|
57
|
+
refine Kernel do
|
58
|
+
def pat(&block)
|
59
|
+
pat_node(RubyVM::AbstractSyntaxTree.of(block).children.last)
|
60
|
+
end
|
61
|
+
|
62
|
+
def pat_node(node)
|
63
|
+
PatternCapture.new(node)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
refine Module do
|
68
|
+
def macro_pattern(pattern, name)
|
69
|
+
macro_patterns[name] = pattern
|
70
|
+
extend Kenma::Macroable
|
71
|
+
end
|
72
|
+
|
73
|
+
def macro_patterns
|
74
|
+
@macro_patterns ||= {}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module Macro
|
80
|
+
module MacroPattern
|
81
|
+
using Kenma::Macroable
|
82
|
+
using Kenma::Refine::Source
|
83
|
+
|
84
|
+
using Module.new {
|
85
|
+
refine MacroPattern do
|
86
|
+
using Kenma::Macroable
|
87
|
+
def macro_patterns
|
88
|
+
singleton_class.ancestors.grep(Kenma::Macroable).map(&:macro_patterns).inject({}, &:merge)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
}
|
92
|
+
|
93
|
+
def node_missing(node, parent)
|
94
|
+
macro = macro_patterns.lazy.reverse_each.map { |name, pat| [name, pat.match(node)] }.find { |name, captured| captured }
|
95
|
+
if macro
|
96
|
+
if macro[1].empty?
|
97
|
+
send(macro[0], node)
|
98
|
+
else
|
99
|
+
send(macro[0], node, **macro[1])
|
100
|
+
end
|
101
|
+
else
|
102
|
+
super(node, parent)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../macroable.rb"
|
4
|
+
require_relative "./macro_function.rb"
|
5
|
+
|
6
|
+
module Kenma
|
7
|
+
module Macro
|
8
|
+
module UseMacro
|
9
|
+
using Kenma::Macroable
|
10
|
+
using Kenma::Refine::Nodable
|
11
|
+
using Kenma::Refine::Source
|
12
|
+
|
13
|
+
def initialize(context = {})
|
14
|
+
super
|
15
|
+
extend *use_macros.reverse unless use_macros.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def use_macro!(node)
|
19
|
+
macro_mod = bind.eval(node.source)
|
20
|
+
use_macros << macro_mod
|
21
|
+
extend macro_mod
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
macro_function :use_macro!
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def use_macro(mod)
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def use_macros
|
33
|
+
scope_context[:use_macros] ||= []
|
34
|
+
end
|
35
|
+
|
36
|
+
def scope_context_switch(context, &block)
|
37
|
+
super(context) { |converter|
|
38
|
+
converter.extend *use_macros.reverse unless use_macros.empty?
|
39
|
+
block.call(converter)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./node_converter.rb"
|
4
|
+
require_relative "./refine/node_to_a.rb"
|
5
|
+
|
6
|
+
module Kenma
|
7
|
+
module Macroable
|
8
|
+
refine Kernel do
|
9
|
+
def ast(context = {}, &body)
|
10
|
+
bind = body.binding unless context[:bind]
|
11
|
+
node = RubyVM::AbstractSyntaxTree.of(body).children.last
|
12
|
+
Kenma.compile(node, { bind: bind }.merge(context))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# TODO: duplicate Reifne::Nodable
|
17
|
+
refine Array do
|
18
|
+
def type; self[0]; end
|
19
|
+
def children; self[1]; end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./refine/source.rb"
|
4
|
+
require_relative "./refine/nodable.rb"
|
5
|
+
require_relative "./refine/node_iteration.rb"
|
6
|
+
|
7
|
+
module Kenma
|
8
|
+
class NodeConverter
|
9
|
+
using Kenma::Refine::Source
|
10
|
+
using Kenma::Refine::Nodable
|
11
|
+
|
12
|
+
def initialize(context = {})
|
13
|
+
@scope_context = context
|
14
|
+
end
|
15
|
+
|
16
|
+
def convert(node)
|
17
|
+
_convert(node) { |node, parent|
|
18
|
+
method_name = "NODE_#{node.type}"
|
19
|
+
send_node(method_name, node, parent)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
KENMA_MACRO_EMPTY_NODE = Object.new.freeze
|
26
|
+
private_constant :KENMA_MACRO_EMPTY_NODE
|
27
|
+
|
28
|
+
attr_reader :bind
|
29
|
+
attr_reader :scope_context
|
30
|
+
|
31
|
+
def bind
|
32
|
+
scope_context[:bind]
|
33
|
+
end
|
34
|
+
|
35
|
+
def scope_context_switch(context, &block)
|
36
|
+
self.class.new(scope_context.merge(context)).then(&block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def _convert(node, &block)
|
40
|
+
return node unless node.node?
|
41
|
+
|
42
|
+
if node.type == :SCOPE
|
43
|
+
return scope_context_switch(scope_context) { |converter|
|
44
|
+
children = [*node.children.take(node.children.size-1), converter.convert(node.children.last)]
|
45
|
+
.reject { |it| KENMA_MACRO_EMPTY_NODE == it }
|
46
|
+
send_node(:NODE_SCOPE, [:SCOPE, children], node)
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
children = node.children
|
51
|
+
converted_children = children
|
52
|
+
.map { |node| _convert(node) { |child| block.call(child, node) || KENMA_MACRO_EMPTY_NODE } }
|
53
|
+
.reject { |it| KENMA_MACRO_EMPTY_NODE == it }
|
54
|
+
|
55
|
+
if converted_children == children
|
56
|
+
node
|
57
|
+
else
|
58
|
+
[node.type, converted_children]
|
59
|
+
end.then { |node| block.call(node, nil) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def send_node(method_name, node, parent)
|
63
|
+
if respond_to?(method_name, true)
|
64
|
+
result = send(method_name, node, parent)
|
65
|
+
if result == node
|
66
|
+
node_missing(node, parent)
|
67
|
+
else
|
68
|
+
result
|
69
|
+
end
|
70
|
+
else
|
71
|
+
node_missing(node, parent)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def node_missing(node, parent)
|
76
|
+
node
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./node_converter.rb"
|
4
|
+
require_relative "./macro/use_macro.rb"
|
5
|
+
require_relative "./macro/basic.rb"
|
6
|
+
require_relative "./macro/macro_function.rb"
|
7
|
+
require_relative "./macro/macro_node.rb"
|
8
|
+
require_relative "./macro/macro_pattern.rb"
|
9
|
+
|
10
|
+
module Kenma
|
11
|
+
class PreProcessor < Kenma::NodeConverter
|
12
|
+
include Macro::UseMacro
|
13
|
+
include Macro::Basic
|
14
|
+
include Macro::MacroFunction
|
15
|
+
include Macro::MacroPattern
|
16
|
+
|
17
|
+
alias_method :compile, :convert
|
18
|
+
|
19
|
+
def self.compile(node, context = {})
|
20
|
+
new(context).compile(node)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.compile_of(body, context = {})
|
24
|
+
bind = body.binding unless context[:bind]
|
25
|
+
compile(RubyVM::AbstractSyntaxTree.of(body), { bind: bind }.merge(context))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rensei"
|
4
|
+
|
5
|
+
module Kenma
|
6
|
+
module Refine
|
7
|
+
module Nodable
|
8
|
+
refine Object do
|
9
|
+
def node?; false; end
|
10
|
+
end
|
11
|
+
|
12
|
+
refine RubyVM::AbstractSyntaxTree::Node do
|
13
|
+
def node?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
refine Hash do
|
19
|
+
def type; self[:type]; end
|
20
|
+
|
21
|
+
def children; self[:children]; end
|
22
|
+
|
23
|
+
def node?; !empty?; end
|
24
|
+
end
|
25
|
+
|
26
|
+
refine Array do
|
27
|
+
def type; self[0]; end
|
28
|
+
|
29
|
+
def children; self[1]; end
|
30
|
+
|
31
|
+
def node?
|
32
|
+
self.size == 2 &&
|
33
|
+
self[0].kind_of?(Symbol) && self[0] == self[0].upcase &&
|
34
|
+
self[1].kind_of?(Array)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rensei"
|
4
|
+
require_relative "./nodable.rb"
|
5
|
+
require_relative "../iteration.rb"
|
6
|
+
|
7
|
+
module Kenma
|
8
|
+
module Refine
|
9
|
+
module NodeIteration
|
10
|
+
def each_node(&block)
|
11
|
+
Kenma::Iteration.each_node(self, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def convert_node(&block)
|
15
|
+
Kenma::Iteration.convert_node(self, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_convert_node(pat, &block)
|
19
|
+
Kenma::Iteration.find_convert_node(self, pat, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
refine Array do
|
23
|
+
include Kenma::Refine::NodeIteration
|
24
|
+
end
|
25
|
+
|
26
|
+
refine RubyVM::AbstractSyntaxTree::Node do
|
27
|
+
include Kenma::Refine::NodeIteration
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rensei"
|
4
|
+
require_relative "./nodable.rb"
|
5
|
+
|
6
|
+
module Kenma
|
7
|
+
module Refine
|
8
|
+
module NodeToArray
|
9
|
+
refine RubyVM::AbstractSyntaxTree::Node do
|
10
|
+
using Module.new {
|
11
|
+
[
|
12
|
+
Object,
|
13
|
+
NilClass,
|
14
|
+
FalseClass,
|
15
|
+
TrueClass,
|
16
|
+
String,
|
17
|
+
Hash,
|
18
|
+
Array,
|
19
|
+
Symbol,
|
20
|
+
Numeric,
|
21
|
+
Regexp,
|
22
|
+
].each { |klass|
|
23
|
+
refine klass do
|
24
|
+
def to_a(*)
|
25
|
+
self
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
def to_a
|
33
|
+
[type, children.map { |it| it.to_a }]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
refine Array do
|
38
|
+
using Module.new {
|
39
|
+
[
|
40
|
+
Object,
|
41
|
+
NilClass,
|
42
|
+
FalseClass,
|
43
|
+
TrueClass,
|
44
|
+
String,
|
45
|
+
Hash,
|
46
|
+
Symbol,
|
47
|
+
Numeric,
|
48
|
+
Regexp,
|
49
|
+
].each { |klass|
|
50
|
+
refine klass do
|
51
|
+
def to_a(*)
|
52
|
+
self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
using NodeToArray
|
60
|
+
|
61
|
+
def to_a(*)
|
62
|
+
map { |it| it.to_a }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rensei"
|
4
|
+
|
5
|
+
module Kenma
|
6
|
+
module Refine
|
7
|
+
module Source
|
8
|
+
refine RubyVM::AbstractSyntaxTree::Node do
|
9
|
+
if RUBY_VERSION >= "3.1.0"
|
10
|
+
def source
|
11
|
+
super.tap { |it|
|
12
|
+
break Rensei.unparse(self) if it.nil?
|
13
|
+
}
|
14
|
+
end
|
15
|
+
else
|
16
|
+
def source
|
17
|
+
Rensei.unparse(self)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
refine Hash do
|
23
|
+
def source; Rensei.unparse(self.dup); end
|
24
|
+
end
|
25
|
+
|
26
|
+
refine Array do
|
27
|
+
def source; Rensei.unparse(self.dup); end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/kenma.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./kenma/version"
|
4
|
+
require_relative "./kenma/pre_processor.rb"
|
5
|
+
require_relative "./kenma/iteration.rb"
|
6
|
+
|
7
|
+
module Kenma
|
8
|
+
using Kenma::Refine::Source
|
9
|
+
|
10
|
+
def self.compile(body, context = {})
|
11
|
+
PreProcessor.compile(body, context)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.compile_of(body, context = {})
|
15
|
+
PreProcessor.compile_of(body, context)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.macro_eval(context = {}, &body)
|
19
|
+
body.binding.eval Kenma.compile_of(body).source
|
20
|
+
end
|
21
|
+
end
|
data/rake_spec_all.sh
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# a < b < c
|
2
|
+
# ↓
|
3
|
+
# a < b && b < c
|
4
|
+
require "kenma"
|
5
|
+
|
6
|
+
using Kenma::Refine::Source
|
7
|
+
|
8
|
+
module ChainingComparisonOperatorsMacro
|
9
|
+
using Kenma::Macroable
|
10
|
+
using Kenma::Refine::NodeToArray
|
11
|
+
|
12
|
+
def chaining_comparison_operators(node, parent)
|
13
|
+
case node.to_a
|
14
|
+
in [:OPCALL, [[:OPCALL, [left, op1, [:LIST, [middle, nil]]]], op2, [:LIST, [right, nil]]]]
|
15
|
+
ast { $left.send(eval!(op1), $middle) && $middle.send(eval!(op2), $right) }
|
16
|
+
else
|
17
|
+
node
|
18
|
+
end
|
19
|
+
end
|
20
|
+
macro_node :OPCALL, :chaining_comparison_operators
|
21
|
+
end
|
22
|
+
|
23
|
+
body = proc {
|
24
|
+
use_macro! ChainingComparisonOperatorsMacro
|
25
|
+
|
26
|
+
0 <= value < 10
|
27
|
+
}
|
28
|
+
|
29
|
+
result = Kenma.compile_of(body)
|
30
|
+
puts result.source
|
31
|
+
|
32
|
+
body = proc {
|
33
|
+
use_macro! ChainingComparisonOperatorsMacro
|
34
|
+
|
35
|
+
def check(value)
|
36
|
+
# to 0 <= input && input < 10
|
37
|
+
if 0 <= value < 10
|
38
|
+
"OK"
|
39
|
+
else
|
40
|
+
"NG"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
check(10)
|
44
|
+
|
45
|
+
puts check(5) # => "OK"
|
46
|
+
puts check(20) # => "NG"
|
47
|
+
}
|
48
|
+
result = Kenma.compile_of(body)
|
49
|
+
puts result.source
|
50
|
+
# => begin def check(value)
|
51
|
+
# (if (0.send(:<=, value) && value.send(:<, 10))
|
52
|
+
# "OK"
|
53
|
+
# else
|
54
|
+
# "NG"
|
55
|
+
# end)
|
56
|
+
# end; check(10); puts(check(5)); puts(check(20)); end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# debug! 1 + 2
|
2
|
+
# ↓
|
3
|
+
# puts "1 + 2 # => #{1 + 2}"
|
4
|
+
require "kenma"
|
5
|
+
|
6
|
+
using Kenma::Refine::Source
|
7
|
+
|
8
|
+
module DebugMacro
|
9
|
+
using Kenma::Macroable
|
10
|
+
|
11
|
+
def debug!(expr)
|
12
|
+
ast { puts "#{stringify! $expr} # => #{$expr}" }
|
13
|
+
end
|
14
|
+
macro_function :debug!
|
15
|
+
end
|
16
|
+
|
17
|
+
body = proc {
|
18
|
+
use_macro! DebugMacro
|
19
|
+
|
20
|
+
debug! 1 + 2 + 3
|
21
|
+
debug! [1, 2, 3].map { _1 + _1 }
|
22
|
+
}
|
23
|
+
puts Kenma.compile_of(body).source
|
24
|
+
# => begin puts("#{"((1 + 2) + 3)"} # => #{((1 + 2) + 3)}"); puts("#{"[1, 2, 3].map() { (_1 + _1) }"} # => #{[1, 2, 3].map() { (_1 + _1) }}"); end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "kenma"
|
2
|
+
|
3
|
+
using Kenma::Refine::Source
|
4
|
+
|
5
|
+
module MultiUsingMacro
|
6
|
+
using Kenma::Macroable
|
7
|
+
using Kenma::Refine::NodeToArray
|
8
|
+
|
9
|
+
def using(*args)
|
10
|
+
args.compact.inject(ast { {} }) { |result, name|
|
11
|
+
ast { $result; using $name }
|
12
|
+
}
|
13
|
+
end
|
14
|
+
macro_function :using
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
body = proc {
|
19
|
+
use_macro! MultiUsingMacro
|
20
|
+
|
21
|
+
using Hoge, Foo, Bar
|
22
|
+
}
|
23
|
+
|
24
|
+
result = Kenma.compile_of(body)
|
25
|
+
puts result.source
|
26
|
+
# => begin begin begin {}; using(Hoge); end; using(Foo); end; using(Bar); end;
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "kenma"
|
2
|
+
|
3
|
+
using Kenma::Refine::Source
|
4
|
+
|
5
|
+
module ShorthandHashLiteralMacro
|
6
|
+
using Kenma::Macroable
|
7
|
+
|
8
|
+
def shorthand_hash_literal(node, args:)
|
9
|
+
args.children.compact.inject(ast { {} }) { |result, name|
|
10
|
+
ast { $result.merge({ symbolify!($name) => $name }) }
|
11
|
+
}
|
12
|
+
end
|
13
|
+
macro_pattern pat { ![*$args] }, :shorthand_hash_literal
|
14
|
+
end
|
15
|
+
|
16
|
+
body = proc {
|
17
|
+
use_macro! ShorthandHashLiteralMacro
|
18
|
+
|
19
|
+
![a, b, c]
|
20
|
+
}
|
21
|
+
|
22
|
+
result = Kenma.compile_of(body)
|
23
|
+
puts result.source
|
24
|
+
# => {}.merge({ a: a }).merge({ b: b }).merge({ c: c });
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kenma
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- manga_osyo
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-09-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rensei
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.2.0
|
27
|
+
description: AST Macro in Ruby
|
28
|
+
email:
|
29
|
+
- manga.osyo@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".github/workflows/kenma.yml"
|
35
|
+
- ".github/workflows/main.yml"
|
36
|
+
- ".gitignore"
|
37
|
+
- ".rspec"
|
38
|
+
- Gemfile
|
39
|
+
- README.md
|
40
|
+
- Rakefile
|
41
|
+
- bin/console
|
42
|
+
- bin/setup
|
43
|
+
- bundle_install_all.sh
|
44
|
+
- kenma.gemspec
|
45
|
+
- lib/kenma.rb
|
46
|
+
- lib/kenma/iteration.rb
|
47
|
+
- lib/kenma/macro/basic.rb
|
48
|
+
- lib/kenma/macro/frozen_constant.rb
|
49
|
+
- lib/kenma/macro/frozen_string_literal.rb
|
50
|
+
- lib/kenma/macro/macro_function.rb
|
51
|
+
- lib/kenma/macro/macro_node.rb
|
52
|
+
- lib/kenma/macro/macro_pattern.rb
|
53
|
+
- lib/kenma/macro/use_macro.rb
|
54
|
+
- lib/kenma/macroable.rb
|
55
|
+
- lib/kenma/node_converter.rb
|
56
|
+
- lib/kenma/pre_processor.rb
|
57
|
+
- lib/kenma/refine/nodable.rb
|
58
|
+
- lib/kenma/refine/node_iteration.rb
|
59
|
+
- lib/kenma/refine/node_to_a.rb
|
60
|
+
- lib/kenma/refine/source.rb
|
61
|
+
- lib/kenma/version.rb
|
62
|
+
- rake_spec_all.sh
|
63
|
+
- sample/chaining_comparison_operators_macro.rb
|
64
|
+
- sample/debug_macro.rb
|
65
|
+
- sample/multi_using_macro.rb
|
66
|
+
- sample/shorthand_hash_literal_macro.rb
|
67
|
+
homepage: https://github.com/osyo-manga/gem-kenma
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 2.6.0
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubygems_version: 3.3.0.dev
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: AST Macro in Ruby
|
90
|
+
test_files: []
|