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