skeem 0.2.15 → 0.2.19
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 +26 -0
- data/Gemfile +2 -0
- data/README.md +3 -2
- data/Rakefile +2 -0
- data/appveyor.yml +3 -4
- data/bin/skeem +15 -15
- data/lib/skeem/datum_dsl.rb +40 -30
- data/lib/skeem/element_visitor.rb +5 -2
- data/lib/skeem/grammar.rb +77 -54
- data/lib/skeem/interpreter.rb +9 -7
- data/lib/skeem/parser.rb +6 -4
- data/lib/skeem/primitive/primitive_builder.rb +130 -122
- data/lib/skeem/primitive/primitive_procedure.rb +23 -25
- data/lib/skeem/runtime.rb +17 -15
- data/lib/skeem/s_expr_builder.rb +39 -147
- 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/tokenizer.rb +40 -30
- data/lib/skeem/version.rb +3 -1
- data/lib/skeem.rb +2 -0
- data/skeem.gemspec +7 -5
- 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 +76 -46
- data/spec/skeem/lambda_spec.rb +13 -11
- data/spec/skeem/parser_spec.rb +23 -19
- data/spec/skeem/primitive/primitive_builder_spec.rb +55 -46
- 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 +13 -9
data/.travis.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
language: ruby
|
2
|
+
dist: trusty
|
3
|
+
|
4
|
+
before_install:
|
5
|
+
- gem update --system
|
6
|
+
- gem install bundler
|
7
|
+
|
8
|
+
script:
|
9
|
+
- bundle exec rake
|
10
|
+
|
11
|
+
rvm:
|
12
|
+
- 2.6.3
|
13
|
+
- 2.5.5
|
14
|
+
- 2.4.6
|
15
|
+
- 2.3.8
|
16
|
+
- jruby-9.1.9.0
|
17
|
+
|
18
|
+
matrix:
|
19
|
+
allow_failures:
|
20
|
+
- rvm: ruby-head
|
21
|
+
- rvm: jruby-head
|
22
|
+
|
23
|
+
|
24
|
+
# whitelist
|
25
|
+
branches:
|
26
|
+
only:
|
27
|
+
- master
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
## [0.2.19] - 2021-08-30
|
2
|
+
- Grammar refactoring: use ?, * and + modifiers in Rley 0.8.03 rules
|
3
|
+
|
4
|
+
### Changed
|
5
|
+
- File `grammar.rb`: Remove redundant rules after introduction og ?, * and + modifiers
|
6
|
+
- Class `SkmBuilder`: Removal of useless methods after removal of their rule counterpart
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
## [0.2.18] - 2021-08-29
|
11
|
+
- Minor refactoring for Rley 0.8.03
|
12
|
+
- Code restyling to please rubocop 1.19.1.
|
13
|
+
|
14
|
+
### Changed
|
15
|
+
- File `.rubocop.yml` updated with newer Rubocop cops
|
16
|
+
- File `grammar.rb`: Calling `Rley::grammar_builder`, replace `LET*` token by `LET_STAR`
|
17
|
+
- Other files changed to get rid of Rubocop offences
|
18
|
+
|
19
|
+
## [0.2.17] - 2020-05-09
|
20
|
+
- Updated `.rubocop.yml` file.
|
21
|
+
- Code restyling to please rubocop 0.8.0.
|
22
|
+
|
23
|
+
## [0.2.16] - 2019-08-18
|
24
|
+
- Code refactoring to use string frozen magic comments (as a consequence, srl_ruby runs only on Rubies 2.3 or newer).
|
25
|
+
- Code restyling to please rubocop 0.7.40.
|
26
|
+
|
1
27
|
## [0.2.15] - 2019-07-02
|
2
28
|
- Added a basic command-line and console interface for Skeem interpreter.
|
3
29
|
- Added procedures: `display!`, `newline`, `make-list`
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -32,7 +32,8 @@ If you're not familiar to Scheme, the section [About Scheme](#about-scheme) cont
|
|
32
32
|
|
33
33
|
## Usage
|
34
34
|
Once the gem is installed, the `skeem` executable can be used.
|
35
|
-
It allows to run the interpreter from the command line.
|
35
|
+
It allows to run the interpreter from a REPL console or from the command line.
|
36
|
+
Another way to interact with the Skeem interpreter is to embed it in your Ruby code.
|
36
37
|
|
37
38
|
### Launching a REPL session
|
38
39
|
To start a REPL (Read-Eval-Print-Loop) session, just type:
|
@@ -42,7 +43,7 @@ To start a REPL (Read-Eval-Print-Loop) session, just type:
|
|
42
43
|
|
43
44
|
Skeem displays a greeting, a prompt and then waits for your input:
|
44
45
|
```
|
45
|
-
Welcome to Skeem 0.2.
|
46
|
+
Welcome to Skeem 0.2.16.
|
46
47
|
>
|
47
48
|
```
|
48
49
|
|
data/Rakefile
CHANGED
data/appveyor.yml
CHANGED
@@ -1,17 +1,16 @@
|
|
1
1
|
version: '{build}'
|
2
|
-
max_jobs:
|
2
|
+
max_jobs: 5
|
3
3
|
environment:
|
4
4
|
matrix:
|
5
|
+
- Ruby_version: 26-x64
|
5
6
|
- Ruby_version: 25-x64
|
6
7
|
- Ruby_version: 24-x64
|
7
8
|
- Ruby_version: 23-x64
|
9
|
+
- Ruby_version: 26
|
8
10
|
- Ruby_version: 25
|
9
11
|
- Ruby_version: 24
|
10
12
|
- Ruby_version: 23
|
11
13
|
|
12
|
-
# These are failing
|
13
|
-
# - Ruby_version: 26
|
14
|
-
# - Ruby_version: 26-x64
|
15
14
|
|
16
15
|
install:
|
17
16
|
- set PATH=C:\Ruby%Ruby_version%\bin;%PATH%
|
data/bin/skeem
CHANGED
@@ -1,20 +1,22 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'skeem'
|
4
5
|
|
5
6
|
class SkeemREPL
|
6
7
|
attr_reader :interpreter
|
7
8
|
|
8
|
-
def initialize
|
9
|
+
def initialize
|
9
10
|
@interpreter = Skeem::Interpreter.new
|
10
11
|
end
|
11
12
|
|
12
13
|
def run_session
|
13
|
-
puts "Welcome to Skeem #{Skeem::VERSION}."
|
14
|
+
puts "Welcome to Skeem #{Skeem::VERSION}."
|
14
15
|
loop do
|
15
16
|
print '> '
|
16
17
|
input = gets.chomp.strip
|
17
|
-
break if
|
18
|
+
break if %w[(quit) (exit)].include?(input)
|
19
|
+
|
18
20
|
process_input(input)
|
19
21
|
end
|
20
22
|
end
|
@@ -22,15 +24,13 @@ class SkeemREPL
|
|
22
24
|
def run_file(aFilename)
|
23
25
|
if File.exist?(aFilename)
|
24
26
|
valid_fname = aFilename
|
25
|
-
|
26
|
-
if File.
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
valid_fname = nil
|
33
|
-
end
|
27
|
+
elsif File.extname(aFilename).empty? # Retry by adding extension...
|
28
|
+
if File.exist?("#{aFilename}.skm")
|
29
|
+
valid_fname = "#{aFilename}.skm"
|
30
|
+
elsif File.exist?("#{aFilename}.scm")
|
31
|
+
valid_fname = "#{aFilename}.scm"
|
32
|
+
else
|
33
|
+
valid_fname = nil
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -43,8 +43,8 @@ class SkeemREPL
|
|
43
43
|
def process_input(input)
|
44
44
|
begin
|
45
45
|
ptree = interpreter.parse(input)
|
46
|
-
rescue StandardError =>
|
47
|
-
$stderr.puts
|
46
|
+
rescue StandardError => e
|
47
|
+
$stderr.puts e.message
|
48
48
|
return
|
49
49
|
end
|
50
50
|
|
@@ -69,4 +69,4 @@ if ARGV.empty?
|
|
69
69
|
djinn.run_session
|
70
70
|
else
|
71
71
|
djinn.run_file(ARGV[0])
|
72
|
-
end
|
72
|
+
end
|
data/lib/skeem/datum_dsl.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'skm_simple_datum'
|
2
4
|
require_relative 'skm_compound_datum'
|
3
5
|
require_relative 'skm_pair'
|
@@ -9,7 +11,7 @@ module Skeem
|
|
9
11
|
def boolean(aBoolean)
|
10
12
|
return aBoolean if aBoolean.kind_of?(SkmBoolean)
|
11
13
|
|
12
|
-
|
14
|
+
case aBoolean
|
13
15
|
when TrueClass, FalseClass
|
14
16
|
SkmBoolean.create(aBoolean)
|
15
17
|
when /^#t(?:rue)?|true$/
|
@@ -24,7 +26,7 @@ module Skeem
|
|
24
26
|
def integer(aLiteral)
|
25
27
|
return aLiteral if aLiteral.kind_of?(SkmInteger)
|
26
28
|
|
27
|
-
|
29
|
+
case aLiteral
|
28
30
|
when Integer
|
29
31
|
SkmInteger.create(aLiteral)
|
30
32
|
when /^[+-]?\d+$/
|
@@ -37,7 +39,7 @@ module Skeem
|
|
37
39
|
def rational(aLiteral)
|
38
40
|
return aLiteral if aLiteral.kind_of?(SkmRational)
|
39
41
|
|
40
|
-
|
42
|
+
case aLiteral
|
41
43
|
when Rational
|
42
44
|
SkmRational.create(aLiteral)
|
43
45
|
when /^[+-]?\d+\/\d+$/
|
@@ -50,7 +52,7 @@ module Skeem
|
|
50
52
|
def real(aLiteral)
|
51
53
|
return aLiteral if aLiteral.kind_of?(SkmReal)
|
52
54
|
|
53
|
-
|
55
|
+
case aLiteral
|
54
56
|
when Numeric
|
55
57
|
SkmReal.create(aLiteral)
|
56
58
|
when /^[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?$/
|
@@ -63,7 +65,7 @@ module Skeem
|
|
63
65
|
def char(aLiteral)
|
64
66
|
return aLiteral if aLiteral.kind_of?(SkmChar)
|
65
67
|
|
66
|
-
|
68
|
+
case aLiteral
|
67
69
|
when Numeric
|
68
70
|
SkmChar.create_from_int(aLiteral)
|
69
71
|
when String
|
@@ -80,7 +82,7 @@ module Skeem
|
|
80
82
|
def string(aLiteral)
|
81
83
|
return aLiteral if aLiteral.kind_of?(SkmString)
|
82
84
|
|
83
|
-
|
85
|
+
case aLiteral
|
84
86
|
when String
|
85
87
|
SkmString.create(aLiteral)
|
86
88
|
when SkmIdentifier
|
@@ -93,7 +95,7 @@ module Skeem
|
|
93
95
|
def identifier(aLiteral)
|
94
96
|
return aLiteral if aLiteral.kind_of?(SkmIdentifier)
|
95
97
|
|
96
|
-
|
98
|
+
case aLiteral
|
97
99
|
when String
|
98
100
|
SkmIdentifier.create(aLiteral)
|
99
101
|
when SkmString
|
@@ -106,7 +108,7 @@ module Skeem
|
|
106
108
|
alias symbol identifier
|
107
109
|
|
108
110
|
def list(aLiteral)
|
109
|
-
|
111
|
+
case aLiteral
|
110
112
|
when Array
|
111
113
|
SkmPair.create_from_a(to_datum(aLiteral))
|
112
114
|
when SkmPair
|
@@ -114,12 +116,10 @@ module Skeem
|
|
114
116
|
else
|
115
117
|
SkmPair.new(to_datum(aLiteral), SkmEmptyList.instance)
|
116
118
|
end
|
117
|
-
|
118
|
-
result
|
119
119
|
end
|
120
120
|
|
121
121
|
def vector(aLiteral)
|
122
|
-
|
122
|
+
case aLiteral
|
123
123
|
when Array
|
124
124
|
SkmVector.new(to_datum(aLiteral))
|
125
125
|
when SkmVector
|
@@ -127,8 +127,6 @@ module Skeem
|
|
127
127
|
else
|
128
128
|
SkmVector.new([to_datum(aLiteral)])
|
129
129
|
end
|
130
|
-
|
131
|
-
result
|
132
130
|
end
|
133
131
|
|
134
132
|
# Conversion from Ruby object value to Skeem datum
|
@@ -137,7 +135,7 @@ module Skeem
|
|
137
135
|
return vector(aLiteral.members) if aLiteral.kind_of?(SkmVector)
|
138
136
|
return aLiteral if aLiteral.kind_of?(Primitive::PrimitiveProcedure)
|
139
137
|
|
140
|
-
|
138
|
+
case aLiteral
|
141
139
|
when Array
|
142
140
|
aLiteral.map { |elem| to_datum(elem) }
|
143
141
|
when Integer
|
@@ -150,33 +148,45 @@ module Skeem
|
|
150
148
|
SkmBoolean.create(aLiteral)
|
151
149
|
when String
|
152
150
|
parse_literal(aLiteral)
|
153
|
-
when SkmPair
|
151
|
+
when SkmPair # Special case: not a PORO literal
|
154
152
|
# One assumes that a Skeem list contains only Skeem datum objects
|
155
153
|
SkmPair.create_from_a(aLiteral.to_a)
|
156
154
|
when SkmUndefined
|
157
155
|
aLiteral
|
158
156
|
else
|
159
157
|
raise StandardError, aLiteral.inspect
|
160
|
-
|
158
|
+
end
|
161
159
|
end
|
162
160
|
|
163
161
|
private
|
164
162
|
|
165
163
|
def parse_literal(aLiteral)
|
166
|
-
if aLiteral =~ /^#t(?:rue)?|true$/
|
167
|
-
boolean(aLiteral)
|
168
|
-
elsif aLiteral =~ /^#f(?:alse)?|false$/
|
169
|
-
boolean(aLiteral)
|
170
|
-
elsif aLiteral =~ /^[+-]?\d+\/\d+$/
|
171
|
-
rational(aLiteral)
|
172
|
-
elsif aLiteral =~ /^[+-]?\d+$/
|
173
|
-
integer(aLiteral)
|
174
|
-
elsif aLiteral =~ /^[+-]?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?$/
|
175
|
-
real(aLiteral)
|
176
|
-
else
|
177
|
-
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)
|
178
189
|
end
|
179
190
|
end
|
180
|
-
|
181
191
|
end # module
|
182
|
-
end # module
|
192
|
+
end # module
|
@@ -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,7 +35,8 @@ 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'
|
36
|
-
rule('definition' => '
|
38
|
+
rule('definition' => 'syntax_definition')
|
39
|
+
rule('definition' => 'LPAREN BEGIN definition* RPAREN').as 'definitions_within_begin'
|
37
40
|
rule('expression' => 'IDENTIFIER').as 'variable_reference'
|
38
41
|
rule 'expression' => 'literal'
|
39
42
|
rule 'expression' => 'procedure_call'
|
@@ -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'
|
@@ -59,99 +63,118 @@ module Skeem
|
|
59
63
|
rule 'simple_datum' => 'symbol'
|
60
64
|
rule 'compound_datum' => 'list'
|
61
65
|
rule 'compound_datum' => 'vector'
|
62
|
-
rule('list' => 'LPAREN
|
66
|
+
rule('list' => 'LPAREN datum* RPAREN').as 'list'
|
63
67
|
rule('list' => 'LPAREN datum_plus PERIOD datum RPAREN').as 'dotted_list'
|
64
|
-
rule('vector' => 'VECTOR_BEGIN
|
68
|
+
rule('vector' => 'VECTOR_BEGIN datum* 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 'datum_star'
|
68
|
-
rule('datum_star' => []).as 'no_datum_yet'
|
69
71
|
rule 'symbol' => 'IDENTIFIER'
|
70
72
|
rule('procedure_call' => 'LPAREN operator RPAREN').as 'proc_call_nullary'
|
71
|
-
rule('procedure_call' => 'LPAREN operator
|
72
|
-
rule('operand_plus' => 'operand_plus operand').as 'multiple_operands'
|
73
|
-
rule('operand_plus' => 'operand').as 'last_operand'
|
73
|
+
rule('procedure_call' => 'LPAREN operator operand+ RPAREN').as 'proc_call_args'
|
74
74
|
rule 'operator' => 'expression'
|
75
75
|
rule 'operand' => 'expression'
|
76
|
-
rule('def_formals' => '
|
77
|
-
rule('def_formals' => '
|
76
|
+
rule('def_formals' => 'IDENTIFIER*').as 'def_formals'
|
77
|
+
rule('def_formals' => 'IDENTIFIER* PERIOD IDENTIFIER').as 'pair_formals'
|
78
78
|
rule('lambda_expression' => 'LPAREN LAMBDA formals body RPAREN').as 'lambda_expression'
|
79
|
-
rule('formals' => 'LPAREN
|
79
|
+
rule('formals' => 'LPAREN IDENTIFIER* RPAREN').as 'fixed_arity_formals'
|
80
80
|
rule('formals' => 'IDENTIFIER').as 'variadic_formals'
|
81
|
-
rule('formals' => 'LPAREN
|
82
|
-
rule('
|
83
|
-
rule('
|
84
|
-
rule('
|
85
|
-
rule('
|
86
|
-
rule('body' => 'definition_star sequence').as 'body'
|
87
|
-
rule('definition_star' => 'definition_star definition').as 'definition_star'
|
88
|
-
rule('definition_star' => []).as 'no_definition_yet'
|
89
|
-
rule('sequence' => 'command_star expression').as 'sequence'
|
90
|
-
rule('command_star' => 'command_star command').as 'multiple_commands'
|
91
|
-
rule('command_star' => []).as 'no_command_yet'
|
92
|
-
rule('conditional' => 'LPAREN IF test consequent alternate RPAREN').as 'conditional'
|
81
|
+
rule('formals' => 'LPAREN IDENTIFIER+ PERIOD IDENTIFIER RPAREN').as 'dotted_formals'
|
82
|
+
rule('syntax_definition' => 'LPAREN DEFINE-SYNTAX keyword transformer_spec RPAREN').as 'syntax_definition'
|
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'
|
93
86
|
rule 'test' => 'expression'
|
94
87
|
rule 'consequent' => 'expression'
|
95
|
-
rule 'alternate' => 'expression'
|
96
|
-
rule 'alternate' => []
|
97
88
|
rule 'number' => 'INTEGER'
|
98
89
|
rule 'number' => 'RATIONAL'
|
99
90
|
rule 'number' => 'REAL'
|
100
91
|
rule('assignment' => 'LPAREN SET! IDENTIFIER expression RPAREN').as 'assignment'
|
101
|
-
rule('derived_expression' => 'LPAREN COND
|
102
|
-
rule('derived_expression' => 'LPAREN COND
|
103
|
-
rule('derived_expression' => 'LPAREN LET LPAREN
|
104
|
-
|
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'
|
95
|
+
# TODO: implement "named let"
|
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'
|
105
98
|
|
106
|
-
# As the R7RS grammar is too restrictive,
|
99
|
+
# As the R7RS grammar is too restrictive,
|
107
100
|
# the next rule was made more general than its standard counterpart
|
108
101
|
rule('derived_expression' => 'LPAREN BEGIN body RPAREN').as 'begin_expression'
|
109
102
|
do_syntax = <<-END_SYNTAX
|
110
|
-
LPAREN DO LPAREN
|
103
|
+
LPAREN DO LPAREN iteration_spec* RPAREN
|
111
104
|
LPAREN test do_result RPAREN
|
112
105
|
command_star RPAREN
|
113
106
|
END_SYNTAX
|
114
107
|
rule('derived_expression' => do_syntax).as 'do_expression'
|
115
108
|
rule 'derived_expression' => 'quasiquotation'
|
116
|
-
rule('cond_clause_plus' => 'cond_clause_plus cond_clause').as 'multiple_cond_clauses'
|
117
|
-
rule('cond_clause_plus' => 'cond_clause').as 'last_cond_clauses'
|
118
|
-
rule('cond_clause_star' => 'cond_clause_star cond_clause').as 'cond_clauses_star'
|
119
|
-
rule('cond_clause_star' => []).as 'last_cond_clauses_star'
|
120
109
|
rule('cond_clause' => 'LPAREN test sequence RPAREN').as 'cond_clause'
|
121
110
|
rule('cond_clause' => 'LPAREN test RPAREN')
|
122
111
|
rule('cond_clause' => 'LPAREN test ARROW recipient RPAREN').as 'cond_arrow_clause'
|
123
112
|
rule('recipient' => 'expression')
|
124
113
|
rule('quasiquotation' => 'LPAREN QUASIQUOTE qq_template RPAREN').as 'quasiquotation'
|
125
114
|
rule('quasiquotation' => 'GRAVE_ACCENT qq_template').as 'quasiquotation_short'
|
126
|
-
rule('binding_spec_star' => 'binding_spec_star binding_spec').as 'multiple_binding_specs'
|
127
|
-
rule('binding_spec_star' => []).as 'no_binding_spec_yet'
|
128
115
|
rule('binding_spec' => 'LPAREN IDENTIFIER expression RPAREN').as 'binding_spec'
|
129
|
-
rule('iteration_spec_star' => 'iteration_spec_star iteration_spec').as 'multiple_iter_specs'
|
130
|
-
rule('iteration_spec_star' => []).as 'no_iter_spec_yet'
|
131
116
|
rule('iteration_spec' => 'LPAREN IDENTIFIER init step RPAREN').as 'iteration_spec_long'
|
132
117
|
rule('iteration_spec' => 'LPAREN IDENTIFIER init RPAREN').as 'iteration_spec_short'
|
133
118
|
rule('init' => 'expression')
|
134
119
|
rule('step' => 'expression')
|
135
|
-
rule 'do_result' => 'sequence'
|
136
|
-
rule('
|
120
|
+
rule 'do_result' => 'sequence?'
|
121
|
+
rule('keyword' => 'IDENTIFIER')
|
122
|
+
rule('includer' => 'LPAREN INCLUDE STRING_LIT+ RPAREN').as 'include'
|
137
123
|
rule 'qq_template' => 'simple_datum'
|
138
124
|
rule 'qq_template' => 'list_qq_template'
|
139
125
|
rule 'qq_template' => 'vector_qq_template'
|
140
126
|
rule 'qq_template' => 'unquotation'
|
141
|
-
rule('list_qq_template' => 'LPAREN
|
142
|
-
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'
|
143
129
|
rule 'list_qq_template' => 'GRAVE_ACCENT qq_template'
|
144
|
-
rule('vector_qq_template' => 'VECTOR_BEGIN
|
130
|
+
rule('vector_qq_template' => 'VECTOR_BEGIN qq_template_or_splice* RPAREN').as 'vector_qq'
|
145
131
|
rule('unquotation' => 'COMMA qq_template').as 'unquotation_short'
|
146
132
|
rule 'unquotation' => 'LPAREN UNQUOTE qq_template RPAREN'
|
147
|
-
rule('qq_template_or_splice_star' => 'qq_template_or_splice_star qq_template_or_splice').as 'multiple_template_splice'
|
148
|
-
rule('qq_template_or_splice_star' => []).as 'no_template_splice_yet'
|
149
|
-
rule 'qq_template_or_splice_plus' => 'qq_template_or_splice_plus qq_template_or_splice'
|
150
|
-
rule 'qq_template_or_splice_plus' => 'qq_template_or_splice'
|
151
133
|
rule 'qq_template_or_splice' => 'qq_template'
|
152
134
|
rule 'qq_template_or_splice' => 'splicing_unquotation'
|
153
135
|
rule 'splicing_unquotation' => 'COMMA_AT_SIGN qq_template'
|
154
136
|
rule 'splicing_unquotation' => 'LPAREN UNQUOTE-SPLICING qq_template RPAREN'
|
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')
|
139
|
+
rule('syntax_rule' => 'LPAREN pattern template RPAREN').as 'syntax_rule'
|
140
|
+
rule('pattern' => 'pattern_identifier')
|
141
|
+
rule('pattern' => 'UNDERSCORE')
|
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')
|
148
|
+
rule('pattern' => 'pattern_datum')
|
149
|
+
rule('pattern_datum' => 'STRING_LIT')
|
150
|
+
rule('pattern_datum' => 'CHAR')
|
151
|
+
rule('pattern_datum' => 'BOOLEAN')
|
152
|
+
rule('pattern_datum' => 'number')
|
153
|
+
# rule('pattern_datum' => 'bytevector')
|
154
|
+
rule('template' => 'pattern_identifier')
|
155
|
+
rule('template' => 'LPAREN template_element* RPAREN')
|
156
|
+
rule('template' => 'LPAREN template_element+ PERIOD template RPAREN')
|
157
|
+
rule('template' => 'VECTOR_BEGIN template_element* RPAREN')
|
158
|
+
rule('template' => 'template_datum')
|
159
|
+
rule('template_element' => 'template')
|
160
|
+
rule('template_element' => 'template ELLIPSIS')
|
161
|
+
rule('template_datum' => 'pattern_datum')
|
162
|
+
rule('pattern_identifier' => 'IDENTIFIER')
|
163
|
+
# Ugly: specialized production rule per keyword...
|
164
|
+
rule('pattern_identifier' => 'BEGIN')
|
165
|
+
rule('pattern_identifier' => 'COND')
|
166
|
+
rule('pattern_identifier' => 'DEFINE')
|
167
|
+
rule('pattern_identifier' => 'ELSE')
|
168
|
+
rule('pattern_identifier' => 'IF')
|
169
|
+
rule('pattern_identifier' => 'INCLUDE')
|
170
|
+
rule('pattern_identifier' => 'LAMBDA')
|
171
|
+
rule('pattern_identifier' => 'LET')
|
172
|
+
rule('pattern_identifier' => 'LET*')
|
173
|
+
rule('pattern_identifier' => 'QUOTE')
|
174
|
+
rule('pattern_identifier' => 'QUASIQUOTE')
|
175
|
+
rule('pattern_identifier' => 'SET!')
|
176
|
+
rule('pattern_identifier' => 'UNQUOTE')
|
177
|
+
rule('pattern_identifier' => 'UNQUOTE-SPLICING')
|
155
178
|
end
|
156
179
|
|
157
180
|
# And now build the grammar and make it accessible via a global constant
|