wlang 0.10.2 → 2.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- 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
|