#! /usr/bin/env python3

def j(l, ext):
    return ' '.join('%s.%s' % (it, ext) for it in l)

mlj = lambda l: j(l, 'ml')
mlij = lambda l: j(l, 'mli')
cmij = lambda l: j(l, 'cmi')
cmoj = lambda l: j(l, 'cmo')
cmxj = lambda l: j(l, 'cmx')

def _c(n, ext):
    return '%s.%s' % (n, ext)

mln = lambda n: _c(n, 'ml')
mlin = lambda n: _c(n, 'mli')
cmin = lambda n: _c(n, 'cmi')
cmon = lambda n: _c(n, 'cmo')
cmxn = lambda n: _c(n, 'cmx')


def build(ctx):
    mlis = ['ast', 'tasm_ast']
    metalib_mls = ['common']
    lib_mls = ['exc', 'scoping', 'cseg', 'switches', 'config',
               'assemble', 'tasm_stringify', 'tasm_bytecode']
    aff_mlis = ['parser', 'tasm_parser']
    non_exec_mls = ['parser', 'scanner',
                    'tasm_parser', 'tasm_scanner',
                    'exp', 'compile']
    target_mls = ['weave']

    external_libs = ','.join(ctx.env.LIBS)
    incl_folder = '%s/src/compiler/' % ctx.out_dir
    build_prefix = '%s/' % ctx.out_dir
    # stupid waf!!

    ctx.exec_command([
        'ruby', 'src/tasm/ccg.rb',
        'src/compiler', 'src/tasm/scanner.mll.p'
    ])

    obj_ext = cmxn if ctx.options.compile_natively else cmon
    obj_j = cmxj if ctx.options.compile_natively else cmoj

    oc_rule = '${OCAMLFIND} ${OC} ${DEBUG} -package %s'\
              ' -I %s -c -o ${TGT} ${SRC}'\
              % (external_libs, incl_folder,)

    ctx.add_group('parser')
    ctx(rule='${MENHIR} --base %s/src/compiler/parser ${SRC}' % ctx.out_dir,
        source='parser.mly',
        target='parser.ml parser.mli')
    ctx(rule='${MENHIR} --base %s/src/compiler/tasm_parser ${SRC}'\
        % ctx.out_dir,
        source='tasm_parser.mly',
        target='tasm_parser.ml tasm_parser.mli')

    ctx(rule='${OCAMLLEX} ${SRC} -o %s${TGT}' % build_prefix,
        source='scanner.mll',
        target='scanner.ml')
    ctx(rule='${OCAMLLEX} ${SRC} -o %s${TGT}' % build_prefix,
        source='tasm_scanner.mll',
        target='tasm_scanner.ml')

    ctx(rule=oc_rule,
        source='ast.mli',
        target=ctx.path.get_bld().find_or_declare('ast.cmi'))
    ctx(rule=oc_rule,
        source='tasm_ast.mli',
        target=ctx.path.get_bld().find_or_declare('tasm_ast.cmi'))

    def cpl_oc(n, src_ext_f, tgt_ext_f):
        ctx(rule=oc_rule,
            source=src_ext_f(n),
            target=tgt_ext_f(n))

    ctx.add_group('metalib')
    for it in metalib_mls:
        cpl_oc(it, mln, obj_ext)

    ctx.add_group('lib')
    for it in lib_mls:
        cpl_oc(it, mln, obj_ext)

    for it in aff_mlis:
        cpl_oc(it, mlin, cmin)

    ctx.add_group('non_exec')
    for it in non_exec_mls:
        cpl_oc(it, mln, obj_ext)

    def cpl_tgt(n):
        ctx(rule=oc_rule,
            source=mln(n),
            target=obj_ext(n))
        ctx(rule='${OCAMLFIND} ${OC} ${DEBUG} -package %s -linkpkg'
                 ' -o %s${TGT} ${SRC}' %\
                 (external_libs, build_prefix),
            source=obj_j(metalib_mls + lib_mls + non_exec_mls + [n]),
            target=n)

    ctx.add_group('tgt')
    for n in target_mls:
        cpl_tgt(n)
