
#include <poplar/Vertex.hpp> 


class Preprocessor: public poplar::Vertex {
    public:
    poplar::InOut<poplar::Vector<char>> inbuf;
    poplar::Output<poplar::Vector<char>> outbuf;

    bool compute() {
        
#pragma IPUpy_start [stdout=outbuf, inbuf=inbuf<char>]

for i, c in enumerate(inbuf):
    if c == 0:
        src = ''.join(chr(x) for x in inbuf[:i])
        break


POPPPY_HEADER = """
// ------------------------ This code was inserted by IPUpyc -------------------------- //
#include <poplar/Vertex.hpp>
#include "poplar/StackSizeDefs.hpp" 
#define RECURSIVE_FUNCTION_SIZE (5 * 1024)
DEF_STACK_USAGE(RECURSIVE_FUNCTION_SIZE, "IPUpy_init");
DEF_STACK_USAGE(RECURSIVE_FUNCTION_SIZE, "IPUpy_deinit");
DEF_STACK_USAGE(RECURSIVE_FUNCTION_SIZE, "IPUpy_add_memory_as_array");
DEF_STACK_USAGE(RECURSIVE_FUNCTION_SIZE, "IPUpy_do_str");
DEF_STACK_USAGE(RECURSIVE_FUNCTION_SIZE, "IPUpy_set_stdout");
extern "C" void IPUpy_init(char *poplar_stack_bottom);
extern "C" void IPUpy_deinit(void);
extern "C" void IPUpy_add_memory_as_array(const char* name, void* data, size_t num_elts, char dtype);
extern "C" void IPUpy_do_str(const char *src, int is_single_line);
extern "C" void IPUpy_set_stdout(char* _stdout, int len);
// ------------------------ This code was inserted by IPUpyc -------------------------- //
"""
IPUpy_START_LINES = """
{indent}// ------------------------ This code was generated by IPUpyc -------------------------- //
{indent}char* poplar_stack_bottom;
{indent}asm volatile("mov %[poplar_stack_bottom], $m11" : [poplar_stack_bottom] "+r" (poplar_stack_bottom) ::);
{indent}IPUpy_set_stdout({set_stdout_args});
{indent}IPUpy_init(poplar_stack_bottom);
"""
IPUpy_VARIABLE_LINE = """{indent}IPUpy_add_memory_as_array("{pyname}", &{cppname}[0], {cppname}.size(), {dtype});"""
IPUpy_PAYLOAD_START = """
{indent}IPUpy_do_str(\""""
IPUpy_PAYLOAD_END = """", 0);
{indent}IPUpy_deinit();
{indent}// ------------------------- This code was generated by IPUpyc ------------------------ //
"""

def parse_varname(varname):
    pyname, cppname = varname.split("=") if "=" in varname else (varname, varname)
    pyname, cppname = pyname.strip(), cppname.strip()
    if cppname.endswith("<float>"):
        cppname, dtype = cppname[:-7].strip(), ord("f")
    elif cppname.endswith("<int>"):
        cppname, dtype = cppname[:-5].strip(), ord("i")
    elif cppname.endswith("<char>"):
        cppname, dtype = cppname[:-6].strip(), ord("b")
    else:
        dtype = ord("i")
    return pyname, cppname, dtype

def preprocess_block(lines):
    header, python_lines = lines[0], lines[1:]
    indent = header[:header.find('#pragma')]
    var_lines = []
    set_stdout_args = "NULL, 0"
    var_list = ' '.join(header.split()[2:])
    assert(var_list[0] == '[' and var_list[-1] == ']')
    for item in var_list[1:-1].split(','):
        pyname, cppname, dtype = parse_varname(item)
        if pyname == 'stdout':
            set_stdout_args = '&{cppname}[0], {cppname}.size()'.format(cppname=cppname)
            continue
        var_lines.append(IPUpy_VARIABLE_LINE.format(
            indent=indent, pyname=pyname, cppname=cppname, dtype=dtype))

    print(IPUpy_START_LINES.format(indent=indent, set_stdout_args=set_stdout_args))
    for ln in var_lines:
        print(ln)
    print(IPUpy_PAYLOAD_START.format(indent=indent), end='')
    for line in filter(lambda ln: ln.strip(), python_lines):
        assert(line.startswith(indent))
        line = line.replace('\\', '\\\\').replace('"', '\\\"')
        print(line[len(indent):] + '\\n', end="")
    print(IPUpy_PAYLOAD_END.format(indent=indent))


current_block = []
print(POPPPY_HEADER)

for line in src.splitlines():
    line_start = ' '.join(line.split()[:2])

    # Not already in a IPUpy block
    if not current_block:
        # Enter a new block
        if line_start == '#pragma IPUpy_start':
            current_block.append(line)
        elif line_start == '#pragma IPUpy_end':
            raise RuntimeError("Found python block end outside a python block")
        else:
            print(line)
        continue

    # We're in a block, is this the end?
    if line_start == '#pragma IPUpy_end':
        preprocess_block(current_block)
        current_block = []
        continue

    # Stay in the block
    current_block.append(line)

if current_block:
    raise RuntimeError("End of file found inside python block")


#pragma IPUpy_end
        return true;
    }
};


