module WLang
class RuleSet
#
# Imperative ruleset, providing special tags to iterate and instantiate
# conditionaly.
#
# For an overview of this ruleset, see the wlang {specification file}[link://files/specification.html].
#
module Imperative
U=WLang::RuleSet::Utils
# Regular expression for #1 in *{wlang/hosted}{...}
EACH_REGEXP = /^([^\s]+)((\s+(using\s+([_a-z]+)))?(\s+(as\s+([a-z]+(,\s+[a-z]+)*)))?)?$/
# 1 23 4 5 6 7 8
# 1 2 3 4 5
# Default mapping between tag symbols and methods
DEFAULT_RULESET = {'?' => :conditional, '*' => :enumeration}
#
# Conditional as ?{wlang/hosted}{...}{...}
#
# (third block is optional) Instantiates #1, looking for an expression in the
# hosting language. Evaluates it, looking for a boolean value (according to
# boolean semantics of the hosting language). If true, instantiates #2,
# otherwise instantiates #3 if present.
#
def self.conditional(parser, offset)
expression, reached = parser.parse(offset, "wlang/ruby")
value = parser.evaluate(expression)
if value
then_block, reached = parser.parse_block(reached)
if parser.has_block?(reached)
else_block, reached = parser.parse_block(reached, "wlang/dummy")
end
[then_block, reached]
else
then_block, reached = parser.parse_block(reached, "wlang/dummy")
else_block = ""
if parser.has_block?(reached)
else_block, reached = parser.parse_block(reached)
end
[else_block, reached]
end
end
# Install args on the parser
def self.merge_each_args(names, args)
hash = {}
size = names.length>args.length ? args.length : names.length
0.upto(size-1) do |i|
hash[names[i]] = args[i]
end
hash
end
#
# Enumeration as *{wlang/hosted using each as x}{...}{...}
#
# (third block is optional) Instantiates #1, looking for an expression in the
# hosting language. Evaluates it, looking for an enumerable. Iterates all its
# elements, instanciating #2 for each of them (the iterated value is set under
# name x in the scope). If #3 is present, it is instantiated between elements.
#
def self.enumeration(parser, offset)
expression, reached = parser.parse(offset, "wlang/ruby")
# decode 'wlang/hosted using each as x' expression
hash = U.expr(:expr,
["using", :var, false],
["as", :multi_as, false]).decode(expression, parser)
hash[:using] = "each" unless hash[:using]
hash[:as] = [] unless hash[:as]
parser.syntax_error(offset, "invalid loop expression '#{expression}'") if hash.nil?
# evaluate 'wlang/hosted' sub-expression
value = hash[:expr]
if value.nil?
expression, reached = parser.parse_block(reached, "wlang/dummy")
expression, reached = parser.parse_block(reached, "wlang/dummy") if parser.has_block?(reached)
["",reached]
else
raise "Enumerated value #{value} does not respond to #{hash[:using]}"\
unless value.respond_to?(hash[:using])
# some variables
iterator, names = hash[:using].to_sym, hash[:as]
buffer = parser.factor_buffer
# wlang start index of each block
block2, block3, theend = reached, nil, nil # *{}{block2}{block3}theend
first = true
# iterate now
value.send iterator do |*args|
if not(first) and parser.has_block?(block3)
# parse #3, positioned at reached after that
parsed, theend = parser.parse_block(block3)
parser.append_buffer(buffer, parsed, true)
end
# install arguments and parse block2, positioned at block3
parser.context_push(merge_each_args(names, args))
parsed, block3 = parser.parse_block(block2)
parser.append_buffer(buffer, parsed, true)
parser.context_pop
first = false
end
# Empty array special case
unless block3
parsed, block3 = parser.parse_block(block2, "wlang/dummy")
end
# Singleton array special case
unless theend
if parser.has_block?(block3)
parsed, theend = parser.parse_block(block3, "wlang/dummy")
else
theend = block3
end
end
[buffer, theend]
end
end
end # module Imperative
end
end