wlang 0.8.5 → 0.9.1
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/CHANGELOG.rdoc +65 -0
- data/README.rdoc +85 -31
- data/bin/wlang +5 -0
- data/doc/specification/dialect.wtpl +14 -0
- data/doc/specification/dialects.wtpl +3 -0
- data/doc/specification/glossary.wtpl +4 -4
- data/doc/specification/rulesets.wtpl +9 -9
- data/doc/specification/specification.css +1 -0
- data/doc/specification/specification.html +68 -5
- data/doc/specification/specification.wtpl +12 -12
- data/doc/specification/specification.yml +9 -9
- data/doc/specification/symbols.wtpl +8 -8
- data/lib/wlang.rb +297 -75
- data/lib/wlang/dialect.rb +7 -3
- data/lib/wlang/dialects/coderay_dialect.rb +4 -4
- data/lib/wlang/dialects/plain_text_dialect.rb +13 -19
- data/lib/wlang/dialects/redcloth_dialect.rb +16 -0
- data/lib/wlang/dialects/ruby_dialect.rb +16 -2
- data/lib/wlang/dialects/standard_dialects.rb +20 -0
- data/lib/wlang/dialects/xhtml_dialect.rb +24 -1
- data/lib/wlang/encoder.rb +1 -1
- data/lib/wlang/encoder_set.rb +5 -0
- data/lib/wlang/errors.rb +70 -6
- data/lib/wlang/ext/hash_methodize.rb +13 -0
- data/lib/wlang/{ruby_extensions.rb → ext/string.rb} +9 -5
- data/lib/wlang/hash_scope.rb +89 -0
- data/lib/wlang/hosted_language.rb +146 -0
- data/lib/wlang/parser.rb +189 -126
- data/lib/wlang/parser_state.rb +94 -0
- data/lib/wlang/rule_set.rb +16 -3
- data/lib/wlang/rulesets/basic_ruleset.rb +14 -6
- data/lib/wlang/rulesets/buffering_ruleset.rb +20 -29
- data/lib/wlang/rulesets/context_ruleset.rb +16 -20
- data/lib/wlang/rulesets/imperative_ruleset.rb +4 -4
- data/lib/wlang/rulesets/ruleset_utils.rb +26 -5
- data/lib/wlang/template.rb +16 -34
- data/lib/wlang/wlang_command.rb +4 -7
- data/lib/wlang/wlang_command_options.rb +5 -0
- data/test/blackbox/basic/execution_1.exp +1 -0
- data/test/blackbox/basic/execution_1.tpl +1 -0
- data/test/blackbox/basic/execution_2.exp +1 -0
- data/test/blackbox/basic/execution_2.tpl +1 -0
- data/test/blackbox/basic/execution_3.exp +1 -0
- data/test/blackbox/basic/execution_3.tpl +1 -0
- data/test/blackbox/basic/execution_4.exp +1 -0
- data/test/blackbox/basic/execution_4.tpl +1 -0
- data/test/blackbox/basic/inclusion_1.exp +1 -0
- data/test/blackbox/basic/inclusion_1.tpl +1 -0
- data/test/blackbox/basic/inclusion_2.exp +1 -0
- data/test/blackbox/basic/inclusion_2.tpl +1 -0
- data/test/blackbox/basic/injection_1.exp +1 -0
- data/test/blackbox/basic/injection_1.tpl +1 -0
- data/test/blackbox/basic/injection_2.exp +1 -0
- data/test/blackbox/basic/injection_2.tpl +1 -0
- data/test/blackbox/basic/modulation_1.exp +1 -0
- data/test/blackbox/basic/modulation_1.tpl +1 -0
- data/test/blackbox/basic/modulation_2.exp +1 -0
- data/test/blackbox/basic/modulation_2.tpl +1 -0
- data/test/blackbox/basic/recursive_app_1.exp +1 -0
- data/test/blackbox/basic/recursive_app_1.tpl +1 -0
- data/test/blackbox/basic/recursive_app_2.exp +1 -0
- data/test/blackbox/basic/recursive_app_2.tpl +1 -0
- data/test/blackbox/buffering/data_1.rb +1 -0
- data/test/blackbox/buffering/data_assignment_1.exp +1 -0
- data/test/blackbox/buffering/data_assignment_1.tpl +1 -0
- data/test/blackbox/buffering/data_assignment_2.exp +1 -0
- data/test/blackbox/buffering/data_assignment_2.tpl +1 -0
- data/test/blackbox/buffering/data_assignment_3.exp +1 -0
- data/test/blackbox/buffering/data_assignment_3.tpl +1 -0
- data/test/blackbox/buffering/data_assignment_4.exp +1 -0
- data/test/blackbox/buffering/data_assignment_4.tpl +1 -0
- data/test/blackbox/buffering/input_1.exp +1 -0
- data/test/blackbox/buffering/input_1.tpl +1 -0
- data/test/blackbox/buffering/input_2.exp +1 -0
- data/test/blackbox/buffering/input_2.tpl +1 -0
- data/test/blackbox/buffering/input_3.exp +1 -0
- data/test/blackbox/buffering/input_3.tpl +1 -0
- data/test/blackbox/buffering/input_inclusion.exp +1 -0
- data/test/blackbox/buffering/input_inclusion.tpl +1 -0
- data/test/blackbox/buffering/input_inclusion_1.exp +0 -0
- data/test/blackbox/buffering/input_inclusion_1.tpl +1 -0
- data/test/blackbox/buffering/input_inclusion_2.exp +1 -0
- data/test/blackbox/buffering/input_inclusion_2.tpl +1 -0
- data/test/blackbox/buffering/input_inclusion_3.exp +1 -0
- data/test/blackbox/buffering/input_inclusion_3.tpl +1 -0
- data/test/blackbox/buffering/input_inclusion_4.exp +0 -0
- data/test/blackbox/buffering/input_inclusion_4.tpl +1 -0
- data/test/blackbox/buffering/input_inclusion_5.exp +1 -0
- data/test/blackbox/buffering/input_inclusion_5.tpl +1 -0
- data/test/blackbox/buffering/input_inclusion_6.exp +1 -0
- data/test/blackbox/buffering/input_inclusion_6.tpl +1 -0
- data/test/blackbox/buffering/input_inclusion_7.exp +0 -0
- data/test/blackbox/buffering/input_inclusion_7.tpl +1 -0
- data/test/blackbox/buffering/text_1.txt +1 -0
- data/test/blackbox/buffering/wlang.txt +1 -0
- data/test/blackbox/context/assignment_1.exp +1 -0
- data/test/blackbox/context/assignment_1.tpl +1 -0
- data/test/blackbox/context/assignment_2.exp +1 -0
- data/test/blackbox/context/assignment_2.tpl +1 -0
- data/test/blackbox/context/assignment_3.exp +2 -0
- data/test/blackbox/context/assignment_3.tpl +2 -0
- data/test/blackbox/context/assignment_4.exp +1 -0
- data/test/blackbox/context/assignment_4.tpl +1 -0
- data/test/blackbox/context/block_assignment_1.exp +1 -0
- data/test/blackbox/context/block_assignment_1.tpl +1 -0
- data/test/blackbox/context/block_assignment_2.exp +1 -0
- data/test/blackbox/context/block_assignment_2.tpl +1 -0
- data/test/blackbox/context/modulo_assignment_1.exp +1 -0
- data/test/blackbox/context/modulo_assignment_1.tpl +1 -0
- data/test/blackbox/context/modulo_assignment_2.exp +1 -0
- data/test/blackbox/context/modulo_assignment_2.tpl +1 -0
- data/test/blackbox/data_1.rb +1 -0
- data/test/blackbox/test_all.rb +59 -0
- data/test/spec/basic_object.spec +40 -0
- data/test/spec/global_extensions.rb +2 -0
- data/test/spec/hash_scope.spec +76 -0
- data/test/spec/redcloth_dialect.spec +24 -0
- data/test/spec/test_all.rb +8 -0
- data/test/spec/wlang.spec +53 -0
- data/test/spec/xhtml_dialect.spec +23 -0
- data/test/{test_all.rb → unit/test_all.rb} +1 -1
- data/test/{wlang → unit/wlang}/anagram_bugs_test.rb +2 -2
- data/test/{wlang → unit/wlang}/basic_ruleset_test.rb +1 -1
- data/test/{wlang → unit/wlang}/buffering_ruleset_test.rb +4 -4
- data/test/{wlang → unit/wlang}/buffering_template1.wtpl +0 -0
- data/test/{wlang → unit/wlang}/buffering_template2.wtpl +0 -0
- data/test/{wlang → unit/wlang}/buffering_template3.wtpl +0 -0
- data/test/unit/wlang/buffering_template4.wtpl +1 -0
- data/test/unit/wlang/buffering_template5.wtpl +1 -0
- data/test/{wlang → unit/wlang}/context_ruleset_test.rb +0 -0
- data/test/{wlang → unit/wlang}/data.rb +0 -0
- data/test/{wlang → unit/wlang}/encoder_set_test.rb +0 -0
- data/test/{wlang → unit/wlang}/imperative_ruleset_test.rb +0 -0
- data/test/{wlang → unit/wlang}/intelligent_buffer_test.rb +0 -0
- data/test/{wlang → unit/wlang}/othersymbols_test.rb +0 -0
- data/test/{wlang → unit/wlang}/parser_test.rb +10 -11
- data/test/{wlang → unit/wlang}/plain_text_dialect_test.rb +0 -0
- data/test/{wlang → unit/wlang}/ruby_dialect_test.rb +0 -0
- data/test/{wlang → unit/wlang}/ruby_expected.rb +0 -0
- data/test/{wlang → unit/wlang}/ruby_template.wrb +0 -0
- data/test/{wlang → unit/wlang}/ruleset_utils_test.rb +0 -0
- data/test/{wlang → unit/wlang}/specification_examples_test.rb +2 -2
- data/test/{wlang → unit/wlang}/test_utils.rb +1 -1
- data/test/{wlang → unit/wlang}/wlang_test.rb +0 -0
- metadata +135 -42
- data/lib/wlang/basic_object.rb +0 -19
- data/lib/wlang/parser_context.rb +0 -139
- data/test/sandbox.rb +0 -1
- data/test/wlang/buffering_template4.wtpl +0 -1
- data/test/wlang/buffering_template5.wtpl +0 -1
- data/test/wlang/parser_context_test.rb +0 -29
data/lib/wlang/dialect.rb
CHANGED
|
@@ -3,8 +3,8 @@ require 'wlang/rule_set'
|
|
|
3
3
|
module WLang
|
|
4
4
|
|
|
5
5
|
#
|
|
6
|
-
# Implements the _dialect_ abstraction (see {README}[link://files/README.
|
|
7
|
-
# A dialect instance is
|
|
6
|
+
# Implements the _dialect_ abstraction (see {README}[link://files/README.rdoc]).
|
|
7
|
+
# A dialect instance is an aggregation of encoders and ruleset (through EncoderSet
|
|
8
8
|
# and RuleSet classes). A dialect is also a node in the dialect tree and has a
|
|
9
9
|
# qualified name through this tree. For example <tt>wlang/xhtml</tt> is the
|
|
10
10
|
# qualified name of a <tt>xhtml</tt> dialect which is a child dialect of
|
|
@@ -14,6 +14,7 @@ module WLang
|
|
|
14
14
|
# Language instead (see WLang::Dialect::DSL).
|
|
15
15
|
#
|
|
16
16
|
# === For developers only
|
|
17
|
+
#
|
|
17
18
|
# In order to avoid having users to install all required gems of all dialects
|
|
18
19
|
# wlang implements a lazy load design pattern on the dialect tree, through the
|
|
19
20
|
# WLang::Dialect::DSL and WLang::Dialect::Loader classes. The former only creates
|
|
@@ -26,7 +27,7 @@ module WLang
|
|
|
26
27
|
# Standard dialect obtention methods (WLang#dialect as well as WLang::Dialect#dialect)
|
|
27
28
|
# ensure that returned dialects are built. If you obtain dialects another way,
|
|
28
29
|
# be sure that they are built before using them (is_built? and build! are your
|
|
29
|
-
# friends to
|
|
30
|
+
# friends to achieve that goal).
|
|
30
31
|
#
|
|
31
32
|
# Moreover, child dialects may require tools of their ancestors. The following
|
|
32
33
|
# invariant should always be respected: if a dialect is built, all its ancestors
|
|
@@ -47,6 +48,9 @@ module WLang
|
|
|
47
48
|
# Parent dialect
|
|
48
49
|
attr_reader :parent
|
|
49
50
|
|
|
51
|
+
# Sub dialects by name
|
|
52
|
+
attr_reader :dialects
|
|
53
|
+
|
|
50
54
|
#
|
|
51
55
|
# Creates a dialect instance. _builder_ block is a chunk of code of the DSL
|
|
52
56
|
# that will be executed twice: once at construction time to create sub dialects
|
|
@@ -13,7 +13,9 @@ module WLang
|
|
|
13
13
|
|
|
14
14
|
# Default encoders
|
|
15
15
|
DEFAULT_ENCODERS = {"java" => :coderay, "ruby" => :coderay, "html" => :coderay,
|
|
16
|
-
"yaml" => :coderay
|
|
16
|
+
"yaml" => :coderay, "sql" => :coderay, "css" => :coderay,
|
|
17
|
+
"javascript" => :coderay, "json" => :coderay, "php" => :coderay,
|
|
18
|
+
"xml" => :coderay}
|
|
17
19
|
|
|
18
20
|
# Upcase encoding
|
|
19
21
|
def self.coderay(src, options);
|
|
@@ -21,10 +23,8 @@ module WLang
|
|
|
21
23
|
encoder = $1.to_sym
|
|
22
24
|
tokens = CodeRay.scan src, encoder
|
|
23
25
|
highlighted = tokens.html({
|
|
24
|
-
:line_numbers => :inline,
|
|
25
26
|
:wrap => :div,
|
|
26
|
-
:css => :
|
|
27
|
-
:style => :cygnus}
|
|
27
|
+
:css => :class}
|
|
28
28
|
)
|
|
29
29
|
return highlighted
|
|
30
30
|
end
|
|
@@ -5,20 +5,14 @@ module WLang
|
|
|
5
5
|
module PlainText
|
|
6
6
|
|
|
7
7
|
# Default encoders
|
|
8
|
-
DEFAULT_ENCODERS = {"upcase"
|
|
9
|
-
"downcase"
|
|
10
|
-
"capitalize"
|
|
11
|
-
"camel
|
|
8
|
+
DEFAULT_ENCODERS = {"upcase" => :upcase,
|
|
9
|
+
"downcase" => :downcase,
|
|
10
|
+
"capitalize" => :capitalize,
|
|
11
|
+
"camel" => :camel_case,
|
|
12
|
+
"camel-case" => :camel_case,
|
|
13
|
+
"upper-camel" => :camel_case,
|
|
14
|
+
"lower-camel" => :lower_camel_case}
|
|
12
15
|
|
|
13
|
-
# Accents to replace when camel-casing
|
|
14
|
-
# ACCENTS = { ['á','à','â','ä','ã','Ã','Ä','Â','À'] => 'a',
|
|
15
|
-
# ['é','è','ê','ë','Ë','É','È','Ê'] => 'e',
|
|
16
|
-
# ['í','ì','î','ï','I','Î','Ì'] => 'i',
|
|
17
|
-
# ['ó','ò','ô','ö','õ','Õ','Ö','Ô','Ò'] => 'o',
|
|
18
|
-
# ['œ'] => 'oe',
|
|
19
|
-
# ['ß'] => 'ss',
|
|
20
|
-
# ['ú','ù','û','ü','U','Û','Ù'] => 'u'}
|
|
21
|
-
|
|
22
16
|
# Upcase encoding
|
|
23
17
|
def self.upcase(src, options); src.upcase; end
|
|
24
18
|
|
|
@@ -30,15 +24,15 @@ module WLang
|
|
|
30
24
|
|
|
31
25
|
# Converts a string as CamelCase
|
|
32
26
|
def self.camel_case(src, options)
|
|
33
|
-
|
|
34
|
-
# ac.each do |s|
|
|
35
|
-
# src.gsub!(s, rep)
|
|
36
|
-
# end
|
|
37
|
-
# end
|
|
38
|
-
src.gsub!(/[^a-zA-Z ]/," ")
|
|
27
|
+
src.gsub!(/[^a-zA-Z\s]/," ")
|
|
39
28
|
src = " " + src.split.join(" ")
|
|
40
29
|
src.gsub!(/ (.)/) { $1.upcase }
|
|
41
30
|
end
|
|
31
|
+
|
|
32
|
+
# Converts a string to lower camelCase
|
|
33
|
+
def self.lower_camel_case(src, options)
|
|
34
|
+
camel_case(src, options).gsub(/^([A-Z])/){ $1.downcase }
|
|
35
|
+
end
|
|
42
36
|
|
|
43
37
|
end # module PlainText
|
|
44
38
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
module WLang
|
|
3
|
+
class EncoderSet
|
|
4
|
+
module RedClothEncoders
|
|
5
|
+
|
|
6
|
+
# Default encoders
|
|
7
|
+
DEFAULT_ENCODERS = {"xhtml" => :xhtml_encoding}
|
|
8
|
+
|
|
9
|
+
# RDoc encoding
|
|
10
|
+
def self.xhtml_encoding(src, options)
|
|
11
|
+
RedCloth.new(src).to_html
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end # RedClothEncoders
|
|
15
|
+
end # module EncoderSet
|
|
16
|
+
end # module WLang
|
|
@@ -5,9 +5,14 @@ module WLang
|
|
|
5
5
|
module Ruby
|
|
6
6
|
|
|
7
7
|
# Default encoders
|
|
8
|
-
DEFAULT_ENCODERS = {"
|
|
8
|
+
DEFAULT_ENCODERS = {"main-encoding" => :main_encoding,
|
|
9
|
+
"single-quoting" => :single_quoting,
|
|
9
10
|
"double-quoting" => :double_quoting,
|
|
10
|
-
"regex-escaping" => :regex_escaping
|
|
11
|
+
"regex-escaping" => :regex_escaping,
|
|
12
|
+
"method-case" => :method_case}
|
|
13
|
+
|
|
14
|
+
# No-op encoding here
|
|
15
|
+
def self.main_encoding(src, options); src; end
|
|
11
16
|
|
|
12
17
|
# Single-quoting encoding
|
|
13
18
|
def self.single_quoting(src, options); src.gsub(/([^\\])'/,%q{\1\\\'}); end
|
|
@@ -17,6 +22,15 @@ module WLang
|
|
|
17
22
|
|
|
18
23
|
# Regexp-escaping encoding
|
|
19
24
|
def self.regex_escaping(src, options); Regexp.escape(src); end
|
|
25
|
+
|
|
26
|
+
# Converts any source to a typical ruby method name
|
|
27
|
+
def self.method_case(src, options)
|
|
28
|
+
src.strip.gsub(/[^a-zA-Z0-9\s]/," ").
|
|
29
|
+
gsub(/([A-Z])/){ " " + $1.downcase}.
|
|
30
|
+
strip.
|
|
31
|
+
gsub(/^([^a-z])/){ "_" + $1 }.
|
|
32
|
+
gsub(/\s+/){"_"}
|
|
33
|
+
end
|
|
20
34
|
|
|
21
35
|
end # module Ruby
|
|
22
36
|
|
|
@@ -27,6 +27,18 @@ WLang::dialect("ruby", ".rb", ".ruby") do
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
# sql dialect
|
|
31
|
+
WLang::dialect("sql", ".sql") do
|
|
32
|
+
ruby_require "wlang/dialects/sql_dialect" do
|
|
33
|
+
encoders WLang::EncoderSet::SQL
|
|
34
|
+
end
|
|
35
|
+
dialect("sybase", '.sybsql') do
|
|
36
|
+
ruby_require "wlang/dialects/sql_dialect" do
|
|
37
|
+
encoders WLang::EncoderSet::SQL::Sybase
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
30
42
|
# ruby dialect
|
|
31
43
|
WLang::dialect("xhtml", ".html", ".xhtml", ".htm") do
|
|
32
44
|
ruby_require "cgi", "wlang/dialects/xhtml_dialect" do
|
|
@@ -46,6 +58,13 @@ WLang::dialect("rdoc") do
|
|
|
46
58
|
end
|
|
47
59
|
end
|
|
48
60
|
|
|
61
|
+
# rdoc dialect
|
|
62
|
+
WLang::dialect("redcloth") do
|
|
63
|
+
ruby_require "RedCloth", "wlang/dialects/redcloth_dialect" do
|
|
64
|
+
encoders WLang::EncoderSet::RedClothEncoders
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
49
68
|
# wlang dialects
|
|
50
69
|
WLang::dialect("wlang") do
|
|
51
70
|
|
|
@@ -56,6 +75,7 @@ WLang::dialect("wlang") do
|
|
|
56
75
|
# wlang/active-string dialect
|
|
57
76
|
dialect("active-string") do
|
|
58
77
|
rules WLang::RuleSet::Basic
|
|
78
|
+
rules WLang::RuleSet::Imperative
|
|
59
79
|
end
|
|
60
80
|
|
|
61
81
|
# wlang/uri dialect
|
|
@@ -31,7 +31,30 @@ module WLang
|
|
|
31
31
|
module XHtml
|
|
32
32
|
|
|
33
33
|
# Default mapping between tag symbols and methods
|
|
34
|
-
DEFAULT_RULESET = {}
|
|
34
|
+
DEFAULT_RULESET = {'@' => :at}
|
|
35
|
+
|
|
36
|
+
def self.at(parser, offset)
|
|
37
|
+
# parse the url
|
|
38
|
+
url, reached = parser.parse(offset, 'wlang/active-string')
|
|
39
|
+
url = WLang::encode(url, 'wlang/xhtml/double-quoting')
|
|
40
|
+
|
|
41
|
+
# parse the label if there is one
|
|
42
|
+
label = nil
|
|
43
|
+
if parser.has_block?(reached)
|
|
44
|
+
label, reached = parser.parse_block(reached)
|
|
45
|
+
label = WLang::encode(label, 'wlang/xhtml/entities-encoding')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if label and url.respond_to?(:to_xhtml_link)
|
|
49
|
+
[url.to_xhtml_link(url, label), reached]
|
|
50
|
+
elsif url.respond_to?(:to_xhtml_href)
|
|
51
|
+
[url.to_xhtml_href(url), reached]
|
|
52
|
+
elsif label
|
|
53
|
+
["<a href=\"#{url}\">#{label}</a>", reached]
|
|
54
|
+
else
|
|
55
|
+
[url, reached]
|
|
56
|
+
end
|
|
57
|
+
end
|
|
35
58
|
|
|
36
59
|
end # module XHtml
|
|
37
60
|
|
data/lib/wlang/encoder.rb
CHANGED
|
@@ -56,7 +56,7 @@ module WLang
|
|
|
56
56
|
# - options: encoding options through a Hash. Available options are documented
|
|
57
57
|
# by encoders themselve.
|
|
58
58
|
#
|
|
59
|
-
def encode(src, options)
|
|
59
|
+
def encode(src, options = {})
|
|
60
60
|
raise(NotImplementedError) unless @block
|
|
61
61
|
@block.call(src, options)
|
|
62
62
|
end
|
data/lib/wlang/encoder_set.rb
CHANGED
|
@@ -25,6 +25,11 @@ module WLang
|
|
|
25
25
|
@encoders = {}
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
# Yields the block with name, encoder pairs
|
|
29
|
+
def each
|
|
30
|
+
@encoders.each_pair{|name,encoder| yield(name, encoder)}
|
|
31
|
+
end
|
|
32
|
+
|
|
28
33
|
#
|
|
29
34
|
# Adds an encoder under a specific name. Supported signatures are as follows:
|
|
30
35
|
# - _name_ is a symbol: _encoder_ and _block_ are ignored and encoder is
|
data/lib/wlang/errors.rb
CHANGED
|
@@ -1,16 +1,80 @@
|
|
|
1
1
|
module WLang
|
|
2
2
|
|
|
3
3
|
# Main error of all WLang errors.
|
|
4
|
-
class Error < StandardError
|
|
4
|
+
class Error < StandardError
|
|
5
|
+
|
|
6
|
+
# The parser state whe this error has been raised
|
|
7
|
+
attr_accessor :parser_state
|
|
8
|
+
|
|
9
|
+
# Optional cause (other lower level exception)
|
|
10
|
+
attr_accessor :cause
|
|
11
|
+
|
|
12
|
+
# Creates an error instance with a given parser state
|
|
13
|
+
def initialize(msg = nil, parser_state = nil, cause = nil)
|
|
14
|
+
raise ArgumentError, "msg expected to be nil or a String" unless (msg.nil? or String===msg)
|
|
15
|
+
raise ArgumentError, "parser_state expected to be nil or a State"\
|
|
16
|
+
unless (parser_state.nil? or ::WLang::Parser::State===parser_state)
|
|
17
|
+
super(msg)
|
|
18
|
+
@parser_state = parser_state
|
|
19
|
+
@cause = cause
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns a friendly wlang backtrace
|
|
23
|
+
def wlang_backtrace
|
|
24
|
+
parser_state ? parser_state.backtrace : ["no backtrace information, sorry"]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end # class Error
|
|
28
|
+
|
|
29
|
+
#
|
|
30
|
+
# Raised by hosted languages when something fails during
|
|
31
|
+
# evaluation.
|
|
32
|
+
#
|
|
33
|
+
class EvalError < ::WLang::Error
|
|
34
|
+
|
|
35
|
+
# The expression whose evaluation failed
|
|
36
|
+
attr_accessor :expression
|
|
37
|
+
|
|
38
|
+
# Creates an error instance with an optional expression that
|
|
39
|
+
# failed
|
|
40
|
+
def initialize(msg = nil, parser_state = nil, expression = nil, cause = nil)
|
|
41
|
+
super(msg, parser_state, cause)
|
|
42
|
+
@expression = expression
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_s
|
|
46
|
+
"Evaluation of #{@expression} failed, #{@cause ? @cause.message : ''}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end # class EvalError
|
|
5
50
|
|
|
6
|
-
#
|
|
7
|
-
|
|
51
|
+
#
|
|
52
|
+
# Raised when a variable may not be found in the current
|
|
53
|
+
# parser scope
|
|
54
|
+
#
|
|
55
|
+
class UndefinedVariableError < ::WLang::EvalError
|
|
56
|
+
|
|
57
|
+
# Name of the variable that could not be found
|
|
58
|
+
attr_accessor :variable
|
|
59
|
+
|
|
60
|
+
# Creates an error instance with an optional variable name
|
|
61
|
+
def initialize(msg = nil, parser_state = nil, expression = nil, variable = nil)
|
|
62
|
+
super(msg, parser_state, expression)
|
|
63
|
+
@variable = variable
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def to_s
|
|
67
|
+
"Unable to find variable #{@variable}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end # class UndefinedVariableError
|
|
8
71
|
|
|
9
72
|
# Error raised by a WLang parser instanciation when an error occurs.
|
|
10
|
-
class ParseError <
|
|
73
|
+
class ParseError < ::WLang::Error
|
|
11
74
|
|
|
75
|
+
# Where did the parsing failed
|
|
12
76
|
attr_accessor :line, :column
|
|
13
77
|
|
|
14
|
-
end
|
|
78
|
+
end # class ParseError
|
|
15
79
|
|
|
16
|
-
end # module WLang
|
|
80
|
+
end # module WLang
|
|
@@ -4,19 +4,21 @@
|
|
|
4
4
|
class String
|
|
5
5
|
|
|
6
6
|
# Converts the string to a wlang template
|
|
7
|
-
def wlang_template(dialect="wlang/active-string",
|
|
8
|
-
WLang::
|
|
7
|
+
def wlang_template(dialect = "wlang/active-string", block_symbols = :braces)
|
|
8
|
+
WLang::template(self, dialect, block_symbols)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
#
|
|
12
12
|
# Instantiates the string as a wlang template using
|
|
13
13
|
# a context object and a dialect.
|
|
14
14
|
#
|
|
15
|
-
def wlang_instantiate(context=nil, dialect="wlang/active-string", block_symbols
|
|
16
|
-
|
|
15
|
+
def wlang_instantiate(context = nil, dialect = "wlang/active-string", block_symbols = :braces)
|
|
16
|
+
WLang::instantiate(self, context, dialect, block_symbols)
|
|
17
17
|
end
|
|
18
18
|
alias :wlang :wlang_instantiate
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
# Computes the column number for a given offset in
|
|
21
|
+
# this string
|
|
20
22
|
def __wlang_column_of(index)
|
|
21
23
|
return 1 if index == 0
|
|
22
24
|
newline_index = rindex("\n", index - 1)
|
|
@@ -27,6 +29,8 @@ class String
|
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
|
|
32
|
+
# Computes the line number for a given offset in
|
|
33
|
+
# this string
|
|
30
34
|
def __wlang_line_of(index)
|
|
31
35
|
self[0...index].count("\n") + 1
|
|
32
36
|
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'delegate'
|
|
2
|
+
module WLang
|
|
3
|
+
#
|
|
4
|
+
# Implements a scoping mechanism on top of a ruby hash (accessible through pairing).
|
|
5
|
+
# Such a scope mimics hashses for has_key?, [] and []= methods. A scope has an
|
|
6
|
+
# accessible parent. Scopes form a tree, the root being accessible using its
|
|
7
|
+
# natural accessor. Scope lookup (has_key? and []) uses the hierarchy to find
|
|
8
|
+
# accessible variables.
|
|
9
|
+
#
|
|
10
|
+
# Branching a scope allows installing new variables that hide variables with the
|
|
11
|
+
# same name in the parent scope. Branching is made easy through the branch methods
|
|
12
|
+
# that accepts a block, passing the child as first argument:
|
|
13
|
+
#
|
|
14
|
+
# scope = HashScope.new(:name => 'wlang')
|
|
15
|
+
# puts scope[:name] # prints 'wlang'
|
|
16
|
+
# scope.branch(:name => 'other') do |child|
|
|
17
|
+
# puts child[:name] # prints 'other'
|
|
18
|
+
# end
|
|
19
|
+
# puts scope[:name] # prints 'wlang'
|
|
20
|
+
#
|
|
21
|
+
# This branching mechanism is intended to be used to keep a current scope as instance
|
|
22
|
+
# variable of a using class:
|
|
23
|
+
#
|
|
24
|
+
# # We create an initial scope at construction
|
|
25
|
+
# def initialize
|
|
26
|
+
# @scope = HashScope.new
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# # Appends the current scope with new key/value pairs. Yields the block
|
|
30
|
+
# # with the new scope and restore the original one after that.
|
|
31
|
+
# def do_something_with_a_new_scope(hash = {})
|
|
32
|
+
# @scope = @scope.branch(:name => 'other')
|
|
33
|
+
# yield if block_given?
|
|
34
|
+
# @scope = @scope.parent
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
class HashScope
|
|
38
|
+
|
|
39
|
+
# The parent scope, or nil if no such parent
|
|
40
|
+
attr_reader :parent
|
|
41
|
+
|
|
42
|
+
# The key/value pairing inside this scope
|
|
43
|
+
attr_reader :pairing
|
|
44
|
+
|
|
45
|
+
# Creates a scope instance with a parent and initial
|
|
46
|
+
# pairing through a Hash
|
|
47
|
+
def initialize(pairing = nil, parent = nil)
|
|
48
|
+
raise ArgumentError, "Hash expected for pairing #{pairing.class} received" unless (pairing.nil? or Hash===pairing)
|
|
49
|
+
@pairing = pairing || {}
|
|
50
|
+
@parent = parent
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns the root scope
|
|
54
|
+
def root
|
|
55
|
+
@root ||= (parent ? parent.root : self)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Checks if a key exists in this scope, delegating to
|
|
59
|
+
# parent if not found and allowed
|
|
60
|
+
def has_key?(key, delegate = true)
|
|
61
|
+
pairing.has_key?(key) || (!delegate.nil? && !parent.nil? && parent.has_key?(key))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Returns the value associated to a key, delegating to parent
|
|
65
|
+
# if not found and allowed
|
|
66
|
+
def [](key, delegate = true)
|
|
67
|
+
pairing.has_key?(key) ? pairing[key] : (delegate && parent && parent[key])
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Associates a key to a value inside this scope
|
|
71
|
+
def []=(key, value)
|
|
72
|
+
pairing[key] = value
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Creates a new child scope and returns it. If a block is given,
|
|
76
|
+
# yields the block with the child scope
|
|
77
|
+
def branch(pairing = nil)
|
|
78
|
+
child = HashScope.new(pairing, self)
|
|
79
|
+
yield child if block_given?
|
|
80
|
+
child
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Converts this scope to a full hash with all variables
|
|
84
|
+
def to_h
|
|
85
|
+
parent ? parent.to_h.merge(pairing) : pairing.dup
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end # class HashScope
|
|
89
|
+
end # module WLang
|