Skip to content

Commit 8020b3c

Browse files
author
webdev778
authored
Merge pull request #722 from interscript/reverse
Reversibility
2 parents 7505fa1 + b32a437 commit 8020b3c

37 files changed

+902
-75
lines changed

README.adoc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,27 @@ It is then easy to see the exact differences in rendering between the systems.
108108
diff bgnpcgn-rus-Latn.txt bas-rus-Latn.txt
109109
----
110110

111+
You can also run some maps in reverse (warning: not all maps are made to be reversed),
112+
either by changing an order of character sets in a name (for bas-rus-`Cyrl-Latn`-2017-bss
113+
it would be bas-rus-`Latn-Cyrl`-2017-bss) or appending `-reverse` to their name:
114+
115+
[source,sh]
116+
----
117+
interscript my_jamos.txt \
118+
--system=var-kor-Hang-Hang-jamo-reverse \
119+
--output=my_hangul.txt
120+
----
121+
122+
You can also compose some maps, by joining their names with `|` (similar to how bash
123+
pipe works). For instance:
124+
125+
[source,sh]
126+
----
127+
interscript my_file.txt \
128+
--system='var-map1-Xxxx-Xxxx|var-map2-Xxxx-Xxxx' \
129+
--output=my_output.txt
130+
----
131+
111132
If you use Interscript from the Git repository, you would call the following command
112133
instead of `interscript`:
113134

docs/Integration_with_Ruby_Applications.adoc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,16 @@ output = Interscript.transliterate("bas-rus-Cyrl-Latn-2017-bss",
7070
cache,
7171
compiler: Interscript::Compiler::Ruby)
7272
----
73+
74+
=== Transliterating in reverse
75+
76+
To reverse a given string using a map with a name of a form:
77+
`bas-rus-Cyrl-Latn-2017-bss`, change places for Cyrl and Latn.
78+
79+
To reverse a given string using a map with a name of a form:
80+
`var-swe-Latn-Latn-2021`, append `-reverse` to its name.
81+
82+
Please note: this only works for Ruby implementation. Other implementations
83+
depend on the Ruby implementation for the purpose of compilation. For those,
84+
you need to compile the map using the Ruby implementation, but the name has
85+
to be given according to the above hint.

docs/Interscript_Map_Format.adoc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,47 @@ stage {
418418
When ran against a string `"abcde"`, this stage will produce an output of
419419
`"[a][b][c]de"`.
420420

421+
== Reversibility
422+
423+
Starting with Interscript 2.2 we added reversibility support. In general all
424+
commands, except for metadata (and tests - for now) support a `reverse_run`
425+
keyword. This keyword is `nil` by default, which means, that it's reversible.
426+
(One exception though: `sub` call, if given a `none` as `to`, defaults to
427+
`reverse_run: false`).
428+
429+
`reverse_run: false` means, that the command is only ran in forward.
430+
`reverse_run: true`, on the other hand, means that the command is only ran in
431+
reverse.
432+
433+
Example 1:
434+
435+
[source,ruby]
436+
----
437+
stage {
438+
sub "a", "b", reverse_run: true
439+
sub "c", "d", reverse_run: false
440+
}
441+
----
442+
443+
When ran in forward mode (normal run) on a string "abcde", it gives "abdde".
444+
When ran in reverse mode on a string "abcde", it gives "aacde".
445+
446+
Example 2:
447+
448+
[source,ruby]
449+
----
450+
stage {
451+
parallel {
452+
sub "a", "あ"
453+
sub "o", "お"
454+
sub "i", "い"
455+
}
456+
}
457+
----
458+
459+
When ran in forward mode (normal run) on a string "あおい", it gives "aoi".
460+
When ran in reverse more on a string "aoi", it gives "あおい".
461+
421462
== Ending notes
422463

423464
This document described everything Interscript currently supports, but it is

ruby/Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,6 @@ unless ENV["SKIP_JS"]
2626
end
2727
end
2828

29+
gem 'pry'
30+
2931
gem 'simplecov', require: false, group: :test

ruby/bin/console

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,8 @@
33
require "bundler/setup"
44
require "interscript"
55

6-
# You can add fixtures and/or initialization code here to make experimenting
7-
# with your gem easier. You can also use a different console, if you like.
6+
require "interscript/utils/helpers"
7+
include Interscript::Utils::Helpers
88

9-
# (If you use this, don't forget to add pry to your Gemfile!)
10-
# require "pry"
11-
# Pry.start
12-
13-
require "irb"
14-
IRB.start(__FILE__)
9+
require "pry"
10+
Pry.start

ruby/lib/interscript/compiler/javascript.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def parallel_regexp_compile(subs_hash)
5353

5454
def compile_rule(r, map = @map, wrapper = false)
5555
c = ""
56+
return c if r.reverse_run == true
5657
case r
5758
when Interscript::Node::Stage
5859
c += "map.stages.#{r.name} = function(s) {\n"
@@ -75,6 +76,7 @@ def compile_rule(r, map = @map, wrapper = false)
7576
raise ArgumentError, "Can't parallelize rules with :not_before" if i.not_before
7677
raise ArgumentError, "Can't parallelize rules with :not_after" if i.not_after
7778

79+
next if i.reverse_run == true
7880
a << [compile_item(i.from, map, :par), compile_item(i.to, map, :parstr)]
7981
end
8082
ah = a.hash.abs
@@ -88,7 +90,8 @@ def compile_rule(r, map = @map, wrapper = false)
8890
a = []
8991
Interscript::Stdlib.deterministic_sort_by_max_length(r.children).each do |i|
9092
raise ArgumentError, "Can't parallelize #{i.class}" unless Interscript::Node::Rule::Sub === i
91-
93+
94+
next if i.reverse_run == true
9295
a << [build_regexp(i, map), compile_item(i.to, map, :parstr)]
9396
end
9497
ah = a.hash.abs
@@ -102,6 +105,8 @@ def compile_rule(r, map = @map, wrapper = false)
102105
from = %{"#{build_regexp(r, map).gsub("/", "\\\\/")}"}
103106
if r.to == :upcase
104107
to = 'function(a){return a.toUpperCase();}'
108+
elsif r.to == :downcase
109+
to = 'function(a){return a.toLowerCase();}'
105110
else
106111
to = compile_item(r.to, map, :str)
107112
end

ruby/lib/interscript/compiler/ruby.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def compile(map, debug: false)
4242

4343
def compile_rule(r, map = @map, wrapper = false)
4444
c = ""
45+
return c if r.reverse_run == true
4546
case r
4647
when Interscript::Node::Stage
4748
c += "Interscript::Maps.add_map_stage \"#{@map.name}\", #{r.name.inspect} do |s|\n"
@@ -65,6 +66,7 @@ def compile_rule(r, map = @map, wrapper = false)
6566
raise ArgumentError, "Can't parallelize rules with :not_before" if i.not_before
6667
raise ArgumentError, "Can't parallelize rules with :not_after" if i.not_after
6768

69+
next if i.reverse_run == true
6870
a << [compile_item(i.from, map, :par), compile_item(i.to, map, :parstr)]
6971
end
7072
ah = a.hash.abs
@@ -79,6 +81,7 @@ def compile_rule(r, map = @map, wrapper = false)
7981
Interscript::Stdlib.deterministic_sort_by_max_length(r.children).each do |i|
8082
raise ArgumentError, "Can't parallelize #{i.class}" unless Interscript::Node::Rule::Sub === i
8183

84+
next if i.reverse_run == true
8285
a << [build_regexp(i, map), compile_item(i.to, map, :parstr)]
8386
end
8487
ah = a.hash.abs
@@ -92,6 +95,8 @@ def compile_rule(r, map = @map, wrapper = false)
9295
from = "/#{build_regexp(r, map).gsub("/", "\\\\/")}/"
9396
if r.to == :upcase
9497
to = '&:upcase'
98+
elsif r.to == :downcase
99+
to = '&:downcase'
95100
else
96101
to = compile_item(r.to, map, :str)
97102
end

ruby/lib/interscript/dsl.rb

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,45 @@
22

33
module Interscript::DSL
44
@cache = {}
5-
def self.parse(map_name)
5+
def self.parse(map_name, reverse: true)
66
# map name aliases? here may be a place to wrap it
77

88
return @cache[map_name] if @cache[map_name]
9-
path = Interscript.locate(map_name)
9+
10+
# This is a composition, so let's make a new virtual map
11+
# that calls all maps in a sequence.
12+
if map_name.include? "|"
13+
map_parts = map_name.split("|").map(&:strip)
14+
15+
doc = Interscript::DSL::Document.new(map_name) do
16+
map_parts.each_with_index do |i, idx|
17+
dependency i, as: :"part#{idx}"
18+
end
19+
20+
stage {
21+
map_parts.each_with_index do |i, idx|
22+
run map[:"part#{idx}"].stage.main
23+
end
24+
}
25+
end.node
26+
27+
return @cache[map_name] = doc
28+
end
29+
30+
path = begin
31+
Interscript.locate(map_name)
32+
rescue Interscript::MapNotFoundError => e
33+
# But maybe we called the map in a reversed fashion?
34+
begin
35+
raise e if reverse == false # Protect from an infinite loop
36+
reverse_name = Interscript::Node::Document.reverse_name(map_name)
37+
return @cache[map_name] = parse(reverse_name, reverse: false).reverse
38+
rescue Interscript::MapNotFoundError
39+
raise e
40+
end
41+
end
1042
library = path.end_with?(".iml")
43+
1144
map_name = File.basename(path, ".imp")
1245
map_name = File.basename(map_name, ".iml")
1346

ruby/lib/interscript/dsl/group.rb

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,24 @@ def initialize(&block)
88
self.instance_exec(&block)
99
end
1010

11-
def run(stage)
11+
def run(stage, **kwargs)
1212
if stage.class != Interscript::Node::Item::Stage
1313
raise TypeError, "I::Node::Item::Stage expected, got #{stage.class}"
1414
end
15-
@node.children << Interscript::Node::Rule::Run.new(stage)
15+
@node.children << Interscript::Node::Rule::Run.new(stage, **kwargs)
1616
end
1717

1818
def sub(from, to, **kwargs, &block)
19-
puts "sub(#{from.inspect},#{to}, kargs = #{
20-
kargs.inspect
19+
puts "sub(#{from.inspect},#{to}, kwargs = #{
20+
kwargs.inspect
2121
}) from #{self.inspect}" if $DEBUG
2222

2323
rule = Interscript::Node::Rule::Sub.new(from, to, **kwargs)
2424
@node.children << rule
2525
end
2626

2727
def upcase; :upcase; end
28+
def downcase; :downcase; end
2829

2930
Interscript::Stdlib.available_functions.each do |fun|
3031
define_method fun do |**kwargs|
@@ -35,9 +36,9 @@ def upcase; :upcase; end
3536
end
3637
end
3738

38-
def parallel(&block)
39+
def parallel(**kwargs, &block)
3940
puts "parallel(#{chars.inspect}) from #{self.inspect}" if $DEBUG
40-
group = Interscript::DSL::Group::Parallel.new(&block)
41+
group = Interscript::DSL::Group::Parallel.new(**kwargs, &block)
4142
@node.children << group.node
4243
end
4344
end
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
class Interscript::DSL::Group::Parallel < Interscript::DSL::Group
2-
def initialize(&block)
3-
@node = Interscript::Node::Group::Parallel.new
2+
def initialize(reverse_run: nil, &block)
3+
@node = Interscript::Node::Group::Parallel.new(reverse_run: reverse_run)
44
self.instance_exec(&block)
55
end
66
end

0 commit comments

Comments
 (0)