Skip to content

Instantly share code, notes, and snippets.

@murooka
Created January 11, 2015 04:36
Show Gist options
  • Select an option

  • Save murooka/67fd9fa545e738cc10b6 to your computer and use it in GitHub Desktop.

Select an option

Save murooka/67fd9fa545e738cc10b6 to your computer and use it in GitHub Desktop.
require 'parslet'
class Parser < Parslet::Parser
rule(:comment) { str(';') >> match(/./).repeat(0) >> str("\n") }
rule(:whitespace) { str(' ') | str("\n") }
rule(:atmosphere) { whitespace | comment }
rule(:intertoken_space) { atmosphere.repeat(0) }
rule(:identifier) { initial >> subsequent.repeat(0) | peculiar_identifier }
rule(:initial) { letter | special_initial }
rule(:letter) { match(/[a-z]/) }
rule(:special_initial) { match(/[!$%&*:<=>?_~\/\^]/) }
rule(:subsequent) { initial | digit | special_subsequent }
rule(:digit) { match(/[0-9]/) }
rule(:special_subsequent) { match(/[+-.@]/) }
rule(:peculiar_identifier) { str('+') | str('-') | str('...') }
rule(:boolean) { str('#t') | str('#f') }
rule(:character) { str('#\\') >> (str('space') | str('newline') | match(/./)) }
rule(:string) { str('"') >> string_elem.repeat(0) >> str('"') }
rule(:string_elem){ str('\\"') | str('\\\\') | match(/[^"\\]/) }
rule(:number) { num10 }
rule(:num10) { prefix10 >> complex10 }
rule(:prefix10) { radix10 >> exactness | exactness >> radix10 }
rule(:radix10) { str('#d').maybe }
rule(:exactness) { (str('#i') | str('#e')).maybe }
rule(:complex10) { real10 }
rule(:real10) { sign >> ureal10 }
rule(:sign) { (str('+') | str('-')).maybe }
rule(:ureal10) { uinteger10 }
rule(:uinteger10) { digit.repeat(1) >> str('#').repeat(0) }
rule(:token) { identifier | number }
rule(:expr) { intertoken_space >> (token.as(:token) >> intertoken_space).repeat(0) }
root(:expr)
end
def translate(ast)
if ast.is_a? Hash
tag = ast.keys[0]
{
tag: tag,
value: translate(ast[tag]),
}
elsif ast.is_a? Array
ast.map { |v| translate(v) }
else
ast.str
end
end
debug = true
if debug
require 'pp'
def test(sexp)
puts sexp
pp translate(Parser.new.parse(sexp))
end
test(<<-EOS)
hoge a123 ...
!abc foo+bar foo-bar ; special comment! $%^&*()
foo.bar foo@bar
#d#i1
EOS
end
__END__
class Parser < Parslet::Parser
rule(:space) { match(/\s/).maybe }
rule(:boolean) { (str('#t') | str('#f')).as(:boolean) }
rule(:character) { (str('#\\space') | str('#\\newline') | str('#\\') >> match(/\w/)).as(:character) }
rule(:string) { (str('"') >> (match(/[^"\\]/) | str('\\\\')| str('\\"')).repeat(0) >> str('"')).as(:string) }
rule(:variable) { match(/[a-zA-Z]/).repeat(1).as(:variable) }
rule(:sexp) { (str('(') >> space >> (expression >> space).repeat(0) >> space >> str(')')).as(:sexp) }
rule(:expression) { character | boolean | string | variable | sexp }
root(:expression)
end
def translate(ast)
if ast.is_a? Hash
tag = ast.keys[0]
{
tag: tag,
value: translate(ast[tag]),
}
elsif ast.is_a? Array
ast.map { |v| translate(v) }
else
ast.str
end
end
debug = true
if debug
require 'pp'
def test(sexp)
puts sexp
pp translate(Parser.new.parse(sexp))
end
test(%q!(foo bar (baz #t))!)
test(%q!(foo #\c #\4 #\newline #\space)!)
test(%q!(foo "hoge")!)
test(%q!(foo "hoge" "\"fuga\"")!)
test('(foo "\\\\aaa\\\\")')
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment