wlang 0.8.4

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