maccro 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +359 -0
- data/Rakefile +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/maccro.rb +147 -0
- data/lib/maccro/builtin.rb +105 -0
- data/lib/maccro/code_range.rb +63 -0
- data/lib/maccro/code_util.rb +106 -0
- data/lib/maccro/dsl.rb +182 -0
- data/lib/maccro/dsl/assign.rb +100 -0
- data/lib/maccro/dsl/expression.rb +166 -0
- data/lib/maccro/dsl/literal.rb +121 -0
- data/lib/maccro/dsl/node.rb +89 -0
- data/lib/maccro/dsl/value.rb +85 -0
- data/lib/maccro/kernel_ext.rb +15 -0
- data/lib/maccro/matched.rb +34 -0
- data/lib/maccro/rewrite_the_world.rb +4 -0
- data/lib/maccro/rule.rb +106 -0
- data/lib/maccro/version.rb +3 -0
- data/maccro.gemspec +27 -0
- metadata +108 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
require_relative "node"
|
2
|
+
|
3
|
+
module Maccro
|
4
|
+
module DSL
|
5
|
+
class MultiAssignment < Node
|
6
|
+
def type; :MASGN; end
|
7
|
+
def self.match?(node); node.type == :MASGN ; end
|
8
|
+
end
|
9
|
+
|
10
|
+
class LocalVariableAssignment < Node
|
11
|
+
def type; :LASGN; end
|
12
|
+
def self.match?(node); node.type == :LASGN ; end
|
13
|
+
end
|
14
|
+
|
15
|
+
class DynamicVariableAssignmentOutOfScope < Node
|
16
|
+
# x = 1; 1.times{ x = 1 }
|
17
|
+
def type; :DASGN; end
|
18
|
+
def self.match?(node); node.type == :DASGN ; end
|
19
|
+
end
|
20
|
+
|
21
|
+
class DynamicVariableAssignmentCurrentScope < Node
|
22
|
+
# 1.times{ x = 1 }
|
23
|
+
def type; :DASGN_CUPR; end
|
24
|
+
def self.match?(node); node.type == :DASGN_CUPR ; end
|
25
|
+
end
|
26
|
+
|
27
|
+
class InstanceVariableAssignment < Node
|
28
|
+
def type; :IASGN; end
|
29
|
+
def self.match?(node); node.type == :IASGN ; end
|
30
|
+
end
|
31
|
+
|
32
|
+
class ClassVariableAssignment < Node
|
33
|
+
def type; :CVASGN; end
|
34
|
+
def self.match?(node); node.type == :CVASGN ; end
|
35
|
+
end
|
36
|
+
|
37
|
+
class GlobalVariableAssignment < Node
|
38
|
+
def type; :GASGN; end
|
39
|
+
def self.match?(node); node.type == :GASGN ; end
|
40
|
+
end
|
41
|
+
|
42
|
+
class AttributeAssignment < Node
|
43
|
+
# x[1] = 1
|
44
|
+
# x.a = 1
|
45
|
+
def type; :ATTRASGN; end
|
46
|
+
def self.match?(node); node.type == :ATTRASGN ; end
|
47
|
+
end
|
48
|
+
|
49
|
+
class ArrayAssignmentWithOperator < Node
|
50
|
+
# x[1] += 1
|
51
|
+
def type; :OP_ASGN1; end
|
52
|
+
def self.match?(node); node.type == :OP_ASGN1 ; end
|
53
|
+
end
|
54
|
+
|
55
|
+
class AttributeAssignmentWithOperator < Node
|
56
|
+
# x.a += 1
|
57
|
+
def type; :OP_ASGN2; end
|
58
|
+
def self.match?(node); node.type == :OP_ASGN2 ; end
|
59
|
+
end
|
60
|
+
|
61
|
+
class AndAssignment < Node
|
62
|
+
# x &&= y
|
63
|
+
def type; :OP_ASGN_AND; end
|
64
|
+
def self.match?(node); node.type == :OP_ASGN_AND ; end
|
65
|
+
end
|
66
|
+
|
67
|
+
class OrAssignment < Node
|
68
|
+
# x ||= y
|
69
|
+
def type; :OP_ASGN_OR; end
|
70
|
+
def self.match?(node); node.type == :OP_ASGN_OR ; end
|
71
|
+
end
|
72
|
+
|
73
|
+
class ConstantDeclaration < Node
|
74
|
+
def type; :CDECL; end
|
75
|
+
def self.match?(node); node.type == :CDECL ; end
|
76
|
+
end
|
77
|
+
|
78
|
+
class ConstantDeclarationWithOperator < Node
|
79
|
+
# A::B ||= 1
|
80
|
+
# A::B += 1
|
81
|
+
def type; :OP_CDECL; end
|
82
|
+
def self.match?(node); node.type == :OP_CDECL ; end
|
83
|
+
end
|
84
|
+
|
85
|
+
class Assignment < Node
|
86
|
+
SUB_TYPES = [
|
87
|
+
MultiAssignment, LocalVariableAssignment,
|
88
|
+
DynamicVariableAssignmentOutOfScope, DynamicVariableAssignmentCurrentScope,
|
89
|
+
InstanceVariableAssignment, ClassVariableAssignment, GlobalVariableAssignment,
|
90
|
+
AttributeAssignment, ArrayAssignmentWithOperator, AttributeAssignmentWithOperator,
|
91
|
+
AndAssignment, OrAssignment,
|
92
|
+
ConstantDeclaration, ConstantDeclarationWithOperator,
|
93
|
+
].freeze
|
94
|
+
|
95
|
+
def self.match?(node)
|
96
|
+
SUB_TYPES.any?{|s| s.match?(node) }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require_relative "node"
|
2
|
+
require_relative "value"
|
3
|
+
require_relative "assign"
|
4
|
+
|
5
|
+
module Maccro
|
6
|
+
module DSL
|
7
|
+
class IfExp < Node
|
8
|
+
def type; :IF; end
|
9
|
+
def self.match?(node); node.type == :IF; end
|
10
|
+
end
|
11
|
+
|
12
|
+
class UnlessExp < Node
|
13
|
+
def type; :UNLESS; end
|
14
|
+
def self.match?(node); node.type == :UNLESS; end
|
15
|
+
end
|
16
|
+
|
17
|
+
class CaseExp < Node
|
18
|
+
def type; :MACCRO_CASE; end
|
19
|
+
def self.match?(node)
|
20
|
+
node.type == :CASE || node.type == :CASE2
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# class BeginExp < Node
|
25
|
+
# # TODO: getting source of begin node DOES drop the beggining "begin" and tailing "end"
|
26
|
+
# def type; :"BEGIN"; end
|
27
|
+
# def self.match?(node); node.type == :"BEGIN"; end
|
28
|
+
# end
|
29
|
+
|
30
|
+
# class RescueExp < Node
|
31
|
+
# # TODO: getting source of rescue node DOES drop the beggining "begin" and tailing "end"
|
32
|
+
# def type; :"RESCUE"; end
|
33
|
+
# def self.match?(node); node.type == :"RESCUE"; end
|
34
|
+
# end
|
35
|
+
|
36
|
+
class AndExp < Node
|
37
|
+
def type; :AND; end
|
38
|
+
def self.match?(node); node.type == :AND; end
|
39
|
+
end
|
40
|
+
|
41
|
+
class OrExp < Node
|
42
|
+
def type; :OR; end
|
43
|
+
def self.match?(node); node.type == :OR; end
|
44
|
+
end
|
45
|
+
|
46
|
+
class CallExp < Node
|
47
|
+
def type; :CALL; end
|
48
|
+
def self.match?(node); node.type == :CALL; end
|
49
|
+
end
|
50
|
+
|
51
|
+
class OperatorCallExp < Node
|
52
|
+
def type; :OPCALL; end
|
53
|
+
def self.match?(node); node.type == :OPCALL; end
|
54
|
+
end
|
55
|
+
|
56
|
+
class SafeCallExp < Node
|
57
|
+
# x&.foo(1)
|
58
|
+
def type; :QCALL; end
|
59
|
+
def self.match?(node); node.type == :QCALL; end
|
60
|
+
end
|
61
|
+
|
62
|
+
class FunctionCallExp < Node
|
63
|
+
def type; :FCALL; end
|
64
|
+
def self.match?(node); node.type == :FCALL; end
|
65
|
+
end
|
66
|
+
|
67
|
+
class VCallExp < Node
|
68
|
+
# function call without arguments
|
69
|
+
def type; :VCALL; end
|
70
|
+
def self.match?(node); node.type == :VCALL; end
|
71
|
+
end
|
72
|
+
|
73
|
+
class SuperExp < Node
|
74
|
+
# super or super without arguments
|
75
|
+
def type; :MACCRO_SUPER; end
|
76
|
+
def self.match?(node)
|
77
|
+
node.type == :SUPER || node.type == :ZSUPER
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class YieldExp < Node
|
82
|
+
def type; :YIELD; end
|
83
|
+
def self.match?(node); node.type == :YIELD; end
|
84
|
+
end
|
85
|
+
|
86
|
+
class MatchExp < Node
|
87
|
+
# MATCH: /.../ without `=~` (matches to $_ implicitly)
|
88
|
+
# MATCH2: /.../ =~ "..." (left side)
|
89
|
+
# MATCH3: "..." =~ /.../ (right side)
|
90
|
+
def type; :MACCRO_MATCH; end
|
91
|
+
def self.match?(node)
|
92
|
+
t = node.type
|
93
|
+
t == :MATCH || t == :MATCH2 || t == :MATCH3
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class DefineMethod < Node
|
98
|
+
def type; :DEFN; end
|
99
|
+
def self.match?(node); node.type == :DEFN; end
|
100
|
+
end
|
101
|
+
|
102
|
+
class DefineSingletonMethod < Node
|
103
|
+
def type; :DEFS; end
|
104
|
+
def self.match?(node); node.type == :DEFS; end
|
105
|
+
end
|
106
|
+
|
107
|
+
class Colon2Exp < Node
|
108
|
+
def type; :COLON2; end
|
109
|
+
def self.match?(node); node.type == :COLON2; end
|
110
|
+
end
|
111
|
+
|
112
|
+
class Colon3Exp < Node
|
113
|
+
# top level reference (::A)
|
114
|
+
def type; :COLON3; end
|
115
|
+
def self.match?(node); node.type == :COLON3; end
|
116
|
+
end
|
117
|
+
|
118
|
+
class Dot2Exp < Node
|
119
|
+
# range constructor (inclusive)
|
120
|
+
def type; :DOT2; end
|
121
|
+
def self.match?(node); node.type == :DOT2; end
|
122
|
+
end
|
123
|
+
|
124
|
+
class Dot3Exp < Node
|
125
|
+
# range constructor (exclusive)
|
126
|
+
def type; :DOT3; end
|
127
|
+
def self.match?(node); node.type == :DOT3; end
|
128
|
+
end
|
129
|
+
|
130
|
+
class Flip2Exp < Node
|
131
|
+
# flip-flop (inclusive)
|
132
|
+
def type; :FLIP2; end
|
133
|
+
def self.match?(node); node.type == :FLIP2; end
|
134
|
+
end
|
135
|
+
|
136
|
+
class Flip3Exp < Node
|
137
|
+
# flip-flop (exclusive)
|
138
|
+
def type; :FLIP3; end
|
139
|
+
def self.match?(node); node.type == :FLIP3; end
|
140
|
+
end
|
141
|
+
|
142
|
+
class DefinedExp < Node
|
143
|
+
def type; :DEFINED; end
|
144
|
+
def self.match?(node); node.type == :DEFINED; end
|
145
|
+
end
|
146
|
+
|
147
|
+
class Expression < Node
|
148
|
+
SUB_TYPES = [
|
149
|
+
Value, Assignment,
|
150
|
+
IfExp, UnlessExp, CaseExp,
|
151
|
+
# BeginExp, RescueExp,
|
152
|
+
AndExp, OrExp,
|
153
|
+
CallExp, OperatorCallExp, SafeCallExp, FunctionCallExp, VCallExp,
|
154
|
+
SuperExp, YieldExp,
|
155
|
+
MatchExp,
|
156
|
+
DefineMethod, DefineSingletonMethod,
|
157
|
+
Colon2Exp, Colon3Exp, Dot2Exp, Dot3Exp, Flip2Exp, Flip3Exp,
|
158
|
+
DefinedExp,
|
159
|
+
].freeze
|
160
|
+
|
161
|
+
def self.match?(node)
|
162
|
+
SUB_TYPES.any?{|s| s.match?(node) }
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require_relative "node"
|
2
|
+
|
3
|
+
module Maccro
|
4
|
+
module DSL
|
5
|
+
class Literal < Node
|
6
|
+
# integer, float, symbol, regex, ...
|
7
|
+
def type; :LIT; end
|
8
|
+
def self.match?(node); node.type == :LIT; end
|
9
|
+
end
|
10
|
+
|
11
|
+
class DSymbol < Node
|
12
|
+
# symbol with string interpolation
|
13
|
+
def type; :DSYM; end
|
14
|
+
def self.match?(node); node.type == :DSYM; end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Symbol < Node
|
18
|
+
def type; :LIT; end
|
19
|
+
def self.match?(node)
|
20
|
+
(node.type == :LIT && node.children[0].is_a?(::Symbol)) || DSymbol.match?(node)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Number < Node
|
25
|
+
def type; :LIT; end
|
26
|
+
def self.match?(node)
|
27
|
+
node.type == :LIT && node.children[0].is_a?(::Numeric)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class RegexpCompiledOnce < Node
|
32
|
+
# regex with RE_OPTION_ONCE (see new_regexp() in parse.y)
|
33
|
+
def type; :ONCE; end
|
34
|
+
def self.match?(node); node.type == :ONCE; end
|
35
|
+
end
|
36
|
+
|
37
|
+
class DRegexp < Node
|
38
|
+
# regex with string interpolation
|
39
|
+
def type; :DREGX; end
|
40
|
+
def self.match?(node); node.type == :DREGX; end
|
41
|
+
end
|
42
|
+
|
43
|
+
class RegularExpression < Node
|
44
|
+
def type; :LIT; end
|
45
|
+
def self.match?(node)
|
46
|
+
node.type == :LIT && node.children[0].is_a?(Regexp)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class FString < Node
|
51
|
+
# string literal without interpolation
|
52
|
+
def type; :STR; end
|
53
|
+
def self.match?(node); node.type == :STR; end
|
54
|
+
end
|
55
|
+
|
56
|
+
class DString < Node
|
57
|
+
# string literal with interpolation ?
|
58
|
+
def type; :DSTR; end
|
59
|
+
def self.match?(node); node.type == :DSTR; end
|
60
|
+
end
|
61
|
+
|
62
|
+
class XString < Node
|
63
|
+
# string from back quote: `...`
|
64
|
+
# is it a literal?
|
65
|
+
def type; :XSTR; end
|
66
|
+
def self.match?(node); node.type == :XSTR; end
|
67
|
+
end
|
68
|
+
|
69
|
+
class DXString < Node
|
70
|
+
# string from back quote with string interpolation: `... #{..} ...`
|
71
|
+
# is it a literal?
|
72
|
+
def type; :DXSTR; end
|
73
|
+
def self.match?(node); node.type == :DXSTR; end
|
74
|
+
end
|
75
|
+
|
76
|
+
class String < Node
|
77
|
+
SUB_TYPES = [FString, DString, XString, DXString].freeze
|
78
|
+
|
79
|
+
def type; :MACCRO_STRING; end
|
80
|
+
|
81
|
+
def self.match?(node)
|
82
|
+
SUB_TYPES.any?{|s| s.match?(node) }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class NilValue < Node
|
87
|
+
def type; :NIL; end
|
88
|
+
def self.match?(node); node.type == :NIL; end
|
89
|
+
end
|
90
|
+
|
91
|
+
class TrueValue < Node
|
92
|
+
def type; :TRUE; end
|
93
|
+
def self.match?(node); node.type == :TRUE; end
|
94
|
+
end
|
95
|
+
|
96
|
+
class FalseValue < Node
|
97
|
+
def type; :FALSE; end
|
98
|
+
def self.match?(node); node.type == :FALSE; end
|
99
|
+
end
|
100
|
+
|
101
|
+
class Lambda < Node
|
102
|
+
def type; :LAMBDA; end
|
103
|
+
def self.match?(node); node.type == :LAMBDA; end
|
104
|
+
end
|
105
|
+
|
106
|
+
class Array < Node
|
107
|
+
# ARRAY and ZARRAY
|
108
|
+
def type; :MACCRO_ARRAY; end
|
109
|
+
def self.match?(node)
|
110
|
+
node.type == :ARRAY || node.type == :ZARRAY
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class Hash < Node
|
115
|
+
# HASH may be a hash literal, or keyword argument assignment `"a: 1" of f(a: 1)`
|
116
|
+
# HASH(nd_alen == 0) is a keyword argument assignment, but no way to get it via AST::Node
|
117
|
+
def type; :HASH; end
|
118
|
+
def self.match?(node); node.type == :HASH; end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require_relative '../code_range'
|
2
|
+
|
3
|
+
module Maccro
|
4
|
+
module DSL
|
5
|
+
module ASTNodeWrapper
|
6
|
+
def children
|
7
|
+
@child_nodes ||= super
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_code_range
|
11
|
+
CodeRange.from_node(self)
|
12
|
+
end
|
13
|
+
|
14
|
+
def match?(node)
|
15
|
+
return false unless node.is_a?(ASTNodeWrapper)
|
16
|
+
return false if node.type != self.type
|
17
|
+
self.children.each_with_index do |c, i|
|
18
|
+
if c.is_a?(ASTNodeWrapper)
|
19
|
+
return false unless c.match?(node.children[i])
|
20
|
+
else
|
21
|
+
return false unless c == node.children[i]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
# same type, all children match with others
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def capture(ast, placeholders)
|
29
|
+
self.children.each_with_index do |c, i|
|
30
|
+
if c.is_a?(ASTNodeWrapper)
|
31
|
+
c.capture(ast.children[i], placeholders)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Node
|
38
|
+
attr_reader :name, :first_lineno, :first_column, :last_lineno, :last_column
|
39
|
+
|
40
|
+
include ASTNodeWrapper
|
41
|
+
|
42
|
+
def initialize(name, code_range)
|
43
|
+
@name = name
|
44
|
+
@code_range = code_range
|
45
|
+
@first_lineno = code_range.first_lineno
|
46
|
+
@first_column = code_range.first_column
|
47
|
+
@last_lineno = code_range.last_lineno
|
48
|
+
@last_column = code_range.last_column
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_code_range
|
52
|
+
@code_range
|
53
|
+
end
|
54
|
+
|
55
|
+
def type
|
56
|
+
:MACCRO_NODE
|
57
|
+
end
|
58
|
+
|
59
|
+
def children
|
60
|
+
[]
|
61
|
+
end
|
62
|
+
|
63
|
+
def match?(node)
|
64
|
+
# literals are not Node in any cases
|
65
|
+
return false unless node.respond_to?(:type)
|
66
|
+
|
67
|
+
if self.class.respond_to?(:match?)
|
68
|
+
self.class.match?(node)
|
69
|
+
else
|
70
|
+
super
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def capture(ast, placeholders)
|
75
|
+
placeholders[@name] = ast.to_code_range
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class AnyNode < Node
|
80
|
+
def match?(node)
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
def capture(ast, placeholders)
|
85
|
+
placeholders[:__target__] = ast
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|