sexpistol 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/README.rdoc CHANGED
@@ -5,19 +5,21 @@ Sexpistol is a simple library for parsing S-Expressions in Ruby. Sexpistol takes
5
5
  === Example
6
6
 
7
7
  (define test (lambda () (
8
- (print "blah")
8
+ (print "Hello world!\n")
9
9
  (print 1)
10
10
  (print 9.01)
11
+ (print 2.0e10)
11
12
  (print (+ 10 12 13))
12
13
  )))
13
14
 
14
15
  would be parsed by Sexpistol like so:
15
16
 
16
17
  [:define, :test, [:lambda, [], [
17
- [:print, "blah"],
18
+ [:print, "Hello world!\n"],
18
19
  [:print, 1],
19
20
  [:print, 9.01],
20
- [:print, [:"+", 10, 12, 13]]
21
+ [:print, 2.0e10],
22
+ [:print, [:+, 10, 12, 13]]
21
23
  ]]]
22
24
 
23
25
  === Type mappings
@@ -26,9 +28,9 @@ Sexpistol supports all of the standard datatypes and converts them directly to t
26
28
 
27
29
  * Lists (a b c)
28
30
  * Integers (1 2 3)
29
- * Floats (1.0 2.0 42.9)
31
+ * Floats (1.0 2.0 42.9 3e6 1.2e2)
30
32
  * Strings ("\t\"Hello world!\"\n")
31
- * Symbols (symbol Symbol __symbol__ symbo_l symbol? symbol!)
33
+ * Symbols (symbol Symbol ____symbol____ symbo_l symbol? symbol! + - / ++ a+ e$, etc...)
32
34
 
33
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:
34
36
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -12,9 +12,7 @@ class Sexpistol
12
12
  # Parse a string containing an S-Expression into a
13
13
  # nested set of Ruby arrays
14
14
  def parse_string( string )
15
- string.gsub!("(", " ( ")
16
- string.gsub!(")", " ) ")
17
- string_array = string.split
15
+ string_array = split_outside_strings(string)
18
16
  tokens = process_tokens( string_array )
19
17
  check_tokens( tokens )
20
18
  structure( tokens )
@@ -24,7 +22,7 @@ class Sexpistol
24
22
  # of open and closing parentheses match
25
23
  def check_tokens( tokens )
26
24
  unless( (tokens.reject {|x| x == "("}).length == (tokens.reject {|x| x == ")"}).length)
27
- raise Exception, "Invalid S-Expression. The number of opening and closing parentheses do not match."
25
+ raise Exception, "Invalid S-Expression. The number of opening and closing parentheses does not match."
28
26
  end
29
27
  end
30
28
 
@@ -41,7 +39,7 @@ class Sexpistol
41
39
  tokens << t and next if(is_paren?(t))
42
40
  tokens << t.to_f and next if( is_float?(t))
43
41
  tokens << t.to_i and next if( is_integer?(t))
44
- tokens << t.to_sym and next if( is_identifier?(t) || is_symbol?(t))
42
+ tokens << t.to_sym and next if( is_symbol?(t))
45
43
  tokens << eval(t) and next if( is_string_literal?(t))
46
44
  raise "\nUnrecognized token: #{t}\n"
47
45
  end
@@ -69,6 +67,31 @@ class Sexpistol
69
67
  return program
70
68
  end
71
69
  end
70
+
71
+ # Split up a string into an array where delimited by whitespace,
72
+ # except inside string literals
73
+ def split_outside_strings( string )
74
+ string_literal_pattern = /"([^"\\]|\\.)*"/
75
+ string_token = "__++STRING_LITERAL++__"
76
+ # Find and extract all the string literals
77
+ string_literals = []
78
+ string.gsub(string_literal_pattern) {|x| string_literals << x}
79
+ # Replace all the string literals with a special token
80
+ string = string.gsub(string_literal_pattern, string_token)
81
+ # Split the string up on whitespace and parentheses
82
+ string.gsub!("(", " ( ")
83
+ string.gsub!(")", " ) ")
84
+ array = string.split(" ")
85
+ # replace the special string token with the original string literals
86
+ array.collect! do |x|
87
+ if( x == string_token)
88
+ string_literals.shift
89
+ else
90
+ x
91
+ end
92
+ end
93
+ return array
94
+ end
72
95
 
73
96
  # Test to see whether or not a string represents the 'nil' literal
74
97
  def is_nil?( string )
@@ -97,22 +120,17 @@ class Sexpistol
97
120
 
98
121
  # Test to see whether or not a string represents a float
99
122
  def is_float?( string )
100
- is_match?( string, /[\-\+]?[0-9]+\.[0-9]+/ )
123
+ is_match?( string, /[\-\+]?[0-9]+\.[0-9]+(e[0-9]+)?/ )
101
124
  end
102
125
 
103
- # Test to see whether or not a string represents an identifier
104
- def is_identifier?( string )
105
- is_match?( string, /_*[a-zA-Z]+[a-zA-Z0-9_]*\??\!?/ )
126
+ # Test to see whether or not a string represents a symbol
127
+ def is_symbol?( string )
128
+ is_match?( string, /[^\"\'\,\(\)]+/ )
106
129
  end
107
130
 
108
131
  # Test to see whether or not a string represents a string literal
109
132
  def is_string_literal?( string )
110
- is_match?( string, /".*"/)
111
- end
112
-
113
- # Test to see whether or not a string represents a symbol
114
- def is_symbol?( string )
115
- is_match?( string, /[\!\*\^=\/\+\-]+/ )
133
+ is_match?( string, /"([^"\\]|\\.)*"/)
116
134
  end
117
135
 
118
136
  # Convert a set of nested arrays back into an S-Expression
data/sexpistol.gemspec ADDED
@@ -0,0 +1,65 @@
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.2"
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-03}
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
+ "sexpistol.gemspec",
28
+ "test/setup/test_unit_extensions.rb",
29
+ "test/test_helper.rb",
30
+ "test/unit/float_literal_test.rb",
31
+ "test/unit/integer_literal_test.rb",
32
+ "test/unit/ruby_keyword_literals_test.rb",
33
+ "test/unit/string_literal_test.rb",
34
+ "test/unit/structure_test.rb",
35
+ "test/unit/symbol_test.rb",
36
+ "test/unit/to_sexp_test.rb"
37
+ ]
38
+ s.homepage = %q{http://github.com/aarongough/sexpistol}
39
+ s.rdoc_options = ["--charset=UTF-8", "--line-numbers", "--inline-source"]
40
+ s.require_paths = ["lib"]
41
+ s.rubygems_version = %q{1.3.7}
42
+ s.summary = %q{An S-Expression Parser Library for Ruby}
43
+ s.test_files = [
44
+ "test/setup/test_unit_extensions.rb",
45
+ "test/test_helper.rb",
46
+ "test/unit/float_literal_test.rb",
47
+ "test/unit/integer_literal_test.rb",
48
+ "test/unit/ruby_keyword_literals_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
+ ]
54
+
55
+ if s.respond_to? :specification_version then
56
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
57
+ s.specification_version = 3
58
+
59
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
60
+ else
61
+ end
62
+ else
63
+ end
64
+ end
65
+
@@ -25,6 +25,11 @@ class FloatLiteralTest < Test::Unit::TestCase
25
25
  ast = @parser.parse_string("1.0000127829")
26
26
  assert_equal [1.0000127829], ast
27
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
28
33
 
29
34
 
30
35
  end
@@ -25,5 +25,15 @@ class StringLiteralTest < Test::Unit::TestCase
25
25
  ast = @parser.parse_string('"\n\t\r"')
26
26
  assert_equal ["\n\t\r"], ast
27
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
28
38
 
29
39
  end
@@ -11,6 +11,11 @@ class RubyKeywordLiteralsTest < Test::Unit::TestCase
11
11
  assert_equal [[:this, [:is, [:an, [:s_expression]]]]], ast
12
12
  end
13
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
+
14
19
  test "should raise error on broken s-expression" do
15
20
  assert_raises Exception do
16
21
  ast = @parser.parse_string('(this (is (an (s_expression) too)')
@@ -45,5 +45,30 @@ class SymbolTest < Test::Unit::TestCase
45
45
  ast = @parser.parse_string("__TestSymbol_TEST__?")
46
46
  assert_equal [:__TestSymbol_TEST__?], ast
47
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
48
73
 
49
74
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
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-02 00:00:00 -04:00
17
+ date: 2010-10-03 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -28,12 +28,14 @@ extra_rdoc_files:
28
28
  - MIT-LICENSE
29
29
  - README.rdoc
30
30
  files:
31
+ - .gitignore
31
32
  - MIT-LICENSE
32
33
  - README.rdoc
33
34
  - Rakefile
34
35
  - VERSION
35
36
  - lib/sexpistol.rb
36
37
  - lib/sexpistol/sexpistol.rb
38
+ - sexpistol.gemspec
37
39
  - test/setup/test_unit_extensions.rb
38
40
  - test/test_helper.rb
39
41
  - test/unit/float_literal_test.rb