wlang 0.8.4 → 0.8.5

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/lib/wlang.rb CHANGED
@@ -18,7 +18,7 @@ require 'wlang/intelligent_buffer'
18
18
  module WLang
19
19
 
20
20
  # Current version of WLang
21
- VERSION = "0.8.4".freeze
21
+ VERSION = "0.8.5".freeze
22
22
 
23
23
  # Reusable string for building dialect name based regexps
24
24
  DIALECT_NAME_REGEXP_STR = "[-a-z]+"
data/lib/wlang/errors.rb CHANGED
@@ -3,35 +3,14 @@ module WLang
3
3
  # Main error of all WLang errors.
4
4
  class Error < StandardError; end
5
5
 
6
+ # Raise when something fails when evaluting through the parser context
7
+ class EvalError < StandardError; end
8
+
6
9
  # Error raised by a WLang parser instanciation when an error occurs.
7
- class ParseError < StandardError;
8
-
9
- attr_reader :line, :column
10
-
11
- # Creates an error with offset information
12
- def initialize(message, offset=nil, template=nil)
13
- @offset = offset
14
- @line, @column = parse(template) if template
15
- unless template and offset
16
- super(message)
17
- else
18
- super("ParseError at #{@line}:#{@column} : #{message}")
19
- end
20
-
21
- end
10
+ class ParseError < StandardError;
22
11
 
23
- # Reparses the template and finds line:column locations
24
- def parse(template)
25
- template = template[0,@offset]
26
- if template =~ /\n/ then
27
- lines = template[0,@offset].split(/\n/)
28
- else
29
- lines = [template]
30
- end
31
- line, column = lines.length, lines.last.length
32
- return [line, column]
33
- end
12
+ attr_accessor :line, :column
34
13
 
35
- end # class ParseError
14
+ end
36
15
 
37
16
  end # module WLang
data/lib/wlang/parser.rb CHANGED
@@ -136,6 +136,8 @@ module WLang
136
136
  #
137
137
  def evaluate(expression)
138
138
  @context.evaluate(expression)
139
+ rescue Exception => ex
140
+ raise ::WLang::EvalError, "#{template.where(@offset)} evaluation of '#{expression}' failed", ex.backtrace
139
141
  end
140
142
 
141
143
  #
@@ -199,19 +201,25 @@ module WLang
199
201
  encoder.encode(src, options)
200
202
  end
201
203
 
204
+ # Raises an exception with a friendly message
205
+ def error(offset, message)
206
+ template.error(offset, message)
207
+ end
208
+
202
209
  #
203
210
  # Raises a ParseError at a given offset.
204
211
  #
205
212
  def syntax_error(offset, msg=nil)
206
213
  text = self.parse(offset, "wlang/dummy", "")
207
- raise ParseError, "Parse error at #{offset} on '#{text}': #{msg}"
214
+ msg = msg.nil? ? '' : ": #{msg}"
215
+ template.parse_error(offset, "parse error on '#{text}'#{msg}")
208
216
  end
209
217
 
210
218
  #
211
219
  # Raises a ParseError at a given offset for a missing block
212
220
  #
213
221
  def block_missing_error(offset)
214
- raise ParseError.new("Block expected", offset, @source_text)
222
+ template.parse_error(offset, "parse error, block was expected")
215
223
  end
216
224
 
217
225
  #
@@ -219,7 +227,7 @@ module WLang
219
227
  # specif. the expected character when EOF found
220
228
  #
221
229
  def unexpected_eof(offset, expected)
222
- raise ParseError.new("'#{expected}' expected, EOF found.", offset, @source_text)
230
+ template.parse_error(offset, "#{expected} expected, EOF found")
223
231
  end
224
232
 
225
233
  #
@@ -104,13 +104,6 @@ module WLang
104
104
  else
105
105
  @current_scope.__evaluate(expression)
106
106
  end
107
- rescue Exception => ex
108
- puts "Warning, some wlang exception when evaluating the expression\n#{expression}"
109
- puts "Message was: #{ex.message}"
110
- puts ex.backtrace.join("\n")
111
- puts "Current scope was:\n"
112
- puts @current_scope.__underlying.inspect
113
- return nil
114
107
  end
115
108
 
116
109
  # Pushes a new scope instance.
@@ -17,5 +17,19 @@ class String
17
17
  end
18
18
  alias :wlang :wlang_instantiate
19
19
 
20
+ def __wlang_column_of(index)
21
+ return 1 if index == 0
22
+ newline_index = rindex("\n", index - 1)
23
+ if newline_index
24
+ index - newline_index
25
+ else
26
+ index + 1
27
+ end
28
+ end
29
+
30
+ def __wlang_line_of(index)
31
+ self[0...index].count("\n") + 1
32
+ end
33
+
20
34
  end
21
35
 
@@ -20,8 +20,13 @@ module WLang
20
20
  # Rule implementation of <tt><<{wlang/uri}</tt>
21
21
  def self.input(parser, offset)
22
22
  uri, reached = parser.parse(offset, "wlang/uri")
23
- file = parser.template.file_resolve(uri, true)
24
- [File.read(file), reached]
23
+ file = parser.template.file_resolve(uri, false)
24
+ if File.file?(file) and File.readable?(file)
25
+ [File.read(file), reached]
26
+ else
27
+ text = parser.parse(offset, "wlang/dummy")[0]
28
+ parser.error(offset, "unable to apply input rule <<{#{text}}, not a file or not readable (#{file})")
29
+ end
25
30
  end
26
31
 
27
32
  # Rule implementation of <tt>>>{wlang/uri}</tt>
@@ -29,11 +34,15 @@ module WLang
29
34
  uri, reached = parser.parse(offset, "wlang/uri")
30
35
  file = parser.template.file_resolve(uri, false)
31
36
  dir = File.dirname(file)
32
- FileUtils.mkdir_p(dir) unless File.exists?(dir)
33
- File.open(file, "w") do |file|
34
- text, reached = parser.parse_block(reached, nil, file)
37
+ if File.writable?(dir) or not(File.exists?(dir))
38
+ FileUtils.mkdir_p(dir) unless File.exists?(dir)
39
+ File.open(file, "w") do |file|
40
+ text, reached = parser.parse_block(reached, nil, file)
41
+ end
42
+ ["", reached]
43
+ else
44
+ parser.error(offset, "unable to apply output rule >>{#{text}}, not a writable directory (#{file})")
35
45
  end
36
- ["", reached]
37
46
  end
38
47
 
39
48
  # Rule implementation of <<={wlang/uri as x}{...}
@@ -44,18 +53,23 @@ module WLang
44
53
  decoded = U.decode_uri_as(uri)
45
54
  parser.syntax_error(offset) if decoded.nil?
46
55
 
47
- file = parser.template.file_resolve(decoded[:uri], true)
48
- data = WLang::load_data(file)
56
+ file = parser.template.file_resolve(decoded[:uri], false)
57
+ if File.file?(file) and File.readable?(file)
58
+ data = WLang::load_data(file)
49
59
 
50
- # handle two different cases
51
- if parser.has_block?(reached)
52
- parser.context_push(decoded[:variable] => data)
53
- text, reached = parser.parse_block(reached)
54
- parser.context_pop
55
- [text, reached]
60
+ # handle two different cases
61
+ if parser.has_block?(reached)
62
+ parser.context_push(decoded[:variable] => data)
63
+ text, reached = parser.parse_block(reached)
64
+ parser.context_pop
65
+ [text, reached]
66
+ else
67
+ parser.context_define(decoded[:variable], data)
68
+ ["", reached]
69
+ end
56
70
  else
57
- parser.context_define(decoded[:variable], data)
58
- ["", reached]
71
+ text = parser.parse(offset, "wlang/dummy")[0]
72
+ parser.error(offset, "unable to apply data-assignment rule <<={#{text}} (#{file}), not a file or not readable (#{file})")
59
73
  end
60
74
  end
61
75
 
@@ -91,9 +105,14 @@ module WLang
91
105
  end
92
106
  end
93
107
 
94
- file = parser.template.file_resolve(decoded[:uri], true)
95
- instantiated = WLang::file_instantiate(file, context)
96
- [instantiated, reached]
108
+ file = parser.template.file_resolve(decoded[:uri], false)
109
+ if File.file?(file) and File.readable?(file)
110
+ instantiated = WLang::file_instantiate(file, context)
111
+ [instantiated, reached]
112
+ else
113
+ text = parser.parse(offset, "wlang/dummy")[0]
114
+ parser.error(offset, "unable to apply input-inclusion rule <<+{#{text}}, not a file or not readable (#{file})")
115
+ end
97
116
  end
98
117
 
99
118
 
@@ -52,10 +52,10 @@ module WLang
52
52
  # Returns template's source text
53
53
  def source_text
54
54
  case @source
55
- when String
56
- @source
57
- else
58
- @source.to_s
55
+ when String
56
+ @source
57
+ else
58
+ @source.to_s
59
59
  end
60
60
  end
61
61
 
@@ -73,6 +73,28 @@ module WLang
73
73
  end
74
74
  instantiated[0]
75
75
  end
76
+
77
+ # Returns a friendly position of an offset in the source text
78
+ def where(offset)
79
+ src = source_text
80
+ "#{@source_file}:#{src.__wlang_line_of(offset)}:#{src.__wlang_column_of(offset)-1}"
81
+ end
82
+
83
+ # Raises a WLang::Error for the given offset
84
+ def error(offset, msg = "")
85
+ src = source_text
86
+ line, column = src.__wlang_line_of(offset), src.__wlang_column_of(offset)-1
87
+ raise WLang::Error, "#{@source_file}:#{line}:#{column} #{msg}"
88
+ end
89
+
90
+ # Raises a friendly ParseError, with positions and so on
91
+ def parse_error(offset, msg = "")
92
+ src = source_text
93
+ line, column = src.__wlang_line_of(offset), src.__wlang_column_of(offset)-1
94
+ ex = ParseError.new("#{@source_file}:#{line}:#{column} #{msg}")
95
+ ex.line, ex.column = line, column
96
+ raise ex
97
+ end
76
98
 
77
99
  end # class Template
78
100
 
@@ -1,4 +1,4 @@
1
- require 'test/unit/testcase'
1
+ require 'test/unit'
2
2
  require 'wlang'
3
3
  module WLang
4
4
 
@@ -77,11 +77,11 @@ class ParserTest < Test::Unit::TestCase
77
77
  def test_parser_error_find_line_and_column
78
78
  assert_error_at_line_column("-{tag", 1, 5)
79
79
  assert_error_at_line_column("-{tag with spaces ", 1, 20)
80
- assert_error_at_line_column("-{tag as i}{\n", 1, 12)
81
- assert_error_at_line_column("-{tag as i}{\n\n", 1, 12)
82
- assert_error_at_line_column("-{tag as i}{\ntext\n", 2, 4)
83
- assert_error_at_line_column("-{tag as i}{\n\ntext\n", 3, 4)
84
- assert_error_at_line_column("-{tag as i}{\n\n\ntext\n", 4, 4)
80
+ assert_error_at_line_column("-{tag as i}{\n", 2, 0)
81
+ assert_error_at_line_column("-{tag as i}{\n\n", 3, 0)
82
+ assert_error_at_line_column("-{tag as i}{\ntext\n", 3, 0)
83
+ assert_error_at_line_column("-{tag as i}{\n\ntext\n", 4, 0)
84
+ assert_error_at_line_column("-{tag as i}{\n\n\ntext\n", 5, 0)
85
85
  end
86
86
 
87
87
  end # ParserTest
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wlang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.4
4
+ version: 0.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-14 00:00:00 +01:00
12
+ date: 2010-01-21 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15