interscript 2.1.0b4 → 2.1.0rc4

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -0
  3. data/Rakefile +9 -1
  4. data/bin/console +4 -8
  5. data/interscript.gemspec +2 -1
  6. data/lib/interscript.rb +78 -0
  7. data/lib/interscript/compiler/javascript.rb +6 -1
  8. data/lib/interscript/compiler/ruby.rb +5 -0
  9. data/lib/interscript/detector.rb +60 -0
  10. data/lib/interscript/dsl.rb +35 -2
  11. data/lib/interscript/dsl/document.rb +2 -1
  12. data/lib/interscript/dsl/group.rb +7 -6
  13. data/lib/interscript/dsl/group/parallel.rb +2 -2
  14. data/lib/interscript/dsl/tests.rb +2 -2
  15. data/lib/interscript/interpreter.rb +5 -1
  16. data/lib/interscript/node.rb +4 -0
  17. data/lib/interscript/node/alias_def.rb +6 -0
  18. data/lib/interscript/node/dependency.rb +16 -0
  19. data/lib/interscript/node/document.rb +34 -0
  20. data/lib/interscript/node/group.rb +13 -2
  21. data/lib/interscript/node/item.rb +4 -0
  22. data/lib/interscript/node/item/alias.rb +12 -0
  23. data/lib/interscript/node/item/any.rb +7 -0
  24. data/lib/interscript/node/item/capture.rb +11 -0
  25. data/lib/interscript/node/item/group.rb +29 -1
  26. data/lib/interscript/node/item/repeat.rb +4 -0
  27. data/lib/interscript/node/item/stage.rb +4 -0
  28. data/lib/interscript/node/item/string.rb +7 -0
  29. data/lib/interscript/node/metadata.rb +10 -0
  30. data/lib/interscript/node/rule.rb +3 -0
  31. data/lib/interscript/node/rule/funcall.rb +12 -2
  32. data/lib/interscript/node/rule/run.rb +16 -3
  33. data/lib/interscript/node/rule/sub.rb +165 -4
  34. data/lib/interscript/node/stage.rb +30 -4
  35. data/lib/interscript/node/tests.rb +10 -0
  36. data/lib/interscript/stdlib.rb +45 -3
  37. data/lib/interscript/utils/helpers.rb +39 -0
  38. data/lib/interscript/version.rb +1 -1
  39. data/lib/interscript/visualize/json.rb +12 -4
  40. metadata +17 -1
@@ -4,6 +4,10 @@ class Interscript::Node
4
4
  raise NotImplementedError, "You can't construct a Node directly"
5
5
  end
6
6
 
7
+ def ==(other)
8
+ self.class == other.class
9
+ end
10
+
7
11
  def to_hash
8
12
  { :class => self.class.to_s,
9
13
  :question => "is something missing?"
@@ -7,6 +7,12 @@ class Interscript::Node::AliasDef < Interscript::Node
7
7
  @data = data
8
8
  end
9
9
 
10
+ def ==(other)
11
+ super &&
12
+ self.name == other.name &&
13
+ self.data == other.data
14
+ end
15
+
10
16
  def to_hash
11
17
  { :class => self.class.to_s,
12
18
  :name => @name,
@@ -4,6 +4,22 @@ class Interscript::Node::Dependency < Interscript::Node
4
4
  def initialize
5
5
  end
6
6
 
7
+ def reverse
8
+ rdep = self.class.new
9
+ rdep.name = name
10
+ rdep.full_name = Interscript::Node::Document.reverse_name(full_name)
11
+ rdep.import = import
12
+ rdep.document = document&.reverse
13
+ rdep
14
+ end
15
+
16
+ def ==(other)
17
+ super &&
18
+ self.full_name == other.full_name &&
19
+ self.import == other.import &&
20
+ self.name == other.name
21
+ end
22
+
7
23
  def to_hash
8
24
  { :class => self.class.to_s,
9
25
  :name => @name,
@@ -1,6 +1,7 @@
1
1
  class Interscript::Node::Document
2
2
  attr_accessor :metadata, :tests, :name
3
3
  attr_accessor :dependencies, :aliases, :stages, :dep_aliases
4
+ attr_accessor :reversed_from
4
5
 
5
6
  def initialize
6
7
  puts "Interscript::Node::Document.new " if $DEBUG
@@ -34,6 +35,39 @@ class Interscript::Node::Document
34
35
  end
35
36
  end
36
37
 
38
+ def reverse
39
+ @reverse ||= self.class.new.tap do |rdoc|
40
+ rdoc.name = self.class.reverse_name(name)
41
+ rdoc.metadata = metadata&.reverse
42
+ rdoc.tests = tests&.reverse
43
+ rdoc.dependencies = dependencies.map(&:reverse)
44
+ rdoc.stages = stages.transform_values(&:reverse)
45
+ rdoc.dep_aliases = dep_aliases.transform_values(&:reverse)
46
+ rdoc.aliases = aliases
47
+ end
48
+ end
49
+
50
+ def self.reverse_name(name)
51
+ newname = (name || "noname").split("-")
52
+ newname[2], newname[3] = newname[3], newname[2] if newname.length >= 4
53
+ newname = newname.join("-")
54
+ if newname == name
55
+ newname.gsub!("-reverse", "")
56
+ end
57
+ if newname == name
58
+ newname += "-reverse"
59
+ end
60
+ newname
61
+ end
62
+
63
+ def ==(other)
64
+ self.class == other.class &&
65
+ self.metadata == other.metadata &&
66
+ self.tests == other.tests &&
67
+ self.stages == other.stages &&
68
+ self.aliases == other.aliases
69
+ end
70
+
37
71
  def to_hash
38
72
  { :class => self.class.to_s, :metadata => @metadata&.to_hash,
39
73
  :tests => @tests&.to_hash,
@@ -1,7 +1,8 @@
1
1
  class Interscript::Node::Group < Interscript::Node
2
- attr_accessor :children
2
+ attr_accessor :children, :reverse_run
3
3
 
4
- def initialize
4
+ def initialize(reverse_run: nil)
5
+ @reverse_run = reverse_run
5
6
  @children = []
6
7
  end
7
8
 
@@ -20,11 +21,21 @@ class Interscript::Node::Group < Interscript::Node
20
21
  self
21
22
  end
22
23
 
24
+ def reverse
25
+ self.class.new(reverse_run: reverse_run.nil? ? nil : !reverse_run).tap do |r|
26
+ r.children = self.children.reverse.map(&:reverse)
27
+ end
28
+ end
29
+
23
30
  def to_hash
24
31
  { :class => self.class.to_s,
25
32
  :children => @children.map{|x| x.to_hash} }
26
33
  end
27
34
 
35
+ def ==(other)
36
+ super && self.children == other.children && self.reverse_run == other.reverse_run
37
+ end
38
+
28
39
  def inspect
29
40
  @children.map(&:inspect).join("\n").gsub(/^/, " ")
30
41
  end
@@ -36,6 +36,10 @@ class Interscript::Node::Item < Interscript::Node
36
36
  :item => self.item }
37
37
  end
38
38
 
39
+ def ==(other)
40
+ super
41
+ end
42
+
39
43
  def self.try_convert(i)
40
44
  i = Interscript::Node::Item::String.new(i) if i.class == ::String
41
45
  raise TypeError, "Wrong type #{i.class}, expected I::Node::Item" unless Interscript::Node::Item === i
@@ -10,6 +10,10 @@ class Interscript::Node::Item::Alias < Interscript::Node::Item
10
10
  !map && Interscript::Stdlib::ALIASES.has_key?(name)
11
11
  end
12
12
 
13
+ def boundary_like?
14
+ Interscript::Stdlib.boundary_like_alias?(name)
15
+ end
16
+
13
17
  def max_length
14
18
  if stdlib?
15
19
  ([:none].include? name) ? 0 : 1
@@ -19,6 +23,10 @@ class Interscript::Node::Item::Alias < Interscript::Node::Item
19
23
  end
20
24
  end
21
25
 
26
+ # Not implemented properly
27
+ def downcase; self; end
28
+ def upcase; self; end
29
+
22
30
  def first_string
23
31
  self
24
32
  end
@@ -32,6 +40,10 @@ class Interscript::Node::Item::Alias < Interscript::Node::Item
32
40
  }
33
41
  end
34
42
 
43
+ def ==(other)
44
+ super && self.name == other.name && self.map == other.map
45
+ end
46
+
35
47
  def inspect
36
48
  if map
37
49
  "map.#{map}.#{name}"
@@ -25,6 +25,9 @@ class Interscript::Node::Item::Any < Interscript::Node::Item
25
25
  end
26
26
  end
27
27
 
28
+ def downcase; self.class.new(self.data.map(&:downcase)); end
29
+ def upcase; self.class.new(self.data.map(&:upcase)); end
30
+
28
31
  def first_string
29
32
  case @value
30
33
  when Array
@@ -70,6 +73,10 @@ class Interscript::Node::Item::Any < Interscript::Node::Item
70
73
  hash
71
74
  end
72
75
 
76
+ def ==(other)
77
+ super && self.data == other.data
78
+ end
79
+
73
80
  def inspect
74
81
  "any(#{value.inspect})"
75
82
  end
@@ -15,11 +15,18 @@ class Interscript::Node::Item::CaptureGroup < Interscript::Node::Item
15
15
  data.nth_string
16
16
  end
17
17
 
18
+ def downcase; self.dup.tap { |i| i.data = i.data.downcase }; end
19
+ def upcase; self.dup.tap { |i| i.data = i.data.upcase }; end
20
+
18
21
  def to_hash
19
22
  { :class => self.class.to_s,
20
23
  :data => self.data.to_hash }
21
24
  end
22
25
 
26
+ def ==(other)
27
+ super && self.data == other.data
28
+ end
29
+
23
30
  def inspect
24
31
  "capture(#{@data.inspect})"
25
32
  end
@@ -44,6 +51,10 @@ class Interscript::Node::Item::CaptureRef < Interscript::Node::Item
44
51
  :id => self.id }
45
52
  end
46
53
 
54
+ def ==(other)
55
+ super && self.id == other.id
56
+ end
57
+
47
58
  def inspect
48
59
  "ref(#{@id.inspect})"
49
60
  end
@@ -10,11 +10,35 @@ class Interscript::Node::Item::Group < Interscript::Node::Item
10
10
  def +(item)
11
11
  item = Interscript::Node::Item.try_convert(item)
12
12
  out = self.dup
13
- out.children << item
13
+ if Interscript::Node::Item::Group === item
14
+ out.children += item.children
15
+ else
16
+ out.children << item
17
+ end
14
18
  out.verify!
15
19
  out
16
20
  end
17
21
 
22
+ def compact
23
+ out = self.dup do |n|
24
+ n.children = n.children.reject do |i|
25
+ (Interscript::Node::Alias === i && i.name == :none) ||
26
+ (Interscript::Node::String === i && i.data == "")
27
+ end
28
+ end
29
+
30
+ if out.children.count == 0
31
+ Interscript::Node::Alias.new(:none)
32
+ elsif out.children.count == 1
33
+ out.children.first
34
+ else
35
+ out
36
+ end
37
+ end
38
+
39
+ def downcase; self.dup.tap { |i| i.children = i.children.map(&:downcase) }; end
40
+ def upcase; self.dup.tap { |i| i.children = i.children.map(&:upcase) }; end
41
+
18
42
  # Verify if a group is valid
19
43
  def verify!
20
44
  wrong = @children.find do |i|
@@ -45,6 +69,10 @@ class Interscript::Node::Item::Group < Interscript::Node::Item
45
69
  :children => self.children.map{|x| x.to_hash} }
46
70
  end
47
71
 
72
+ def ==(other)
73
+ super && self.children == other.children
74
+ end
75
+
48
76
  def inspect
49
77
  @children.map(&:inspect).join("+")
50
78
  end
@@ -22,6 +22,10 @@ class Interscript::Node::Item::Repeat < Interscript::Node::Item
22
22
  :data => self.data.to_hash }
23
23
  end
24
24
 
25
+ def ==(other)
26
+ super && self.data == other.data
27
+ end
28
+
25
29
  def inspect
26
30
  str = case self
27
31
  when Interscript::Node::Item::Maybe
@@ -13,6 +13,10 @@ class Interscript::Node::Item::Stage < Interscript::Node::Item
13
13
  }
14
14
  end
15
15
 
16
+ def ==(other)
17
+ super && self.name == other.name && self.map == other.map
18
+ end
19
+
16
20
  def inspect
17
21
  if map
18
22
  "map.#{@map}.stage.#{@name}"
@@ -17,6 +17,9 @@ class Interscript::Node::Item::String < Interscript::Node::Item
17
17
  self.data
18
18
  end
19
19
 
20
+ def downcase; self.dup.tap { |i| i.data = i.data.downcase }; end
21
+ def upcase; self.dup.tap { |i| i.data = i.data.upcase }; end
22
+
20
23
  alias nth_string first_string
21
24
 
22
25
  def + other
@@ -33,6 +36,10 @@ class Interscript::Node::Item::String < Interscript::Node::Item
33
36
  end
34
37
  end
35
38
 
39
+ def ==(other)
40
+ super && self.data == other.data
41
+ end
42
+
36
43
  def inspect
37
44
  @data.inspect
38
45
  end
@@ -11,6 +11,16 @@ class Interscript::Node::MetaData < Interscript::Node
11
11
  @data[k]
12
12
  end
13
13
 
14
+ def reverse
15
+ self.class.new(data.dup, **{}).tap do |rmd|
16
+ rmd[:source_script], rmd[:destination_script] = rmd[:destination_script], rmd[:source_script]
17
+ end
18
+ end
19
+
20
+ def ==(other)
21
+ super && self.data == other.data
22
+ end
23
+
14
24
  def to_hash
15
25
  {:class => self.class.to_s,
16
26
  :data => @data}
@@ -1,4 +1,7 @@
1
1
  class Interscript::Node::Rule < Interscript::Node
2
+ def ==(other)
3
+ super && self.reverse_run == other.reverse_run
4
+ end
2
5
  end
3
6
 
4
7
  require "interscript/node/rule/sub"
@@ -1,7 +1,8 @@
1
1
  class Interscript::Node::Rule::Funcall < Interscript::Node::Rule
2
- attr_accessor :name, :kwargs
3
- def initialize name, **kwargs
2
+ attr_accessor :name, :kwargs, :reverse_run
3
+ def initialize name, reverse_run: nil, **kwargs
4
4
  @name = name
5
+ @reverse_run = reverse_run
5
6
  @kwargs = kwargs
6
7
  end
7
8
 
@@ -12,6 +13,15 @@ class Interscript::Node::Rule::Funcall < Interscript::Node::Rule
12
13
  }
13
14
  end
14
15
 
16
+ def reverse
17
+ self.class.new(Interscript::Stdlib.reverse_function[@name.to_sym],
18
+ reverse_run: reverse_run.nil? ? nil : !reverse_run, **kwargs)
19
+ end
20
+
21
+ def ==
22
+ super && self.name == other.name && self.kwargs == other.kwargs
23
+ end
24
+
15
25
  def inspect
16
26
  "#{@name} #{kwargs.inspect[1..-2]}"
17
27
  end
@@ -1,7 +1,8 @@
1
1
  class Interscript::Node::Rule::Run < Interscript::Node::Rule
2
- attr_accessor :stage
3
- def initialize stage
2
+ attr_accessor :stage, :reverse_run
3
+ def initialize stage, reverse_run: nil
4
4
  @stage = stage
5
+ @reverse_run = reverse_run
5
6
  end
6
7
 
7
8
  def to_hash
@@ -9,7 +10,19 @@ class Interscript::Node::Rule::Run < Interscript::Node::Rule
9
10
  :stage => self.stage.to_hash }
10
11
  end
11
12
 
13
+ def reverse
14
+ Interscript::Node::Rule::Run.new(stage,
15
+ reverse_run: reverse_run.nil? ? nil : !reverse_run
16
+ )
17
+ end
18
+
19
+ def ==(other)
20
+ super && self.stage == other.stage
21
+ end
22
+
12
23
  def inspect
13
- "run #{@stage.inspect}"
24
+ out = "run #{@stage.inspect}"
25
+ out += ", reverse_run: #{@reverse_run.inspect}" unless reverse_run.nil?
26
+ out
14
27
  end
15
28
  end
@@ -1,12 +1,19 @@
1
1
  class Interscript::Node::Rule::Sub < Interscript::Node::Rule
2
2
  attr_accessor :from, :to
3
3
  attr_accessor :before, :not_before, :after, :not_after
4
+ attr_accessor :reverse_before, :reverse_not_before, :reverse_after, :reverse_not_after
5
+ attr_accessor :reverse_run
4
6
  attr_accessor :priority
5
7
 
6
- def initialize from, to, before: nil, not_before: nil, after: nil, not_after: nil, priority: nil
8
+ def initialize (from, to,
9
+ before: nil, not_before: nil,
10
+ after: nil, not_after: nil,
11
+ priority: nil, reverse_run: nil)
7
12
  self.from = Interscript::Node::Item.try_convert from
8
13
  if to == :upcase
9
14
  self.to = :upcase
15
+ elsif to == :downcase
16
+ self.to = :downcase
10
17
  else
11
18
  self.to = Interscript::Node::Item.try_convert to
12
19
  end
@@ -16,6 +23,8 @@ class Interscript::Node::Rule::Sub < Interscript::Node::Rule
16
23
  #raise TypeError, "Can't supply both before and not_before" if before && not_before
17
24
  #raise TypeError, "Can't supply both after and not_after" if after && not_after
18
25
 
26
+ self.reverse_run = reverse_run
27
+
19
28
  self.before = Interscript::Node::Item.try_convert(before) if before
20
29
  self.after = Interscript::Node::Item.try_convert(after) if after
21
30
  self.not_before = Interscript::Node::Item.try_convert(not_before) if not_before
@@ -37,7 +46,13 @@ class Interscript::Node::Rule::Sub < Interscript::Node::Rule
37
46
  puts params.inspect if $DEBUG
38
47
  hash = { :class => self.class.to_s,
39
48
  :from => self.from.to_hash,
40
- :to => Symbol === self.to ? self.to : self.to.to_hash
49
+ :to => Symbol === self.to ? self.to : self.to.to_hash,
50
+ :reverse_run => self.reverse_run,
51
+ :before => self.before&.to_hash,
52
+ :not_before => self.not_before&.to_hash,
53
+ :after => self.after&.to_hash,
54
+ :not_after => self.not_after&.to_hash,
55
+ :priority => self.priority
41
56
  }
42
57
 
43
58
  hash[:before] = self.before&.to_hash if self.before
@@ -49,19 +64,165 @@ class Interscript::Node::Rule::Sub < Interscript::Node::Rule
49
64
  hash
50
65
  end
51
66
 
67
+ def reverse
68
+ if to == :upcase
69
+ xfrom = from.downcase
70
+ xto = :downcase
71
+ elsif to == :downcase
72
+ xfrom = from.upcase
73
+ xto = :upcase
74
+ else
75
+ xto, xfrom = reverse_transfer(from, to)
76
+ end
77
+
78
+ # A special case: sub "a", "" shouldn't be present in a reverse map
79
+ rrun = self.reverse_run.nil? ? nil : !self.reverse_run
80
+ if rrun.nil? && !has_assertions? &&
81
+ (xfrom == "" ||
82
+ (Interscript::Node::Item::String === xfrom && xfrom.data == '') ||
83
+ (Interscript::Node::Item::Alias === xfrom && xfrom.name == :none)
84
+ )
85
+
86
+ rrun = true
87
+ end
88
+
89
+ Interscript::Node::Rule::Sub.new(xfrom, xto,
90
+ before: before, after: after,
91
+ not_before: not_before, not_after: not_after,
92
+
93
+ reverse_run: rrun,
94
+
95
+ priority: priority ? -priority : nil
96
+ )
97
+ end
98
+
99
+ def has_assertions?
100
+ !!(before || not_before || not_after || after)
101
+ end
102
+
103
+ # Attempt to transfer some references to boundary/line_begin around.
104
+ # Those in general should go into before/after clauses, but for now
105
+ # let's try to get the best compatibility possible. Also, CaptureGroup,
106
+ # CaptureRef need to be shifted around
107
+ def reverse_transfer from, to
108
+ # This part is about moving initial and final boundary like aliases
109
+ case from
110
+ when Interscript::Node::Item::Group
111
+ first = from.children.first
112
+ last = from.children.last
113
+
114
+ if Interscript::Node::Item::Alias === first && first.boundary_like?
115
+ out = Interscript::Node::Item::Group.new + first + to
116
+ to = out.compact
117
+
118
+ from = from.dup.tap do |i|
119
+ i.children = i.children[1..-1]
120
+ end.compact
121
+ end
122
+
123
+ if Interscript::Node::Item::Alias === last && last.boundary_like?
124
+ out = Interscript::Node::Item::Group.new + to + last
125
+ to = out.compact
126
+
127
+ from = from.dup.tap do |i|
128
+ i.children = i.children[0..-2]
129
+ end.compact
130
+ end
131
+ when Interscript::Node::Item::Alias
132
+ if from.boundary_like?
133
+ to = if from.name.to_s.end_with? "_end"
134
+ Interscript::Node::Item::Group.new + to + from
135
+ else
136
+ Interscript::Node::Item::Group.new + from + to
137
+ end
138
+ from = Interscript::Node::Item::Alias.new(:none)
139
+ end
140
+ end
141
+
142
+ # This part is about moving backreferences
143
+ state = {left:[], right:[]}
144
+
145
+ from = reverse_transfer_visit(from, :from, state)
146
+ to = reverse_transfer_visit(to, :to, state)
147
+
148
+ [from, to]
149
+ end
150
+
151
+ private def reverse_transfer_visit(node, type, state)
152
+ node = Interscript::Node::Item.try_convert(node)
153
+
154
+ case node
155
+ when Interscript::Node::Item::Alias
156
+ if node.name == :kor_maybedash
157
+ state[:left] << node
158
+ Interscript::Node::Item::CaptureRef.new(state[:left].length)
159
+ else
160
+ node
161
+ end
162
+ when Interscript::Node::Item::String
163
+ node
164
+ when Interscript::Node::Item::Any
165
+ if Array === node.value
166
+ node.dup.tap do |i|
167
+ i.value = i.value.map { |c| reverse_transfer_visit(c, type, state) }
168
+ end
169
+ else
170
+ node
171
+ end
172
+ when Interscript::Node::Item::Group
173
+ node.dup.tap do |i|
174
+ i.children = i.children.map { |c| reverse_transfer_visit(c, type, state) }
175
+ end
176
+ when Interscript::Node::Item::Repeat
177
+ node.dup.tap do |i|
178
+ i.data = reverse_transfer_visit(i.data, type, state)
179
+ end
180
+ when Interscript::Node::Item::CaptureRef
181
+ if type == :from
182
+ node
183
+ elsif state[:right][node.id]
184
+ node
185
+ else
186
+ state[:right][node.id] = true
187
+ state[:left][node.id - 1] or raise "Capture count doesn't match"
188
+ end
189
+ when Interscript::Node::Item::CaptureGroup
190
+ state[:left] << node
191
+ out = Interscript::Node::Item::CaptureRef.new(state[:left].length)
192
+ reverse_transfer_visit(node.data, type, state) # Visit but don't care
193
+ out
194
+ else
195
+ raise "Type #{node.class} unhandled!"
196
+ end
197
+ end
198
+
199
+ def ==(other)
200
+ super &&
201
+ self.from == other.from &&
202
+ self.to == other.to &&
203
+ self.before == other.before &&
204
+ self.after == other.after &&
205
+ self.not_before == other.not_before &&
206
+ self.not_after == other.not_after &&
207
+ self.priority == other.priority
208
+ end
209
+
52
210
  def inspect
53
211
  out = "sub "
54
212
  params = []
55
213
  params << @from.inspect
56
- if @to == :upcase
57
- params << "upcase"
214
+ if Symbol === @to
215
+ params << @to.to_s
58
216
  else
59
217
  params << @to.inspect
60
218
  end
219
+ params << "reverse_run: #{@reverse_run.inspect}" unless @reverse_run.nil?
220
+
61
221
  params << "before: #{@before.inspect}" if @before
62
222
  params << "after: #{@after.inspect}" if @after
63
223
  params << "not_before: #{@not_before.inspect}" if @not_before
64
224
  params << "not_after: #{@not_after.inspect}" if @not_after
225
+
65
226
  params << "priority: #{@priority.inspect}" if @priority
66
227
  out << params.join(", ")
67
228
  end