wlang 0.10.2 → 2.0.0.beta
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.
- data/CHANGELOG.md +3 -121
- data/Gemfile +23 -1
- data/Gemfile.lock +32 -28
- data/LICENCE.md +18 -21
- data/Manifest.txt +4 -5
- data/README.md +100 -174
- data/Rakefile +1 -13
- data/bin/wlang +3 -29
- data/lib/wlang.rb +21 -394
- data/lib/wlang/command.rb +94 -0
- data/lib/wlang/compiler.rb +78 -0
- data/lib/wlang/compiler/autospacing.rb +60 -0
- data/lib/wlang/compiler/dialect_enforcer.rb +91 -0
- data/lib/wlang/compiler/filter.rb +32 -0
- data/lib/wlang/compiler/grammar.citrus +67 -0
- data/lib/wlang/compiler/parser.rb +26 -0
- data/lib/wlang/compiler/proc_call_removal.rb +15 -0
- data/lib/wlang/compiler/static_merger.rb +28 -0
- data/lib/wlang/compiler/strconcat_flattener.rb +25 -0
- data/lib/wlang/compiler/to_ruby_abstraction.rb +22 -0
- data/lib/wlang/compiler/to_ruby_code.rb +55 -0
- data/lib/wlang/dialect.rb +40 -237
- data/lib/wlang/dialect/dispatching.rb +51 -0
- data/lib/wlang/dialect/evaluation.rb +30 -0
- data/lib/wlang/dialect/tags.rb +50 -0
- data/lib/wlang/dummy.rb +32 -0
- data/lib/wlang/html.rb +106 -0
- data/lib/wlang/loader.rb +6 -0
- data/lib/wlang/mustang.rb +90 -0
- data/lib/wlang/scope.rb +57 -0
- data/lib/wlang/scope/binding_scope.rb +18 -0
- data/lib/wlang/scope/object_scope.rb +25 -0
- data/lib/wlang/scope/proxy_scope.rb +18 -0
- data/lib/wlang/scope/root_scope.rb +24 -0
- data/lib/wlang/template.rb +16 -86
- data/lib/wlang/version.rb +9 -8
- data/spec/fixtures/dialect/foobar.rb +31 -0
- data/spec/fixtures/dialect/upcasing.rb +13 -0
- data/spec/fixtures/templates/hello.tpl +1 -0
- data/spec/integration/examples/1-basics.txt +65 -0
- data/spec/integration/examples/2-imperative.txt +51 -0
- data/spec/integration/examples/3-partials.txt +76 -0
- data/spec/integration/examples/4-recursion.txt +16 -0
- data/spec/integration/html/test_ampersand.rb +15 -0
- data/spec/integration/html/test_bang.rb +38 -0
- data/spec/integration/html/test_caret.rb +33 -0
- data/spec/integration/html/test_dollar.rb +16 -0
- data/spec/integration/html/test_greater.rb +23 -0
- data/spec/integration/html/test_modulo.rb +16 -0
- data/spec/integration/html/test_plus.rb +48 -0
- data/spec/integration/html/test_question.rb +33 -0
- data/spec/integration/html/test_sharp.rb +21 -0
- data/spec/integration/html/test_slash.rb +16 -0
- data/spec/integration/html/test_star.rb +37 -0
- data/spec/integration/test_dummy.rb +51 -0
- data/spec/integration/test_examples.rb +29 -0
- data/spec/integration/test_mustang.rb +120 -0
- data/spec/integration/test_readme.rb +56 -0
- data/spec/integration/test_upcasing.rb +22 -0
- data/spec/spec_helper.rb +62 -1
- data/spec/test_wlang.rb +101 -0
- data/spec/unit/compiler/autospacing/test_right_strip.rb +30 -0
- data/spec/unit/compiler/autospacing/test_unindent.rb +30 -0
- data/spec/unit/compiler/test_dialect_enforcer.rb +168 -0
- data/spec/unit/compiler/test_grammar.rb +207 -0
- data/spec/unit/compiler/test_parser.rb +69 -0
- data/spec/unit/compiler/test_proc_call_removal.rb +24 -0
- data/spec/unit/compiler/test_static_merger.rb +29 -0
- data/spec/unit/compiler/test_strconcat_flattener.rb +30 -0
- data/spec/unit/compiler/test_to_ruby_abstraction.rb +59 -0
- data/spec/unit/compiler/test_to_ruby_code.rb +24 -0
- data/spec/unit/dialect/test_compile.rb +52 -0
- data/spec/unit/dialect/test_dispatching.rb +19 -0
- data/spec/unit/dialect/test_evaluate.rb +41 -0
- data/spec/unit/dialect/test_render.rb +33 -0
- data/spec/unit/dialect/test_tags.rb +32 -0
- data/spec/unit/dialect/test_with_scope.rb +18 -0
- data/spec/unit/scope/test_binding_scope.rb +27 -0
- data/spec/unit/scope/test_coerce.rb +22 -0
- data/spec/unit/scope/test_object_scope.rb +38 -0
- data/spec/unit/scope/test_proxy_scope.rb +22 -0
- data/spec/unit/scope/test_root_scope.rb +22 -0
- data/spec/unit/test_assumptions.rb +29 -0
- data/spec/unit/test_scope.rb +57 -0
- data/tasks/debug_mail.rake +42 -45
- data/tasks/gem.rake +22 -17
- data/tasks/spec_test.rake +9 -17
- data/tasks/unit_test.rake +11 -12
- data/tasks/yard.rake +13 -13
- data/wlang.gemspec +36 -32
- data/wlang.noespec +27 -35
- metadata +268 -451
- data/doc/specification/about.rdoc +0 -61
- data/doc/specification/analytics.wtpl +0 -13
- data/doc/specification/dialect.wtpl +0 -14
- data/doc/specification/dialects.wtpl +0 -3
- data/doc/specification/examples.rb +0 -3
- data/doc/specification/glossary.wtpl +0 -14
- data/doc/specification/hosting.rdoc +0 -0
- data/doc/specification/overview.rdoc +0 -116
- data/doc/specification/rulesets.wtpl +0 -87
- data/doc/specification/specification.css +0 -53
- data/doc/specification/specification.html +0 -1690
- data/doc/specification/specification.js +0 -8
- data/doc/specification/specification.wtpl +0 -42
- data/doc/specification/specification.yml +0 -432
- data/doc/specification/symbols.wtpl +0 -16
- data/lib/wlang/dialect_dsl.rb +0 -141
- data/lib/wlang/dialect_loader.rb +0 -74
- data/lib/wlang/dialects/bluecloth_dialect.rb +0 -16
- data/lib/wlang/dialects/coderay_dialect.rb +0 -45
- data/lib/wlang/dialects/hosted_dialect.rb +0 -50
- data/lib/wlang/dialects/plain_text_dialect.rb +0 -69
- data/lib/wlang/dialects/rdoc_dialect.rb +0 -33
- data/lib/wlang/dialects/redcloth_dialect.rb +0 -16
- data/lib/wlang/dialects/ruby_dialect.rb +0 -118
- data/lib/wlang/dialects/sql_dialect.rb +0 -38
- data/lib/wlang/dialects/standard_dialects.rb +0 -181
- data/lib/wlang/dialects/xhtml_dialect.rb +0 -63
- data/lib/wlang/dialects/yaml_dialect.rb +0 -30
- data/lib/wlang/encoder.rb +0 -62
- data/lib/wlang/encoder_set.rb +0 -122
- data/lib/wlang/errors.rb +0 -80
- data/lib/wlang/ext/hash_methodize.rb +0 -13
- data/lib/wlang/ext/string.rb +0 -44
- data/lib/wlang/hash_scope.rb +0 -89
- data/lib/wlang/hosted_language.rb +0 -146
- data/lib/wlang/intelligent_buffer.rb +0 -94
- data/lib/wlang/parser.rb +0 -332
- data/lib/wlang/parser_state.rb +0 -94
- data/lib/wlang/rule.rb +0 -66
- data/lib/wlang/rule_set.rb +0 -106
- data/lib/wlang/rulesets/basic_ruleset.rb +0 -83
- data/lib/wlang/rulesets/buffering_ruleset.rb +0 -115
- data/lib/wlang/rulesets/context_ruleset.rb +0 -111
- data/lib/wlang/rulesets/encoding_ruleset.rb +0 -73
- data/lib/wlang/rulesets/imperative_ruleset.rb +0 -132
- data/lib/wlang/rulesets/ruleset_utils.rb +0 -317
- data/lib/wlang/wlang_command.rb +0 -51
- data/lib/wlang/wlang_command_options.rb +0 -163
- data/spec/basic_object.spec +0 -40
- data/spec/coderay_dialect.spec +0 -8
- data/spec/dialect/apply_post_transform.spec +0 -16
- data/spec/global_extensions.rb +0 -2
- data/spec/hash_scope.spec +0 -76
- data/spec/redcloth_dialect.spec +0 -24
- data/spec/test_all.rb +0 -8
- data/spec/wlang.spec +0 -53
- data/spec/wlang_spec.rb +0 -8
- data/spec/xhtml_dialect.spec +0 -22
- data/tasks/genspec.rake +0 -5
- data/test/blackbox/basic/execution_1.exp +0 -1
- data/test/blackbox/basic/execution_1.tpl +0 -1
- data/test/blackbox/basic/execution_2.exp +0 -1
- data/test/blackbox/basic/execution_2.tpl +0 -1
- data/test/blackbox/basic/execution_3.exp +0 -1
- data/test/blackbox/basic/execution_3.tpl +0 -1
- data/test/blackbox/basic/execution_4.exp +0 -1
- data/test/blackbox/basic/execution_4.tpl +0 -1
- data/test/blackbox/basic/inclusion_1.exp +0 -1
- data/test/blackbox/basic/inclusion_1.tpl +0 -1
- data/test/blackbox/basic/inclusion_2.exp +0 -1
- data/test/blackbox/basic/inclusion_2.tpl +0 -1
- data/test/blackbox/basic/injection_1.exp +0 -1
- data/test/blackbox/basic/injection_1.tpl +0 -1
- data/test/blackbox/basic/injection_2.exp +0 -1
- data/test/blackbox/basic/injection_2.tpl +0 -1
- data/test/blackbox/basic/modulation_1.exp +0 -1
- data/test/blackbox/basic/modulation_1.tpl +0 -1
- data/test/blackbox/basic/modulation_2.exp +0 -1
- data/test/blackbox/basic/modulation_2.tpl +0 -1
- data/test/blackbox/basic/recursive_app_1.exp +0 -1
- data/test/blackbox/basic/recursive_app_1.tpl +0 -1
- data/test/blackbox/basic/recursive_app_2.exp +0 -1
- data/test/blackbox/basic/recursive_app_2.tpl +0 -1
- data/test/blackbox/buffering/data_1.rb +0 -1
- data/test/blackbox/buffering/data_assignment_1.exp +0 -1
- data/test/blackbox/buffering/data_assignment_1.tpl +0 -1
- data/test/blackbox/buffering/data_assignment_2.exp +0 -1
- data/test/blackbox/buffering/data_assignment_2.tpl +0 -1
- data/test/blackbox/buffering/data_assignment_3.exp +0 -1
- data/test/blackbox/buffering/data_assignment_3.tpl +0 -1
- data/test/blackbox/buffering/data_assignment_4.exp +0 -1
- data/test/blackbox/buffering/data_assignment_4.tpl +0 -1
- data/test/blackbox/buffering/input_1.exp +0 -1
- data/test/blackbox/buffering/input_1.tpl +0 -1
- data/test/blackbox/buffering/input_2.exp +0 -1
- data/test/blackbox/buffering/input_2.tpl +0 -1
- data/test/blackbox/buffering/input_3.exp +0 -1
- data/test/blackbox/buffering/input_3.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion.exp +0 -1
- data/test/blackbox/buffering/input_inclusion.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_1.exp +0 -0
- data/test/blackbox/buffering/input_inclusion_1.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_2.exp +0 -1
- data/test/blackbox/buffering/input_inclusion_2.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_3.exp +0 -1
- data/test/blackbox/buffering/input_inclusion_3.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_4.exp +0 -0
- data/test/blackbox/buffering/input_inclusion_4.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_5.exp +0 -1
- data/test/blackbox/buffering/input_inclusion_5.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_6.exp +0 -1
- data/test/blackbox/buffering/input_inclusion_6.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_7.exp +0 -0
- data/test/blackbox/buffering/input_inclusion_7.tpl +0 -1
- data/test/blackbox/buffering/text_1.txt +0 -1
- data/test/blackbox/buffering/wlang.txt +0 -1
- data/test/blackbox/context/assignment_1.exp +0 -1
- data/test/blackbox/context/assignment_1.tpl +0 -1
- data/test/blackbox/context/assignment_2.exp +0 -1
- data/test/blackbox/context/assignment_2.tpl +0 -1
- data/test/blackbox/context/assignment_3.exp +0 -2
- data/test/blackbox/context/assignment_3.tpl +0 -2
- data/test/blackbox/context/assignment_4.exp +0 -1
- data/test/blackbox/context/assignment_4.tpl +0 -1
- data/test/blackbox/context/block_assignment_1.exp +0 -1
- data/test/blackbox/context/block_assignment_1.tpl +0 -1
- data/test/blackbox/context/block_assignment_2.exp +0 -1
- data/test/blackbox/context/block_assignment_2.tpl +0 -1
- data/test/blackbox/context/modulo_assignment_1.exp +0 -1
- data/test/blackbox/context/modulo_assignment_1.tpl +0 -1
- data/test/blackbox/context/modulo_assignment_2.exp +0 -1
- data/test/blackbox/context/modulo_assignment_2.tpl +0 -1
- data/test/blackbox/data_1.rb +0 -1
- data/test/blackbox/postblock/hello.exp +0 -1
- data/test/blackbox/postblock/hello.pre +0 -1
- data/test/blackbox/postblock/hello.tpl +0 -1
- data/test/blackbox/postblock/hello_input_inclusion.exp +0 -1
- data/test/blackbox/postblock/hello_input_inclusion.tpl +0 -1
- data/test/blackbox/postblock/hello_to_authors.exp +0 -1
- data/test/blackbox/postblock/hello_to_authors.tpl +0 -1
- data/test/blackbox/poststring/hello.exp +0 -1
- data/test/blackbox/poststring/hello.tpl +0 -1
- data/test/blackbox/test_all.rb +0 -70
- data/test/standard_dialects/ruby/data.rb +0 -7
- data/test/standard_dialects/ruby/inclusion.exp +0 -6
- data/test/standard_dialects/ruby/inclusion.tpl +0 -6
- data/test/standard_dialects/test_all.rb +0 -29
- data/test/standard_dialects/yaml/assumptions_test.rb +0 -13
- data/test/standard_dialects/yaml/data.rb +0 -3
- data/test/standard_dialects/yaml/inclusion_1.exp +0 -7
- data/test/standard_dialects/yaml/inclusion_1.tpl +0 -2
- data/test/standard_dialects/yaml/inclusion_2.exp +0 -5
- data/test/standard_dialects/yaml/inclusion_2.tpl +0 -3
- data/test/unit/test_all.rb +0 -9
- data/test/unit/wlang/anagram_bugs_test.rb +0 -111
- data/test/unit/wlang/basic_ruleset_test.rb +0 -52
- data/test/unit/wlang/buffering_ruleset_test.rb +0 -102
- data/test/unit/wlang/buffering_template1.wtpl +0 -1
- data/test/unit/wlang/buffering_template2.wtpl +0 -1
- data/test/unit/wlang/buffering_template3.wtpl +0 -1
- data/test/unit/wlang/buffering_template4.wtpl +0 -1
- data/test/unit/wlang/buffering_template5.wtpl +0 -1
- data/test/unit/wlang/context_ruleset_test.rb +0 -32
- data/test/unit/wlang/data.rb +0 -3
- data/test/unit/wlang/encoder_set_test.rb +0 -42
- data/test/unit/wlang/imperative_ruleset_test.rb +0 -107
- data/test/unit/wlang/intelligent_buffer_test.rb +0 -194
- data/test/unit/wlang/othersymbols_test.rb +0 -16
- data/test/unit/wlang/parser_test.rb +0 -88
- data/test/unit/wlang/plain_text_dialect_test.rb +0 -21
- data/test/unit/wlang/ruby_dialect_test.rb +0 -100
- data/test/unit/wlang/ruby_expected.rb +0 -3
- data/test/unit/wlang/ruby_template.wrb +0 -3
- data/test/unit/wlang/ruleset_utils_test.rb +0 -245
- data/test/unit/wlang/specification_examples_test.rb +0 -54
- data/test/unit/wlang/test_utils.rb +0 -25
- data/test/unit/wlang/wlang_test.rb +0 -80
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module WLang
|
|
2
|
+
class Compiler
|
|
3
|
+
class StaticMerger < Filter
|
|
4
|
+
|
|
5
|
+
def on_strconcat(*exps)
|
|
6
|
+
result = [:strconcat]
|
|
7
|
+
text = nil
|
|
8
|
+
|
|
9
|
+
exps.each do |exp|
|
|
10
|
+
if exp.first == :static
|
|
11
|
+
if text
|
|
12
|
+
text << exp.last
|
|
13
|
+
else
|
|
14
|
+
text = exp.last.dup
|
|
15
|
+
result << [:static, text]
|
|
16
|
+
end
|
|
17
|
+
else
|
|
18
|
+
result << compile(exp)
|
|
19
|
+
text = nil
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
result
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end # class StaticMerger
|
|
27
|
+
end # class Compiler
|
|
28
|
+
end # module WLang
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module WLang
|
|
2
|
+
class Compiler
|
|
3
|
+
class StrconcatFlattener < Filter
|
|
4
|
+
|
|
5
|
+
def on_strconcat(*children)
|
|
6
|
+
if children.size == 1
|
|
7
|
+
call(children.first)
|
|
8
|
+
else
|
|
9
|
+
children.inject [:strconcat] do |rw,child|
|
|
10
|
+
child = call(child)
|
|
11
|
+
if child.first == :strconcat
|
|
12
|
+
child[1..-1].each do |subchild|
|
|
13
|
+
rw << subchild
|
|
14
|
+
end
|
|
15
|
+
else
|
|
16
|
+
rw << child
|
|
17
|
+
end
|
|
18
|
+
rw
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end # class StrconcatFlattener
|
|
24
|
+
end # class Compiler
|
|
25
|
+
end # module WLang
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module WLang
|
|
2
|
+
class Compiler
|
|
3
|
+
class ToRubyAbstraction < Filter
|
|
4
|
+
|
|
5
|
+
def on_strconcat(*cases)
|
|
6
|
+
[:multi] + cases.map{|c| call(c)}
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def on_fn(code)
|
|
10
|
+
[:proc, call(code)]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def on_wlang(symbols, *fns)
|
|
14
|
+
meth = Dialect.tag_dispatching_name(symbols)
|
|
15
|
+
fns.inject [:dispatch, meth] do |rw, fn|
|
|
16
|
+
rw << call(fn)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end # class ToRubyAbstraction
|
|
21
|
+
end # class Compiler
|
|
22
|
+
end # module WLang
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module WLang
|
|
2
|
+
class Compiler
|
|
3
|
+
class ToRubyCode < Temple::Generator
|
|
4
|
+
|
|
5
|
+
class IdGen
|
|
6
|
+
def initialize; @current = 0; end
|
|
7
|
+
def next; @current += 1; end
|
|
8
|
+
def to_s; @current.to_s; end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def idgen
|
|
12
|
+
options[:idgen] ? options[:idgen] : (@idgen ||= IdGen.new)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def myid
|
|
16
|
+
options[:myid] || 0
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call(x)
|
|
20
|
+
compile(x)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def on_template(fn)
|
|
24
|
+
call(fn)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def on_dispatch(meth, *procs)
|
|
28
|
+
procs = procs.map{|p| call(p)}.join(', ')
|
|
29
|
+
"d#{myid}.#{meth}(b#{myid}, #{procs})"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def on_arg(code)
|
|
33
|
+
code.inspect
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def on_modulo(dialect, fn)
|
|
37
|
+
if fn.first == :arg
|
|
38
|
+
call(fn)
|
|
39
|
+
else
|
|
40
|
+
id = idgen.next
|
|
41
|
+
code = call(fn)
|
|
42
|
+
"Proc.new{|d#{id},b#{id}| #{code}.call(#{dialect}.factor(d#{id}.options), b#{id}) }"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def on_proc(code)
|
|
47
|
+
id = idgen.next
|
|
48
|
+
gen = ToRubyCode.new(:buffer => "b#{id}", :idgen => idgen, :myid => id)
|
|
49
|
+
code = gen.call(code)
|
|
50
|
+
"Proc.new{|d#{id},b#{id}| #{code} }"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end # class ToRubyCode
|
|
54
|
+
end # class Compiler
|
|
55
|
+
end # module WLang
|
data/lib/wlang/dialect.rb
CHANGED
|
@@ -1,250 +1,53 @@
|
|
|
1
|
-
require 'wlang/
|
|
2
|
-
require 'wlang/
|
|
1
|
+
require 'wlang/dialect/dispatching'
|
|
2
|
+
require 'wlang/dialect/evaluation'
|
|
3
|
+
require 'wlang/dialect/tags'
|
|
3
4
|
module WLang
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
# Implements the _dialect_ abstraction (see {README}[link://files/README.rdoc]).
|
|
7
|
-
# A dialect instance is an aggregation of encoders and ruleset (through EncoderSet
|
|
8
|
-
# and RuleSet classes). A dialect is also a node in the dialect tree and has a
|
|
9
|
-
# qualified name through this tree. For example <tt>wlang/xhtml</tt> is the
|
|
10
|
-
# qualified name of a <tt>xhtml</tt> dialect which is a child dialect of
|
|
11
|
-
# <tt>wlang</tt>.
|
|
12
|
-
#
|
|
13
|
-
# Users are not intended to use this class directly. Use the Domain Specific
|
|
14
|
-
# Language instead (see WLang::Dialect::DSL).
|
|
15
|
-
#
|
|
16
|
-
# === For developers only
|
|
17
|
-
#
|
|
18
|
-
# In order to avoid having users to install all required gems of all dialects
|
|
19
|
-
# wlang implements a lazy load design pattern on the dialect tree, through the
|
|
20
|
-
# WLang::Dialect::DSL and WLang::Dialect::Loader classes. The former only creates
|
|
21
|
-
# Dialect instances as tree nodes (by chaining dialects through @parent) and
|
|
22
|
-
# installs mapping with file extensions. Rules and encoders are not initially
|
|
23
|
-
# installed (precisely: WLang::Dialect::DSL#require_ruby is simply ignored).
|
|
24
|
-
# When a given dialect is needed by wlang it is first built (through the build!
|
|
25
|
-
# method and the WLang::Dialect::Loader class).
|
|
26
|
-
#
|
|
27
|
-
# Standard dialect obtention methods (WLang#dialect as well as WLang::Dialect#dialect)
|
|
28
|
-
# ensure that returned dialects are built. If you obtain dialects another way,
|
|
29
|
-
# be sure that they are built before using them (is_built? and build! are your
|
|
30
|
-
# friends to achieve that goal).
|
|
31
|
-
#
|
|
32
|
-
# Moreover, child dialects may require tools of their ancestors. The following
|
|
33
|
-
# invariant should always be respected: if a dialect is built, all its ancestors
|
|
34
|
-
# are built as well. This invariant is not enforced by the build! method because
|
|
35
|
-
# it is trivially respected by the way WLang::Dialect#dialect is implemented.
|
|
36
|
-
#
|
|
37
5
|
class Dialect
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# Underlying encoders
|
|
43
|
-
attr_reader :encoders
|
|
6
|
+
include Dialect::Dispatching
|
|
7
|
+
include Dialect::Evaluation
|
|
8
|
+
include Dialect::Tags
|
|
44
9
|
|
|
45
|
-
|
|
46
|
-
attr_reader :name
|
|
47
|
-
|
|
48
|
-
# Parent dialect
|
|
49
|
-
attr_reader :parent
|
|
50
|
-
|
|
51
|
-
# Sub dialects by name
|
|
52
|
-
attr_reader :dialects
|
|
53
|
-
|
|
54
|
-
# Post transformer
|
|
55
|
-
attr_accessor :post_transformer
|
|
56
|
-
|
|
57
|
-
#
|
|
58
|
-
# Creates a dialect instance. _builder_ block is a chunk of code of the DSL
|
|
59
|
-
# that will be executed twice: once at construction time to create sub dialects
|
|
60
|
-
# nodes and install file extensions and once at building time to install ruleset
|
|
61
|
-
# and encoders.
|
|
62
|
-
#
|
|
63
|
-
def initialize(name, parent, &builder)
|
|
64
|
-
@name, @parent = name, parent
|
|
65
|
-
@builder, @built = builder, builder.nil?
|
|
66
|
-
@dialects = nil
|
|
67
|
-
@encoders = nil
|
|
68
|
-
@ruleset = nil
|
|
69
|
-
DSL.new(self).instance_eval(&builder) unless builder.nil?
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
### Lazy load mechanism ######################################################
|
|
73
|
-
|
|
74
|
-
#
|
|
75
|
-
# Force the dialect to be built. Has no effect if it is already built. Invokes
|
|
76
|
-
# the DSL chunk of code through WLang::DSL::Loader otherwise.
|
|
77
|
-
#
|
|
78
|
-
def build!
|
|
79
|
-
unless is_built?
|
|
80
|
-
WLang::Dialect::Loader.new(self).instance_eval(&@builder)
|
|
81
|
-
@built = true
|
|
82
|
-
end
|
|
83
|
-
self
|
|
84
|
-
end
|
|
10
|
+
class << self
|
|
85
11
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return @built
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
### Installation #############################################################
|
|
93
|
-
|
|
94
|
-
#
|
|
95
|
-
# Adds a child dialect under _name_. _name_ cannot be qualified and must be a
|
|
96
|
-
# valid dialect name according to the wlang specification (see WLang::DIALECT_NAME_REGEXP).
|
|
97
|
-
# _child_ must be a Dialect instance.
|
|
98
|
-
#
|
|
99
|
-
def add_child_dialect(name, child)
|
|
100
|
-
raise(ArgumentError, "Invalid dialect name") unless WLang::DIALECT_NAME_REGEXP =~ name
|
|
101
|
-
raise(ArgumentError, "Dialect expected") unless Dialect===child
|
|
102
|
-
@dialects = {} if @dialects.nil?
|
|
103
|
-
@dialects[name] = child
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# See EncoderSet#add_encoder
|
|
107
|
-
def add_encoder(name, &block)
|
|
108
|
-
@encoders = EncoderSet.new if @encoders.nil?
|
|
109
|
-
@encoders.add_encoder(name, &block)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# See EncoderSet#add_encoders
|
|
113
|
-
def add_encoders(mod, pairs)
|
|
114
|
-
@encoders = EncoderSet.new if @encoders.nil?
|
|
115
|
-
@encoders.add_encoders(mod, pairs)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# See RuleSet::add_rule
|
|
119
|
-
def add_rule(name, &block)
|
|
120
|
-
@ruleset = RuleSet.new if @ruleset.nil?
|
|
121
|
-
@ruleset.add_rule(name, &block)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
# See RuleSet::add_rules
|
|
125
|
-
def add_rules(mod, pairs)
|
|
126
|
-
@ruleset = RuleSet.new if @ruleset.nil?
|
|
127
|
-
@ruleset.add_rules(mod, pairs)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
### Query API ################################################################
|
|
131
|
-
|
|
132
|
-
# Returns qualified name of this dialect
|
|
133
|
-
def qualified_name
|
|
134
|
-
parentname = @parent.nil? ? "" : @parent.to_s
|
|
135
|
-
return ""==parentname ? @name : parentname + '/' + @name
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
#
|
|
139
|
-
# Finds a child dialect by name. _name_ can be a String denoting a qualified
|
|
140
|
-
# name as well as an Array of strings, resulting from a qualified name split.
|
|
141
|
-
# This method should always be invoked on built dialects, it always returns nil
|
|
142
|
-
# otherwise. When found, returned dialect is automatically built as well as all
|
|
143
|
-
# its ancestors. When not found, the method returns nil.
|
|
144
|
-
#
|
|
145
|
-
def dialect(name)
|
|
146
|
-
# implement argument conventions
|
|
147
|
-
if String===name
|
|
148
|
-
raise(ArgumentError, "Invalid dialect name #{name}") unless WLang::QUALIFIED_DIALECT_NAME_REGEXP =~ name
|
|
149
|
-
name = name.split('/')
|
|
150
|
-
elsif not(Array===name)
|
|
151
|
-
raise(ArgumentError,"Invalid dialect name #{name}")
|
|
12
|
+
def factor(options = {})
|
|
13
|
+
new(default_options.merge(options))
|
|
152
14
|
end
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
# get first child name and find it
|
|
158
|
-
child_name = name[0]
|
|
159
|
-
child_dialect = @dialects[child_name]
|
|
160
|
-
|
|
161
|
-
if child_dialect.nil?
|
|
162
|
-
# unexisting, return nil
|
|
163
|
-
return nil
|
|
164
|
-
elsif name.length==1
|
|
165
|
-
# found and last of qualified name -> build it
|
|
166
|
-
return child_dialect.build!
|
|
167
|
-
else
|
|
168
|
-
# found but not last of qualified name -> build it and delegate
|
|
169
|
-
child_dialect.build!
|
|
170
|
-
return child_dialect.dialect(name[1..-1])
|
|
15
|
+
|
|
16
|
+
def default_options(options = {})
|
|
17
|
+
@default_options ||= (superclass.default_options.dup rescue {})
|
|
18
|
+
@default_options.merge!(options)
|
|
171
19
|
end
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
def apply_post_transform(text)
|
|
176
|
-
case self.post_transformer
|
|
177
|
-
when String
|
|
178
|
-
WLang::encode(text, self.post_transformer, {})
|
|
179
|
-
when Proc
|
|
180
|
-
self.post_transformer.call(text)
|
|
181
|
-
else
|
|
182
|
-
text
|
|
20
|
+
|
|
21
|
+
def compiler(options = {})
|
|
22
|
+
factor(options).compiler
|
|
183
23
|
end
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
# Finds an encoder by name.
|
|
188
|
-
#
|
|
189
|
-
def encoder(name)
|
|
190
|
-
# implement argument conventions
|
|
191
|
-
if String===name
|
|
192
|
-
raise(ArgumentError, "Invalid encoder name #{name}") unless WLang::QUALIFIED_ENCODER_NAME_REGEXP =~ name
|
|
193
|
-
name = name.split('/')
|
|
194
|
-
elsif not(Array===name)
|
|
195
|
-
raise(ArgumentError,"Invalid encoder name #{name}")
|
|
24
|
+
|
|
25
|
+
def compile(source, options = {})
|
|
26
|
+
compiler(options).compile(source)
|
|
196
27
|
end
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
# delegate to encoders
|
|
201
|
-
return nil if @encoders.nil?
|
|
202
|
-
return @encoders.get_encoder(name[0])
|
|
203
|
-
else
|
|
204
|
-
# find sub dialect, and delegate
|
|
205
|
-
child_name = name[0]
|
|
206
|
-
child_dialect = dialect(child_name)
|
|
207
|
-
if child_dialect.nil?
|
|
208
|
-
return nil
|
|
209
|
-
else
|
|
210
|
-
return child_dialect.encoder(name[1..-1])
|
|
211
|
-
end
|
|
28
|
+
|
|
29
|
+
def to_ruby_code(source, options = {})
|
|
30
|
+
compiler(options).to_ruby_code(source)
|
|
212
31
|
end
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def find_encoder(name)
|
|
217
|
-
raise(ArgumentError, "Invalid (relative) encoder name #{name}") unless String===name
|
|
218
|
-
raise(ArgumentError, "Invalid (relative) encoder name #{name}") if name.include?("/")
|
|
219
|
-
return nil if @encoders.nil?
|
|
220
|
-
if @encoders.has_encoder?(name)
|
|
221
|
-
@encoders.get_encoder(name)
|
|
222
|
-
elsif @parent
|
|
223
|
-
@parent.find_encoder(name)
|
|
224
|
-
else
|
|
225
|
-
nil
|
|
32
|
+
|
|
33
|
+
def render(source, scope = {}, buffer = "")
|
|
34
|
+
compile(source).call(scope, buffer)
|
|
226
35
|
end
|
|
36
|
+
|
|
227
37
|
end
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
""
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
# Returns a string representation
|
|
244
|
-
def to_s
|
|
245
|
-
qualified_name
|
|
38
|
+
|
|
39
|
+
default_options :braces => WLang::BRACES,
|
|
40
|
+
:autospacing => false
|
|
41
|
+
|
|
42
|
+
attr_reader :options
|
|
43
|
+
def braces; options[:braces]; end
|
|
44
|
+
|
|
45
|
+
attr_reader :compiler
|
|
46
|
+
|
|
47
|
+
def initialize(options = {})
|
|
48
|
+
@options = options
|
|
49
|
+
@compiler = WLang::Compiler.new(self)
|
|
246
50
|
end
|
|
247
|
-
|
|
51
|
+
|
|
248
52
|
end # class Dialect
|
|
249
|
-
|
|
250
|
-
end #module WLang
|
|
53
|
+
end # module WLang
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module WLang
|
|
2
|
+
class Dialect
|
|
3
|
+
module Dispatching
|
|
4
|
+
|
|
5
|
+
module ClassMethods
|
|
6
|
+
|
|
7
|
+
def tag_dispatching_name(symbols, prefix = "_tag")
|
|
8
|
+
symbols = symbols.chars unless symbols.is_a?(Array)
|
|
9
|
+
chars = symbols.map{|s| s.ord}.join("_")
|
|
10
|
+
"#{prefix}_#{chars}".to_sym
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def define_tag_method(symbols, dialects, code)
|
|
16
|
+
rulename = tag_dispatching_name(symbols, "_tag")
|
|
17
|
+
case code
|
|
18
|
+
when Symbol
|
|
19
|
+
module_eval %Q{ alias :#{rulename} #{code} }
|
|
20
|
+
when Proc
|
|
21
|
+
define_method(rulename, code)
|
|
22
|
+
else
|
|
23
|
+
raise "Unable to use #{code} for a tag"
|
|
24
|
+
end
|
|
25
|
+
dialects_info_name = tag_dispatching_name(symbols, "_diatag")
|
|
26
|
+
define_method(dialects_info_name) do dialects end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end # module ClassMethods
|
|
30
|
+
|
|
31
|
+
module InstanceMethods
|
|
32
|
+
|
|
33
|
+
def dialects_for(symbols)
|
|
34
|
+
info = Dialect.tag_dispatching_name(symbols, "_diatag")
|
|
35
|
+
if respond_to?(info)
|
|
36
|
+
send(info)
|
|
37
|
+
else
|
|
38
|
+
raise ArgumentError, "No tag for #{symbols}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end # module InstanceMethods
|
|
43
|
+
|
|
44
|
+
def self.included(mod)
|
|
45
|
+
mod.instance_eval{ include(Dispatching::InstanceMethods) }
|
|
46
|
+
mod.extend(ClassMethods)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end # module Dispatching
|
|
50
|
+
end # class Dialect
|
|
51
|
+
end # module WLang
|