sexpr/src/sexpr.cr

76 lines
1.4 KiB
Crystal
Raw Normal View History

2021-10-18 17:15:28 +00:00
# Based on fast-sexpr (https://www.npmjs.com/package/fast-sexpr)
module Sexpr
extend self
VERSION = {{ `shards version`.stringify.chomp }}
2021-10-20 19:00:55 +00:00
alias Node = String | Body
alias Body = Array(String) | Array(Node)
2021-10-18 17:15:28 +00:00
2021-12-27 17:57:19 +00:00
class Parser
2021-10-18 17:15:28 +00:00
private property i = 0
private property source : String
2021-12-27 17:57:19 +00:00
module Terms
2021-10-18 17:15:28 +00:00
STRING = /"/
SPACE = /\s/
LIST = /(#{SPACE})|[()]/
end
def initialize(@source : String)
end
private def get_char : Char?
if @i == @source.size
return nil
end
char = @source[@i]
@i += 1
char
end
private def read_value(is_terminator : Regex) : String
value = ""
2021-12-27 18:40:09 +00:00
while !is_terminator.matches?(str_char = get_char.to_s)
value += str_char
2021-10-18 17:15:28 +00:00
end
value
end
2021-12-27 18:40:09 +00:00
private def un_get_char : Nil
2021-10-18 17:15:28 +00:00
@i -= 1
end
2021-10-20 19:00:55 +00:00
def parse : Body
body = [] of Node
2021-10-18 17:15:28 +00:00
while char = get_char
if char == ')'
break
elsif char == '('
body << parse
elsif char == '"'
2021-10-20 19:00:55 +00:00
body << read_value(Terms::STRING)
2021-10-18 17:15:28 +00:00
elsif !Terms::SPACE.matches?(char.to_s)
un_get_char
2021-10-20 19:00:55 +00:00
body << read_value(Terms::LIST)
2021-10-18 17:15:28 +00:00
un_get_char
end
end
body
end
end
2021-10-19 15:26:49 +00:00
def remove_comments(source : String) : String
source.gsub(/;;?.+/, nil)
end
2021-10-20 19:00:55 +00:00
def parse(source : String) : Body
2021-12-27 17:57:19 +00:00
Parser.new(remove_comments(source)).parse
2021-10-18 17:15:28 +00:00
end
end