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