Skip to content
This repository has been archived by the owner on Dec 24, 2023. It is now read-only.

Commit

Permalink
Reworked templates for parser, now everyfin is awesome
Browse files Browse the repository at this point in the history
  • Loading branch information
deathbeam committed Mar 23, 2016
1 parent 1116ddb commit 8e17e2e
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 28 deletions.
47 changes: 31 additions & 16 deletions lib/spoon/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@

module Spoon
class Parser < Spoon::Util::IndentParser
store :COMMA, 'op(",")'
store :HASH, 'key("#")'
store :DOT, 'op(".")'
store :RETURN, 'key("return")'
template :COMMA, 'op(",")'
template :HASH, 'key("#")'
template :DOT, 'op(".")'
template :RETURN, 'key("return")'
template :ARROW, 'sym("->")'
template :DEF, 'key("def")'
template :IF, 'key("if")'
template :ELSE, 'key("else")'

# Matches entire file, skipping all whitespace at beginning and end
the :root, [
Expand Down Expand Up @@ -96,28 +100,39 @@ class Parser < Spoon::Util::IndentParser

# Matches closure
# example: (a) -> b
rule(:closure) { (parens(parameter_list.as(:parameters)).maybe >> sym("->") >> body.as(:body)).as(:closure) }
the :closure, [
'(parens(parameter_list:parameters)? AND ARROW AND body:body):closure'
]

# Matches function parameter
# example a = 1
rule(:parameter) { word.as(:name) >> (op("=") >> expression.as(:value)).maybe }
the :parameter, [
'word:name AND (op("=") AND expression:value)?'
]

# Matches expression
rule(:expression) { (value.as(:left) >> operator >> value.as(:right)) | value }
the :expression, [
'(value:left AND operator AND value:right)',
'value'
]

# Matches function definition
# example: def (a) b
rule(:function) {
(key("def") >> word.as(:name) >>
(parens(parameter_list.as(:parameters)).maybe >> body.as(:body) | body.as(:body))).as(:function)
}
the :function, [
'(DEF AND word:name AND function_body):function'
]

# Matches function body
the :function_body, [
'parens(parameter_list:parameters)? AND body:body',
'body:body'
]

# Matches if-else if-else in recursive structure
# example: if (a) b else if(c) d else e
rule(:condition) {
(key("if") >> parens(expression.as(:body)) >>
body.as(:if_true) >>
(key("else") >> body.as(:if_false)).maybe).as(:condition)
}
the :condition, [
'(IF AND parens(expression:body) AND body:if_true AND '\
'(ELSE AND body:if_false)?):condition'
]
end
end
34 changes: 22 additions & 12 deletions lib/spoon/util/parser_extensions.rb
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
require 'to_regexp'
require 'spoon/util/indent_parser'

module Spoon
module Util
# Monkey-patch the parser to include some common methods
class Spoon::Util::IndentParser
@@storage = {
" AND " => " >> ",
" OR " => " | ",
"?" => ".maybe"
@@templates = {
' AND ' => ' >> ',
' OR ' => ' | ',
'?' => '.maybe',
'/ \* ([0-9]+)/' => '.repeat(\1)',
'/:([\w_]+)/' => '.as(:\1)'
}

# DSL for our awesome parser
def self.store(key, value)
@@storage[key] = value
def self.template(key, value)
@@templates[key] = value
end

def self.the(name, arr)
arr.map! do |item|
temp = item
@@storage.each { |k, v| temp = temp.gsub(k.to_s, v.to_s) }
item = temp
result = item

@@templates.each do |k, v|
toreplace = k.to_s

if k.respond_to? :to_regexp
toreplace = k.to_regexp || k.to_s
end

result = result.gsub(toreplace, v.to_s)
end

result
end

script = arr.join(" | ")
.gsub(/ \* ([0-9]+)/, '.repeat(\1)')
.gsub(/((?:\w+)|(?:\(.+\))):(\w+)/, '\1.as(:\2)')

rule(name) { eval(" " + script) }
end

Expand Down
1 change: 1 addition & 0 deletions spoon.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
spec.add_dependency "colorize"
spec.add_dependency "parslet"
spec.add_dependency "thor"
spec.add_dependency "to_regexp"

spec.add_development_dependency "bundler", "~> 1.11"
spec.add_development_dependency "coveralls"
Expand Down

0 comments on commit 8e17e2e

Please sign in to comment.