<commit_before>#include "cgen.hh"

#include <iostream>
#include <sstream>
#include <vector>

#include "trim.hh"

using namespace nolang;

Cgen::Cgen()
    : m_autogen_index(0),
      m_autogen_prefix("__autogen_")
{
}

std::string Cgen::autogen()
{
    std::stringstream ss;
    ss << m_autogen_prefix << ++m_autogen_index;
    return ss.str();
}

std::string Cgen::solveNativeType(const std::string & s) const
{
    // Defaulting "int" to int32
    if (s == "int32" || s == "int") {
        return "int32_t";
    } else if (s == "int8") {
        return "int8_t";
    } else if (s == "int16") {
        return "int16_t";
    } else if (s == "int64") {
        return "int64_t";
    } else if (s == "uint32") {
        return "uint32_t";
    } else if (s == "uint8") {
        return "uint8_t";
    } else if (s == "uint16") {
        return "uint16_t";
    } else if (s == "uint64") {
        return "uint64_t";
    } else if (s == "Double") {
        return "double";
    } else if (s == "f64") {
        return "double";
    } else if (s == "f32") {
        return "float";
    }
    throw "Unknown native type: " + s;
}

TypeIdent *Cgen::solveVariable(const std::string &name, const PureMethod *m) const
{
    if (!m) return nullptr;
    for (auto var : m->variables()) {
        if (var->code() == name) {
            return var;
        }
    }
    return nullptr;
}

std::string Cgen::solveNativeType(const Statement *s, const PureMethod *m) const
{
    if (s->type() == "TypeDef") {
        if (s->code() == "void") {
            return "void";
        }
        return solveNativeType(s->code());
        // FIXME
    } else if (s->type() == "TypeIdent") {
        const TypeIdent *i = static_cast<const TypeIdent *>(s);
        std::string native = solveNativeType(i->m_var_type);
        std::cout << "aSTT " << native << "\n";
    } else if (s->type() == "Identifier") {
        TypeIdent *var = solveVariable(s->code(), m);
        if (var) {
            return solveNativeType(var->m_var_type);
            //std::cout << "STT " << native << "\n";
        }
        return "invalid";
    } else if (s->type() == "String") {
        // FIXME "const char*" or "char*"
        return "char *";
    } else if (s->type() == "Number") {
        // FIXME type and size, floats
        return "long";
    } else {
        throw std::string("Unknown type: " + s->type());
    }
    #if 0
    //if (TypeDef *tdef = dynamic_cast<TypeDef*>(s)) {
    else if (StringValue *sval = dynamic_cast<StringValue*>(s)) {
        // FIXME "const char*" or "char*"
        return "char *";
    }
    else if (NumberValue *nval = dynamic_cast<NumberValue*>(s)) {
        // FIXME type and size, floats
        return "long";
    }
    #endif
    return "";
    //return "void *";
}

std::string Cgen::solveTypeOfChain(std::vector<Statement*> chain, const PureMethod *m) const
{
    std::string res;
    for (auto c : chain) {
        std::string t = solveNativeType(c, m);
        if (!t.empty()) {
            if (res.empty()) {
                res = t;
            } else if (res == t) {
                // OK
            } else {
                // Need to solve
                std::cerr << "*** ERROR: Can't solve type of chain, conflicting types: " << res << ", " << t << "\n";
            }
        }
    }
    return res;
}

std::string Cgen::generateConst(const Statement *)
{
    // FIXME
    return "";
}

std::string Cgen::generateImport(const std::string &imp)
{
    std::string res;
    // FIXME Built-in import
    if (imp == "IO") {
       res += "#include <stdio.h>\n";
    } else {
        std::cerr << "** ERROR: Unhandled import " << imp << "\n";
    }
    return res;
}

std::vector<std::string> Cgen::generateMethodCall(const MethodCall *mc, const PureMethod *m)
{
    // Strategy is to parse params first, and store result to temporary variables.
    std::vector<std::string> ptypes;
    std::vector<std::string> pnames;
    std::vector<std::string> res;
    for (auto parm : mc->params()) {
        //std::string tmp;
        std::string pname = autogen();
        std::string t = solveTypeOfChain(parm, m);
        if (t.empty()) {
            // FIXME
            t = "void *";
        }
        ptypes.push_back(t);
        pnames.push_back(pname);
        //tmp = t + " " + pname + ";\n";
        //tmp = t + " " + pname + " = ";
        res.push_back(t + " " + pname + " = ");
        for (auto v : parm) {
            for (auto l : generateStatement(v, m)) {
                res.push_back(l);
            }
            //tmp += generateStatement(v);
        }
        //tmp += ";\n";
        //res.push_back(";\n");
        res.push_back("<EOS>");
        //ptypes.push_back(tmp);
    }
    // FIXME Hardcoding
    if (mc->namespaces().size() == 2 &&
        mc->namespaces()[0] == "IO" &&
        (mc->namespaces()[1] == "print" ||
         mc->namespaces()[1] == "println")) {
        std::string tmp;
        tmp += "printf(\"";
        for (auto v : ptypes) {
            if (v == "char *") tmp += "\%s";
            else if (v == "int") tmp += "\%d";
            else if (v == "uint8_t") tmp += "\%u";
            else if (v == "uint16_t") tmp += "\%u";
            else if (v == "uint32_t") tmp += "\%lu";
            else if (v == "uint64_t") tmp += "\%llu";
            else if (v == "int8_t") tmp += "\%d";
            else if (v == "int16_t") tmp += "\%d";
            else if (v == "int32_t") tmp += "\%ld";
            else if (v == "int64_t") tmp += "\%lld";
            // FIXME
            //else tmp += "\%d";
        }
        if (mc->namespaces()[1] == "println") {
            tmp += "\\n";
        }
        tmp += "\", ";
        bool first = true;
        for (auto v : pnames) {
            if (!first) {
                tmp += ", ";
            }
            tmp += v;
            first = false;
        }
        tmp += ");";
        res.push_back(tmp);
        res.push_back("<EOS>");
    } else {
        std::string mname;
        for (std::string n : mc->namespaces()) {
            if (!mname.empty()) mname += '.';
            mname += n;
        }
        std::string params = "(";
        bool first = true;
        for (auto v : pnames) {
            if (!first) {
                params += ", ";
            }
            params += v;
            first = false;
        }
        params += ")";
        res.push_back(mname + params);
        res.push_back("<EOS>");
    }

    return res;
}

std::vector<std::string> Cgen::generateStatement(const Statement *s, const PureMethod *m)
{
    std::vector<std::string> res;

    if (s->type() == "String" ||
        s->type() == "Number") {
        res.push_back(s->code() + " ");
    } else if (s->type() == "Op") {
        std::string pp = s->code();
        if (pp == "div") pp = "/";
        res.push_back(pp + " ");
        //res.push_back(s->code() + " ");
        //res += s->code() + " ";
    } else if (s->type() == "MethodCall") {
        const MethodCall *mc = static_cast<const MethodCall*>(s);
        for (auto l : generateMethodCall(mc, m)) {
            res.push_back(l);
        }
    } else if (s->type() == "Assignment") {
        res.push_back(s->code() + " = ");
        const Assignment *ass = static_cast<const Assignment*>(s);
        for (auto s : ass->m_statements) {
            for (auto l : generateStatement(s, m)) {
                res.push_back(l);
            }
        }
        //
    } else if (s->type() == "Identifier") {
        // Fixme typeconv
        res.push_back(s->code() + " ");
    } else if (s->type() == "EOS") {
        res.push_back("<EOS>");
    } else {
        std::cerr << "** ERROR: Unhandled statement: " << s->type() << " " << s->code() << "\n";
    }

    return res;
}

std::vector<std::string> Cgen::generateBlock(const std::vector<std::vector<Statement *>> &block, const std::string &ret, const PureMethod *m)
{
    std::vector<std::string> lines;
    for (auto line : block) {
        std::vector<std::string> tmp;
        //std::cout << "BB\n";
        for (auto stmt : line) {
            //tmp += generateStatement(stmt);
            for (auto l : generateStatement(stmt, m)) {
                //tmp += l;
                //res.push_back(l);
                //l = trim(l);
                if (!l.empty()) {
                    tmp.push_back(l);
                }
            }
            /*
            std::cout << "LLLL ";
            for (auto l : ltmp) {
                std::cout << l;
            }
            std::cout << "\n";
            */
        }
        //tmp = trim(tmp);
        if (!tmp.empty()) {
            std::string resline;
            //tmp += ";\n";
            for (auto ll : tmp) {
                if (ll == "<EOS>") {
                    resline = trim(resline);
                    if (!resline.empty()) {
                        lines.push_back(resline + ";\n");
                    }
                    resline = "";
                } else {
                    resline += ll;
                    //lines.push_back(ll);
                }
            }
            //lines.push_back(";");
            if (!resline.empty()) {
                lines.push_back(resline + ";\n");
            }
        }
    }

    /*
    if (lines.empty()) {
        return "";
    }
    */
    // FIXME multiline block does not work with this
#if 0
    if (!lines.empty() && ret != "void") {
        std::string last = lines.back();

        if (last.substr(0, 6) != "return ") {
            lines.pop_back();
            last = "return " + last;
            lines.push_back(last);
        }
    }
#endif

#if 0
    std::string res;
    for (auto line : lines) {
        res += line + ";\n";
    }

    return res;
#endif
    return lines;
}

std::vector<std::string> Cgen::generateVariable(const TypeIdent *i)
{
    std::vector<std::string> res;

    std::string native = solveNativeType(i->m_var_type);

    res.push_back(native + " " + i->code() +  ";\n");

    return res;
}

std::string Cgen::solveReturnType(const Statement *t, const PureMethod *m) const
{
    std::string ret = solveNativeType(m->returnType(), m);
#if 1
    // FIXME Forcing main to be "int"
    if (m->name() == "main") {
        //
        if (ret == "void") ret = "int";
    }
#endif
    return ret;
}

std::string Cgen::generateMethodPrototype(const PureMethod *m)
{
    // FIXME combine with below
    std::string res;

    std::string ret = solveReturnType(m->returnType(), m);

    std::string param_str;
    for (auto param : m->params()) {
        std::string t = solveNativeType(param->varType());
        if (!param_str.empty()) param_str += ", ";
        param_str += t + " " + param->code();
    }

    return ret + " " + m->name() + "(" + param_str +  ")";
}

std::string Cgen::generateMethod(const PureMethod *m)
{
    std::string res;
    std::string proto = generateMethodPrototype(m);

    std::string ret = solveReturnType(m->returnType(), m);

    std::vector<std::string> lines;
    for (auto var : m->variables()) {
        for (auto l : generateVariable(var)) {
            lines.push_back(l);
        }
    }

    for (auto block : m->blocks()) {
        for (auto l : generateBlock(block, ret, m)) {
            lines.push_back(l);
        }
    }

    if (!lines.empty() && ret != "void") {
        std::string last = trim(lines.back());

        if (last.substr(0, 7) != "return ") {
            lines.pop_back();
            last = "   return " + last;
            lines.push_back(last);
        }
    }

    std::string body;
    for (auto l : lines) {
        body += l;
    }

    //res += ret + " " + m->name() + "(" + param_str +  ") {\n";
    res += proto + " {\n";
    res += body + "\n";
    res += "}\n";

    return res;
}

std::string Cgen::generateUnit(const Compiler *c)
{
    std::string code;
    code += "#include <stdint.h>\n";
    for (auto m : c->imports()) {
        code += generateImport(m);
    }
    code += "\n/***** Prototypes **/\n";
    for (auto m : c->methods()) {
        code += generateMethodPrototype(m.second) + ";\n";
    }
    for (auto m : c->methods()) {
        code += "\n/***** Method " + m.second->name() + " **/\n";
        code += generateMethod(m.second);
    }
    return code;
}
<commit_msg>Cleanups<commit_after>#include "cgen.hh"

#include <iostream>
#include <sstream>
#include <vector>

#include "trim.hh"

using namespace nolang;

Cgen::Cgen()
    : m_autogen_index(0),
      m_autogen_prefix("__autogen_")
{
}

std::string Cgen::autogen()
{
    std::stringstream ss;
    ss << m_autogen_prefix << ++m_autogen_index;
    return ss.str();
}

std::string Cgen::solveNativeType(const std::string & s) const
{
    // Defaulting "int" to int32
    if (s == "int32" || s == "int") {
        return "int32_t";
    } else if (s == "int8") {
        return "int8_t";
    } else if (s == "int16") {
        return "int16_t";
    } else if (s == "int64") {
        return "int64_t";
    } else if (s == "uint32") {
        return "uint32_t";
    } else if (s == "uint8") {
        return "uint8_t";
    } else if (s == "uint16") {
        return "uint16_t";
    } else if (s == "uint64") {
        return "uint64_t";
    } else if (s == "Double") {
        return "double";
    } else if (s == "f64") {
        return "double";
    } else if (s == "f32") {
        return "float";
    }
    throw "Unknown native type: " + s;
}

TypeIdent *Cgen::solveVariable(const std::string &name, const PureMethod *m) const
{
    if (!m) return nullptr;
    for (auto var : m->variables()) {
        if (var->code() == name) {
            return var;
        }
    }
    return nullptr;
}

std::string Cgen::solveNativeType(const Statement *s, const PureMethod *m) const
{
    if (s->type() == "TypeDef") {
        if (s->code() == "void") {
            return "void";
        }
        return solveNativeType(s->code());
        // FIXME
    } else if (s->type() == "TypeIdent") {
        const TypeIdent *i = static_cast<const TypeIdent *>(s);
        std::string native = solveNativeType(i->m_var_type);
        std::cout << "aSTT " << native << "\n";
    } else if (s->type() == "Identifier") {
        TypeIdent *var = solveVariable(s->code(), m);
        if (var) {
            return solveNativeType(var->m_var_type);
            //std::cout << "STT " << native << "\n";
        }
        return "invalid";
    } else if (s->type() == "String") {
        // FIXME "const char*" or "char*"
        return "char *";
    } else if (s->type() == "Number") {
        // FIXME type and size, floats
        return "long";
    } else {
        throw std::string("Unknown type: " + s->type());
    }
    #if 0
    //if (TypeDef *tdef = dynamic_cast<TypeDef*>(s)) {
    else if (StringValue *sval = dynamic_cast<StringValue*>(s)) {
        // FIXME "const char*" or "char*"
        return "char *";
    }
    else if (NumberValue *nval = dynamic_cast<NumberValue*>(s)) {
        // FIXME type and size, floats
        return "long";
    }
    #endif
    return "";
    //return "void *";
}

std::string Cgen::solveTypeOfChain(std::vector<Statement*> chain, const PureMethod *m) const
{
    std::string res;
    for (auto c : chain) {
        std::string t = solveNativeType(c, m);
        if (!t.empty()) {
            if (res.empty()) {
                res = t;
            } else if (res == t) {
                // OK
            } else {
                // Need to solve
                std::cerr << "*** ERROR: Can't solve type of chain, conflicting types: " << res << ", " << t << "\n";
            }
        }
    }
    return res;
}

std::string Cgen::generateConst(const Statement *)
{
    // FIXME
    return "";
}

std::string Cgen::generateImport(const std::string &imp)
{
    std::string res;
    // FIXME Built-in import
    if (imp == "IO") {
       res += "#include <stdio.h>\n";
    } else {
        std::cerr << "** ERROR: Unhandled import " << imp << "\n";
    }
    return res;
}

std::vector<std::string> Cgen::generateMethodCall(const MethodCall *mc, const PureMethod *m)
{
    // Strategy is to parse params first, and store result to temporary variables.
    std::vector<std::string> ptypes;
    std::vector<std::string> pnames;
    std::vector<std::string> res;
    for (auto parm : mc->params()) {
        //std::string tmp;
        std::string pname = autogen();
        std::string t = solveTypeOfChain(parm, m);
        if (t.empty()) {
            // FIXME
            t = "void *";
        }
        ptypes.push_back(t);
        pnames.push_back(pname);
        //tmp = t + " " + pname + ";\n";
        //tmp = t + " " + pname + " = ";
        res.push_back(t + " " + pname + " = ");
        for (auto v : parm) {
            for (auto l : generateStatement(v, m)) {
                res.push_back(l);
            }
            //tmp += generateStatement(v);
        }
        //tmp += ";\n";
        //res.push_back(";\n");
        res.push_back("<EOS>");
        //ptypes.push_back(tmp);
    }
    // FIXME Hardcoding
    if (mc->namespaces().size() == 2 &&
        mc->namespaces()[0] == "IO" &&
        (mc->namespaces()[1] == "print" ||
         mc->namespaces()[1] == "println")) {
        std::string tmp;
        tmp += "printf(\"";
        for (auto v : ptypes) {
            if (v == "char *") tmp += "\%s";
            else if (v == "int") tmp += "\%d";
            else if (v == "uint8_t") tmp += "\%u";
            else if (v == "uint16_t") tmp += "\%u";
            else if (v == "uint32_t") tmp += "\%lu";
            else if (v == "uint64_t") tmp += "\%llu";
            else if (v == "int8_t") tmp += "\%d";
            else if (v == "int16_t") tmp += "\%d";
            else if (v == "int32_t") tmp += "\%ld";
            else if (v == "int64_t") tmp += "\%lld";
            // FIXME
            //else tmp += "\%d";
        }
        if (mc->namespaces()[1] == "println") {
            tmp += "\\n";
        }
        tmp += "\", ";
        bool first = true;
        for (auto v : pnames) {
            if (!first) {
                tmp += ", ";
            }
            tmp += v;
            first = false;
        }
        tmp += ");";
        res.push_back(tmp);
        res.push_back("<EOS>");
    } else {
        std::string mname;
        for (std::string n : mc->namespaces()) {
            if (!mname.empty()) mname += '.';
            mname += n;
        }
        std::string params = "(";
        bool first = true;
        for (auto v : pnames) {
            if (!first) {
                params += ", ";
            }
            params += v;
            first = false;
        }
        params += ")";
        res.push_back(mname + params);
        res.push_back("<EOS>");
    }

    return res;
}

std::vector<std::string> Cgen::generateStatement(const Statement *s, const PureMethod *m)
{
    std::vector<std::string> res;

    if (s->type() == "String" ||
        s->type() == "Number") {
        res.push_back(s->code() + " ");
    } else if (s->type() == "Op") {
        std::string pp = s->code();
        if (pp == "div") pp = "/";
        res.push_back(pp + " ");
        //res.push_back(s->code() + " ");
        //res += s->code() + " ";
    } else if (s->type() == "MethodCall") {
        const MethodCall *mc = static_cast<const MethodCall*>(s);
        for (auto l : generateMethodCall(mc, m)) {
            res.push_back(l);
        }
    } else if (s->type() == "Assignment") {
        res.push_back(s->code() + " = ");
        const Assignment *ass = static_cast<const Assignment*>(s);
        for (auto s : ass->m_statements) {
            for (auto l : generateStatement(s, m)) {
                res.push_back(l);
            }
        }
        //
    } else if (s->type() == "Identifier") {
        // Fixme typeconv
        res.push_back(s->code() + " ");
    } else if (s->type() == "EOS") {
        res.push_back("<EOS>");
    } else {
        std::cerr << "** ERROR: Unhandled statement: " << s->type() << " " << s->code() << "\n";
    }

    return res;
}

std::vector<std::string> Cgen::generateBlock(const std::vector<std::vector<Statement *>> &block, const std::string &ret, const PureMethod *m)
{
    std::vector<std::string> lines;
    for (auto line : block) {
        std::vector<std::string> tmp;
        //std::cout << "BB\n";
        for (auto stmt : line) {
            //tmp += generateStatement(stmt);
            for (auto l : generateStatement(stmt, m)) {
                //tmp += l;
                //res.push_back(l);
                //l = trim(l);
                if (!l.empty()) {
                    tmp.push_back(l);
                }
            }
            /*
            std::cout << "LLLL ";
            for (auto l : ltmp) {
                std::cout << l;
            }
            std::cout << "\n";
            */
        }
        //tmp = trim(tmp);
        if (!tmp.empty()) {
            std::string resline;
            //tmp += ";\n";
            for (auto ll : tmp) {
                if (ll == "<EOS>") {
                    resline = trim(resline);
                    if (!resline.empty()) {
                        lines.push_back(resline + ";\n");
                    }
                    resline = "";
                } else {
                    resline += ll;
                    //lines.push_back(ll);
                }
            }
            //lines.push_back(";");
            if (!resline.empty()) {
                lines.push_back(resline + ";\n");
            }
        }
    }

    /*
    if (lines.empty()) {
        return "";
    }
    */
    // FIXME multiline block does not work with this
#if 0
    if (!lines.empty() && ret != "void") {
        std::string last = lines.back();

        if (last.substr(0, 6) != "return ") {
            lines.pop_back();
            last = "return " + last;
            lines.push_back(last);
        }
    }
#endif

#if 0
    std::string res;
    for (auto line : lines) {
        res += line + ";\n";
    }

    return res;
#endif
    return lines;
}

std::vector<std::string> Cgen::generateVariable(const TypeIdent *i)
{
    std::vector<std::string> res;

    std::string native = solveNativeType(i->m_var_type);

    res.push_back(native + " " + i->code() +  ";\n");

    return res;
}

std::string Cgen::solveReturnType(const Statement *t, const PureMethod *m) const
{
    std::string ret = solveNativeType(m->returnType(), m);
#if 1
    // FIXME Forcing main to be "int"
    if (m->name() == "main") {
        //
        if (ret == "void") ret = "int";
    }
#endif
    return ret;
}

std::string Cgen::generateMethodPrototype(const PureMethod *m)
{
    std::string ret = solveReturnType(m->returnType(), m);

    std::string param_str;
    for (auto param : m->params()) {
        std::string t = solveNativeType(param->varType());
        if (!param_str.empty()) param_str += ", ";
        param_str += t + " " + param->code();
    }

    return ret + " " + m->name() + "(" + param_str +  ")";
}

std::string Cgen::generateMethod(const PureMethod *m)
{
    std::string res;
    std::string proto = generateMethodPrototype(m);

    std::string ret = solveReturnType(m->returnType(), m);

    std::vector<std::string> lines;
    for (auto var : m->variables()) {
        for (auto l : generateVariable(var)) {
            lines.push_back(l);
        }
    }

    for (auto block : m->blocks()) {
        for (auto l : generateBlock(block, ret, m)) {
            lines.push_back(l);
        }
    }

    if (!lines.empty() && ret != "void") {
        std::string last = trim(lines.back());

        if (last.substr(0, 7) != "return ") {
            lines.pop_back();
            last = "   return " + last;
            lines.push_back(last);
        }
    }

    std::string body;
    for (auto l : lines) {
        body += l;
    }

    res += proto + " {\n";
    res += body + "\n";
    res += "}\n";

    return res;
}

std::string Cgen::generateUnit(const Compiler *c)
{
    std::string code;
    code += "#include <stdint.h>\n";

    code += "\n/***** Imports **/\n";
    for (auto m : c->imports()) {
        code += generateImport(m);
    }

    code += "\n/***** Globals **/\n";

    code += "\n/***** Prototypes **/\n";
    for (auto m : c->methods()) {
        code += generateMethodPrototype(m.second) + ";\n";
    }
    code += "\n/***** Methods **/\n";
    for (auto m : c->methods()) {
        code += generateMethod(m.second);
    }
    return code;
}
<|endoftext|>


<commit_before>#include <cassert>
#include <cstdint>
#include <unordered_set>

// with these settings it works up to size 16
typedef uint32_t pos_t;         // increase the size of this for larger boards
constexpr pos_t CELL_WIDTH = 2; // number of bits per cell

constexpr pos_t CELL_MAX = (1 << CELL_WIDTH) - 1;          // max value of a cell
constexpr pos_t MAX_SIZE = sizeof(pos_t) * 8 / CELL_WIDTH; // max board size

struct Cell {
    pos_t value;
    Cell(pos_t value) : value(value) {}

    Cell flip() const {
        if (value == 1)
            return Cell(2);
        if (value == 2)
            return Cell(1);
        assert(false);
    }
    bool is_stone() const { return value == 1 || value == 2; }
    bool operator==(Cell o) const { return value == o.value; }
    operator bool() const { return value; }
    friend std::ostream &operator<<(std::ostream &os, const Cell cell) {
        os << ".BW"[cell.value];
        return os;
    }
};
const Cell EMPTY = Cell(0);
const Cell BLACK = Cell(1);
const Cell WHITE = Cell(2);

struct Move {
    Cell color;
    pos_t position; // meaningless if is_pass is true
    bool is_pass;
    Move(Cell color, pos_t position, bool is_pass = false)
        : color(color), position(position), is_pass(is_pass) {}
    static Move pass(Cell color) { return Move(color, 0, true); }
};

struct Score {
    pos_t black, white;
    Score() : black(0), white(0) {}
    Score(pos_t black, pos_t white) : black(black), white(white) {}

    bool operator==(Score o) const { return o.black == black && o.white == white; }
};

// a chain represents a sequence of stones with the same cell value
struct Chain {
    Cell cell;
    pos_t position, size;
    Chain(Cell cell, pos_t position, pos_t size) : cell(cell), position(position), size(size) {}
};

struct Board {
    const pos_t size;
    pos_t board;
    Board(pos_t size) : size(size), board(0) {}

    inline Cell get(pos_t pos) const {
        assert(pos < size);
        return Cell(board >> pos * CELL_WIDTH & CELL_MAX);
    }
    inline void set(pos_t pos, Cell cell) {
        assert(pos < size);
        assert(cell.value <= CELL_MAX);
        board ^= (board & CELL_MAX << pos * CELL_WIDTH) ^ cell.value << pos * CELL_WIDTH;
    }
    Score score() const {
        Score sc;
        Board left_smear(size), right_smear(size);
        Cell last_left = EMPTY, last_right = EMPTY;
        for (pos_t i = 0; i < size; i++) {
            if (Cell next = get(i))
                last_right = next;
            right_smear.set(i, last_right);
            if (Cell next = get(size - i - 1))
                last_left = next;
            left_smear.set(size - i - 1, last_left);
        }
        for (pos_t i = 0; i < size; i++) {
            Cell left = left_smear.get(i), right = right_smear.get(i);
            if ((left == BLACK && (left == right || right == EMPTY)) ||
                (right == BLACK && left == EMPTY))
                sc.black++;
            if ((left == WHITE && (left == right || right == EMPTY)) ||
                (right == WHITE && left == EMPTY))
                sc.white++;
        }
        return sc;
    }
    // returns a bitset of empty positions on the board.
    pos_t empty_set() const {
        pos_t res = 0;
        for (pos_t i = size; i--;)
            res <<= 1, res |= get(i) == EMPTY;
        return res;
    }
    // retuns a vector of all chains on the board, ordered.
    std::vector<Chain> chains() const {
        std::vector<Chain> chains{Chain(get(0), 0, 1)};
        for (pos_t i = 1; i < size; i++) {
            if (get(i) == chains.back().cell)
                chains.back().size++;
            else
                chains.push_back(Chain(get(i), i, 1));
        }
        return chains;
    }
    // remove all stones in a chain
    void clear_chain(Chain chain) {
        // we can make this O(1)
        for (pos_t i = 0; i < chain.size; i++)
            set(i + chain.position, EMPTY);
    }
    // clear any chains captured by a recent play at the given position
    bool clear_captured(pos_t position) {
        return iter_captured(position, [this](Chain c) { clear_chain(c); });
    }
    bool iter_captured(pos_t position, std::function<void(Chain)> fn) {
        // this can probably be optimized
        assert(get(position).is_stone());
        auto ch = chains();
        bool any = false;
        for (size_t i = 0; i < ch.size(); i++) {
            if (ch[i].cell.is_stone() &&
                (position == ch[i].position - 1 || position == ch[i].position + ch[i].size)) {
                // left boundary
                if (i == 0 && i + 1 < ch.size() && ch[i + 1].cell.is_stone())
                    fn(ch[i]), any |= true;
                // right boundary
                else if (i > 0 && i + 1 == ch.size() && ch[i - 1].cell.is_stone())
                    fn(ch[i]), any |= true;
                // middle
                else if (i > 0 && i + 1 < ch.size() && ch[i - 1].cell.is_stone() &&
                         ch[i + 1].cell.is_stone() && ch[i - 1].cell == ch[i + 1].cell)
                    fn(ch[i]), any |= true;
            }
        }
        return any;
    }
    bool operator==(Board o) const { return o.board == board; }
    friend std::ostream &operator<<(std::ostream &os, Board board) {
        for (pos_t i = 0; i < board.size; i++)
            os << board.get(i);
        return os;
    }
};

struct BoardHasher {
    size_t operator()(Board b) const { return b.board; }
};

struct History {
    std::unordered_set<Board, BoardHasher> states;

    void add(Board s) { states.insert(s); }
    // returns true if the given board has previously been added
    bool check(Board s) const { return states.find(s) != states.end(); }
};

struct State {
    Board board;
    History history;
    enum GameState { NORMAL, PASS, GAME_OVER } game_state = NORMAL;
    State(pos_t size) : board(size) {}

    bool terminal() const { return game_state == GAME_OVER; }
    void play(Move move) {
        assert(game_state != GAME_OVER);
        if (move.is_pass) {
            if (game_state == NORMAL)
                game_state = PASS;
            else if (game_state == PASS)
                game_state = GAME_OVER;
        } else {
            assert(legal_moves(move.color) & 1 << move.position);
            assert(board.get(move.position) == EMPTY);
            board.set(move.position, move.color);
            board.clear_captured(move.position);
            assert(!history.check(board));
            history.add(board);
            game_state = NORMAL;
        }
    }
    // retuns a bitset of all legal moves for a given color
    pos_t legal_moves(Cell color) const {
        assert(color.is_stone());
        pos_t legal = board.empty_set();
        auto illegal = [&](pos_t i) { legal &= ~(1 << i); };

        // check history
        for (pos_t i = 0; i < board.size; i++) {
            Board b = board;
            b.set(i, color);
            b.clear_captured(i);
            if (history.check(b))
                illegal(i);
        }

        // check liberties
        auto ch = board.chains();
        for (size_t i = 0; i < ch.size(); i++) {
            if (ch[i].cell == EMPTY && ch[i].size == 1) {
                Board b = board;
                b.set(ch[i].position, color);
                bool captured = b.iter_captured(ch[i].position, [](Chain) {});

                // suicide is possible only if we didn't capture any stones
                if (!captured) {
                    // left suicide
                    if (i == 0 && i < ch.size() - 2 && ch[i + 1].cell == color.flip())
                        illegal(ch[i].position);
                    // right suicide
                    else if (i == ch.size() - 1 && i > 1 && ch[i - 1].cell == color.flip())
                        illegal(ch[i].position);
                    // middle suicide
                    else if (i > 0 && i < ch.size() - 1 && ch[i - 1].cell == color.flip() &&
                             ch[i + 1].cell == color.flip())
                        illegal(ch[i].position);
                }
            }
        }
        return legal;
    }

    // append legal moves of a specific type and color to a vector.
    // TODO
    void atari_moves(Cell color, std::vector<Move> &moves) const {}
    void cell_2_conjecture(Cell color, std::vector<Move> &moves) const {}
    void safe_moves(Cell color, std::vector<Move> &moves) const {}
    void other_moves(Cell color, std::vector<Move> &moves) const {}
    void moves(Cell color, std::vector<Move> &moves) const {
        moves.push_back(Move::pass(color));
        atari_moves(color, moves);
        cell_2_conjecture(color, moves);
        safe_moves(color, moves);
        other_moves(color, moves);
    }
};
<commit_msg>Improve complexity of clear_chain<commit_after>#include <cassert>
#include <cstdint>
#include <unordered_set>

// with these settings it works up to size 16
typedef uint32_t pos_t;         // increase the size of this for larger boards
constexpr pos_t CELL_WIDTH = 2; // number of bits per cell

constexpr pos_t CELL_MAX = (1 << CELL_WIDTH) - 1;          // max value of a cell
constexpr pos_t MAX_SIZE = sizeof(pos_t) * 8 / CELL_WIDTH; // max board size

struct Cell {
    pos_t value;
    Cell(pos_t value) : value(value) {}

    Cell flip() const {
        if (value == 1)
            return Cell(2);
        if (value == 2)
            return Cell(1);
        assert(false);
    }
    bool is_stone() const { return value == 1 || value == 2; }
    bool operator==(Cell o) const { return value == o.value; }
    operator bool() const { return value; }
    friend std::ostream &operator<<(std::ostream &os, const Cell cell) {
        os << ".BW"[cell.value];
        return os;
    }
};
const Cell EMPTY = Cell(0);
const Cell BLACK = Cell(1);
const Cell WHITE = Cell(2);

struct Move {
    Cell color;
    pos_t position; // meaningless if is_pass is true
    bool is_pass;
    Move(Cell color, pos_t position, bool is_pass = false)
        : color(color), position(position), is_pass(is_pass) {}
    static Move pass(Cell color) { return Move(color, 0, true); }
};

struct Score {
    pos_t black, white;
    Score() : black(0), white(0) {}
    Score(pos_t black, pos_t white) : black(black), white(white) {}

    bool operator==(Score o) const { return o.black == black && o.white == white; }
};

// a chain represents a sequence of stones with the same cell value
struct Chain {
    Cell cell;
    pos_t position, size;
    Chain(Cell cell, pos_t position, pos_t size) : cell(cell), position(position), size(size) {}
};

struct Board {
    const pos_t size;
    pos_t board;
    Board(pos_t size) : size(size), board(0) {}

    inline Cell get(pos_t pos) const {
        assert(pos < size);
        return Cell(board >> pos * CELL_WIDTH & CELL_MAX);
    }
    inline void set(pos_t pos, Cell cell) {
        assert(pos < size);
        assert(cell.value <= CELL_MAX);
        board ^= (board & CELL_MAX << pos * CELL_WIDTH) ^ cell.value << pos * CELL_WIDTH;
    }
    Score score() const {
        Score sc;
        Board left_smear(size), right_smear(size);
        Cell last_left = EMPTY, last_right = EMPTY;
        for (pos_t i = 0; i < size; i++) {
            if (Cell next = get(i))
                last_right = next;
            right_smear.set(i, last_right);
            if (Cell next = get(size - i - 1))
                last_left = next;
            left_smear.set(size - i - 1, last_left);
        }
        for (pos_t i = 0; i < size; i++) {
            Cell left = left_smear.get(i), right = right_smear.get(i);
            if ((left == BLACK && (left == right || right == EMPTY)) ||
                (right == BLACK && left == EMPTY))
                sc.black++;
            if ((left == WHITE && (left == right || right == EMPTY)) ||
                (right == WHITE && left == EMPTY))
                sc.white++;
        }
        return sc;
    }
    // returns a bitset of empty positions on the board.
    pos_t empty_set() const {
        pos_t res = 0;
        for (pos_t i = size; i--;)
            res <<= 1, res |= get(i) == EMPTY;
        return res;
    }
    // retuns a vector of all chains on the board, ordered.
    std::vector<Chain> chains() const {
        std::vector<Chain> chains{Chain(get(0), 0, 1)};
        for (pos_t i = 1; i < size; i++) {
            if (get(i) == chains.back().cell)
                chains.back().size++;
            else
                chains.push_back(Chain(get(i), i, 1));
        }
        return chains;
    }
    // remove all stones in a chain
    void clear_chain(Chain chain) {
        pos_t mask = (chain.position + chain.size != MAX_SIZE) * // handle overflow edge case
                         ~((1 << CELL_WIDTH * (chain.position + chain.size)) - 1) |
                     ((1 << CELL_WIDTH * chain.position) - 1);
        board &= mask;
    }
    // clear any chains captured by a recent play at the given position
    bool clear_captured(pos_t position) {
        return iter_captured(position, [this](Chain c) { clear_chain(c); });
    }
    bool iter_captured(pos_t position, std::function<void(Chain)> fn) {
        // this can probably be optimized
        assert(get(position).is_stone());
        auto ch = chains();
        bool any = false;
        for (size_t i = 0; i < ch.size(); i++) {
            if (ch[i].cell.is_stone() &&
                (position == ch[i].position - 1 || position == ch[i].position + ch[i].size)) {
                // left boundary
                if (i == 0 && i + 1 < ch.size() && ch[i + 1].cell.is_stone())
                    fn(ch[i]), any |= true;
                // right boundary
                else if (i > 0 && i + 1 == ch.size() && ch[i - 1].cell.is_stone())
                    fn(ch[i]), any |= true;
                // middle
                else if (i > 0 && i + 1 < ch.size() && ch[i - 1].cell.is_stone() &&
                         ch[i + 1].cell.is_stone() && ch[i - 1].cell == ch[i + 1].cell)
                    fn(ch[i]), any |= true;
            }
        }
        return any;
    }
    bool operator==(Board o) const { return o.board == board; }
    friend std::ostream &operator<<(std::ostream &os, Board board) {
        for (pos_t i = 0; i < board.size; i++)
            os << board.get(i);
        return os;
    }
};

struct BoardHasher {
    size_t operator()(Board b) const { return b.board; }
};

struct History {
    std::unordered_set<Board, BoardHasher> states;

    void add(Board s) { states.insert(s); }
    // returns true if the given board has previously been added
    bool check(Board s) const { return states.find(s) != states.end(); }
};

struct State {
    Board board;
    History history;
    enum GameState { NORMAL, PASS, GAME_OVER } game_state = NORMAL;
    State(pos_t size) : board(size) {}

    bool terminal() const { return game_state == GAME_OVER; }
    void play(Move move) {
        assert(game_state != GAME_OVER);
        if (move.is_pass) {
            if (game_state == NORMAL)
                game_state = PASS;
            else if (game_state == PASS)
                game_state = GAME_OVER;
        } else {
            assert(legal_moves(move.color) & 1 << move.position);
            assert(board.get(move.position) == EMPTY);
            board.set(move.position, move.color);
            board.clear_captured(move.position);
            assert(!history.check(board));
            history.add(board);
            game_state = NORMAL;
        }
    }
    // retuns a bitset of all legal moves for a given color
    pos_t legal_moves(Cell color) const {
        assert(color.is_stone());
        pos_t legal = board.empty_set();
        auto illegal = [&](pos_t i) { legal &= ~(1 << i); };

        // check history
        for (pos_t i = 0; i < board.size; i++) {
            Board b = board;
            b.set(i, color);
            b.clear_captured(i);
            if (history.check(b))
                illegal(i);
        }

        // check liberties
        auto ch = board.chains();
        for (size_t i = 0; i < ch.size(); i++) {
            if (ch[i].cell == EMPTY && ch[i].size == 1) {
                Board b = board;
                b.set(ch[i].position, color);
                bool captured = b.iter_captured(ch[i].position, [](Chain) {});

                // suicide is possible only if we didn't capture any stones
                if (!captured) {
                    // left suicide
                    if (i == 0 && i < ch.size() - 2 && ch[i + 1].cell == color.flip())
                        illegal(ch[i].position);
                    // right suicide
                    else if (i == ch.size() - 1 && i > 1 && ch[i - 1].cell == color.flip())
                        illegal(ch[i].position);
                    // middle suicide
                    else if (i > 0 && i < ch.size() - 1 && ch[i - 1].cell == color.flip() &&
                             ch[i + 1].cell == color.flip())
                        illegal(ch[i].position);
                }
            }
        }
        return legal;
    }

    // append legal moves of a specific type and color to a vector.
    // TODO
    void atari_moves(Cell color, std::vector<Move> &moves) const {}
    void cell_2_conjecture(Cell color, std::vector<Move> &moves) const {}
    void safe_moves(Cell color, std::vector<Move> &moves) const {}
    void other_moves(Cell color, std::vector<Move> &moves) const {}
    void moves(Cell color, std::vector<Move> &moves) const {
        moves.push_back(Move::pass(color));
        atari_moves(color, moves);
        cell_2_conjecture(color, moves);
        safe_moves(color, moves);
        other_moves(color, moves);
    }
};
<|endoftext|>


<commit_before>// added library for support windows 10<commit_msg>Fixed fatal error in library for support W10.<commit_after>// added library for support windows 10

// fixed fatal error<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "config.h"
#include "include/types.h"
#include "armor.h"

#include <errno.h>
#include <fstream>

namespace ceph {

Spinlock buffer_lock("buffer_lock");
atomic_t buffer_total_alloc;

void buffer::list::encode_base64(buffer::list& o)
{
  bufferptr bp(length() * 4 / 3 + 1);
  int l = ceph_armor(bp.c_str(), c_str(), c_str() + length());
  bp.set_length(l);
  o.push_back(bp);
}

void buffer::list::decode_base64(buffer::list& e)
{
  bufferptr bp(e.length() * 3 / 4 + 1);
  int l = ceph_unarmor(bp.c_str(), e.c_str(), e.c_str() + e.length());
  assert(l <= (int)bp.length());
  bp.set_length(l);
  push_back(bp);
}

int buffer::list::read_file(const char *fn, bool silent)
{
  struct stat st;
  int fd = ::open(fn, O_RDONLY);
  if (fd < 0) {
    if (!silent) {
      char buf[80];
      cerr << "can't open " << fn << ": " << strerror_r(errno, buf, sizeof(buf)) << std::endl;
    }
    return -errno;
  }
  ::fstat(fd, &st);
  int s = ROUND_UP_TO(st.st_size, PAGE_SIZE);
  bufferptr bp = buffer::create_page_aligned(s);
  int left = st.st_size;
  int got = 0;
  while (left > 0) {
    int r = ::read(fd, (void *)(bp.c_str() + got), left);
    if (r <= 0)
      break;
    got += r;
    left -= r;
  }
  ::close(fd);
  bp.set_length(got);
  append(bp);
  return 0;
}

int buffer::list::write_file(const char *fn, int mode)
{
  int fd = ::open(fn, O_WRONLY|O_CREAT|O_TRUNC, mode);
  if (fd < 0) {
    char buf[80];
    cerr << "can't write " << fn << ": " << strerror_r(errno, buf, sizeof(buf)) << std::endl;
    return -errno;
  }
  for (std::list<ptr>::const_iterator it = _buffers.begin();
       it != _buffers.end();
       it++) {
    const char *c = it->c_str();
    int left = it->length();
    while (left > 0) {
      int r = ::write(fd, c, left);
      if (r < 0) {
	::close(fd);
	return -errno;
      }
      c += r;
      left -= r;
    }
  }
  ::close(fd);
  return 0;
}

void buffer::list::hexdump(std::ostream &out) const
{
  out.setf(std::ios::right);
  out.fill('0');

  unsigned per = 16;

  for (unsigned o=0; o<length(); o += per) {
    out << std::hex << std::setw(4) << o << " :";

    unsigned i;
    for (i=0; i<per && o+i<length(); i++) {
      out << " " << std::setw(2) << ((unsigned)(*this)[o+i] & 0xff);
    }
    for (; i<per; i++)
      out << "   ";

    out << " : ";
    for (i=0; i<per && o+i<length(); i++) {
      char c = (*this)[o+i];
      if (isupper(c) || islower(c) || isdigit(c) || c == ' ' || ispunct(c))
	out << c;
      else
	out << '.';
    }
    out << std::dec << std::endl;
  }
  out.unsetf(std::ios::right);
}

}
<commit_msg>buffer: Include Spinlock.h.<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "config.h"
#include "include/types.h"
#include "armor.h"
#include "include/Spinlock.h"

#include <errno.h>
#include <fstream>

namespace ceph {

Spinlock buffer_lock("buffer_lock");
atomic_t buffer_total_alloc;

void buffer::list::encode_base64(buffer::list& o)
{
  bufferptr bp(length() * 4 / 3 + 1);
  int l = ceph_armor(bp.c_str(), c_str(), c_str() + length());
  bp.set_length(l);
  o.push_back(bp);
}

void buffer::list::decode_base64(buffer::list& e)
{
  bufferptr bp(e.length() * 3 / 4 + 1);
  int l = ceph_unarmor(bp.c_str(), e.c_str(), e.c_str() + e.length());
  assert(l <= (int)bp.length());
  bp.set_length(l);
  push_back(bp);
}

int buffer::list::read_file(const char *fn, bool silent)
{
  struct stat st;
  int fd = ::open(fn, O_RDONLY);
  if (fd < 0) {
    if (!silent) {
      char buf[80];
      cerr << "can't open " << fn << ": " << strerror_r(errno, buf, sizeof(buf)) << std::endl;
    }
    return -errno;
  }
  ::fstat(fd, &st);
  int s = ROUND_UP_TO(st.st_size, PAGE_SIZE);
  bufferptr bp = buffer::create_page_aligned(s);
  int left = st.st_size;
  int got = 0;
  while (left > 0) {
    int r = ::read(fd, (void *)(bp.c_str() + got), left);
    if (r <= 0)
      break;
    got += r;
    left -= r;
  }
  ::close(fd);
  bp.set_length(got);
  append(bp);
  return 0;
}

int buffer::list::write_file(const char *fn, int mode)
{
  int fd = ::open(fn, O_WRONLY|O_CREAT|O_TRUNC, mode);
  if (fd < 0) {
    char buf[80];
    cerr << "can't write " << fn << ": " << strerror_r(errno, buf, sizeof(buf)) << std::endl;
    return -errno;
  }
  for (std::list<ptr>::const_iterator it = _buffers.begin();
       it != _buffers.end();
       it++) {
    const char *c = it->c_str();
    int left = it->length();
    while (left > 0) {
      int r = ::write(fd, c, left);
      if (r < 0) {
	::close(fd);
	return -errno;
      }
      c += r;
      left -= r;
    }
  }
  ::close(fd);
  return 0;
}

void buffer::list::hexdump(std::ostream &out) const
{
  out.setf(std::ios::right);
  out.fill('0');

  unsigned per = 16;

  for (unsigned o=0; o<length(); o += per) {
    out << std::hex << std::setw(4) << o << " :";

    unsigned i;
    for (i=0; i<per && o+i<length(); i++) {
      out << " " << std::setw(2) << ((unsigned)(*this)[o+i] & 0xff);
    }
    for (; i<per; i++)
      out << "   ";

    out << " : ";
    for (i=0; i<per && o+i<length(); i++) {
      char c = (*this)[o+i];
      if (isupper(c) || islower(c) || isdigit(c) || c == ' ' || ispunct(c))
	out << c;
      else
	out << '.';
    }
    out << std::dec << std::endl;
  }
  out.unsetf(std::ios::right);
}

}
<|endoftext|>


<commit_before>/* Copyright 2012-present Facebook, Inc.
 * Licensed under the Apache License, Version 2.0 */

#include "watchman.h"
#include <array>
#include <limits>
#include <sstream>
#ifdef __APPLE__
#include <pthread.h>
#endif
#include <folly/Optional.h>
#include <folly/ScopeGuard.h>
#include <folly/ThreadLocal.h>
#include <folly/system/ThreadName.h>
#include "Logging.h"

using namespace watchman;

int log_level = LogLevel::ERR;
static folly::ThreadLocal<folly::Optional<std::string>> threadName;
static constexpr size_t kMaxFrames = 64;

std::string log_name;

namespace {
template <typename String>
void write_stderr(const String& str) {
  w_string_piece piece = str;
  ignore_result(write(STDERR_FILENO, piece.data(), piece.size()));
}

template <typename String, typename... Strings>
void write_stderr(const String& str, Strings&&... strings) {
  write_stderr(str);
  write_stderr(strings...);
}
} // namespace

static void log_stack_trace(void) {
#if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
  std::array<void*, kMaxFrames> array;
  size_t size;
  char** strings;
  size_t i;

  size = backtrace(array.data(), array.size());
  strings = backtrace_symbols(array.data(), size);

  write_stderr("Fatal error detected at:\n");

  for (i = 0; i < size; i++) {
    write_stderr(strings[i], "\n");
  }

  free(strings);
#endif
}

namespace watchman {

namespace {
struct levelMaps {
  // Actually a map of LogLevel, w_string, but it is relatively high friction
  // to define the hasher for an enum key :-p
  std::unordered_map<int, w_string> levelToLabel;
  std::unordered_map<w_string, enum LogLevel> labelToLevel;

  levelMaps()
      : levelToLabel{{ABORT, "abort"},
                     {FATAL, "fatal"},
                     {ERR, "error"},
                     {OFF, "off"},
                     {DBG, "debug"}} {
    // Create the reverse map
    for (auto& it : levelToLabel) {
      labelToLevel.insert(
          std::make_pair(it.second, static_cast<enum LogLevel>(it.first)));
    }
  }
};

// Meyers singleton for holding the log level maps
levelMaps& getLevelMaps() {
  static levelMaps maps;
  return maps;
}

} // namespace

const w_string& logLevelToLabel(enum LogLevel level) {
  return getLevelMaps().levelToLabel.at(static_cast<int>(level));
}

enum LogLevel logLabelToLevel(const w_string& label) {
  return getLevelMaps().labelToLevel.at(label);
}

Log::Log()
    : errorPub_(std::make_shared<Publisher>()),
      debugPub_(std::make_shared<Publisher>()) {
  setStdErrLoggingLevel(ERR);
}

Log& getLog() {
  static Log log;
  return log;
}

char* Log::timeString(char* buf, size_t bufsize, timeval tv) {
  struct tm tm;
#ifdef _WIN32
  time_t seconds = (time_t)tv.tv_sec;
  tm = *localtime(&seconds);
#else
  localtime_r(&tv.tv_sec, &tm);
#endif

  char timebuf[64];
  strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm);
  snprintf(buf, bufsize, "%s,%03d", timebuf, (int)tv.tv_usec / 1000);
  return buf;
}

char* Log::currentTimeString(char* buf, size_t bufsize) {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return timeString(buf, bufsize, tv);
}

const char* Log::setThreadName(std::string&& name) {
  folly::setThreadName(name);
  threadName->assign(name);
  return threadName->value().c_str();
}

const char* Log::getThreadName() {
  if (!threadName->hasValue()) {
    auto name = folly::getCurrentThreadName();
    if (name.hasValue()) {
      threadName->assign(name);
    } else {
      std::stringstream ss;
      ss << std::this_thread::get_id();
      threadName->assign(ss.str());
    }
  }
  return threadName->value().c_str();
}

void Log::setStdErrLoggingLevel(enum LogLevel level) {
  auto notify = [this]() { doLogToStdErr(); };
  switch (level) {
    case OFF:
      errorSub_.reset();
      debugSub_.reset();
      return;
    case DBG:
      if (!debugSub_) {
        debugSub_ = debugPub_->subscribe(notify);
      }
      if (!errorSub_) {
        errorSub_ = errorPub_->subscribe(notify);
      }
      return;
    default:
      debugSub_.reset();
      if (!errorSub_) {
        errorSub_ = errorPub_->subscribe(notify);
      }
      return;
  }
}

void Log::doLogToStdErr() {
  std::vector<std::shared_ptr<const watchman::Publisher::Item>> items;

  {
    std::lock_guard<std::mutex> lock(stdErrPrintMutex_);
    getPending(items, errorSub_, debugSub_);
  }

  bool doFatal = false;
  bool doAbort = false;
  static w_string kFatal("fatal");
  static w_string kAbort("abort");

  for (auto& item : items) {
    auto& log = json_to_w_string(item->payload.get("log"));
    ignore_result(write(STDERR_FILENO, log.data(), log.size()));

    auto level = json_to_w_string(item->payload.get("level"));
    if (level == kFatal) {
      doFatal = true;
    } else if (level == kAbort) {
      doAbort = true;
    }
  }

  if (doFatal || doAbort) {
    log_stack_trace();
    if (doAbort) {
      abort();
    } else {
      _exit(1);
    }
  }
}

#ifdef _WIN32
LONG WINAPI exception_filter(LPEXCEPTION_POINTERS excep) {
  std::array<void*, kMaxFrames> array;
  size_t size;
  char** strings;
  size_t i;
  char timebuf[64];

  size = backtrace_from_exception(excep, array.data(), array.size());
  strings = backtrace_symbols(array.data(), size);

  write_stderr(
      watchman::Log::currentTimeString(timebuf, sizeof(timebuf)),
      ": [",
      watchman::Log::getThreadName(),
      "] Unhandled win32 exception.  Fatal error detected at:\n");

  for (i = 0; i < size; i++) {
    write_stderr(strings[i], "\n");
  }
  free(strings);

  write_stderr("the stack trace for the exception filter call is:\n");
  size = backtrace(array.data(), array.size());
  strings = backtrace_symbols(array.data(), size);
  for (i = 0; i < size; i++) {
    write_stderr(strings[i], "\n");
  }
  free(strings);

  // Terminate the process.
  // msvcrt abort() ultimately calls exit(3), so we shortcut that.
  exit(3);
  return EXCEPTION_CONTINUE_SEARCH;
}
#endif

} // namespace watchman
<commit_msg>watchman: use ::write for stderr logging<commit_after>/* Copyright 2012-present Facebook, Inc.
 * Licensed under the Apache License, Version 2.0 */

#include "watchman.h"
#include <array>
#include <limits>
#include <sstream>
#ifdef __APPLE__
#include <pthread.h>
#endif
#include <folly/Optional.h>
#include <folly/ScopeGuard.h>
#include <folly/ThreadLocal.h>
#include <folly/system/ThreadName.h>
#include "Logging.h"

using namespace watchman;

int log_level = LogLevel::ERR;
static folly::ThreadLocal<folly::Optional<std::string>> threadName;
static constexpr size_t kMaxFrames = 64;

std::string log_name;

namespace {
template <typename String>
void write_stderr(const String& str) {
  w_string_piece piece = str;
  ignore_result(::write(STDERR_FILENO, piece.data(), piece.size()));
}

template <typename String, typename... Strings>
void write_stderr(const String& str, Strings&&... strings) {
  write_stderr(str);
  write_stderr(strings...);
}
} // namespace

static void log_stack_trace(void) {
#if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
  std::array<void*, kMaxFrames> array;
  size_t size;
  char** strings;
  size_t i;

  size = backtrace(array.data(), array.size());
  strings = backtrace_symbols(array.data(), size);

  write_stderr("Fatal error detected at:\n");

  for (i = 0; i < size; i++) {
    write_stderr(strings[i], "\n");
  }

  free(strings);
#endif
}

namespace watchman {

namespace {
struct levelMaps {
  // Actually a map of LogLevel, w_string, but it is relatively high friction
  // to define the hasher for an enum key :-p
  std::unordered_map<int, w_string> levelToLabel;
  std::unordered_map<w_string, enum LogLevel> labelToLevel;

  levelMaps()
      : levelToLabel{{ABORT, "abort"},
                     {FATAL, "fatal"},
                     {ERR, "error"},
                     {OFF, "off"},
                     {DBG, "debug"}} {
    // Create the reverse map
    for (auto& it : levelToLabel) {
      labelToLevel.insert(
          std::make_pair(it.second, static_cast<enum LogLevel>(it.first)));
    }
  }
};

// Meyers singleton for holding the log level maps
levelMaps& getLevelMaps() {
  static levelMaps maps;
  return maps;
}

} // namespace

const w_string& logLevelToLabel(enum LogLevel level) {
  return getLevelMaps().levelToLabel.at(static_cast<int>(level));
}

enum LogLevel logLabelToLevel(const w_string& label) {
  return getLevelMaps().labelToLevel.at(label);
}

Log::Log()
    : errorPub_(std::make_shared<Publisher>()),
      debugPub_(std::make_shared<Publisher>()) {
  setStdErrLoggingLevel(ERR);
}

Log& getLog() {
  static Log log;
  return log;
}

char* Log::timeString(char* buf, size_t bufsize, timeval tv) {
  struct tm tm;
#ifdef _WIN32
  time_t seconds = (time_t)tv.tv_sec;
  tm = *localtime(&seconds);
#else
  localtime_r(&tv.tv_sec, &tm);
#endif

  char timebuf[64];
  strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%S", &tm);
  snprintf(buf, bufsize, "%s,%03d", timebuf, (int)tv.tv_usec / 1000);
  return buf;
}

char* Log::currentTimeString(char* buf, size_t bufsize) {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return timeString(buf, bufsize, tv);
}

const char* Log::setThreadName(std::string&& name) {
  folly::setThreadName(name);
  threadName->assign(name);
  return threadName->value().c_str();
}

const char* Log::getThreadName() {
  if (!threadName->hasValue()) {
    auto name = folly::getCurrentThreadName();
    if (name.hasValue()) {
      threadName->assign(name);
    } else {
      std::stringstream ss;
      ss << std::this_thread::get_id();
      threadName->assign(ss.str());
    }
  }
  return threadName->value().c_str();
}

void Log::setStdErrLoggingLevel(enum LogLevel level) {
  auto notify = [this]() { doLogToStdErr(); };
  switch (level) {
    case OFF:
      errorSub_.reset();
      debugSub_.reset();
      return;
    case DBG:
      if (!debugSub_) {
        debugSub_ = debugPub_->subscribe(notify);
      }
      if (!errorSub_) {
        errorSub_ = errorPub_->subscribe(notify);
      }
      return;
    default:
      debugSub_.reset();
      if (!errorSub_) {
        errorSub_ = errorPub_->subscribe(notify);
      }
      return;
  }
}

void Log::doLogToStdErr() {
  std::vector<std::shared_ptr<const watchman::Publisher::Item>> items;

  {
    std::lock_guard<std::mutex> lock(stdErrPrintMutex_);
    getPending(items, errorSub_, debugSub_);
  }

  bool doFatal = false;
  bool doAbort = false;
  static w_string kFatal("fatal");
  static w_string kAbort("abort");

  for (auto& item : items) {
    auto& log = json_to_w_string(item->payload.get("log"));
    ignore_result(::write(STDERR_FILENO, log.data(), log.size()));

    auto level = json_to_w_string(item->payload.get("level"));
    if (level == kFatal) {
      doFatal = true;
    } else if (level == kAbort) {
      doAbort = true;
    }
  }

  if (doFatal || doAbort) {
    log_stack_trace();
    if (doAbort) {
      abort();
    } else {
      _exit(1);
    }
  }
}

#ifdef _WIN32
LONG WINAPI exception_filter(LPEXCEPTION_POINTERS excep) {
  std::array<void*, kMaxFrames> array;
  size_t size;
  char** strings;
  size_t i;
  char timebuf[64];

  size = backtrace_from_exception(excep, array.data(), array.size());
  strings = backtrace_symbols(array.data(), size);

  write_stderr(
      watchman::Log::currentTimeString(timebuf, sizeof(timebuf)),
      ": [",
      watchman::Log::getThreadName(),
      "] Unhandled win32 exception.  Fatal error detected at:\n");

  for (i = 0; i < size; i++) {
    write_stderr(strings[i], "\n");
  }
  free(strings);

  write_stderr("the stack trace for the exception filter call is:\n");
  size = backtrace(array.data(), array.size());
  strings = backtrace_symbols(array.data(), size);
  for (i = 0; i < size; i++) {
    write_stderr(strings[i], "\n");
  }
  free(strings);

  // Terminate the process.
  // msvcrt abort() ultimately calls exit(3), so we shortcut that.
  exit(3);
  return EXCEPTION_CONTINUE_SEARCH;
}
#endif

} // namespace watchman
<|endoftext|>


<commit_before>#include "gen.h"
#include "ast.h"
#include "syntactic.hpp"

#include <exception>

#include <llvm/ADT/Twine.h>
#include <llvm/IR/LegacyPassManager.h>

using namespace std;

LLVMContext TheContext;

/* Compile the AST into a module */
void CodeGenContext::generateCode(NBlock &root) {
  std::cout << "Generating code...\n";

  /* Create the top level interpreter function to call as entry */
  vector<Type *> argTypes;
  FunctionType *ftype = FunctionType::get(Type::getVoidTy(getGlobalContext()),
                                          makeArrayRef(argTypes), false);
  mainFunction =
      Function::Create(ftype, GlobalValue::InternalLinkage, "main", module);
  BasicBlock *bblock =
      BasicBlock::Create(getGlobalContext(), "entry", mainFunction, 0);

  /* Push a new variable/block context */
  pushBlock(bblock);
  root.codeGen(*this); /* emit bytecode for the toplevel block */
  ReturnInst::Create(getGlobalContext(), bblock);
  popBlock();

  /* Print the bytecode in a human-readable format
     to see if our program compiled properly
   */
  std::cout << "Code is generated.\n";

#if LLVM_VERSION_MAJOR < 10
  PassManager<Module> pm;
  AnalysisManager<Module> am;
  pm.addPass(PrintModulePass(outs()));
  pm.run(*module, am);
#else
  llvm::legacy::PassManager pm;
  pm.add(createPrintModulePass(outs()));
  pm.run(*module);
#endif
}

/* Executes the AST by running the main function */
GenericValue CodeGenContext::runCode() {
  try {
    std::cout << "Running code:\n";
    ExecutionEngine *ee = EngineBuilder(unique_ptr<Module>(module)).create();
    ee->finalizeObject();
    vector<GenericValue> noargs;
    GenericValue v = ee->runFunction(mainFunction, noargs);
    delete ee;
    return v;
  } catch (std::exception &ex) {
    std::cout << ex.what() << std::endl;
  }
}

/* -- Code Generation -- */

Value *NInteger::codeGen(CodeGenContext &context) {
  std::cout << "Creating integer: " << value << endl;
  return ConstantInt::get(Type::getInt64Ty(getGlobalContext()), value, true);
}

Value *NIdentifier::codeGen(CodeGenContext &context) {
  std::cout << "Creating identifier reference: " << name << endl;
  if (context.locals().find(name) == context.locals().end()) {
    std::cout << "undeclared variable " << name << endl;
    std::cout << "Creating variable declaration " << name << endl;
    AllocaInst *alloc = new AllocaInst(Type::getInt64Ty(getGlobalContext()), 0u,
                                       name.c_str(), context.currentBlock());
    context.locals()[name] = alloc;
  }

#if LLVM_VERSION_MAJOR == 12
  const auto &local = context.locals()[name];
  return new LoadInst(cast<PointerType>(local->getType())->getElementType(),
                      local, llvm::Twine(""), false, context.currentBlock());
#else
  return new LoadInst(context.locals()[name], "", false,
                      context.currentBlock());
#endif
}

Value *NMethodCall::codeGen(CodeGenContext &context) {
  Function *function = context.module->getFunction(id.name.c_str());
  if (function == NULL) {
    std::cerr << "no such function " << id.name << endl;
  }
  std::vector<Value *> args;
  ExpressionList::const_iterator it;
  for (it = arguments.begin(); it != arguments.end(); it++) {
    args.push_back((**it).codeGen(context));
  }
  CallInst *call = CallInst::Create(function, makeArrayRef(args), "",
                                    context.currentBlock());
  std::cout << "Creating method call: " << id.name << endl;
  return call;
}

Value *NBinaryOperator::codeGen(CodeGenContext &context) {
  std::cout << "Creating binary operation " << op << endl;
  Instruction::BinaryOps instr;
  switch (op) {
  case TPLUS:
    instr = Instruction::Add;
    goto math;
  case TMINUS:
    instr = Instruction::Sub;
    goto math;
  case TMUL:
    instr = Instruction::Mul;
    goto math;
  case TDIV:
    instr = Instruction::SDiv;
    goto math;

    /* TODO comparison */
  }

  return NULL;
math:
  return BinaryOperator::Create(instr, lhs.codeGen(context),
                                rhs.codeGen(context), "",
                                context.currentBlock());
}

Value *NAssignment::codeGen(CodeGenContext &context) {
  std::cout << "Creating assignment for " << lhs.name << endl;
  if (context.locals().find(lhs.name) == context.locals().end()) {
    std::cout << "undeclared variable " << lhs.name << endl;
    std::cout << "Creating variable declaration " << lhs.name << endl;
    AllocaInst *alloc =
        new AllocaInst(Type::getInt64Ty(getGlobalContext()), 0u,
                       lhs.name.c_str(), context.currentBlock());
    context.locals()[lhs.name] = alloc;
  }
  return new StoreInst(rhs.codeGen(context), context.locals()[lhs.name], false,
                       context.currentBlock());
}

Value *NBlock::codeGen(CodeGenContext &context) {
  StatementList::const_iterator it;
  Value *last = NULL;
  for (it = statements.begin(); it != statements.end(); it++) {
    std::cout << "Generating code for " << typeid(**it).name() << endl;
    last = (**it).codeGen(context);
  }
  std::cout << "Creating block" << endl;
  return last;
}

Value *NExpressionStatement::codeGen(CodeGenContext &context) {
  std::cout << "Generating code for " << typeid(expression).name() << endl;
  return expression.codeGen(context);
}

Value *NReturnStatement::codeGen(CodeGenContext &context) {
  std::cout << "Generating return code for " << typeid(expression).name()
            << endl;
  Value *returnValue = expression.codeGen(context);
  context.setCurrentReturnValue(returnValue);
  return returnValue;
}

Value *NExternDeclaration::codeGen(CodeGenContext &context) {
  vector<Type *> argTypes;
  VariableList::const_iterator it;
  for (it = arguments.begin(); it != arguments.end(); it++) {
    argTypes.push_back(Type::getInt64Ty(getGlobalContext()));
  }
  FunctionType *ftype = FunctionType::get(Type::getInt64Ty(getGlobalContext()),
                                          makeArrayRef(argTypes), false);
  Function *function = Function::Create(ftype, GlobalValue::ExternalLinkage,
                                        id.name.c_str(), context.module);
  return function;
}

Value *NFunctionDeclaration::codeGen(CodeGenContext &context) {
  vector<Type *> argTypes;
  VariableList::const_iterator it;
  for (it = arguments.begin(); it != arguments.end(); it++) {
    argTypes.push_back(Type::getInt64Ty(getGlobalContext()));
  }
  FunctionType *ftype = FunctionType::get(Type::getInt64Ty(getGlobalContext()),
                                          makeArrayRef(argTypes), false);
  Function *function = Function::Create(ftype, GlobalValue::InternalLinkage,
                                        id.name.c_str(), context.module);
  BasicBlock *bblock =
      BasicBlock::Create(getGlobalContext(), "entry", function, 0);

  context.pushBlock(bblock);

  Function::arg_iterator argsValues = function->arg_begin();
  Value *argumentValue;

  for (it = arguments.begin(); it != arguments.end(); it++) {
    (**it).codeGen(context);

    argumentValue = &*argsValues++;
    argumentValue->setName((*it)->name.c_str());
    StoreInst *inst = new StoreInst(
        argumentValue, context.locals()[(*it)->name], false, bblock);
  }

  block.codeGen(context);
  ReturnInst::Create(getGlobalContext(), context.getCurrentReturnValue(),
                     bblock);

  context.popBlock();
  std::cout << "Creating function: " << id.name << endl;
  return function;
}
<commit_msg>Update gen.cpp<commit_after>#include "gen.h"
#include "ast.h"
#include "syntactic.hpp"

#include <exception>

#include <llvm/ADT/Twine.h>
#include <llvm/IR/LegacyPassManager.h>

using namespace std;

LLVMContext TheContext;

/* Compile the AST into a module */
void CodeGenContext::generateCode(NBlock &root) {
  std::cout << "Generating code...\n";

  /* Create the top level interpreter function to call as entry */
  vector<Type *> argTypes;
  FunctionType *ftype = FunctionType::get(Type::getVoidTy(getGlobalContext()),
                                          makeArrayRef(argTypes), false);
  mainFunction =
      Function::Create(ftype, GlobalValue::InternalLinkage, "main", module);
  BasicBlock *bblock =
      BasicBlock::Create(getGlobalContext(), "entry", mainFunction, 0);

  /* Push a new variable/block context */
  pushBlock(bblock);
  root.codeGen(*this); /* emit bytecode for the toplevel block */
  ReturnInst::Create(getGlobalContext(), bblock);
  popBlock();

  /* Print the bytecode in a human-readable format
     to see if our program compiled properly
   */
  std::cout << "Code is generated.\n";

#if LLVM_VERSION_MAJOR < 10
  PassManager<Module> pm;
  AnalysisManager<Module> am;
  pm.addPass(PrintModulePass(outs()));
  pm.run(*module, am);
#else
  llvm::legacy::PassManager pm;
  pm.add(createPrintModulePass(outs()));
  pm.run(*module);
#endif
}

/* Executes the AST by running the main function */
GenericValue CodeGenContext::runCode() {
  try {
    std::cout << "Running code:\n";
    ExecutionEngine *ee = EngineBuilder(unique_ptr<Module>(module)).create();
    ee->finalizeObject();
    vector<GenericValue> noargs;
    GenericValue v = ee->runFunction(mainFunction, noargs);
    delete ee;
    return v;
  } catch (std::exception &ex) {
    std::cout << ex.what() << std::endl;
  }
}

/* -- Code Generation -- */

Value *NInteger::codeGen(CodeGenContext &context) {
  std::cout << "Creating integer: " << value << endl;
  return ConstantInt::get(Type::getInt64Ty(getGlobalContext()), value, true);
}

Value *NIdentifier::codeGen(CodeGenContext &context) {
  std::cout << "Creating identifier reference: " << name << endl;
  if (context.locals().find(name) == context.locals().end()) {
    std::cout << "undeclared variable " << name << endl;
    std::cout << "Creating variable declaration " << name << endl;
    AllocaInst *alloc = new AllocaInst(Type::getInt64Ty(getGlobalContext()), 0u,
                                       name.c_str(), context.currentBlock());
    context.locals()[name] = alloc;
  }

#if LLVM_VERSION_MAJOR >= 12
  const auto &local = context.locals()[name];
  return new LoadInst(cast<PointerType>(local->getType())->getElementType(),
                      local, llvm::Twine(""), false, context.currentBlock());
#else
  return new LoadInst(context.locals()[name], "", false,
                      context.currentBlock());
#endif
}

Value *NMethodCall::codeGen(CodeGenContext &context) {
  Function *function = context.module->getFunction(id.name.c_str());
  if (function == NULL) {
    std::cerr << "no such function " << id.name << endl;
  }
  std::vector<Value *> args;
  ExpressionList::const_iterator it;
  for (it = arguments.begin(); it != arguments.end(); it++) {
    args.push_back((**it).codeGen(context));
  }
  CallInst *call = CallInst::Create(function, makeArrayRef(args), "",
                                    context.currentBlock());
  std::cout << "Creating method call: " << id.name << endl;
  return call;
}

Value *NBinaryOperator::codeGen(CodeGenContext &context) {
  std::cout << "Creating binary operation " << op << endl;
  Instruction::BinaryOps instr;
  switch (op) {
  case TPLUS:
    instr = Instruction::Add;
    goto math;
  case TMINUS:
    instr = Instruction::Sub;
    goto math;
  case TMUL:
    instr = Instruction::Mul;
    goto math;
  case TDIV:
    instr = Instruction::SDiv;
    goto math;

    /* TODO comparison */
  }

  return NULL;
math:
  return BinaryOperator::Create(instr, lhs.codeGen(context),
                                rhs.codeGen(context), "",
                                context.currentBlock());
}

Value *NAssignment::codeGen(CodeGenContext &context) {
  std::cout << "Creating assignment for " << lhs.name << endl;
  if (context.locals().find(lhs.name) == context.locals().end()) {
    std::cout << "undeclared variable " << lhs.name << endl;
    std::cout << "Creating variable declaration " << lhs.name << endl;
    AllocaInst *alloc =
        new AllocaInst(Type::getInt64Ty(getGlobalContext()), 0u,
                       lhs.name.c_str(), context.currentBlock());
    context.locals()[lhs.name] = alloc;
  }
  return new StoreInst(rhs.codeGen(context), context.locals()[lhs.name], false,
                       context.currentBlock());
}

Value *NBlock::codeGen(CodeGenContext &context) {
  StatementList::const_iterator it;
  Value *last = NULL;
  for (it = statements.begin(); it != statements.end(); it++) {
    std::cout << "Generating code for " << typeid(**it).name() << endl;
    last = (**it).codeGen(context);
  }
  std::cout << "Creating block" << endl;
  return last;
}

Value *NExpressionStatement::codeGen(CodeGenContext &context) {
  std::cout << "Generating code for " << typeid(expression).name() << endl;
  return expression.codeGen(context);
}

Value *NReturnStatement::codeGen(CodeGenContext &context) {
  std::cout << "Generating return code for " << typeid(expression).name()
            << endl;
  Value *returnValue = expression.codeGen(context);
  context.setCurrentReturnValue(returnValue);
  return returnValue;
}

Value *NExternDeclaration::codeGen(CodeGenContext &context) {
  vector<Type *> argTypes;
  VariableList::const_iterator it;
  for (it = arguments.begin(); it != arguments.end(); it++) {
    argTypes.push_back(Type::getInt64Ty(getGlobalContext()));
  }
  FunctionType *ftype = FunctionType::get(Type::getInt64Ty(getGlobalContext()),
                                          makeArrayRef(argTypes), false);
  Function *function = Function::Create(ftype, GlobalValue::ExternalLinkage,
                                        id.name.c_str(), context.module);
  return function;
}

Value *NFunctionDeclaration::codeGen(CodeGenContext &context) {
  vector<Type *> argTypes;
  VariableList::const_iterator it;
  for (it = arguments.begin(); it != arguments.end(); it++) {
    argTypes.push_back(Type::getInt64Ty(getGlobalContext()));
  }
  FunctionType *ftype = FunctionType::get(Type::getInt64Ty(getGlobalContext()),
                                          makeArrayRef(argTypes), false);
  Function *function = Function::Create(ftype, GlobalValue::InternalLinkage,
                                        id.name.c_str(), context.module);
  BasicBlock *bblock =
      BasicBlock::Create(getGlobalContext(), "entry", function, 0);

  context.pushBlock(bblock);

  Function::arg_iterator argsValues = function->arg_begin();
  Value *argumentValue;

  for (it = arguments.begin(); it != arguments.end(); it++) {
    (**it).codeGen(context);

    argumentValue = &*argsValues++;
    argumentValue->setName((*it)->name.c_str());
    StoreInst *inst = new StoreInst(
        argumentValue, context.locals()[(*it)->name], false, bblock);
  }

  block.codeGen(context);
  ReturnInst::Create(getGlobalContext(), context.getCurrentReturnValue(),
                     bblock);

  context.popBlock();
  std::cout << "Creating function: " << id.name << endl;
  return function;
}
<|endoftext|>