skeem 0.2.06 → 0.2.07
Sign up to get free protection for your applications and to get access to all the features.
- 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
|