sexpistol 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/sexpistol/sexpistol.rb +31 -52
- data/sexpistol.gemspec +5 -3
- data/test/performance/benchmark_test.rb +34 -0
- data/test/unit/structure_test.rb +3 -3
- metadata +5 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/lib/sexpistol/sexpistol.rb
CHANGED
@@ -3,10 +3,21 @@
|
|
3
3
|
# native Ruby representation like:
|
4
4
|
# [:def, :something [:lambda, [:a], [:do_something]]]
|
5
5
|
class Sexpistol
|
6
|
+
|
6
7
|
attr_accessor :ruby_keyword_literals
|
7
8
|
|
8
9
|
def initialize
|
9
10
|
@ruby_keyword_literals = false
|
11
|
+
|
12
|
+
# Setup all of our token patterns as instance variables
|
13
|
+
# so they don't have to be re-instantiated for each
|
14
|
+
# run & match
|
15
|
+
@string_literal_pattern = /"([^"\\]|\\.)*"/
|
16
|
+
@integer_literal_pattern = /[\-\+]?[0-9]+/
|
17
|
+
@float_literal_pattern = /[\-\+]?[0-9]+\.[0-9]+(e[0-9]+)?/
|
18
|
+
@symbol_pattern = /[^\"\'\,\(\)]+/
|
19
|
+
|
20
|
+
@string_replacement_token = "__++STRING_LITERAL++__"
|
10
21
|
end
|
11
22
|
|
12
23
|
# Parse a string containing an S-Expression into a
|
@@ -14,16 +25,7 @@ class Sexpistol
|
|
14
25
|
def parse_string( string )
|
15
26
|
string_array = split_outside_strings(string)
|
16
27
|
tokens = process_tokens( string_array )
|
17
|
-
|
18
|
-
structure( tokens )
|
19
|
-
end
|
20
|
-
|
21
|
-
# Check and array of tokens to make sure that the number
|
22
|
-
# of open and closing parentheses match
|
23
|
-
def check_tokens( tokens )
|
24
|
-
unless( (tokens.reject {|x| x == "("}).length == (tokens.reject {|x| x == ")"}).length)
|
25
|
-
raise Exception, "Invalid S-Expression. The number of opening and closing parentheses does not match."
|
26
|
-
end
|
28
|
+
structure( tokens )[1]
|
27
29
|
end
|
28
30
|
|
29
31
|
# Iterate over an array of strings and turn each
|
@@ -32,11 +34,11 @@ class Sexpistol
|
|
32
34
|
tokens = []
|
33
35
|
token_array.each do |t|
|
34
36
|
if(@ruby_keyword_literals)
|
35
|
-
tokens << nil and next if(
|
36
|
-
tokens << true and next if(
|
37
|
-
tokens << false and next if(
|
37
|
+
tokens << nil and next if(t == "nil")
|
38
|
+
tokens << true and next if(t == "true")
|
39
|
+
tokens << false and next if(t == "false")
|
38
40
|
end
|
39
|
-
tokens << t and next if(
|
41
|
+
tokens << t and next if(t == "(" || t == ")")
|
40
42
|
tokens << t.to_f and next if( is_float?(t))
|
41
43
|
tokens << t.to_i and next if( is_integer?(t))
|
42
44
|
tokens << t.to_sym and next if( is_symbol?(t))
|
@@ -61,30 +63,27 @@ class Sexpistol
|
|
61
63
|
end
|
62
64
|
offset += 1
|
63
65
|
end
|
64
|
-
|
65
|
-
return [offset, program]
|
66
|
-
else
|
67
|
-
return program
|
68
|
-
end
|
66
|
+
return [offset, program]
|
69
67
|
end
|
70
68
|
|
71
69
|
# Split up a string into an array where delimited by whitespace,
|
72
70
|
# except inside string literals
|
73
71
|
def split_outside_strings( string )
|
74
|
-
string_literal_pattern = /"([^"\\]|\\.)*"/
|
75
|
-
string_token = "__++STRING_LITERAL++__"
|
76
72
|
# Find and extract all the string literals
|
77
73
|
string_literals = []
|
78
|
-
string.gsub(string_literal_pattern)
|
79
|
-
|
80
|
-
|
74
|
+
string = string.gsub(@string_literal_pattern) do |x|
|
75
|
+
string_literals << x
|
76
|
+
@string_replacement_token
|
77
|
+
end
|
78
|
+
# Make sure the s-expression is valid
|
79
|
+
unless( string.count("(") == string.count(")") )
|
80
|
+
raise Exception, "Invalid S-Expression. The number of opening and closing parentheses does not match."
|
81
|
+
end
|
81
82
|
# Split the string up on whitespace and parentheses
|
82
|
-
string.gsub
|
83
|
-
string.gsub!(")", " ) ")
|
84
|
-
array = string.split(" ")
|
83
|
+
array = string.gsub("(", " ( ").gsub(")", " ) ").split(" ")
|
85
84
|
# replace the special string token with the original string literals
|
86
85
|
array.collect! do |x|
|
87
|
-
if( x ==
|
86
|
+
if( x == @string_replacement_token)
|
88
87
|
string_literals.shift
|
89
88
|
else
|
90
89
|
x
|
@@ -93,44 +92,24 @@ class Sexpistol
|
|
93
92
|
return array
|
94
93
|
end
|
95
94
|
|
96
|
-
# Test to see whether or not a string represents the 'nil' literal
|
97
|
-
def is_nil?( string )
|
98
|
-
true if(string == "nil")
|
99
|
-
end
|
100
|
-
|
101
|
-
# Test to see whether or not a string represents the 'true' literal
|
102
|
-
def is_true?( string )
|
103
|
-
true if(string == "true")
|
104
|
-
end
|
105
|
-
|
106
|
-
# Test to see whether or not a string represents the 'false' literal
|
107
|
-
def is_false?( string )
|
108
|
-
true if(string == "false")
|
109
|
-
end
|
110
|
-
|
111
|
-
# Test to see whether a string represents a parentheses
|
112
|
-
def is_paren?( string )
|
113
|
-
is_match?( string, /[\(\)]+/ )
|
114
|
-
end
|
115
|
-
|
116
95
|
# Test to see whether or not a string represents an integer
|
117
96
|
def is_integer?( string )
|
118
|
-
is_match?( string,
|
97
|
+
is_match?( string, @integer_literal_pattern )
|
119
98
|
end
|
120
99
|
|
121
100
|
# Test to see whether or not a string represents a float
|
122
101
|
def is_float?( string )
|
123
|
-
is_match?( string,
|
102
|
+
is_match?( string, @float_literal_pattern )
|
124
103
|
end
|
125
104
|
|
126
105
|
# Test to see whether or not a string represents a symbol
|
127
106
|
def is_symbol?( string )
|
128
|
-
is_match?( string,
|
107
|
+
is_match?( string, @symbol_pattern )
|
129
108
|
end
|
130
109
|
|
131
110
|
# Test to see whether or not a string represents a string literal
|
132
111
|
def is_string_literal?( string )
|
133
|
-
is_match?( string,
|
112
|
+
is_match?( string, @string_literal_pattern )
|
134
113
|
end
|
135
114
|
|
136
115
|
# Convert a set of nested arrays back into an S-Expression
|
data/sexpistol.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{sexpistol}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Aaron Gough"]
|
12
|
-
s.date = %q{2010-10-
|
12
|
+
s.date = %q{2010-10-06}
|
13
13
|
s.description = %q{Sexpistol is an easy-to-use S-Expression parser for Ruby. It is fast and has no dependencies.}
|
14
14
|
s.email = %q{aaron@aarongough.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
"lib/sexpistol.rb",
|
26
26
|
"lib/sexpistol/sexpistol.rb",
|
27
27
|
"sexpistol.gemspec",
|
28
|
+
"test/performance/benchmark_test.rb",
|
28
29
|
"test/setup/test_unit_extensions.rb",
|
29
30
|
"test/test_helper.rb",
|
30
31
|
"test/unit/float_literal_test.rb",
|
@@ -41,7 +42,8 @@ Gem::Specification.new do |s|
|
|
41
42
|
s.rubygems_version = %q{1.3.7}
|
42
43
|
s.summary = %q{An S-Expression Parser Library for Ruby}
|
43
44
|
s.test_files = [
|
44
|
-
"test/
|
45
|
+
"test/performance/benchmark_test.rb",
|
46
|
+
"test/setup/test_unit_extensions.rb",
|
45
47
|
"test/test_helper.rb",
|
46
48
|
"test/unit/float_literal_test.rb",
|
47
49
|
"test/unit/integer_literal_test.rb",
|
@@ -0,0 +1,34 @@
|
|
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
|
+
test "benchmark sexpistol" do
|
8
|
+
puts "\nRunning performance test...\n"
|
9
|
+
parser = Sexpistol.new
|
10
|
+
parser.ruby_keyword_literals = true
|
11
|
+
Benchmark.bmbm do |b|
|
12
|
+
b.report do
|
13
|
+
5000.times do
|
14
|
+
parser.parse_string <<-EOD
|
15
|
+
|
16
|
+
(display "This is a test string!")
|
17
|
+
|
18
|
+
(define test (lambda () (begin
|
19
|
+
(display (== 1 1))
|
20
|
+
(display (== true true))
|
21
|
+
(display (== false false))
|
22
|
+
(display (== nil nil))
|
23
|
+
(display (== 2.09 1.08))
|
24
|
+
(display (== 2e6 2e12))
|
25
|
+
)))
|
26
|
+
|
27
|
+
EOD
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
puts
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/test/unit/structure_test.rb
CHANGED
@@ -5,10 +5,10 @@ class RubyKeywordLiteralsTest < Test::Unit::TestCase
|
|
5
5
|
def setup
|
6
6
|
@parser = Sexpistol.new
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
test "should create nested set of arrays from s-expression" do
|
10
|
-
ast = @parser.parse_string('(this (is (an (s_expression))))')
|
11
|
-
assert_equal [[:this, [:is, [:an, [:s_expression]]]]], ast
|
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
12
|
end
|
13
13
|
|
14
14
|
test "should create nested set of arrays from s-expression with string literals" do
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 3
|
9
|
+
version: 0.0.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Aaron Gough
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-10-
|
17
|
+
date: 2010-10-06 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -36,6 +36,7 @@ files:
|
|
36
36
|
- lib/sexpistol.rb
|
37
37
|
- lib/sexpistol/sexpistol.rb
|
38
38
|
- sexpistol.gemspec
|
39
|
+
- test/performance/benchmark_test.rb
|
39
40
|
- test/setup/test_unit_extensions.rb
|
40
41
|
- test/test_helper.rb
|
41
42
|
- test/unit/float_literal_test.rb
|
@@ -80,6 +81,7 @@ signing_key:
|
|
80
81
|
specification_version: 3
|
81
82
|
summary: An S-Expression Parser Library for Ruby
|
82
83
|
test_files:
|
84
|
+
- test/performance/benchmark_test.rb
|
83
85
|
- test/setup/test_unit_extensions.rb
|
84
86
|
- test/test_helper.rb
|
85
87
|
- test/unit/float_literal_test.rb
|