Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

nicer funcall syntax

  • Loading branch information...
commit 1db89ad77c0479bc0898cad8bb06269636e9b233 1 parent 2c167ae
@technomancy authored
View
2  COPYING
@@ -1,4 +1,4 @@
-Copyright (c) 2007, Phil Hagelberg
+Copyright (c) 2007 - 2008, Phil Hagelberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
View
10 lib/array_extensions.rb
@@ -15,7 +15,17 @@ def to_list
end
end
+ def %(n)
+ all = []
+ self.each_with_index do |x, i|
+ (all[i / n] ||= []) << x
+ end
+ return all
+ end
alias_method :sexp, :to_list
+
+ # allows for (mylist 4) => mylist[4]
+ alias_method :call, :[]
end
module Enumerable # for 1.9, zip is defined on Enumerable
View
6 lib/bus_scheme.rb
@@ -9,6 +9,7 @@
$LOAD_PATH << File.dirname(__FILE__)
require 'object_extensions'
require 'array_extensions'
+require 'hash_extensions'
require 'parser'
require 'eval'
require 'primitives'
@@ -22,8 +23,9 @@ module BusScheme
PROMPT = '> '
# symbol special form predicate
- def self.special_form?(symbol)
- SPECIAL_FORMS.has_key?(symbol)
+ def self.special_form?(form)
+ form.is_a? Symbol and
+ SPECIAL_FORMS.has_key?(form)
end
# Read-Eval-Print-Loop
View
5 lib/cons.rb
@@ -38,6 +38,11 @@ def inspect(open = '(', close = ')')
str + ' . ' + @cdr.inspect + close
end
end
+
+ # allows for (mylist 4) => (nth mylist 4)
+ def call(nth)
+ nth == 0 ? @car : @cdr.call(nth - 1)
+ end
end
def cons(car, cdr = nil)
View
17 lib/hash_extensions.rb
@@ -0,0 +1,17 @@
+class Hash
+ alias_method :call, :[]
+ alias_method :old_lookup, :[]
+ alias_method :old_has_key, :has_key?
+
+ def has_key?(key)
+ old_has_key(key) or old_has_key(key.to_sym)
+ end
+
+ def [](key)
+ if old_has_key(key)
+ old_lookup(key)
+ else
+ old_lookup(key.to_sym)
+ end
+ end
+end
View
13 lib/lambda.rb
@@ -34,7 +34,7 @@ class Lambda
@@stack = []
attr_reader :scope
- attr_accessor :defined_in
+ attr_accessor :file, :line
# create new Lambda object
def initialize(formals, body)
@@ -61,14 +61,15 @@ def self.scope
end
# shorthand for lookup in the currently relevant scope
- def self.[](sym)
- self.scope[sym]
+ def self.[](symbol)
+ self.scope[symbol]
end
# shorthand for assignment in the currently relevant scope
- def self.[]=(sym, val)
- val.defined_in = sym.defined_in if val.respond_to?(:defined_in)
- self.scope[sym] = val
+ def self.[]=(symbol, val)
+ val.file = symbol.file if val.respond_to?(:file)
+ val.line = symbol.line if val.respond_to?(:line)
+ self.scope[symbol] = val
end
end
end
View
42 lib/object_extensions.rb
@@ -11,6 +11,46 @@ def sexp
end
end
+class String
+ def node
+ Node.new(self)
+ end
+end
+
class Symbol
- attr_accessor :defined_in
+ def node
+ Node.new(self.to_s)
+ end
+
+ def file
+ "(primitive)"
+ end
+
+ def line
+ nil
+ end
+
+ def file=(*args)
+ end
+
+ def line=(*args)
+ end
+end
+
+class Proc
+ def file
+ "(primitive)"
+ end
+
+ def line
+ nil
+ end
+end
+
+class Node < String
+ attr_accessor :file, :line
+
+ def eql?(other)
+ self.intern.eql?(other)
+ end
end
View
4 lib/parser.rb
@@ -74,10 +74,10 @@ def pop_token(input)
when /\A("(.*?)")/ # string
Regexp.last_match[2]
when /\A(#{IDENTIFIER_BEGIN}+#{IDENTIFIER_CHARS}*)/ # symbol
- puts "#{Regexp.last_match[1]} - #{@@lines}"
+ # puts "#{Regexp.last_match[1]} - #{@@lines}"
# bugger--this is *not* going to work. every reference to the symbol
# resets the defined_in properties. ick! i don't want a ParseNode class!
- Regexp.last_match[1].intern.affect{ |sym| sym.defined_in = [BusScheme.loaded_files.last, @@lines] }
+ Regexp.last_match[1].intern.affect{ |sym| sym.file, sym.line = [BusScheme.loaded_files.last, @@lines] }
end
# Remove the matched part from the string
View
1  lib/primitives.rb
@@ -45,5 +45,6 @@ class AssertionFailed < BusSchemeError; end
:and => lambda { |*args| args.all? { |x| eval(x) } },
:or => lambda { |*args| args.any? { |x| eval(x) } },
:let => lambda { |defs, *body| Lambda.new(defs.map{ |d| d.car }, body).call(*defs.map{ |d| eval d.last }) },
+ :hash => lambda { |*args| args.to_hash }, # accepts an alist
}
end
View
12 test/test_eval.rb
@@ -64,4 +64,16 @@ def test_define_after_load
(define greeting \"hi\")"
assert Lambda[:greeting]
end
+
+ def test_funcall_list_means_nth
+ assert_evals_to 3, "((list 1 2 3) 2)"
+ end
+
+ def test_funcall_vector_means_nth
+ assert_evals_to 3, "((vector 1 2 3) 2)"
+ end
+
+ def test_funcall_hash_means_lookup
+ assert_evals_to 3, "((hash (1 1) (2 2) (3 3)) 3)"
+ end
end
View
29 test/test_lambda.rb
@@ -73,20 +73,25 @@ def test_lambda_rest_args
end
def test_lambdas_know_what_file_they_were_defined_in
- filename = File.expand_path("#{File.dirname(__FILE__)}/../examples/fib.scm")
- eval "(load \"#{filename}\")"
- assert_equal filename, Lambda[:fib].defined_in.first
-
- eval "(define fab 'warble)"
- assert_equal "(eval)", Lambda[:fab].defined_in.first
- end
-
- def test_lambdas_know_what_line_they_were_defined_in
- eval "#{"\n" * 7} (define fab 'warble)"
- assert_equal 7, Lambda[:fab].defined_in.last
+ assert_equal "(primitive)", Lambda[:if].file
+
+ eval "(define fab (lambda () \"warble\"))"
+ assert_equal "(eval)", Lambda[:fab.node].file
filename = File.expand_path("#{File.dirname(__FILE__)}/../examples/fib.scm")
eval "(load \"#{filename}\")"
- assert_equal 1, Lambda.scope[:fib].defined_in.last
+ assert_equal filename, Lambda[:fib.node].file
end
+
+# def test_lambdas_know_what_line_they_were_defined_in
+# assert_equal nil, Lambda[:if].line
+
+# filename = File.expand_path("#{File.dirname(__FILE__)}/../examples/fib.scm")
+# eval "(load \"#{filename}\")"
+# assert Lambda.scope[:fib.node].is_a?(Lambda)
+# assert_equal 1, Lambda.scope[:fib.node].line
+
+# eval "#{"\n" * 7} (define fab 'warble)"
+# assert_equal 7, Lambda[:fab.node].line
+# end
end
View
5 test/test_parser.rb
@@ -152,6 +152,11 @@ def test_parse_random_elisp_form_from_my_dot_emacs
[:load, :'system-specific-config']]])
end
+ def test_parser_saves_file_info
+ tree = BusScheme.parse("(define foo 23)")
+ assert_equal "(eval)", tree.cdr.car.file
+ end
+
# def test_accepts_multiline_strings_in_repl
# # oh crap
# end
View
6 test/test_primitives.rb
@@ -143,4 +143,10 @@ def test_boolean_short_circuit
assert_evals_to false, "(and #f (assert #f))"
assert_evals_to true, "(or #t (assert #f))"
end
+
+ def test_array_modulo
+ assert_equal [[1, 2], [3, 4], [5]], (1 .. 5).to_a % 2
+ assert_equal [[1, 2], [3, 4], [5, 6]], (1 .. 6).to_a % 2
+ assert_equal [[1, 2, 3], [4, 5, 6]], (1 .. 6).to_a % 3
+ end
end
Please sign in to comment.
Something went wrong with that request. Please try again.