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