Skip to content

Commit

Permalink
Style improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
ajoo committed Apr 10, 2008
1 parent 65fc19b commit 6cbc8bd
Show file tree
Hide file tree
Showing 15 changed files with 266 additions and 33 deletions.
15 changes: 15 additions & 0 deletions rparsec/context.rb
Expand Up @@ -3,6 +3,7 @@
class ParseContext
attr_reader :error, :src, :index, :result
attr_writer :error, :index, :result

def initialize(src, index=0, error=nil)
@src, @index, @error = src, index, error
end
Expand All @@ -12,53 +13,67 @@ def scanner
@scanner.pos= @index
@scanner
end

def prepare_error
@error.flatten! if @error.kind_of?(Array)
end

def to_msg
return '' if @error.nil?
return @error.msg unless @error.kind_of?(Array)
@error.map{|e|e.msg}.join(' or ')
end

def error_input
return nil if @error.nil?
err = @error
err = err.last if err.kind_of? Array
err.input
end

def reset_error
@error = nil
end

def current
@src[@index]
end

def eof
@index >= @src.length
end

def available
@src.length - @index
end

def peek i
@src[@index+i]
end

def next
@index += 1
end

def advance n
@index += n
end

def retn(val)
@result = val
true
end

def failure(msg=nil)
@error = Failure.new(@index, get_current_input, msg)
return false
end

def expecting(expected=nil)
@error = Expected.new(@index, get_current_input, expected)
return false
end

def get_current_input
return nil if eof
current
Expand Down
7 changes: 5 additions & 2 deletions rparsec/error.rb
Expand Up @@ -4,14 +4,17 @@ class ParserException < StandardError
def_readable :index
end
class Failure
def initialize(ind, input, msg=nil)
@index, @input, @msg = ind, input, msg
def initialize(ind, input, message=nil)
@index, @input, @msg = ind, input, message
end

attr_reader :index, :input
attr_writer :index

def msg
return @msg.to_s
end

Precedence = 100
end

Expand Down
71 changes: 57 additions & 14 deletions rparsec/expressions.rb
Expand Up @@ -12,21 +12,25 @@ class OperatorTable
# operators attribute is used internally. Do not access it.
#
attr_reader :operators

#
# Re-initialize the operator table.
# Re-initialize the operator table. Internal use only.
#
def reinit
@operators = []
end

#
# To create an OperatorTable instance.
# If a block is given, it is invoked to do post-instantiation.
# For example:
#
# OperatorTable.new do |tbl|
# tbl.infixl(char(?+) >> Plus)
# tbl.infixl(char(?-) >> Minus)
# tbl.prefix(char(?-) >> Neg)
# tbl.infixl(char(?+) >> Plus, 10)
# tbl.infixl(char(?-) >> Minus, 10)
# tbl.infixl(char(?*) >> Mul, 20)
# tbl.infixl(char(?/) >> Div, 20)
# tbl.prefix(char(?-) >> Neg, 50)
# end
#
def self.new
Expand All @@ -37,19 +41,49 @@ def self.new
end
this
end
private

#
# To define methods for registering operator.
# This is typically used internally.
# Defines a prefix operator that returns a unary Proc object with a precedence associated.
# Returns self.
#
def self.def_operator(*kinds)
kinds.each do |kind|
define_method(kind) do |op, precedence|
add(kind, op, precedence)
end
end
def prefix(op, precedence)
add(:prefix, op, precedence)
end

#
# Defines a postfix operator that returns a unary Proc object with a precedence associated.
# Returns self.
#
def postfix(op, precedence)
add(:postfix, op, precedence)
end

#
# Defines a left associative infix operator that returns a binary Proc object with a precedence
# associated. Returns self.
#
def infixl(op, precedence)
add(:infixl, op, precedence)
end

#
# Defines a right associative infix operator that returns a binary Proc object with a precedence
# associated. Returns self.
#
def infixr(op, precedence)
add(:infixr, op, precedence)
end
def_operator(*Associativities)

#
# Defines a non-associative infix operator that returns a binary Proc object with a precedence
# associated. Returns self.
#
def infixn(op, precedence)
add(:infixn, op, precedence)
end

private

def add(*entry)
@operators << entry
self
Expand All @@ -63,15 +97,19 @@ def add(*entry)
#
module Expressions
private

def self.array_to_dict arr
result = {}
arr.each_with_index do |key,i|
result [key] = i unless result.include? key
end
result
end

KindPrecedence = array_to_dict Associativities

public

#
# build an expression parser using the given term parser
# and operator table.
Expand All @@ -82,7 +120,9 @@ def self.build(term, table, delim=nil)
# sort so that higher precedence first.
apply_operators(term, prepare_suites(table).sort, delim)
end

private

def self.apply_operators(term, entries, delim)
# apply operators stored in [[precedence,associativity],[op...]] starting from beginning.
entries.inject(term) do |result, entry|
Expand All @@ -93,6 +133,7 @@ def self.apply_operators(term, entries, delim)
apply_operator(result, op, Associativities[kind_index], delim)
end
end

def self.apply_operator(term, op, kind, delim)
term, op = ignore_rest(term, delim), ignore_rest(op, delim)
# we could use send here,
Expand All @@ -114,10 +155,12 @@ def self.apply_operator(term, op, kind, delim)
raise ArgumentError, "unknown associativity: #{kind}"
end
end

def self.ignore_rest(parser, delim)
return parser if delim.nil?
parser << delim
end

def self.prepare_suites(table)
# create a hash with [precedence, associativity] as key, and op as value.
suites = {}
Expand Down

0 comments on commit 6cbc8bd

Please sign in to comment.