Class: RubyLisp::Reader
- Inherits:
-
Object
- Object
- RubyLisp::Reader
- Defined in:
- lib/rubylisp/reader.rb
Constant Summary collapse
- TOKEN_REGEX =
from kanaka/mal
%r{ # ignore whitespace and commas [\s,]* # match any of... ( # the splice-unquote reader macro ~@| # special characters [\[\]{}()'`~^@]| # strings "(?:\\.|[^\\"])*"| # comments ;.*| # any sequence of non-special characters # e.g. symbols, numbers, keywords, booleans, etc. [^\s\[\]{}('"`,;)]* ) }x
Instance Attribute Summary collapse
-
#position ⇒ Object
Returns the value of attribute position.
-
#tokens ⇒ Object
Returns the value of attribute tokens.
Class Method Summary collapse
Instance Method Summary collapse
- #next_token ⇒ Object
- #peek ⇒ Object
- #read_atom ⇒ Object
- #read_deref_form ⇒ Object
- #read_form ⇒ Object
- #read_form_with_metadata ⇒ Object
- #read_hashmap ⇒ Object
- #read_list ⇒ Object
- #read_quasiquoted_form ⇒ Object
- #read_quoted_form ⇒ Object
- #read_seq(type_name, constructor, end_token, seq = []) ⇒ Object
- #read_special_form(special) ⇒ Object
- #read_splice_unquoted_form ⇒ Object
- #read_unquoted_form ⇒ Object
- #read_vector ⇒ Object
- #tokenize(str) ⇒ Object
Instance Attribute Details
#position ⇒ Object
Returns the value of attribute position.
30 31 32 |
# File 'lib/rubylisp/reader.rb', line 30 def position @position end |
#tokens ⇒ Object
Returns the value of attribute tokens.
30 31 32 |
# File 'lib/rubylisp/reader.rb', line 30 def tokens @tokens end |
Class Method Details
.read_str(str) ⇒ Object
197 198 199 200 201 202 203 204 205 |
# File 'lib/rubylisp/reader.rb', line 197 def Reader.read_str str reader = Reader.new reader.tokenize(str) forms = [] while reader.position < reader.tokens.count forms << reader.read_form end forms end |
Instance Method Details
#next_token ⇒ Object
36 37 38 39 40 |
# File 'lib/rubylisp/reader.rb', line 36 def next_token token = peek @position += 1 token end |
#peek ⇒ Object
32 33 34 |
# File 'lib/rubylisp/reader.rb', line 32 def peek @tokens[@position] end |
#read_atom ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/rubylisp/reader.rb', line 67 def read_atom token = next_token case token when nil nil when /^\-?\d+$/ Value.new(token.to_i) when /^\-?\d+\.\d+$/ Value.new(token.to_f) when /^".*"$/ # it's safe to use eval here because the tokenizer ensures that # the token is an escaped string representation Value.new(eval(token)) # it's a little weird that an unfinished string (e.g. "abc) gets # tokenized as "", but at least the behavior is consistent ¯\_(ツ)_/¯ when "" raise ParseError, "Unexpected EOF while parsing string." when /^:/ Value.new(token[1..-1].to_sym) when 'nil' Value.new(nil) when 'true' Value.new(true) when 'false' Value.new(false) else Symbol.new(token) end end |
#read_deref_form ⇒ Object
121 122 123 |
# File 'lib/rubylisp/reader.rb', line 121 def read_deref_form read_special_form 'deref' end |
#read_form ⇒ Object
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/rubylisp/reader.rb', line 148 def read_form case peek when /^;/ # ignore comments next_token read_form when '(' next_token read_list when '[' next_token read_vector when '{' next_token read_hashmap when ')' raise ParseError, "Unexpected ')'." when ']' raise ParseError, "Unexpected ']'." when '}' raise ParseError, "Unexpected '}'." when "'" next_token read_quoted_form when '`' next_token read_quasiquoted_form when '~' next_token read_unquoted_form when '~@' next_token read_splice_unquoted_form when '@' next_token read_deref_form when '^' next_token else read_atom end end |
#read_form_with_metadata ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/rubylisp/reader.rb', line 125 def token = peek case token when nil raise ParseError, "Unexpected EOF while parsing metadata." when '{' next_token = read_hashmap when /^:/ kw = read_form = hash_map [kw, Value.new(true)] else raise ParseError, "Invalid metadata: '#{token}'" end form = read_form unless form raise ParseError, "Unexpected EOF after metadata." end list [Symbol.new("with-meta"), form, ] end |
#read_hashmap ⇒ Object
63 64 65 |
# File 'lib/rubylisp/reader.rb', line 63 def read_hashmap read_seq 'hash-map', RubyLisp.method(:hash_map), '}' end |
#read_list ⇒ Object
55 56 57 |
# File 'lib/rubylisp/reader.rb', line 55 def read_list read_seq 'list', RubyLisp.method(:list), ')' end |
#read_quasiquoted_form ⇒ Object
109 110 111 |
# File 'lib/rubylisp/reader.rb', line 109 def read_quasiquoted_form read_special_form 'quasiquote' end |
#read_quoted_form ⇒ Object
105 106 107 |
# File 'lib/rubylisp/reader.rb', line 105 def read_quoted_form read_special_form 'quote' end |
#read_seq(type_name, constructor, end_token, seq = []) ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/rubylisp/reader.rb', line 42 def read_seq(type_name, constructor, end_token, seq=[]) case peek when nil raise ParseError, "Unexpected EOF while parsing #{type_name}." when end_token next_token constructor.call(seq) else seq << read_form read_seq(type_name, constructor, end_token, seq) end end |
#read_special_form(special) ⇒ Object
97 98 99 100 101 102 103 |
# File 'lib/rubylisp/reader.rb', line 97 def read_special_form(special) form = read_form unless form raise ParseError, "Unexpected EOF while parsing #{special} form." end list [Symbol.new(special), form] end |
#read_splice_unquoted_form ⇒ Object
117 118 119 |
# File 'lib/rubylisp/reader.rb', line 117 def read_splice_unquoted_form read_special_form 'splice-unquote' end |
#read_unquoted_form ⇒ Object
113 114 115 |
# File 'lib/rubylisp/reader.rb', line 113 def read_unquoted_form read_special_form 'unquote' end |
#read_vector ⇒ Object
59 60 61 |
# File 'lib/rubylisp/reader.rb', line 59 def read_vector read_seq 'vector', RubyLisp.method(:vec), ']' end |
#tokenize(str) ⇒ Object
192 193 194 195 |
# File 'lib/rubylisp/reader.rb', line 192 def tokenize str @tokens = str.strip.scan(TOKEN_REGEX).flatten[0...-1] @position = 0 end |