wlang 0.8.4
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/LICENCE.rdoc +25 -0
- data/README.rdoc +111 -0
- data/bin/wlang +24 -0
- data/doc/specification/about.rdoc +61 -0
- data/doc/specification/dialects.wtpl +0 -0
- data/doc/specification/examples.rb +3 -0
- data/doc/specification/glossary.wtpl +14 -0
- data/doc/specification/hosting.rdoc +0 -0
- data/doc/specification/overview.rdoc +116 -0
- data/doc/specification/rulesets.wtpl +87 -0
- data/doc/specification/specification.css +52 -0
- data/doc/specification/specification.html +1361 -0
- data/doc/specification/specification.js +8 -0
- data/doc/specification/specification.wtpl +41 -0
- data/doc/specification/specification.yml +430 -0
- data/doc/specification/symbols.wtpl +16 -0
- data/lib/wlang.rb +186 -0
- data/lib/wlang/basic_object.rb +19 -0
- data/lib/wlang/dialect.rb +230 -0
- data/lib/wlang/dialect_dsl.rb +136 -0
- data/lib/wlang/dialect_loader.rb +69 -0
- data/lib/wlang/dialects/coderay_dialect.rb +35 -0
- data/lib/wlang/dialects/plain_text_dialect.rb +75 -0
- data/lib/wlang/dialects/rdoc_dialect.rb +33 -0
- data/lib/wlang/dialects/ruby_dialect.rb +35 -0
- data/lib/wlang/dialects/sql_dialect.rb +38 -0
- data/lib/wlang/dialects/standard_dialects.rb +113 -0
- data/lib/wlang/dialects/xhtml_dialect.rb +40 -0
- data/lib/wlang/encoder.rb +66 -0
- data/lib/wlang/encoder_set.rb +117 -0
- data/lib/wlang/errors.rb +37 -0
- data/lib/wlang/intelligent_buffer.rb +94 -0
- data/lib/wlang/parser.rb +251 -0
- data/lib/wlang/parser_context.rb +146 -0
- data/lib/wlang/ruby_extensions.rb +21 -0
- data/lib/wlang/rule.rb +66 -0
- data/lib/wlang/rule_set.rb +93 -0
- data/lib/wlang/rulesets/basic_ruleset.rb +75 -0
- data/lib/wlang/rulesets/buffering_ruleset.rb +103 -0
- data/lib/wlang/rulesets/context_ruleset.rb +115 -0
- data/lib/wlang/rulesets/encoding_ruleset.rb +73 -0
- data/lib/wlang/rulesets/imperative_ruleset.rb +132 -0
- data/lib/wlang/rulesets/ruleset_utils.rb +296 -0
- data/lib/wlang/template.rb +79 -0
- data/lib/wlang/wlang_command.rb +54 -0
- data/lib/wlang/wlang_command_options.rb +158 -0
- data/test/sandbox.rb +1 -0
- data/test/test_all.rb +8 -0
- data/test/wlang/anagram_bugs_test.rb +111 -0
- data/test/wlang/basic_ruleset_test.rb +52 -0
- data/test/wlang/buffering_ruleset_test.rb +102 -0
- data/test/wlang/buffering_template1.wtpl +1 -0
- data/test/wlang/buffering_template2.wtpl +1 -0
- data/test/wlang/buffering_template3.wtpl +1 -0
- data/test/wlang/buffering_template4.wtpl +1 -0
- data/test/wlang/buffering_template5.wtpl +1 -0
- data/test/wlang/context_ruleset_test.rb +32 -0
- data/test/wlang/data.rb +3 -0
- data/test/wlang/encoder_set_test.rb +42 -0
- data/test/wlang/imperative_ruleset_test.rb +107 -0
- data/test/wlang/intelligent_buffer_test.rb +194 -0
- data/test/wlang/othersymbols_test.rb +16 -0
- data/test/wlang/parser_context_test.rb +29 -0
- data/test/wlang/parser_test.rb +89 -0
- data/test/wlang/plain_text_dialect_test.rb +21 -0
- data/test/wlang/ruby_dialect_test.rb +100 -0
- data/test/wlang/ruby_expected.rb +3 -0
- data/test/wlang/ruby_template.wrb +3 -0
- data/test/wlang/ruleset_utils_test.rb +245 -0
- data/test/wlang/specification_examples_test.rb +52 -0
- data/test/wlang/test_utils.rb +25 -0
- data/test/wlang/wlang_test.rb +80 -0
- metadata +136 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
<table class="symbols">
|
2
|
+
<tr>
|
3
|
+
<th class="name">name</th>
|
4
|
+
<th class="symbol">symbol</th>
|
5
|
+
<th class="meaning">meaning</th>
|
6
|
+
<th class="remark">remark</th>
|
7
|
+
</tr>
|
8
|
+
*{spec/symbols as s}{
|
9
|
+
<tr>
|
10
|
+
<td><em>${s/name}</em></td>
|
11
|
+
<td>${s/symbol}</td>
|
12
|
+
<td>${s/meaning}</td>
|
13
|
+
<td>${s/remark}</td>
|
14
|
+
</tr>
|
15
|
+
}
|
16
|
+
</table>
|
data/lib/wlang.rb
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'wlang/ruby_extensions'
|
2
|
+
require 'stringio'
|
3
|
+
require 'wlang/rule'
|
4
|
+
require 'wlang/rule_set'
|
5
|
+
require 'wlang/encoder_set'
|
6
|
+
require 'wlang/dialect'
|
7
|
+
require 'wlang/dialect_dsl'
|
8
|
+
require 'wlang/dialect_loader'
|
9
|
+
require 'wlang/parser'
|
10
|
+
require 'wlang/parser_context'
|
11
|
+
require 'wlang/intelligent_buffer'
|
12
|
+
|
13
|
+
#
|
14
|
+
# Main module of the _wlang_ code generator/template engine, providing a facade
|
15
|
+
# on _wlang_ tools. See also the Roadmap section of {README}[link://files/README.html]
|
16
|
+
# to enter the library.
|
17
|
+
#
|
18
|
+
module WLang
|
19
|
+
|
20
|
+
# Current version of WLang
|
21
|
+
VERSION = "0.8.4".freeze
|
22
|
+
|
23
|
+
# Reusable string for building dialect name based regexps
|
24
|
+
DIALECT_NAME_REGEXP_STR = "[-a-z]+"
|
25
|
+
|
26
|
+
#
|
27
|
+
# Regular expression for dialect names.
|
28
|
+
#
|
29
|
+
DIALECT_NAME_REGEXP = /^([-a-z]+)*$/
|
30
|
+
|
31
|
+
# Reusable string for building dialect name based regexps
|
32
|
+
QUALIFIED_DIALECT_NAME_REGEXP_STR = "[-a-z]+([\/][-a-z]+)*"
|
33
|
+
|
34
|
+
#
|
35
|
+
# Regular expression for dialect qualified names. Dialect qualified names are
|
36
|
+
# '/' seperated names, where a name is [-a-z]+.
|
37
|
+
# Examples: wlang/xhtml/uri, wlang/plain-text, ...
|
38
|
+
#
|
39
|
+
QUALIFIED_DIALECT_NAME_REGEXP = /^[-a-z]+([\/][-a-z]+)*$/
|
40
|
+
|
41
|
+
# Reusable string for building encoder name based regexps
|
42
|
+
ENCODER_NAME_REGEXP_STR = "[-a-z]+"
|
43
|
+
|
44
|
+
#
|
45
|
+
# Regular expression for encoder names.
|
46
|
+
#
|
47
|
+
ENCODER_NAME_REGEXP = /^([-a-z]+)*$/
|
48
|
+
|
49
|
+
#
|
50
|
+
# Regular expression for encoder qualified names. Encoder qualified names are
|
51
|
+
# '/' seperated names, where a name is [-a-z]+.
|
52
|
+
# Examples: xhtml/entities-encoding, sql/single-quoting, ...
|
53
|
+
#
|
54
|
+
QUALIFIED_ENCODER_NAME_REGEXP = /^([-a-z]+)([\/][-a-z]+)*$/
|
55
|
+
|
56
|
+
# Reusable string for building qualified encoder name based regexps
|
57
|
+
QUALIFIED_ENCODER_NAME_REGEXP_STR = "[-a-z]+([\/][-a-z]+)*"
|
58
|
+
|
59
|
+
#
|
60
|
+
# Provides installed {file extension => dialect} mappings. File extensions
|
61
|
+
# (keys) contain the first dot (like .wtpl, .whtml, ...). Dialects (values) are
|
62
|
+
# qualified names, not Dialect instances.
|
63
|
+
#
|
64
|
+
FILE_EXTENSIONS = {}
|
65
|
+
|
66
|
+
#
|
67
|
+
# Provides installed {file extension => data loader} mapping. File extensions
|
68
|
+
# (keys) contain the first dot (like .wtpl, .whtml, ...). Data loades are
|
69
|
+
# Proc instances that take a single |uri| argument.
|
70
|
+
#
|
71
|
+
DATA_EXTENSIONS = {}
|
72
|
+
|
73
|
+
#
|
74
|
+
# Main anonymous dialect. All installed dialects are children of this one,
|
75
|
+
# which is anonymous because it does not appear in qualified names.
|
76
|
+
#
|
77
|
+
@dialect = Dialect.new("", nil)
|
78
|
+
|
79
|
+
#
|
80
|
+
# Installs or query a dialect.
|
81
|
+
#
|
82
|
+
# <b>When called with a block</b>, this method installs a _wlang_ dialect under
|
83
|
+
# _name_ (which cannot be qualified). Extensions can be provided to let _wlang_
|
84
|
+
# automatically recognize files that are expressed in this dialect. The block
|
85
|
+
# is interpreted as code in the dialect DSL (domain specific language, see
|
86
|
+
# WLang::Dialect::DSL). Returns nil in this case.
|
87
|
+
#
|
88
|
+
# <b>When called without a block</b> this method returns a Dialect instance
|
89
|
+
# installed under name (which can be a qualified name). Extensions are ignored
|
90
|
+
# in this case. Returns nil if not found, a Dialect instance otherwise.
|
91
|
+
#
|
92
|
+
def self.dialect(name, *extensions, &block)
|
93
|
+
if block_given?
|
94
|
+
raise "Unsupported qualified names in dialect installation"\
|
95
|
+
unless name.index('/').nil?
|
96
|
+
Dialect::DSL.new(@dialect).dialect(name, *extensions, &block).build!
|
97
|
+
else
|
98
|
+
@dialect.dialect(name)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Adds a data loader for file extensions.
|
104
|
+
#
|
105
|
+
def self.data_loader(*exts, &block)
|
106
|
+
raise(ArgumentError, "Block expected") unless block_given?
|
107
|
+
raise(ArgumentError, "Block of arity 1 expected") unless block.arity==1
|
108
|
+
exts.each do |ext|
|
109
|
+
DATA_EXTENSIONS[ext] = block
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Loads data from a given URI. If _extension_ is omitted, tries to infer it
|
115
|
+
# from the uri, otherwise use it directly. Returns loaded data.
|
116
|
+
#
|
117
|
+
def self.load_data(uri, extension=nil)
|
118
|
+
if extension.nil?
|
119
|
+
extension = File.extname(uri)
|
120
|
+
raise("Unable to infer data loader from #{uri}") if extension.nil?
|
121
|
+
end
|
122
|
+
loader = DATA_EXTENSIONS[extension]
|
123
|
+
raise("No data loader for #{extension}") if loader.nil?
|
124
|
+
loader.call(uri)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Infers a dialect from a file extension
|
128
|
+
def self.infer_dialect(uri)
|
129
|
+
WLang::FILE_EXTENSIONS[File.extname(uri)]
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# Returns an encoder installed under a qualified name. Returns nil if not
|
134
|
+
# found.
|
135
|
+
#
|
136
|
+
def self.encoder(name)
|
137
|
+
@dialect.encoder(name)
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Instantiates a template written in some _wlang_ dialect, using a given _context_
|
142
|
+
# (providing instantiation data). Returns instantiatiation as a String. If you want
|
143
|
+
# to instantiate the template in a specific buffer (a file or console for example),
|
144
|
+
# use Template. _template_ is expected to be a String and _context_ a Hash. To
|
145
|
+
# know available dialects, see WLang::StandardDialects. <em>block_symbols</em>
|
146
|
+
# can be <tt>:braces</tt> ('{' and '}' pairs), <tt>:brackets</tt> ('[' and ']'
|
147
|
+
# pairs) or <tt>:parentheses</tt> ('(' and ')' pairs).
|
148
|
+
#
|
149
|
+
# Examples:
|
150
|
+
# WLang.instantiate "Hello ${who} !", {"who" => "Mr. Jones"}
|
151
|
+
# WLang.instantiate "SELECT * FROM people WHERE name='{name}'", {"who" => "Mr. O'Neil"}, "wlang/sql"
|
152
|
+
# WLang.instantiate "Hello $(who) !", {"who" => "Mr. Jones"}, "wlang/active-string", :parentheses
|
153
|
+
#
|
154
|
+
def self.instantiate(template, context=nil, dialect="wlang/active-string", block_symbols = :braces)
|
155
|
+
WLang::Template.new(template, dialect, context, block_symbols).instantiate
|
156
|
+
end
|
157
|
+
|
158
|
+
#
|
159
|
+
# Instantiates a file written in some _wlang_ dialect, using a given _context_
|
160
|
+
# (providing instantiation data). Outputs instantiation in _buffer_ (any object
|
161
|
+
# responding to <tt><<</tt>, usually a IO; String is supported as well). If
|
162
|
+
# _dialect_ is nil, tries to infer it from the file extension; otherwise _dialect_
|
163
|
+
# is expected to be a qualified dialect name. See instantiate about <tt>block_symbols</tt>.
|
164
|
+
# Returns _buffer_.
|
165
|
+
#
|
166
|
+
# Examples:
|
167
|
+
# Wlang.file_instantiate "template.wtpl", {"who" => "Mr. Jones"}
|
168
|
+
# Wlang.file_instantiate "template.wtpl", {"who" => "Mr. Jones"}, STDOUT
|
169
|
+
# Wlang.file_instantiate "template.xxx", {"who" => "Mr. Jones"}, STDOUT, "wlang/xhtml"
|
170
|
+
#
|
171
|
+
def self.file_instantiate(file, context=nil, buffer=nil, dialect=nil, block_symbols = :braces)
|
172
|
+
raise "File '#{file}' does not exists or is unreadable"\
|
173
|
+
unless File.exists?(file) and File.readable?(file)
|
174
|
+
if dialect.nil?
|
175
|
+
dialect = infer_dialect(file) if dialect.nil?
|
176
|
+
raise("No known dialect for file extension '#{File.extname(file)}'\n"\
|
177
|
+
"Known extensions are: " << WLang::FILE_EXTENSIONS.keys.join(", "))\
|
178
|
+
if dialect.nil?
|
179
|
+
end
|
180
|
+
t = WLang::Template.new(File.read(file), dialect, context, block_symbols)
|
181
|
+
t.source_file = file
|
182
|
+
t.instantiate(buffer)
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
require 'wlang/dialects/standard_dialects'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module WLang
|
2
|
+
|
3
|
+
#
|
4
|
+
# Provides an Object with all inherited instance methods removed.
|
5
|
+
#
|
6
|
+
class BasicObject
|
7
|
+
|
8
|
+
# Methods that we keep
|
9
|
+
KEPT_METHODS = ["__send__", "__id__", "instance_eval", "initialize", "object_id",
|
10
|
+
:__send__, :__id__, :instance_eval, :initialize, :object_id]
|
11
|
+
|
12
|
+
# Removes all methods that are not needed to the class
|
13
|
+
(instance_methods + private_instance_methods).each do |m|
|
14
|
+
undef_method(m) unless KEPT_METHODS.include?(m)
|
15
|
+
end
|
16
|
+
|
17
|
+
end # class BasicObject
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'wlang/encoder_set'
|
2
|
+
require 'wlang/rule_set'
|
3
|
+
module WLang
|
4
|
+
|
5
|
+
#
|
6
|
+
# Implements the _dialect_ abstraction (see {README}[link://files/README.html]).
|
7
|
+
# A dialect instance is a 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
|
+
# In order to avoid having users to install all required gems of all dialects
|
18
|
+
# wlang implements a lazy load design pattern on the dialect tree, through the
|
19
|
+
# WLang::Dialect::DSL and WLang::Dialect::Loader classes. The former only creates
|
20
|
+
# Dialect instances as tree nodes (by chaining dialects through @parent) and
|
21
|
+
# installs mapping with file extensions. Rules and encoders are not initially
|
22
|
+
# installed (precisely: WLang::Dialect::DSL#require_ruby is simply ignored).
|
23
|
+
# When a given dialect is needed by wlang it is first built (through the build!
|
24
|
+
# method and the WLang::Dialect::Loader class).
|
25
|
+
#
|
26
|
+
# Standard dialect obtention methods (WLang#dialect as well as WLang::Dialect#dialect)
|
27
|
+
# ensure that returned dialects are built. If you obtain dialects another way,
|
28
|
+
# be sure that they are built before using them (is_built? and build! are your
|
29
|
+
# friends to achive that goal).
|
30
|
+
#
|
31
|
+
# Moreover, child dialects may require tools of their ancestors. The following
|
32
|
+
# invariant should always be respected: if a dialect is built, all its ancestors
|
33
|
+
# are built as well. This invariant is not enforced by the build! method because
|
34
|
+
# it is trivially respected by the way WLang::Dialect#dialect is implemented.
|
35
|
+
#
|
36
|
+
class Dialect
|
37
|
+
|
38
|
+
# Underlying ruleset
|
39
|
+
attr_reader :ruleset
|
40
|
+
|
41
|
+
# Underlying encoders
|
42
|
+
attr_reader :encoders
|
43
|
+
|
44
|
+
# Dialect name
|
45
|
+
attr_reader :name
|
46
|
+
|
47
|
+
# Parent dialect
|
48
|
+
attr_reader :parent
|
49
|
+
|
50
|
+
#
|
51
|
+
# Creates a dialect instance. _builder_ block is a chunk of code of the DSL
|
52
|
+
# that will be executed twice: once at construction time to create sub dialects
|
53
|
+
# nodes and install file extensions and once at building time to install ruleset
|
54
|
+
# and encoders.
|
55
|
+
#
|
56
|
+
def initialize(name, parent, &builder)
|
57
|
+
@name, @parent = name, parent
|
58
|
+
@builder, @built = builder, builder.nil?
|
59
|
+
@dialects = nil
|
60
|
+
@encoders = nil
|
61
|
+
@ruleset = nil
|
62
|
+
DSL.new(self).instance_eval(&builder) unless builder.nil?
|
63
|
+
end
|
64
|
+
|
65
|
+
### Lazy load mechanism ######################################################
|
66
|
+
|
67
|
+
#
|
68
|
+
# Force the dialect to be built. Has no effect if it is already built. Invokes
|
69
|
+
# the DSL chunk of code through WLang::DSL::Loader otherwise.
|
70
|
+
#
|
71
|
+
def build!
|
72
|
+
unless is_built?
|
73
|
+
WLang::Dialect::Loader.new(self).instance_eval(&@builder)
|
74
|
+
@built = true
|
75
|
+
end
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns true if this dialect is already built, false otherwise.
|
80
|
+
def is_built?
|
81
|
+
return @built
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
### Installation #############################################################
|
86
|
+
|
87
|
+
#
|
88
|
+
# Adds a child dialect under _name_. _name_ cannot be qualified and must be a
|
89
|
+
# valid dialect name according to the wlang specification (see WLang::DIALECT_NAME_REGEXP).
|
90
|
+
# _child_ must be a Dialect instance.
|
91
|
+
#
|
92
|
+
def add_child_dialect(name, child)
|
93
|
+
raise(ArgumentError, "Invalid dialect name") unless WLang::DIALECT_NAME_REGEXP =~ name
|
94
|
+
raise(ArgumentError, "Dialect expected") unless Dialect===child
|
95
|
+
@dialects = {} if @dialects.nil?
|
96
|
+
@dialects[name] = child
|
97
|
+
end
|
98
|
+
|
99
|
+
# See EncoderSet#add_encoder
|
100
|
+
def add_encoder(name, &block)
|
101
|
+
@encoders = EncoderSet.new if @encoders.nil?
|
102
|
+
@encoders.add_encoder(name, &block)
|
103
|
+
end
|
104
|
+
|
105
|
+
# See EncoderSet#add_encoders
|
106
|
+
def add_encoders(mod, pairs)
|
107
|
+
@encoders = EncoderSet.new if @encoders.nil?
|
108
|
+
@encoders.add_encoders(mod, pairs)
|
109
|
+
end
|
110
|
+
|
111
|
+
# See RuleSet::add_rule
|
112
|
+
def add_rule(name, &block)
|
113
|
+
@ruleset = RuleSet.new if @ruleset.nil?
|
114
|
+
@ruleset.add_rule(name, &block)
|
115
|
+
end
|
116
|
+
|
117
|
+
# See RuleSet::add_rules
|
118
|
+
def add_rules(mod, pairs)
|
119
|
+
@ruleset = RuleSet.new if @ruleset.nil?
|
120
|
+
@ruleset.add_rules(mod, pairs)
|
121
|
+
end
|
122
|
+
|
123
|
+
### Query API ################################################################
|
124
|
+
|
125
|
+
# Returns qualified name of this dialect
|
126
|
+
def qualified_name
|
127
|
+
parentname = @parent.nil? ? "" : @parent.to_s
|
128
|
+
return ""==parentname ? @name : parentname + '/' + @name
|
129
|
+
end
|
130
|
+
|
131
|
+
#
|
132
|
+
# Finds a child dialect by name. _name_ can be a String denoting a qualified
|
133
|
+
# name as well as an Array of strings, resulting from a qualified name split.
|
134
|
+
# This method should always be invoked on built dialects, it always returns nil
|
135
|
+
# otherwise. When found, returned dialect is automatically built as well as all
|
136
|
+
# its ancestors. When not found, the method returns nil.
|
137
|
+
#
|
138
|
+
def dialect(name)
|
139
|
+
# implement argument conventions
|
140
|
+
if String===name
|
141
|
+
raise(ArgumentError, "Invalid dialect name #{name}") unless WLang::QUALIFIED_DIALECT_NAME_REGEXP =~ name
|
142
|
+
name = name.split('/')
|
143
|
+
elsif not(Array===name)
|
144
|
+
raise(ArgumentError,"Invalid dialect name #{name}")
|
145
|
+
end
|
146
|
+
|
147
|
+
# not built or no child at all
|
148
|
+
return nil if @dialects.nil?
|
149
|
+
|
150
|
+
# get first child name and find it
|
151
|
+
child_name = name[0]
|
152
|
+
child_dialect = @dialects[child_name]
|
153
|
+
|
154
|
+
if child_dialect.nil?
|
155
|
+
# unexisting, return nil
|
156
|
+
return nil
|
157
|
+
elsif name.length==1
|
158
|
+
# found and last of qualified name -> build it
|
159
|
+
return child_dialect.build!
|
160
|
+
else
|
161
|
+
# found but not last of qualified name -> build it and delegate
|
162
|
+
child_dialect.build!
|
163
|
+
return child_dialect.dialect(name[1..-1])
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
#
|
168
|
+
# Finds an encoder by name.
|
169
|
+
#
|
170
|
+
def encoder(name)
|
171
|
+
# implement argument conventions
|
172
|
+
if String===name
|
173
|
+
raise(ArgumentError, "Invalid encoder name #{name}") unless WLang::QUALIFIED_ENCODER_NAME_REGEXP =~ name
|
174
|
+
name = name.split('/')
|
175
|
+
elsif not(Array===name)
|
176
|
+
raise(ArgumentError,"Invalid encoder name #{name}")
|
177
|
+
end
|
178
|
+
|
179
|
+
# last name in qualified?
|
180
|
+
if name.length==1
|
181
|
+
# delegate to encoders
|
182
|
+
return nil if @encoders.nil?
|
183
|
+
return @encoders.get_encoder(name[0])
|
184
|
+
else
|
185
|
+
# find sub dialect, and delegate
|
186
|
+
child_name = name[0]
|
187
|
+
child_dialect = dialect(child_name)
|
188
|
+
if child_dialect.nil?
|
189
|
+
return nil
|
190
|
+
else
|
191
|
+
return child_dialect.encoder(name[1..-1])
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Finds a encoder in dialect tree
|
197
|
+
def find_encoder(name)
|
198
|
+
raise(ArgumentError, "Invalid (relative) encoder name #{name}") unless String===name
|
199
|
+
raise(ArgumentError, "Invalid (relative) encoder name #{name}") if name.include?("/")
|
200
|
+
return nil if @encoders.nil?
|
201
|
+
if @encoders.has_encoder?(name)
|
202
|
+
@encoders.get_encoder(name)
|
203
|
+
elsif @parent
|
204
|
+
@parent.find_encoder(name)
|
205
|
+
else
|
206
|
+
nil
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# See RuleSet#pattern.
|
211
|
+
def pattern(block_symbols)
|
212
|
+
return RuleSet.new.pattern(block_symbols) if @ruleset.nil?
|
213
|
+
@ruleset.pattern(block_symbols)
|
214
|
+
end
|
215
|
+
|
216
|
+
### Other utilities ##########################################################
|
217
|
+
|
218
|
+
# Factors a spacing friendly buffer for instantiation in this dialect
|
219
|
+
def factor_buffer
|
220
|
+
IntelligentBuffer.new
|
221
|
+
end
|
222
|
+
|
223
|
+
# Returns a string representation
|
224
|
+
def to_s
|
225
|
+
qualified_name
|
226
|
+
end
|
227
|
+
|
228
|
+
end # class Dialect
|
229
|
+
|
230
|
+
end #module WLang
|