lasp 0.10.1 → 0.11.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 31657ba16b8344004fdeedb166f0be8c69d56529
4
- data.tar.gz: fb32904a4b52419ccbbb7f8d38d931673e9f6df5
3
+ metadata.gz: 239d33a36efb77e46301fa1f4f5eab3355d95371
4
+ data.tar.gz: 2b63d5918420dd74b0e4e73e9b799eed3ab33113
5
5
  SHA512:
6
- metadata.gz: 9eb7709cc5b98b0bea98a8c908c630e68d1ac78a1678b12e9e195021cdcf270d07a25c4bd46103d8142484dc154a572342579132896d7ae211c49d0680473f9e
7
- data.tar.gz: b603eb61bd7aa5d9fdaaf3a74a5ca67383040dc5e958953a5488b16d7fc4c5a3fec7790ffe4e9a5bb1e2b8109272a32d65d16a056954eb9408cd80a2e9f1772a
6
+ metadata.gz: 74d78665c4fa130cb7a583c4cce512bdce06db31086f4ad889a0ef0015d60b3a84892e530236f7f21937f4663e5e6e1c5f6383f5d9af6baa6871974524074d97
7
+ data.tar.gz: 1a7daa286ff20db4c8b3008525c1b10edff6c61a4848f5bb2c04b97ad58cef832bfb72961765c422a761cdae26371c297e1a47d6fc1d307e2e2c943add69e1ea
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Läsp changelog
2
2
 
3
+ ## v0.11.0 - 2016-03-05
4
+
5
+ ### Added
6
+
7
+ - Allow `require` to accept a second argument, when it is truthy it uses a path
8
+ relative to the file that called `require`.
9
+ - Allow `_` to be used several times in parameter lists to ignore parameters
10
+ - Additions to standard library
11
+ - `and`
12
+ - `or`
13
+
14
+ ### Changed
15
+
16
+ - `require` now uses a static paths by default.
17
+ - The `.` function has been renamed to `send`, the `.` can now instead be used
18
+ as a prefix to call Ruby methods, what previously looked like this: `(. obj method)`
19
+ now looks like this `(.method obj)`. This is equivalent to `(send :method obj)`.
20
+
21
+ ### Fixed
22
+
23
+ - Relative paths in `require` was completely broken before this.
24
+ - `empty?` no longer returns `true` for lists with a `nil` value at the first position.
25
+
26
+
3
27
  ## v0.10.1 - 2016-02-22
4
28
 
5
29
  ### Fixed
data/DOCUMENTATION.md CHANGED
@@ -40,7 +40,7 @@ create a local binding, use [let](#let) instead.
40
40
 
41
41
  Creates a function.
42
42
 
43
- Parameters `(parameters body)`
43
+ Parameters `(parameters body)`:
44
44
 
45
45
  1. A list of parameters that the function shall accept, e.g. `(arg1 arg2)`, `(one two & others)`, `(& args)`
46
46
  2. The body of the function, the declared parameters will be available in here.
@@ -49,11 +49,12 @@ Parameters `(parameters body)`
49
49
  ; This creates a function object, it can be read as "a function of x".
50
50
  (fn (x) (+ x 2)) ; => #<Fn (x)>
51
51
 
52
- ; Functions are called when placed as the first item in a form:
52
+ ; Functions are called when placed as the first element in a form:
53
53
  ((fn (x) (+ x 2)) 40) ; => 42
54
54
  ```
55
55
 
56
- Most of the time, you'll want to define a function before using it (see [defn](#defn)):
56
+ Most of the time, you'll want to define a function before using it (see
57
+ [defn](#defn) for a nicer syntax for doing this):
57
58
 
58
59
  ```clojure
59
60
  (def plus-two (fn (x) (+ x 2)))
@@ -67,6 +68,8 @@ Functions will enforce that the correct number of arguments is passed to them:
67
68
  (plus-two 40 41) ; !> Lasp::ArgumentError: wrong number of arguments (2 for 1)
68
69
  ```
69
70
 
71
+ #### Variadic parameter lists
72
+
70
73
  Functions can also accept any number of extra arguments as a list:
71
74
 
72
75
  ```clojure
@@ -84,6 +87,16 @@ Functions can also accept any number of extra arguments as a list:
84
87
  (show-args) ; !> Lasp::ArgumentError: wrong number of arguments (0 for 1+)
85
88
  ```
86
89
 
90
+ #### Ignoring parameters
91
+
92
+ Normally you get an error from naming 2 parameters the same, but if you want to
93
+ ignore parameters, the `_` is allowed to be used several times.
94
+
95
+ ```clojure
96
+ (def ignore-2 (fn (nope nope) (println "lalalala"))) ; !> Lasp::SyntaxError
97
+ (def ignore-2 (fn (_ _) (println "lalalala"))) ; => #<Fn (_ _)>
98
+ ```
99
+
87
100
 
88
101
  ### do
89
102
 
@@ -181,7 +194,8 @@ Except for the order of evaluation, macros behave just like functions and can
181
194
  accept rest-arguments etc. the same way. Just like functions, you mostly want
182
195
  to define them before you use them, see [defm](#defm).
183
196
 
184
- **It is important to quote things that you do not want evaluated until after the macro has returned.**
197
+ **It is important to quote things that you do not want evaluated until after
198
+ the macro has returned.**
185
199
 
186
200
  ```clojure
187
201
  ; Note that we want `if` to be evaluated after the macro has returned, so we have to quote it.
@@ -193,7 +207,25 @@ to define them before you use them, see [defm](#defm).
193
207
  (reverse-if true "yes" "no") ; => "no"
194
208
  ```
195
209
 
196
- To debug macros and see what they expand to without trying to evaluate the result, see [macroexpand](#macroexpand).
210
+ To debug macros and see what they expand to without trying to evaluate the
211
+ result, see [macroexpand](#macroexpand).
212
+
213
+
214
+ ### require
215
+
216
+ Loads and runs a Läsp file. Paths are relative to the folder where the `lasp`
217
+ command was invoked, or, if a second truthy parameter is passed, to the file
218
+ where `require` is called.
219
+
220
+ ```clojure
221
+ (require "lasp_file.lasp")
222
+ (require "dir/lasp_file.lasp")
223
+ (require "../lasp_file.lasp")
224
+
225
+ ; Pass a truthy second parameter to use relative paths:
226
+ (require "lasp_file.lasp" true)
227
+ (require "lasp_file.lasp" :relative)
228
+ ```
197
229
 
198
230
 
199
231
  ## Core library
@@ -469,18 +501,18 @@ Applies a function to a list of arguments as if they were passed in directly.
469
501
  ```
470
502
 
471
503
 
472
- ### .
504
+ ### send
473
505
 
474
- Interoperability operator - calls a Ruby method.
506
+ Calls a Ruby method on an object.
475
507
 
476
- Parameters `(object message & args)`:
508
+ Parameters `(message object & args)`:
477
509
 
478
510
  1. The object to send the message to
479
511
  2. A text with the message name
480
512
  3. Any number of arguments to be passed along with the message
481
513
 
482
514
  ```clojure
483
- (. "01011101" :to_i 2) ; => 93
515
+ (send :to_i "01011101" 2) ; => 93
484
516
  ```
485
517
 
486
518
  ```ruby
@@ -488,16 +520,11 @@ Parameters `(object message & args)`:
488
520
  "01011101".to_i(2)
489
521
  ```
490
522
 
491
-
492
- ### require
493
-
494
- Loads and runs a Läsp file. Paths are relative to the file they are being
495
- required in.
523
+ You can accomplish the same by prepending a dot to the function name, this
524
+ makes it look very similar to a normal Läsp function call:
496
525
 
497
526
  ```clojure
498
- (require "lasp_file.lasp") ; lasp_file.lasp is in the same directory as this code
499
- (require "dir/lasp_file.lasp") ; dir/ is a folder with a lasp file in this directory
500
- (require "../lasp_file.lasp") ; lasp_file.lasp is in the parent folder
527
+ (.upcase "hello") ; => "HELLO"
501
528
  ```
502
529
 
503
530
 
@@ -947,6 +974,49 @@ If given an uneven number of bindings, the last one will be assigned to `nil`.
947
974
  ```
948
975
 
949
976
 
977
+ ### or
978
+
979
+ Evaluates its arguments in turn, returning:
980
+
981
+ - the first **truthy** value it encounters
982
+ - the last value, if all forms evaluate to logical **false**
983
+ - `nil` if no arguments are given
984
+
985
+ ```clojure
986
+ ; Typical usage in if-statements
987
+ (or (= 1 2) (= 3 3)) ; => true
988
+ (or (= 1 2) (= 3 4)) ; => false
989
+
990
+ (or) ; => nil
991
+ (or nil nil false) ; => false
992
+
993
+ ; will return without printing anything
994
+ (or (not true) 42 (println "nope")) ; => 42
995
+ ```
996
+
997
+
998
+ ### and
999
+
1000
+ Evaluates its arguments in turn, returning:
1001
+
1002
+ - the first **falsy** value it encounters
1003
+ - the last value, if all forms evaluate to logical **true**
1004
+ - `true` if no arguments are given
1005
+
1006
+ ```clojure
1007
+ ; Typical usage in if-statements
1008
+ (and (= 1 1) (= 2 2)) ; => true
1009
+ (and (= 1 1) (= 2 3)) ; => false
1010
+
1011
+ (and) ; => nil
1012
+ (and true true 42) ; => 42
1013
+
1014
+ ; will return without printing anything
1015
+ (and 42 false (println "nope")) ; => false
1016
+ ```
1017
+
1018
+
1019
+
950
1020
  ### macroexpand
951
1021
 
952
1022
  Returns the unevaluated result of a macro, indispensable for debugging.
data/README.md CHANGED
@@ -1,14 +1,17 @@
1
- # Läsp
1
+ # Läsp [![Build Status](https://travis-ci.org/alcesleo/lasp.svg?branch=master)](https://travis-ci.org/alcesleo/lasp)
2
2
 
3
3
  A Lisp implementation in Ruby.
4
4
 
5
5
  ## Features
6
6
 
7
- - Very concise [core library](lib/lasp/corelib.rb) written in Ruby
8
- - [Standard library](lib/lasp/stdlib.lisp) written in Läsp itself
7
+ - Comprehensive [documentation](DOCUMENTATION.md)
9
8
  - Interactive REPL with auto-closing of missing trailing parentheses
9
+ - Closures
10
+ - let-bindings
10
11
  - Fully functional macro system
11
12
  - Interoperability with Ruby
13
+ - Very concise [core library](lib/lasp/corelib.rb) written in Ruby
14
+ - [Standard library](lib/lasp/stdlib.lisp) written in Läsp itself
12
15
 
13
16
  ## Installation
14
17
 
@@ -75,7 +78,7 @@ Comments start with a `;` and end at the end of a line
75
78
  ### Run the specs
76
79
 
77
80
  ```bash
78
- rake
81
+ bundle exec rake
79
82
  ```
80
83
 
81
84
  ### Dev REPL
data/bin/lasp CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  require "lasp"
4
4
  require "lasp/repl"
5
- Lasp::load_stdlib!
6
5
 
7
6
  if ARGV.first
8
- Lasp::execute_file(ARGV.first)
7
+ Lasp::execute_file(ARGV.first, Lasp::env_with_stdlib)
9
8
  else
10
9
  Lasp::Repl.run
11
10
  end
data/lasp.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Jimmy Börjesson"]
10
10
  spec.email = ["lagginglion@gmail.com"]
11
11
 
12
- spec.summary = %q{A simple programming language similar to Clojure, but much worse.}
12
+ spec.summary = %q{A simple Lisp-dialect programming language inspired by Clojure.}
13
13
  spec.homepage = "https://github.com/alcesleo/lasp"
14
14
  spec.license = "MIT"
15
15
 
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.required_ruby_version = '~> 2.0'
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "bundler", "~> 1.7"
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.4"
25
26
  end
data/lib/lasp/corelib.rb CHANGED
@@ -1,5 +1,3 @@
1
- require "lasp"
2
-
3
1
  module Lasp
4
2
  CORELIB = {
5
3
  :+ => -> (*args) { args.reduce(:+) },
@@ -23,7 +21,6 @@ module Lasp
23
21
  :print => -> (*output) { STDOUT.print(*output) },
24
22
  :readln => -> () { STDIN.gets.chomp },
25
23
  :apply => -> (f, list) { f.call(*list) },
26
- :"." => -> (obj, m, *args) { obj.send(m, *args) },
27
- :require => -> (p) { execute_file(File.expand_path(p, __dir__)) },
24
+ :send => -> (m, o, *args) { o.public_send(m, *args) },
28
25
  }
29
26
  end
data/lib/lasp/env.rb CHANGED
@@ -1,9 +1,17 @@
1
- require "lasp/corelib"
1
+ require "forwardable"
2
2
 
3
3
  module Lasp
4
- module_function
4
+ class Env
5
+ extend Forwardable
5
6
 
6
- def global_env
7
- @global_env ||= {}.merge(CORELIB)
7
+ def_delegators :@env, :fetch, :[]=
8
+
9
+ def initialize(env = {})
10
+ @env = env
11
+ end
12
+
13
+ def merge(hash)
14
+ Env.new(@env.merge(hash))
15
+ end
8
16
  end
9
17
  end
data/lib/lasp/fn.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require "lasp/interpreter"
2
- require "lasp/params"
2
+ require "lasp/params_builder"
3
3
  require "lasp/errors"
4
4
 
5
5
  module Lasp
@@ -7,7 +7,7 @@ module Lasp
7
7
  attr_reader :params, :body, :env
8
8
 
9
9
  def initialize(params, body, env)
10
- @params = Params.new(params)
10
+ @params = ParamsBuilder.build(params)
11
11
  @body = body
12
12
  @env = env
13
13
  end
@@ -24,26 +24,7 @@ module Lasp
24
24
  private
25
25
 
26
26
  def env_with_args(args)
27
- enforce_arity!(args)
28
-
29
- params_with_args = params
30
- .ordered
31
- .zip(args.take(params.length))
32
- .to_h
33
-
34
- if params.variadic?
35
- params_with_args[params.rest] = args.drop(params.length)
36
- end
37
-
38
- env.merge(params_with_args)
39
- end
40
-
41
- def enforce_arity!(args)
42
- wrong_number_of_args!(args) unless params.matches_arity?(args.length)
43
- end
44
-
45
- def wrong_number_of_args!(args)
46
- fail ArgumentError, "wrong number of arguments (#{args.length} for #{params.arity})"
27
+ env.merge(params.with_args(args))
47
28
  end
48
29
  end
49
30
  end
@@ -1,3 +1,4 @@
1
+ require "lasp"
1
2
  require "lasp/fn"
2
3
  require "lasp/macro"
3
4
  require "lasp/errors"
@@ -22,12 +23,13 @@ module Lasp
22
23
  head, *tail = *form
23
24
 
24
25
  case head
25
- when :def then def_special_form(tail, env)
26
- when :fn then fn_special_form(tail, env)
27
- when :do then do_special_form(tail, env)
28
- when :if then if_special_form(tail, env)
29
- when :quote then quote_special_form(tail, env)
30
- when :macro then macro_special_form(tail, env)
26
+ when :def then def_special_form(tail, env)
27
+ when :fn then fn_special_form(tail, env)
28
+ when :do then do_special_form(tail, env)
29
+ when :if then if_special_form(tail, env)
30
+ when :quote then quote_special_form(tail, env)
31
+ when :macro then macro_special_form(tail, env)
32
+ when :require then require_special_form(tail, env)
31
33
  else call_function(head, tail, env)
32
34
  end
33
35
  end
@@ -75,5 +77,14 @@ module Lasp
75
77
  params, func = form
76
78
  Macro.new(params, func, env)
77
79
  end
80
+
81
+ def require_special_form(form, env)
82
+ require_path, is_relative = form
83
+
84
+ require_root = is_relative ? File.dirname(env.fetch(:__FILE__)) : Dir.pwd
85
+ absolute_path = File.expand_path(require_path, require_root)
86
+
87
+ Lasp::execute_file(absolute_path, env)
88
+ end
78
89
  end
79
90
  end
data/lib/lasp/lexer.rb CHANGED
@@ -4,6 +4,7 @@ class Lexer
4
4
  TOKENS = [
5
5
  /\(|\)/, # parens
6
6
  /'/, # quote
7
+ /\./, # dot
7
8
  /"(\\"|[^"])*"/, # string literal
8
9
  /[^\s)]+/, # any non-whitespace character excluding )
9
10
  ]
data/lib/lasp/params.rb CHANGED
@@ -6,76 +6,41 @@ module Lasp
6
6
 
7
7
  def initialize(param_list)
8
8
  @param_list = param_list
9
-
10
- validate_params!
11
9
  end
12
10
 
13
- def ordered
14
- param_list.take_while { |p| p != :& }
11
+ def to_s
12
+ "(" + param_list.join(" ") + ")"
15
13
  end
16
14
 
17
- def rest
18
- unless variadic?
19
- fail LaspError, "a non-variadic function does not have rest-arguments"
20
- end
21
- param_list.last
15
+ def with_args(args)
16
+ enforce_arity!(args)
17
+ fixed_params.zip(args.take(length)).to_h
22
18
  end
23
19
 
24
- def variadic?
25
- param_list.include?(:&)
20
+ private
21
+
22
+ def fixed_params
23
+ param_list
26
24
  end
27
25
 
28
26
  def arity
29
- ordered.length.to_s + (variadic? ? "+" : "")
27
+ length.to_s
30
28
  end
31
29
 
32
30
  def matches_arity?(num_args)
33
- if variadic?
34
- num_args >= length
35
- else
36
- num_args == length
37
- end
31
+ num_args == length
38
32
  end
39
33
 
40
34
  def length
41
- ordered.length
42
- end
43
-
44
- def to_s
45
- "(" + param_list.join(" ") + ")"
46
- end
47
-
48
- private
49
-
50
- def validate_params!
51
- validate_list!
52
- validate_single_ampersand!
53
- validate_single_rest_parameter!
54
- validate_unique_parameter_names!
55
- end
56
-
57
- def validate_list!
58
- unless Array === param_list
59
- fail SyntaxError, "parameters must be a list"
60
- end
61
- end
62
-
63
- def validate_unique_parameter_names!
64
- unless param_list.uniq.length == param_list.length
65
- fail SyntaxError, "parameter names have to be unique"
66
- end
67
- end
68
-
69
- def validate_single_ampersand!
70
- invalid_rest_argument_usage! unless param_list.select { |p| p == :& }.length <= 1
35
+ fixed_params.length
71
36
  end
72
37
 
73
- def validate_single_rest_parameter!
74
- invalid_rest_argument_usage! if variadic? && param_list[-2] != :&
38
+ def enforce_arity!(args)
39
+ wrong_number_of_args!(args) unless matches_arity?(args.length)
75
40
  end
76
41
 
77
- def invalid_rest_argument_usage!
78
- fail SyntaxError, "rest-arguments may only be used once, at the end, with a single binding"
42
+ def wrong_number_of_args!(args)
43
+ fail ArgumentError, "wrong number of arguments (#{args.length} for #{arity})"
79
44
  end
80
45
  end
81
46
  end
@@ -0,0 +1,69 @@
1
+ require "lasp/errors"
2
+ require "lasp/params"
3
+ require "lasp/variadic_params"
4
+
5
+ module Lasp
6
+ class ParamsBuilder
7
+ def self.build(param_list)
8
+ new(param_list).build
9
+ end
10
+
11
+ def initialize(param_list)
12
+ @param_list = param_list
13
+ end
14
+
15
+ def build
16
+ validate_params!
17
+ params_object
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :param_list
23
+
24
+ def params_object
25
+ if variadic?
26
+ VariadicParams.new(param_list)
27
+ else
28
+ Params.new(param_list)
29
+ end
30
+ end
31
+
32
+ def validate_params!
33
+ validate_list!
34
+ validate_single_ampersand!
35
+ validate_single_rest_parameter!
36
+ validate_unique_parameter_names!
37
+ end
38
+
39
+ def variadic?
40
+ param_list.include?(:&)
41
+ end
42
+
43
+ def validate_list!
44
+ unless Array === param_list
45
+ fail SyntaxError, "parameters must be a list"
46
+ end
47
+ end
48
+
49
+ def validate_unique_parameter_names!
50
+ accepted_params = param_list.reject { |p| p == :_ }
51
+
52
+ unless accepted_params.uniq.length == accepted_params.length
53
+ fail SyntaxError, "parameter names must be unique (except for _)"
54
+ end
55
+ end
56
+
57
+ def validate_single_ampersand!
58
+ invalid_rest_argument_usage! unless param_list.select { |p| p == :& }.length <= 1
59
+ end
60
+
61
+ def validate_single_rest_parameter!
62
+ invalid_rest_argument_usage! if variadic? && param_list[-2] != :&
63
+ end
64
+
65
+ def invalid_rest_argument_usage!
66
+ fail SyntaxError, "rest-arguments may only be used once, at the end, with a single binding"
67
+ end
68
+ end
69
+ end
data/lib/lasp/parser.rb CHANGED
@@ -30,6 +30,7 @@ module Lasp
30
30
  case token
31
31
  when "(" then form(tokens)
32
32
  when "'" then quote(tokens)
33
+ when "." then dot(tokens)
33
34
  else atom(token)
34
35
  end
35
36
  end
@@ -47,6 +48,12 @@ module Lasp
47
48
  [:quote] << build_ast(tokens)
48
49
  end
49
50
 
51
+ def dot(tokens)
52
+ method = tokens.shift
53
+ tokens.unshift(":" + method)
54
+ :send
55
+ end
56
+
50
57
  def atom(token)
51
58
  case token
52
59
  when "true" then true
data/lib/lasp/repl.rb CHANGED
@@ -11,13 +11,15 @@ module Lasp
11
11
  def run
12
12
  trap("SIGINT") { puts "\n\nBye!"; exit }
13
13
 
14
+ env = Lasp::env_with_stdlib
15
+
14
16
  puts "((( Läsp v#{Lasp::VERSION} REPL (ctrl+c to exit) )))\n\n"
15
17
  loop do
16
18
  begin
17
19
  history = true
18
20
  input = Readline.readline(prompt, history).to_s
19
21
  input = autoclose_parentheses(input)
20
- result = Lasp::execute(input)
22
+ result = Lasp::execute(input, env)
21
23
  print_result(result)
22
24
  rescue => error
23
25
  print_error(error)
data/lib/lasp/stdlib.lasp CHANGED
@@ -1,4 +1,4 @@
1
- (require "stdmacros.lasp")
1
+ (require "stdmacros.lasp" :relative)
2
2
 
3
3
  ; Aliases
4
4
  (def first head)
@@ -16,7 +16,7 @@
16
16
  ; If a list is empty
17
17
  (defn empty?
18
18
  (coll)
19
- (nil? (head coll)))
19
+ (= coll (rest coll)))
20
20
 
21
21
  ; If all arguments are not equal
22
22
  (defn not= (& args)
@@ -143,7 +143,7 @@
143
143
 
144
144
  ; Takes a method from Ruby-land and returns a Lasp function
145
145
  (defn ruby-method (meth)
146
- (fn (arg) (. arg meth)))
146
+ (fn (arg) (send meth arg)))
147
147
 
148
148
 
149
149
  ; Conversion functions
@@ -67,3 +67,21 @@
67
67
  (form)
68
68
  (list 'apply (first form)
69
69
  (list 'quote (rest form))))
70
+
71
+ (defm or
72
+ (& args)
73
+ (if (empty? args) nil
74
+ (if (empty? (tail args)) (head args)
75
+
76
+ (list 'let
77
+ (list 'or-value (head args))
78
+ (list 'if 'or-value 'or-value (cons 'or (tail args)))))))
79
+
80
+ (defm and
81
+ (& args)
82
+ (if (empty? args) true
83
+ (if (empty? (tail args)) (head args)
84
+
85
+ (list 'let
86
+ (list 'and-value (head args))
87
+ (list 'if 'and-value (cons 'and (tail args)) 'and-value)))))
@@ -0,0 +1,27 @@
1
+ require "lasp/params"
2
+
3
+ module Lasp
4
+ class VariadicParams < Params
5
+ def with_args(args)
6
+ super.merge(rest_args(args))
7
+ end
8
+
9
+ private
10
+
11
+ def fixed_params
12
+ param_list.take_while { |p| p != :& }
13
+ end
14
+
15
+ def arity
16
+ super + "+"
17
+ end
18
+
19
+ def matches_arity?(num_args)
20
+ num_args >= length
21
+ end
22
+
23
+ def rest_args(args)
24
+ { param_list.last => args.drop(length) }
25
+ end
26
+ end
27
+ end
data/lib/lasp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lasp
2
- VERSION = "0.10.1"
2
+ VERSION = "0.11.0"
3
3
  end
data/lib/lasp.rb CHANGED
@@ -2,6 +2,7 @@ require "lasp/version"
2
2
  require "lasp/env"
3
3
  require "lasp/parser"
4
4
  require "lasp/interpreter"
5
+ require "lasp/corelib"
5
6
  require "lasp/ext"
6
7
 
7
8
  module Lasp
@@ -9,15 +10,24 @@ module Lasp
9
10
 
10
11
  module_function
11
12
 
12
- def execute_file(path)
13
- execute("(do #{File.read(path)})")
13
+ def execute(program, env = env_with_corelib)
14
+ Interpreter.eval(Parser.parse(program), env)
14
15
  end
15
16
 
16
- def execute(program, env = global_env)
17
- Interpreter.eval(Parser.parse(program), env)
17
+ def execute_file(path, env = env_with_corelib)
18
+ env[:__FILE__] = path
19
+ result = execute("(do #{File.read(path)})", env)
20
+ env[:__FILE__] = nil
21
+ result
22
+ end
23
+
24
+ def env_with_corelib
25
+ Env.new(CORELIB.dup)
18
26
  end
19
27
 
20
- def load_stdlib!
21
- Lasp::execute_file(STDLIB_PATH)
28
+ def env_with_stdlib
29
+ env_with_corelib.tap do |env|
30
+ Lasp::execute_file(STDLIB_PATH, env)
31
+ end
22
32
  end
23
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lasp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jimmy Börjesson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-22 00:00:00.000000000 Z
11
+ date: 2016-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.10'
19
+ version: '1.7'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.10'
26
+ version: '1.7'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.4'
41
55
  description:
42
56
  email:
43
57
  - lagginglion@gmail.com
@@ -67,10 +81,12 @@ files:
67
81
  - lib/lasp/lexer.rb
68
82
  - lib/lasp/macro.rb
69
83
  - lib/lasp/params.rb
84
+ - lib/lasp/params_builder.rb
70
85
  - lib/lasp/parser.rb
71
86
  - lib/lasp/repl.rb
72
87
  - lib/lasp/stdlib.lasp
73
88
  - lib/lasp/stdmacros.lasp
89
+ - lib/lasp/variadic_params.rb
74
90
  - lib/lasp/version.rb
75
91
  homepage: https://github.com/alcesleo/lasp
76
92
  licenses:
@@ -95,5 +111,5 @@ rubyforge_project:
95
111
  rubygems_version: 2.4.5
96
112
  signing_key:
97
113
  specification_version: 4
98
- summary: A simple programming language similar to Clojure, but much worse.
114
+ summary: A simple Lisp-dialect programming language inspired by Clojure.
99
115
  test_files: []