skeem 0.2.11 → 0.2.12

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: 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