skeem 0.2.06 → 0.2.07
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 +9 -0
- data/README.md +5 -2
- data/lib/skeem/primitive/primitive_builder.rb +163 -49
- data/lib/skeem/primitive/primitive_procedure.rb +4 -0
- data/lib/skeem/s_expr_nodes.rb +8 -0
- data/lib/skeem/skm_element.rb +4 -0
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/primitive/primitive_builder_spec.rb +58 -0
- 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: 3dd3d2443ae53822f3ebf6f0ce042b52455fff6592bd8aa26e91e4ac548c2c87
|
4
|
+
data.tar.gz: 8eb8851aa0bf2b643949c1dd21284178a83891982eff75cffc1ec10ab1fbe537
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ebe0ba16a14e6c08638c63fabb83a38cd001914277a58bada5419020f92fbd83bfe7ad382ffa1bb44bb6307175f34108a407e60401f0c5657f11d484c97973aa
|
7
|
+
data.tar.gz: 4d61121cce897e2d4c4a6d3cb2b070522aa32785e76c18059cd86d6150bcd5e3d6ac6eb6c4bd2e1531dde19448341c938dc88b0d0722fd3ed1a6d605c7112344
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## [0.2.07] - 2019-05-31
|
2
|
+
- New standard procedures implemented: `list-copy`, `procedure?`, `apply` and `map`
|
3
|
+
|
4
|
+
### Added
|
5
|
+
- File `primitive_builder.rb`. New methods for implementing `list-copy`, `procedure?`, `apply` and `map`
|
6
|
+
|
7
|
+
### Changed
|
8
|
+
- File `README.md` Added mentions to new procedures.
|
9
|
+
|
1
10
|
## [0.2.06] - 2019-05-30
|
2
11
|
- NEW Special `cond` (= condional) form implemented. Supports `else` alternative and arrow (=>) syntax.
|
3
12
|
- FIX Corner case in procedure `append`.
|
data/README.md
CHANGED
@@ -160,7 +160,6 @@ Here are a few pointers for the Scheme programming language:
|
|
160
160
|
(signum -3)
|
161
161
|
SKEEM
|
162
162
|
|
163
|
-
# Ask Ruby to execute Scheme code
|
164
163
|
result = schemer.run(scheme_code)
|
165
164
|
puts result.value # => -1
|
166
165
|
```
|
@@ -187,6 +186,7 @@ Here are a few pointers for the Scheme programming language:
|
|
187
186
|
- Conditionals (if, cond)
|
188
187
|
- Definitions
|
189
188
|
- Assignments
|
189
|
+
- Control procedures
|
190
190
|
|
191
191
|
### Standard syntactic forms
|
192
192
|
#### define
|
@@ -251,7 +251,7 @@ This section lists the implemented standard procedures
|
|
251
251
|
* Integer-level: `even?`, `odd?`
|
252
252
|
|
253
253
|
#### List procedures
|
254
|
-
* `list?`, `null?`, `pair?`, `append`, `car`, `cdr`, `caar`, `cadr`, `cdar`, `cddr`, `cons`, `length`, `list`, `list->vector`, `set-car!`, `set-cdr!`
|
254
|
+
* `list?`, `null?`, `pair?`, `append`, `car`, `cdr`, `caar`, `cadr`, `cdar`, `cddr`, `cons`, `length`, `list`, `list-copy`, `list->vector`, `set-car!`, `set-cdr!`
|
255
255
|
|
256
256
|
#### String procedures
|
257
257
|
* `string?`, `string=?`, `string-append`, `string-length`, `string->symbol`
|
@@ -262,6 +262,9 @@ This section lists the implemented standard procedures
|
|
262
262
|
#### Vector procedures
|
263
263
|
* `vector?`, `make-vector`, `vector`, `vector-length`, `vector-set!`, `vector->list`
|
264
264
|
|
265
|
+
#### Control procedures
|
266
|
+
* `procedure?`, `apply`, `map`
|
267
|
+
|
265
268
|
#### Input/output procedures
|
266
269
|
* `newline`
|
267
270
|
|
@@ -17,6 +17,7 @@ module Skeem
|
|
17
17
|
add_symbol_procedures(aRuntime)
|
18
18
|
add_list_procedures(aRuntime)
|
19
19
|
add_vector_procedures(aRuntime)
|
20
|
+
add_control_procedures(aRuntime)
|
20
21
|
add_io_procedures(aRuntime)
|
21
22
|
add_special_procedures(aRuntime)
|
22
23
|
end
|
@@ -41,8 +42,8 @@ module Skeem
|
|
41
42
|
|
42
43
|
def one_or_two
|
43
44
|
SkmArity.new(1, 2)
|
44
|
-
end
|
45
|
-
|
45
|
+
end
|
46
|
+
|
46
47
|
def one_or_more
|
47
48
|
SkmArity.new(1, '*')
|
48
49
|
end
|
@@ -107,6 +108,9 @@ module Skeem
|
|
107
108
|
create_append(aRuntime)
|
108
109
|
create_setcar(aRuntime)
|
109
110
|
create_setcdr(aRuntime)
|
111
|
+
create_assq(aRuntime)
|
112
|
+
create_assv(aRuntime)
|
113
|
+
create_list_copy(aRuntime)
|
110
114
|
end
|
111
115
|
|
112
116
|
def add_vector_procedures(aRuntime)
|
@@ -118,6 +122,12 @@ module Skeem
|
|
118
122
|
create_vector2list(aRuntime)
|
119
123
|
end
|
120
124
|
|
125
|
+
def add_control_procedures(aRuntime)
|
126
|
+
create_object_predicate(aRuntime, 'procedure?')
|
127
|
+
create_apply(aRuntime)
|
128
|
+
create_map(aRuntime)
|
129
|
+
end
|
130
|
+
|
121
131
|
def add_io_procedures(aRuntime)(aRuntime)
|
122
132
|
create_newline(aRuntime)
|
123
133
|
end
|
@@ -486,46 +496,55 @@ module Skeem
|
|
486
496
|
|
487
497
|
define_primitive_proc(aRuntime, 'list->vector', unary, primitive)
|
488
498
|
end
|
489
|
-
|
490
|
-
def
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
if result.kind_of?(SkmEmptyList)
|
506
|
-
result = cloned
|
507
|
-
else
|
508
|
-
if result.kind_of?(SkmEmptyList)
|
509
|
-
result = SkmPair.new(arg, SkmEmptyList.instance)
|
510
|
-
else
|
511
|
-
result.append_list(cloned)
|
512
|
-
end
|
513
|
-
end
|
514
|
-
when SkmEmptyList
|
515
|
-
# Do nothing
|
499
|
+
|
500
|
+
def append_core(arglist)
|
501
|
+
if arglist.empty?
|
502
|
+
result = SkmEmptyList.instance
|
503
|
+
elsif arglist.size == 1
|
504
|
+
result = arglist[0]
|
505
|
+
else
|
506
|
+
but_last = arglist.take(arglist.length - 1)
|
507
|
+
check_arguments(but_last, [SkmPair, SkmEmptyList], 'list', 'append')
|
508
|
+
result = arglist.shift.klone # First list is taken
|
509
|
+
arglist.each do |arg|
|
510
|
+
case arg
|
511
|
+
when SkmPair
|
512
|
+
cloned = arg.klone
|
513
|
+
if result.kind_of?(SkmEmptyList)
|
514
|
+
result = cloned
|
516
515
|
else
|
517
516
|
if result.kind_of?(SkmEmptyList)
|
518
|
-
result = arg
|
517
|
+
result = SkmPair.new(arg, SkmEmptyList.instance)
|
519
518
|
else
|
520
|
-
result.
|
519
|
+
result.append_list(cloned)
|
521
520
|
end
|
522
|
-
|
521
|
+
end
|
522
|
+
when SkmEmptyList
|
523
|
+
# Do nothing
|
524
|
+
else
|
525
|
+
if result.kind_of?(SkmEmptyList)
|
526
|
+
result = arg
|
527
|
+
else
|
528
|
+
result.append(arg)
|
529
|
+
end
|
523
530
|
end
|
524
531
|
end
|
532
|
+
end
|
533
|
+
|
534
|
+
result
|
535
|
+
end
|
536
|
+
|
537
|
+
def create_append(aRuntime)
|
538
|
+
primitive = ->(runtime, arglist) do
|
539
|
+
if arglist.size > 1
|
540
|
+
arguments = evaluate_arguments(arglist, aRuntime)
|
541
|
+
else
|
542
|
+
arguments = arglist
|
543
|
+
end
|
544
|
+
|
545
|
+
append_core(arguments)
|
546
|
+
end
|
525
547
|
|
526
|
-
result
|
527
|
-
end
|
528
|
-
|
529
548
|
define_primitive_proc(aRuntime, 'append', zero_or_more, primitive)
|
530
549
|
end
|
531
550
|
|
@@ -577,6 +596,47 @@ module Skeem
|
|
577
596
|
define_primitive_proc(aRuntime, 'set-cdr!', binary, primitive)
|
578
597
|
end
|
579
598
|
|
599
|
+
# create_assv(aRuntime)
|
600
|
+
def create_assq(aRuntime)
|
601
|
+
primitive = ->(runtime, obj_arg, alist_arg) do
|
602
|
+
# assoc_list = alist_arg.evaluate(runtime)
|
603
|
+
# check_assoc_list(assoc_list, 'assq')
|
604
|
+
# result = boolean(false)
|
605
|
+
# pair = assoc_list
|
606
|
+
# while (pair.cdr && (pair.cdr.kind_of?(SkmPair)) do
|
607
|
+
# are_equal = @primitive_map['equal?'].call(runtime, pair.car, obj_arg)
|
608
|
+
# if are_equal
|
609
|
+
# result = pair
|
610
|
+
# break
|
611
|
+
# else
|
612
|
+
# pair = pair.cdr
|
613
|
+
# end
|
614
|
+
# end
|
615
|
+
|
616
|
+
# result
|
617
|
+
end
|
618
|
+
define_primitive_proc(aRuntime, 'assq', binary, primitive)
|
619
|
+
end
|
620
|
+
|
621
|
+
def check_assoc_list(alist, proc_name)
|
622
|
+
check_argtype(alist, SkmPair, 'association list', 'proc_name')
|
623
|
+
end
|
624
|
+
|
625
|
+
def create_assv(aRuntime)
|
626
|
+
end
|
627
|
+
|
628
|
+
|
629
|
+
def create_list_copy(aRuntime)
|
630
|
+
primitive = ->(runtime, arg) do
|
631
|
+
arg_evaluated = arg.evaluate(runtime)
|
632
|
+
check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'list-copy')
|
633
|
+
arg.klone
|
634
|
+
end
|
635
|
+
|
636
|
+
define_primitive_proc(aRuntime, 'list-copy', unary, primitive)
|
637
|
+
end
|
638
|
+
|
639
|
+
|
580
640
|
def create_vector(aRuntime)
|
581
641
|
primitive = ->(runtime, arglist) do
|
582
642
|
if arglist.empty?
|
@@ -600,7 +660,7 @@ module Skeem
|
|
600
660
|
|
601
661
|
define_primitive_proc(aRuntime, 'vector-length', unary, primitive)
|
602
662
|
end
|
603
|
-
|
663
|
+
|
604
664
|
def create_make_vector(aRuntime)
|
605
665
|
primitive = ->(runtime, count_arg, arglist) do
|
606
666
|
count = count_arg.evaluate(runtime)
|
@@ -612,11 +672,11 @@ module Skeem
|
|
612
672
|
end
|
613
673
|
elements = Array.new(count.value, filler)
|
614
674
|
|
615
|
-
vector(elements)
|
675
|
+
vector(elements)
|
616
676
|
end
|
617
677
|
|
618
678
|
define_primitive_proc(aRuntime, 'make-vector', one_or_two, primitive)
|
619
|
-
end
|
679
|
+
end
|
620
680
|
|
621
681
|
def create_vector_ref(aRuntime)
|
622
682
|
# argument 1: a vector, argument 2: an index(integer)
|
@@ -643,6 +703,58 @@ module Skeem
|
|
643
703
|
define_primitive_proc(aRuntime, 'vector->list', unary, primitive)
|
644
704
|
end
|
645
705
|
|
706
|
+
def create_apply(aRuntime)
|
707
|
+
primitive = ->(runtime, first_operand, arglist) do
|
708
|
+
proc_arg = first_operand.evaluate(runtime)
|
709
|
+
if arglist.empty?
|
710
|
+
result = SkmEmptyList.instance
|
711
|
+
else
|
712
|
+
arguments = evaluate_arguments(arglist, runtime)
|
713
|
+
single_list = append_core(arguments)
|
714
|
+
invoke = ProcedureCall.new(nil, proc_arg, single_list.to_a)
|
715
|
+
result = invoke.evaluate(runtime)
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
define_primitive_proc(aRuntime, 'apply', one_or_more, primitive)
|
720
|
+
end
|
721
|
+
|
722
|
+
def create_map(aRuntime)
|
723
|
+
primitive = ->(runtime, first_operand, list_of_lists) do
|
724
|
+
proc_arg = first_operand.evaluate(runtime)
|
725
|
+
if list_of_lists.empty?
|
726
|
+
result = SkmEmptyList.instance
|
727
|
+
else
|
728
|
+
arguments = evaluate_arguments(list_of_lists, runtime)
|
729
|
+
curr_cells = arguments.to_a
|
730
|
+
arity = curr_cells.size
|
731
|
+
initial_result = nil
|
732
|
+
curr_result = nil
|
733
|
+
loop do
|
734
|
+
call_args = curr_cells.map(&:car)
|
735
|
+
invoke = ProcedureCall.new(nil, proc_arg, call_args)
|
736
|
+
call_result = invoke.evaluate(runtime)
|
737
|
+
new_result = SkmPair.new(call_result, SkmEmptyList.instance)
|
738
|
+
if initial_result
|
739
|
+
curr_result.cdr = new_result
|
740
|
+
else
|
741
|
+
initial_result = new_result
|
742
|
+
end
|
743
|
+
curr_result = new_result
|
744
|
+
|
745
|
+
curr_cells.map!(&:cdr)
|
746
|
+
break if curr_cells.find { |cdr_entry| ! cdr_entry.kind_of?(SkmPair) }
|
747
|
+
end
|
748
|
+
|
749
|
+
result = initial_result
|
750
|
+
end
|
751
|
+
|
752
|
+
result
|
753
|
+
end
|
754
|
+
|
755
|
+
define_primitive_proc(aRuntime, 'map', one_or_more, primitive)
|
756
|
+
end
|
757
|
+
|
646
758
|
def create_newline(aRuntime)
|
647
759
|
primitive = ->(runtime) do
|
648
760
|
# @TODO: make output stream configurable
|
@@ -671,7 +783,7 @@ module Skeem
|
|
671
783
|
end
|
672
784
|
|
673
785
|
# DON'T USE IT
|
674
|
-
# Non-standard procedure reserved for internal testing/debugging purposes.
|
786
|
+
# Non-standard procedure reserved for internal testing/debugging purposes.
|
675
787
|
def create_debug(aRuntime)
|
676
788
|
primitive = ->(runtime) do
|
677
789
|
require 'debug'
|
@@ -679,7 +791,7 @@ module Skeem
|
|
679
791
|
|
680
792
|
define_primitive_proc(aRuntime, 'debug', nullary, primitive)
|
681
793
|
end
|
682
|
-
|
794
|
+
|
683
795
|
# DON'T USE IT
|
684
796
|
# Non-standard procedure reserved for internal testing/debugging purposes.
|
685
797
|
def create_inspect(aRuntime)
|
@@ -688,7 +800,7 @@ module Skeem
|
|
688
800
|
$stderr.puts 'INSPECT>' + arg_evaluated.inspect
|
689
801
|
Skeem::SkmUndefined.instance
|
690
802
|
end
|
691
|
-
define_primitive_proc(aRuntime, '_inspect', unary, primitive)
|
803
|
+
define_primitive_proc(aRuntime, '_inspect', unary, primitive)
|
692
804
|
end
|
693
805
|
|
694
806
|
def create_object_predicate(aRuntime, predicate_name, msg_name = nil)
|
@@ -701,15 +813,17 @@ module Skeem
|
|
701
813
|
define_primitive_proc(aRuntime, predicate_name, unary, primitive)
|
702
814
|
end
|
703
815
|
|
704
|
-
def def_procedure(aRuntime, pairs)
|
705
|
-
pairs.each_slice(2) do |(name, code)|
|
706
|
-
func = PrimitiveProcedure.new(name, code)
|
707
|
-
define(aRuntime, func.identifier, func)
|
708
|
-
end
|
709
|
-
end
|
816
|
+
# def def_procedure(aRuntime, pairs)
|
817
|
+
# pairs.each_slice(2) do |(name, code)|
|
818
|
+
# func = PrimitiveProcedure.new(name, code)
|
819
|
+
# define(aRuntime, func.identifier, func)
|
820
|
+
# end
|
821
|
+
# end
|
710
822
|
|
711
823
|
def define_primitive_proc(aRuntime, anIdentifier, anArity, aRubyLambda)
|
712
824
|
primitive = PrimitiveProcedure.new(anIdentifier, anArity, aRubyLambda)
|
825
|
+
@primitive_map = {} unless @primitives_map
|
826
|
+
@primitive_map[primitive.identifier] = primitive.code
|
713
827
|
define(aRuntime, primitive.identifier, primitive)
|
714
828
|
end
|
715
829
|
|
@@ -725,7 +839,7 @@ module Skeem
|
|
725
839
|
arglist.evaluate(aRuntime).to_a
|
726
840
|
end
|
727
841
|
end
|
728
|
-
|
842
|
+
|
729
843
|
def check_arguments(arguments, requiredRubyClass, requiredSkmType, aProcName)
|
730
844
|
arguments.each do |argument|
|
731
845
|
if requiredRubyClass.kind_of?(Array)
|
@@ -738,7 +852,7 @@ module Skeem
|
|
738
852
|
end
|
739
853
|
end
|
740
854
|
end
|
741
|
-
end
|
855
|
+
end
|
742
856
|
|
743
857
|
def check_argtype(argument, requiredRubyClass, requiredSkmType, aProcName)
|
744
858
|
if requiredRubyClass.kind_of?(Array)
|
data/lib/skeem/s_expr_nodes.rb
CHANGED
@@ -384,6 +384,10 @@ module Skeem
|
|
384
384
|
def callable?
|
385
385
|
true
|
386
386
|
end
|
387
|
+
|
388
|
+
def procedure?
|
389
|
+
true
|
390
|
+
end
|
387
391
|
|
388
392
|
def call(aRuntime, theActuals)
|
389
393
|
set_cond_environment(aRuntime.environment) # Last chance for anonymous lambda
|
@@ -536,6 +540,10 @@ require_relative 'skm_procedure_exec'
|
|
536
540
|
def callable?
|
537
541
|
true
|
538
542
|
end
|
543
|
+
|
544
|
+
def procedure?
|
545
|
+
true
|
546
|
+
end
|
539
547
|
=begin
|
540
548
|
TODO
|
541
549
|
def quasiquote(aRuntime)
|
data/lib/skeem/skm_element.rb
CHANGED
data/lib/skeem/version.rb
CHANGED
@@ -633,6 +633,28 @@ SKEEM
|
|
633
633
|
result = subject.run(source)
|
634
634
|
expect(result.last.cdr).to eq(1)
|
635
635
|
end
|
636
|
+
|
637
|
+
it 'should implement the list-copy procedure' do
|
638
|
+
checks = [
|
639
|
+
["(list-copy '())", []],
|
640
|
+
["(list-copy '(a b c))", ['a', 'b', 'c']]
|
641
|
+
]
|
642
|
+
checks.each do |(skeem_expr, expectation)|
|
643
|
+
result = subject.run(skeem_expr)
|
644
|
+
expect(result.to_a).to eq(expectation)
|
645
|
+
end
|
646
|
+
|
647
|
+
source =<<-SKEEM
|
648
|
+
(define a '(1 8 2 8)) ; a may be immutable
|
649
|
+
(define b (list-copy a))
|
650
|
+
(set-car! b 3) ; b is mutable
|
651
|
+
SKEEM
|
652
|
+
subject.run(source)
|
653
|
+
result = subject.run('b')
|
654
|
+
expect(result.to_a).to eq([3, 8, 2, 8])
|
655
|
+
result = subject.run('a')
|
656
|
+
expect(result.to_a).to eq([1, 8, 2, 8])
|
657
|
+
end
|
636
658
|
end # context
|
637
659
|
|
638
660
|
context 'Vector procedures:' do
|
@@ -709,6 +731,42 @@ SKEEM
|
|
709
731
|
end
|
710
732
|
end # context
|
711
733
|
|
734
|
+
context 'Control procedures:' do
|
735
|
+
it 'should implement the procedure? predicate' do
|
736
|
+
checks = [
|
737
|
+
["(procedure? car)", true],
|
738
|
+
["(procedure? 'car)", false],
|
739
|
+
["(procedure? (lambda (x) (* x x)))", true],
|
740
|
+
# ["(procedure? '(lambda (x) (* x x)))", false] # Parse failure!
|
741
|
+
]
|
742
|
+
checks.each do |(skeem_expr, expectation)|
|
743
|
+
result = subject.run(skeem_expr)
|
744
|
+
expect(result).to eq(expectation)
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
it 'should implement the apply procedure' do
|
749
|
+
checks = [
|
750
|
+
["(apply + '(3 4))", 7]
|
751
|
+
]
|
752
|
+
checks.each do |(skeem_expr, expectation)|
|
753
|
+
result = subject.run(skeem_expr)
|
754
|
+
expect(result).to eq(expectation)
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
758
|
+
it 'should implement the map procedure' do
|
759
|
+
checks = [
|
760
|
+
["(map car '((a b) (d e) (g h)))", ['a', 'd', 'g']],
|
761
|
+
["(map + '(1 2 3) '(4 5 6 7))", [5, 7, 9]]
|
762
|
+
]
|
763
|
+
checks.each do |(skeem_expr, expectation)|
|
764
|
+
result = subject.run(skeem_expr)
|
765
|
+
expect(result.to_a).to eq(expectation)
|
766
|
+
end
|
767
|
+
end
|
768
|
+
end # context
|
769
|
+
|
712
770
|
context 'IO procedures:' do
|
713
771
|
it 'should implement the newline procedure' do
|
714
772
|
default_stdout = $stdout
|
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.07
|
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-05-
|
11
|
+
date: 2019-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|