deil_sexpistol 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
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 'rake/rdoctask'
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 = "deil_sexpistol"
12
+ gemspec.summary = "An S-Expression Parser Library for Ruby. Forked"
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", "Anton Kosyakin"]
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.8
@@ -0,0 +1,56 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{deil_sexpistol}
8
+ s.version = "0.0.8"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Aaron Gough", "Anton Kosyakin"]
12
+ s.date = %q{2011-09-14}
13
+ s.description = %q{Sexpistol is an easy-to-use S-Expression parser for Ruby. It is fast and has no dependencies.}
14
+ s.email = %q{aaron@aarongough.com}
15
+ s.extra_rdoc_files = [
16
+ "MIT-LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ "MIT-LICENSE",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "lib/sexpistol.rb",
25
+ "lib/sexpistol/sexpistol.rb",
26
+ "lib/sexpistol/sexpistol_parser.rb",
27
+ "sexpistol.gemspec",
28
+ "test/performance/benchmark_test.rb",
29
+ "test/setup/test_unit_extensions.rb",
30
+ "test/test_helper.rb",
31
+ "test/unit/float_literal_test.rb",
32
+ "test/unit/integer_literal_test.rb",
33
+ "test/unit/ruby_keyword_literals_test.rb",
34
+ "test/unit/scheme_compatability_test.rb",
35
+ "test/unit/string_literal_test.rb",
36
+ "test/unit/structure_test.rb",
37
+ "test/unit/symbol_test.rb",
38
+ "test/unit/to_sexp_test.rb"
39
+ ]
40
+ s.homepage = %q{http://github.com/aarongough/sexpistol}
41
+ s.rdoc_options = ["--line-numbers", "--inline-source"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.7}
44
+ s.summary = %q{An S-Expression Parser Library for Ruby. Forked}
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ else
52
+ end
53
+ else
54
+ end
55
+ end
56
+
@@ -0,0 +1,78 @@
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 Sexpistol
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 = SexpistolParser.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
+ elsif item.is_a?(String)
51
+ "\"" + item + "\""
52
+ else
53
+ item.to_s
54
+ end
55
+ end
56
+ "(" + mapped.join(" ") + ")"
57
+ else
58
+ data.to_s
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def recursive_map(data, &block)
65
+ if(data.is_a?(Array))
66
+ return data.map do |x|
67
+ if(x.is_a?(Array))
68
+ recursive_map(x, &block)
69
+ else
70
+ block.call(x)
71
+ end
72
+ end
73
+ else
74
+ block.call(data)
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,64 @@
1
+ require 'strscan'
2
+
3
+ class SexpistolParser < StringScanner
4
+
5
+ def initialize(string)
6
+ unless(string.count('(') == string.count(')'))
7
+ raise Exception, "Missing closing parentheses"
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/lib/sexpistol.rb ADDED
@@ -0,0 +1,2 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'sexpistol', 'sexpistol_parser.rb'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'sexpistol', 'sexpistol.rb'))
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{sexpistol}
8
+ s.version = "0.0.7"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Aaron Gough"]
12
+ s.date = %q{2010-10-15}
13
+ s.description = %q{Sexpistol is an easy-to-use S-Expression parser for Ruby. It is fast and has no dependencies.}
14
+ s.email = %q{aaron@aarongough.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/aarongough/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 S-Expression 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 sexpistol" do
23
+ puts "\nRunning performance test...\n"
24
+
25
+ parser = Sexpistol.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
@@ -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 = Sexpistol.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 = Sexpistol.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 = Sexpistol.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 = Sexpistol.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 = Sexpistol.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 = Sexpistol.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 = Sexpistol.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 = Sexpistol.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,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deil_sexpistol
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 8
10
+ version: 0.0.8
11
+ platform: ruby
12
+ authors:
13
+ - Aaron Gough
14
+ - Anton Kosyakin
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-09-14 00:00:00 +04:00
20
+ default_executable:
21
+ dependencies: []
22
+
23
+ description: Sexpistol is an easy-to-use S-Expression parser for Ruby. It is fast and has no dependencies.
24
+ email: aaron@aarongough.com
25
+ executables: []
26
+
27
+ extensions: []
28
+
29
+ extra_rdoc_files:
30
+ - MIT-LICENSE
31
+ - README.rdoc
32
+ files:
33
+ - MIT-LICENSE
34
+ - README.rdoc
35
+ - Rakefile
36
+ - VERSION
37
+ - deil_sexpistol.gemspec
38
+ - lib/sexpistol.rb
39
+ - lib/sexpistol/sexpistol.rb
40
+ - lib/sexpistol/sexpistol_parser.rb
41
+ - sexpistol.gemspec
42
+ - test/performance/benchmark_test.rb
43
+ - test/setup/test_unit_extensions.rb
44
+ - test/test_helper.rb
45
+ - test/unit/float_literal_test.rb
46
+ - test/unit/integer_literal_test.rb
47
+ - test/unit/ruby_keyword_literals_test.rb
48
+ - test/unit/scheme_compatability_test.rb
49
+ - test/unit/string_literal_test.rb
50
+ - test/unit/structure_test.rb
51
+ - test/unit/symbol_test.rb
52
+ - test/unit/to_sexp_test.rb
53
+ has_rdoc: true
54
+ homepage: http://github.com/aarongough/sexpistol
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options:
59
+ - --line-numbers
60
+ - --inline-source
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.7
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: An S-Expression Parser Library for Ruby. Forked
88
+ test_files: []
89
+