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 +4 -4
- data/CHANGELOG.md +17 -1
- data/README.md +9 -5
- data/lib/skeem/grammar.rb +3 -2
- data/lib/skeem/primitive/primitive_builder.rb +77 -5
- data/lib/skeem/primitive/primitive_procedure.rb +0 -1
- data/lib/skeem/s_expr_builder.rb +1 -0
- data/lib/skeem/skm_element.rb +4 -0
- data/lib/skeem/skm_pair.rb +5 -0
- data/lib/skeem/skm_simple_datum.rb +10 -4
- data/lib/skeem/tokenizer.rb +72 -12
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/interpreter_spec.rb +1 -1
- data/spec/skeem/primitive/primitive_builder_spec.rb +44 -0
- data/spec/skeem/tokenizer_spec.rb +52 -26
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d37e901cd3042b1b0b81e29aa885c78bcfd61494e015508687187380be313d5d
|
4
|
+
data.tar.gz: 99918e85f8dafcd9a53465d77dfad99961786bafed16458d3d58eb2a36e39867
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0834459d4d616c84b66ac0e261737388002ba972586a343767ca1f41e5c3d2c52ee31a2367a75362e6b9c9618baf2b69b4feff81fee7e71acd4948900ddb9e1
|
7
|
+
data.tar.gz: 9653c511dd58eabbd15340becadbb4bd23d6bab4cd8ed454e6d98d9e4d304f7837d60775fd40b0528cac252958012a4a7c1c9e3421e3f28074033d21917c7a60
|
data/CHANGELOG.md
CHANGED
@@ -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__
|
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=?`,
|
269
|
+
* `string?`, `string=?`, `string`, `make-string`, `string-append`, `string-length`, `string->symbol`
|
266
270
|
|
267
271
|
#### Symbol procedures
|
268
272
|
* `symbol?`, `symbol=?`, `symbol->string`
|
data/lib/skeem/grammar.rb
CHANGED
@@ -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('
|
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
|
-
|
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
|
-
|
588
|
+
filler = SkmChar.create(rand(0xff).chr)
|
559
589
|
else
|
560
|
-
|
561
|
-
|
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
|
data/lib/skeem/s_expr_builder.rb
CHANGED
data/lib/skeem/skm_element.rb
CHANGED
data/lib/skeem/skm_pair.rb
CHANGED
@@ -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)
|
data/lib/skeem/tokenizer.rb
CHANGED
@@ -78,7 +78,7 @@ module Skeem
|
|
78
78
|
private
|
79
79
|
|
80
80
|
def _next_token
|
81
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
data/lib/skeem/version.rb
CHANGED
@@ -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
|
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
|
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
|
94
|
-
|
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
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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.
|
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-
|
11
|
+
date: 2019-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|