class Eggshell::Compiler::DefaultAssembler
Public Instance Methods
_expand_for(args, lines)
click to toggle source
# File lib/eggshell/compiler.rb, line 167 def _expand_for(args, lines) end
_expand_if(args, lines)
click to toggle source
takes chained if-elsif-else macros and creates actual if/elsif/else code @param Array args Arguments given to @pipe chain
# File lib/eggshell/compiler.rb, line 143 def _expand_if(args, lines) id = Time.new.to_i.to_s @pending_funcs[-1][1] << insert_statement(HANDLER_SAVE_REF, 'ID' => id) lines.each do |line| type = line[1] cond_args = line[2] cond = cond_args.is_a?(Array) ? cond_args[0] : nil # @todo expand condition check as natively as possible if type != 'else' @pending_funcs[-1][1] << "\t#{type} (processor.expr_eval(#{cond.inspect}))" else @pending_funcs[-1][1] << "\telse" end #puts ">> #{line[3][0..2].inspect}" assemble(line[3]) if type == 'else' @pending_funcs[-1][1] << "\tend" end end @pending_funcs[-1][1] << insert_statement(HANDLER_RESTORE_REF, 'ID' => id) end
_expand_while(args, lines)
click to toggle source
# File lib/eggshell/compiler.rb, line 170 def _expand_while(args, lines) end
add_func(name, func_body)
click to toggle source
# File lib/eggshell/compiler.rb, line 103 def add_func(name, func_body) @pending_funcs << [name, [func_body]] end
add_lines(lines)
click to toggle source
# File lib/eggshell/compiler.rb, line 173 def add_lines(lines) if @chained_macros.length > 0 info = @chained_macros.pop _expand_if(info[:args], lines) else lines.each do |line| if line.is_a?(String) @pending_funcs[-1][1] << insert_statement(LINE, 'LINE' => line.inspect) elsif line.is_a?(Eggshell::Line) @pending_funcs[-1][1] << insert_statement(LINE_EGG, 'LINE' => line.line.inspect, 'TAB' => line.tab_str.inspect, 'INDENT' => line.indent_lvl, 'LINE_NUM' => line.line_num) elsif line.is_a?(Array) id = Time.new.to_i.to_s @pending_funcs[-1][1] << insert_statement(HANDLER_SAVE_REF, 'ID' => id) assemble([line]) @pending_funcs[-1][1] << insert_statement(HANDLER_RESTORE_REF, 'ID' => id) end end end end
assemble(parse_tree)
click to toggle source
# File lib/eggshell/compiler.rb, line 231 def assemble(parse_tree) joiner = @opts[:join] || "\n" parse_tree = parse_tree.tree if parse_tree.is_a?(Eggshell::ParseTree) raise Exception.new("input not an array or ParseTree") if !parse_tree.is_a?(Array) last_type = nil last_line = 0 deferred = nil inline_count = -1 parse_tree.each do |unit| if unit.is_a?(String) do_line(unit) last_line += 1 last_type = nil elsif unit.is_a?(Eggshell::Line) do_line(unit.to_s) last_line = unit.line_nameum last_type = nil elsif unit.is_a?(Array) name = unit[1] args_o = unit[2] || [] args = args_o lines = unit[ParseTree::IDX_LINES] lines_start = unit[ParseTree::IDX_LINES_START] lines_end = unit[ParseTree::IDX_LINES_END] _handler, _name, _args, _lines = deferred if unit[0] == :block handler = @processor.get_block_handler(name) if deferred if last_type == :macro && (lines_start - last_line <= 1) && _handler.equal?(handler, name) chain_append([]) add_lines(lines) else inline_count = -1 commit_handler(_name, args_o) #@pending_funcs[-1][1] << "# block: #{name} (LINE: #{lines_start})" start_block(name, args_o, []) add_lines(lines) deferred = [handler, name, args, lines] end else #@pending_funcs[-1][1] << "# block: #{name} (LINE: #{lines_start})" inline_count = -1 start_block(name, args_o, []) add_lines(lines) deferred = [handler, name, args, lines] end last_line = lines_end else handler = @processor.get_macro_handler(name) @pending_funcs[-1][1] << "\t# macro: #{name} (LINE: #{lines_start})" if deferred && lines_start - last_line == 1 _last = _lines[-1] pinline = false # check last line of last block for number of inlines if inline_count == -1 inline_count = 0 _last.to_s.gsub(Eggshell::Processor::PIPE_INLINE) do |m| inline_count += 1 end inline_count = -1 if inline_count == 0 end if inline_count > 0 pinline = true inline_count -= 1 pipe_inline_start() else pipe_append_start() end start_macro(name, args_o, []) add_lines(lines) commit_handler(name, args_o) # inline pipe; join output with literal \n to avoid processing lines in block process if pinline pipe_inline_end() else pipe_append_end() end else if deferred #start_block(_name, _args, []) #add_lines(_lines) commit_handler(_name, _args) deferred = nil end start_macro(name, args_o, []) add_lines(lines) commit_handler(name, args_o) end last_line = lines_end end last_type = unit[0] elsif unit $stderr.write "not sure how to handle #{unit.class}\n" $stderr.write unit.inspect $stderr.write "\n" last_type = nil end end if deferred _handler, _name, _args, _lines = deferred commit_handler(_name, _args) deferred = nil end end
chain_append(lines)
click to toggle source
# File lib/eggshell/compiler.rb, line 193 def chain_append(lines) add_lines(lines) end
commit_handler(name, args)
click to toggle source
# File lib/eggshell/compiler.rb, line 213 def commit_handler(name, args) type = @handler_stack.pop @pending_funcs[-1][1] << insert_statement(HANDLER_COMMIT, 'HANDLER_NAME' => name, 'ARGS' => args.inspect) @pending_funcs[-1][1] << "# COMMIT #{name} (#{type})\n" if type == :macro pop_func() @call_depth -= 1 end end
do_line(line)
click to toggle source
# File lib/eggshell/compiler.rb, line 111 def do_line(line) @pending_funcs[-1][1] << insert_statement(LINE_OUT, 'LINE' => line.inspect) end
init(processor, opts = {})
click to toggle source
:func_main: entry point to processing data :func_main_body: starting body initialization @todo :exception_handler: defaults to 'raise Exception.new' @todo :
# File lib/eggshell/compiler.rb, line 91 def init(processor, opts = {}) @processor = processor @opts = opts @pending_funcs = [] @funcs = [] @macro_counter = 1 @handler_stack = [] @call_depth = 0 @chained_macros = [] add_func(opts[:func_main] ? opts[:func_main] : 'process()', opts[:func_main_body] ? opts[:func_main_body] : BODY) end
insert_statement(str, kv)
click to toggle source
# File lib/eggshell/compiler.rb, line 223 def insert_statement(str, kv) kv.each do |key, val| str = str.gsub("@@#{key}@@", val.to_s) end str end
pipe_append_end()
click to toggle source
# File lib/eggshell/compiler.rb, line 209 def pipe_append_end @pending_funcs[-1][1] << PIPE_APPEND_END end
pipe_append_start()
click to toggle source
# File lib/eggshell/compiler.rb, line 205 def pipe_append_start @pending_funcs[-1][1] << PIPE_APPEND_START end
pipe_inline_end()
click to toggle source
# File lib/eggshell/compiler.rb, line 201 def pipe_inline_end @pending_funcs[-1][1] << PIPE_INLINE_END end
pipe_inline_start()
click to toggle source
# File lib/eggshell/compiler.rb, line 197 def pipe_inline_start @pending_funcs[-1][1] << PIPE_INLINE_START end
pop_func()
click to toggle source
# File lib/eggshell/compiler.rb, line 107 def pop_func @funcs << @pending_funcs.pop end
start_block(name, args, lines)
click to toggle source
# File lib/eggshell/compiler.rb, line 115 def start_block(name, args, lines) #puts "> b: #{name}" @handler_stack << :block @pending_funcs[-1][1] << insert_statement(BLOCK_HANDLER, 'HANDLER_NAME' => name, 'ARGS' => args.inspect, 'RAW_LINES' => lines.inspect) end
start_macro(name, args, lines)
click to toggle source
# File lib/eggshell/compiler.rb, line 121 def start_macro(name, args, lines) #puts "> m: #{name}" name_esc = name.gsub(/[^\w]+/, '_') func_name = "__macro_#{name_esc}_#{@macro_counter}" @pending_funcs[-1][1] << "\t#{func_name}(out, call_depth + 1)" add_func("#{func_name}(out, call_depth)", BODY_MACRO) @macro_counter += 1 @handler_stack << :macro @call_depth += 1 # @todo handle for/while/loop as well if name == 'pipe' && args && args[0].is_a?(Hash) && args[0]['chained'] == 'if' @pending_funcs[-1][1] << "\t# chained macros: #{args[0]['chained']}" @chained_macros << {:type=>args[0]['chained'], :args=>args} end @pending_funcs[-1][1] << insert_statement(MACRO_HANDLER, 'HANDLER_NAME' => name, 'ARGS' => args.inspect, 'RAW_LINES' => lines.inspect) end
write(stream)
click to toggle source
# File lib/eggshell/compiler.rb, line 351 def write(stream) while @pending_funcs.length > 0 pop_func() end @funcs.reverse.each do |func_entry| stream.write("def #{func_entry[0]}\n") stream.write(func_entry[1].join("\n")) stream.write("end\n\n") end end