elparser 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c146b65d433ec89e7357565a95dcca4381c2f6e6
4
+ data.tar.gz: 7dadc1c9fa424b5ca8586cc523477924c93fb4bc
5
+ SHA512:
6
+ metadata.gz: 30307d68b5b13a897f237588d75a1330db7d25b008ad633bdcd1efdb327f6f545ce38fb5f2e35699759b1f4a75d12765cb6f3a3fec331a6d3ed7ccfcb41e5cce
7
+ data.tar.gz: 1d6d2343058ee730d581b940ee7bb371e3f0d9ce8da85a1b0f577f77ccd7fb33560249fbd0b498884863f531a94d64f01b146191132ccb5794c95003792ff46f
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in elparser.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 SAKURAI Masashi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # Elparser
2
+
3
+ A parser for S-expression of emacs lisp and some utilities.
4
+
5
+ ## Sample code
6
+
7
+ ### Parsing S-exp and getting ruby objects
8
+
9
+ ```ruby
10
+ require 'elparser'
11
+
12
+ parser = Elparser::Parser.new
13
+
14
+ # list and literals
15
+ obj1 = parser.parse("(1 2.3 a \"b\" () (c 'd))")
16
+
17
+ p obj1.to_ruby
18
+ # => [1, 2.3, :a, "b", nil, [:c, [:d]]]
19
+
20
+
21
+ # alist and hash
22
+ obj2 = parser.parse("( (a . 1) (b . \"xxx\") (c 3 4) (\"d\" . \"e\"))")
23
+
24
+ p obj2.to_ruby
25
+ # => [[:a, 1], [:b, "xxx"], [:c, 3, 4], ["d", "e"]]
26
+
27
+ p obj2.to_h
28
+ # => {:a=>1, :b=>"xxx", :c=>[3, 4], "d"=>"e"}
29
+ ```
30
+
31
+ ### Encoding ruby objects into S-exp
32
+
33
+ ```ruby
34
+ p Elparser::encode([1,1.2,-4,"xxx",:www,true,nil])
35
+ # => "(1 1.2 -4 \"xxx\" www t nil)"
36
+
37
+ p Elparser::encode({:a => [1,2,3], :b => {:c => [4,5,6]}})
38
+ # => "((a 1 2 3) (b (c 4 5 6)))"
39
+ ```
40
+
41
+ ## Installation
42
+
43
+ Add this line to your application's Gemfile:
44
+
45
+ ```ruby
46
+ gem 'elparser'
47
+ ```
48
+
49
+ And then execute:
50
+
51
+ $ bundle
52
+
53
+ Or install it yourself as:
54
+
55
+ $ gem install elparser
56
+
57
+
58
+ ## API Document
59
+
60
+ ### Parser
61
+
62
+ The class `Elparser::Parser` is parser for emacs-lisp S-expression.
63
+ The user program creates an instance of the class and parses the S-exp
64
+ string with `parse` method.
65
+
66
+ If the `parse` method succeed in parsing the given S-exp string, it
67
+ returns a `SExp` object which is AST of S-exp. Invoking `to_ruby`
68
+ method of the `SExp` object, one can obtain a ruby object.
69
+
70
+ The `SExp` objects are instances of `SExpXXX` classes: `SExpNumber`,
71
+ `SExpString`, `SExpSymbol`, `SExpNil`, `SExpCons`, `SExpList`,
72
+ `SExpListDot` and `SExpQuoted`. Each classes represent corresponding
73
+ S-exp objects.
74
+
75
+ If the given S-exp list is an alist, invoking `SExpList#to_h` method,
76
+ a `Hash` object can be obtained.
77
+
78
+ ### Encoder
79
+
80
+ The module method `Elparser::encode` encodes the ruby objects into
81
+ elisp S-expressions.
82
+
83
+ If an object which is not defined in serialization rules is given,
84
+ this method raises the exception `StandardError` with some messages.
85
+ See the next section for the encoding detail.
86
+
87
+ ### Object Mapping
88
+
89
+ The primitive objects are translated straightforwardly.
90
+
91
+ #### Decoding (S-expression -> Ruby)
92
+
93
+ A quoted expression is translated to an array.
94
+ Both `nil` and `()` are translated to `nil`.
95
+ Cons cells and lists are translated to arrays.
96
+
97
+ | type | S-exp (input) | Ruby (output) |
98
+ |------------------+---------------------+---------------------|
99
+ | integer | `1` | `1` |
100
+ | float | `1.2` | `1.2` |
101
+ | float | `1e4` | `1e4` |
102
+ | float | `.45` | `.45` |
103
+ | symbol | `abc` | `:abc` |
104
+ | string | `"abc"` | `"abc"` |
105
+ | quote | `'abc` | `[:abc]` |
106
+ | null | `nil` | `nil` |
107
+ | empty list | `()` | `nil` |
108
+ | list | `(1 2)` | `[1,2]` |
109
+ | nest list | `(a (b))` | `[:a [:b]]` |
110
+ | cons cell | `(a . b)` | `[:a,:b]` |
111
+ | dot list | `(a b . d)` | `[:a,:b,:c]` |
112
+ | alist(`to_ruby`) | `((a . 1) (b . 2))` | `[[:a,1],[:b,2]]` |
113
+ | alist(`to_h`) | `((a . 1) (b . 2))` | `{:a=>1,:b=>2}` |
114
+ | alist list | `((a 1 2) (b . 3))` | `{:a=>[1,2],:b=>3}` |
115
+
116
+ #### Encoding (Ruby -> S-expression)
117
+
118
+ The Array and Hash objects are translated to lists and alist
119
+ respectively. Cons cells and quoted expressions can't be expressed by
120
+ any Ruby object. If those S-expressions are needed, one can obtain
121
+ such S-expressions with creating instances of `SExpCons` and
122
+ `SExpQuoted` directly and calling the `to_s` method.
123
+
124
+ | type | Ruby (input) | S-exp (output) |
125
+ |------------+------------------------------------------+------------------------------|
126
+ | primitive | `[1,1.2,-4,"xxx",:www,true,nil]` | `(1 1.2 -4 "xxx" www t nil)` |
127
+ | empty list | `[]` | `nil` |
128
+ | nest list | `[1,[2,[3,4]]]` | `(1 (2 (3 4)))` |
129
+ | hash | `{"a" => "b", "c" => "d"}` | `(("a" . "b") ("c" . "d"))` |
130
+ | hash | `{:a => [1,2,3], :b => {:c => [4,5,6]}}` | `((a 1 2 3) (b (c 4 5 6)))` |
131
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/elparser.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'elparser/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "elparser"
8
+ spec.version = Elparser::VERSION
9
+ spec.authors = ["SAKURAI Masashi"]
10
+ spec.email = ["m.sakurai@kiwanami.net"]
11
+ spec.summary = %q{A parser for S-expression of emacs lisp}
12
+ spec.description = %q{A parser for S-expression of emacs lisp}
13
+ spec.homepage = "https://github.com/kiwanami/ruby-elparser"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+ spec.extra_rdoc_files = ['readme.html']
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.7"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "racc", "~> 1.4"
25
+ spec.add_development_dependency "test-unit", "~> 3.0"
26
+ end
@@ -0,0 +1,3 @@
1
+ module Elparser
2
+ VERSION = "0.0.1"
3
+ end
data/lib/elparser.rb ADDED
@@ -0,0 +1,305 @@
1
+ require "elparser/version"
2
+ require 'elparser/parser.tab.rb'
3
+ require 'strscan'
4
+
5
+ module Elparser
6
+
7
+ class AbstractSExp
8
+ def atom?
9
+ false
10
+ end
11
+ def cons?
12
+ false
13
+ end
14
+ def list?
15
+ false
16
+ end
17
+ def ==(obj)
18
+ self.class == obj.class && self.to_s == obj.to_s
19
+ end
20
+ def visit
21
+ raise "Not implemented!"
22
+ end
23
+ def to_ruby
24
+ raise "Not implemented!"
25
+ end
26
+ end
27
+
28
+ class AbstractSExpAtom < AbstractSExp
29
+ def atom?
30
+ true
31
+ end
32
+ end
33
+
34
+ class SExpNil < AbstractSExpAtom
35
+ def list?
36
+ true
37
+ end
38
+ def to_s
39
+ "nil"
40
+ end
41
+ def visit
42
+ # do nothing
43
+ end
44
+ def to_ruby
45
+ nil
46
+ end
47
+ end
48
+
49
+ class SExpSymbol < AbstractSExpAtom
50
+ attr_reader :name
51
+ def initialize(name)
52
+ @name = name
53
+ end
54
+ def to_s
55
+ @name
56
+ end
57
+ def to_ruby
58
+ @name.to_sym
59
+ end
60
+ end
61
+
62
+ class SExpString < AbstractSExpAtom
63
+ attr_reader :str
64
+ def initialize(str)
65
+ @str = str
66
+ end
67
+ def to_s
68
+ @str.dump
69
+ end
70
+ def to_ruby
71
+ @str
72
+ end
73
+ end
74
+
75
+ class SExpNumber < AbstractSExpAtom
76
+ def self.int(val)
77
+ SExpNumber.new(:INTEGER, val)
78
+ end
79
+ def self.float(val)
80
+ SExpNumber.new(:FLOAT, val)
81
+ end
82
+
83
+ def initialize(type, val)
84
+ @type = type
85
+ @val = val
86
+ end
87
+ def value
88
+ case @type
89
+ when :INTEGER
90
+ @val.to_i
91
+ when :FLOAT
92
+ @val.to_f
93
+ else
94
+ raise "Unknown type #{@type}:#{@val}"
95
+ end
96
+ end
97
+ def to_s
98
+ @val
99
+ end
100
+ def to_ruby
101
+ value
102
+ end
103
+ end
104
+
105
+ class AbstractSExpCons < AbstractSExp
106
+ def cons?
107
+ true
108
+ end
109
+ end
110
+
111
+ class SExpCons < AbstractSExpCons
112
+ attr_reader :car, :cdr
113
+ def initialize(car, cdr)
114
+ @car = car
115
+ @cdr = cdr
116
+ end
117
+ def visit
118
+ @car = yield @car
119
+ @cdr = yield @cdr
120
+ end
121
+ def to_s
122
+ if @cdr.class == SExpList then
123
+ "(#{@car} "+@cdr.list.map{|i| i.to_s }.join(" ")+")"
124
+ else
125
+ "(#{@car} . #{@cdr})"
126
+ end
127
+ end
128
+ def to_ruby
129
+ [@car.to_ruby, @cdr.to_ruby]
130
+ end
131
+ end
132
+
133
+ class SExpList < AbstractSExpCons
134
+ attr_reader :list
135
+ def initialize(list)
136
+ @list = list
137
+ end
138
+ def car
139
+ @list[0]
140
+ end
141
+ def cdr
142
+ if @list.size == 1
143
+ SExpNil.new
144
+ else
145
+ SExpList.new @list.slice(1..-1)
146
+ end
147
+ end
148
+ def list?
149
+ true
150
+ end
151
+ def to_s
152
+ "("+@list.map{|i| i.to_s }.join(" ")+")"
153
+ end
154
+ def visit(&block)
155
+ @list = @list.map(&block)
156
+ end
157
+ def to_ruby
158
+ @list.map {|i| i.to_ruby}
159
+ end
160
+ def alist?
161
+ @list.all? {|i| i.cons? }
162
+ end
163
+ # alist -> hash
164
+ def to_h
165
+ ret = Hash.new
166
+ @list.each do |i|
167
+ ret[i.car.to_ruby] = i.cdr.to_ruby
168
+ end
169
+ ret
170
+ end
171
+ end
172
+
173
+ # (list . last)
174
+ class SExpListDot < AbstractSExpCons
175
+ def initialize(list, last)
176
+ @list = list
177
+ @last = last
178
+ end
179
+ def car
180
+ @list[0]
181
+ end
182
+ def cdr
183
+ if @list.size == 2 then
184
+ SExpCons.new(@list[1], @last)
185
+ else
186
+ SExpListDot.new(@list.slice(1..-1),@last)
187
+ end
188
+ end
189
+ def list?
190
+ false
191
+ end
192
+ def to_s
193
+ "("+@list.map{|i| i.to_s }.join(" ") + " . #{@last.to_s})"
194
+ end
195
+ def visit(&block)
196
+ @list = @list.map(&block)
197
+ @last = block.call(@last)
198
+ end
199
+ def to_ruby
200
+ @list.map {|i| i.to_ruby}.push(@last.to_ruby)
201
+ end
202
+ end
203
+
204
+ class SExpQuoted < AbstractSExp
205
+ def initialize(sexp)
206
+ @sexp = sexp
207
+ end
208
+ def to_s
209
+ "'#{@sexp.to_s}"
210
+ end
211
+ def visit(&blcok)
212
+ @sexp.visit(&block)
213
+ end
214
+ def to_ruby
215
+ [@sexp.to_ruby]
216
+ end
217
+ end
218
+
219
+ # parser class for
220
+ class Parser
221
+
222
+ # parse s-expression string and return sexp objects.
223
+ def parse(str)
224
+ s = StringScanner.new str
225
+ @tokens = []
226
+
227
+ until s.eos?
228
+ s.skip(/\s+/) ? nil :
229
+ s.scan(/\A[-+]?[0-9]*\.[0-9]+(e[-+]?[0-9]+)?/i) ? (@tokens << [:FLOAT, s.matched]) :
230
+ s.scan(/\A[-+]?(0|[1-9]\d*)/) ? (@tokens << [:INTEGER, s.matched]) :
231
+ s.scan(/\A\.(?=\s)/) ? (@tokens << ['.', '.']) :
232
+ s.scan(/\A[a-z\-.\/_:*+=$][a-z\-.\/_:$*+=0-9]*/i) ? (@tokens << [:SYMBOL, s.matched]) :
233
+ s.scan(/\A"(([^\\"]|\\.)*)"/) ? (@tokens << [:STRING, s.matched.slice(1...-1)]) :
234
+ s.scan(/\A./) ? (a = s.matched; @tokens << [a, a]) :
235
+ (raise "scanner error")
236
+ end
237
+ @tokens.push [false, '$end']
238
+
239
+ normalize do_parse
240
+ end
241
+
242
+ def next_token
243
+ @tokens.shift
244
+ end
245
+
246
+ # replace special symbols
247
+ def normalize(ast)
248
+ if ast.class == SExpSymbol
249
+ case ast.name
250
+ when "nil"
251
+ return SExpNil.new
252
+ else
253
+ return ast
254
+ end
255
+ elsif ast.cons? then
256
+ ast.visit do |i|
257
+ normalize(i)
258
+ end
259
+ end
260
+ return ast
261
+ end
262
+ end
263
+
264
+
265
+ # translate ruby objects to s-expression string.
266
+ def self.encode(arg)
267
+ return _encode(arg).to_s
268
+ end
269
+
270
+ private
271
+
272
+ def self._encode(arg)
273
+ return "nil" if arg.nil?
274
+ c = arg.class
275
+ if c == Fixnum then
276
+ return SExpNumber.new :INTEGER, arg.to_s
277
+ elsif c == Float then
278
+ return SExpNumber.new :FLOAT, arg.to_s
279
+ elsif c == String then
280
+ return SExpString.new arg
281
+ elsif c == Symbol then
282
+ return SExpSymbol.new arg.to_s
283
+ elsif c == Array then
284
+ return _encode_array(arg)
285
+ elsif c == Hash then
286
+ return _encode_hash(arg)
287
+ elsif c == TrueClass then
288
+ return SExpSymbol.new "t"
289
+ elsif c == FalseClass then
290
+ return SExpNil.new
291
+ end
292
+ raise "Can't encode object : #{arg}"
293
+ end
294
+
295
+ def self._encode_array(arg)
296
+ return SExpNil.new if arg.nil? || arg.size == 0
297
+ return SExpList.new arg.map{|i| _encode(i)}
298
+ end
299
+
300
+ def self._encode_hash(arg)
301
+ return SExpNil.new if arg.nil? || arg.size == 0
302
+ return SExpList.new arg.map{|k,v| SExpCons.new(_encode(k),_encode(v))}
303
+ end
304
+
305
+ end
data/readme.html ADDED
@@ -0,0 +1,226 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
+ <meta http-equiv="Content-Style-Type" content="text/css" />
6
+ <meta name="generator" content="pandoc" />
7
+ <title></title>
8
+ <style type="text/css">code{white-space: pre;}</style>
9
+ <style type="text/css">
10
+ table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
11
+ margin: 0; padding: 0; vertical-align: baseline; border: none; }
12
+ table.sourceCode { width: 100%; line-height: 100%; }
13
+ td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
14
+ td.sourceCode { padding-left: 5px; }
15
+ code > span.kw { color: #007020; font-weight: bold; }
16
+ code > span.dt { color: #902000; }
17
+ code > span.dv { color: #40a070; }
18
+ code > span.bn { color: #40a070; }
19
+ code > span.fl { color: #40a070; }
20
+ code > span.ch { color: #4070a0; }
21
+ code > span.st { color: #4070a0; }
22
+ code > span.co { color: #60a0b0; font-style: italic; }
23
+ code > span.ot { color: #007020; }
24
+ code > span.al { color: #ff0000; font-weight: bold; }
25
+ code > span.fu { color: #06287e; }
26
+ code > span.er { color: #ff0000; font-weight: bold; }
27
+ </style>
28
+ <link href="data:text/css,body%20%7B%0A%20%20font%2Dfamily%3A%20Helvetica%2C%20arial%2C%20sans%2Dserif%3B%0A%20%20font%2Dsize%3A%2014px%3B%0A%20%20margin%3A%200%20auto%3B%0A%20%20max%2Dwidth%3A%20790px%3B%0A%20%20line%2Dheight%3A%201%2E6%3B%0A%20%20padding%2Dtop%3A%2010px%3B%0A%20%20padding%2Dbottom%3A%2010px%3B%0A%20%20background%2Dcolor%3A%20white%3B%0A%20%20padding%3A%2030px%3B%20%7D%0A%0Abody%20%3E%20%2A%3Afirst%2Dchild%20%7B%0A%20%20margin%2Dtop%3A%200%20%21important%3B%20%7D%0Abody%20%3E%20%2A%3Alast%2Dchild%20%7B%0A%20%20margin%2Dbottom%3A%200%20%21important%3B%20%7D%0A%0Aa%20%7B%0A%20%20color%3A%20%234183C4%3B%20%7D%0Aa%2Eabsent%20%7B%0A%20%20color%3A%20%23cc0000%3B%20%7D%0Aa%2Eanchor%20%7B%0A%20%20display%3A%20block%3B%0A%20%20padding%2Dleft%3A%2030px%3B%0A%20%20margin%2Dleft%3A%20%2D30px%3B%0A%20%20cursor%3A%20pointer%3B%0A%20%20position%3A%20absolute%3B%0A%20%20top%3A%200%3B%0A%20%20left%3A%200%3B%0A%20%20bottom%3A%200%3B%20%7D%0A%0Ah1%20a%2C%20h2%20a%2C%20h3%20a%2C%20h4%20a%2C%20h5%20a%2C%20h6%20a%20%7B%0A%20%20color%3A%20black%20%21important%3B%0A%20%20text%2Ddecoration%3A%20none%20%21important%3B%0A%7D%0A%0Ah1%2C%20h2%2C%20h3%2C%20h4%2C%20h5%2C%20h6%20%7B%0A%20%20margin%3A%2020px%200%2010px%3B%0A%20%20padding%3A%200%3B%0A%20%20font%2Dweight%3A%20bold%3B%0A%20%20%2Dwebkit%2Dfont%2Dsmoothing%3A%20antialiased%3B%0A%20%20cursor%3A%20text%3B%0A%20%20position%3A%20relative%3B%20%7D%0A%0Ah1%3Ahover%20a%2Eanchor%2C%20h2%3Ahover%20a%2Eanchor%2C%20h3%3Ahover%20a%2Eanchor%2C%20h4%3Ahover%20a%2Eanchor%2C%20h5%3Ahover%20a%2Eanchor%2C%20h6%3Ahover%20a%2Eanchor%20%7B%0A%20%20background%3A%20url%28data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw%2FeHBhY2tldCBiZWdpbj0i77u%2FIiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8%2BIDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI%2FPsQhXeAAAABfSURBVHjaYvz%2F%2Fz8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg%3D%3D%29%20no%2Drepeat%2010px%20center%3B%0A%20%20text%2Ddecoration%3A%20none%3B%20%7D%0A%0Ah1%20tt%2C%20h1%20code%20%7B%0A%20%20font%2Dsize%3A%20inherit%3B%20%7D%0A%0Ah2%20tt%2C%20h2%20code%20%7B%0A%20%20font%2Dsize%3A%20inherit%3B%20%7D%0A%0Ah3%20tt%2C%20h3%20code%20%7B%0A%20%20font%2Dsize%3A%20inherit%3B%20%7D%0A%0Ah4%20tt%2C%20h4%20code%20%7B%0A%20%20font%2Dsize%3A%20inherit%3B%20%7D%0A%0Ah5%20tt%2C%20h5%20code%20%7B%0A%20%20font%2Dsize%3A%20inherit%3B%20%7D%0A%0Ah6%20tt%2C%20h6%20code%20%7B%0A%20%20font%2Dsize%3A%20inherit%3B%20%7D%0A%0Ah1%20%7B%0A%20%20font%2Dsize%3A%2028px%3B%0A%20%20color%3A%20black%3B%20%7D%0A%0Ah2%20%7B%0A%20%20font%2Dsize%3A%2024px%3B%0A%20%20border%2Dbottom%3A%201px%20solid%20%23cccccc%3B%0A%20%20color%3A%20black%3B%20%7D%0A%0Ah3%20%7B%0A%20%20font%2Dsize%3A%2018px%3B%20%7D%0A%0Ah4%20%7B%0A%20%20font%2Dsize%3A%2016px%3B%20%7D%0A%0Ah5%20%7B%0A%20%20font%2Dsize%3A%2014px%3B%20%7D%0A%0Ah6%20%7B%0A%20%20color%3A%20%23777777%3B%0A%20%20font%2Dsize%3A%2014px%3B%20%7D%0A%0Ap%2C%20blockquote%2C%20ul%2C%20ol%2C%20dl%2C%20li%2C%20table%2C%20pre%20%7B%0A%20%20margin%3A%2015px%200%3B%20%7D%0A%0Ahr%20%7B%0A%20%20background%3A%20transparent%20url%28data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw%2FeHBhY2tldCBiZWdpbj0i77u%2FIiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8%2BIDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI%2FPqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC%29%20repeat%2Dx%200%200%3B%0A%20%20border%3A%200%20none%3B%0A%20%20color%3A%20%23cccccc%3B%0A%20%20height%3A%204px%3B%0A%20%20padding%3A%200%3B%20%7D%0A%0Abody%20%3E%20h2%3Afirst%2Dchild%20%7B%0A%20%20margin%2Dtop%3A%200%3B%0A%20%20padding%2Dtop%3A%200%3B%20%7D%0Abody%20%3E%20h1%3Afirst%2Dchild%20%7B%0A%20%20margin%2Dtop%3A%200%3B%0A%20%20padding%2Dtop%3A%200%3B%20%7D%0A%20%20body%20%3E%20h1%3Afirst%2Dchild%20%2B%20h2%20%7B%0A%20%20%20%20margin%2Dtop%3A%200%3B%0A%20%20%20%20padding%2Dtop%3A%200%3B%20%7D%0Abody%20%3E%20h3%3Afirst%2Dchild%2C%20body%20%3E%20h4%3Afirst%2Dchild%2C%20body%20%3E%20h5%3Afirst%2Dchild%2C%20body%20%3E%20h6%3Afirst%2Dchild%20%7B%0A%20%20margin%2Dtop%3A%200%3B%0A%20%20padding%2Dtop%3A%200%3B%20%7D%0A%0Aa%3Afirst%2Dchild%20h1%2C%20a%3Afirst%2Dchild%20h2%2C%20a%3Afirst%2Dchild%20h3%2C%20a%3Afirst%2Dchild%20h4%2C%20a%3Afirst%2Dchild%20h5%2C%20a%3Afirst%2Dchild%20h6%20%7B%0A%20%20margin%2Dtop%3A%200%3B%0A%20%20padding%2Dtop%3A%200%3B%20%7D%0A%0Ah1%20p%2C%20h2%20p%2C%20h3%20p%2C%20h4%20p%2C%20h5%20p%2C%20h6%20p%20%7B%0A%20%20margin%2Dtop%3A%200%3B%20%7D%0A%0Ali%20p%2Efirst%20%7B%0A%20%20display%3A%20inline%2Dblock%3B%20%7D%0A%0Aul%2C%20ol%20%7B%0A%20%20padding%2Dleft%3A%2030px%3B%20%7D%0A%0Aul%20%3Afirst%2Dchild%2C%20ol%20%3Afirst%2Dchild%20%7B%0A%20%20margin%2Dtop%3A%200%3B%20%7D%0A%0Aul%20%3Alast%2Dchild%2C%20ol%20%3Alast%2Dchild%20%7B%0A%20%20margin%2Dbottom%3A%200%3B%20%7D%0A%0Adl%20%7B%0A%20%20padding%3A%200%3B%20%7D%0A%20%20dl%20dt%20%7B%0A%20%20%20%20font%2Dsize%3A%2014px%3B%0A%20%20%20%20font%2Dweight%3A%20bold%3B%0A%20%20%20%20font%2Dstyle%3A%20italic%3B%0A%20%20%20%20padding%3A%200%3B%0A%20%20%20%20margin%3A%2015px%200%205px%3B%20%7D%0A%20%20%20%20dl%20dt%3Afirst%2Dchild%20%7B%0A%20%20%20%20%20%20padding%3A%200%3B%20%7D%0A%20%20%20%20dl%20dt%20%3E%20%3Afirst%2Dchild%20%7B%0A%20%20%20%20%20%20margin%2Dtop%3A%200%3B%20%7D%0A%20%20%20%20dl%20dt%20%3E%20%3Alast%2Dchild%20%7B%0A%20%20%20%20%20%20margin%2Dbottom%3A%200%3B%20%7D%0A%20%20dl%20dd%20%7B%0A%20%20%20%20margin%3A%200%200%2015px%3B%0A%20%20%20%20padding%3A%200%2015px%3B%20%7D%0A%20%20%20%20dl%20dd%20%3E%20%3Afirst%2Dchild%20%7B%0A%20%20%20%20%20%20margin%2Dtop%3A%200%3B%20%7D%0A%20%20%20%20dl%20dd%20%3E%20%3Alast%2Dchild%20%7B%0A%20%20%20%20%20%20margin%2Dbottom%3A%200%3B%20%7D%0A%0Ablockquote%20%7B%0A%20%20border%2Dleft%3A%204px%20solid%20%23dddddd%3B%0A%20%20padding%3A%200%2015px%3B%0A%20%20color%3A%20%23777777%3B%20%7D%0A%20%20blockquote%20%3E%20%3Afirst%2Dchild%20%7B%0A%20%20%20%20margin%2Dtop%3A%200%3B%20%7D%0A%20%20blockquote%20%3E%20%3Alast%2Dchild%20%7B%0A%20%20%20%20margin%2Dbottom%3A%200%3B%20%7D%0A%0Atable%20%7B%0A%20%20padding%3A%200%3B%20%7D%0A%20%20table%20tr%20%7B%0A%20%20%20%20border%2Dtop%3A%201px%20solid%20%23cccccc%3B%0A%20%20%20%20background%2Dcolor%3A%20white%3B%0A%20%20%20%20margin%3A%200%3B%0A%20%20%20%20padding%3A%200%3B%20%7D%0A%20%20%20%20table%20tr%3Anth%2Dchild%282n%29%20%7B%0A%20%20%20%20%20%20background%2Dcolor%3A%20%23f8f8f8%3B%20%7D%0A%20%20%20%20table%20tr%20th%20%7B%0A%20%20%20%20%20%20font%2Dweight%3A%20bold%3B%0A%20%20%20%20%20%20border%3A%201px%20solid%20%23cccccc%3B%0A%20%20%20%20%20%20text%2Dalign%3A%20left%3B%0A%20%20%20%20%20%20margin%3A%200%3B%0A%20%20%20%20%20%20padding%3A%206px%2013px%3B%20%7D%0A%20%20%20%20table%20tr%20td%20%7B%0A%20%20%20%20%20%20border%3A%201px%20solid%20%23cccccc%3B%0A%20%20%20%20%20%20text%2Dalign%3A%20left%3B%0A%20%20%20%20%20%20margin%3A%200%3B%0A%20%20%20%20%20%20padding%3A%206px%2013px%3B%20%7D%0A%20%20%20%20table%20tr%20th%20%3Afirst%2Dchild%2C%20table%20tr%20td%20%3Afirst%2Dchild%20%7B%0A%20%20%20%20%20%20margin%2Dtop%3A%200%3B%20%7D%0A%20%20%20%20table%20tr%20th%20%3Alast%2Dchild%2C%20table%20tr%20td%20%3Alast%2Dchild%20%7B%0A%20%20%20%20%20%20margin%2Dbottom%3A%200%3B%20%7D%0A%0Aimg%20%7B%0A%20%20max%2Dwidth%3A%20100%25%3B%20%7D%0A%0Aspan%2Eframe%20%7B%0A%20%20display%3A%20block%3B%0A%20%20overflow%3A%20hidden%3B%20%7D%0A%20%20span%2Eframe%20%3E%20span%20%7B%0A%20%20%20%20border%3A%201px%20solid%20%23dddddd%3B%0A%20%20%20%20display%3A%20block%3B%0A%20%20%20%20float%3A%20left%3B%0A%20%20%20%20overflow%3A%20hidden%3B%0A%20%20%20%20margin%3A%2013px%200%200%3B%0A%20%20%20%20padding%3A%207px%3B%0A%20%20%20%20width%3A%20auto%3B%20%7D%0A%20%20span%2Eframe%20span%20img%20%7B%0A%20%20%20%20display%3A%20block%3B%0A%20%20%20%20float%3A%20left%3B%20%7D%0A%20%20span%2Eframe%20span%20span%20%7B%0A%20%20%20%20clear%3A%20both%3B%0A%20%20%20%20color%3A%20%23333333%3B%0A%20%20%20%20display%3A%20block%3B%0A%20%20%20%20padding%3A%205px%200%200%3B%20%7D%0Aspan%2Ealign%2Dcenter%20%7B%0A%20%20display%3A%20block%3B%0A%20%20overflow%3A%20hidden%3B%0A%20%20clear%3A%20both%3B%20%7D%0A%20%20span%2Ealign%2Dcenter%20%3E%20span%20%7B%0A%20%20%20%20display%3A%20block%3B%0A%20%20%20%20overflow%3A%20hidden%3B%0A%20%20%20%20margin%3A%2013px%20auto%200%3B%0A%20%20%20%20text%2Dalign%3A%20center%3B%20%7D%0A%20%20span%2Ealign%2Dcenter%20span%20img%20%7B%0A%20%20%20%20margin%3A%200%20auto%3B%0A%20%20%20%20text%2Dalign%3A%20center%3B%20%7D%0Aspan%2Ealign%2Dright%20%7B%0A%20%20display%3A%20block%3B%0A%20%20overflow%3A%20hidden%3B%0A%20%20clear%3A%20both%3B%20%7D%0A%20%20span%2Ealign%2Dright%20%3E%20span%20%7B%0A%20%20%20%20display%3A%20block%3B%0A%20%20%20%20overflow%3A%20hidden%3B%0A%20%20%20%20margin%3A%2013px%200%200%3B%0A%20%20%20%20text%2Dalign%3A%20right%3B%20%7D%0A%20%20span%2Ealign%2Dright%20span%20img%20%7B%0A%20%20%20%20margin%3A%200%3B%0A%20%20%20%20text%2Dalign%3A%20right%3B%20%7D%0Aspan%2Efloat%2Dleft%20%7B%0A%20%20display%3A%20block%3B%0A%20%20margin%2Dright%3A%2013px%3B%0A%20%20overflow%3A%20hidden%3B%0A%20%20float%3A%20left%3B%20%7D%0A%20%20span%2Efloat%2Dleft%20span%20%7B%0A%20%20%20%20margin%3A%2013px%200%200%3B%20%7D%0Aspan%2Efloat%2Dright%20%7B%0A%20%20display%3A%20block%3B%0A%20%20margin%2Dleft%3A%2013px%3B%0A%20%20overflow%3A%20hidden%3B%0A%20%20float%3A%20right%3B%20%7D%0A%20%20span%2Efloat%2Dright%20%3E%20span%20%7B%0A%20%20%20%20display%3A%20block%3B%0A%20%20%20%20overflow%3A%20hidden%3B%0A%20%20%20%20margin%3A%2013px%20auto%200%3B%0A%20%20%20%20text%2Dalign%3A%20right%3B%20%7D%0A%0Acode%2C%20tt%20%7B%0A%20%20margin%3A%200%202px%3B%0A%20%20padding%3A%200%205px%3B%0A%20%20white%2Dspace%3A%20nowrap%3B%0A%20%20border%3A%201px%20solid%20%23eaeaea%3B%0A%20%20background%2Dcolor%3A%20%23f8f8f8%3B%0A%20%20border%2Dradius%3A%203px%3B%20%7D%0A%0Apre%20code%20%7B%0A%20%20margin%3A%200%3B%0A%20%20padding%3A%200%3B%0A%20%20white%2Dspace%3A%20pre%3B%0A%20%20border%3A%20none%3B%0A%20%20background%3A%20transparent%3B%20%7D%0A%0A%2Ehighlight%20pre%20%7B%0A%20%20background%2Dcolor%3A%20%23f8f8f8%3B%0A%20%20border%3A%201px%20solid%20%23cccccc%3B%0A%20%20font%2Dsize%3A%2013px%3B%0A%20%20line%2Dheight%3A%2019px%3B%0A%20%20overflow%3A%20auto%3B%0A%20%20padding%3A%206px%2010px%3B%0A%20%20border%2Dradius%3A%203px%3B%20%7D%0A%0Apre%20%7B%0A%20%20background%2Dcolor%3A%20%23f8f8f8%3B%0A%20%20border%3A%201px%20solid%20%23cccccc%3B%0A%20%20font%2Dsize%3A%2013px%3B%0A%20%20line%2Dheight%3A%2019px%3B%0A%20%20overflow%3A%20auto%3B%0A%20%20padding%3A%206px%2010px%3B%0A%20%20border%2Dradius%3A%203px%3B%20%7D%0A%20%20pre%20code%2C%20pre%20tt%20%7B%0A%20%20%20%20background%2Dcolor%3A%20transparent%3B%0A%20%20%20%20border%3A%20none%3B%20%7D%0A%0A%2Efigure%20%7B%0A%20%20%20display%3A%20block%3B%0A%20%20%20text%2Dalign%3A%20center%3B%0A%20%20%20margin%3A%2010px%200%2010px%200%3B%0A%20%20%20padding%3A%2010px%2010px%200px%2010px%3B%0A%20%20%20border%3A%202px%20solid%20%23eaeaea%3B%0A%20%20%20background%2Dcolor%3A%20%23f8f8f8%3B%0A%20%20%20border%2Dradius%3A%203px%3B%0A%7D%0A%0A%2Efigure%20img%20%7B%0A%20%20%20max%2Dwidth%3A%20700px%3B%0A%20%20%20background%2Dcolor%3A%20white%3B%0A%7D%0A%0A%2Ecaption%20%7B%0A%20%20%20font%2Dsize%3A%2016px%3B%0A%20%20%20font%2Dweight%3A%20bold%3B%0A%20%20%20%2Dwebkit%2Dfont%2Dsmoothing%3A%20antialiased%3B%0A%7D%0A" rel="stylesheet" type="text/css" />
29
+ </head>
30
+ <body>
31
+ <div id="TOC">
32
+ <ul>
33
+ <li><a href="#elparser">Elparser</a><ul>
34
+ <li><a href="#sample-code">Sample code</a><ul>
35
+ <li><a href="#parsing-s-exp-and-getting-ruby-objects">Parsing S-exp and getting ruby objects</a></li>
36
+ <li><a href="#encoding-ruby-objects-into-s-exp">Encoding ruby objects into S-exp</a></li>
37
+ </ul></li>
38
+ <li><a href="#installation">Installation</a></li>
39
+ <li><a href="#api-document">API Document</a><ul>
40
+ <li><a href="#parser">Parser</a></li>
41
+ <li><a href="#encoder">Encoder</a></li>
42
+ <li><a href="#object-mapping">Object Mapping</a></li>
43
+ </ul></li>
44
+ </ul></li>
45
+ </ul>
46
+ </div>
47
+ <h1 id="elparser"><a href="#elparser">Elparser</a></h1>
48
+ <p>A parser for S-expression of emacs lisp and some utilities.</p>
49
+ <h2 id="sample-code"><a href="#sample-code">Sample code</a></h2>
50
+ <h3 id="parsing-s-exp-and-getting-ruby-objects"><a href="#parsing-s-exp-and-getting-ruby-objects">Parsing S-exp and getting ruby objects</a></h3>
51
+ <pre class="sourceCode ruby"><code class="sourceCode ruby">require <span class="st">'elparser'</span>
52
+
53
+ parser = <span class="dt">Elparser</span>::<span class="dt">Parser</span>.new
54
+
55
+ <span class="co"># list and literals</span>
56
+ obj1 = parser.parse(<span class="st">&quot;(1 2.3 a \&quot;b\&quot; () (c 'd))&quot;</span>)
57
+
58
+ p obj1.to_ruby
59
+ <span class="co"># =&gt; [1, 2.3, :a, &quot;b&quot;, nil, [:c, [:d]]]</span>
60
+
61
+
62
+ <span class="co"># alist and hash</span>
63
+ obj2 = parser.parse(<span class="st">&quot;( (a . 1) (b . \&quot;xxx\&quot;) (c 3 4) (\&quot;d\&quot; . \&quot;e\&quot;))&quot;</span>)
64
+
65
+ p obj2.to_ruby
66
+ <span class="co"># =&gt; [[:a, 1], [:b, &quot;xxx&quot;], [:c, 3, 4], [&quot;d&quot;, &quot;e&quot;]] </span>
67
+
68
+ p obj2.to_h
69
+ <span class="co"># =&gt; {:a=&gt;1, :b=&gt;&quot;xxx&quot;, :c=&gt;[3, 4], &quot;d&quot;=&gt;&quot;e&quot;} </span></code></pre>
70
+ <h3 id="encoding-ruby-objects-into-s-exp"><a href="#encoding-ruby-objects-into-s-exp">Encoding ruby objects into S-exp</a></h3>
71
+ <pre class="sourceCode ruby"><code class="sourceCode ruby">p <span class="dt">Elparser</span>::encode([<span class="dv">1</span>,<span class="fl">1.2</span>,-<span class="dv">4</span>,<span class="st">&quot;xxx&quot;</span>,<span class="st">:www</span>,<span class="dv">true</span>,<span class="dv">nil</span>])
72
+ <span class="co"># =&gt; &quot;(1 1.2 -4 \&quot;xxx\&quot; www t nil)&quot;</span>
73
+
74
+ p <span class="dt">Elparser</span>::encode({<span class="st">:a</span> =&gt; [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>], <span class="st">:b</span> =&gt; {<span class="st">:c</span> =&gt; [<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span>]}})
75
+ <span class="co"># =&gt; &quot;((a 1 2 3) (b (c 4 5 6)))&quot;</span></code></pre>
76
+ <h2 id="installation"><a href="#installation">Installation</a></h2>
77
+ <p>Add this line to your application's Gemfile:</p>
78
+ <pre class="sourceCode ruby"><code class="sourceCode ruby">gem <span class="st">'elparser'</span></code></pre>
79
+ <p>And then execute:</p>
80
+ <pre><code>$ bundle</code></pre>
81
+ <p>Or install it yourself as:</p>
82
+ <pre><code>$ gem install elparser</code></pre>
83
+ <h2 id="api-document"><a href="#api-document">API Document</a></h2>
84
+ <h3 id="parser"><a href="#parser">Parser</a></h3>
85
+ <p>The class <code>Elparser::Parser</code> is parser for emacs-lisp S-expression. The user program creates an instance of the class and parses the S-exp string with <code>parse</code> method.</p>
86
+ <p>If the <code>parse</code> method succeed in parsing the given S-exp string, it returns a <code>SExp</code> object which is AST of S-exp. Invoking <code>to_ruby</code> method of the <code>SExp</code> object, one can obtain a ruby object.</p>
87
+ <p>The <code>SExp</code> objects are instances of <code>SExpXXX</code> classes: <code>SExpNumber</code>, <code>SExpString</code>, <code>SExpSymbol</code>, <code>SExpNil</code>, <code>SExpCons</code>, <code>SExpList</code>, <code>SExpListDot</code> and <code>SExpQuoted</code>. Each classes represent corresponding S-exp objects.</p>
88
+ <p>If the given S-exp list is an alist, invoking <code>SExpList#to_h</code> method, a <code>Hash</code> object can be obtained.</p>
89
+ <h3 id="encoder"><a href="#encoder">Encoder</a></h3>
90
+ <p>The module method <code>Elparser::encode</code> encodes the ruby objects into elisp S-expressions.</p>
91
+ <p>If an object which is not defined in serialization rules is given, this method raises the exception <code>StandardError</code> with some messages. See the next section for the encoding detail.</p>
92
+ <h3 id="object-mapping"><a href="#object-mapping">Object Mapping</a></h3>
93
+ <p>The primitive objects are translated straightforwardly.</p>
94
+ <h4 id="decoding-s-expression---ruby"><a href="#decoding-s-expression---ruby">Decoding (S-expression -&gt; Ruby)</a></h4>
95
+ <p>A quoted expression is translated to an array. Both <code>nil</code> and <code>()</code> are translated to <code>nil</code>. Cons cells and lists are translated to arrays.</p>
96
+ <table>
97
+ <thead>
98
+ <tr class="header">
99
+ <th align="left">type</th>
100
+ <th align="left">S-exp (input)</th>
101
+ <th align="left">Ruby (output)</th>
102
+ </tr>
103
+ </thead>
104
+ <tbody>
105
+ <tr class="odd">
106
+ <td align="left">integer</td>
107
+ <td align="left"><code>1</code></td>
108
+ <td align="left"><code>1</code></td>
109
+ </tr>
110
+ <tr class="even">
111
+ <td align="left">float</td>
112
+ <td align="left"><code>1.2</code></td>
113
+ <td align="left"><code>1.2</code></td>
114
+ </tr>
115
+ <tr class="odd">
116
+ <td align="left">float</td>
117
+ <td align="left"><code>1e4</code></td>
118
+ <td align="left"><code>1e4</code></td>
119
+ </tr>
120
+ <tr class="even">
121
+ <td align="left">float</td>
122
+ <td align="left"><code>.45</code></td>
123
+ <td align="left"><code>.45</code></td>
124
+ </tr>
125
+ <tr class="odd">
126
+ <td align="left">symbol</td>
127
+ <td align="left"><code>abc</code></td>
128
+ <td align="left"><code>:abc</code></td>
129
+ </tr>
130
+ <tr class="even">
131
+ <td align="left">string</td>
132
+ <td align="left"><code>&quot;abc&quot;</code></td>
133
+ <td align="left"><code>&quot;abc&quot;</code></td>
134
+ </tr>
135
+ <tr class="odd">
136
+ <td align="left">quote</td>
137
+ <td align="left"><code>'abc</code></td>
138
+ <td align="left"><code>[:abc]</code></td>
139
+ </tr>
140
+ <tr class="even">
141
+ <td align="left">null</td>
142
+ <td align="left"><code>nil</code></td>
143
+ <td align="left"><code>nil</code></td>
144
+ </tr>
145
+ <tr class="odd">
146
+ <td align="left">empty list</td>
147
+ <td align="left"><code>()</code></td>
148
+ <td align="left"><code>nil</code></td>
149
+ </tr>
150
+ <tr class="even">
151
+ <td align="left">list</td>
152
+ <td align="left"><code>(1 2)</code></td>
153
+ <td align="left"><code>[1,2]</code></td>
154
+ </tr>
155
+ <tr class="odd">
156
+ <td align="left">nest list</td>
157
+ <td align="left"><code>(a (b))</code></td>
158
+ <td align="left"><code>[:a [:b]]</code></td>
159
+ </tr>
160
+ <tr class="even">
161
+ <td align="left">cons cell</td>
162
+ <td align="left"><code>(a . b)</code></td>
163
+ <td align="left"><code>[:a,:b]</code></td>
164
+ </tr>
165
+ <tr class="odd">
166
+ <td align="left">dot list</td>
167
+ <td align="left"><code>(a b . d)</code></td>
168
+ <td align="left"><code>[:a,:b,:c]</code></td>
169
+ </tr>
170
+ <tr class="even">
171
+ <td align="left">alist(<code>to_ruby</code>)</td>
172
+ <td align="left"><code>((a . 1) (b . 2))</code></td>
173
+ <td align="left"><code>[[:a,1],[:b,2]]</code></td>
174
+ </tr>
175
+ <tr class="odd">
176
+ <td align="left">alist(<code>to_h</code>)</td>
177
+ <td align="left"><code>((a . 1) (b . 2))</code></td>
178
+ <td align="left"><code>{:a=&gt;1,:b=&gt;2}</code></td>
179
+ </tr>
180
+ <tr class="even">
181
+ <td align="left">alist list</td>
182
+ <td align="left"><code>((a 1 2) (b . 3))</code></td>
183
+ <td align="left"><code>{:a=&gt;[1,2],:b=&gt;3}</code></td>
184
+ </tr>
185
+ </tbody>
186
+ </table>
187
+ <h4 id="encoding-ruby---s-expression"><a href="#encoding-ruby---s-expression">Encoding (Ruby -&gt; S-expression)</a></h4>
188
+ <p>The Array and Hash objects are translated to lists and alist respectively. Cons cells and quoted expressions can't be expressed by any Ruby object. If those S-expressions are needed, one can obtain such S-expressions with creating instances of <code>SExpCons</code> and <code>SExpQuoted</code> directly and calling the <code>to_s</code> method.</p>
189
+ <table>
190
+ <thead>
191
+ <tr class="header">
192
+ <th align="left">type</th>
193
+ <th align="left">Ruby (input)</th>
194
+ <th align="left">S-exp (output)</th>
195
+ </tr>
196
+ </thead>
197
+ <tbody>
198
+ <tr class="odd">
199
+ <td align="left">primitive</td>
200
+ <td align="left"><code>[1,1.2,-4,&quot;xxx&quot;,:www,true,nil]</code></td>
201
+ <td align="left"><code>(1 1.2 -4 &quot;xxx&quot; www t nil)</code></td>
202
+ </tr>
203
+ <tr class="even">
204
+ <td align="left">empty list</td>
205
+ <td align="left"><code>[]</code></td>
206
+ <td align="left"><code>nil</code></td>
207
+ </tr>
208
+ <tr class="odd">
209
+ <td align="left">nest list</td>
210
+ <td align="left"><code>[1,[2,[3,4]]]</code></td>
211
+ <td align="left"><code>(1 (2 (3 4)))</code></td>
212
+ </tr>
213
+ <tr class="even">
214
+ <td align="left">hash</td>
215
+ <td align="left"><code>{&quot;a&quot; =&gt; &quot;b&quot;, &quot;c&quot; =&gt; &quot;d&quot;}</code></td>
216
+ <td align="left"><code>((&quot;a&quot; . &quot;b&quot;) (&quot;c&quot; . &quot;d&quot;))</code></td>
217
+ </tr>
218
+ <tr class="odd">
219
+ <td align="left">hash</td>
220
+ <td align="left"><code>{:a =&gt; [1,2,3], :b =&gt; {:c =&gt; [4,5,6]}}</code></td>
221
+ <td align="left"><code>((a 1 2 3) (b (c 4 5 6)))</code></td>
222
+ </tr>
223
+ </tbody>
224
+ </table>
225
+ </body>
226
+ </html>
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elparser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - SAKURAI Masashi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: racc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: A parser for S-expression of emacs lisp
70
+ email:
71
+ - m.sakurai@kiwanami.net
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files:
75
+ - readme.html
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - elparser.gemspec
83
+ - lib/elparser.rb
84
+ - lib/elparser/version.rb
85
+ - readme.html
86
+ homepage: https://github.com/kiwanami/ruby-elparser
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.4.3
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: A parser for S-expression of emacs lisp
110
+ test_files: []