Class: SexpistolParser
- Inherits:
-
StringScanner
- Object
- StringScanner
- SexpistolParser
- Defined in:
- lib/vendor/sexpistol/sexpistol/sexpistol_parser.rb
Instance Method Summary collapse
- #expression_ender ⇒ Object
- #fetch_token ⇒ Object
-
#initialize(string) ⇒ SexpistolParser
constructor
A new instance of SexpistolParser.
- #parse ⇒ Object
Constructor Details
#initialize(string) ⇒ SexpistolParser
Returns a new instance of SexpistolParser.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/vendor/sexpistol/sexpistol/sexpistol_parser.rb', line 8 def initialize(string) # step through string counting closing parens, exclude parens in string literals in_string_literal = false escape_char = false paren_count = 0 string.bytes.each do |byte| if escape_char escape_char = false next end case byte.chr when '\\' escape_char = true next when '(' if !in_string_literal paren_count += 1 end when ')' if !in_string_literal paren_count -= 1 end when '"' in_string_literal = !in_string_literal end end if paren_count > 0 raise ParseException.new("Missing closing parentheses") elsif paren_count < 0 raise ParseException.new("Missing opening parentheses") end super(string) end |
Instance Method Details
#expression_ender ⇒ Object
98 99 100 101 102 103 104 |
# File 'lib/vendor/sexpistol/sexpistol/sexpistol_parser.rb', line 98 def expression_ender # end Fixnum and Float matchers with a non-grouping positive lookahead # assertion that matches a closing paren, whitespace, or string end. The # positive lookahead (?=...) ensures the string scanner includes the ending # character in next fetch_token call. '(?=(?:\)|\s|$))' end |
#fetch_token ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/vendor/sexpistol/sexpistol/sexpistol_parser.rb', line 68 def fetch_token skip(/\s+/) return nil if(eos?) @token = # Match parentheses if scan(/[\(\)]/) matched # Match a string literal elsif scan(/"([^"\\]|\\.)*"/) eval(matched) # Match a float literal elsif scan(/[\-\+]? [0-9]+ ((e[0-9]+) | (\.[0-9]+(e[0-9]+)?))#{ expression_ender }/x) matched.to_f # Match an integer literal elsif scan(/[\-\+]?[0-9]+#{ expression_ender }/) matched.to_i # Match a comma (for comma quoting) elsif scan(/'/) matched.to_sym # Match a symbol elsif scan(/[^\(\)\s]+/) matched.to_sym # If we've gotten here then we have an invalid token else near = scan %r{.{0,20}} raise "Invalid character at position #{pos} near '#{near}'." end end |
#parse ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/vendor/sexpistol/sexpistol/sexpistol_parser.rb', line 46 def parse exp = [] while true case fetch_token when '(' exp << parse when ')' break when :"'" case fetch_token when '(' then exp << [:quote].concat([parse]) else exp << [:quote, @token] end when String, Fixnum, Float, Symbol exp << @token when nil break end end exp end |