loxxy 0.2.01 → 0.2.02

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3137f0d16bb2c3dbbc4e2036abbf45888ba06b863fef69a8682898ffdb2a146b
4
- data.tar.gz: 344ff5f99e7d64dd45074aaacde5622ecb676d8d3112773555b0fbcffbd5aa89
3
+ metadata.gz: afc822710c5023cdffd8eeb9e9316736f2b2d9ddb2d05e4c4e835dee9b9b4d8b
4
+ data.tar.gz: 5debd7264833555cc34c64586de96d4e811eef4ebebe25f6c42a0832dee8e433
5
5
  SHA512:
6
- metadata.gz: f3cd447081d53619afeb040d9eade7fab0c0d5db79b8407fba412df727fb72849e5671679d7fd13fded703b9009399febfac6506ef91ac0bdd3220ef26472408
7
- data.tar.gz: 4a83b84a9853787369d51f48d7c2eacfe8a7e58b4ab8cb5d5322b02e0a5de68c4481effa61587db70f066902d21c7b2a310509de74d13f2cf1476a490e2728a7
6
+ metadata.gz: d988772978387faa28692101e6b2dab580a93b6f5738ad9094faf22d8aed78aca68123982ff0a25d9b9029d4d27ef4f82788009b10942a14ce5dd9bd9f1e37a7
7
+ data.tar.gz: 711b3188b0dd14a9821eee5227ee0d574c60144b7be88a3f722d10b4506556fa864685659c7493acfd6d63c2cf82f8c0c6c36cc0431a57a2d476efe3b4bf7efd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## [0.2.02] - 2021-04-21
2
+ - Improvements in the scanner class (escape sequence for quotes and newlines), error messages closer to jlox.
3
+
4
+ ### Changed
5
+ - File `loxxy` executable doesn't show a stack trace for scanner errors
6
+ - Class `ScannerError` is now a subclass of `Loxxy::Error`
7
+ - Class `Scanner` now returns a specific error message for unterminated strings
8
+ - Class `Scanner` error messages are closer to the ones from jlox
9
+ - Class `Scanner` supports now escape sequences \" for double quotes, \n for newlines
10
+ - File `README.md` Reshuffled some text
11
+
1
12
  ## [0.2.01] - 2021-04-18
2
13
  - Minor improvements in CLI, starting re-documenting `README.md`.
3
14
 
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Build status](https://ci.appveyor.com/api/projects/status/8e5p7dgjanm0qjkp?svg=true)](https://ci.appveyor.com/project/famished-tiger/loxxy)
4
4
  [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://github.com/famished-tiger/loxxy/blob/main/LICENSE.txt)
5
5
 
6
- ### What is loxxy?
6
+ ## What is loxxy?
7
7
  A Ruby implementation of the [Lox programming language](https://craftinginterpreters.com/the-lox-language.html ),
8
8
  a simple language defined in Bob Nystrom's excellent online book [Crafting Interpreters](https://craftinginterpreters.com/ ).
9
9
 
@@ -16,6 +16,14 @@ Although __Lox__ is fairly simple, it is far from being a toy language:
16
16
  - Functions and closures
17
17
  - Object-orientation (classes, methods, inheritance).
18
18
 
19
+ ### Loxxy gem features
20
+ - Complete tree-walking interpreter including lexer, parser and resolver
21
+ - 100% pure Ruby with clean design (not a port from some other language)
22
+ - Minimal runtime dependency (Rley gem). Won't drag a bunch of gems...
23
+ - Ruby API for integrating a Lox interpreter with your code.
24
+ - A command-line interpreter `loxxy`
25
+ - Open for your language extensions
26
+
19
27
  ## How to start in 1, 2, 3...?
20
28
  ... in less than 3 minutes...
21
29
 
@@ -42,10 +50,11 @@ Lo and behold! The output device displays the famous greeting:
42
50
  Hello, world.
43
51
 
44
52
 
45
- Congrats! You ran your first `Lox` program with __Loxxy__.
53
+ Congrats! You ran your first `Lox` program thanks __Loxxy__ gem.
54
+ For a less superficial encounter with the language jump to the next section.
46
55
 
47
- ### Something beefier?...
48
- Let's admit it, the hello world example was unimpressive.
56
+ ## So you want something beefier?...
57
+ Let's admit it, the hello world example was unimpressive.
49
58
  To a get a taste of `Lox` object-oriented capabilities, let's try another `Hello world` variant:
50
59
 
51
60
  ```javascript
@@ -172,12 +181,6 @@ Indeed, an open-source language that misses some features is an invitation for t
172
181
  There are already a number of programming languages derived from `Lox`...
173
182
 
174
183
  ## Why `Loxxy`? What's in it for me?...
175
- Features:
176
- - Complete tree-walking interpreter including lexer, parser and resolver
177
- - 100% pure Ruby with clean design (not a port from some other language)
178
- - Ruby API for integrating a Lox interpreter with your code.
179
- - Minimal runtime dependency (Rley gem). Won't drag a bunch of gems...
180
-
181
184
 
182
185
  ### Purpose of this project:
183
186
  - To deliver an open source example of a programming language fully implemented in Ruby
data/bin/loxxy CHANGED
@@ -17,11 +17,15 @@ class LoxxyRunner
17
17
  return if file_names.nil? || file_names.empty?
18
18
 
19
19
  lox = Loxxy::Interpreter.new
20
- file_names.each do |lox_file|
21
- fname = validate_filename(lox_file)
22
- next unless file_exist?(fname)
23
-
24
- File.open(fname, 'r') { |f| lox.evaluate(f.read) }
20
+ begin
21
+ file_names.each do |lox_file|
22
+ fname = validate_filename(lox_file)
23
+ next unless file_exist?(fname)
24
+
25
+ File.open(fname, 'r') { |f| lox.evaluate(f.read) }
26
+ end
27
+ rescue Loxxy::ScanError => e
28
+ $stderr.puts e.message
25
29
  end
26
30
  end
27
31
 
data/lib/loxxy/error.rb CHANGED
@@ -7,6 +7,9 @@ module Loxxy
7
7
  # Error occurring while Loxxy executes some invalid Lox code.
8
8
  class RuntimeError < Error; end
9
9
 
10
+ # Error occurring while Loxxy scans invalid input.
11
+ class ScanError < Error; end
12
+
10
13
  # Error occurring while Loxxy parses some invalid Lox code.
11
14
  class SyntaxError < Error; end
12
15
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'strscan'
4
4
  require 'rley'
5
+ require_relative '../error'
5
6
  require_relative '../datatype/all_datatypes'
6
7
  require_relative 'literal'
7
8
 
@@ -60,8 +61,6 @@ module Loxxy
60
61
  PRINT RETURN SUPER THIS TRUE VAR WHILE
61
62
  ].map { |x| [x, x] }.to_h
62
63
 
63
- class ScanError < StandardError; end
64
-
65
64
  # Constructor. Initialize a tokenizer for Lox input.
66
65
  # @param source [String] Lox text to tokenize.
67
66
  def initialize(source = nil)
@@ -117,11 +116,14 @@ module Loxxy
117
116
  keyw = @@keywords[lexeme.upcase]
118
117
  tok_type = keyw || 'IDENTIFIER'
119
118
  token = build_token(tok_type, lexeme)
119
+ elsif scanner.scan(/"(?:\\"|[^"])*\z/)
120
+ # Error: unterminated string...
121
+ col = scanner.pos - @line_start + 1
122
+ raise ScanError, "Error: [line #{lineno}:#{col}]: Unterminated string."
120
123
  else # Unknown token
121
- erroneous = curr_ch.nil? ? '' : scanner.scan(/./)
122
- sequel = scanner.scan(/.{1,20}/)
123
- erroneous += sequel unless sequel.nil?
124
- raise ScanError, "Unknown token #{erroneous} on line #{lineno}"
124
+ col = scanner.pos - @line_start + 1
125
+ _erroneous = curr_ch.nil? ? '' : scanner.scan(/./)
126
+ raise ScanError, "Error: [line #{lineno}:#{col}]: Unexpected character."
125
127
  end
126
128
 
127
129
  return token
@@ -156,7 +158,7 @@ module Loxxy
156
158
  when 'NUMBER'
157
159
  value = Datatype::Number.new(aLexeme)
158
160
  when 'STRING'
159
- value = Datatype::LXString.new(aLexeme)
161
+ value = Datatype::LXString.new(unescape_string(aLexeme))
160
162
  when 'TRUE'
161
163
  value = Datatype::True.instance
162
164
  else
@@ -166,6 +168,29 @@ module Loxxy
166
168
  return [value, symb]
167
169
  end
168
170
 
171
+ # Replace any sequence sequence by their "real" value.
172
+ def unescape_string(aText)
173
+ result = +''
174
+ previous = nil
175
+
176
+ aText.each_char do |ch|
177
+ if previous
178
+ if ch == ?n
179
+ result << "\n"
180
+ else
181
+ result << ch
182
+ end
183
+ previous = nil
184
+ elsif ch == '\\'
185
+ previous = ?\
186
+ else
187
+ result << ch
188
+ end
189
+ end
190
+
191
+ result
192
+ end
193
+
169
194
  # Skip non-significant whitespaces and comments.
170
195
  # Advance the scanner until something significant is found.
171
196
  def skip_intertoken_spaces
data/lib/loxxy/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loxxy
4
- VERSION = '0.2.01'
4
+ VERSION = '0.2.02'
5
5
  end
@@ -189,6 +189,26 @@ LOX_END
189
189
  end
190
190
  end
191
191
 
192
+ it 'should recognize escaped quotes' do
193
+ embedded_quotes = %q{she said: \"Hello\"}
194
+ result = subject.send(:unescape_string, embedded_quotes)
195
+ expect(result).to eq('she said: "Hello"')
196
+ end
197
+
198
+ it 'should recognize escaped backslash' do
199
+ embedded_backslash = 'backslash>\\\\'
200
+ result = subject.send(:unescape_string, embedded_backslash)
201
+ expect(result).to eq('backslash>\\')
202
+ end
203
+
204
+ # rubocop: disable Style/StringConcatenation
205
+ it 'should recognize newline escape sequence' do
206
+ embedded_newline = 'line1\\nline2'
207
+ result = subject.send(:unescape_string, embedded_newline)
208
+ expect(result).to eq('line1' + "\n" + 'line2')
209
+ end
210
+ # rubocop: enable Style/StringConcatenation
211
+
192
212
  it 'should recognize a nil token' do
193
213
  subject.start_with('nil')
194
214
  token_nil = subject.tokens[0]
@@ -237,6 +257,20 @@ LOX_END
237
257
  ]
238
258
  match_expectations(subject, expectations)
239
259
  end
260
+
261
+ it 'should complain if it finds an unterminated string' do
262
+ subject.start_with('var a = "Unfinished;')
263
+ err = Loxxy::ScanError
264
+ err_msg = 'Error: [line 1:21]: Unterminated string.'
265
+ expect { subject.tokens }.to raise_error(err, err_msg)
266
+ end
267
+
268
+ it 'should complain if it finds an unexpected character' do
269
+ subject.start_with('var a = ?1?;')
270
+ err = Loxxy::ScanError
271
+ err_msg = 'Error: [line 1:9]: Unexpected character.'
272
+ expect { subject.tokens }.to raise_error(err, err_msg)
273
+ end
240
274
  end # context
241
275
  end # describe
242
276
  end # module
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loxxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.01
4
+ version: 0.2.02
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-18 00:00:00.000000000 Z
11
+ date: 2021-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley