Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ require 'rubygems'
require File.expand_path('../lib/heist', __FILE__)

file "lib/heist/builtin/compiled_library.rb" do |t|
library_source = %w[util logic numeric list character string vector].
library_source = %w[util logic numeric list character string vector keyword].
map { |l| File.read "lib/heist/builtin/lib/#{l}.scm" }.
join("\n\n")

Expand Down
2 changes: 1 addition & 1 deletion lib/heist/builtin/compiled_library.rb

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions lib/heist/builtin/lib/keyword.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
; (get-keyword keyword args [default])
; Returns the subsequent element to +keyword+ in +args+ if
; present. Otherwise returns the return value of applying the thunk
; +default+ or, if +default+ is not given, returns +#f+.
(define (get-keyword keyword args . thunk)
(let ((default (if (pair? thunk) (car thunk) (lambda () #f))))
(let loop ((args args))
(cond ((null? args) (default))
((eq? keyword (car args))
(cadr args))
(else
(loop (cddr args)))))))

; (let-keywords args ((keyword default) keyword ...) body ...)
; Convenience syntax for binding a list of keyword arguments to variables.
; Note that this macro is very inefficient at the moment.
(define-syntax let-keywords
(syntax-rules ()
((_ args () body ...) (begin body ...))
((_ args ((keyword default) rest ...) body ...)
(let ((keyword (get-keyword
(string->keyword
(symbol->string 'keyword))
args
(lambda () default))))
(let-keywords args (rest ...)
body ...)))
((_ args (keyword rest ...) body ...)
(let-keywords args ((keyword #f) rest ...)
body ...))))
18 changes: 18 additions & 0 deletions lib/heist/builtin/primitives.rb
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@
Vector === value
end

define('keyword?') do |value|
Keyword === value
end

#----------------------------------------------------------------

# Numerical functions
Expand Down Expand Up @@ -336,6 +340,20 @@

#----------------------------------------------------------------

# Keyword functions

# Returns the string representing the name of the given keyword
define('keyword->string') do |keyword|
keyword.keyword_name
end

# Returns the keyword whose name is the given string
define('string->keyword') do |string|
Keyword.new(string)
end

#----------------------------------------------------------------

# Character functions

# Returns true iff the two characters are equal
Expand Down
22 changes: 22 additions & 0 deletions lib/heist/runtime/data/keyword.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Heist
class Runtime

# A +Keyword+ is a a self-quoting identifier ending in ":". The
# separate class is merely a convenience for implementing the
# +keyword?+ predicate.
class Keyword < Identifier

attr_reader :keyword_name

# Since keywords need never be renamed they don't need an
# +original_name+ argument.
def initialize(name)
@keyword_name = name
super("#{name}:")
end

end

end
end

2 changes: 1 addition & 1 deletion lib/heist/runtime/runtime.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module Heist
#
class Runtime

%w[ data/expression data/identifier data/character
%w[ data/expression data/identifier data/character data/keyword
data/cons data/vector data/value
callable/function callable/syntax callable/macro callable/continuation
frame stack stackless
Expand Down
1 change: 1 addition & 0 deletions lib/heist/runtime/scope.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def initialize(parent = {})
#
def [](name)
name = to_name(name)
return Keyword.new(name[0..-2]) if name.end_with?(':')
bound = @symbols.has_key?(name)

raise UndefinedVariable.new(
Expand Down