skeem 0.2.14 → 0.2.18
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/.rubocop.yml +451 -195
- data/.travis.yml +27 -0
- data/CHANGELOG.md +35 -1
- data/Gemfile +2 -0
- data/README.md +125 -56
- data/Rakefile +2 -0
- data/appveyor.yml +3 -4
- data/bin/cubic.skm +4 -0
- data/bin/hello-world.skm +1 -0
- data/bin/skeem +72 -0
- data/lib/skeem/datum_dsl.rb +40 -30
- data/lib/skeem/element_visitor.rb +5 -2
- data/lib/skeem/grammar.rb +88 -26
- data/lib/skeem/interpreter.rb +9 -7
- data/lib/skeem/parser.rb +6 -4
- data/lib/skeem/primitive/primitive_builder.rb +148 -122
- data/lib/skeem/primitive/primitive_procedure.rb +23 -25
- data/lib/skeem/runtime.rb +17 -15
- data/lib/skeem/s_expr_builder.rb +49 -117
- data/lib/skeem/s_expr_nodes.rb +147 -132
- data/lib/skeem/skeem_exception.rb +1 -0
- data/lib/skeem/skm_binding.rb +9 -11
- data/lib/skeem/skm_compound_datum.rb +9 -6
- data/lib/skeem/skm_element.rb +15 -13
- data/lib/skeem/skm_empty_list.rb +6 -4
- data/lib/skeem/skm_exception.rb +9 -0
- data/lib/skeem/skm_expression.rb +3 -1
- data/lib/skeem/skm_frame.rb +3 -2
- data/lib/skeem/skm_pair.rb +26 -18
- data/lib/skeem/skm_procedure_exec.rb +11 -6
- data/lib/skeem/skm_simple_datum.rb +23 -20
- data/lib/skeem/skm_unary_expression.rb +34 -37
- data/lib/skeem/standard/base.skm +4 -0
- data/lib/skeem/tokenizer.rb +38 -28
- data/lib/skeem/version.rb +3 -1
- data/lib/skeem.rb +2 -0
- data/skeem.gemspec +9 -6
- data/spec/skeem/add4.skm +4 -0
- data/spec/skeem/datum_dsl_spec.rb +13 -12
- data/spec/skeem/element_visitor_spec.rb +14 -10
- data/spec/skeem/interpreter_spec.rb +84 -44
- data/spec/skeem/lambda_spec.rb +13 -11
- data/spec/skeem/parser_spec.rb +23 -19
- data/spec/skeem/primitive/primitive_builder_spec.rb +65 -48
- data/spec/skeem/primitive/primitive_procedure_spec.rb +14 -12
- data/spec/skeem/runtime_spec.rb +20 -18
- data/spec/skeem/s_expr_nodes_spec.rb +8 -6
- data/spec/skeem/skm_compound_datum_spec.rb +12 -10
- data/spec/skeem/skm_element_spec.rb +7 -5
- data/spec/skeem/skm_empty_list_spec.rb +7 -5
- data/spec/skeem/skm_frame_spec.rb +5 -4
- data/spec/skeem/skm_pair_spec.rb +9 -8
- data/spec/skeem/skm_procedure_exec_spec.rb +2 -0
- data/spec/skeem/skm_simple_datum_spec.rb +24 -22
- data/spec/skeem/skm_unary_expression_spec.rb +11 -9
- data/spec/skeem/tokenizer_spec.rb +54 -43
- data/spec/skeem_spec.rb +2 -0
- data/spec/spec_helper.rb +15 -10
- metadata +18 -10
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Skeem
|
2
4
|
class SkmElementVisitor
|
3
5
|
# Link to the root element to visit
|
@@ -12,6 +14,7 @@ module Skeem
|
|
12
14
|
# @param aRoot [SkmElement] the parse tree to visit.
|
13
15
|
def initialize(aRoot)
|
14
16
|
raise StandardError if aRoot.nil?
|
17
|
+
|
15
18
|
@root = aRoot
|
16
19
|
@subscribers = []
|
17
20
|
end
|
@@ -57,7 +60,6 @@ module Skeem
|
|
57
60
|
broadcast(:after_empty_list, anEmptyList)
|
58
61
|
end
|
59
62
|
|
60
|
-
|
61
63
|
def visit_pair(aPair)
|
62
64
|
broadcast(:before_pair, aPair)
|
63
65
|
traverse_car_cdr(aPair)
|
@@ -110,8 +112,9 @@ module Skeem
|
|
110
112
|
def broadcast(msg, *args)
|
111
113
|
subscribers.each do |subscr|
|
112
114
|
next unless subscr.respond_to?(msg) || subscr.respond_to?(:accept_all)
|
115
|
+
|
113
116
|
subscr.send(msg, runtime, *args)
|
114
117
|
end
|
115
118
|
end
|
116
119
|
end # class
|
117
|
-
end # module
|
120
|
+
end # module
|
data/lib/skeem/grammar.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Grammar for Skeem (a subset of Scheme language)
|
2
4
|
require 'rley' # Load the gem
|
3
5
|
|
@@ -7,11 +9,11 @@ module Skeem
|
|
7
9
|
# Official Small Scheme grammar is available at:
|
8
10
|
# https://bitbucket.org/cowan/r7rs/src/draft-10/rnrs/r7rs.pdf
|
9
11
|
# Names of grammar elements are based on the R7RS documentation
|
10
|
-
builder = Rley::
|
12
|
+
builder = Rley::grammar_builder do
|
11
13
|
# Delimiters, separators...
|
12
14
|
add_terminals('APOSTROPHE', 'COMMA', 'COMMA_AT_SIGN')
|
13
15
|
add_terminals('GRAVE_ACCENT', 'LPAREN', 'RPAREN')
|
14
|
-
add_terminals('PERIOD', 'ARROW')
|
16
|
+
add_terminals('PERIOD', 'UNDERSCORE', 'ARROW', 'ELLIPSIS')
|
15
17
|
add_terminals('VECTOR_BEGIN')
|
16
18
|
|
17
19
|
# Literal values...
|
@@ -19,9 +21,9 @@ module Skeem
|
|
19
21
|
add_terminals('CHAR', 'STRING_LIT', 'IDENTIFIER')
|
20
22
|
|
21
23
|
# Keywords...
|
22
|
-
add_terminals('BEGIN', 'COND', 'DEFINE', '
|
23
|
-
add_terminals('IF', 'LAMBDA', 'LET', '
|
24
|
-
add_terminals('QUOTE', 'QUASIQUOTE', 'SET!')
|
24
|
+
add_terminals('BEGIN', 'COND', 'DEFINE', 'DEFINE-SYNTAX', 'DO')
|
25
|
+
add_terminals('ELSE', 'IF', 'INCLUDE', 'LAMBDA', 'LET', 'LET_STAR')
|
26
|
+
add_terminals('QUOTE', 'QUASIQUOTE', 'SET!', 'SYNTAX-RULES')
|
25
27
|
add_terminals('UNQUOTE', 'UNQUOTE-SPLICING')
|
26
28
|
|
27
29
|
rule('program' => 'cmd_or_def_plus').as 'main'
|
@@ -33,6 +35,7 @@ module Skeem
|
|
33
35
|
rule 'command' => 'expression'
|
34
36
|
rule('definition' => 'LPAREN DEFINE IDENTIFIER expression RPAREN').as 'definition'
|
35
37
|
rule('definition' => 'LPAREN DEFINE LPAREN IDENTIFIER def_formals RPAREN body RPAREN').as 'alt_definition'
|
38
|
+
rule('definition' => 'syntax_definition')
|
36
39
|
rule('definition' => 'LPAREN BEGIN definition_star RPAREN').as 'definitions_within_begin'
|
37
40
|
rule('expression' => 'IDENTIFIER').as 'variable_reference'
|
38
41
|
rule 'expression' => 'literal'
|
@@ -41,8 +44,9 @@ module Skeem
|
|
41
44
|
rule 'expression' => 'conditional'
|
42
45
|
rule 'expression' => 'assignment'
|
43
46
|
rule 'expression' => 'derived_expression'
|
47
|
+
rule 'expression' => 'includer'
|
44
48
|
rule 'literal' => 'quotation'
|
45
|
-
rule 'literal' => 'self-evaluating'
|
49
|
+
rule 'literal' => 'self-evaluating'
|
46
50
|
rule('quotation' => 'APOSTROPHE datum').as 'quotation_short'
|
47
51
|
rule('quotation' => 'LPAREN QUOTE datum RPAREN').as 'quotation'
|
48
52
|
rule 'self-evaluating' => 'BOOLEAN'
|
@@ -64,8 +68,8 @@ module Skeem
|
|
64
68
|
rule('vector' => 'VECTOR_BEGIN datum_star RPAREN').as 'vector'
|
65
69
|
rule('datum_plus' => 'datum_plus datum').as 'multiple_datums'
|
66
70
|
rule('datum_plus' => 'datum').as 'last_datum'
|
67
|
-
rule('datum_star' => 'datum_star datum').as '
|
68
|
-
rule('datum_star' => []).as 'no_datum_yet'
|
71
|
+
rule('datum_star' => 'datum_star datum').as 'star_default'
|
72
|
+
rule('datum_star' => []).as 'star_base' ## 'no_datum_yet'
|
69
73
|
rule 'symbol' => 'IDENTIFIER'
|
70
74
|
rule('procedure_call' => 'LPAREN operator RPAREN').as 'proc_call_nullary'
|
71
75
|
rule('procedure_call' => 'LPAREN operator operand_plus RPAREN').as 'proc_call_args'
|
@@ -79,16 +83,17 @@ module Skeem
|
|
79
83
|
rule('formals' => 'LPAREN identifier_star RPAREN').as 'fixed_arity_formals'
|
80
84
|
rule('formals' => 'IDENTIFIER').as 'variadic_formals'
|
81
85
|
rule('formals' => 'LPAREN identifier_plus PERIOD IDENTIFIER RPAREN').as 'dotted_formals'
|
82
|
-
rule('
|
83
|
-
rule('identifier_star' =>
|
86
|
+
rule('syntax_definition' => 'LPAREN DEFINE-SYNTAX keyword transformer_spec RPAREN').as 'syntax_definition'
|
87
|
+
rule('identifier_star' => 'identifier_star IDENTIFIER').as 'star_default'
|
88
|
+
rule('identifier_star' => []).as 'star_base' ## 'no_identifier_yet'
|
84
89
|
rule('identifier_plus' => 'identifier_plus IDENTIFIER').as 'multiple_identifiers'
|
85
90
|
rule('identifier_plus' => 'IDENTIFIER').as 'last_identifier'
|
86
91
|
rule('body' => 'definition_star sequence').as 'body'
|
87
|
-
rule('definition_star' => 'definition_star definition').as '
|
88
|
-
rule('definition_star' => []).as 'no_definition_yet'
|
92
|
+
rule('definition_star' => 'definition_star definition').as 'star_default'
|
93
|
+
rule('definition_star' => []).as 'star_base' ## 'no_definition_yet'
|
89
94
|
rule('sequence' => 'command_star expression').as 'sequence'
|
90
|
-
rule('command_star' => 'command_star command').as '
|
91
|
-
rule('command_star' => []).as 'no_command_yet'
|
95
|
+
rule('command_star' => 'command_star command').as 'star_default'
|
96
|
+
rule('command_star' => []).as 'star_base' ## 'no_command_yet'
|
92
97
|
rule('conditional' => 'LPAREN IF test consequent alternate RPAREN').as 'conditional'
|
93
98
|
rule 'test' => 'expression'
|
94
99
|
rule 'consequent' => 'expression'
|
@@ -101,13 +106,15 @@ module Skeem
|
|
101
106
|
rule('derived_expression' => 'LPAREN COND cond_clause_plus RPAREN').as 'cond_form'
|
102
107
|
rule('derived_expression' => 'LPAREN COND cond_clause_star LPAREN ELSE sequence RPAREN RPAREN').as 'cond_else_form'
|
103
108
|
rule('derived_expression' => 'LPAREN LET LPAREN binding_spec_star RPAREN body RPAREN').as 'short_let_form'
|
104
|
-
|
109
|
+
# TODO: implement "named let"
|
110
|
+
rule('derived_expression' => 'LPAREN LET IDENTIFIER LPAREN binding_spec_star RPAREN body RPAREN') # .as 'named_form'
|
111
|
+
rule('derived_expression' => 'LPAREN LET_STAR LPAREN binding_spec_star RPAREN body RPAREN').as 'let_star_form'
|
105
112
|
|
106
|
-
# As the R7RS grammar is too restrictive,
|
113
|
+
# As the R7RS grammar is too restrictive,
|
107
114
|
# the next rule was made more general than its standard counterpart
|
108
115
|
rule('derived_expression' => 'LPAREN BEGIN body RPAREN').as 'begin_expression'
|
109
116
|
do_syntax = <<-END_SYNTAX
|
110
|
-
LPAREN DO LPAREN iteration_spec_star RPAREN
|
117
|
+
LPAREN DO LPAREN iteration_spec_star RPAREN
|
111
118
|
LPAREN test do_result RPAREN
|
112
119
|
command_star RPAREN
|
113
120
|
END_SYNTAX
|
@@ -115,25 +122,29 @@ END_SYNTAX
|
|
115
122
|
rule 'derived_expression' => 'quasiquotation'
|
116
123
|
rule('cond_clause_plus' => 'cond_clause_plus cond_clause').as 'multiple_cond_clauses'
|
117
124
|
rule('cond_clause_plus' => 'cond_clause').as 'last_cond_clauses'
|
118
|
-
rule('cond_clause_star' => 'cond_clause_star cond_clause').as '
|
119
|
-
rule('cond_clause_star' => []).as 'last_cond_clauses_star'
|
125
|
+
rule('cond_clause_star' => 'cond_clause_star cond_clause').as 'star_default'
|
126
|
+
rule('cond_clause_star' => []).as 'star_base' ## 'last_cond_clauses_star'
|
120
127
|
rule('cond_clause' => 'LPAREN test sequence RPAREN').as 'cond_clause'
|
121
128
|
rule('cond_clause' => 'LPAREN test RPAREN')
|
122
129
|
rule('cond_clause' => 'LPAREN test ARROW recipient RPAREN').as 'cond_arrow_clause'
|
123
130
|
rule('recipient' => 'expression')
|
124
131
|
rule('quasiquotation' => 'LPAREN QUASIQUOTE qq_template RPAREN').as 'quasiquotation'
|
125
132
|
rule('quasiquotation' => 'GRAVE_ACCENT qq_template').as 'quasiquotation_short'
|
126
|
-
rule('binding_spec_star' => 'binding_spec_star binding_spec').as '
|
127
|
-
rule('binding_spec_star' => []).as 'no_binding_spec_yet'
|
133
|
+
rule('binding_spec_star' => 'binding_spec_star binding_spec').as 'star_default'
|
134
|
+
rule('binding_spec_star' => []).as 'star_base' ## 'no_binding_spec_yet'
|
128
135
|
rule('binding_spec' => 'LPAREN IDENTIFIER expression RPAREN').as 'binding_spec'
|
129
|
-
rule('iteration_spec_star' => 'iteration_spec_star iteration_spec').as '
|
130
|
-
rule('iteration_spec_star' => []).as 'no_iter_spec_yet'
|
136
|
+
rule('iteration_spec_star' => 'iteration_spec_star iteration_spec').as 'star_default'
|
137
|
+
rule('iteration_spec_star' => []).as 'star_base' ## 'no_iter_spec_yet'
|
131
138
|
rule('iteration_spec' => 'LPAREN IDENTIFIER init step RPAREN').as 'iteration_spec_long'
|
132
139
|
rule('iteration_spec' => 'LPAREN IDENTIFIER init RPAREN').as 'iteration_spec_short'
|
133
140
|
rule('init' => 'expression')
|
134
141
|
rule('step' => 'expression')
|
135
142
|
rule 'do_result' => 'sequence'
|
136
|
-
rule('do_result' => []).as 'empty_do_result'
|
143
|
+
rule('do_result' => []).as 'star_base' ## 'empty_do_result'
|
144
|
+
rule('keyword' => 'IDENTIFIER')
|
145
|
+
rule('includer' => 'LPAREN INCLUDE string_plus RPAREN').as 'include'
|
146
|
+
rule('string_plus' => 'string_plus STRING_LIT').as 'multiple_string'
|
147
|
+
rule('string_plus' => 'STRING_LIT').as 'last_single_string'
|
137
148
|
rule 'qq_template' => 'simple_datum'
|
138
149
|
rule 'qq_template' => 'list_qq_template'
|
139
150
|
rule 'qq_template' => 'vector_qq_template'
|
@@ -144,14 +155,65 @@ END_SYNTAX
|
|
144
155
|
rule('vector_qq_template' => 'VECTOR_BEGIN qq_template_or_splice_star RPAREN').as 'vector_qq'
|
145
156
|
rule('unquotation' => 'COMMA qq_template').as 'unquotation_short'
|
146
157
|
rule 'unquotation' => 'LPAREN UNQUOTE qq_template RPAREN'
|
147
|
-
rule('qq_template_or_splice_star' => 'qq_template_or_splice_star qq_template_or_splice').as '
|
148
|
-
rule('qq_template_or_splice_star' => []).as 'no_template_splice_yet'
|
158
|
+
rule('qq_template_or_splice_star' => 'qq_template_or_splice_star qq_template_or_splice').as 'star_default'
|
159
|
+
rule('qq_template_or_splice_star' => []).as 'star_base' ## 'no_template_splice_yet'
|
149
160
|
rule 'qq_template_or_splice_plus' => 'qq_template_or_splice_plus qq_template_or_splice'
|
150
161
|
rule 'qq_template_or_splice_plus' => 'qq_template_or_splice'
|
151
162
|
rule 'qq_template_or_splice' => 'qq_template'
|
152
163
|
rule 'qq_template_or_splice' => 'splicing_unquotation'
|
153
164
|
rule 'splicing_unquotation' => 'COMMA_AT_SIGN qq_template'
|
154
165
|
rule 'splicing_unquotation' => 'LPAREN UNQUOTE-SPLICING qq_template RPAREN'
|
166
|
+
rule('transformer_spec' => 'LPAREN SYNTAX-RULES LPAREN identifier_star RPAREN syntax_rule_star RPAREN').as 'transformer_syntax'
|
167
|
+
rule('transformer_spec' => 'LPAREN SYNTAX-RULES IDENTIFIER LPAREN identifier_star RPAREN syntax_rule_star RPAREN')
|
168
|
+
rule('syntax_rule_star' => 'syntax_rule_star syntax_rule').as 'star_default'
|
169
|
+
rule('syntax_rule_star' => []).as 'star_base'
|
170
|
+
rule('syntax_rule' => 'LPAREN pattern template RPAREN').as 'syntax_rule'
|
171
|
+
rule('pattern' => 'pattern_identifier')
|
172
|
+
rule('pattern' => 'UNDERSCORE')
|
173
|
+
rule('pattern' => 'LPAREN pattern_star RPAREN')
|
174
|
+
rule('pattern' => 'LPAREN pattern_plus PERIOD pattern RPAREN')
|
175
|
+
rule('pattern' => 'LPAREN pattern_plus ELLIPSIS pattern_star RPAREN')
|
176
|
+
rule('pattern' => 'LPAREN pattern_plus ELLIPSIS pattern_star PERIOD pattern RPAREN')
|
177
|
+
rule('pattern' => 'VECTOR_BEGIN pattern_star RPAREN')
|
178
|
+
rule('pattern' => 'VECTOR_BEGIN pattern_plus ELLIPSIS pattern_star RPAREN')
|
179
|
+
rule('pattern' => 'pattern_datum')
|
180
|
+
rule('pattern_star' => 'pattern_star pattern').as 'star_default'
|
181
|
+
rule('pattern_star' => []).as 'star_base'
|
182
|
+
rule('pattern_plus' => 'pattern_plus pattern')
|
183
|
+
rule('pattern_plus' => 'pattern')
|
184
|
+
rule('pattern_datum' => 'STRING_LIT')
|
185
|
+
rule('pattern_datum' => 'CHAR')
|
186
|
+
rule('pattern_datum' => 'BOOLEAN')
|
187
|
+
rule('pattern_datum' => 'number')
|
188
|
+
# rule('pattern_datum' => 'bytevector')
|
189
|
+
rule('template' => 'pattern_identifier')
|
190
|
+
rule('template' => 'LPAREN template_element_star RPAREN')
|
191
|
+
rule('template' => 'LPAREN template_element_plus PERIOD template RPAREN')
|
192
|
+
rule('template' => 'VECTOR_BEGIN template_element_star RPAREN')
|
193
|
+
rule('template' => 'template_datum')
|
194
|
+
rule('template_element_star' => 'template_element_star template_element').as 'star_default'
|
195
|
+
rule('template_element_star' => []).as 'star_base'
|
196
|
+
rule('template_element_plus' => 'template_element_plus template_element')
|
197
|
+
rule('template_element_plus' => 'template_element')
|
198
|
+
rule('template_element' => 'template')
|
199
|
+
rule('template_element' => 'template ELLIPSIS')
|
200
|
+
rule('template_datum' => 'pattern_datum')
|
201
|
+
rule('pattern_identifier' => 'IDENTIFIER')
|
202
|
+
# Ugly: specailized production rule per keyword...
|
203
|
+
rule('pattern_identifier' => 'BEGIN')
|
204
|
+
rule('pattern_identifier' => 'COND')
|
205
|
+
rule('pattern_identifier' => 'DEFINE')
|
206
|
+
rule('pattern_identifier' => 'ELSE')
|
207
|
+
rule('pattern_identifier' => 'IF')
|
208
|
+
rule('pattern_identifier' => 'INCLUDE')
|
209
|
+
rule('pattern_identifier' => 'LAMBDA')
|
210
|
+
rule('pattern_identifier' => 'LET')
|
211
|
+
rule('pattern_identifier' => 'LET*')
|
212
|
+
rule('pattern_identifier' => 'QUOTE')
|
213
|
+
rule('pattern_identifier' => 'QUASIQUOTE')
|
214
|
+
rule('pattern_identifier' => 'SET!')
|
215
|
+
rule('pattern_identifier' => 'UNQUOTE')
|
216
|
+
rule('pattern_identifier' => 'UNQUOTE-SPLICING')
|
155
217
|
end
|
156
218
|
|
157
219
|
# And now build the grammar and make it accessible via a global constant
|
data/lib/skeem/interpreter.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'parser'
|
2
4
|
require_relative 'skm_frame'
|
3
5
|
require_relative 'runtime'
|
@@ -9,7 +11,7 @@ module Skeem
|
|
9
11
|
attr_reader(:parser)
|
10
12
|
attr_reader(:runtime)
|
11
13
|
|
12
|
-
def initialize
|
14
|
+
def initialize
|
13
15
|
@runtime = Runtime.new(SkmFrame.new)
|
14
16
|
@parser = Parser.new
|
15
17
|
|
@@ -20,16 +22,16 @@ module Skeem
|
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
def add_default_procedures
|
25
|
+
def add_default_procedures
|
24
26
|
add_primitives(runtime)
|
25
27
|
add_standard(runtime)
|
26
28
|
end
|
27
29
|
|
28
|
-
def parse(source,
|
30
|
+
def parse(source, _mode = nil)
|
29
31
|
@parser ||= Parser.new
|
30
32
|
@ptree = parser.parse(source)
|
31
|
-
# $stderr.puts @ptree.root.inspect if
|
32
|
-
# require 'debug' unless
|
33
|
+
# $stderr.puts @ptree.root.inspect if _mode.nil?
|
34
|
+
# require 'debug' unless _mode.nil?
|
33
35
|
end
|
34
36
|
|
35
37
|
def run(source, mode = nil)
|
@@ -43,7 +45,7 @@ module Skeem
|
|
43
45
|
end
|
44
46
|
|
45
47
|
def add_standard(_runtime)
|
46
|
-
std_pathname = File.dirname(__FILE__)
|
48
|
+
std_pathname = "#{File.dirname(__FILE__)}/standard/base.skm"
|
47
49
|
load_lib(std_pathname)
|
48
50
|
end
|
49
51
|
|
@@ -57,4 +59,4 @@ module Skeem
|
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end # class
|
60
|
-
end # module
|
62
|
+
end # module
|
data/lib/skeem/parser.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'tokenizer'
|
2
4
|
require_relative 'grammar'
|
3
5
|
require_relative 's_expr_builder'
|
@@ -5,10 +7,10 @@ require_relative 's_expr_builder'
|
|
5
7
|
module Skeem
|
6
8
|
class Parser
|
7
9
|
attr_reader(:engine)
|
8
|
-
|
9
|
-
def initialize
|
10
|
+
|
11
|
+
def initialize
|
10
12
|
# Create a Rley facade object
|
11
|
-
@engine = Rley::Engine.new do |cfg|
|
13
|
+
@engine = Rley::Engine.new do |cfg|
|
12
14
|
cfg.diagnose = true
|
13
15
|
cfg.repr_builder = SkmBuilder
|
14
16
|
end
|
@@ -16,7 +18,7 @@ module Skeem
|
|
16
18
|
# Step 1. Load Skeem grammar
|
17
19
|
@engine.use_grammar(Skeem::Grammar)
|
18
20
|
end
|
19
|
-
|
21
|
+
|
20
22
|
# Parse the given Skeem expression into a parse tree.
|
21
23
|
# @param source [String] Skeem expression to parse
|
22
24
|
# @return [ParseTree] A regexp object equivalent to the Skeem expression.
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'primitive_procedure'
|
2
4
|
require_relative '../datum_dsl'
|
5
|
+
require_relative '../skm_exception'
|
3
6
|
require_relative '../skm_pair'
|
4
7
|
|
5
8
|
module Skeem
|
@@ -34,7 +37,7 @@ module Skeem
|
|
34
37
|
def binary
|
35
38
|
SkmArity.new(2, 2)
|
36
39
|
end
|
37
|
-
|
40
|
+
|
38
41
|
def ternary
|
39
42
|
SkmArity.new(3, 3)
|
40
43
|
end
|
@@ -130,6 +133,7 @@ module Skeem
|
|
130
133
|
create_cons(aRuntime)
|
131
134
|
create_car(aRuntime)
|
132
135
|
create_cdr(aRuntime)
|
136
|
+
create_make_list(aRuntime)
|
133
137
|
create_length(aRuntime)
|
134
138
|
create_list2vector(aRuntime)
|
135
139
|
create_append(aRuntime)
|
@@ -157,11 +161,12 @@ module Skeem
|
|
157
161
|
create_map(aRuntime)
|
158
162
|
end
|
159
163
|
|
160
|
-
def add_io_procedures(aRuntime)
|
161
|
-
|
164
|
+
def add_io_procedures(aRuntime)
|
165
|
+
create_display(aRuntime)
|
162
166
|
end
|
163
167
|
|
164
168
|
def add_special_procedures(aRuntime)
|
169
|
+
create_error(aRuntime)
|
165
170
|
create_test_assert(aRuntime)
|
166
171
|
create_debug(aRuntime)
|
167
172
|
create_inspect(aRuntime)
|
@@ -169,7 +174,7 @@ module Skeem
|
|
169
174
|
|
170
175
|
def create_plus(aRuntime)
|
171
176
|
# arglist should be a Ruby Array
|
172
|
-
primitive =
|
177
|
+
primitive = lambda do |_runtime, arglist|
|
173
178
|
if arglist.empty?
|
174
179
|
integer(0)
|
175
180
|
else
|
@@ -183,7 +188,7 @@ module Skeem
|
|
183
188
|
end
|
184
189
|
|
185
190
|
def create_minus(aRuntime)
|
186
|
-
primitive =
|
191
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
187
192
|
raw_result = first_operand.value
|
188
193
|
if arglist.empty?
|
189
194
|
raw_result = -raw_result
|
@@ -197,7 +202,7 @@ module Skeem
|
|
197
202
|
end
|
198
203
|
|
199
204
|
def create_multiply(aRuntime)
|
200
|
-
primitive =
|
205
|
+
primitive = lambda do |_runtime, arglist|
|
201
206
|
if arglist.empty?
|
202
207
|
integer(1)
|
203
208
|
else
|
@@ -211,7 +216,6 @@ module Skeem
|
|
211
216
|
end
|
212
217
|
|
213
218
|
def reciprocal(aLiteral)
|
214
|
-
|
215
219
|
case aLiteral
|
216
220
|
when Integer
|
217
221
|
result = Rational(1, aLiteral)
|
@@ -225,29 +229,26 @@ module Skeem
|
|
225
229
|
end
|
226
230
|
|
227
231
|
def create_divide(aRuntime)
|
228
|
-
primitive =
|
232
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
229
233
|
raw_result = first_operand.value
|
230
234
|
if arglist.empty?
|
231
235
|
raw_result = reciprocal(raw_result)
|
232
236
|
else
|
233
|
-
# Ugly: Ruby version dependency: Rubies older than 2.4 have class Fixnum instead of Integer
|
234
|
-
int_class = (RUBY_VERSION[0..2] < "2.4") ? Fixnum : Integer
|
235
|
-
|
236
237
|
arglist.each do |elem|
|
237
238
|
elem_value = elem.value
|
238
239
|
case [raw_result.class, elem_value.class]
|
239
|
-
when [
|
240
|
+
when [Integer, Integer]
|
240
241
|
if raw_result.modulo(elem_value).zero?
|
241
|
-
raw_result
|
242
|
+
raw_result /= elem_value
|
242
243
|
else
|
243
244
|
raw_result = Rational(raw_result, elem_value)
|
244
245
|
end
|
245
246
|
|
246
|
-
when [
|
247
|
-
raw_result
|
247
|
+
when [Integer, Rational]
|
248
|
+
raw_result *= reciprocal(elem_value)
|
248
249
|
|
249
250
|
when [Rational, Rational]
|
250
|
-
raw_result
|
251
|
+
raw_result *= reciprocal(elem_value)
|
251
252
|
else
|
252
253
|
raw_result = raw_result.to_f
|
253
254
|
raw_result /= elem_value
|
@@ -261,8 +262,8 @@ module Skeem
|
|
261
262
|
end
|
262
263
|
|
263
264
|
def create_floor_slash(aRuntime)
|
264
|
-
primitive =
|
265
|
-
(quotient, modulus) =
|
265
|
+
primitive = lambda do |_runtime, operand1, operand2|
|
266
|
+
(quotient, modulus) = operand1.value.divmod(operand2.value)
|
266
267
|
SkmPair.new(to_datum(quotient), to_datum(modulus)) # improper list!
|
267
268
|
end
|
268
269
|
|
@@ -270,10 +271,10 @@ module Skeem
|
|
270
271
|
end
|
271
272
|
|
272
273
|
def create_truncate_slash(aRuntime)
|
273
|
-
primitive =
|
274
|
-
modulo_ =
|
275
|
-
modulo_ += 1 if modulo_
|
276
|
-
remainder_ =
|
274
|
+
primitive = lambda do |_runtime, operand1, operand2|
|
275
|
+
modulo_ = operand1.value / operand2.value
|
276
|
+
modulo_ += 1 if modulo_.negative?
|
277
|
+
remainder_ = operand1.value.remainder(operand2.value)
|
277
278
|
SkmPair.new(to_datum(modulo_), to_datum(remainder_)) # improper list!
|
278
279
|
end
|
279
280
|
|
@@ -281,7 +282,7 @@ module Skeem
|
|
281
282
|
end
|
282
283
|
|
283
284
|
def create_gcd(aRuntime)
|
284
|
-
primitive =
|
285
|
+
primitive = lambda do |_runtime, arglist|
|
285
286
|
if arglist.empty?
|
286
287
|
integer(0)
|
287
288
|
else
|
@@ -300,7 +301,7 @@ module Skeem
|
|
300
301
|
end
|
301
302
|
|
302
303
|
def create_lcm(aRuntime)
|
303
|
-
primitive =
|
304
|
+
primitive = lambda do |_runtime, arglist|
|
304
305
|
if arglist.empty?
|
305
306
|
integer(1)
|
306
307
|
else
|
@@ -314,7 +315,7 @@ module Skeem
|
|
314
315
|
end
|
315
316
|
|
316
317
|
def create_numerator(aRuntime)
|
317
|
-
primitive =
|
318
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
318
319
|
case arg_evaluated
|
319
320
|
when SkmInteger
|
320
321
|
result = arg_evaluated
|
@@ -328,7 +329,7 @@ module Skeem
|
|
328
329
|
end
|
329
330
|
|
330
331
|
def create_denominator(aRuntime)
|
331
|
-
primitive =
|
332
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
332
333
|
case arg_evaluated
|
333
334
|
when SkmInteger
|
334
335
|
result = 1
|
@@ -342,7 +343,7 @@ module Skeem
|
|
342
343
|
end
|
343
344
|
|
344
345
|
def create_floor(aRuntime)
|
345
|
-
primitive =
|
346
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
346
347
|
result = arg_evaluated.value.floor
|
347
348
|
integer(result)
|
348
349
|
end
|
@@ -351,7 +352,7 @@ module Skeem
|
|
351
352
|
end
|
352
353
|
|
353
354
|
def create_ceiling(aRuntime)
|
354
|
-
primitive =
|
355
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
355
356
|
result = arg_evaluated.value.ceil
|
356
357
|
integer(result)
|
357
358
|
end
|
@@ -360,7 +361,7 @@ module Skeem
|
|
360
361
|
end
|
361
362
|
|
362
363
|
def create_round(aRuntime)
|
363
|
-
primitive =
|
364
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
364
365
|
result = arg_evaluated.value.round
|
365
366
|
integer(result)
|
366
367
|
end
|
@@ -374,8 +375,8 @@ module Skeem
|
|
374
375
|
end
|
375
376
|
|
376
377
|
def create_eqv?(aRuntime)
|
377
|
-
primitive =
|
378
|
-
core_eqv?(
|
378
|
+
primitive = lambda do |_runtime, operand1, operand2|
|
379
|
+
core_eqv?(operand1, operand2)
|
379
380
|
end
|
380
381
|
|
381
382
|
define_primitive_proc(aRuntime, 'eqv?', binary, primitive)
|
@@ -387,7 +388,7 @@ module Skeem
|
|
387
388
|
end
|
388
389
|
|
389
390
|
def create_eq?(aRuntime)
|
390
|
-
primitive =
|
391
|
+
primitive = lambda do |_runtime, operand1, operand2|
|
391
392
|
core_eq?(operand1, operand2)
|
392
393
|
end
|
393
394
|
|
@@ -395,8 +396,8 @@ module Skeem
|
|
395
396
|
end
|
396
397
|
|
397
398
|
def create_equal?(aRuntime)
|
398
|
-
primitive =
|
399
|
-
raw_result =
|
399
|
+
primitive = lambda do |_runtime, operand1, operand2|
|
400
|
+
raw_result = operand1.skm_equal?(operand2)
|
400
401
|
boolean(raw_result)
|
401
402
|
end
|
402
403
|
|
@@ -404,7 +405,7 @@ module Skeem
|
|
404
405
|
end
|
405
406
|
|
406
407
|
def create_equal(aRuntime)
|
407
|
-
primitive =
|
408
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
408
409
|
if arglist.empty?
|
409
410
|
boolean(true)
|
410
411
|
else
|
@@ -418,11 +419,11 @@ module Skeem
|
|
418
419
|
end
|
419
420
|
|
420
421
|
def create_lt(aRuntime)
|
421
|
-
primitive =
|
422
|
+
primitive = lambda do |runtime, first_operand, arglist|
|
422
423
|
if arglist.empty?
|
423
424
|
result = false
|
424
425
|
else
|
425
|
-
result = primitive_comparison(:<,
|
426
|
+
result = primitive_comparison(:<, runtime, first_operand, arglist)
|
426
427
|
end
|
427
428
|
boolean(result)
|
428
429
|
end
|
@@ -431,11 +432,11 @@ module Skeem
|
|
431
432
|
end
|
432
433
|
|
433
434
|
def create_gt(aRuntime)
|
434
|
-
primitive =
|
435
|
+
primitive = lambda do |runtime, first_operand, arglist|
|
435
436
|
if arglist.empty?
|
436
437
|
result = false
|
437
438
|
else
|
438
|
-
result = primitive_comparison(:>,
|
439
|
+
result = primitive_comparison(:>, runtime, first_operand, arglist)
|
439
440
|
end
|
440
441
|
boolean(result)
|
441
442
|
end
|
@@ -444,11 +445,11 @@ module Skeem
|
|
444
445
|
end
|
445
446
|
|
446
447
|
def create_lte(aRuntime)
|
447
|
-
primitive =
|
448
|
+
primitive = lambda do |runtime, first_operand, arglist|
|
448
449
|
if arglist.empty?
|
449
450
|
result = true
|
450
451
|
else
|
451
|
-
result = primitive_comparison(:<=,
|
452
|
+
result = primitive_comparison(:<=, runtime, first_operand, arglist)
|
452
453
|
end
|
453
454
|
boolean(result)
|
454
455
|
end
|
@@ -457,11 +458,11 @@ module Skeem
|
|
457
458
|
end
|
458
459
|
|
459
460
|
def create_gte(aRuntime)
|
460
|
-
primitive =
|
461
|
+
primitive = lambda do |runtime, first_operand, arglist|
|
461
462
|
if arglist.empty?
|
462
463
|
result = true
|
463
464
|
else
|
464
|
-
result = primitive_comparison(:>=,
|
465
|
+
result = primitive_comparison(:>=, runtime, first_operand, arglist)
|
465
466
|
end
|
466
467
|
boolean(result)
|
467
468
|
end
|
@@ -480,7 +481,7 @@ module Skeem
|
|
480
481
|
end
|
481
482
|
|
482
483
|
def create_max(aRuntime)
|
483
|
-
primitive =
|
484
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
484
485
|
if arglist.empty?
|
485
486
|
result = first_operand
|
486
487
|
else
|
@@ -498,7 +499,7 @@ module Skeem
|
|
498
499
|
end
|
499
500
|
|
500
501
|
def create_min(aRuntime)
|
501
|
-
primitive =
|
502
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
502
503
|
if arglist.empty?
|
503
504
|
result = first_operand
|
504
505
|
else
|
@@ -517,7 +518,7 @@ module Skeem
|
|
517
518
|
|
518
519
|
def create_number2string(aRuntime)
|
519
520
|
# TODO: add support for radix argument
|
520
|
-
primitive =
|
521
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
521
522
|
check_argtype(arg_evaluated, SkmNumber, 'number', 'number->string')
|
522
523
|
string(arg_evaluated.value)
|
523
524
|
end
|
@@ -528,7 +529,7 @@ module Skeem
|
|
528
529
|
def create_and(aRuntime)
|
529
530
|
# arglist should be a Ruby Array
|
530
531
|
# Arguments aren't evaluated yet!...
|
531
|
-
primitive =
|
532
|
+
primitive = lambda do |runtime, arglist|
|
532
533
|
if arglist.empty?
|
533
534
|
boolean(true) # in conformance with 4.2.1
|
534
535
|
else
|
@@ -536,7 +537,7 @@ module Skeem
|
|
536
537
|
last_result = nil
|
537
538
|
# $stderr.puts arglist.inspect
|
538
539
|
arglist.each do |raw_arg|
|
539
|
-
argument = raw_arg.evaluate(
|
540
|
+
argument = raw_arg.evaluate(runtime)
|
540
541
|
last_result = argument
|
541
542
|
raw_result &&= !(argument.boolean? && !argument.value)
|
542
543
|
break unless raw_result # stop here, a false was found...
|
@@ -554,14 +555,14 @@ module Skeem
|
|
554
555
|
def create_or(aRuntime)
|
555
556
|
# arglist should be a Ruby Array
|
556
557
|
# Arguments aren't evaluated yet!...
|
557
|
-
primitive =
|
558
|
+
primitive = lambda do |runtime, arglist|
|
558
559
|
if arglist.empty?
|
559
560
|
boolean(false) # in conformance with 4.2.1
|
560
561
|
else
|
561
562
|
raw_result = false
|
562
563
|
last_result = nil
|
563
564
|
arglist.each do |raw_arg|
|
564
|
-
argument = raw_arg.evaluate(
|
565
|
+
argument = raw_arg.evaluate(runtime)
|
565
566
|
last_result = argument
|
566
567
|
raw_result ||= (!argument.boolean? || argument.value)
|
567
568
|
break if raw_result # stop here, a true was found...
|
@@ -601,7 +602,7 @@ module Skeem
|
|
601
602
|
end
|
602
603
|
|
603
604
|
def create_boolean_equal(aRuntime)
|
604
|
-
primitive =
|
605
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
605
606
|
compare_all(first_operand, arglist, :==)
|
606
607
|
end
|
607
608
|
|
@@ -609,7 +610,7 @@ module Skeem
|
|
609
610
|
end
|
610
611
|
|
611
612
|
def create_char2int(aRuntime)
|
612
|
-
primitive =
|
613
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
613
614
|
check_argtype(arg_evaluated, SkmChar, 'character', 'char->integer')
|
614
615
|
integer(arg_evaluated.value.ord)
|
615
616
|
end
|
@@ -618,7 +619,7 @@ module Skeem
|
|
618
619
|
end
|
619
620
|
|
620
621
|
def create_int2char(aRuntime)
|
621
|
-
primitive =
|
622
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
622
623
|
check_argtype(arg_evaluated, SkmInteger, 'integer', 'integer->char')
|
623
624
|
char(arg_evaluated.value.ord)
|
624
625
|
end
|
@@ -627,7 +628,7 @@ module Skeem
|
|
627
628
|
end
|
628
629
|
|
629
630
|
def create_char_equal(aRuntime)
|
630
|
-
primitive =
|
631
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
631
632
|
compare_all(first_operand, arglist, :==)
|
632
633
|
end
|
633
634
|
|
@@ -635,7 +636,7 @@ module Skeem
|
|
635
636
|
end
|
636
637
|
|
637
638
|
def create_char_lt(aRuntime)
|
638
|
-
primitive =
|
639
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
639
640
|
compare_all(first_operand, arglist, :<)
|
640
641
|
end
|
641
642
|
|
@@ -643,7 +644,7 @@ module Skeem
|
|
643
644
|
end
|
644
645
|
|
645
646
|
def create_char_gt(aRuntime)
|
646
|
-
primitive =
|
647
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
647
648
|
compare_all(first_operand, arglist, :>)
|
648
649
|
end
|
649
650
|
|
@@ -651,7 +652,7 @@ module Skeem
|
|
651
652
|
end
|
652
653
|
|
653
654
|
def create_char_lte(aRuntime)
|
654
|
-
primitive =
|
655
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
655
656
|
compare_all(first_operand, arglist, :<=)
|
656
657
|
end
|
657
658
|
|
@@ -659,23 +660,22 @@ module Skeem
|
|
659
660
|
end
|
660
661
|
|
661
662
|
def create_char_gte(aRuntime)
|
662
|
-
primitive =
|
663
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
663
664
|
compare_all(first_operand, arglist, :>=)
|
664
665
|
end
|
665
666
|
|
666
667
|
define_primitive_proc(aRuntime, 'char>=?', one_or_more, primitive)
|
667
668
|
end
|
668
669
|
|
669
|
-
|
670
670
|
def create_make_string(aRuntime)
|
671
|
-
primitive =
|
671
|
+
primitive = lambda do |_runtime, count_arg, arglist|
|
672
672
|
count = count_arg
|
673
|
-
check_argtype(count, SkmInteger, 'integer', '
|
673
|
+
check_argtype(count, SkmInteger, 'integer', 'make-string')
|
674
674
|
if arglist.empty?
|
675
675
|
filler = SkmChar.create(rand(0xff).chr)
|
676
676
|
else
|
677
677
|
filler = arglist.first
|
678
|
-
check_argtype(filler, SkmChar, 'char', '
|
678
|
+
check_argtype(filler, SkmChar, 'char', 'make-string')
|
679
679
|
end
|
680
680
|
string(filler.value.to_s * count.value)
|
681
681
|
end
|
@@ -684,11 +684,11 @@ module Skeem
|
|
684
684
|
end
|
685
685
|
|
686
686
|
def create_string_string(aRuntime)
|
687
|
-
primitive =
|
687
|
+
primitive = lambda do |_runtime, arglist|
|
688
688
|
if arglist.empty?
|
689
689
|
value = ''
|
690
690
|
else
|
691
|
-
value = arglist.reduce('') do |interim, some_char|
|
691
|
+
value = arglist.reduce(+'') do |interim, some_char|
|
692
692
|
check_argtype(some_char, SkmChar, 'character', 'string')
|
693
693
|
interim << some_char.value
|
694
694
|
end
|
@@ -701,7 +701,7 @@ module Skeem
|
|
701
701
|
end
|
702
702
|
|
703
703
|
def create_string_equal(aRuntime)
|
704
|
-
primitive =
|
704
|
+
primitive = lambda do |_runtime, first_operand, arglist|
|
705
705
|
all_same?(first_operand, arglist)
|
706
706
|
end
|
707
707
|
|
@@ -709,11 +709,11 @@ module Skeem
|
|
709
709
|
end
|
710
710
|
|
711
711
|
def create_string_append(aRuntime)
|
712
|
-
primitive =
|
712
|
+
primitive = lambda do |_runtime, arglist|
|
713
713
|
if arglist.empty?
|
714
714
|
value = ''
|
715
715
|
else
|
716
|
-
value = arglist.reduce('') { |interim, substr| interim << substr.value }
|
716
|
+
value = arglist.reduce(+'') { |interim, substr| interim << substr.value }
|
717
717
|
end
|
718
718
|
|
719
719
|
string(value)
|
@@ -723,7 +723,7 @@ module Skeem
|
|
723
723
|
end
|
724
724
|
|
725
725
|
def create_string_length(aRuntime)
|
726
|
-
primitive =
|
726
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
727
727
|
check_argtype(arg_evaluated, SkmString, 'string', 'string-length')
|
728
728
|
integer(arg_evaluated.length)
|
729
729
|
end
|
@@ -732,7 +732,7 @@ module Skeem
|
|
732
732
|
end
|
733
733
|
|
734
734
|
def create_string2symbol(aRuntime)
|
735
|
-
primitive =
|
735
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
736
736
|
check_argtype(arg_evaluated, SkmString, 'string', 'string->symbol')
|
737
737
|
identifier(arg_evaluated)
|
738
738
|
end
|
@@ -741,7 +741,7 @@ module Skeem
|
|
741
741
|
end
|
742
742
|
|
743
743
|
def create_symbol2string(aRuntime)
|
744
|
-
primitive =
|
744
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
745
745
|
check_argtype(arg_evaluated, SkmIdentifier, 'symbol', 'symbol->string')
|
746
746
|
string(arg_evaluated)
|
747
747
|
end
|
@@ -750,7 +750,7 @@ module Skeem
|
|
750
750
|
end
|
751
751
|
|
752
752
|
def create_car(aRuntime)
|
753
|
-
primitive =
|
753
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
754
754
|
check_argtype(arg_evaluated, SkmPair, 'pair', 'car')
|
755
755
|
arg_evaluated.car
|
756
756
|
end
|
@@ -759,7 +759,7 @@ module Skeem
|
|
759
759
|
end
|
760
760
|
|
761
761
|
def create_cdr(aRuntime)
|
762
|
-
primitive =
|
762
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
763
763
|
check_argtype(arg_evaluated, SkmPair, 'pair', 'cdr')
|
764
764
|
arg_evaluated.cdr
|
765
765
|
end
|
@@ -768,15 +768,31 @@ module Skeem
|
|
768
768
|
end
|
769
769
|
|
770
770
|
def create_cons(aRuntime)
|
771
|
-
primitive =
|
771
|
+
primitive = lambda do |_runtime, obj1, obj2|
|
772
772
|
SkmPair.new(obj1, obj2)
|
773
773
|
end
|
774
774
|
|
775
775
|
define_primitive_proc(aRuntime, 'cons', binary, primitive)
|
776
776
|
end
|
777
777
|
|
778
|
+
def create_make_list(aRuntime)
|
779
|
+
primitive = lambda do |_runtime, count_arg, arglist|
|
780
|
+
count = count_arg
|
781
|
+
check_argtype(count, SkmInteger, 'integer', 'make-list')
|
782
|
+
if arglist.empty?
|
783
|
+
filler = SkmUndefined.instance
|
784
|
+
else
|
785
|
+
filler = arglist.first
|
786
|
+
end
|
787
|
+
arr = Array.new(count.value, filler)
|
788
|
+
SkmPair.create_from_a(arr)
|
789
|
+
end
|
790
|
+
|
791
|
+
define_primitive_proc(aRuntime, 'make-list', one_or_two, primitive)
|
792
|
+
end
|
793
|
+
|
778
794
|
def create_length(aRuntime)
|
779
|
-
primitive =
|
795
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
780
796
|
check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'length')
|
781
797
|
integer(arg_evaluated.length)
|
782
798
|
end
|
@@ -785,7 +801,7 @@ module Skeem
|
|
785
801
|
end
|
786
802
|
|
787
803
|
def create_list2vector(aRuntime)
|
788
|
-
primitive =
|
804
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
789
805
|
check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'list->vector')
|
790
806
|
vector(arg_evaluated.to_a)
|
791
807
|
end
|
@@ -801,7 +817,7 @@ module Skeem
|
|
801
817
|
else
|
802
818
|
but_last = arglist.take(arglist.length - 1)
|
803
819
|
check_arguments(but_last, [SkmPair, SkmEmptyList], 'list', 'append')
|
804
|
-
result = arglist.shift.klone
|
820
|
+
result = arglist.shift.klone # First list is taken
|
805
821
|
arglist.each do |arg|
|
806
822
|
case arg
|
807
823
|
when SkmPair
|
@@ -809,11 +825,7 @@ module Skeem
|
|
809
825
|
if result.kind_of?(SkmEmptyList)
|
810
826
|
result = cloned
|
811
827
|
else
|
812
|
-
|
813
|
-
result = SkmPair.new(arg, SkmEmptyList.instance)
|
814
|
-
else
|
815
|
-
result.append_list(cloned)
|
816
|
-
end
|
828
|
+
result.append_list(cloned)
|
817
829
|
end
|
818
830
|
when SkmEmptyList
|
819
831
|
# Do nothing
|
@@ -832,9 +844,9 @@ module Skeem
|
|
832
844
|
|
833
845
|
def create_append(aRuntime)
|
834
846
|
# Arguments aren't evaluated yet!...
|
835
|
-
primitive =
|
847
|
+
primitive = lambda do |runtime, arglist|
|
836
848
|
if arglist.size > 1
|
837
|
-
arguments = evaluate_arguments(arglist,
|
849
|
+
arguments = evaluate_arguments(arglist, runtime)
|
838
850
|
else
|
839
851
|
arguments = arglist
|
840
852
|
end
|
@@ -846,13 +858,14 @@ module Skeem
|
|
846
858
|
end
|
847
859
|
|
848
860
|
def create_reverse(aRuntime)
|
849
|
-
primitive =
|
861
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
850
862
|
check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'reverse')
|
851
863
|
if arg_evaluated == SkmEmptyList.instance
|
852
864
|
result = arg_evaluated
|
853
865
|
else
|
854
866
|
err_msg = 'reverse procedure requires a proper list as argument'
|
855
|
-
raise StandardError, err_msg
|
867
|
+
raise StandardError, err_msg unless arg_evaluated.proper?
|
868
|
+
|
856
869
|
elems_reversed = arg_evaluated.to_a.reverse
|
857
870
|
result = SkmPair.create_from_a(elems_reversed)
|
858
871
|
end
|
@@ -864,7 +877,7 @@ module Skeem
|
|
864
877
|
|
865
878
|
def create_setcar(aRuntime)
|
866
879
|
# Arguments aren't evaluated yet!...
|
867
|
-
primitive =
|
880
|
+
primitive = lambda do |runtime, pair_arg, obj_arg|
|
868
881
|
case pair_arg
|
869
882
|
when SkmPair
|
870
883
|
pair = pair_arg
|
@@ -889,7 +902,7 @@ module Skeem
|
|
889
902
|
|
890
903
|
def create_setcdr(aRuntime)
|
891
904
|
# Arguments aren't evaluated yet!...
|
892
|
-
primitive =
|
905
|
+
primitive = lambda do |runtime, pair_arg, obj_arg|
|
893
906
|
case pair_arg
|
894
907
|
when SkmPair
|
895
908
|
pair = pair_arg
|
@@ -913,21 +926,22 @@ module Skeem
|
|
913
926
|
end
|
914
927
|
|
915
928
|
def create_assq(aRuntime)
|
916
|
-
primitive =
|
929
|
+
primitive = lambda do |runtime, obj_arg, alist_arg|
|
917
930
|
assoc_list = alist_arg.evaluate(runtime)
|
918
931
|
check_assoc_list(assoc_list, 'assq')
|
919
932
|
obj = obj_arg.evaluate(runtime)
|
920
933
|
result = boolean(false)
|
921
934
|
unless assoc_list.empty?
|
922
935
|
pair = assoc_list
|
923
|
-
|
936
|
+
loop do
|
924
937
|
are_equal = core_eq?(pair.car.car, obj)
|
925
938
|
if are_equal.value
|
926
939
|
result = pair.car
|
927
940
|
break
|
928
941
|
end
|
929
942
|
pair = pair.cdr
|
930
|
-
|
943
|
+
break unless pair.kind_of?(SkmPair)
|
944
|
+
end
|
931
945
|
end
|
932
946
|
|
933
947
|
result
|
@@ -936,19 +950,20 @@ module Skeem
|
|
936
950
|
end
|
937
951
|
|
938
952
|
def create_assv(aRuntime)
|
939
|
-
primitive =
|
953
|
+
primitive = lambda do |_runtime, obj, assoc_list|
|
940
954
|
check_assoc_list(assoc_list, 'assq')
|
941
955
|
result = boolean(false)
|
942
956
|
unless assoc_list.empty?
|
943
957
|
pair = assoc_list
|
944
|
-
|
958
|
+
loop do
|
945
959
|
are_equal = core_eqv?(pair.car.car, obj)
|
946
960
|
if are_equal.value
|
947
961
|
result = pair.car
|
948
962
|
break
|
949
963
|
end
|
950
964
|
pair = pair.cdr
|
951
|
-
|
965
|
+
break unless pair.kind_of?(SkmPair)
|
966
|
+
end
|
952
967
|
end
|
953
968
|
|
954
969
|
result
|
@@ -961,15 +976,16 @@ module Skeem
|
|
961
976
|
|
962
977
|
unless alist.empty?
|
963
978
|
cell = SkmPair.new(integer(1), alist)
|
964
|
-
|
979
|
+
loop do
|
965
980
|
cell = cell.cdr
|
966
981
|
check_argtype(cell, SkmPair, 'association list', proc_name)
|
967
|
-
|
982
|
+
break unless cell.cdr.kind_of?(SkmPair)
|
983
|
+
end
|
968
984
|
end
|
969
985
|
end
|
970
986
|
|
971
987
|
def create_list_copy(aRuntime)
|
972
|
-
primitive =
|
988
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
973
989
|
check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'list-copy')
|
974
990
|
arg_evaluated.klone # Previously: arg.klone
|
975
991
|
end
|
@@ -978,7 +994,7 @@ module Skeem
|
|
978
994
|
end
|
979
995
|
|
980
996
|
def create_vector(aRuntime)
|
981
|
-
primitive =
|
997
|
+
primitive = lambda do |_runtime, elements|
|
982
998
|
vector(elements)
|
983
999
|
end
|
984
1000
|
|
@@ -986,7 +1002,7 @@ module Skeem
|
|
986
1002
|
end
|
987
1003
|
|
988
1004
|
def create_vector_length(aRuntime)
|
989
|
-
primitive =
|
1005
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
990
1006
|
check_argtype(arg_evaluated, SkmVector, 'vector', 'vector-length')
|
991
1007
|
integer(arg_evaluated.length)
|
992
1008
|
end
|
@@ -995,7 +1011,7 @@ module Skeem
|
|
995
1011
|
end
|
996
1012
|
|
997
1013
|
def create_make_vector(aRuntime)
|
998
|
-
primitive =
|
1014
|
+
primitive = lambda do |runtime, count_arg, arglist|
|
999
1015
|
count = count_arg.evaluate(runtime)
|
1000
1016
|
check_argtype(count, SkmInteger, 'integer', 'make_vector')
|
1001
1017
|
if arglist.empty?
|
@@ -1011,8 +1027,8 @@ module Skeem
|
|
1011
1027
|
end
|
1012
1028
|
|
1013
1029
|
def create_vector_ref(aRuntime)
|
1014
|
-
|
1015
|
-
|
1030
|
+
# argument 1: a vector, argument 2: an index(integer)
|
1031
|
+
primitive = lambda do |_runtime, vector, index|
|
1016
1032
|
check_argtype(vector, SkmVector, 'vector', 'vector-ref')
|
1017
1033
|
check_argtype(index, SkmInteger, 'integer', 'vector-ref')
|
1018
1034
|
# TODO: index checking
|
@@ -1022,10 +1038,10 @@ module Skeem
|
|
1022
1038
|
|
1023
1039
|
define_primitive_proc(aRuntime, 'vector-ref', binary, primitive)
|
1024
1040
|
end
|
1025
|
-
|
1041
|
+
|
1026
1042
|
def create_vector_set(aRuntime)
|
1027
|
-
|
1028
|
-
|
1043
|
+
# Arguments aren't evaluated yet!...
|
1044
|
+
primitive = lambda do |runtime, vector, k, object|
|
1029
1045
|
index = k.evaluate(runtime)
|
1030
1046
|
check_argtype(vector, SkmVector, 'vector', 'vector-set!')
|
1031
1047
|
check_argtype(index, SkmInteger, 'integer', 'vector-set!')
|
@@ -1033,12 +1049,12 @@ module Skeem
|
|
1033
1049
|
vector.members[index.value] = object
|
1034
1050
|
vector
|
1035
1051
|
end
|
1036
|
-
|
1052
|
+
|
1037
1053
|
define_primitive_proc(aRuntime, 'vector-set!', ternary, primitive)
|
1038
1054
|
end
|
1039
1055
|
|
1040
1056
|
def create_vector2list(aRuntime)
|
1041
|
-
primitive =
|
1057
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
1042
1058
|
check_argtype(arg_evaluated, SkmVector, 'vector', 'vector->list')
|
1043
1059
|
SkmPair.create_from_a(arg_evaluated.members)
|
1044
1060
|
end
|
@@ -1047,7 +1063,7 @@ module Skeem
|
|
1047
1063
|
end
|
1048
1064
|
|
1049
1065
|
def create_apply(aRuntime)
|
1050
|
-
primitive =
|
1066
|
+
primitive = lambda do |runtime, proc_arg, arglist|
|
1051
1067
|
if arglist.empty?
|
1052
1068
|
result = SkmEmptyList.instance
|
1053
1069
|
else
|
@@ -1055,18 +1071,19 @@ module Skeem
|
|
1055
1071
|
invoke = ProcedureCall.new(nil, proc_arg, single_list.to_a)
|
1056
1072
|
result = invoke.evaluate(runtime)
|
1057
1073
|
end
|
1074
|
+
result
|
1058
1075
|
end
|
1059
1076
|
|
1060
1077
|
define_primitive_proc(aRuntime, 'apply', one_or_more, primitive)
|
1061
1078
|
end
|
1062
1079
|
|
1063
1080
|
def create_map(aRuntime)
|
1064
|
-
primitive =
|
1081
|
+
primitive = lambda do |runtime, proc_arg, arglist|
|
1065
1082
|
if arglist.empty?
|
1066
1083
|
result = SkmEmptyList.instance
|
1067
1084
|
else
|
1068
1085
|
curr_cells = arglist
|
1069
|
-
arity = curr_cells.size
|
1086
|
+
# arity = curr_cells.size
|
1070
1087
|
initial_result = nil
|
1071
1088
|
curr_result = nil
|
1072
1089
|
loop do
|
@@ -1082,7 +1099,7 @@ module Skeem
|
|
1082
1099
|
curr_result = new_result
|
1083
1100
|
|
1084
1101
|
curr_cells.map!(&:cdr)
|
1085
|
-
break if curr_cells.find { |cdr_entry| !
|
1102
|
+
break if curr_cells.find { |cdr_entry| !cdr_entry.kind_of?(SkmPair) }
|
1086
1103
|
end
|
1087
1104
|
|
1088
1105
|
result = initial_result
|
@@ -1094,24 +1111,33 @@ module Skeem
|
|
1094
1111
|
define_primitive_proc(aRuntime, 'map', one_or_more, primitive)
|
1095
1112
|
end
|
1096
1113
|
|
1097
|
-
def
|
1098
|
-
primitive =
|
1114
|
+
def create_display(aRuntime)
|
1115
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
1099
1116
|
# @TODO: make output stream configurable
|
1100
|
-
print
|
1117
|
+
print arg_evaluated.value.to_s
|
1118
|
+
SkmUndefined.instance
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
define_primitive_proc(aRuntime, 'display', unary, primitive)
|
1122
|
+
end
|
1123
|
+
|
1124
|
+
def create_error(aRuntime)
|
1125
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
1126
|
+
raise SkmError, arg_evaluated.value
|
1101
1127
|
end
|
1102
1128
|
|
1103
|
-
define_primitive_proc(aRuntime, '
|
1129
|
+
define_primitive_proc(aRuntime, 'error', unary, primitive)
|
1104
1130
|
end
|
1105
1131
|
|
1106
1132
|
def create_test_assert(aRuntime)
|
1107
|
-
primitive =
|
1133
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
1108
1134
|
if arg_evaluated.boolean? && arg_evaluated.value == false
|
1109
1135
|
assert_call = aRuntime.caller
|
1110
1136
|
pos = assert_call.call_site
|
1111
1137
|
# Error: assertion failed: (> 1 2)
|
1112
1138
|
msg1 = "assertion failed on line #{pos.line}, column #{pos.column}"
|
1113
1139
|
msg2 = ", with #{arg_evaluated.inspect}"
|
1114
|
-
raise StandardError,
|
1140
|
+
raise StandardError, "Error: #{msg1}#{msg2}"
|
1115
1141
|
else
|
1116
1142
|
boolean(true)
|
1117
1143
|
end
|
@@ -1123,7 +1149,7 @@ module Skeem
|
|
1123
1149
|
# DON'T USE IT
|
1124
1150
|
# Non-standard procedure reserved for internal testing/debugging purposes.
|
1125
1151
|
def create_debug(aRuntime)
|
1126
|
-
primitive =
|
1152
|
+
primitive = lambda do |_runtime|
|
1127
1153
|
require 'debug'
|
1128
1154
|
end
|
1129
1155
|
|
@@ -1133,8 +1159,8 @@ module Skeem
|
|
1133
1159
|
# DON'T USE IT
|
1134
1160
|
# Non-standard procedure reserved for internal testing/debugging purposes.
|
1135
1161
|
def create_inspect(aRuntime)
|
1136
|
-
primitive =
|
1137
|
-
$stderr.puts
|
1162
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
1163
|
+
$stderr.puts "INSPECT>#{arg_evaluated.inspect}"
|
1138
1164
|
Skeem::SkmUndefined.instance
|
1139
1165
|
end
|
1140
1166
|
define_primitive_proc(aRuntime, '_inspect', unary, primitive)
|
@@ -1142,7 +1168,7 @@ module Skeem
|
|
1142
1168
|
|
1143
1169
|
def create_object_predicate(aRuntime, predicate_name, msg_name = nil)
|
1144
1170
|
msg_name = predicate_name if msg_name.nil?
|
1145
|
-
primitive =
|
1171
|
+
primitive = lambda do |_runtime, arg_evaluated|
|
1146
1172
|
to_datum(arg_evaluated.send(msg_name))
|
1147
1173
|
end
|
1148
1174
|
|
@@ -1202,7 +1228,7 @@ module Skeem
|
|
1202
1228
|
else
|
1203
1229
|
msg2 = "but got #{argument.class}"
|
1204
1230
|
end
|
1205
|
-
raise StandardError, msg1
|
1231
|
+
raise StandardError, "#{msg1} #{msg2}"
|
1206
1232
|
end
|
1207
1233
|
|
1208
1234
|
def remaining_args(arglist, aRuntime)
|
@@ -1216,4 +1242,4 @@ module Skeem
|
|
1216
1242
|
end
|
1217
1243
|
end # module
|
1218
1244
|
end # module
|
1219
|
-
end # module
|
1245
|
+
end # module
|