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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f14377aa793138a9eb14281b8f72ea29a8008da684b5d462c0060f635b2b5a9b
4
- data.tar.gz: 2e37d741b3a156c4dabf20138cc604db4e9fb59dd78e2a8b518ad59566c2ecb5
3
+ metadata.gz: 3dd3d2443ae53822f3ebf6f0ce042b52455fff6592bd8aa26e91e4ac548c2c87
4
+ data.tar.gz: 8eb8851aa0bf2b643949c1dd21284178a83891982eff75cffc1ec10ab1fbe537
5
5
  SHA512:
6
- metadata.gz: 45a19a92c4c3e9b7033edebb197af870b20cd139db4246d14c6e9d9520105f6057435a60bdef2ad39466fa86b5179404cd19b79a604f70ea7d30abfc6ea80803
7
- data.tar.gz: 5ecb615aef9290a912919272c6f47f372b2b9b990a3867f66205fcc2cf21005c2b0d7cfc38479dad9137c142969d36b7b856ded9cd297a426a0c6ba1f8ea0e64
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 create_append(aRuntime)
491
- primitive = ->(runtime, arglist) do
492
- if arglist.empty?
493
- result = SkmEmptyList.instance
494
- elsif arglist.size == 1
495
- result = arglist[0]
496
- else
497
- parts = evaluate_arguments(arglist, aRuntime)
498
- but_last = parts.take(parts.length - 1)
499
- check_arguments(but_last, [SkmPair, SkmEmptyList], 'list', 'append')
500
- result = parts.shift.klone # First list is taken
501
- parts.each do |arg|
502
- case arg
503
- when SkmPair
504
- cloned = arg.klone
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.append(arg)
519
+ result.append_list(cloned)
521
520
  end
522
- end
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)
@@ -17,6 +17,10 @@ module Skeem
17
17
  def callable?
18
18
  true
19
19
  end
20
+
21
+ def procedure?
22
+ true
23
+ end
20
24
 
21
25
  # This method should be invoked when the procedure isn't
22
26
  # explicitly called (with arguments). In this case, the name
@@ -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)
@@ -44,6 +44,10 @@ module Skeem
44
44
  def pair?
45
45
  false
46
46
  end
47
+
48
+ def procedure?
49
+ false
50
+ end
47
51
 
48
52
  def vector?
49
53
  false
data/lib/skeem/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Skeem
2
- VERSION = '0.2.06'.freeze
2
+ VERSION = '0.2.07'.freeze
3
3
  end
@@ -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.06
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-30 00:00:00.000000000 Z
11
+ date: 2019-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley