Download
109 lines 3.2 KiBMoonScriptModified 2022-06-08executable raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
#!/usr/bin/env moon
util = require 'util'
import log, viz, set_file from util

number_code = (code, color="1")->
    line = 0
    (code\gsub("\n$","")\gsub "[^\n]*", =>
        line += 1
        "\x1b[2m#{("% 4d")\format line}|\x1b[22m \x1b[#{color}m#{@}\x1b[m"
    )

verbose = false
compile = false
files, args = {}, {}
output_file = nil
qbe_file = nil
asm_file = nil
so_file = nil
i = 1
while i <= #arg
    a = arg[i]
    if a == "-h" or a == "--help"
        print "blangc - compile blang programs\nUsage: blangc [-v|--verbose] [-c|--compile] [-o output_binary_file] [-a output_asm_file] [-q output_qbe_file] file"
        os.exit!
    elseif a == "-v" or a == "--verbose"
        verbose = true
    elseif a == "-c" or a == "--compile"
        compile = true
    elseif a == "-o"
        output_file = assert(arg[i+1], "No output name provided")
        i += 2
        continue
    elseif a == "-a"
        asm_file = assert(arg[i+1], "No asm name provided")
        i += 2
        continue
    elseif a == "-s"
        so_file = assert(arg[i+1], "No .so file provided")
        i += 2
        continue
    elseif a == "-q"
        qbe_file = assert(arg[i+1], "No qbe name provided")
        i += 2
        continue
    elseif a == "--"
        args = {table.unpack(arg, i+1, #arg)}
        break
    else
        table.insert files, a
    i += 1

unless verbose
    log = ->
    util.log = log

parse = require 'parse'
import compile_prog from require 'compile'

mktemp = (suffix)-> io.popen("mktemp --suffix=#{suffix} /tmp/blang.XXXXXX")\read("l")

assert #files == 1, "Expected exactly one file, but got #{#files}"

filename = files[1]
file = assert(io.open(filename), "Couldn't open file: #{filename}")
log "\x1b[1;4mFile #{filename}\x1b[m"
with file
    dirname = filename\match("^.*/") or "./"
    base_name = filename\match("[^/]*$")\gsub("%.bl$", "")
    text = \read "*a"
    set_file filename, text
    log number_code(text, "34;1")
    ast = parse text, filename
    assert ast, "No match!"
    ast = ast[1]
    log "#{viz ast}"

    code = compile_prog ast, filename
    log number_code(code, "36;1")

    qbe_file or= filename..".qbe"

    with io.open qbe_file, "w"
        \write code
        \close!

    run = (cmd)->
        log "> \x1b[1m#{cmd}\x1b[m"
        success,how,what = os.execute cmd
        if not success
            log "\x1b[31;1mCommand `#{cmd}` #{how}ed: #{what}\x1b[m"
            os.exit(1)

    log "\x1b[2mRunning QBE...\x1b[m"
    asm_file or= filename..".s"
    run "qbe #{qbe_file} > #{asm_file}"
    log "\x1b[2mCompiling assembly...\x1b[m"
    output_file or= dirname..base_name..".o"
    run "rm -f #{output_file}"
    if compile
        run "cc -O3 #{asm_file} -c -fPIC -ggdb -o #{output_file} -lm -lbhash -lbp -lgc -L . -lintern -lcord"
        so_file or= dirname.."lib"..base_name..".so"
        run "rm -f #{so_file}"
        run "cc -O3 lib/*.o -shared -Wl,-soname,lib#{base_name}.so.1 -o #{so_file} #{output_file} -lc -lm -lbhash -lbp -lgc -L . -lintern -lcord"
        log "Compiled to #{so_file}"
    else
        run "cc -O3 #{asm_file} -ggdb -o #{output_file} lib/*.o -lc -lm -lbhash -lbp -lgc -L . -lintern -lcord"
        log "Compiled to #{output_file}"

    \close!