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
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
module WLang
|
|
2
|
-
|
|
3
|
-
# Provides an intelligent output buffer
|
|
4
|
-
class IntelligentBuffer < String
|
|
5
|
-
|
|
6
|
-
# Some string utilities
|
|
7
|
-
module Methods
|
|
8
|
-
|
|
9
|
-
# Aligns _str_ at left offset _n_
|
|
10
|
-
# Credits: Treetop and Facets 2.0.2
|
|
11
|
-
def tabto(str, n)
|
|
12
|
-
if str =~ /^( *)\S/
|
|
13
|
-
indent(str, n - $1.length)
|
|
14
|
-
else
|
|
15
|
-
str
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Positive or negative indentation of _str_
|
|
20
|
-
# Credits: Treetop and Facets 2.0.2
|
|
21
|
-
def indent(str, n)
|
|
22
|
-
if n >= 0
|
|
23
|
-
str.gsub(/^/, ' ' * n)
|
|
24
|
-
else
|
|
25
|
-
str.gsub(/^ {0,#{-n}}/, "")
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Checks if _str_ contains multiple lines
|
|
30
|
-
def is_multiline?(str)
|
|
31
|
-
str =~ /\n/ ? true : false
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
#
|
|
35
|
-
# Strips a multiline block.
|
|
36
|
-
#
|
|
37
|
-
# Example:
|
|
38
|
-
# ([\t ]*\n)?
|
|
39
|
-
# ([\t ]\n)*
|
|
40
|
-
# [\t ]*some text here\n
|
|
41
|
-
# [\t ]* indented also\n?
|
|
42
|
-
# [\t ]*
|
|
43
|
-
#
|
|
44
|
-
# becomes:
|
|
45
|
-
# some text here\n
|
|
46
|
-
# indented also\n
|
|
47
|
-
#
|
|
48
|
-
def strip_block(str)
|
|
49
|
-
match = str.match(/\A[\t ]*\n?/)
|
|
50
|
-
str = match.post_match if match
|
|
51
|
-
match = str.match(/\n[\t ]*\Z/)
|
|
52
|
-
str = (match.pre_match << "\n") if match
|
|
53
|
-
str
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Returns column number of a specific offset
|
|
57
|
-
# Credits: Treetop and Facets 2.0.2
|
|
58
|
-
def column_of(str, index)
|
|
59
|
-
return 1 if index == 0
|
|
60
|
-
newline_index = str.rindex("\n", index - 1)
|
|
61
|
-
if newline_index
|
|
62
|
-
index - newline_index
|
|
63
|
-
else
|
|
64
|
-
index + 1
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Returns the column of the last character
|
|
69
|
-
def last_column(str)
|
|
70
|
-
column_of(str, str.length)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Pushes a string, aligning it first
|
|
74
|
-
def <<(str, block=false)
|
|
75
|
-
if block and is_multiline?(str) and stripped = strip_block(str)
|
|
76
|
-
str = tabto(stripped, last_column(self)-1)
|
|
77
|
-
str = str.match(/\A[\t ]*/).post_match
|
|
78
|
-
end
|
|
79
|
-
super(str)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# WLang explicit appending
|
|
83
|
-
def wlang_append(str, block)
|
|
84
|
-
self.<<(str, block)
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Include utilities
|
|
90
|
-
include Methods
|
|
91
|
-
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
end
|
data/lib/wlang/parser.rb
DELETED
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
require 'stringio'
|
|
2
|
-
require 'wlang/rule'
|
|
3
|
-
require 'wlang/rule_set'
|
|
4
|
-
require 'wlang/errors'
|
|
5
|
-
require 'wlang/template'
|
|
6
|
-
module WLang
|
|
7
|
-
#
|
|
8
|
-
# Parser for wlang templates.
|
|
9
|
-
#
|
|
10
|
-
# This class implements the parsing algorithm of wlang, recognizing special tags
|
|
11
|
-
# and replacing them using installed rules. Instanciating a template is done
|
|
12
|
-
# using instantiate. All other methods (parse, parse_block, has_block?) and the
|
|
13
|
-
# like are callbacks for rules and should not be used by users themselve.
|
|
14
|
-
#
|
|
15
|
-
# == Detailed API
|
|
16
|
-
class Parser
|
|
17
|
-
|
|
18
|
-
# Initializes a parser instance.
|
|
19
|
-
def initialize(hosted, template, scope)
|
|
20
|
-
raise(ArgumentError, "Hosted language is mandatory (a ::WLang::HostedLanguage)") unless ::WLang::HostedLanguage===hosted
|
|
21
|
-
raise(ArgumentError, "Template is mandatory (a ::WLang::Template)") unless ::WLang::Template===template
|
|
22
|
-
raise(ArgumentError, "Scope is mandatory (a Hash)") unless ::Hash===scope
|
|
23
|
-
@state = ::WLang::Parser::State.new(self).branch(
|
|
24
|
-
:hosted => hosted,
|
|
25
|
-
:template => template,
|
|
26
|
-
:dialect => template.dialect,
|
|
27
|
-
:offset => 0,
|
|
28
|
-
:shared => :none,
|
|
29
|
-
:scope => scope,
|
|
30
|
-
:buffer => template.dialect.factor_buffer)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
###################################################################### Facade on the parser state
|
|
34
|
-
|
|
35
|
-
# Returns the current parser state
|
|
36
|
-
def state(); @state; end
|
|
37
|
-
|
|
38
|
-
# Returns the current template
|
|
39
|
-
def template() state.template; end
|
|
40
|
-
|
|
41
|
-
# Returns the current buffer
|
|
42
|
-
def dialect() state.dialect; end
|
|
43
|
-
|
|
44
|
-
# Returns the current template's source text
|
|
45
|
-
def source_text() state.template.source_text; end
|
|
46
|
-
|
|
47
|
-
# Returns the current offset
|
|
48
|
-
def offset() state.offset; end
|
|
49
|
-
|
|
50
|
-
# Sets the current offset of the parser
|
|
51
|
-
def offset=(offset) state.offset = offset; end
|
|
52
|
-
|
|
53
|
-
# Returns the current buffer
|
|
54
|
-
def buffer() state.buffer; end
|
|
55
|
-
|
|
56
|
-
# Returns the current hosted language
|
|
57
|
-
def hosted() state.hosted; end
|
|
58
|
-
|
|
59
|
-
# Branches the current parser
|
|
60
|
-
def branch(opts = {})
|
|
61
|
-
raise ArgumentError, "Parser branching requires a block" unless block_given?
|
|
62
|
-
@state = @state.branch(opts)
|
|
63
|
-
result = yield(@state)
|
|
64
|
-
@state = @state.parent
|
|
65
|
-
result
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
###################################################################### Facade on the file system
|
|
69
|
-
|
|
70
|
-
# Resolves an URI throught the current template
|
|
71
|
-
def file_resolve(uri)
|
|
72
|
-
template.file_resolve(uri)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
###################################################################### Facade on wlang itself
|
|
76
|
-
|
|
77
|
-
# Factors a template instance for a given file
|
|
78
|
-
def file_template(file, dialect = nil, block_symbols = :braces)
|
|
79
|
-
WLang::file_template(file, dialect, block_symbols)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Finds a real dialect instance from an argument (Dialect instance or
|
|
83
|
-
# qualified name)
|
|
84
|
-
def ensure_dialect(dialect)
|
|
85
|
-
if String===dialect
|
|
86
|
-
dname, dialect = dialect, WLang::dialect(dialect)
|
|
87
|
-
raise(ParseError,"Unknown modulation dialect: #{dname}") if dialect.nil?
|
|
88
|
-
elsif not(Dialect===dialect)
|
|
89
|
-
raise(ParseError,"Unknown modulation dialect: #{dialect}")
|
|
90
|
-
end
|
|
91
|
-
dialect
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Finds a real ecoder instance from an argument (Encoder instance or
|
|
95
|
-
# qualified or unqualified name)
|
|
96
|
-
def ensure_encoder(encoder)
|
|
97
|
-
if String===encoder
|
|
98
|
-
if encoder.include?("/")
|
|
99
|
-
ename, encoder = encoder, WLang::encoder(encoder)
|
|
100
|
-
raise(ParseError,"Unknown encoder: #{ename}") if encoder.nil?
|
|
101
|
-
else
|
|
102
|
-
ename, encoder = encoder, self.dialect.find_encoder(encoder)
|
|
103
|
-
raise(ParseError,"Unknown encoder: #{ename}") if encoder.nil?
|
|
104
|
-
end
|
|
105
|
-
elsif not(Encoder===encoder)
|
|
106
|
-
raise(ParseError,"Unknown encoder: #{encoder}")
|
|
107
|
-
end
|
|
108
|
-
encoder
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
###################################################################### Main parser methods
|
|
112
|
-
|
|
113
|
-
# Checks the result of a given rule
|
|
114
|
-
def launch_rule(dialect, rule_symbol, rule, offset)
|
|
115
|
-
result = rule.start_tag(self, offset)
|
|
116
|
-
raise WLang::Error, "Bad rule implementation #{dialect.qualified_name} #{rule_symbol}{}\n#{result.inspect}"\
|
|
117
|
-
unless result.size == 2 and String===result[0] and Integer===result[1]
|
|
118
|
-
result
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
#
|
|
122
|
-
# Parses the template's text and instantiate it. Dialect post_transformer is
|
|
123
|
-
# only applied of _apply_posttransform_ is set to true.
|
|
124
|
-
#
|
|
125
|
-
def instantiate(apply_posttransform = true)
|
|
126
|
-
# Main variables put in local scope for efficiency:
|
|
127
|
-
# - template: current parsed template
|
|
128
|
-
# - source_text: current template's source text
|
|
129
|
-
# - offset: matching current position
|
|
130
|
-
# - pattern: current dialect's regexp pattern
|
|
131
|
-
# - rules: handlers of '{' currently opened
|
|
132
|
-
template = self.template
|
|
133
|
-
symbols = self.template.block_symbols
|
|
134
|
-
source_text = self.source_text
|
|
135
|
-
dialect = self.dialect
|
|
136
|
-
buffer = self.buffer
|
|
137
|
-
pattern = dialect.pattern(template.block_symbols)
|
|
138
|
-
rules = []
|
|
139
|
-
|
|
140
|
-
# we start matching everything in the ruleset
|
|
141
|
-
while match_at=source_text.index(pattern, self.offset)
|
|
142
|
-
match, match_length = $~[0], $~[0].length
|
|
143
|
-
|
|
144
|
-
# puts pre_match (we can't use $~.pre_match !)
|
|
145
|
-
self.<<(source_text[self.offset, match_at-self.offset], false) if match_at>0
|
|
146
|
-
|
|
147
|
-
if source_text[match_at,1]=='\\' # escaping sequence
|
|
148
|
-
self.<<(match[1..-1], false)
|
|
149
|
-
self.offset = match_at + match_length
|
|
150
|
-
|
|
151
|
-
elsif match.length==1 # simple '{' or '}' here
|
|
152
|
-
self.offset = match_at + match_length
|
|
153
|
-
if match==Template::BLOCK_SYMBOLS[symbols][0]
|
|
154
|
-
self.<<(match, false) # simple '{' are always pushed
|
|
155
|
-
# we push '{' in rules to recognize it's associated '}'
|
|
156
|
-
# that must be pushed on buffer also
|
|
157
|
-
rules << match
|
|
158
|
-
else
|
|
159
|
-
# end of my job if I can't pop a previous rule
|
|
160
|
-
break if rules.empty?
|
|
161
|
-
# otherwise, push '}' only if associated to a simple '{'
|
|
162
|
-
self.<<(match, false) unless Rule===rules.pop
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
elsif match[-1,1]==Template::BLOCK_SYMBOLS[symbols][0] # opening special tag
|
|
166
|
-
# following line should never return nil as the matching pattern comes
|
|
167
|
-
# from the ruleset itself!
|
|
168
|
-
rule_symbol = match[0..-2]
|
|
169
|
-
rule = dialect.ruleset[rule_symbol]
|
|
170
|
-
rules << rule
|
|
171
|
-
|
|
172
|
-
# Just added to get the last position in case of an error
|
|
173
|
-
self.offset = match_at + match_length
|
|
174
|
-
|
|
175
|
-
# lauch that rule, get it's replacement and my new offset
|
|
176
|
-
replacement, self.offset = launch_rule(dialect, rule_symbol, rule, self.offset)
|
|
177
|
-
|
|
178
|
-
# push replacement
|
|
179
|
-
self.<<(replacement, true) unless replacement.empty?
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
end # while match_at=...
|
|
183
|
-
|
|
184
|
-
# trailing data (end of template reached only if no match_at)
|
|
185
|
-
unless match_at
|
|
186
|
-
unexpected_eof(source_text.length, '}') unless rules.empty?
|
|
187
|
-
self.<<(source_text[self.offset, 1+source_text.length-self.offset], false)
|
|
188
|
-
self.offset = source_text.length
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
# Apply post-transformation only if required
|
|
192
|
-
if apply_posttransform
|
|
193
|
-
[dialect.apply_post_transform(buffer), self.offset-1]
|
|
194
|
-
else
|
|
195
|
-
[buffer, self.offset-1]
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
###################################################################### Callbacks for rule sets
|
|
200
|
-
|
|
201
|
-
#
|
|
202
|
-
# Launches a child parser for instantiation at a given _offset_ in given
|
|
203
|
-
# _dialect_ (same dialect than self if dialect is nil) and with an output
|
|
204
|
-
# _buffer_.
|
|
205
|
-
#
|
|
206
|
-
def parse(offset, req_dialect = nil, req_buffer = nil)
|
|
207
|
-
dialect = ensure_dialect(req_dialect.nil? ? self.dialect : req_dialect)
|
|
208
|
-
buffer = (req_buffer.nil? ? dialect.factor_buffer : req_buffer)
|
|
209
|
-
branch(:offset => offset,
|
|
210
|
-
:dialect => dialect,
|
|
211
|
-
:buffer => buffer) do
|
|
212
|
-
instantiate(!req_dialect.nil?)
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
#
|
|
217
|
-
# Checks if a given offset is a starting block. For easy implementation of rules
|
|
218
|
-
# the check applied here is that text starting at _offset_ in the template is precisely
|
|
219
|
-
# '}{' (the reason for that is that instantiate, parse, parse_block always stop
|
|
220
|
-
# parsing on a '}')
|
|
221
|
-
#
|
|
222
|
-
def has_block?(offset)
|
|
223
|
-
self.source_text[offset,2] == template.block_endstart
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
#
|
|
227
|
-
# Parses a given block starting at a given _offset_, expressed in a given
|
|
228
|
-
# _dialect_ and using an output _buffer_. This method raises a ParseError if
|
|
229
|
-
# there is no block at the offset. It implies that we are on a '}{', see
|
|
230
|
-
# has_block? for details. Rules may thus force mandatory block parsing without
|
|
231
|
-
# having to check anything. Optional blocks must be handled by rules themselve.
|
|
232
|
-
#
|
|
233
|
-
def parse_block(offset, dialect=nil, buffer=nil)
|
|
234
|
-
block_missing_error(offset+2) unless has_block?(offset)
|
|
235
|
-
parse(offset+2, dialect, buffer)
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
###################################################################### Facade on the buffer
|
|
239
|
-
|
|
240
|
-
# Appends on a given buffer
|
|
241
|
-
def append_buffer(buffer, str, block)
|
|
242
|
-
if buffer.respond_to?(:wlang_append)
|
|
243
|
-
buffer.wlang_append(str, block)
|
|
244
|
-
else
|
|
245
|
-
buffer << str
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
# Pushes a given string on the output buffer
|
|
250
|
-
def <<(str, block)
|
|
251
|
-
append_buffer(buffer, str, block)
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
###################################################################### Facade on the scope
|
|
255
|
-
|
|
256
|
-
# Yields the block in a new scope branch, pushing pairing values on it.
|
|
257
|
-
# Original scope is restored after that. Returns what the yielded block
|
|
258
|
-
# returned.
|
|
259
|
-
def branch_scope(pairing = {}, which = :all)
|
|
260
|
-
raise ArgumentError, "Parser.branch_scope expects a block" unless block_given?
|
|
261
|
-
branch(:scope => pairing, :shared => which) { yield }
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
# Adds a key/value pair on the current scope.
|
|
265
|
-
def scope_define(key, value)
|
|
266
|
-
state.scope[key] = value
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
###################################################################### Facade on the hosted language
|
|
270
|
-
|
|
271
|
-
#
|
|
272
|
-
# Evaluates a ruby expression on the current context.
|
|
273
|
-
# See WLang::Parser::Context#evaluate.
|
|
274
|
-
#
|
|
275
|
-
def evaluate(expression)
|
|
276
|
-
hosted.evaluate(expression, state)
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
###################################################################### Facade on the dialect
|
|
280
|
-
|
|
281
|
-
# Factors a specific buffer on the current dialect
|
|
282
|
-
def factor_buffer
|
|
283
|
-
self.dialect.factor_buffer
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
#
|
|
287
|
-
# Encodes a given text using an encoder, that may be a qualified name or an
|
|
288
|
-
# Encoder instance.
|
|
289
|
-
#
|
|
290
|
-
def encode(src, encoder, options=nil)
|
|
291
|
-
options = {} unless options
|
|
292
|
-
options['_encoder_'] = encoder
|
|
293
|
-
options['_template_'] = template
|
|
294
|
-
ensure_encoder(encoder).encode(src, options)
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
###################################################################### About errors
|
|
298
|
-
|
|
299
|
-
# Raises an exception with a friendly message
|
|
300
|
-
def error(offset, message)
|
|
301
|
-
template.error(offset, message)
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
#
|
|
305
|
-
# Raises a ParseError at a given offset.
|
|
306
|
-
#
|
|
307
|
-
def syntax_error(offset, msg=nil)
|
|
308
|
-
text = self.parse(offset, "wlang/dummy", "")
|
|
309
|
-
msg = msg.nil? ? '' : ": #{msg}"
|
|
310
|
-
template.parse_error(offset, "parse error on '#{text}'#{msg}")
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
#
|
|
314
|
-
# Raises a ParseError at a given offset for a missing block
|
|
315
|
-
#
|
|
316
|
-
def block_missing_error(offset)
|
|
317
|
-
template.parse_error(offset, "parse error, block was expected")
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
#
|
|
321
|
-
# Raises a ParseError at a given offset for a unexpected EOF
|
|
322
|
-
# specif. the expected character when EOF found
|
|
323
|
-
#
|
|
324
|
-
def unexpected_eof(offset, expected)
|
|
325
|
-
template.parse_error(offset, "#{expected} expected, EOF found")
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
# Protected methods are...
|
|
329
|
-
protected :hosted, :offset, :source_text, :dialect
|
|
330
|
-
|
|
331
|
-
end # class Parser
|
|
332
|
-
end # module WLang
|
data/lib/wlang/parser_state.rb
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
module WLang
|
|
2
|
-
class Parser
|
|
3
|
-
#
|
|
4
|
-
# Encapsulates all state information of a WLang parser
|
|
5
|
-
#
|
|
6
|
-
class State
|
|
7
|
-
|
|
8
|
-
# The attached parser
|
|
9
|
-
attr_accessor :parser
|
|
10
|
-
|
|
11
|
-
# The parent state
|
|
12
|
-
attr_accessor :parent
|
|
13
|
-
|
|
14
|
-
# The current hosted language
|
|
15
|
-
attr_accessor :hosted
|
|
16
|
-
|
|
17
|
-
# The current template
|
|
18
|
-
attr_accessor :template
|
|
19
|
-
|
|
20
|
-
# The current dialect
|
|
21
|
-
attr_accessor :dialect
|
|
22
|
-
|
|
23
|
-
# The current offset in template's source code
|
|
24
|
-
attr_accessor :offset
|
|
25
|
-
|
|
26
|
-
# The current scope
|
|
27
|
-
attr_accessor :scope
|
|
28
|
-
|
|
29
|
-
# The current output buffer
|
|
30
|
-
attr_accessor :buffer
|
|
31
|
-
|
|
32
|
-
# Creates a new state instance for a given parser and optional
|
|
33
|
-
# parent.
|
|
34
|
-
def initialize(parser, parent = nil)
|
|
35
|
-
@parser, @parent = parser, parent
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Checks internals
|
|
39
|
-
def check
|
|
40
|
-
raise "WLang::Parser::State fatal: invalid parser #{parser}" unless ::WLang::Parser===parser
|
|
41
|
-
raise "WLang::Parser::State fatal: invalid hosted #{hosted}" unless ::WLang::HostedLanguage===hosted
|
|
42
|
-
raise "WLang::Parser::State fatal: missing template #{template}" unless ::WLang::Template===template
|
|
43
|
-
raise "WLang::Parser::State fatal: missing dialect #{dialect}" unless ::WLang::Dialect===dialect
|
|
44
|
-
raise "WLang::Parser::State fatal: missing offset #{offset}" unless Integer===offset
|
|
45
|
-
raise "WLang::Parser::State fatal: missing scope #{scope}" unless ::WLang::HashScope===scope
|
|
46
|
-
raise "WLang::Parser::State fatal: missing buffer #{buffer}" unless buffer.respond_to?(:<<)
|
|
47
|
-
self
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
#
|
|
51
|
-
# Branches this state.
|
|
52
|
-
#
|
|
53
|
-
# Branching allows creating a child parser state of this one. Options are:
|
|
54
|
-
# - :hosted => a new hosted language
|
|
55
|
-
# - :template => a new template
|
|
56
|
-
# - :dialect => a new dialect
|
|
57
|
-
# - :offset => a new offset in the template
|
|
58
|
-
# - :shared => :all, :root or :none (which scoping should be shared)
|
|
59
|
-
# - :scope => a Hash of new pairing to push on the new scope
|
|
60
|
-
# - :buffer => a new output buffer to use
|
|
61
|
-
#
|
|
62
|
-
def branch(opts = {})
|
|
63
|
-
child = State.new(parser, self)
|
|
64
|
-
child.hosted = opts[:hosted] || hosted
|
|
65
|
-
child.template = opts[:template] || template
|
|
66
|
-
child.dialect = opts[:dialect] || child.template.dialect
|
|
67
|
-
child.offset = opts[:offset] || offset
|
|
68
|
-
child.buffer = opts[:buffer] || child.dialect.factor_buffer
|
|
69
|
-
child.scope = case opts[:shared]
|
|
70
|
-
when :all, NilClass
|
|
71
|
-
scope.branch(opts[:scope])
|
|
72
|
-
when :root
|
|
73
|
-
scope.root.branch(opts[:scope])
|
|
74
|
-
when :none
|
|
75
|
-
::WLang::HashScope.new(opts[:scope])
|
|
76
|
-
else
|
|
77
|
-
raise ArgumentError, "Invalid ParserState.branch option :shared #{opts[:shared]}"
|
|
78
|
-
end
|
|
79
|
-
child.check
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Returns a friendly location for this parser state
|
|
83
|
-
def where
|
|
84
|
-
template ? template.where(offset) : "Source template tree"
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# Returns a friendly wlang backtrace as an array
|
|
88
|
-
def backtrace
|
|
89
|
-
parent ? parent.backtrace.unshift(where) : [where]
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
end # class State
|
|
93
|
-
end # class Parser
|
|
94
|
-
end # module WLang
|