skeem 0.2.11 → 0.2.12

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: c08f4d71464aad98f53e99e6f66cd18e5961dbd1930353a560844b05d824e288
4
- data.tar.gz: f38223cedadc6689670c1d4db901a25cf18caf5b2761519e866909575228b5d9
3
+ metadata.gz: d37e901cd3042b1b0b81e29aa885c78bcfd61494e015508687187380be313d5d
4
+ data.tar.gz: 99918e85f8dafcd9a53465d77dfad99961786bafed16458d3d58eb2a36e39867
5
5
  SHA512:
6
- metadata.gz: 6618523bb5c1a4145b625ed5d264c1879f6980677df9c18e208f9a623652329cf952b4620a8c0c15c96cc38157e75f0590e9555535fa76b63a4361c866393bfb
7
- data.tar.gz: 2b0ce438844db721e855dc9a805a66dcacac97240895d3be96e09e9634b8d80056e7dd4cdcb9e36c98896bb536f36ef0801ae830173a8b7ff0d1f032cfd3f18f
6
+ metadata.gz: e0834459d4d616c84b66ac0e261737388002ba972586a343767ca1f41e5c3d2c52ee31a2367a75362e6b9c9618baf2b69b4feff81fee7e71acd4948900ddb9e1
7
+ data.tar.gz: 9653c511dd58eabbd15340becadbb4bd23d6bab4cd8ed454e6d98d9e4d304f7837d60775fd40b0528cac252958012a4a7c1c9e3421e3f28074033d21917c7a60
@@ -1,3 +1,19 @@
1
+ ## [0.2.12] - 2019-06-19
2
+ - Skeem now supports character datatype
3
+ - Added procedures: `boolean=?`, `char?`, `string`, `make-string`, `reverse`
4
+
5
+ ### Added
6
+ - Class `SkmChar`
7
+ - Method `SkmPair#proper?` to check whether a pair/list is a proper one.
8
+
9
+ ### Changed
10
+ - Class Tokenizer updated to recognize character literals (specified by name, by hexadecimal code, escaped).
11
+ - File `grammar.rb` Added new terminal CHAR and one derivation rule
12
+ - File `primitive_builder.rb` Implemented primitive procedures `boolean=?`, `char?`, `string`, `make-string`, `reverse`
13
+ - File `README.md` Added mentions to new procedures.
14
+ - File `tokenize_spec.rb`DRYing the spec file.`
15
+ - File `primitive_builder_spec.rb`: Added tests for new procedures.
16
+
1
17
  ## [0.2.11] - 2019-06-16
2
18
  - Added procedures: `gcd`, `lcm`, `numerator`, `denominator`, `floor`, `ceiling`, `truncate`,
3
19
  `round`.
@@ -19,12 +35,12 @@
19
35
 
20
36
  ### Changed
21
37
  - `DatumDSL#to_datum(aLiteral): added conversion of literal rational into rational value.
38
+ - Class Tokenizer updated to recognize rational numbers.
22
39
  - File `grammar.rb` Added new terminal RATIONAL and rule deriving number from rational
23
40
  - File `primitive_builder.rb` Implemented primitive procedures floor/ and truncate/
24
41
  - Class `SkmInteger` now inherits from `SkmRational` class
25
42
  - File `base.skm` added implementation of `floor-quotient`, `floor-remainder`, `truncate-quotient`,
26
43
  `truncate-remainder`, `quotient`, `remainder`, `modulo`
27
- - Class Tokenizer updated to recognize rational numbers.
28
44
  - Test suite file `base_tests.scm` expanded.
29
45
  - File `README.md` Added mentions to new procedures.
30
46
 
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  [![Gem Version](https://badge.fury.io/rb/skeem.svg)](https://badge.fury.io/rb/skeem)
7
7
  [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://github.com/famished-tiger/Skeem/blob/master/LICENSE.txt)
8
8
 
9
- __Skeem__ will be an interpreter of a subset of the Scheme programming language.
9
+ __Skeem__ is a Scheme language interpreter written in Ruby.
10
10
 
11
11
 
12
12
  ## Installation
@@ -171,10 +171,11 @@ Here are a few pointers for the Scheme programming language:
171
171
  - Block `#| ... |#` comments
172
172
 
173
173
  ### Data type literals
174
- - Booleans: `#t`, `#true`, `#f`, `#false`
174
+ - Booleans: `#t`, `#true`, `#f`, `#false`
175
+ - Characters: `#\a`, `#\newline`, `#\x3BB`
175
176
  - Of the number hierarchy:
176
177
  `real` (e.g. 2.718, 6.671e-11),
177
- `rational` (e.g. 22/7, 1/137, -13/41)
178
+ `rational` (e.g. 22/7, 1/137, -13/41)
178
179
  `integer` (42, -3)
179
180
  - Lists (quoted) : '(1 two "three")
180
181
  - Strings: `"Hello, world."`
@@ -250,6 +251,9 @@ This section lists the implemented standard procedures
250
251
  #### Boolean procedures
251
252
  * `boolean?`, `and`, `or`, `not`
252
253
 
254
+ #### Character procedures
255
+ * `char?`
256
+
253
257
  #### Numerical operations
254
258
  * Number-level: `number?`, `complex?`, `real?`, `rational?`, `integer?`, `zero?`, `exact?`, `inexact?`, `exact-integer?` , `+`, `-`, `*`, `/`,
255
259
  `=`, `square`, `number->string`
@@ -258,11 +262,11 @@ This section lists the implemented standard procedures
258
262
  * Integer-level: `even?`, `odd?`
259
263
 
260
264
  #### List procedures
261
- * `list?`, `null?`, `pair?`, `append`, `car`, `cdr`, `caar`, `cadr`, `cdar`, `cddr`, `cons`, `length`, `list`, `list-copy`, `list->vector`, `set-car!`, `set-cdr!`
265
+ * `list?`, `null?`, `pair?`, `append`, `car`, `cdr`, `caar`, `cadr`, `cdar`, `cddr`, `cons`, `length`, `list`, `list-copy`, `list->vector`, `reverse`, `set-car!`, `set-cdr!`
262
266
  , `assq`, `assv`
263
267
 
264
268
  #### String procedures
265
- * `string?`, `string=?`, `string-append`, `string-length`, `string->symbol`
269
+ * `string?`, `string=?`, `string`, `make-string`, `string-append`, `string-length`, `string->symbol`
266
270
 
267
271
  #### Symbol procedures
268
272
  * `symbol?`, `symbol=?`, `symbol->string`
@@ -15,8 +15,8 @@ module Skeem
15
15
  add_terminals('VECTOR_BEGIN')
16
16
 
17
17
  # Literal values...
18
- add_terminals('BOOLEAN', 'INTEGER', 'RATIONAL')
19
- add_terminals('REAL', 'STRING_LIT', 'IDENTIFIER')
18
+ add_terminals('BOOLEAN', 'INTEGER', 'RATIONAL', 'REAL')
19
+ add_terminals('CHAR', 'STRING_LIT', 'IDENTIFIER')
20
20
 
21
21
  # Keywords...
22
22
  add_terminals('BEGIN', 'COND', 'DEFINE', 'ELSE')
@@ -47,6 +47,7 @@ module Skeem
47
47
  rule('quotation' => 'LPAREN QUOTE datum RPAREN').as 'quotation'
48
48
  rule 'self-evaluating' => 'BOOLEAN'
49
49
  rule 'self-evaluating' => 'number'
50
+ rule 'self-evaluating' => 'CHAR'
50
51
  rule 'self-evaluating' => 'STRING_LIT'
51
52
  rule 'self-evaluating' => 'vector'
52
53
  rule 'datum' => 'simple_datum'
@@ -11,6 +11,7 @@ module Skeem
11
11
  add_comparison(aRuntime)
12
12
  add_number_procedures(aRuntime)
13
13
  add_boolean_procedures(aRuntime)
14
+ add_char_procedures(aRuntime)
14
15
  add_string_procedures(aRuntime)
15
16
  add_symbol_procedures(aRuntime)
16
17
  add_list_procedures(aRuntime)
@@ -89,10 +90,17 @@ module Skeem
89
90
  create_and(aRuntime)
90
91
  create_or(aRuntime)
91
92
  create_object_predicate(aRuntime, 'boolean?')
93
+ create_boolean_equal(aRuntime)
94
+ end
95
+
96
+ def add_char_procedures(aRuntime)
97
+ create_object_predicate(aRuntime, 'char?')
92
98
  end
93
99
 
94
100
  def add_string_procedures(aRuntime)
95
101
  create_object_predicate(aRuntime, 'string?')
102
+ create_make_string(aRuntime)
103
+ create_string_string(aRuntime)
96
104
  create_string_equal(aRuntime)
97
105
  create_string_append(aRuntime)
98
106
  create_string_length(aRuntime)
@@ -114,6 +122,7 @@ module Skeem
114
122
  create_length(aRuntime)
115
123
  create_list2vector(aRuntime)
116
124
  create_append(aRuntime)
125
+ create_reverse(aRuntime)
117
126
  create_setcar(aRuntime)
118
127
  create_setcdr(aRuntime)
119
128
  create_assq(aRuntime)
@@ -552,15 +561,61 @@ module Skeem
552
561
  define_primitive_proc(aRuntime, 'or', zero_or_more, primitive)
553
562
  end
554
563
 
555
- def create_string_equal(aRuntime)
564
+ # Return true, if all arguments have the same values
565
+ def all_same?(first_operand, arglist)
566
+ if arglist.empty?
567
+ boolean(true)
568
+ else
569
+ first_value = first_operand.value
570
+ all_equal = arglist.all? { |elem| first_value == elem.value }
571
+ boolean(all_equal)
572
+ end
573
+ end
574
+
575
+ def create_boolean_equal(aRuntime)
556
576
  primitive = ->(_runtime, first_operand, arglist) do
577
+ all_same?(first_operand, arglist)
578
+ end
579
+
580
+ define_primitive_proc(aRuntime, 'boolean=?', one_or_more, primitive)
581
+ end
582
+
583
+ def create_make_string(aRuntime)
584
+ primitive = ->(runtime, count_arg, arglist) do
585
+ count = count_arg
586
+ check_argtype(count, SkmInteger, 'integer', 'make_string')
557
587
  if arglist.empty?
558
- boolean(true)
588
+ filler = SkmChar.create(rand(0xff).chr)
559
589
  else
560
- first_value = first_operand.value
561
- all_equal = arglist.all? { |elem| first_value == elem.value }
562
- boolean(all_equal)
590
+ filler = arglist.first
591
+ check_argtype(filler, SkmChar, 'char', 'make_string')
563
592
  end
593
+ string(filler.value.to_s * count.value)
594
+ end
595
+
596
+ define_primitive_proc(aRuntime, 'make-string', one_or_two, primitive)
597
+ end
598
+
599
+ def create_string_string(aRuntime)
600
+ primitive = ->(_runtime, arglist) do
601
+ if arglist.empty?
602
+ value = ''
603
+ else
604
+ value = arglist.reduce('') do |interim, some_char|
605
+ check_argtype(some_char, SkmChar, 'character', 'string')
606
+ interim << some_char.value
607
+ end
608
+ end
609
+
610
+ string(value)
611
+ end
612
+
613
+ define_primitive_proc(aRuntime, 'string', zero_or_more, primitive)
614
+ end
615
+
616
+ def create_string_equal(aRuntime)
617
+ primitive = ->(_runtime, first_operand, arglist) do
618
+ all_same?(first_operand, arglist)
564
619
  end
565
620
 
566
621
  define_primitive_proc(aRuntime, 'string=?', one_or_more, primitive)
@@ -703,6 +758,23 @@ module Skeem
703
758
  define_primitive_proc(aRuntime, 'append', zero_or_more, primitive)
704
759
  end
705
760
 
761
+ def create_reverse(aRuntime)
762
+ primitive = ->(_runtime, arg_evaluated) do
763
+ check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'reverse')
764
+ if arg_evaluated == SkmEmptyList.instance
765
+ result = arg_evaluated
766
+ else
767
+ err_msg = 'reverse procedure requires a proper list as argument'
768
+ raise StandardError, err_msg unless arg_evaluated.proper?
769
+ elems_reversed = arg_evaluated.to_a.reverse
770
+ result = SkmPair.create_from_a(elems_reversed)
771
+ end
772
+ result
773
+ end
774
+
775
+ define_primitive_proc(aRuntime, 'reverse', unary, primitive)
776
+ end
777
+
706
778
  def create_setcar(aRuntime)
707
779
  # Arguments aren't evaluated yet!...
708
780
  primitive = ->(runtime, pair_arg, obj_arg) do
@@ -122,7 +122,6 @@ module Skeem
122
122
  result = code.call(aRuntime, evaluated_args)
123
123
  end
124
124
  else
125
- # require 'debug'
126
125
  args = operands.take(arity.low)
127
126
  args.map! { |arg| arg.evaluate(aRuntime) } unless args.empty?
128
127
  count_delta = operands.size - arity.low
@@ -14,6 +14,7 @@ module Skeem
14
14
  class SkmBuilder < Rley::ParseRep::ASTBaseBuilder
15
15
  Terminal2NodeClass = {
16
16
  'BOOLEAN' => SkmBoolean,
17
+ 'CHAR' => SkmChar,
17
18
  'IDENTIFIER' => SkmIdentifier,
18
19
  'INTEGER' => SkmInteger,
19
20
  'RATIONAL' => SkmRational,
@@ -32,6 +32,10 @@ module Skeem
32
32
  def boolean?
33
33
  false
34
34
  end
35
+
36
+ def char?
37
+ false
38
+ end
35
39
 
36
40
  def string?
37
41
  false
@@ -98,6 +98,11 @@ module Skeem
98
98
  cdr.last_pair
99
99
  end
100
100
  end
101
+
102
+ def proper?
103
+ last_node = self.last_pair
104
+ last_node.cdr.nil? || (last_node.cdr == SkmEmptyList.instance)
105
+ end
101
106
 
102
107
  def last
103
108
  self.to_a.last
@@ -97,7 +97,7 @@ module Skeem
97
97
  def number?
98
98
  true
99
99
  end
100
-
100
+
101
101
  def complex?
102
102
  false
103
103
  end
@@ -123,7 +123,7 @@ module Skeem
123
123
  def real?
124
124
  true
125
125
  end
126
-
126
+
127
127
  def complex?
128
128
  true
129
129
  end
@@ -132,7 +132,7 @@ module Skeem
132
132
  false
133
133
  end
134
134
  end # class
135
-
135
+
136
136
  class SkmRational < SkmReal
137
137
  def rational?
138
138
  true
@@ -141,7 +141,7 @@ module Skeem
141
141
  def exact?
142
142
  true
143
143
  end
144
- end # class
144
+ end # class
145
145
 
146
146
  class SkmInteger < SkmRational
147
147
  def integer?
@@ -149,6 +149,12 @@ module Skeem
149
149
  end
150
150
  end # class
151
151
 
152
+ class SkmChar < SkmSimpleDatum
153
+ def char?
154
+ true
155
+ end
156
+ end # class
157
+
152
158
  class SkmString < SkmSimpleDatum
153
159
  # Override
154
160
  def init_value(aValue)
@@ -78,7 +78,7 @@ module Skeem
78
78
  private
79
79
 
80
80
  def _next_token
81
- skip_whitespaces
81
+ skip_intertoken_spaces
82
82
  curr_ch = scanner.peek(1)
83
83
  return nil if curr_ch.nil? || curr_ch.empty?
84
84
 
@@ -91,10 +91,12 @@ module Skeem
91
91
  token = build_token('PERIOD', lexeme)
92
92
  elsif (lexeme = scanner.scan(/(?:,@?)|(?:=>)/))
93
93
  token = build_token(@@lexeme2name[lexeme], lexeme)
94
+ elsif (token = recognize_char_token)
95
+ # Do nothing
94
96
  elsif (lexeme = scanner.scan(/#(?:(?:true)|(?:false)|(?:u8)|[\\\(tfeiodx]|(?:\d+[=#]))/))
95
97
  token = cardinal_token(lexeme)
96
98
  elsif (lexeme = scanner.scan(/[+-]?[0-9]+\/[0-9]+(?=\s|[|()";]|$)/))
97
- token = build_token('RATIONAL', lexeme) # Decimal radix
99
+ token = build_token('RATIONAL', lexeme) # Decimal radix
98
100
  elsif (lexeme = scanner.scan(/[+-]?[0-9]+(?:.0+)?(?=\s|[|()";]|$)/))
99
101
  token = build_token('INTEGER', lexeme) # Decimal radix
100
102
  elsif (lexeme = scanner.scan(/[+-]?[0-9]+(?:\.[0-9]*)?(?:(?:e|E)[+-]?[0-9]+)?/))
@@ -128,11 +130,6 @@ module Skeem
128
130
  end
129
131
 
130
132
  =begin
131
- #t #f These are the boolean constants (section 6.3), along
132
- with the alternatives #true and #false.
133
- #\ This introduces a character constant (section 6.6).
134
- #( This introduces a vector constant (section 6.8). Vector
135
- constants are terminated by ) .
136
133
  #u8( This introduces a bytevector constant (section 6.9).
137
134
  Bytevector constants are terminated by ) .
138
135
  #e #i #b #o #d #x These are used in the notation for
@@ -152,6 +149,23 @@ other literal data (section 2.4).
152
149
  return token
153
150
  end
154
151
 
152
+ def recognize_char_token()
153
+ token = nil
154
+ if lexeme = scanner.scan(/#\\/)
155
+ if lexeme = scanner.scan(/(?:alarm|backspace|delete|escape|newline|null|return|space|tab)/)
156
+ token = build_token('CHAR', lexeme, :name)
157
+ elsif lexeme = scanner.scan(/[^x]/)
158
+ token = build_token('CHAR', lexeme, :escaped)
159
+ elsif lexeme = scanner.scan(/x[0-9a-fA-F]+/)
160
+ token = build_token('CHAR', lexeme, :hex_value)
161
+ elsif lexeme = scanner.scan(/x/)
162
+ token = build_token('CHAR', lexeme, :escaped)
163
+ end
164
+ end
165
+
166
+ token
167
+ end
168
+
155
169
  def build_token(aSymbolName, aLexeme, aFormat = :default)
156
170
  begin
157
171
  (value, symb) = convert_to(aLexeme, aSymbolName, aFormat)
@@ -178,6 +192,8 @@ other literal data (section 2.4).
178
192
  symb = 'INTEGER' if value.kind_of?(Integer)
179
193
  when 'REAL'
180
194
  value = to_real(aLexeme, aFormat)
195
+ when 'CHAR'
196
+ value = to_char(aLexeme, aFormat)
181
197
  when 'STRING_LIT'
182
198
  value = to_string(aLexeme, aFormat)
183
199
  when 'IDENTIFIER'
@@ -199,7 +215,7 @@ other literal data (section 2.4).
199
215
  value = aLexeme.to_i
200
216
  end
201
217
 
202
- return value
218
+ value
203
219
  end
204
220
 
205
221
  def to_rational(aLexeme, aFormat)
@@ -209,16 +225,29 @@ other literal data (section 2.4).
209
225
  value = value.numerator if value.denominator == 1
210
226
  end
211
227
 
212
- return value
228
+ value
213
229
  end
214
-
230
+
215
231
  def to_real(aLexeme, aFormat)
216
232
  case aFormat
217
233
  when :default
218
234
  value = aLexeme.to_f
219
235
  end
220
236
 
221
- return value
237
+ value
238
+ end
239
+
240
+ def to_char(aLexeme, aFormat)
241
+ case aFormat
242
+ when :name
243
+ value = named_char(aLexeme)
244
+ when :escaped
245
+ value = escaped_char(aLexeme)
246
+ when :hex_value
247
+ value = hex_value_char(aLexeme)
248
+ end
249
+
250
+ value
222
251
  end
223
252
 
224
253
  def to_string(aLexeme, aFormat)
@@ -239,7 +268,38 @@ other literal data (section 2.4).
239
268
  return value
240
269
  end
241
270
 
242
- def skip_whitespaces
271
+ def named_char(aLexeme)
272
+ name = aLexeme.sub(/^\#\\/, '')
273
+ name2char = {
274
+ 'alarm' => ?\a,
275
+ 'backspace' => ?\b,
276
+ 'delete' => ?\x7f,
277
+ 'escape' => ?\e,
278
+ 'newline' => ?\n,
279
+ 'null' => ?\x00,
280
+ 'return' => ?\r,
281
+ 'space' => ?\s,
282
+ 'tab' => ?\t
283
+ }
284
+
285
+ name2char[name]
286
+ end
287
+
288
+ def escaped_char(aLexeme)
289
+ aLexeme.chr
290
+ end
291
+
292
+ def hex_value_char(aLexeme)
293
+ hex_literal = aLexeme.sub(/^x/, '')
294
+ hex_value = hex_literal.to_i(16)
295
+ if hex_value < 0xff
296
+ hex_value.chr
297
+ else
298
+ [hex_value].pack('U')
299
+ end
300
+ end
301
+
302
+ def skip_intertoken_spaces
243
303
  pre_pos = scanner.pos
244
304
 
245
305
  loop do
@@ -1,3 +1,3 @@
1
1
  module Skeem
2
- VERSION = '0.2.11'.freeze
2
+ VERSION = '0.2.12'.freeze
3
3
  end
@@ -718,7 +718,7 @@ SKEEM
718
718
  ["(not 'nil)", false]
719
719
  ]
720
720
  compare_to_predicted(checks)
721
- end
721
+ end
722
722
 
723
723
  it 'should implement the list procedure' do
724
724
  checks = [
@@ -413,6 +413,16 @@ SKEEM
413
413
  ]
414
414
  compare_to_predicted(checks)
415
415
  end
416
+
417
+ it 'should implement the boolean=? procedure' do
418
+ checks = [
419
+ ['(boolean=? #t #t)', true],
420
+ ['(boolean=? #f #f)', true],
421
+ ['(boolean=? #t #f)', false],
422
+ ['(boolean=? #f #t)', false]
423
+ ]
424
+ compare_to_predicted(checks)
425
+ end
416
426
  end # context
417
427
 
418
428
  context 'String procedures:' do
@@ -444,6 +454,24 @@ SKEEM
444
454
  compare_to_predicted(checks)
445
455
  end
446
456
 
457
+ it 'should implement the string procedure' do
458
+ checks = [
459
+ ['(string)', ''],
460
+ ['(string #\a #\b #\c)', 'abc'],
461
+ ['(string #\H #\e #\l #\l #\o #\x021 #\newline)', "Hello!\n"]
462
+ ]
463
+ compare_to_predicted(checks)
464
+ end
465
+
466
+ it 'should implement the make-string procedure' do
467
+ checks = [
468
+ ['(make-string 0)', ''],
469
+ ['(make-string 0 #\x)', ''],
470
+ ['(make-string 5 #\x)', 'x' * 5]
471
+ ]
472
+ compare_to_predicted(checks)
473
+ end
474
+
447
475
  it 'should implement the string-append procedure' do
448
476
  checks = [
449
477
  ['(string-append)', ''],
@@ -637,6 +665,22 @@ SKEEM
637
665
  expect(result.cdr.cdr.cdr).to eq( SkmIdentifier.create('d'))
638
666
  end
639
667
 
668
+
669
+ it 'should implement the reverse procedure' do
670
+ checks = [
671
+ ["(reverse '())", SkmEmptyList.instance],
672
+ ["(reverse '(a b c))", array2list_ids(['c', 'b', 'a'])],
673
+ ["(reverse '((a) b c))", array2list_ids(['c', 'b']) << SkmPair.new(SkmIdentifier.create('a'), nil)]
674
+ ]
675
+ compare_to_predicted(checks) do |result, expectation|
676
+ if result.kind_of?(SkmPair)
677
+ expect(result.to_a).to eq(expectation)
678
+ else
679
+ expect(result).to eq(expectation)
680
+ end
681
+ end
682
+ end
683
+
640
684
  it 'should implement the list->vector procedure' do
641
685
  checks = [
642
686
  ["(list->vector '())", []],
@@ -11,6 +11,16 @@ module Skeem
11
11
  end
12
12
  end
13
13
 
14
+ # Assumption: subject is a Skeem::Tokenizer
15
+ def check_tokens(tokenTests, tokType)
16
+ tokenTests.each do |(input, prediction)|
17
+ subject.reinitialize(input)
18
+ token = subject.tokens.first
19
+ expect(token.terminal).to eq(tokType)
20
+ expect(token.lexeme).to eq(prediction)
21
+ end
22
+ end
23
+
14
24
  def unquoted(aString)
15
25
  aString.gsub(/(^")|("$)/, '')
16
26
  end
@@ -52,12 +62,7 @@ module Skeem
52
62
  [' #false', false]
53
63
  ]
54
64
 
55
- tests.each do |(input, prediction)|
56
- subject.reinitialize(input)
57
- token = subject.tokens.first
58
- expect(token.terminal).to eq('BOOLEAN')
59
- expect(token.lexeme).to eq(prediction)
60
- end
65
+ check_tokens(tests, 'BOOLEAN')
61
66
  end
62
67
  end # context
63
68
 
@@ -73,12 +78,7 @@ module Skeem
73
78
  ['-1234', -1234]
74
79
  ]
75
80
 
76
- tests.each do |(input, prediction)|
77
- subject.reinitialize(input)
78
- token = subject.tokens.first
79
- expect(token.terminal).to eq('INTEGER')
80
- expect(token.lexeme).to eq(prediction)
81
- end
81
+ check_tokens(tests, 'INTEGER')
82
82
  end
83
83
  end # context
84
84
 
@@ -90,18 +90,13 @@ module Skeem
90
90
  ['-22/7', -Rational(22, 7)],
91
91
  ]
92
92
 
93
- tests.each do |(input, prediction)|
94
- subject.reinitialize(input)
95
- token = subject.tokens.first
96
- expect(token.terminal).to eq('RATIONAL')
97
- expect(token.lexeme).to eq(prediction)
98
- end
99
-
93
+ check_tokens(tests, 'RATIONAL')
94
+
100
95
  # Special case: implicit promotion to integer
101
96
  subject.reinitialize('8/4')
102
97
  token = subject.tokens.first
103
98
  expect(token.terminal).to eq('INTEGER')
104
- expect(token.lexeme).to eq(2)
99
+ expect(token.lexeme).to eq(2)
105
100
  end
106
101
  end # context
107
102
 
@@ -115,12 +110,43 @@ module Skeem
115
110
  ['123e+45', 1.23e+47]
116
111
  ]
117
112
 
118
- tests.each do |(input, prediction)|
119
- subject.reinitialize(input)
120
- token = subject.tokens.first
121
- expect(token.terminal).to eq('REAL')
122
- expect(token.lexeme).to eq(prediction)
123
- end
113
+ check_tokens(tests, 'REAL')
114
+ end
115
+ end # context
116
+
117
+ context 'Character literal recognition:' do
118
+ it 'should tokenize named characters' do
119
+ tests = [
120
+ # couple [raw input, expected]
121
+ ["#\\alarm", ?\a],
122
+ ["#\\newline", ?\n],
123
+ ["#\\return", ?\r]
124
+ ]
125
+
126
+ check_tokens(tests, 'CHAR')
127
+ end
128
+
129
+ it 'should tokenize escaped characters' do
130
+ tests = [
131
+ # couple [raw input, expected]
132
+ ["#\\a", ?a],
133
+ ["#\\A", ?A],
134
+ ["#\\(", ?(],
135
+ ["#\\ ", ?\s]
136
+ ]
137
+
138
+ check_tokens(tests, 'CHAR')
139
+ end
140
+
141
+ it 'should tokenize hex-coded characters' do
142
+ tests = [
143
+ # couple [raw input, expected]
144
+ ["#\\x07", ?\a],
145
+ ["#\\x1B", ?\e],
146
+ ["#\\x3BB", ?\u03bb]
147
+ ]
148
+
149
+ check_tokens(tests, 'CHAR')
124
150
  end
125
151
  end # context
126
152
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skeem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.11
4
+ version: 0.2.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-16 00:00:00.000000000 Z
11
+ date: 2019-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley