bracer 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 +7 -0
- data/.gitignore +1 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +89 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/lib/sexpistol.rb +2 -0
- data/lib/sexpistol/sexpistol.rb +76 -0
- data/lib/sexpistol/sexpistol_parser.rb +64 -0
- data/sexpistol.gemspec +70 -0
- data/test/performance/benchmark_test.rb +46 -0
- data/test/setup/test_unit_extensions.rb +21 -0
- data/test/test_helper.rb +10 -0
- data/test/unit/float_literal_test.rb +40 -0
- data/test/unit/integer_literal_test.rb +24 -0
- data/test/unit/ruby_keyword_literals_test.rb +45 -0
- data/test/unit/scheme_compatability_test.rb +46 -0
- data/test/unit/string_literal_test.rb +39 -0
- data/test/unit/structure_test.rb +30 -0
- data/test/unit/symbol_test.rb +74 -0
- data/test/unit/to_sexp_test.rb +51 -0
- metadata +81 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c8b71bbf9c678ae9d2e8a33ccc8dc54bb0a04683
|
4
|
+
data.tar.gz: 2d7f04f3b5cf21afefe7a3ea9855f6be80d28ea2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 58bea8f8543d81af5ecb11f3da3d2ca878ef75e99c3126f47bfaf19a129c7ccbe5c434cf52cca2410fa2de1fc005cccb332827c9c711f8bf034d4b8c2a991467
|
7
|
+
data.tar.gz: 749658b045ace5f741332ed8ee5d1f127a1db8e9b1e38a885964a5eeeb6b97909b6564825024526373059a9357512b238d990c13280b9b7a8915c9016d7a137d
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Aaron Gough (http://thingsaaronmade.com/)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
= Sexpistol
|
2
|
+
|
3
|
+
Sexpistol is a very fast and easy-to-use library for parsing S-Expressions in Ruby. Sexpistol takes an S-Expression in string form and turns it into a native Ruby data structure made up of nested sets of arrays.
|
4
|
+
|
5
|
+
=== Example
|
6
|
+
|
7
|
+
(define test (lambda () (
|
8
|
+
(print "Hello world!\n")
|
9
|
+
(print 1)
|
10
|
+
(print 9.01)
|
11
|
+
(print 2.0e10)
|
12
|
+
(print (+ 10 12 13))
|
13
|
+
)))
|
14
|
+
|
15
|
+
would be parsed by Sexpistol like so:
|
16
|
+
|
17
|
+
[:define, :test, [:lambda, [], [
|
18
|
+
[:print, "Hello world!\n"],
|
19
|
+
[:print, 1],
|
20
|
+
[:print, 9.01],
|
21
|
+
[:print, 2.0e10],
|
22
|
+
[:print, [:+, 10, 12, 13]]
|
23
|
+
]]]
|
24
|
+
|
25
|
+
=== Type mappings
|
26
|
+
|
27
|
+
Sexpistol supports all of the standard datatypes and converts them directly to their Ruby equivalents:
|
28
|
+
|
29
|
+
* Lists (a b c)
|
30
|
+
* Integers (1 2 3)
|
31
|
+
* Floats (1.0 2.0 42.9 3e6 1.2e2)
|
32
|
+
* Strings ("\t\"Hello world!\"\n")
|
33
|
+
* Symbols (symbol Symbol ____symbol____ symbo_l symbol? symbol! + - / ++ a+ e$, etc...)
|
34
|
+
|
35
|
+
Sexpistol also supports mapping the Ruby keyword literals (nil, true, false) to their native Ruby types, although this is disabled by default for compatibility. To enable it use `@parser.ruby_keyword_literals = true`, eg:
|
36
|
+
|
37
|
+
@parser = Sexpistol.new
|
38
|
+
@parser.parse_string("nil false true")
|
39
|
+
#=> [:nil, :false, :true]
|
40
|
+
|
41
|
+
@parser.ruby_keyword_literals = true
|
42
|
+
@parser.parse_string("nil false true")
|
43
|
+
#=> [nil, false, true]
|
44
|
+
|
45
|
+
== Scheme compatibility
|
46
|
+
|
47
|
+
Above all Sexpistol strives to be compatible with Scheme-style S-Expressions. This means that Sexpistol supports comma quoting, though quasi-quoting is not yet implemented. Sexpistol can also generate Scheme compatible external representations when the 'scheme_compatability' options is set to true:
|
48
|
+
|
49
|
+
@parser = Sexpistol.new
|
50
|
+
@parser.scheme_compatability = true
|
51
|
+
@parser.to_sexp([:test, false, true, nil])
|
52
|
+
#=> "(test #f #t ())"
|
53
|
+
|
54
|
+
=== Installation
|
55
|
+
|
56
|
+
For convenience Sexpistol is packaged as a RubyGem, to install it simply enter the following at your command line:
|
57
|
+
|
58
|
+
gem install sexpistol
|
59
|
+
|
60
|
+
=== Usage
|
61
|
+
|
62
|
+
# Create a new parser instance
|
63
|
+
@parser = Sexpistol.new
|
64
|
+
|
65
|
+
# Parse a string
|
66
|
+
ast = @parser.parse_string("(string (to (parse)))")
|
67
|
+
#=> [:string, [:to, [:parse]]]
|
68
|
+
|
69
|
+
# Change the representation
|
70
|
+
ast[1][0] = :is
|
71
|
+
ast[1][1][0] = :parsed
|
72
|
+
#=> [:string, [:is, [:parsed]]]
|
73
|
+
|
74
|
+
# Turn the array structure back into an S-Expression
|
75
|
+
@parser.to_sexp( ast )
|
76
|
+
#=> "( string ( is ( parsed ) ) )"
|
77
|
+
|
78
|
+
=== Performance
|
79
|
+
|
80
|
+
The core of Sexpistol was recently re-written using StringScanner and the new version is roughly twice as fast as the older ones.
|
81
|
+
|
82
|
+
Parsing throughput on my test machine (2Ghz Core 2 Duo, 4GB RAM, Ruby 1.9) is approximately 1 Megabytes/sec. This is fairly high given that Sexpistol is pure Ruby. Benchmarking Sexpistol against other popular S-Expression parser gems shows that it is roughly 8x faster than the nearest competitor.
|
83
|
+
|
84
|
+
=== Author & Credits
|
85
|
+
|
86
|
+
Author:: {Aaron Gough}[mailto:aaron@aarongough.com]
|
87
|
+
Contributors:: {Shane Hanna}[http://github.com/shanna]
|
88
|
+
|
89
|
+
Copyright (c) 2010 {Aaron Gough}[http://thingsaaronmade.com/] ({thingsaaronmade.com}[http://thingsaaronmade.com/]), released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rdoc/task'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'jeweler'
|
10
|
+
Jeweler::Tasks.new do |gemspec|
|
11
|
+
gemspec.name = "sexpistol"
|
12
|
+
gemspec.summary = "An S-Expression Parser Library for Ruby"
|
13
|
+
gemspec.description = "Sexpistol is an easy-to-use S-Expression parser for Ruby. It is fast and has no dependencies."
|
14
|
+
gemspec.email = "aaron@aarongough.com"
|
15
|
+
gemspec.homepage = "http://github.com/aarongough/sexpistol"
|
16
|
+
gemspec.authors = ["Aaron Gough"]
|
17
|
+
gemspec.rdoc_options << '--line-numbers' << '--inline-source'
|
18
|
+
gemspec.extra_rdoc_files = ['README.rdoc', 'MIT-LICENSE']
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
desc 'Test sexpistol.'
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'lib/*.rb'
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
30
|
+
t.verbose = true
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
desc 'Generate documentation for sexpistol.'
|
35
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
36
|
+
rdoc.rdoc_dir = 'rdoc'
|
37
|
+
rdoc.title = 'Koi'
|
38
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
39
|
+
rdoc.rdoc_files.include('README.rdoc')
|
40
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
41
|
+
rdoc.rdoc_files.include('app/**/*.rb')
|
42
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.7
|
data/lib/sexpistol.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# This class contains our logic for parsing
|
2
|
+
# S-Expressions. They are turned into a
|
3
|
+
# native Ruby representation like:
|
4
|
+
# [:def, :something [:lambda, [:a], [:do_something]]]
|
5
|
+
class Bracer
|
6
|
+
|
7
|
+
attr_accessor :ruby_keyword_literals, :scheme_compatability
|
8
|
+
|
9
|
+
# Parse a string containing an S-Expression into a
|
10
|
+
# nested set of Ruby arrays
|
11
|
+
def parse_string(string)
|
12
|
+
tree = BracerParser.new(string).parse
|
13
|
+
return convert_ruby_keyword_literals(tree) if(@ruby_keyword_literals)
|
14
|
+
return tree
|
15
|
+
end
|
16
|
+
|
17
|
+
# Convert symbols corresponding to Ruby's keyword literals
|
18
|
+
# into their literal forms
|
19
|
+
def convert_ruby_keyword_literals(expression)
|
20
|
+
return recursive_map(expression) do |x|
|
21
|
+
case x
|
22
|
+
when :'nil' then nil
|
23
|
+
when :'true' then true
|
24
|
+
when :'false' then false
|
25
|
+
else x
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Convert nil, true and false into (), #t and #f for compatability
|
31
|
+
# with Scheme
|
32
|
+
def convert_scheme_literals(data)
|
33
|
+
return recursive_map(data) do |x|
|
34
|
+
case x
|
35
|
+
when nil then []
|
36
|
+
when true then :"#t"
|
37
|
+
when false then :"#f"
|
38
|
+
else x
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Convert a set of nested arrays back into an S-Expression
|
44
|
+
def to_sexp(data)
|
45
|
+
data = convert_scheme_literals(data) if(@scheme_compatability)
|
46
|
+
if( data.is_a?(Array))
|
47
|
+
mapped = data.map do |item|
|
48
|
+
if( item.is_a?(Array))
|
49
|
+
to_sexp(item)
|
50
|
+
else
|
51
|
+
item.to_s
|
52
|
+
end
|
53
|
+
end
|
54
|
+
"[" + mapped.join(" ") + "]"
|
55
|
+
else
|
56
|
+
data.to_s
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def recursive_map(data, &block)
|
63
|
+
if(data.is_a?(Array))
|
64
|
+
return data.map do |x|
|
65
|
+
if(x.is_a?(Array))
|
66
|
+
recursive_map(x, &block)
|
67
|
+
else
|
68
|
+
block.call(x)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
else
|
72
|
+
block.call(data)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
class BracerParser < StringScanner
|
4
|
+
|
5
|
+
def initialize(string)
|
6
|
+
unless(string.count('[') == string.count(']'))
|
7
|
+
raise Exception, "Missing closing braces"
|
8
|
+
end
|
9
|
+
super(string)
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse
|
13
|
+
exp = []
|
14
|
+
while true
|
15
|
+
case fetch_token
|
16
|
+
when '['
|
17
|
+
exp << parse
|
18
|
+
when ']'
|
19
|
+
break
|
20
|
+
when :"'"
|
21
|
+
case fetch_token
|
22
|
+
when '[' then exp << [:quote].concat([parse])
|
23
|
+
else exp << [:quote, @token]
|
24
|
+
end
|
25
|
+
when String, Fixnum, Float, Symbol
|
26
|
+
exp << @token
|
27
|
+
when nil
|
28
|
+
break
|
29
|
+
end
|
30
|
+
end
|
31
|
+
exp
|
32
|
+
end
|
33
|
+
|
34
|
+
def fetch_token
|
35
|
+
skip(/\s+/)
|
36
|
+
return nil if(eos?)
|
37
|
+
|
38
|
+
@token =
|
39
|
+
# Match parentheses
|
40
|
+
if scan(/[\[\]]/)
|
41
|
+
matched
|
42
|
+
# Match a string literal
|
43
|
+
elsif scan(/"([^"\\]|\\.)*"/)
|
44
|
+
eval(matched)
|
45
|
+
# Match a float literal
|
46
|
+
elsif scan(/[\-\+]? [0-9]+ ((e[0-9]+) | (\.[0-9]+(e[0-9]+)?))/x)
|
47
|
+
matched.to_f
|
48
|
+
# Match an integer literal
|
49
|
+
elsif scan(/[\-\+]?[0-9]+/)
|
50
|
+
matched.to_i
|
51
|
+
# Match a comma (for comma quoting)
|
52
|
+
elsif scan(/'/)
|
53
|
+
matched.to_sym
|
54
|
+
# Match a symbol
|
55
|
+
elsif scan(/[^\[\]\s]+/)
|
56
|
+
matched.to_sym
|
57
|
+
# If we've gotten here then we have an invalid token
|
58
|
+
else
|
59
|
+
near = scan %r{.{0,20}}
|
60
|
+
raise "Invalid character at position #{pos} near '#{near}'."
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/sexpistol.gemspec
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{bracer}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Aaron Gough","The Trung"]
|
12
|
+
s.date = %q{2015-02-07}
|
13
|
+
s.description = %q{Brace is Sexpistol with braces, an easy-to-use S-Expression parser for Ruby. It is fast and has no dependencies.}
|
14
|
+
s.email = %q{aaron@aarongough.com, deulamco@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"MIT-LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"MIT-LICENSE",
|
22
|
+
"README.rdoc",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION",
|
25
|
+
"lib/sexpistol.rb",
|
26
|
+
"lib/sexpistol/sexpistol.rb",
|
27
|
+
"lib/sexpistol/sexpistol_parser.rb",
|
28
|
+
"sexpistol.gemspec",
|
29
|
+
"test/performance/benchmark_test.rb",
|
30
|
+
"test/setup/test_unit_extensions.rb",
|
31
|
+
"test/test_helper.rb",
|
32
|
+
"test/unit/float_literal_test.rb",
|
33
|
+
"test/unit/integer_literal_test.rb",
|
34
|
+
"test/unit/ruby_keyword_literals_test.rb",
|
35
|
+
"test/unit/scheme_compatability_test.rb",
|
36
|
+
"test/unit/string_literal_test.rb",
|
37
|
+
"test/unit/structure_test.rb",
|
38
|
+
"test/unit/symbol_test.rb",
|
39
|
+
"test/unit/to_sexp_test.rb"
|
40
|
+
]
|
41
|
+
s.homepage = %q{http://github.com/thetrung/sexpistol}
|
42
|
+
s.rdoc_options = ["--charset=UTF-8", "--line-numbers", "--inline-source"]
|
43
|
+
s.require_paths = ["lib"]
|
44
|
+
s.rubygems_version = %q{1.3.7}
|
45
|
+
s.summary = %q{An Braces S-Expression with Parser Library for Ruby}
|
46
|
+
s.test_files = [
|
47
|
+
"test/performance/benchmark_test.rb",
|
48
|
+
"test/setup/test_unit_extensions.rb",
|
49
|
+
"test/test_helper.rb",
|
50
|
+
"test/unit/float_literal_test.rb",
|
51
|
+
"test/unit/integer_literal_test.rb",
|
52
|
+
"test/unit/ruby_keyword_literals_test.rb",
|
53
|
+
"test/unit/scheme_compatability_test.rb",
|
54
|
+
"test/unit/string_literal_test.rb",
|
55
|
+
"test/unit/structure_test.rb",
|
56
|
+
"test/unit/symbol_test.rb",
|
57
|
+
"test/unit/to_sexp_test.rb"
|
58
|
+
]
|
59
|
+
|
60
|
+
if s.respond_to? :specification_version then
|
61
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
62
|
+
s.specification_version = 3
|
63
|
+
|
64
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
65
|
+
else
|
66
|
+
end
|
67
|
+
else
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class BenchmarkTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
require 'benchmark'
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@example_sexp = <<-EOD
|
9
|
+
[display "This is a test string!"]
|
10
|
+
|
11
|
+
[define test [lambda [] [begin
|
12
|
+
[display [== 1 1]]
|
13
|
+
[display [== true true]]
|
14
|
+
[display [== false false]]
|
15
|
+
[display [== nil nil]]
|
16
|
+
[display [== 2.09 1.08]]
|
17
|
+
[display [== 2e6 2e12]]
|
18
|
+
]]]
|
19
|
+
EOD
|
20
|
+
end
|
21
|
+
|
22
|
+
test "benchmark bracer" do
|
23
|
+
puts "\nRunning performance test...\n"
|
24
|
+
|
25
|
+
parser = Bracer.new
|
26
|
+
parser.ruby_keyword_literals = true
|
27
|
+
|
28
|
+
Benchmark.bmbm do |b|
|
29
|
+
b.report("Parse") do
|
30
|
+
5000.times do
|
31
|
+
parser.parse_string(@example_sexp)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
b.report("to_sexp") do
|
36
|
+
ast = parser.parse_string(@example_sexp)
|
37
|
+
5000.times do
|
38
|
+
parser.to_sexp(ast)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
puts
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Test::Unit
|
2
|
+
# Used to fix a minor minitest/unit incompatibility in flexmock
|
3
|
+
AssertionFailedError = Class.new(StandardError)
|
4
|
+
|
5
|
+
class TestCase
|
6
|
+
|
7
|
+
def self.test(name, &block)
|
8
|
+
test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
9
|
+
defined = instance_method(test_name) rescue false
|
10
|
+
raise "#{test_name} is already defined in #{self}" if defined
|
11
|
+
if block_given?
|
12
|
+
define_method(test_name, &block)
|
13
|
+
else
|
14
|
+
define_method(test_name) do
|
15
|
+
flunk "No implementation provided for #{name}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
require_files = []
|
5
|
+
require_files << File.join(File.dirname(__FILE__), '..', 'lib', 'sexpistol.rb')
|
6
|
+
require_files.concat Dir[File.join(File.dirname(__FILE__), 'setup', '*.rb')]
|
7
|
+
|
8
|
+
require_files.each do |file|
|
9
|
+
require File.expand_path(file)
|
10
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class FloatLiteralTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@parser = Bracer.new
|
7
|
+
end
|
8
|
+
|
9
|
+
test "should parse sexp containing an implicitly positive float literal" do
|
10
|
+
ast = @parser.parse_string("[10.00]")
|
11
|
+
assert_equal [[10.00]], ast
|
12
|
+
end
|
13
|
+
|
14
|
+
test "should parse sexp containing an explicitly positive float literal" do
|
15
|
+
ast = @parser.parse_string("[+910.00]")
|
16
|
+
assert_equal [[910.00]], ast
|
17
|
+
end
|
18
|
+
|
19
|
+
test "should parse sexp containing an explicitly negative float literal" do
|
20
|
+
ast = @parser.parse_string("[-10.00]")
|
21
|
+
assert_equal [[-10.00]], ast
|
22
|
+
end
|
23
|
+
|
24
|
+
test "should parse sexp containing a large float literal" do
|
25
|
+
ast = @parser.parse_string("[1.0000127829]")
|
26
|
+
assert_equal [[1.0000127829]], ast
|
27
|
+
end
|
28
|
+
|
29
|
+
test "should parse sexp containing a float defined in scientific notation" do
|
30
|
+
ast = @parser.parse_string("[1.0e6]")
|
31
|
+
assert_equal [[1.0e6]], ast
|
32
|
+
end
|
33
|
+
|
34
|
+
test "should parse sexp containing a float defined in scientific notation with no decimal place" do
|
35
|
+
ast = @parser.parse_string("[10e2]")
|
36
|
+
assert_equal [[10e2]], ast
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class IntegerLiteralTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@parser = Bracer.new
|
7
|
+
end
|
8
|
+
|
9
|
+
test "should parse sexp containing an implicitly positive integer literal" do
|
10
|
+
ast = @parser.parse_string("[10]")
|
11
|
+
assert_equal [[10]], ast
|
12
|
+
end
|
13
|
+
|
14
|
+
test "should parse sexp containing an explicitly positive integer literal" do
|
15
|
+
ast = @parser.parse_string("[+910]")
|
16
|
+
assert_equal [[910]], ast
|
17
|
+
end
|
18
|
+
|
19
|
+
test "should parse sexp containing an explicitly negative integer literal" do
|
20
|
+
ast = @parser.parse_string("[-10]")
|
21
|
+
assert_equal [[-10]], ast
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class RubyKeywordLiteralsTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@parser = Bracer.new
|
7
|
+
end
|
8
|
+
|
9
|
+
test "should parse nil as literal" do
|
10
|
+
@parser.ruby_keyword_literals = true
|
11
|
+
ast = @parser.parse_string("[nil]")
|
12
|
+
assert_equal [[nil]], ast
|
13
|
+
end
|
14
|
+
|
15
|
+
test "should not parse nil as literal" do
|
16
|
+
@parser.ruby_keyword_literals = false
|
17
|
+
ast = @parser.parse_string("[nil]")
|
18
|
+
assert_equal [[:nil]], ast
|
19
|
+
end
|
20
|
+
|
21
|
+
test "should parse true as literal" do
|
22
|
+
@parser.ruby_keyword_literals = true
|
23
|
+
ast = @parser.parse_string("[true]")
|
24
|
+
assert_equal [[true]], ast
|
25
|
+
end
|
26
|
+
|
27
|
+
test "should not parse true as literal" do
|
28
|
+
@parser.ruby_keyword_literals = false
|
29
|
+
ast = @parser.parse_string("[true]")
|
30
|
+
assert_equal [[:true]], ast
|
31
|
+
end
|
32
|
+
|
33
|
+
test "should parse false as literal" do
|
34
|
+
@parser.ruby_keyword_literals = true
|
35
|
+
ast = @parser.parse_string("[false]")
|
36
|
+
assert_equal [[false]], ast
|
37
|
+
end
|
38
|
+
|
39
|
+
test "should notparse false as literal" do
|
40
|
+
@parser.ruby_keyword_literals = false
|
41
|
+
ast = @parser.parse_string("[false]")
|
42
|
+
assert_equal [[:false]], ast
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class SchemeCompatabilityTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@parser = Bracer.new
|
7
|
+
@parser.scheme_compatability = true
|
8
|
+
end
|
9
|
+
|
10
|
+
test "should parse #t as symbol" do
|
11
|
+
ast = @parser.parse_string('[#t]')
|
12
|
+
assert_equal [[:"#t"]], ast
|
13
|
+
end
|
14
|
+
|
15
|
+
test "should parse #f as symbol" do
|
16
|
+
ast = @parser.parse_string('[#f]')
|
17
|
+
assert_equal [[:"#f"]], ast
|
18
|
+
end
|
19
|
+
|
20
|
+
test "should allow comma quoting" do
|
21
|
+
ast = @parser.parse_string("[this is '[ a test] too foo][foo]")
|
22
|
+
assert_equal [[:this, :is, [:quote, [:a, :test]], :too, :foo ],[:foo]], ast
|
23
|
+
end
|
24
|
+
|
25
|
+
test "should allow complicated comma quoting" do
|
26
|
+
ast = @parser.parse_string("[this is '[ a test] [also]]")
|
27
|
+
assert_equal [[:this, :is, [:quote, [:a, :test]], [:also]]], ast
|
28
|
+
end
|
29
|
+
|
30
|
+
test "should allow comma quoting of integer literal" do
|
31
|
+
ast = @parser.parse_string("[this is '1 [also]]")
|
32
|
+
assert_equal [[:this, :is, [:quote, 1], [:also]]], ast
|
33
|
+
end
|
34
|
+
|
35
|
+
test "should allow comma quoting of string literal" do
|
36
|
+
ast = @parser.parse_string("[this is '\"test\" [also]]")
|
37
|
+
assert_equal [[:this, :is, [:quote, "test"], [:also]]], ast
|
38
|
+
end
|
39
|
+
|
40
|
+
test "should return scheme compatible external representation" do
|
41
|
+
ast = [true, false, nil]
|
42
|
+
string = @parser.to_sexp(ast)
|
43
|
+
assert_equal "[#t #f []]", string
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class StringLiteralTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@parser = Bracer.new
|
7
|
+
end
|
8
|
+
|
9
|
+
test "should parse empty string literal" do
|
10
|
+
ast = @parser.parse_string('[""]')
|
11
|
+
assert_equal [[""]], ast
|
12
|
+
end
|
13
|
+
|
14
|
+
test "should parse string literal" do
|
15
|
+
ast = @parser.parse_string('["test"]')
|
16
|
+
assert_equal [["test"]], ast
|
17
|
+
end
|
18
|
+
|
19
|
+
test "should parse string literal containing escaped quotes" do
|
20
|
+
ast = @parser.parse_string('["te\"st"]')
|
21
|
+
assert_equal [["te\"st"]], ast
|
22
|
+
end
|
23
|
+
|
24
|
+
test "should parse string literal containing escaped characters" do
|
25
|
+
ast = @parser.parse_string('["\n\t\r"]')
|
26
|
+
assert_equal [["\n\t\r"]], ast
|
27
|
+
end
|
28
|
+
|
29
|
+
test "should parse string literal containing spaces" do
|
30
|
+
ast = @parser.parse_string('["blah foo"]')
|
31
|
+
assert_equal [["blah foo"]], ast
|
32
|
+
end
|
33
|
+
|
34
|
+
test "should parse string literal containing newlines" do
|
35
|
+
ast = @parser.parse_string('["blah' + "\n" + 'foo"]')
|
36
|
+
assert_equal [["blah\nfoo"]], ast
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class StructureTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@parser = Bracer.new
|
7
|
+
end
|
8
|
+
|
9
|
+
test "should create nested set of arrays from s-expression" do
|
10
|
+
ast = @parser.parse_string('[this [is [an [s_expression] [also] blah] foo] [test]]')
|
11
|
+
assert_equal [[:this, [:is, [:an, [:s_expression], [:also], :blah], :foo], [:test]]], ast
|
12
|
+
end
|
13
|
+
|
14
|
+
test "should create nested set of arrays from s-expression with string literals" do
|
15
|
+
ast = @parser.parse_string('[this [is [an ["s_expression"]]]]')
|
16
|
+
assert_equal [[:this, [:is, [:an, ["s_expression"]]]]], ast
|
17
|
+
end
|
18
|
+
|
19
|
+
test "should raise error on broken s-expression" do
|
20
|
+
assert_raises Exception do
|
21
|
+
ast = @parser.parse_string('[this [is [an [s_expression] too]')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
test "should parser [] as empty list" do
|
26
|
+
ast = @parser.parse_string('[]')
|
27
|
+
assert_equal [[]], ast
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class SymbolTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@parser = Bracer.new
|
7
|
+
end
|
8
|
+
|
9
|
+
test "should parse simple symbol" do
|
10
|
+
ast = @parser.parse_string("[test]")
|
11
|
+
assert_equal [[:test]], ast
|
12
|
+
end
|
13
|
+
|
14
|
+
test "should parse symbol with trailing exclamation mark" do
|
15
|
+
ast = @parser.parse_string("[test!]")
|
16
|
+
assert_equal [[:test!]], ast
|
17
|
+
end
|
18
|
+
|
19
|
+
test "should parse symbol with trailing question mark" do
|
20
|
+
ast = @parser.parse_string("[test?]")
|
21
|
+
assert_equal [[:test?]], ast
|
22
|
+
end
|
23
|
+
|
24
|
+
test "should parse symbol containing underscores" do
|
25
|
+
ast = @parser.parse_string("[te__st]")
|
26
|
+
assert_equal [[:te__st]], ast
|
27
|
+
end
|
28
|
+
|
29
|
+
test "should parse symbol with leading underscores" do
|
30
|
+
ast = @parser.parse_string("[__test]")
|
31
|
+
assert_equal [[:__test]], ast
|
32
|
+
end
|
33
|
+
|
34
|
+
test "should parse symbol with trailing underscores" do
|
35
|
+
ast = @parser.parse_string("[test__]")
|
36
|
+
assert_equal [[:test__]], ast
|
37
|
+
end
|
38
|
+
|
39
|
+
test "should parse CamelCase symbol" do
|
40
|
+
ast = @parser.parse_string("[TestSymbol]")
|
41
|
+
assert_equal [[:TestSymbol]], ast
|
42
|
+
end
|
43
|
+
|
44
|
+
test "should parse complex symbol" do
|
45
|
+
ast = @parser.parse_string("[__TestSymbol_TEST__?]")
|
46
|
+
assert_equal [[:__TestSymbol_TEST__?]], ast
|
47
|
+
end
|
48
|
+
|
49
|
+
test "should parse symbol containing addition operators" do
|
50
|
+
ast = @parser.parse_string("[+]")
|
51
|
+
assert_equal [[:+]], ast
|
52
|
+
end
|
53
|
+
|
54
|
+
test "should parse symbol containing multiplication operators" do
|
55
|
+
ast = @parser.parse_string("[*]")
|
56
|
+
assert_equal [[:*]], ast
|
57
|
+
end
|
58
|
+
|
59
|
+
test "should parse symbol containing subtraction operators" do
|
60
|
+
ast = @parser.parse_string("[-]")
|
61
|
+
assert_equal [[:-]], ast
|
62
|
+
end
|
63
|
+
|
64
|
+
test "should parse symbol containing division operators" do
|
65
|
+
ast = @parser.parse_string("[/]")
|
66
|
+
assert_equal [[:"/"]], ast
|
67
|
+
end
|
68
|
+
|
69
|
+
test "should parse symbol containing any character except single and double quotes, backquote, parentheses and comma" do
|
70
|
+
ast = @parser.parse_string("[~1!2@3#4$%5^6&7*890-_+=|)}({poiuytrewqasdfghjklmnbvcxzZXCVBNMLKJHGFDSAQWERTYUIOP:;/?><]")
|
71
|
+
assert_equal [[:"~1!2@3#4$%5^6&7*890-_+=|\)}({poiuytrewqasdfghjklmnbvcxzZXCVBNMLKJHGFDSAQWERTYUIOP:;/?><"]], ast
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper.rb'))
|
2
|
+
|
3
|
+
class ToSexpTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@parser = Bracer.new
|
7
|
+
end
|
8
|
+
|
9
|
+
test "should convert nested arrays back into an S-Expression" do
|
10
|
+
ast = [:string, [:is, [:parsed]]]
|
11
|
+
sexp = @parser.to_sexp(ast)
|
12
|
+
assert_equal "[string [is [parsed]]]", sexp
|
13
|
+
end
|
14
|
+
|
15
|
+
test "should structure containing integers and strings back into an S-Expression" do
|
16
|
+
ast = ["String!", [1, [2, "Other string."]]]
|
17
|
+
sexp = @parser.to_sexp(ast)
|
18
|
+
assert_equal "[String! [1 [2 Other string.]]]", sexp
|
19
|
+
end
|
20
|
+
|
21
|
+
test "should not output true and false using scheme notation when scheme compat is off" do
|
22
|
+
ast = [true, [false, [true, false]]]
|
23
|
+
sexp = @parser.to_sexp(ast)
|
24
|
+
assert_equal "[true [false [true false]]]", sexp
|
25
|
+
end
|
26
|
+
|
27
|
+
test "when not passed array to_sexp should print value [integer]" do
|
28
|
+
ast = 1
|
29
|
+
sexp = @parser.to_sexp(ast)
|
30
|
+
assert_equal "1", sexp
|
31
|
+
end
|
32
|
+
|
33
|
+
test "when not passed array to_sexp should print value [string]" do
|
34
|
+
ast = "test"
|
35
|
+
sexp = @parser.to_sexp(ast)
|
36
|
+
assert_equal "test", sexp
|
37
|
+
end
|
38
|
+
|
39
|
+
test "when not passed array to_sexp should print value [symbol]" do
|
40
|
+
ast = :test
|
41
|
+
sexp = @parser.to_sexp(ast)
|
42
|
+
assert_equal "test", sexp
|
43
|
+
end
|
44
|
+
|
45
|
+
test "lists passed to to_sexp should have not extraneous spaces" do
|
46
|
+
ast = [1, 2, 3]
|
47
|
+
sexp = @parser.to_sexp(ast)
|
48
|
+
assert_equal "[1 2 3]", sexp
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bracer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Gough
|
8
|
+
- The Trung
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-02-07 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Brace is Sexpistol with braces, an easy-to-use S-Expression parser for
|
15
|
+
Ruby. It is fast and has no dependencies.
|
16
|
+
email: aaron@aarongough.com, deulamco@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files:
|
20
|
+
- MIT-LICENSE
|
21
|
+
- README.rdoc
|
22
|
+
files:
|
23
|
+
- ".gitignore"
|
24
|
+
- MIT-LICENSE
|
25
|
+
- README.rdoc
|
26
|
+
- Rakefile
|
27
|
+
- VERSION
|
28
|
+
- lib/sexpistol.rb
|
29
|
+
- lib/sexpistol/sexpistol.rb
|
30
|
+
- lib/sexpistol/sexpistol_parser.rb
|
31
|
+
- sexpistol.gemspec
|
32
|
+
- test/performance/benchmark_test.rb
|
33
|
+
- test/setup/test_unit_extensions.rb
|
34
|
+
- test/test_helper.rb
|
35
|
+
- test/unit/float_literal_test.rb
|
36
|
+
- test/unit/integer_literal_test.rb
|
37
|
+
- test/unit/ruby_keyword_literals_test.rb
|
38
|
+
- test/unit/scheme_compatability_test.rb
|
39
|
+
- test/unit/string_literal_test.rb
|
40
|
+
- test/unit/structure_test.rb
|
41
|
+
- test/unit/symbol_test.rb
|
42
|
+
- test/unit/to_sexp_test.rb
|
43
|
+
homepage: http://github.com/thetrung/sexpistol
|
44
|
+
licenses: []
|
45
|
+
metadata: {}
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options:
|
48
|
+
- "--charset=UTF-8"
|
49
|
+
- "--line-numbers"
|
50
|
+
- "--inline-source"
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 2.4.5
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: An Braces S-Expression with Parser Library for Ruby
|
69
|
+
test_files:
|
70
|
+
- test/performance/benchmark_test.rb
|
71
|
+
- test/setup/test_unit_extensions.rb
|
72
|
+
- test/test_helper.rb
|
73
|
+
- test/unit/float_literal_test.rb
|
74
|
+
- test/unit/integer_literal_test.rb
|
75
|
+
- test/unit/ruby_keyword_literals_test.rb
|
76
|
+
- test/unit/scheme_compatability_test.rb
|
77
|
+
- test/unit/string_literal_test.rb
|
78
|
+
- test/unit/structure_test.rb
|
79
|
+
- test/unit/symbol_test.rb
|
80
|
+
- test/unit/to_sexp_test.rb
|
81
|
+
has_rdoc:
|