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.
Files changed (73) hide show
  1. data/LICENCE.rdoc +25 -0
  2. data/README.rdoc +111 -0
  3. data/bin/wlang +24 -0
  4. data/doc/specification/about.rdoc +61 -0
  5. data/doc/specification/dialects.wtpl +0 -0
  6. data/doc/specification/examples.rb +3 -0
  7. data/doc/specification/glossary.wtpl +14 -0
  8. data/doc/specification/hosting.rdoc +0 -0
  9. data/doc/specification/overview.rdoc +116 -0
  10. data/doc/specification/rulesets.wtpl +87 -0
  11. data/doc/specification/specification.css +52 -0
  12. data/doc/specification/specification.html +1361 -0
  13. data/doc/specification/specification.js +8 -0
  14. data/doc/specification/specification.wtpl +41 -0
  15. data/doc/specification/specification.yml +430 -0
  16. data/doc/specification/symbols.wtpl +16 -0
  17. data/lib/wlang.rb +186 -0
  18. data/lib/wlang/basic_object.rb +19 -0
  19. data/lib/wlang/dialect.rb +230 -0
  20. data/lib/wlang/dialect_dsl.rb +136 -0
  21. data/lib/wlang/dialect_loader.rb +69 -0
  22. data/lib/wlang/dialects/coderay_dialect.rb +35 -0
  23. data/lib/wlang/dialects/plain_text_dialect.rb +75 -0
  24. data/lib/wlang/dialects/rdoc_dialect.rb +33 -0
  25. data/lib/wlang/dialects/ruby_dialect.rb +35 -0
  26. data/lib/wlang/dialects/sql_dialect.rb +38 -0
  27. data/lib/wlang/dialects/standard_dialects.rb +113 -0
  28. data/lib/wlang/dialects/xhtml_dialect.rb +40 -0
  29. data/lib/wlang/encoder.rb +66 -0
  30. data/lib/wlang/encoder_set.rb +117 -0
  31. data/lib/wlang/errors.rb +37 -0
  32. data/lib/wlang/intelligent_buffer.rb +94 -0
  33. data/lib/wlang/parser.rb +251 -0
  34. data/lib/wlang/parser_context.rb +146 -0
  35. data/lib/wlang/ruby_extensions.rb +21 -0
  36. data/lib/wlang/rule.rb +66 -0
  37. data/lib/wlang/rule_set.rb +93 -0
  38. data/lib/wlang/rulesets/basic_ruleset.rb +75 -0
  39. data/lib/wlang/rulesets/buffering_ruleset.rb +103 -0
  40. data/lib/wlang/rulesets/context_ruleset.rb +115 -0
  41. data/lib/wlang/rulesets/encoding_ruleset.rb +73 -0
  42. data/lib/wlang/rulesets/imperative_ruleset.rb +132 -0
  43. data/lib/wlang/rulesets/ruleset_utils.rb +296 -0
  44. data/lib/wlang/template.rb +79 -0
  45. data/lib/wlang/wlang_command.rb +54 -0
  46. data/lib/wlang/wlang_command_options.rb +158 -0
  47. data/test/sandbox.rb +1 -0
  48. data/test/test_all.rb +8 -0
  49. data/test/wlang/anagram_bugs_test.rb +111 -0
  50. data/test/wlang/basic_ruleset_test.rb +52 -0
  51. data/test/wlang/buffering_ruleset_test.rb +102 -0
  52. data/test/wlang/buffering_template1.wtpl +1 -0
  53. data/test/wlang/buffering_template2.wtpl +1 -0
  54. data/test/wlang/buffering_template3.wtpl +1 -0
  55. data/test/wlang/buffering_template4.wtpl +1 -0
  56. data/test/wlang/buffering_template5.wtpl +1 -0
  57. data/test/wlang/context_ruleset_test.rb +32 -0
  58. data/test/wlang/data.rb +3 -0
  59. data/test/wlang/encoder_set_test.rb +42 -0
  60. data/test/wlang/imperative_ruleset_test.rb +107 -0
  61. data/test/wlang/intelligent_buffer_test.rb +194 -0
  62. data/test/wlang/othersymbols_test.rb +16 -0
  63. data/test/wlang/parser_context_test.rb +29 -0
  64. data/test/wlang/parser_test.rb +89 -0
  65. data/test/wlang/plain_text_dialect_test.rb +21 -0
  66. data/test/wlang/ruby_dialect_test.rb +100 -0
  67. data/test/wlang/ruby_expected.rb +3 -0
  68. data/test/wlang/ruby_template.wrb +3 -0
  69. data/test/wlang/ruleset_utils_test.rb +245 -0
  70. data/test/wlang/specification_examples_test.rb +52 -0
  71. data/test/wlang/test_utils.rb +25 -0
  72. data/test/wlang/wlang_test.rb +80 -0
  73. metadata +136 -0
@@ -0,0 +1,115 @@
1
+ require 'wlang/rulesets/ruleset_utils'
2
+ module WLang
3
+ class RuleSet
4
+
5
+ #
6
+ # Provides a ruleset for managing the context/scoping during instantitation.
7
+ #
8
+ # For an overview of this ruleset, see the wlang {specification file}[link://files/specification.html].
9
+ #
10
+ module Context
11
+ U=WLang::RuleSet::Utils
12
+
13
+ # Default mapping between tag symbols and methods
14
+ DEFAULT_RULESET = {'=' => :assignment,
15
+ '#=' => :block_assignment,
16
+ '%=' => :modulo_assignment,
17
+ '^=' => :encoding_assignment}
18
+
19
+ # Rule implementation of <tt>={wlang/hosted as x}{...}</tt>
20
+ def self.assignment(parser, offset)
21
+ expr, reached = parser.parse(offset, "wlang/ruby")
22
+
23
+ # decode expression
24
+ decoded = U.decode_expr_as(expr)
25
+ parser.syntax_error(offset) if decoded.nil?
26
+
27
+ # evaluate it
28
+ value = parser.evaluate(decoded[:expr])
29
+
30
+ # handle two different cases
31
+ if parser.has_block?(reached)
32
+ parser.context_push(decoded[:variable] => value)
33
+ text, reached = parser.parse_block(reached)
34
+ parser.context_pop
35
+ [text, reached]
36
+ else
37
+ parser.context_define(decoded[:variable], value)
38
+ ["", reached]
39
+ end
40
+ end
41
+
42
+ # Rule implementation of <tt>#={wlang/active-string}{...}{...}</tt>
43
+ def self.block_assignment(parser, offset)
44
+ variable, reached = parser.parse(offset, "wlang/active-string")
45
+
46
+ # decode expression
47
+ decoded = U.decode_var(variable)
48
+ parser.syntax_error(offset) if decoded.nil?
49
+
50
+ # parse second block in that dialect
51
+ value, reached = parser.parse_block(reached)
52
+
53
+ # handle two different cases
54
+ if parser.has_block?(reached)
55
+ parser.context_push(decoded[:variable] => value)
56
+ text, reached = parser.parse_block(reached)
57
+ parser.context_pop
58
+ [text, reached]
59
+ else
60
+ parser.context_define(decoded[:variable], value)
61
+ ["", reached]
62
+ end
63
+ end
64
+
65
+ # Rule implementation of <tt>%={wlang/active-string as x}{...}{...}</tt>
66
+ def self.modulo_assignment(parser, offset)
67
+ dialect_as, reached = parser.parse(offset, "wlang/ruby")
68
+
69
+ # decode expression
70
+ decoded = U.decode_qdialect_as(dialect_as)
71
+ parser.syntax_error(offset) if decoded.nil?
72
+
73
+ # parse second block in that dialect
74
+ value, reached = parser.parse_block(reached, decoded[:dialect])
75
+
76
+ # handle two different cases
77
+ if parser.has_block?(reached)
78
+ parser.context_push(decoded[:variable] => value)
79
+ text, reached = parser.parse_block(reached)
80
+ parser.context_pop
81
+ [text, reached]
82
+ else
83
+ parser.context_define(decoded[:variable], value)
84
+ ["", reached]
85
+ end
86
+ end
87
+
88
+ # Rule implementation of <tt>^={wlang/active-string as x}{...}{...}</tt>
89
+ def self.encoding_assignment(parser, offset)
90
+ encoding_as, reached = parser.parse(offset, "wlang/ruby")
91
+
92
+ # decode expression
93
+ decoded = U.decode_qencoder_as(encoding_as)
94
+ parser.syntax_error(offset) if decoded.nil?
95
+
96
+ # parse second block in that dialect
97
+ value, reached = parser.parse_block(reached)
98
+ value = parser.encode(value, decoded[:encoder])
99
+
100
+ # handle two different cases
101
+ if parser.has_block?(reached)
102
+ parser.context_push(decoded[:variable] => value)
103
+ text, reached = parser.parse_block(reached)
104
+ parser.context_pop
105
+ [text, reached]
106
+ else
107
+ parser.context_define(decoded[:variable], value)
108
+ ["", reached]
109
+ end
110
+ end
111
+
112
+ end # module Context
113
+
114
+ end
115
+ end
@@ -0,0 +1,73 @@
1
+ module WLang
2
+ class RuleSet
3
+
4
+ #
5
+ # Encoding RuleSet, commonly installed in any wlang dialect. Note that this
6
+ # ruleset overrides <tt>${...}</tt> implemented in WLang::RuleSet::Basic.
7
+ #
8
+ # For an overview of this ruleset, see the wlang {specification file}[link://files/specification.html].
9
+ #
10
+ module Encoding
11
+
12
+ # Default mapping between tag symbols and methods
13
+ DEFAULT_RULESET = {'&' => :main_encoding, '&;' => :entities_encoding,
14
+ "&'" => :single_quoting, '&"' => :double_quoting,
15
+ "$" => :injection, "'" => :single_quoted,
16
+ '"' => :double_quoted}
17
+
18
+ # Main encoding as <tt>&{...}</tt>
19
+ def self.main_encoding(parser, offset)
20
+ parsed, reached = parser.parse(offset)
21
+ result = parser.encode(parsed, "main-encoding")
22
+ [result, reached]
23
+ end
24
+
25
+ # Entities-encoding as <tt>&;{...}</tt>
26
+ def self.entities_encoding(parser, offset)
27
+ parsed, reached = parser.parse(offset)
28
+ result = parser.encode(parsed, "entities-encoding")
29
+ [result, reached]
30
+ end
31
+
32
+ # Single-quoting as <tt>&'{...}</tt>
33
+ def self.single_quoting(parser, offset)
34
+ parsed, reached = parser.parse(offset)
35
+ result = parser.encode(parsed, "single-quoting")
36
+ [result, reached]
37
+ end
38
+
39
+ # Double-quoting as <tt>&"{...}</tt>
40
+ def self.double_quoting(parser, offset)
41
+ parsed, reached = parser.parse(offset)
42
+ result = parser.encode(parsed, "double-quoting")
43
+ [result, reached]
44
+ end
45
+
46
+ # Injection as <tt>${wlang/ruby}</tt>
47
+ def self.injection(parser, offset)
48
+ expression, reached = parser.parse(offset, "wlang/ruby")
49
+ result = parser.evaluate(expression)
50
+ encoded = parser.encode(result.to_s, "main-encoding")
51
+ [encoded, reached]
52
+ end
53
+
54
+ # Single-quoted as <tt>'{wlang/ruby}</tt>
55
+ def self.single_quoted(parser, offset)
56
+ expression, reached = parser.parse(offset, "wlang/ruby")
57
+ result = parser.evaluate(expression)
58
+ encoded = parser.encode(result.to_s, "single-quoting")
59
+ ["'" << encoded, reached]
60
+ end
61
+
62
+ # Double-quoted as <tt>"{wlang/ruby}</tt>
63
+ def self.double_quoted(parser, offset)
64
+ expression, reached = parser.parse(offset, "wlang/ruby")
65
+ result = parser.evaluate(expression)
66
+ encoded = parser.encode(result.to_s, "double-quoting")
67
+ ['"' << encoded, reached]
68
+ end
69
+
70
+ end # module Encoding
71
+
72
+ end
73
+ end
@@ -0,0 +1,132 @@
1
+ module WLang
2
+ class RuleSet
3
+
4
+ #
5
+ # Imperative ruleset, providing special tags to iterate and instantiate
6
+ # conditionaly.
7
+ #
8
+ # For an overview of this ruleset, see the wlang {specification file}[link://files/specification.html].
9
+ #
10
+ module Imperative
11
+ U=WLang::RuleSet::Utils
12
+
13
+ # Regular expression for #1 in <tt>*{wlang/hosted}{...}</tt>
14
+ EACH_REGEXP = /^([^\s]+)((\s+(using\s+([_a-z]+)))?(\s+(as\s+([a-z]+(,\s+[a-z]+)*)))?)?$/
15
+ # 1 23 4 5 6 7 8
16
+ # 1 2 3 4 5
17
+
18
+ # Default mapping between tag symbols and methods
19
+ DEFAULT_RULESET = {'?' => :conditional, '*' => :enumeration}
20
+
21
+ #
22
+ # Conditional as <tt>?{wlang/hosted}{...}{...}</tt>
23
+ #
24
+ # (third block is optional) Instantiates #1, looking for an expression in the
25
+ # hosting language. Evaluates it, looking for a boolean value (according to
26
+ # boolean semantics of the hosting language). If true, instantiates #2,
27
+ # otherwise instantiates #3 if present.
28
+ #
29
+ def self.conditional(parser, offset)
30
+ expression, reached = parser.parse(offset, "wlang/ruby")
31
+ value = parser.evaluate(expression)
32
+ if value
33
+ then_block, reached = parser.parse_block(reached)
34
+ if parser.has_block?(reached)
35
+ else_block, reached = parser.parse_block(reached, "wlang/dummy")
36
+ end
37
+ [then_block, reached]
38
+ else
39
+ then_block, reached = parser.parse_block(reached, "wlang/dummy")
40
+ else_block = ""
41
+ if parser.has_block?(reached)
42
+ else_block, reached = parser.parse_block(reached)
43
+ end
44
+ [else_block, reached]
45
+ end
46
+ end
47
+
48
+ # Install args on the parser
49
+ def self.merge_each_args(names, args)
50
+ hash = {}
51
+ size = names.length>args.length ? args.length : names.length
52
+ 0.upto(size-1) do |i|
53
+ hash[names[i]] = args[i]
54
+ end
55
+ hash
56
+ end
57
+
58
+ #
59
+ # Enumeration as <tt>*{wlang/hosted using each as x}{...}{...}</tt>
60
+ #
61
+ # (third block is optional) Instantiates #1, looking for an expression in the
62
+ # hosting language. Evaluates it, looking for an enumerable. Iterates all its
63
+ # elements, instanciating #2 for each of them (the iterated value is set under
64
+ # name x in the scope). If #3 is present, it is instantiated between elements.
65
+ #
66
+ def self.enumeration(parser, offset)
67
+ expression, reached = parser.parse(offset, "wlang/ruby")
68
+
69
+ # decode 'wlang/hosted using each as x' expression
70
+ hash = U.expr(:expr,
71
+ ["using", :var, false],
72
+ ["as", :multi_as, false]).decode(expression, parser)
73
+ hash[:using] = "each" unless hash[:using]
74
+ hash[:as] = [] unless hash[:as]
75
+ parser.syntax_error(offset, "invalid loop expression '#{expression}'") if hash.nil?
76
+
77
+ # evaluate 'wlang/hosted' sub-expression
78
+ value = hash[:expr]
79
+ if value.nil?
80
+ expression, reached = parser.parse_block(reached, "wlang/dummy")
81
+ expression, reached = parser.parse_block(reached, "wlang/dummy") if parser.has_block?(reached)
82
+ ["",reached]
83
+ else
84
+ raise "Enumerated value #{value} does not respond to #{hash[:using]}"\
85
+ unless value.respond_to?(hash[:using])
86
+
87
+ # some variables
88
+ iterator, names = hash[:using].to_sym, hash[:as]
89
+ buffer = parser.factor_buffer
90
+
91
+ # wlang start index of each block
92
+ block2, block3, theend = reached, nil, nil # *{}{block2}{block3}theend
93
+ first = true
94
+
95
+ # iterate now
96
+ value.send iterator do |*args|
97
+ if not(first) and parser.has_block?(block3)
98
+ # parse #3, positioned at reached after that
99
+ parsed, theend = parser.parse_block(block3)
100
+ parser.append_buffer(buffer, parsed, true)
101
+ end
102
+
103
+ # install arguments and parse block2, positioned at block3
104
+ parser.context_push(merge_each_args(names, args))
105
+ parsed, block3 = parser.parse_block(block2)
106
+ parser.append_buffer(buffer, parsed, true)
107
+ parser.context_pop
108
+ first = false
109
+ end
110
+
111
+ # Empty array special case
112
+ unless block3
113
+ parsed, block3 = parser.parse_block(block2, "wlang/dummy")
114
+ end
115
+
116
+ # Singleton array special case
117
+ unless theend
118
+ if parser.has_block?(block3)
119
+ parsed, theend = parser.parse_block(block3, "wlang/dummy")
120
+ else
121
+ theend = block3
122
+ end
123
+ end
124
+ [buffer, theend]
125
+ end
126
+
127
+ end
128
+
129
+ end # module Imperative
130
+
131
+ end
132
+ end
@@ -0,0 +1,296 @@
1
+ module WLang
2
+ class RuleSet
3
+ module Utils
4
+
5
+ # Regexp string for 'dialect'
6
+ DIALECT = '[-a-z]+'
7
+
8
+ # Regexp string for 'encoder'
9
+ ENCODER = '[-a-z]+'
10
+
11
+ # Regexp string for 'qualified/dialect'
12
+ QDIALECT = DIALECT + '([\/]' + DIALECT + ')*'
13
+
14
+ # Regexp string for 'qualified/encoder'
15
+ QENCODER = ENCODER + '([\/]' + ENCODER + ')*'
16
+
17
+ # Regexp string for 'user_variable'
18
+ VAR = '[a-z][a-z0-9_]*'
19
+
20
+ # Regexp string for expression in the hosting language
21
+ EXPR = '.*?'
22
+
23
+ # Regexp string for URI expresion
24
+ URI = '[^\s]+'
25
+
26
+ # Part of a with expression
27
+ WITH_PART = '(' + VAR + ')' + '\s*:\s*(' + EXPR + ')'
28
+
29
+ # Regexp string for with expression
30
+ WITH = WITH_PART + '(\s*,\s*(' + WITH_PART + '))*'
31
+
32
+ # Regexp string for as expression
33
+ MULTI_AS = VAR + '(' + '\s*,\s*' + VAR + ')*'
34
+
35
+ # USING string for as expression
36
+ USING = VAR + '(' + '\s*,\s*' + VAR + ')*'
37
+
38
+ # Basic blocks for building expressions
39
+ BASIC_BLOCKS = {
40
+ :dialect => {:str => DIALECT, :groups => 0, :decoder => nil},
41
+ :encoder => {:str => ENCODER, :groups => 0, :decoder => nil},
42
+ :qdialect => {:str => QDIALECT, :groups => 1, :decoder => nil},
43
+ :qencoder => {:str => QENCODER, :groups => 1, :decoder => nil},
44
+ :var => {:str => VAR, :groups => 0, :decoder => nil},
45
+ :expr => {:str => EXPR, :groups => 0, :decoder => :decode_expr},
46
+ :uri => {:str => URI, :groups => 0, :decoder => nil},
47
+ :with => {:str => WITH, :groups => 6, :decoder => :decode_with},
48
+ :multi_as => {:str => MULTI_AS, :groups => 1, :decoder => :decode_multi_as},
49
+ :using => {:str => USING, :groups => 1, :decoder => :decode_using}
50
+ }
51
+
52
+ # Regular expressions of built expressions
53
+ REGEXPS = {}
54
+
55
+ # Builds an expression.
56
+ def self.expr(*args)
57
+ expr = REGEXPS[args]
58
+ if expr.nil?
59
+ # 1) we simply create an equivalent regular expression in _str_
60
+ str, hash, count = '^\s*', {}, 0
61
+ args.each do |arg|
62
+ case arg
63
+ when Symbol
64
+ raise ArgumentError, "No reusable RuleSet::Utils block called #{arg}"\
65
+ unless BASIC_BLOCKS[arg]
66
+ str << '(' << BASIC_BLOCKS[arg][:str] << ')'
67
+ hash[arg] = [(count+=1), BASIC_BLOCKS[arg][:decoder]]
68
+ count += BASIC_BLOCKS[arg][:groups]
69
+ when Array
70
+ keyword, what, mandatory = arg
71
+ raise ArgumentError, "No reusable RuleSet::Utils block called #{what}"\
72
+ unless BASIC_BLOCKS[what]
73
+ mandatory = true if mandatory.nil?
74
+ unless mandatory
75
+ str << '('
76
+ count += 1
77
+ end
78
+ str << '\s+' << keyword << '\s+'
79
+ str << '(' << BASIC_BLOCKS[what][:str] << ')'
80
+ str << ')?' unless mandatory
81
+ hash[keyword.to_sym] = [(count+=1), BASIC_BLOCKS[what][:decoder]]
82
+ count += BASIC_BLOCKS[what][:groups]
83
+ else
84
+ raise ArgumentError, "Symbol or Array expected"
85
+ end
86
+ end
87
+ str << '\s*$'
88
+
89
+ # here is the expression, on which we put a decode method
90
+ expr = {:regexp => Regexp.new(str), :places => hash}
91
+ def expr.decode(str, parser=nil)
92
+ matchdata = self[:regexp].match(str)
93
+ return nil if matchdata.nil?
94
+ decoded = {}
95
+ self[:places].each_pair do |k,v|
96
+ value = matchdata[v[0]]
97
+ value = Utils.send(v[1], value, parser)\
98
+ if v[1] and not(value.nil?)
99
+ decoded[k] = value
100
+ end
101
+ return decoded
102
+ end
103
+
104
+ # and we save it!
105
+ REGEXPS[args] = expr
106
+ end
107
+ expr
108
+ end
109
+
110
+ # Decodes an expression using the parser
111
+ def self.decode_expr(expr, parser)
112
+ return expr if parser.nil?
113
+ parser.evaluate(expr)
114
+ end
115
+
116
+ # Regular expression for WITH
117
+ RG_WITH = Regexp.new('^' + WITH + '$')
118
+
119
+ # Decodes a with expression
120
+ def self.decode_with(expr, parser, hash={})
121
+ matchdata = RG_WITH.match(expr)
122
+ return hash if matchdata.nil?
123
+ hash[matchdata[1]] = decode_expr(matchdata[2], parser)
124
+ decode_with(matchdata[4], parser, hash)
125
+ end
126
+
127
+ # Decodes a multi as expression
128
+ def self.decode_multi_as(expr, parser)
129
+ expr.split(/\s*,\s*/)
130
+ end
131
+
132
+ # Decodes a multi as expression
133
+ def self.decode_using(expr, parser)
134
+ expr.split(/\s*,\s*/).collect{|s| decode_expr(s, parser)}
135
+ end
136
+
137
+ # Builds a hash for 'using ... with ...' rules from a decoded expression
138
+ def self.context_from_using_and_with(decoded)
139
+ context = decoded[:using]
140
+ context = context.dup unless context.nil?
141
+ context = {} if context.nil?
142
+ context.merge!(decoded[:with]) unless decoded[:with].nil?
143
+ context
144
+ end
145
+
146
+
147
+ ### DEPRECATED API ####################################################
148
+
149
+ # Regular expression for 'user_variable'
150
+ RG_VAR = Regexp.new('^\s*(' + VAR + ')\s*$')
151
+
152
+ # Regular expression for expression in the hosting language
153
+ RG_EXPR = Regexp.new('^\s*(' + EXPR + ')\s*$')
154
+
155
+ # Regular expression for expression in the hosting language
156
+ RG_URI = Regexp.new('^\s*(' + URI + ')\s*$')
157
+
158
+ # Part of a with expression
159
+ RG_WITH_PART = Regexp.new('(' + VAR + ')' + '\s*:\s*([^,]+)')
160
+
161
+ # Regular expression for 'dialect'
162
+ RG_DIALECT = Regexp.new('^\s*(' + DIALECT + ')\s*$')
163
+
164
+ # Regular expression for 'encoder'
165
+ RG_ENCODER = Regexp.new('^\s*(' + ENCODER + ')\s*$')
166
+
167
+ # Regular expression for 'qualified/dialect'
168
+ RG_QDIALECT = Regexp.new('^\s*(' + QDIALECT + ')\s*$')
169
+
170
+ # Regular expression for 'qualified/encoder'
171
+ RG_QENCODER = Regexp.new('^\s*(' + QENCODER + ')\s*$')
172
+
173
+ # Regexp string for 'qualified/dialect as var'
174
+ QDIALECT_AS = '(' + QDIALECT + ')\s+as\s+(' + VAR + ')'
175
+
176
+ # Regular expression for 'qualified/dialect as var'
177
+ RG_QDIALECT_AS = Regexp.new('^\s*(' + QDIALECT_AS + ')\s*$')
178
+
179
+ # Regexp string for 'qualified/dialect with ...'
180
+ QDIALECT_WITH = '(' + QDIALECT + ')\s+as\s+(' + WITH + ')'
181
+
182
+ # Regular expression for 'qualified/dialect with ...'
183
+ RG_QDIALECT_WITH = Regexp.new('^\s*(' + QDIALECT_WITH + ')\s*$')
184
+
185
+ # Regexp string for 'qualified/encoder as var'
186
+ QENCODER_AS = '(' + QENCODER + ')\s+as\s+(' + VAR + ')'
187
+
188
+ # Regular expression for 'qualified/encoder as var'
189
+ RG_QENCODER_AS = Regexp.new('^\s*(' + QENCODER_AS + ')\s*$')
190
+
191
+ # Regexp string for 'wlang/hosted as var'
192
+ EXPR_AS = '(' + EXPR + ')\s+as\s+(' + VAR + ')'
193
+
194
+ # Regular expression for 'wlang/hosted as var'
195
+ RG_EXPR_AS = Regexp.new('^\s*(' + EXPR_AS + ')\s*$')
196
+
197
+ # Regexp string for 'wlang/uri as var'
198
+ URI_AS = '(' + URI + ')\s+as\s+(' + VAR + ')'
199
+
200
+ # Regular expression for 'wlang/uri as var'
201
+ RG_URI_AS = Regexp.new('^\s*(' + URI_AS + ')\s*$')
202
+
203
+ # Regespc string for 'wlang/uri with ...'
204
+ URI_WITH = '(' + URI + ')\s+with\s+(' + WITH + ')'
205
+
206
+ # Regular expression for 'wlang/uri as var'
207
+ RG_URI_WITH = Regexp.new('^\s*(' + URI_WITH + ')\s*$')
208
+
209
+ # Decodes a simple var expression
210
+ def self.decode_var(src)
211
+ match = RG_VAR.match(src)
212
+ return nil unless match
213
+ {:variable => match[1]}
214
+ end
215
+
216
+ # Decodes a 'qualified/dialect as var'. Returns a hash
217
+ # with :dialect and :variable keys, or nil if _str_ does
218
+ # not match.
219
+ def self.decode_qdialect_as(str)
220
+ match = RG_QDIALECT_AS.match(str)
221
+ return nil unless match
222
+ {:dialect => match[2], :variable => match[4]}
223
+ end
224
+
225
+ # Decodes a 'qualified/encoder as var'. Returns a hash
226
+ # with :encoder and :variable keys, or nil if _str_ does
227
+ # not match.
228
+ def self.decode_qencoder_as(str)
229
+ match = RG_QENCODER_AS.match(str)
230
+ return nil unless match
231
+ {:encoder => match[2], :variable => match[4]}
232
+ end
233
+
234
+ # Decodes a 'wlang/hosted as var'. Returns a hash
235
+ # with :expression and :variable keys, or nil if _str_ does
236
+ # not match.
237
+ def self.decode_expr_as(str)
238
+ match = RG_EXPR_AS.match(str)
239
+ return nil unless match
240
+ {:expr => match[2], :variable => match[3]}
241
+ end
242
+
243
+ # Decodes a 'wlang/uri as var'. Returns a hash
244
+ # with :uri and :variable keys, or nil if _str_ does
245
+ # not match.
246
+ def self.decode_uri_as(str)
247
+ match = RG_URI_AS.match(str)
248
+ return nil unless match
249
+ {:uri => match[2], :variable => match[3]}
250
+ end
251
+
252
+ # Decodes a 'wlang/uri with ...'. Returns a hash
253
+ # with :uri and :with keys (with being another hash), or nil if _str_ does
254
+ # not match.
255
+ def self.decode_uri_with(str, parser=nil, optional=false)
256
+ match = RG_URI_WITH.match(str)
257
+ if match.nil?
258
+ return nil unless optional
259
+ match = RG_URI.match(str)
260
+ return nil if match.nil?
261
+ return {:uri => match[1], :with => nil}
262
+ else
263
+ with_expr, with = match[3], {}
264
+ exprs = with_expr.split(/\s*,\s*/)
265
+ exprs.each do |expr|
266
+ RG_WITH_PART =~ expr
267
+ with[$1] = parser.nil? ? $2 : parser.evaluate($2)
268
+ end
269
+ {:uri => match[2], :with => with}
270
+ end
271
+ end
272
+
273
+ # Decodes a 'wlang/dialect with ...'. Returns a hash
274
+ # with :dialect and :with keys (with being another hash),
275
+ # or nil if _str_ does not match.
276
+ def self.decode_qdialect_with(str, parser=nil, optional=false)
277
+ match = RG_QDIALECT_WITH.match(str)
278
+ if match.nil?
279
+ return nil unless optional
280
+ match = RG_QDIALECT.match(str)
281
+ return nil if match.nil?
282
+ return {:dialect => match[1], :with => nil}
283
+ else
284
+ with_expr, with = match[3], {}
285
+ exprs = with_expr.split(/\s*,\s*/)
286
+ exprs.each do |expr|
287
+ RG_WITH_PART =~ expr
288
+ with[$1] = parser.nil? ? $2 : parser.evaluate($2)
289
+ end
290
+ {:dialect => match[2], :with => with}
291
+ end
292
+ end
293
+
294
+ end
295
+ end
296
+ end