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 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