flea 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/build.yml +30 -0
  3. data/.gitignore +3 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +30 -0
  6. data/Gemfile +5 -0
  7. data/Gemfile.lock +65 -0
  8. data/MIT-LICENSE +1 -1
  9. data/README.md +345 -0
  10. data/bin/flea +17 -15
  11. data/flea-language-spec/{README.rdoc → README.md} +2 -2
  12. data/flea-language-spec/test-cases/01-display-and-basic-literals/05-display-list-literal-using-quote.scm +1 -1
  13. data/flea-language-spec/test-cases/02-variables/05-define-with-list.scm +1 -1
  14. data/flea-language-spec/test-cases/04-quoting/01-quoting.scm +5 -0
  15. data/flea.gemspec +34 -0
  16. data/lib/flea/environment.rb +20 -18
  17. data/lib/flea/interpreter.rb +44 -44
  18. data/lib/flea/standard_library/display.scm +7 -1
  19. data/lib/flea/standard_library/null.scm +1 -1
  20. data/lib/flea/standard_library/read.scm +1 -1
  21. data/lib/flea/version.rb +5 -0
  22. data/lib/flea.rb +6 -4
  23. metadata +110 -138
  24. data/README.rdoc +0 -274
  25. data/Rakefile +0 -36
  26. data/VERSION +0 -1
  27. data/flea-language-spec/test-cases/04-comma-quoting/01-comma-quoting.scm +0 -5
  28. data/spec/flea/environment_spec.rb +0 -114
  29. data/spec/flea/interpreter_spec.rb +0 -85
  30. data/spec/flea/standard_library/addition_operator_spec.rb +0 -23
  31. data/spec/flea/standard_library/append_spec.rb +0 -17
  32. data/spec/flea/standard_library/begin_spec.rb +0 -20
  33. data/spec/flea/standard_library/car_spec.rb +0 -17
  34. data/spec/flea/standard_library/cdr_spec.rb +0 -17
  35. data/spec/flea/standard_library/cons_spec.rb +0 -25
  36. data/spec/flea/standard_library/display_spec.rb +0 -36
  37. data/spec/flea/standard_library/division_operator_spec.rb +0 -29
  38. data/spec/flea/standard_library/equality_operator_spec.rb +0 -45
  39. data/spec/flea/standard_library/gets_spec.rb +0 -23
  40. data/spec/flea/standard_library/greater_than_spec.rb +0 -29
  41. data/spec/flea/standard_library/if_spec.rb +0 -59
  42. data/spec/flea/standard_library/lambda_spec.rb +0 -70
  43. data/spec/flea/standard_library/less_than_spec.rb +0 -29
  44. data/spec/flea/standard_library/list_predicate_spec.rb +0 -25
  45. data/spec/flea/standard_library/list_spec.rb +0 -24
  46. data/spec/flea/standard_library/list_tail_spec.rb +0 -17
  47. data/spec/flea/standard_library/mutiplication_operator_spec.rb +0 -23
  48. data/spec/flea/standard_library/null_spec.rb +0 -26
  49. data/spec/flea/standard_library/quote_spec.rb +0 -20
  50. data/spec/flea/standard_library/rand_spec.rb +0 -25
  51. data/spec/flea/standard_library/read_spec.rb +0 -23
  52. data/spec/flea/standard_library/set_spec.rb +0 -23
  53. data/spec/flea/standard_library/string_to_num_spec.rb +0 -28
  54. data/spec/flea/standard_library/subtraction_operator_spec.rb +0 -24
  55. data/spec/spec_helper.rb +0 -10
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 45c4d8338ff0266e41e153d43a451cfe72225d15b1a9b0b91c02923096c10880
4
+ data.tar.gz: 2588e992c1b9b5e2d8de2e7fe7cf1336b031d1f075e01ef84f6ba86642aebeed
5
+ SHA512:
6
+ metadata.gz: 89c54c2f8cf295379fa2a30cce74d2cde2bb0d05ca5c9fd80f23ade581628db180b68a80f0f485112c75c6d85df07b7dad7c9eb9d60c6baa6d9d10657cb86f87
7
+ data.tar.gz: 8bd3f4dc4c13741143a81c4f045d926c2f5331bd96b2ae505e8415cab150527c123d0f49e2bc95a110576d74038934f932a1cd7b6ffee9eea17aa03828465c5e
@@ -0,0 +1,30 @@
1
+ name: build
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+
9
+ steps:
10
+ - uses: actions/checkout@v1
11
+
12
+ - name: Install Ruby (2.6)
13
+ uses: actions/setup-ruby@v1
14
+ with:
15
+ ruby-version: 2.6.x
16
+
17
+ - name: Setup Code Climate test-reporter
18
+ run: |
19
+ curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
20
+ chmod +x ./cc-test-reporter
21
+ ./cc-test-reporter before-build
22
+ - name: Build and test with RSpec
23
+ run: |
24
+ gem install bundler
25
+ bundle install --jobs 4 --retry 3
26
+ bundle exec rspec
27
+ - name: Publish code coverage
28
+ run: |
29
+ export GIT_BRANCH="${GITHUB_REF/refs\/heads\//}"
30
+ ./cc-test-reporter after-build --id ${{secrets.CC_TEST_REPORTER_ID}} --coverage-input-type simplecov
data/.gitignore CHANGED
@@ -1 +1,4 @@
1
1
  *.swp
2
+ .DS_Store
3
+ *.gem
4
+ coverage
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format progress
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,30 @@
1
+ Metrics/BlockLength:
2
+ IgnoredMethods: ['describe', 'context']
3
+
4
+ Style/SymbolProc:
5
+ IgnoredMethods: ['configure']
6
+
7
+ AllCops:
8
+ SuggestExtensions: false
9
+ NewCops: enable
10
+
11
+ Style/Documentation:
12
+ Enabled: false
13
+
14
+ Metrics/AbcSize:
15
+ Max: 20
16
+
17
+ Metrics/MethodLength:
18
+ Max: 15
19
+
20
+ Metrics/CyclomaticComplexity:
21
+ Max: 10
22
+
23
+ Gemspec/RequireMFA:
24
+ Enabled: false
25
+
26
+ Naming/PredicateName:
27
+ AllowedMethods: ['has_variable?']
28
+
29
+ Security/Eval:
30
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,65 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ flea (0.1.1)
5
+ sexpistol (~> 0.1.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ any-spec (0.1.0)
11
+ ast (2.4.2)
12
+ diff-lcs (1.3)
13
+ docile (1.3.5)
14
+ json (2.6.1)
15
+ parallel (1.21.0)
16
+ parser (3.1.0.0)
17
+ ast (~> 2.4.1)
18
+ rainbow (3.0.0)
19
+ regexp_parser (2.2.0)
20
+ rexml (3.2.5)
21
+ rspec (3.6.0)
22
+ rspec-core (~> 3.6.0)
23
+ rspec-expectations (~> 3.6.0)
24
+ rspec-mocks (~> 3.6.0)
25
+ rspec-core (3.6.0)
26
+ rspec-support (~> 3.6.0)
27
+ rspec-expectations (3.6.0)
28
+ diff-lcs (>= 1.2.0, < 2.0)
29
+ rspec-support (~> 3.6.0)
30
+ rspec-mocks (3.6.0)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.6.0)
33
+ rspec-support (3.6.0)
34
+ rubocop (1.24.1)
35
+ parallel (~> 1.10)
36
+ parser (>= 3.0.0.0)
37
+ rainbow (>= 2.2.2, < 4.0)
38
+ regexp_parser (>= 1.8, < 3.0)
39
+ rexml
40
+ rubocop-ast (>= 1.15.1, < 2.0)
41
+ ruby-progressbar (~> 1.7)
42
+ unicode-display_width (>= 1.4.0, < 3.0)
43
+ rubocop-ast (1.15.1)
44
+ parser (>= 3.0.1.1)
45
+ ruby-progressbar (1.11.0)
46
+ sexpistol (0.1.2)
47
+ simplecov (0.17.1)
48
+ docile (~> 1.1)
49
+ json (>= 1.8, < 3)
50
+ simplecov-html (~> 0.10.0)
51
+ simplecov-html (0.10.2)
52
+ unicode-display_width (2.1.0)
53
+
54
+ PLATFORMS
55
+ ruby
56
+
57
+ DEPENDENCIES
58
+ any-spec (~> 0.1.0)
59
+ flea!
60
+ rspec (~> 3.2)
61
+ rubocop (~> 1.24.1)
62
+ simplecov (~> 0.17.1)
63
+
64
+ BUNDLED WITH
65
+ 1.17.3
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Aaron Gough (http://thingsaaronmade.com/)
1
+ Copyright (c) 2022 Aaron Gough (http://aarongough.com/)
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md ADDED
@@ -0,0 +1,345 @@
1
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)
2
+ [![Actions Status](https://github.com/aarongough/flea/actions/workflows/build.yml/badge.svg)](https://github.com/aarongough/flea/actions/workflows/build.yml)
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/eae94ce7c694372a56cb/maintainability)](https://codeclimate.com/github/aarongough/flea/maintainability)
4
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/eae94ce7c694372a56cb/test_coverage)](https://codeclimate.com/github/aarongough/flea/test_coverage)
5
+ [![Gem Version](https://badge.fury.io/rb/flea.svg)](https://badge.fury.io/rb/flea)
6
+
7
+ # Flea
8
+
9
+ Flea is a tiny Lisp interpreter implemented in Ruby. Flea is not designed to be a production language, instead it is designed to be an example of how simple it can be to bootstrap the core of a small flexible language. Flea essentially defines an informal subset of Scheme, just enough to be fun and interesting.
10
+
11
+ ### A Quick Example:
12
+
13
+ This is the classic 'guess the number' program implemented in Flea:
14
+
15
+ ```scheme
16
+ (define number (+ (rand 9) 1))
17
+
18
+ (display "\n\nI'm thinking of a number between 1 and 10,\n")
19
+ (display "try to guess it!\n\n")
20
+
21
+ (define user-guess
22
+ (lambda ()
23
+ (display "Take a guess - ")
24
+ (define guess (string-to-num (gets)))
25
+ (if (equal? guess number)
26
+ (display "Good guess!\n")
27
+ (begin
28
+ (if (greater-than? guess number)
29
+ (display "Lower!\n")
30
+ (display "Higher!\n"))
31
+ (user-guess)))))
32
+
33
+ (user-guess)
34
+ ```
35
+
36
+ ### Installation:
37
+
38
+ For ease of use the Flea is packaged as a RubyGem. Providing you already have Ruby and RubyGems installing Flea is as easy as entering the following command in a terminal:
39
+
40
+ gem install flea
41
+
42
+ Mac OS X and most Unix/Linux distributions come with an installation of Ruby and RubyGems. If you do not have Ruby and RubyGems installed please check the [Ruby website for instructions](http://www.ruby-lang.org/en/downloads/).
43
+
44
+ ### Usage:
45
+
46
+ After Flea is installed you can run a program by typing the following on the command line:
47
+
48
+ flea /path/to/program
49
+
50
+ You can also launch Flea's interactive shell by simply calling `flea` with no arguments.
51
+
52
+ ## How it works:
53
+
54
+ Flea's core is only about 100 lines of code, and provides a simple interface that is used to build the rest of the language. Flea is highly extensible because of its foreign function interface which allows Ruby Proc objects to be defined and then executed within the context of the Flea interpreter. The entire standard library of the language is implemented using this foreign function interface. For example, here is the implementation of the multiplication operator:
55
+
56
+ ```scheme
57
+ (define *
58
+ (native_function "
59
+ Proc.new() do |arguments, interpreter|
60
+ tmp = arguments.map {|item| interpreter.evaluate(item)}
61
+ tmp.inject {|sum, n| sum * n}
62
+ end
63
+ "))
64
+ ```
65
+
66
+ ## API Documentation:
67
+
68
+ Flea comes with a small but thoughtful standard library that includes functions for:
69
+
70
+ #### Output:
71
+
72
+ `(display)` Outputs data to STDOUT:
73
+
74
+ ```scheme
75
+ (display "test")
76
+ # => test
77
+
78
+ (display (quote(1 2 3)))
79
+ # => (1 2 3)
80
+ ```
81
+
82
+ #### Input:
83
+
84
+ `(read)` Reads and parses an s-expression from STDIN:
85
+
86
+ ```scheme
87
+ (read) # user enters '(1 2 3)'
88
+ # => (1 2 3)
89
+ ```
90
+
91
+ `(gets)` Reads a string from STDIN:
92
+
93
+ ```scheme
94
+ (gets) # user enters '(1 2 3)'
95
+ # => "(1 2 3)"
96
+ ```
97
+
98
+ #### Variables:
99
+
100
+ `(define)` Sets a variable:
101
+
102
+ ```scheme
103
+ (define test 1)
104
+ (display test)
105
+ # => 1
106
+ ```
107
+
108
+ `(set!)` Re-defines an existing variable:
109
+
110
+ ```scheme
111
+ (define test 1)
112
+ (set! test 2)
113
+ (display test)
114
+ # => 2
115
+ ```
116
+
117
+ #### Numeric operations:
118
+
119
+ `(+)` Add one or more numbers:
120
+
121
+ ```scheme
122
+ (+ 1 2 3)
123
+ # => 6
124
+ ```
125
+
126
+ `(-)` Subtract one or more numbers:
127
+
128
+ ```scheme
129
+ (- 10 2 1)
130
+ # => 7
131
+ ```
132
+
133
+ `(*)` Multiply one or more numbers:
134
+
135
+ ```scheme
136
+ (* 10 2 4)
137
+ # => 80
138
+ ```
139
+
140
+ `(/)` Divide one or more numbers:
141
+
142
+ ```scheme
143
+ (/ 100 2 2)
144
+ # => 25
145
+ ```
146
+
147
+ `(greater-than?)` Returns true if it's first argument is greater than all the others, false otherwise:
148
+
149
+ ```scheme
150
+ (greater-than? 10 2 3 4)
151
+ # => #t
152
+
153
+ (greater-than? 1 2 3 4)
154
+ # => #f
155
+ ```
156
+
157
+ `(less-than?)` Returns true if it's first argument is smaller than all the others, false otherwise:
158
+
159
+ ```scheme
160
+ (less-than? 1 3 4 5)
161
+ # => #t
162
+
163
+ (less-than? 50 2 45 100)
164
+ # => #f
165
+ ```
166
+
167
+ `(equal?)` and `(=)` Return true if all their arguments are the same, false otherwise:
168
+
169
+ ```scheme
170
+ (equal? 1 1 1)
171
+ # => #t
172
+
173
+ (= 1 2 3)
174
+ # => #f
175
+ ```
176
+
177
+ #### List creation and manipulation:
178
+
179
+ `(list)` Creates a new list from it's arguments:
180
+
181
+ ```scheme
182
+ (list (+ 1 2) "test" (rand 10))
183
+ # => (3 "test" 5)
184
+ ```
185
+
186
+ `(list?)` Returns true if it's first argument is a list, false otherwise:
187
+
188
+ ```scheme
189
+ (list? (quote ()))
190
+ # => #t
191
+
192
+ (list? 1)
193
+ # => #f
194
+ ```
195
+
196
+ `(list-tail)` Returns a new list created by removing the first n elements of the provided list:
197
+
198
+ ```scheme
199
+ (define a (quote (1 2 3 4 5 6)))
200
+ (list-tail a 3)
201
+ # => (4 5 6)
202
+ ```
203
+
204
+ `(car)` Returns the first item of a list:
205
+
206
+ ```scheme
207
+ (car (quote (1 2 3)))
208
+ # => 1
209
+ ```
210
+
211
+ `(cdr)` Returns the remainder of a list:
212
+
213
+ ```scheme
214
+ (cdr (quote (1 2 3)))
215
+ # => (2 3)
216
+ ```
217
+
218
+ `(cons)` Creates a new list by using it's first argument as the CAR it's second argument as the CDR:
219
+
220
+ ```scheme
221
+ (cons (quote (1 2 3)) 3)
222
+ # => ((1 2 3) 3)
223
+
224
+ (cons 1 2)
225
+ # => (1 2)
226
+
227
+
228
+ (cons 1 (2 3 4))
229
+ # => (1 2 3 4)
230
+ ```
231
+
232
+ `(append)` Creates a new list by concatenating it's arguments, it's first argument must be a list:
233
+
234
+ ```scheme
235
+ (append (quote (1 2)) (quote (3 4)) 5)
236
+ # => (1 2 3 4 5)
237
+ ```
238
+
239
+ `(null?)` Returns true if it's first argument is null (the empty list):
240
+
241
+ ```scheme
242
+ (null? (quote ()))
243
+ # => #t
244
+
245
+ (null? (quote (1 2 3)))
246
+ # => #f
247
+
248
+ (null? 1)
249
+ # => #f
250
+ ```
251
+
252
+ #### Conditionals:
253
+
254
+ `(if)` If it's first argument is true then it will execute it's first code block, otherwise it will execute the second code block (if any):
255
+
256
+ ```scheme
257
+ (if (equal? 1 1)
258
+ (display "true")
259
+ (display "false"))
260
+ # => true
261
+
262
+ (if (equal? 2 1)
263
+ (display "true")
264
+ (display "false"))
265
+ # => false
266
+ ```
267
+
268
+ #### Function creation:
269
+
270
+ `(lambda)` Creates a new function:
271
+
272
+ ```scheme
273
+ (define adder
274
+ (lambda (a)
275
+ (+ a 10)))
276
+
277
+ (adder 5)
278
+ # => 15
279
+ ```
280
+
281
+ For more info on lambda syntax read the [R5RS Scheme specification](http://schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-7.html#%_sec_4.1.4).
282
+
283
+ ### Type conversion:
284
+
285
+ `(string-to-num)` Converts a string containing a number into a numeric literal:
286
+
287
+ ```scheme
288
+ (string-to-num "123")
289
+ # => 123
290
+ ```
291
+
292
+ #### Misc:
293
+
294
+ `(rand)` Returns a random number less than or equal to it's first argument:
295
+
296
+ ```scheme
297
+ (rand 10)
298
+ # => 1
299
+
300
+ (rand 10)
301
+ # => 6
302
+ ```
303
+
304
+ #### Foreign function interface:
305
+
306
+ `(native_function)` Takes a string representing a Ruby Proc object and returns it in a form that is able to be called like any other Flea function. The proc must take two arguments (arguments and interpreter):
307
+
308
+ ```scheme
309
+ (define test
310
+ (native_function "
311
+ Proc.new() do |arguments, interpreter|
312
+ puts "Arguments class: " + arguments.class
313
+ puts "Arguments: " + arguments.inspect
314
+ puts "Interpreter class: " + interpreter.class
315
+ puts "foo"
316
+ end
317
+ ")
318
+
319
+ (test 1 2 3 4)
320
+ # => Arguments class: Array
321
+ Arguments: [1, 2, 3, 4]
322
+ Interpreter class: Flea::Interpreter
323
+ foo
324
+ ```
325
+
326
+ ## Development and Testing:
327
+
328
+ Before doing any development work make sure you have all the development dependencies installed by running `bundle install` in the root of the project directory.
329
+
330
+ Making changes to Flea is made simpler by the presence of an extensive test suite. Tests are written in [RSpec](https://rspec.info/) and live in the `/spec` folder. To run the tests simply type `rspec` in the root of the project directory.
331
+
332
+ Flea also has an 'executable language specification' which is a series of small programs that exercise every part of the language and also assert what the output for each small program should be. The language specification is written with the use of a helper tool called [AnySpec](https://github.com/aarongough/any-spec), and the test cases can be found at `/flea-language-spec`. To run the executable language specification run the following command from the root of the project directory:
333
+
334
+ ```
335
+ bundle exec any-spec ./bin/flea flea-language-spec/flea-language-spec.yaml
336
+ ```
337
+
338
+ ---
339
+
340
+ ### Author & Credits:
341
+
342
+ Author: [Aaron Gough](mailto:aaron@aarongough.com)
343
+
344
+ Copyright © 2021 [Aaron Gough](http://thingsaaronmade.com/), released under the MIT license
345
+
data/bin/flea CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require 'stringio'
4
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'flea.rb'))
4
+ require 'bundler/setup'
5
+ require 'flea'
5
6
 
6
7
  interpreter = Flea::Interpreter.new
7
8
 
8
- if ARGV.length > 0
9
+ if ARGV.length.positive?
9
10
  interpreter.run(ARGF.read)
10
11
  exit
11
12
  end
@@ -14,20 +15,21 @@ loop do
14
15
  program = []
15
16
  indent = 0
16
17
  loop do
17
- print "> " + (" " * indent)
18
+ print "> #{' ' * indent}"
18
19
  program << gets
19
-
20
- tmp_program = program.join(" ")
21
- open_p_count = tmp_program.count("(")
22
- close_p_count = tmp_program.count(")")
23
-
20
+
21
+ tmp_program = program.join(' ')
22
+ open_p_count = tmp_program.count('(')
23
+ close_p_count = tmp_program.count(')')
24
+
24
25
  break if open_p_count == close_p_count
25
- indent += 1 if program.last.count("(") > program.last.count(")")
26
- indent -= 1 if program.last.count("(") < program.last.count(")")
26
+
27
+ indent += 1 if program.last.count('(') > program.last.count(')')
28
+ indent -= 1 if program.last.count('(') < program.last.count(')')
27
29
  end
28
- program = program.join(" ")
29
- exit if program.strip == "quit"
30
-
30
+ program = program.join(' ')
31
+ exit if program.strip == 'quit'
32
+
31
33
  old_stdout = $stdout
32
34
  buffer = StringIO.new
33
35
  $stdout = buffer
@@ -36,4 +38,4 @@ loop do
36
38
  print buffer.string
37
39
  print "\n" unless buffer.string.empty?
38
40
  puts " => #{result.inspect}"
39
- end
41
+ end
@@ -1,3 +1,3 @@
1
- = Flea Language Specifcation
1
+ # Flea Language Specifcation
2
2
 
3
- This is a small executable language specification for Flea written using {AnySpec}[https://github.com/aarongough/any-spec]. It basically serves as an integration test-suite for the language, and provides an easy way of doing test-first development of new language features.
3
+ This is a small executable language specification for Flea written using [AnySpec](https://github.com/aarongough/any-spec). It basically serves as an integration test-suite for the language, and provides an easy way of doing test-first development of new language features.
@@ -2,4 +2,4 @@
2
2
 
3
3
  ----
4
4
 
5
- assert_output "(1 Hello! #t #f)"
5
+ assert_output '(1 "Hello!" #t #f)'
@@ -3,4 +3,4 @@
3
3
 
4
4
  ----
5
5
 
6
- assert_output "(1 Hello! #t #f)"
6
+ assert_output '(1 "Hello!" #t #f)'
@@ -0,0 +1,5 @@
1
+ (display (quote (1 "Hello!" #t #f)))
2
+
3
+ ----
4
+
5
+ assert_output '(1 "Hello!" #t #f)'
data/flea.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'flea/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'flea'
9
+ spec.version = Flea::VERSION
10
+ spec.authors = ['Aaron Gough']
11
+ spec.email = ['aaron@aarongough.com']
12
+
13
+ spec.summary = 'A tiny but flexible Lisp interpreter written in Ruby'
14
+ spec.description = 'Flea is an extremely simple, but extremely extensible Lisp interpreter written in Ruby.'
15
+ spec.homepage = 'https://github.com/aarongough/flea'
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+
22
+ spec.bindir = 'exe'
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.add_dependency 'sexpistol', '~> 0.1.2'
27
+
28
+ spec.required_ruby_version = '>= 2.5.0'
29
+
30
+ spec.add_development_dependency 'any-spec', '~> 0.1.0'
31
+ spec.add_development_dependency 'rspec', '~> 3.2'
32
+ spec.add_development_dependency 'rubocop', '~> 1.24.1'
33
+ spec.add_development_dependency 'simplecov', '~> 0.17.1'
34
+ end
@@ -1,38 +1,40 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Flea
2
4
  class Environment
3
-
4
- attr_accessor :parent
5
-
5
+ attr_accessor :parent, :table
6
+
6
7
  def initialize(parent = nil)
7
8
  @parent = parent
8
9
  @table = {}
9
10
  add_globals if @parent.nil?
10
11
  end
11
-
12
+
12
13
  def has_variable?(name)
13
- return true if @table.has_key?(name)
14
+ return true if @table.key?(name)
14
15
  return false if @parent.nil?
15
- return @parent.has_variable?(name)
16
+
17
+ @parent.has_variable?(name)
16
18
  end
17
-
19
+
18
20
  def find(name)
19
- return @table[name] if @table.has_key?(name)
21
+ return @table[name] if @table.key?(name)
20
22
  return nil if @parent.nil?
21
- return @parent.find(name)
23
+
24
+ @parent.find(name)
22
25
  end
23
-
26
+
24
27
  def define(name, value)
25
28
  @table[name] = value
26
29
  end
27
-
30
+
28
31
  private
29
-
32
+
30
33
  def add_globals
31
- @table.merge!({
32
- :"#t" => true,
33
- :"#f" => false
34
- })
34
+ @table.merge!(
35
+ '#t': true,
36
+ '#f': false
37
+ )
35
38
  end
36
-
37
39
  end
38
- end
40
+ end