kdl 0.1.1 → 0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27d22aaf844ad47e14321925d2ef8d3346b0960fe5d284ca191fb25231571d2c
4
- data.tar.gz: c22e4025f6ed2f42654e899123f46a46f195ce7b14d002b2c240d6b24222871a
3
+ metadata.gz: dfb8d87e0f543090b994347f56085b076d82ce8050f52e49e112a2e723aafc09
4
+ data.tar.gz: 33443ec26405e8cd235275ab262378d2afc6bfebf4bf186a22580d6c62d8db07
5
5
  SHA512:
6
- metadata.gz: a810a2fbd5c1d3336e89bff3a59af3e93aa9d1c1fc80c37e5f02e93d9b96bec0a6cf6ad448b8c6d624d380dee65a5c99290c4352edb3acca5b673a4728c8aa45
7
- data.tar.gz: b1af0ff7997fac32d3d4640866b788cf884cfac8ca342e6de02296c59f5ef58b4d230d0a67be17cc687c98dd6ad15f0f21b729c2dbcd27f3ffadf2d5169f70ee
6
+ metadata.gz: '0396991421855a4b2c9b40263a50b255c8ab78b493604254437a6fe2cae9a05d8ac967c6fa19893e8712f210d5e882d6f98338331d56fa2b80e01c24c33b980e'
7
+ data.tar.gz: 9a3af62eae607011f76a1b154cf4604afd9d6cb38dacdaccc28f735720b8caec9789d6d75766904d395a4969a44b903e890363b7df17533349b8d8c2186a790e
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # KDL
2
2
 
3
- [![Actions Status](https://github.com/jellymann/kdl-rb/workflows/Ruby/badge.svg)](https://github.com/jellymann/kdl-rb\/actions)
3
+ [![Actions Status](https://github.com/jellymann/kdl-rb/workflows/Ruby/badge.svg)](https://github.com/jellymann/kdl-rb/actions)
4
4
 
5
5
  This is a Ruby implementation of the [KDL Document Language](https://kdl.dev)
6
6
 
@@ -33,15 +33,15 @@ rule
33
33
  node_term: linespaces | semicolon_term
34
34
  semicolon_term: SEMICOLON | SEMICOLON linespaces
35
35
 
36
- identifier: IDENT { val[0] }
37
- | STRING { val[0] }
36
+ identifier: IDENT { val[0].value }
37
+ | STRING { val[0].value }
38
38
 
39
39
  property: identifier EQUALS value { [val[0], val[2]] }
40
40
 
41
- value : STRING { KDL::Value::String.new(val[0]) }
42
- | RAWSTRING { KDL::Value::String.new(val[0]) }
43
- | INTEGER { KDL::Value::Int.new(val[0]) }
44
- | FLOAT { KDL::Value::Float.new(val[0]) }
41
+ value : STRING { KDL::Value::String.new(val[0].value) }
42
+ | RAWSTRING { KDL::Value::String.new(val[0].value) }
43
+ | INTEGER { KDL::Value::Int.new(val[0].value) }
44
+ | FLOAT { KDL::Value::Float.new(val[0].value) }
45
45
  | boolean { KDL::Value::Boolean.new(val[0]) }
46
46
  | NULL { KDL::Value::Null }
47
47
 
@@ -1,6 +1,32 @@
1
1
  module KDL
2
2
  class Tokenizer
3
- class Error < StandardError; end
3
+ class Error < StandardError
4
+ def initialize(message, line, column)
5
+ super("#{message} (#{line}:#{column})")
6
+ end
7
+ end
8
+
9
+ class Token
10
+ attr_reader :type, :value, :line, :column
11
+
12
+ def initialize(type, value, line, column)
13
+ @type = type
14
+ @value = value
15
+ @line = line
16
+ @column = column
17
+ end
18
+
19
+ def ==(other)
20
+ return false unless other.is_a?(Token)
21
+
22
+ type == other.type && value == other.value && line == other.line && column == other.column
23
+ end
24
+
25
+ def to_s
26
+ "#{value.inspect} (#{line}:#{column})"
27
+ end
28
+ alias inspect to_s
29
+ end
4
30
 
5
31
  attr_reader :index
6
32
 
@@ -32,11 +58,15 @@ module KDL
32
58
  @buffer = ""
33
59
  @done = false
34
60
  @previous_context = nil
61
+ @line = 1
62
+ @column = 1
35
63
  end
36
64
 
37
65
  def next_token
38
66
  @context = nil
39
67
  @previous_context = nil
68
+ @line_at_start = @line
69
+ @column_at_start = @column
40
70
  loop do
41
71
  c = @str[@index]
42
72
  case @context
@@ -45,11 +75,11 @@ module KDL
45
75
  when '"'
46
76
  self.context = :string
47
77
  @buffer = ''
48
- @index += 1
78
+ traverse(1)
49
79
  when 'r'
50
80
  if @str[@index + 1] == '"'
51
81
  self.context = :rawstring
52
- @index += 2
82
+ traverse(2)
53
83
  @rawstring_hashes = 0
54
84
  @buffer = ''
55
85
  next
@@ -69,20 +99,20 @@ module KDL
69
99
  end
70
100
  self.context = :ident
71
101
  @buffer = c
72
- @index += 1
102
+ traverse(1)
73
103
  when /[0-9\-+]/
74
104
  n = @str[@index + 1]
75
105
  if c == '0' && n =~ /[box]/
76
- @index += 2
106
+ traverse(2)
77
107
  @buffer = ''
78
108
  self.context = case n
79
- when 'b' then :binary
80
- when 'o' then :octal
81
- when 'x' then :hexadecimal
82
- end
109
+ when 'b' then :binary
110
+ when 'o' then :octal
111
+ when 'x' then :hexadecimal
112
+ end
83
113
  else
84
114
  self.context = :decimal
85
- @index += 1
115
+ traverse(1)
86
116
  @buffer = c
87
117
  end
88
118
  when '\\'
@@ -90,68 +120,74 @@ module KDL
90
120
  la = t.next_token[0]
91
121
  if la == :NEWLINE
92
122
  @index = t.index
123
+ new_line
93
124
  elsif la == :WS && (lan = t.next_token[0]) == :NEWLINE
94
125
  @index = t.index
126
+ new_line
95
127
  else
96
- raise Error, "Unexpected '\\'"
128
+ raise_error "Unexpected '\\'"
97
129
  end
98
130
  when *SYMBOLS.keys
99
- @index += 1
100
- return [SYMBOLS[c], c]
131
+ return token(SYMBOLS[c], c).tap { traverse(1) }
101
132
  when "\r"
102
133
  n = @str[@index + 1]
103
134
  if n == "\n"
104
- @index += 2
105
- return [:NEWLINE, "#{c}#{n}"]
135
+ return token(:NEWLINE, "#{c}#{n}").tap do
136
+ traverse(2)
137
+ new_line
138
+ end
106
139
  else
107
- @index += 1
108
- return [:NEWLINE, c]
140
+ return token(:NEWLINE, c).tap do
141
+ traverse(1)
142
+ new_line
143
+ end
109
144
  end
110
145
  when *NEWLINES
111
- @index += 1
112
- return [:NEWLINE, c]
146
+ return token(:NEWLINE, c).tap do
147
+ traverse(1)
148
+ new_line
149
+ end
113
150
  when "/"
114
151
  if @str[@index + 1] == '/'
115
152
  self.context = :single_line_comment
116
- @index += 2
153
+ traverse(2)
117
154
  elsif @str[@index + 1] == '*'
118
155
  self.context = :multi_line_comment
119
156
  @comment_nesting = 1
120
- @index += 2
157
+ traverse(2)
121
158
  elsif @str[@index + 1] == '-'
122
- @index += 2
123
- return [:SLASHDASH, '/-']
159
+ return token(:SLASHDASH, '/-').tap { traverse(2) }
124
160
  else
125
161
  self.context = :ident
126
162
  @buffer = c
127
- @index += 1
163
+ traverse(1)
128
164
  end
129
165
  when *WHITEPACE
130
166
  self.context = :whitespace
131
167
  @buffer = c
132
- @index += 1
168
+ traverse(1)
133
169
  when nil
134
- return [false, false] if @done
170
+ return [false, token(:EOF, :EOF)[1]] if @done
135
171
  @done = true
136
- return [:EOF, '']
172
+ return token(:EOF, :EOF)
137
173
  when INITIAL_IDENTIFIER_CHARS
138
174
  self.context = :ident
139
175
  @buffer = c
140
- @index += 1
176
+ traverse(1)
141
177
  else
142
- raise Error, "Unexpected character #{c.inspect}"
178
+ raise_error "Unexpected character #{c.inspect}"
143
179
  end
144
180
  when :ident
145
181
  case c
146
182
  when IDENTIFIER_CHARS
147
- @index += 1
183
+ traverse(1)
148
184
  @buffer += c
149
185
  else
150
186
  case @buffer
151
- when 'true' then return [:TRUE, true]
152
- when 'false' then return [:FALSE, false]
153
- when 'null' then return [:NULL, nil]
154
- else return [:IDENT, @buffer]
187
+ when 'true' then return token(:TRUE, true)
188
+ when 'false' then return token(:FALSE, false)
189
+ when 'null' then return token(:NULL, nil)
190
+ else return token(:IDENT, @buffer)
155
191
  end
156
192
  end
157
193
  when :string
@@ -159,18 +195,17 @@ module KDL
159
195
  when '\\'
160
196
  @buffer += c
161
197
  @buffer += @str[@index + 1]
162
- @index += 2
198
+ traverse(2)
163
199
  when '"'
164
- @index += 1
165
- return [:STRING, convert_escapes(@buffer)]
200
+ return token(:STRING, convert_escapes(@buffer)).tap { traverse(1) }
166
201
  when nil
167
- raise Error, "Unterminated string literal"
202
+ raise_error "Unterminated string literal"
168
203
  else
169
204
  @buffer += c
170
- @index += 1
205
+ traverse(1)
171
206
  end
172
207
  when :rawstring
173
- raise Error, "Unterminated rawstring literal" if c.nil?
208
+ raise_error "Unterminated rawstring literal" if c.nil?
174
209
 
175
210
  if c == '"'
176
211
  h = 0
@@ -178,17 +213,16 @@ module KDL
178
213
  h += 1
179
214
  end
180
215
  if h == @rawstring_hashes
181
- @index += 1 + h
182
- return [:RAWSTRING, @buffer]
216
+ return token(:RAWSTRING, @buffer).tap { traverse(1 + h) }
183
217
  end
184
218
  end
185
219
 
186
220
  @buffer += c
187
- @index += 1
221
+ traverse(1)
188
222
  when :decimal
189
223
  case c
190
224
  when /[0-9.\-+_eE]/
191
- @index += 1
225
+ traverse(1)
192
226
  @buffer += c
193
227
  else
194
228
  return parse_decimal(@buffer)
@@ -196,7 +230,7 @@ module KDL
196
230
  when :hexadecimal
197
231
  case c
198
232
  when /[0-9a-fA-F_]/
199
- @index += 1
233
+ traverse(1)
200
234
  @buffer += c
201
235
  else
202
236
  return parse_hexadecimal(@buffer)
@@ -204,7 +238,7 @@ module KDL
204
238
  when :octal
205
239
  case c
206
240
  when /[0-7_]/
207
- @index += 1
241
+ traverse(1)
208
242
  @buffer += c
209
243
  else
210
244
  return parse_octal(@buffer)
@@ -212,7 +246,7 @@ module KDL
212
246
  when :binary
213
247
  case c
214
248
  when /[01_]/
215
- @index += 1
249
+ traverse(1)
216
250
  @buffer += c
217
251
  else
218
252
  return parse_binary(@buffer)
@@ -220,51 +254,74 @@ module KDL
220
254
  when :single_line_comment
221
255
  if NEWLINES.include?(c) || c == "\r"
222
256
  self.context = nil
257
+ @column_at_start = @column
223
258
  next
224
259
  elsif c.nil?
225
260
  @done = true
226
- return [:EOF, '']
261
+ return token(:EOF, :EOF)
227
262
  else
228
- @index += 1
263
+ traverse(1)
229
264
  end
230
265
  when :multi_line_comment
231
266
  if c == '/' && @str[@index + 1] == '*'
232
267
  @comment_nesting += 1
233
- @index += 2
268
+ traverse(2)
234
269
  elsif c == '*' && @str[@index + 1] == '/'
235
270
  @comment_nesting -= 1
236
- @index += 2
271
+ traverse(2)
237
272
  if @comment_nesting == 0
238
273
  revert_context
239
274
  end
240
275
  else
241
- @index += 1
276
+ traverse(1)
242
277
  end
243
278
  when :whitespace
244
279
  if WHITEPACE.include?(c)
245
- @index += 1
280
+ traverse(1)
246
281
  @buffer += c
247
282
  elsif c == "\\"
248
283
  t = Tokenizer.new(@str, @index + 1)
249
284
  la = t.next_token[0]
250
285
  if la == :NEWLINE
251
286
  @index = t.index
287
+ new_line
252
288
  elsif (la == :WS && (lan = t.next_token[0]) == :NEWLINE)
253
289
  @index = t.index
290
+ new_line
254
291
  else
255
- raise Error, "Unexpected '\\'"
292
+ raise_error "Unexpected '\\'"
256
293
  end
257
294
  elsif c == "/" && @str[@index + 1] == '*'
258
295
  self.context = :multi_line_comment
259
296
  @comment_nesting = 1
260
- @index += 2
297
+ traverse(2)
261
298
  else
262
- return [:WS, @buffer]
299
+ return token(:WS, @buffer)
263
300
  end
264
301
  end
265
302
  end
266
303
  end
267
304
 
305
+ private
306
+
307
+ def token(type, value)
308
+ [type, Token.new(type, value, @line_at_start, @column_at_start)]
309
+ end
310
+
311
+ def traverse(n = 1)
312
+ @column += n
313
+ @index += n
314
+ end
315
+
316
+ def raise_error(message)
317
+ raise Error.new(message, @line, @column)
318
+ end
319
+
320
+ def new_line
321
+ @column = 1
322
+ @line += 1
323
+ end
324
+
268
325
  def context=(val)
269
326
  @previous_context = @context
270
327
  @context = val
@@ -275,23 +332,21 @@ module KDL
275
332
  @previous_context = nil
276
333
  end
277
334
 
278
- private
279
-
280
335
  def parse_decimal(s)
281
- return [:FLOAT, Float(munch_underscores(s))] if s =~ /[.eE]/
282
- [:INTEGER, Integer(munch_underscores(s), 10)]
336
+ return token(:FLOAT, Float(munch_underscores(s))) if s =~ /[.eE]/
337
+ token(:INTEGER, Integer(munch_underscores(s), 10))
283
338
  end
284
339
 
285
340
  def parse_hexadecimal(s)
286
- [:INTEGER, Integer(munch_underscores(s), 16)]
341
+ token(:INTEGER, Integer(munch_underscores(s), 16))
287
342
  end
288
343
 
289
344
  def parse_octal(s)
290
- [:INTEGER, Integer(munch_underscores(s), 8)]
345
+ token(:INTEGER, Integer(munch_underscores(s), 8))
291
346
  end
292
347
 
293
348
  def parse_binary(s)
294
- [:INTEGER, Integer(munch_underscores(s), 2)]
349
+ token(:INTEGER, Integer(munch_underscores(s), 2))
295
350
  end
296
351
 
297
352
  def munch_underscores(s)
@@ -308,12 +363,13 @@ module KDL
308
363
  when '\"' then "\""
309
364
  when '\b' then "\b"
310
365
  when '\f' then "\f"
311
- else raise Error, "Unexpected escape #{m.inspect}"
366
+ when '\/' then "/"
367
+ else raise_error "Unexpected escape #{m.inspect}"
312
368
  end
313
369
  end.gsub(/\\u\{[0-9a-fA-F]{0,6}\}/) do |m|
314
370
  i = Integer(m[3..-2], 16)
315
371
  if i < 0 || i > 0x10FFFF
316
- raise Error, "Invalid code point #{u}"
372
+ raise_error "Invalid code point #{u}"
317
373
  end
318
374
  i.chr(Encoding::UTF_8)
319
375
  end
@@ -1,3 +1,3 @@
1
1
  module KDL
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kdl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Smith
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-27 00:00:00.000000000 Z
11
+ date: 2021-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: racc
@@ -33,7 +33,6 @@ extra_rdoc_files: []
33
33
  files:
34
34
  - ".github/workflows/ruby.yml"
35
35
  - ".gitignore"
36
- - ".travis.yml"
37
36
  - CODE_OF_CONDUCT.md
38
37
  - Gemfile
39
38
  - LICENSE.txt
@@ -1,6 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.7.0
6
- before_install: gem install bundler -v 2.1.2