skeem 0.2.16 → 0.2.20
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 +283 -11
- data/.travis.yml +27 -0
- data/CHANGELOG.md +30 -1
- data/README.md +1 -1
- data/bin/skeem +4 -4
- data/lib/skeem/datum_dsl.rb +36 -35
- data/lib/skeem/grammar.rb +38 -77
- data/lib/skeem/interpreter.rb +8 -4
- data/lib/skeem/primitive/primitive_builder.rb +7 -15
- data/lib/skeem/primitive/primitive_procedure.rb +11 -5
- data/lib/skeem/runtime.rb +8 -10
- data/lib/skeem/s_expr_builder.rb +18 -57
- data/lib/skeem/s_expr_nodes.rb +46 -45
- data/lib/skeem/skeem_exception.rb +1 -0
- data/lib/skeem/skm_binding.rb +4 -5
- data/lib/skeem/skm_compound_datum.rb +2 -3
- data/lib/skeem/skm_element.rb +1 -1
- data/lib/skeem/skm_pair.rb +5 -2
- data/lib/skeem/skm_procedure_exec.rb +3 -0
- data/lib/skeem/skm_simple_datum.rb +12 -10
- data/lib/skeem/skm_unary_expression.rb +25 -26
- data/lib/skeem/tokenizer.rb +14 -7
- data/lib/skeem/version.rb +1 -1
- data/skeem.gemspec +5 -5
- data/spec/skeem/element_visitor_spec.rb +3 -1
- data/spec/skeem/interpreter_spec.rb +3 -1
- data/spec/skeem/lambda_spec.rb +4 -4
- data/spec/skeem/parser_spec.rb +2 -0
- data/spec/skeem/primitive/primitive_builder_spec.rb +5 -5
- data/spec/skeem/primitive/primitive_procedure_spec.rb +1 -1
- data/spec/skeem/runtime_spec.rb +2 -2
- data/spec/skeem/skm_compound_datum_spec.rb +1 -1
- data/spec/skeem/skm_pair_spec.rb +5 -5
- data/spec/skeem/tokenizer_spec.rb +4 -2
- data/spec/spec_helper.rb +13 -10
- metadata +10 -9
data/lib/skeem/datum_dsl.rb
CHANGED
@@ -11,7 +11,7 @@ module Skeem
|
|
11
11
|
def boolean(aBoolean)
|
12
12
|
return aBoolean if aBoolean.kind_of?(SkmBoolean)
|
13
13
|
|
14
|
-
|
14
|
+
case aBoolean
|
15
15
|
when TrueClass, FalseClass
|
16
16
|
SkmBoolean.create(aBoolean)
|
17
17
|
when /^#t(?:rue)?|true$/
|
@@ -21,13 +21,12 @@ module Skeem
|
|
21
21
|
else
|
22
22
|
raise StandardError, aBoolean.inspect
|
23
23
|
end
|
24
|
-
result
|
25
24
|
end
|
26
25
|
|
27
26
|
def integer(aLiteral)
|
28
27
|
return aLiteral if aLiteral.kind_of?(SkmInteger)
|
29
28
|
|
30
|
-
|
29
|
+
case aLiteral
|
31
30
|
when Integer
|
32
31
|
SkmInteger.create(aLiteral)
|
33
32
|
when /^[+-]?\d+$/
|
@@ -35,13 +34,12 @@ module Skeem
|
|
35
34
|
else
|
36
35
|
raise StandardError, aLiteral.inspect
|
37
36
|
end
|
38
|
-
result
|
39
37
|
end
|
40
38
|
|
41
39
|
def rational(aLiteral)
|
42
40
|
return aLiteral if aLiteral.kind_of?(SkmRational)
|
43
41
|
|
44
|
-
|
42
|
+
case aLiteral
|
45
43
|
when Rational
|
46
44
|
SkmRational.create(aLiteral)
|
47
45
|
when /^[+-]?\d+\/\d+$/
|
@@ -49,13 +47,12 @@ module Skeem
|
|
49
47
|
else
|
50
48
|
raise StandardError, aLiteral.inspect
|
51
49
|
end
|
52
|
-
result
|
53
50
|
end
|
54
51
|
|
55
52
|
def real(aLiteral)
|
56
53
|
return aLiteral if aLiteral.kind_of?(SkmReal)
|
57
54
|
|
58
|
-
|
55
|
+
case aLiteral
|
59
56
|
when Numeric
|
60
57
|
SkmReal.create(aLiteral)
|
61
58
|
when /^[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?$/
|
@@ -63,13 +60,12 @@ module Skeem
|
|
63
60
|
else
|
64
61
|
raise StandardError, aLiteral.inspect
|
65
62
|
end
|
66
|
-
result
|
67
63
|
end
|
68
64
|
|
69
65
|
def char(aLiteral)
|
70
66
|
return aLiteral if aLiteral.kind_of?(SkmChar)
|
71
67
|
|
72
|
-
|
68
|
+
case aLiteral
|
73
69
|
when Numeric
|
74
70
|
SkmChar.create_from_int(aLiteral)
|
75
71
|
when String
|
@@ -81,13 +77,12 @@ module Skeem
|
|
81
77
|
else
|
82
78
|
raise StandardError, aLiteral.inspect
|
83
79
|
end
|
84
|
-
result
|
85
80
|
end
|
86
81
|
|
87
82
|
def string(aLiteral)
|
88
83
|
return aLiteral if aLiteral.kind_of?(SkmString)
|
89
84
|
|
90
|
-
|
85
|
+
case aLiteral
|
91
86
|
when String
|
92
87
|
SkmString.create(aLiteral)
|
93
88
|
when SkmIdentifier
|
@@ -95,13 +90,12 @@ module Skeem
|
|
95
90
|
else
|
96
91
|
SkmString.create(aLiteral.to_s)
|
97
92
|
end
|
98
|
-
result
|
99
93
|
end
|
100
94
|
|
101
95
|
def identifier(aLiteral)
|
102
96
|
return aLiteral if aLiteral.kind_of?(SkmIdentifier)
|
103
97
|
|
104
|
-
|
98
|
+
case aLiteral
|
105
99
|
when String
|
106
100
|
SkmIdentifier.create(aLiteral)
|
107
101
|
when SkmString
|
@@ -109,13 +103,12 @@ module Skeem
|
|
109
103
|
else
|
110
104
|
raise StandardError, aLiteral.inspect
|
111
105
|
end
|
112
|
-
result
|
113
106
|
end
|
114
107
|
|
115
108
|
alias symbol identifier
|
116
109
|
|
117
110
|
def list(aLiteral)
|
118
|
-
|
111
|
+
case aLiteral
|
119
112
|
when Array
|
120
113
|
SkmPair.create_from_a(to_datum(aLiteral))
|
121
114
|
when SkmPair
|
@@ -123,12 +116,10 @@ module Skeem
|
|
123
116
|
else
|
124
117
|
SkmPair.new(to_datum(aLiteral), SkmEmptyList.instance)
|
125
118
|
end
|
126
|
-
|
127
|
-
result
|
128
119
|
end
|
129
120
|
|
130
121
|
def vector(aLiteral)
|
131
|
-
|
122
|
+
case aLiteral
|
132
123
|
when Array
|
133
124
|
SkmVector.new(to_datum(aLiteral))
|
134
125
|
when SkmVector
|
@@ -136,8 +127,6 @@ module Skeem
|
|
136
127
|
else
|
137
128
|
SkmVector.new([to_datum(aLiteral)])
|
138
129
|
end
|
139
|
-
|
140
|
-
result
|
141
130
|
end
|
142
131
|
|
143
132
|
# Conversion from Ruby object value to Skeem datum
|
@@ -146,7 +135,7 @@ module Skeem
|
|
146
135
|
return vector(aLiteral.members) if aLiteral.kind_of?(SkmVector)
|
147
136
|
return aLiteral if aLiteral.kind_of?(Primitive::PrimitiveProcedure)
|
148
137
|
|
149
|
-
|
138
|
+
case aLiteral
|
150
139
|
when Array
|
151
140
|
aLiteral.map { |elem| to_datum(elem) }
|
152
141
|
when Integer
|
@@ -166,25 +155,37 @@ module Skeem
|
|
166
155
|
aLiteral
|
167
156
|
else
|
168
157
|
raise StandardError, aLiteral.inspect
|
169
|
-
|
170
|
-
result
|
158
|
+
end
|
171
159
|
end
|
172
160
|
|
173
161
|
private
|
174
162
|
|
175
163
|
def parse_literal(aLiteral)
|
176
|
-
if aLiteral =~ /^#t(?:rue)?|true$/
|
177
|
-
boolean(aLiteral)
|
178
|
-
elsif aLiteral =~ /^#f(?:alse)?|false$/
|
179
|
-
boolean(aLiteral)
|
180
|
-
elsif aLiteral =~ /^[+-]?\d+\/\d+$/
|
181
|
-
rational(aLiteral)
|
182
|
-
elsif aLiteral =~ /^[+-]?\d+$/
|
183
|
-
integer(aLiteral)
|
184
|
-
elsif aLiteral =~ /^[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?$/
|
185
|
-
real(aLiteral)
|
186
|
-
else
|
187
|
-
string(aLiteral)
|
164
|
+
# if aLiteral =~ /^#t(?:rue)?|true$/
|
165
|
+
# boolean(aLiteral)
|
166
|
+
# elsif aLiteral =~ /^#f(?:alse)?|false$/
|
167
|
+
# boolean(aLiteral)
|
168
|
+
# elsif aLiteral =~ /^[+-]?\d+\/\d+$/
|
169
|
+
# rational(aLiteral)
|
170
|
+
# elsif aLiteral =~ /^[+-]?\d+$/
|
171
|
+
# integer(aLiteral)
|
172
|
+
# elsif aLiteral =~ /^[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?$/
|
173
|
+
# real(aLiteral)
|
174
|
+
# else
|
175
|
+
# string(aLiteral)
|
176
|
+
# end
|
177
|
+
|
178
|
+
case aLiteral
|
179
|
+
when /^#t(?:rue)?|true$/, /^#f(?:alse)?|false$/
|
180
|
+
boolean(aLiteral)
|
181
|
+
when /^[+-]?\d+\/\d+$/
|
182
|
+
rational(aLiteral)
|
183
|
+
when /^[+-]?\d+$/
|
184
|
+
integer(aLiteral)
|
185
|
+
when /^[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?$/
|
186
|
+
real(aLiteral)
|
187
|
+
else
|
188
|
+
string(aLiteral)
|
188
189
|
end
|
189
190
|
end
|
190
191
|
end # module
|
data/lib/skeem/grammar.rb
CHANGED
@@ -6,10 +6,10 @@ require 'rley' # Load the gem
|
|
6
6
|
module Skeem
|
7
7
|
########################################
|
8
8
|
# Define a grammar for Skeem
|
9
|
-
#
|
9
|
+
# The official Small Scheme language grammar is available at:
|
10
10
|
# https://bitbucket.org/cowan/r7rs/src/draft-10/rnrs/r7rs.pdf
|
11
11
|
# Names of grammar elements are based on the R7RS documentation
|
12
|
-
builder = Rley::
|
12
|
+
builder = Rley::grammar_builder do
|
13
13
|
# Delimiters, separators...
|
14
14
|
add_terminals('APOSTROPHE', 'COMMA', 'COMMA_AT_SIGN')
|
15
15
|
add_terminals('GRAVE_ACCENT', 'LPAREN', 'RPAREN')
|
@@ -22,7 +22,7 @@ module Skeem
|
|
22
22
|
|
23
23
|
# Keywords...
|
24
24
|
add_terminals('BEGIN', 'COND', 'DEFINE', 'DEFINE-SYNTAX', 'DO')
|
25
|
-
add_terminals('ELSE', 'IF', 'INCLUDE', 'LAMBDA', 'LET', '
|
25
|
+
add_terminals('ELSE', 'IF', 'INCLUDE', 'LAMBDA', 'LET', 'LET_STAR')
|
26
26
|
add_terminals('QUOTE', 'QUASIQUOTE', 'SET!', 'SYNTAX-RULES')
|
27
27
|
add_terminals('UNQUOTE', 'UNQUOTE-SPLICING')
|
28
28
|
|
@@ -36,7 +36,7 @@ module Skeem
|
|
36
36
|
rule('definition' => 'LPAREN DEFINE IDENTIFIER expression RPAREN').as 'definition'
|
37
37
|
rule('definition' => 'LPAREN DEFINE LPAREN IDENTIFIER def_formals RPAREN body RPAREN').as 'alt_definition'
|
38
38
|
rule('definition' => 'syntax_definition')
|
39
|
-
rule('definition' => 'LPAREN BEGIN
|
39
|
+
rule('definition' => 'LPAREN BEGIN definition* RPAREN').as 'definitions_within_begin'
|
40
40
|
rule('expression' => 'IDENTIFIER').as 'variable_reference'
|
41
41
|
rule 'expression' => 'literal'
|
42
42
|
rule 'expression' => 'procedure_call'
|
@@ -63,143 +63,104 @@ module Skeem
|
|
63
63
|
rule 'simple_datum' => 'symbol'
|
64
64
|
rule 'compound_datum' => 'list'
|
65
65
|
rule 'compound_datum' => 'vector'
|
66
|
-
rule('list' => 'LPAREN
|
66
|
+
rule('list' => 'LPAREN datum* RPAREN').as 'list'
|
67
67
|
rule('list' => 'LPAREN datum_plus PERIOD datum RPAREN').as 'dotted_list'
|
68
|
-
rule('vector' => 'VECTOR_BEGIN
|
68
|
+
rule('vector' => 'VECTOR_BEGIN datum* RPAREN').as 'vector'
|
69
69
|
rule('datum_plus' => 'datum_plus datum').as 'multiple_datums'
|
70
70
|
rule('datum_plus' => 'datum').as 'last_datum'
|
71
|
-
rule('datum_star' => 'datum_star datum').as 'star_default'
|
72
|
-
rule('datum_star' => []).as 'star_base' ## 'no_datum_yet'
|
73
71
|
rule 'symbol' => 'IDENTIFIER'
|
74
72
|
rule('procedure_call' => 'LPAREN operator RPAREN').as 'proc_call_nullary'
|
75
|
-
rule('procedure_call' => 'LPAREN operator
|
76
|
-
rule('operand_plus' => 'operand_plus operand').as 'multiple_operands'
|
77
|
-
rule('operand_plus' => 'operand').as 'last_operand'
|
73
|
+
rule('procedure_call' => 'LPAREN operator operand+ RPAREN').as 'proc_call_args'
|
78
74
|
rule 'operator' => 'expression'
|
79
75
|
rule 'operand' => 'expression'
|
80
|
-
rule('def_formals' => '
|
81
|
-
rule('def_formals' => '
|
76
|
+
rule('def_formals' => 'IDENTIFIER*').as 'def_formals'
|
77
|
+
rule('def_formals' => 'IDENTIFIER* PERIOD IDENTIFIER').as 'pair_formals'
|
82
78
|
rule('lambda_expression' => 'LPAREN LAMBDA formals body RPAREN').as 'lambda_expression'
|
83
|
-
rule('formals' => 'LPAREN
|
79
|
+
rule('formals' => 'LPAREN IDENTIFIER* RPAREN').as 'fixed_arity_formals'
|
84
80
|
rule('formals' => 'IDENTIFIER').as 'variadic_formals'
|
85
|
-
rule('formals' => 'LPAREN
|
81
|
+
rule('formals' => 'LPAREN IDENTIFIER+ PERIOD IDENTIFIER RPAREN').as 'dotted_formals'
|
86
82
|
rule('syntax_definition' => 'LPAREN DEFINE-SYNTAX keyword transformer_spec RPAREN').as 'syntax_definition'
|
87
|
-
rule('
|
88
|
-
rule('
|
89
|
-
rule('
|
90
|
-
rule('identifier_plus' => 'IDENTIFIER').as 'last_identifier'
|
91
|
-
rule('body' => 'definition_star sequence').as 'body'
|
92
|
-
rule('definition_star' => 'definition_star definition').as 'star_default'
|
93
|
-
rule('definition_star' => []).as 'star_base' ## 'no_definition_yet'
|
94
|
-
rule('sequence' => 'command_star expression').as 'sequence'
|
95
|
-
rule('command_star' => 'command_star command').as 'star_default'
|
96
|
-
rule('command_star' => []).as 'star_base' ## 'no_command_yet'
|
97
|
-
rule('conditional' => 'LPAREN IF test consequent alternate RPAREN').as 'conditional'
|
83
|
+
rule('body' => 'definition* sequence').as 'body'
|
84
|
+
rule('sequence' => 'command* expression').as 'sequence'
|
85
|
+
rule('conditional' => 'LPAREN IF test consequent expression? RPAREN').as 'conditional'
|
98
86
|
rule 'test' => 'expression'
|
99
87
|
rule 'consequent' => 'expression'
|
100
|
-
rule 'alternate' => 'expression'
|
101
|
-
rule 'alternate' => []
|
102
88
|
rule 'number' => 'INTEGER'
|
103
89
|
rule 'number' => 'RATIONAL'
|
104
90
|
rule 'number' => 'REAL'
|
105
91
|
rule('assignment' => 'LPAREN SET! IDENTIFIER expression RPAREN').as 'assignment'
|
106
|
-
rule('derived_expression' => 'LPAREN COND
|
107
|
-
rule('derived_expression' => 'LPAREN COND
|
108
|
-
rule('derived_expression' => 'LPAREN LET LPAREN
|
92
|
+
rule('derived_expression' => 'LPAREN COND cond_clause+ RPAREN').as 'cond_form'
|
93
|
+
rule('derived_expression' => 'LPAREN COND cond_clause* LPAREN ELSE sequence RPAREN RPAREN').as 'cond_else_form'
|
94
|
+
rule('derived_expression' => 'LPAREN LET LPAREN binding_spec* RPAREN body RPAREN').as 'short_let_form'
|
109
95
|
# TODO: implement "named let"
|
110
|
-
rule('derived_expression' => 'LPAREN LET IDENTIFIER LPAREN
|
111
|
-
rule('derived_expression' => 'LPAREN
|
96
|
+
rule('derived_expression' => 'LPAREN LET IDENTIFIER LPAREN binding_spec* RPAREN body RPAREN') # .as 'named_form'
|
97
|
+
rule('derived_expression' => 'LPAREN LET_STAR LPAREN binding_spec* RPAREN body RPAREN').as 'let_star_form'
|
112
98
|
|
113
99
|
# As the R7RS grammar is too restrictive,
|
114
100
|
# the next rule was made more general than its standard counterpart
|
115
101
|
rule('derived_expression' => 'LPAREN BEGIN body RPAREN').as 'begin_expression'
|
116
102
|
do_syntax = <<-END_SYNTAX
|
117
|
-
LPAREN DO LPAREN
|
103
|
+
LPAREN DO LPAREN iteration_spec* RPAREN
|
118
104
|
LPAREN test do_result RPAREN
|
119
|
-
|
105
|
+
rep_command_star RPAREN
|
120
106
|
END_SYNTAX
|
121
107
|
rule('derived_expression' => do_syntax).as 'do_expression'
|
122
108
|
rule 'derived_expression' => 'quasiquotation'
|
123
|
-
rule('cond_clause_plus' => 'cond_clause_plus cond_clause').as 'multiple_cond_clauses'
|
124
|
-
rule('cond_clause_plus' => 'cond_clause').as 'last_cond_clauses'
|
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'
|
127
109
|
rule('cond_clause' => 'LPAREN test sequence RPAREN').as 'cond_clause'
|
128
110
|
rule('cond_clause' => 'LPAREN test RPAREN')
|
129
111
|
rule('cond_clause' => 'LPAREN test ARROW recipient RPAREN').as 'cond_arrow_clause'
|
130
112
|
rule('recipient' => 'expression')
|
131
113
|
rule('quasiquotation' => 'LPAREN QUASIQUOTE qq_template RPAREN').as 'quasiquotation'
|
132
114
|
rule('quasiquotation' => 'GRAVE_ACCENT qq_template').as 'quasiquotation_short'
|
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'
|
135
115
|
rule('binding_spec' => 'LPAREN IDENTIFIER expression RPAREN').as 'binding_spec'
|
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'
|
138
116
|
rule('iteration_spec' => 'LPAREN IDENTIFIER init step RPAREN').as 'iteration_spec_long'
|
139
117
|
rule('iteration_spec' => 'LPAREN IDENTIFIER init RPAREN').as 'iteration_spec_short'
|
140
118
|
rule('init' => 'expression')
|
141
119
|
rule('step' => 'expression')
|
142
|
-
rule
|
143
|
-
rule('do_result' => []).as 'star_base' ## 'empty_do_result'
|
120
|
+
rule('do_result' => 'sequence?').tag 'do_result'
|
144
121
|
rule('keyword' => 'IDENTIFIER')
|
145
|
-
rule('includer' => 'LPAREN INCLUDE
|
146
|
-
rule('string_plus' => 'string_plus STRING_LIT').as 'multiple_string'
|
147
|
-
rule('string_plus' => 'STRING_LIT').as 'last_single_string'
|
122
|
+
rule('includer' => 'LPAREN INCLUDE STRING_LIT+ RPAREN').as 'include'
|
148
123
|
rule 'qq_template' => 'simple_datum'
|
149
124
|
rule 'qq_template' => 'list_qq_template'
|
150
125
|
rule 'qq_template' => 'vector_qq_template'
|
151
126
|
rule 'qq_template' => 'unquotation'
|
152
|
-
rule('list_qq_template' => 'LPAREN
|
153
|
-
rule 'list_qq_template' => 'LPAREN
|
127
|
+
rule('list_qq_template' => 'LPAREN qq_template_or_splice* RPAREN').as 'list_qq'
|
128
|
+
rule 'list_qq_template' => 'LPAREN qq_template_or_splice+ PERIOD qq_template RPAREN'
|
154
129
|
rule 'list_qq_template' => 'GRAVE_ACCENT qq_template'
|
155
|
-
rule('vector_qq_template' => 'VECTOR_BEGIN
|
130
|
+
rule('vector_qq_template' => 'VECTOR_BEGIN qq_template_or_splice* RPAREN').as 'vector_qq'
|
156
131
|
rule('unquotation' => 'COMMA qq_template').as 'unquotation_short'
|
157
132
|
rule 'unquotation' => 'LPAREN UNQUOTE qq_template RPAREN'
|
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'
|
160
|
-
rule 'qq_template_or_splice_plus' => 'qq_template_or_splice_plus qq_template_or_splice'
|
161
|
-
rule 'qq_template_or_splice_plus' => 'qq_template_or_splice'
|
162
133
|
rule 'qq_template_or_splice' => 'qq_template'
|
163
134
|
rule 'qq_template_or_splice' => 'splicing_unquotation'
|
164
135
|
rule 'splicing_unquotation' => 'COMMA_AT_SIGN qq_template'
|
165
136
|
rule 'splicing_unquotation' => 'LPAREN UNQUOTE-SPLICING qq_template RPAREN'
|
166
|
-
rule('transformer_spec' => 'LPAREN SYNTAX-RULES LPAREN
|
167
|
-
rule('transformer_spec' => 'LPAREN SYNTAX-RULES IDENTIFIER LPAREN
|
168
|
-
rule('syntax_rule_star' => 'syntax_rule_star syntax_rule').as 'star_default'
|
169
|
-
rule('syntax_rule_star' => []).as 'star_base'
|
137
|
+
rule('transformer_spec' => 'LPAREN SYNTAX-RULES LPAREN IDENTIFIER* RPAREN syntax_rule* RPAREN').as 'transformer_syntax'
|
138
|
+
rule('transformer_spec' => 'LPAREN SYNTAX-RULES IDENTIFIER LPAREN IDENTIFIER* RPAREN syntax_rule* RPAREN')
|
170
139
|
rule('syntax_rule' => 'LPAREN pattern template RPAREN').as 'syntax_rule'
|
171
140
|
rule('pattern' => 'pattern_identifier')
|
172
141
|
rule('pattern' => 'UNDERSCORE')
|
173
|
-
rule('pattern' => 'LPAREN
|
174
|
-
rule('pattern' => 'LPAREN
|
175
|
-
rule('pattern' => 'LPAREN
|
176
|
-
rule('pattern' => 'LPAREN
|
177
|
-
rule('pattern' => 'VECTOR_BEGIN
|
178
|
-
rule('pattern' => 'VECTOR_BEGIN
|
142
|
+
rule('pattern' => 'LPAREN pattern* RPAREN')
|
143
|
+
rule('pattern' => 'LPAREN pattern+ PERIOD pattern RPAREN')
|
144
|
+
rule('pattern' => 'LPAREN pattern+ ELLIPSIS pattern* RPAREN')
|
145
|
+
rule('pattern' => 'LPAREN pattern+ ELLIPSIS pattern* PERIOD pattern RPAREN')
|
146
|
+
rule('pattern' => 'VECTOR_BEGIN pattern* RPAREN')
|
147
|
+
rule('pattern' => 'VECTOR_BEGIN pattern+ ELLIPSIS pattern* RPAREN')
|
179
148
|
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
149
|
rule('pattern_datum' => 'STRING_LIT')
|
185
150
|
rule('pattern_datum' => 'CHAR')
|
186
151
|
rule('pattern_datum' => 'BOOLEAN')
|
187
152
|
rule('pattern_datum' => 'number')
|
188
153
|
# rule('pattern_datum' => 'bytevector')
|
189
154
|
rule('template' => 'pattern_identifier')
|
190
|
-
rule('template' => 'LPAREN
|
191
|
-
rule('template' => 'LPAREN
|
192
|
-
rule('template' => 'VECTOR_BEGIN
|
155
|
+
rule('template' => 'LPAREN template_element* RPAREN')
|
156
|
+
rule('template' => 'LPAREN template_element+ PERIOD template RPAREN')
|
157
|
+
rule('template' => 'VECTOR_BEGIN template_element* RPAREN')
|
193
158
|
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
159
|
rule('template_element' => 'template')
|
199
160
|
rule('template_element' => 'template ELLIPSIS')
|
200
161
|
rule('template_datum' => 'pattern_datum')
|
201
162
|
rule('pattern_identifier' => 'IDENTIFIER')
|
202
|
-
# Ugly:
|
163
|
+
# Ugly: specialized production rule per keyword...
|
203
164
|
rule('pattern_identifier' => 'BEGIN')
|
204
165
|
rule('pattern_identifier' => 'COND')
|
205
166
|
rule('pattern_identifier' => 'DEFINE')
|
data/lib/skeem/interpreter.rb
CHANGED
@@ -8,7 +8,11 @@ require_relative './primitive/primitive_builder'
|
|
8
8
|
module Skeem
|
9
9
|
class Interpreter
|
10
10
|
include Primitive::PrimitiveBuilder
|
11
|
+
|
12
|
+
# @return [Skeem::Parser] Link to Skeem parser
|
11
13
|
attr_reader(:parser)
|
14
|
+
|
15
|
+
# @return [Skeem::Runtime] Link to runtime object (holds call stack & frames)
|
12
16
|
attr_reader(:runtime)
|
13
17
|
|
14
18
|
def initialize
|
@@ -27,11 +31,11 @@ module Skeem
|
|
27
31
|
add_standard(runtime)
|
28
32
|
end
|
29
33
|
|
30
|
-
def parse(source,
|
34
|
+
def parse(source, _mode = nil)
|
31
35
|
@parser ||= Parser.new
|
32
36
|
@ptree = parser.parse(source)
|
33
|
-
# $stderr.puts @ptree.root.inspect if
|
34
|
-
# require 'debug' unless
|
37
|
+
# $stderr.puts @ptree.root.inspect if _mode.nil?
|
38
|
+
# require 'debug' unless _mode.nil?
|
35
39
|
end
|
36
40
|
|
37
41
|
def run(source, mode = nil)
|
@@ -45,7 +49,7 @@ module Skeem
|
|
45
49
|
end
|
46
50
|
|
47
51
|
def add_standard(_runtime)
|
48
|
-
std_pathname = File.dirname(__FILE__)
|
52
|
+
std_pathname = "#{File.dirname(__FILE__)}/standard/base.skm"
|
49
53
|
load_lib(std_pathname)
|
50
54
|
end
|
51
55
|
|
@@ -234,23 +234,17 @@ module Skeem
|
|
234
234
|
if arglist.empty?
|
235
235
|
raw_result = reciprocal(raw_result)
|
236
236
|
else
|
237
|
-
# Ugly: Ruby version dependency: Rubies older than 2.4 have class Fixnum instead of Integer
|
238
|
-
int_class = (RUBY_VERSION[0..2] < '2.4') ? Fixnum : Integer
|
239
|
-
|
240
237
|
arglist.each do |elem|
|
241
238
|
elem_value = elem.value
|
242
239
|
case [raw_result.class, elem_value.class]
|
243
|
-
when [
|
240
|
+
when [Integer, Integer]
|
244
241
|
if raw_result.modulo(elem_value).zero?
|
245
242
|
raw_result /= elem_value
|
246
243
|
else
|
247
244
|
raw_result = Rational(raw_result, elem_value)
|
248
245
|
end
|
249
246
|
|
250
|
-
when [
|
251
|
-
raw_result *= reciprocal(elem_value)
|
252
|
-
|
253
|
-
when [Rational, Rational]
|
247
|
+
when [Integer, Rational], [Rational, Rational]
|
254
248
|
raw_result *= reciprocal(elem_value)
|
255
249
|
else
|
256
250
|
raw_result = raw_result.to_f
|
@@ -827,8 +821,6 @@ module Skeem
|
|
827
821
|
cloned = arg.klone
|
828
822
|
if result.kind_of?(SkmEmptyList)
|
829
823
|
result = cloned
|
830
|
-
elsif result.kind_of?(SkmEmptyList)
|
831
|
-
result = SkmPair.new(arg, SkmEmptyList.instance)
|
832
824
|
else
|
833
825
|
result.append_list(cloned)
|
834
826
|
end
|
@@ -945,7 +937,7 @@ module Skeem
|
|
945
937
|
break
|
946
938
|
end
|
947
939
|
pair = pair.cdr
|
948
|
-
break unless pair
|
940
|
+
break unless pair.kind_of?(SkmPair)
|
949
941
|
end
|
950
942
|
end
|
951
943
|
|
@@ -967,7 +959,7 @@ module Skeem
|
|
967
959
|
break
|
968
960
|
end
|
969
961
|
pair = pair.cdr
|
970
|
-
break unless pair
|
962
|
+
break unless pair.kind_of?(SkmPair)
|
971
963
|
end
|
972
964
|
end
|
973
965
|
|
@@ -1142,7 +1134,7 @@ module Skeem
|
|
1142
1134
|
# Error: assertion failed: (> 1 2)
|
1143
1135
|
msg1 = "assertion failed on line #{pos.line}, column #{pos.column}"
|
1144
1136
|
msg2 = ", with #{arg_evaluated.inspect}"
|
1145
|
-
raise StandardError,
|
1137
|
+
raise StandardError, "Error: #{msg1}#{msg2}"
|
1146
1138
|
else
|
1147
1139
|
boolean(true)
|
1148
1140
|
end
|
@@ -1165,7 +1157,7 @@ module Skeem
|
|
1165
1157
|
# Non-standard procedure reserved for internal testing/debugging purposes.
|
1166
1158
|
def create_inspect(aRuntime)
|
1167
1159
|
primitive = lambda do |_runtime, arg_evaluated|
|
1168
|
-
$stderr.puts
|
1160
|
+
$stderr.puts "INSPECT>#{arg_evaluated.inspect}"
|
1169
1161
|
Skeem::SkmUndefined.instance
|
1170
1162
|
end
|
1171
1163
|
define_primitive_proc(aRuntime, '_inspect', unary, primitive)
|
@@ -1233,7 +1225,7 @@ module Skeem
|
|
1233
1225
|
else
|
1234
1226
|
msg2 = "but got #{argument.class}"
|
1235
1227
|
end
|
1236
|
-
raise StandardError, msg1
|
1228
|
+
raise StandardError, "#{msg1} #{msg2}"
|
1237
1229
|
end
|
1238
1230
|
|
1239
1231
|
def remaining_args(arglist, aRuntime)
|
@@ -5,8 +5,13 @@ require_relative '../s_expr_nodes'
|
|
5
5
|
module Skeem
|
6
6
|
module Primitive
|
7
7
|
class PrimitiveProcedure
|
8
|
+
# @return [Skeem::SkmIdentifier] 'name' of the procedure
|
8
9
|
attr_reader(:identifier)
|
10
|
+
|
11
|
+
# @return [Skeem::Arity] number of arguments of the procedure
|
9
12
|
attr_reader(:arity)
|
13
|
+
|
14
|
+
# @return [Proc] A Ruby lambda that implements the primitive procedure
|
10
15
|
attr_reader(:code)
|
11
16
|
|
12
17
|
# param [anArity] Arity of the lambda code (ignoring the runtime object)
|
@@ -42,10 +47,11 @@ module Skeem
|
|
42
47
|
check_actual_count(actuals)
|
43
48
|
# TODO: check that next line became useless
|
44
49
|
# aProcedureCall.operands_consumed = true
|
45
|
-
result = do_call(aRuntime, actuals)
|
50
|
+
# result = do_call(aRuntime, actuals)
|
46
51
|
# $stderr.puts " Result: #{result.inspect}"
|
47
52
|
# $stderr.puts "--- End of procedure #{identifier}"
|
48
|
-
result
|
53
|
+
# result
|
54
|
+
do_call(aRuntime, actuals)
|
49
55
|
end
|
50
56
|
|
51
57
|
def skm_equal?(other)
|
@@ -146,20 +152,20 @@ module Skeem
|
|
146
152
|
|
147
153
|
def error_lambda(message_suffix)
|
148
154
|
msg1 = "Primitive procedure '#{identifier.value}'"
|
149
|
-
raise StandardError, msg1
|
155
|
+
raise StandardError, "#{msg1} #{message_suffix}"
|
150
156
|
end
|
151
157
|
|
152
158
|
def discrepancy_arity_argument_count(arity_required, count_param, delta)
|
153
159
|
msg1 = "Discrepancy in primitive procedure '#{identifier.value}'"
|
154
160
|
msg2 = "between arity (#{arity_required}) + #{delta}"
|
155
161
|
msg3 = "and parameter count of lambda #{count_param}."
|
156
|
-
raise StandardError, msg1
|
162
|
+
raise StandardError, "#{msg1} #{msg2} #{msg3}"
|
157
163
|
end
|
158
164
|
|
159
165
|
def wrong_number_arguments(required, actual)
|
160
166
|
msg1 = "Wrong number of arguments for #<Procedure #{identifier.value}>"
|
161
167
|
msg2 = "(required at least #{required}, got #{actual})"
|
162
|
-
raise StandardError, msg1
|
168
|
+
raise StandardError, "#{msg1} #{msg2}"
|
163
169
|
end
|
164
170
|
end # class
|
165
171
|
end # module
|
data/lib/skeem/runtime.rb
CHANGED
@@ -124,16 +124,14 @@ module Skeem
|
|
124
124
|
private
|
125
125
|
|
126
126
|
def normalize_key(aKey)
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
result
|
127
|
+
case aKey
|
128
|
+
when String
|
129
|
+
aKey
|
130
|
+
when SkmVariableReference
|
131
|
+
aKey.child.value
|
132
|
+
else
|
133
|
+
aKey.evaluate(self).value
|
134
|
+
end
|
137
135
|
end
|
138
136
|
end # class
|
139
137
|
end # module
|