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 +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
|
[](https://badge.fury.io/rb/skeem)
|
7
7
|
[](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
|