//===-- gen/ldctraits.d - LDC-specific __traits handling ----------*- D -*-===//
//
//                         LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
//
//
//
//===----------------------------------------------------------------------===//

module gen.ldctraits;

import ddmd.arraytypes;
import ddmd.dscope;
import ddmd.dtemplate;
import ddmd.expression;
import ddmd.errors;
import ddmd.mtype;
import ddmd.id;

// TODO: move this to a D interfacing helper file
extern(C++) struct Dstring
{
  const(char)* ptr;
  size_t len;
};

extern(C++) Dstring traitsGetTargetCPU();
extern(C++) bool traitsTargetHasFeature(Dstring feature);

Expression semanticTraitsLDC(TraitsExp e, Scope* sc)
{
    size_t arg_count = e.args ? e.args.dim : 0;

    if (e.ident == Id.targetCPU)
    {
        if (arg_count != 0)
        {
            e.warning("ignoring arguments for __traits %s", e.ident.toChars());
        }

        auto cpu = traitsGetTargetCPU();
        auto se = new StringExp(e.loc, cast(void*)cpu.ptr, cpu.len);
        return se.semantic(sc);
    }
    if (e.ident == Id.targetHasFeature)
    {
        if (arg_count != 1)
        {
            e.error("__traits %s expects one argument, not %u", e.ident.toChars(), cast(uint)arg_count);
            return new ErrorExp();
        }

        auto ex = isExpression((*e.args)[0]);
        if (!ex)
        {
            e.error("expression expected as argument of __traits %s", e.ident.toChars());
            return new ErrorExp();
        }
        ex = ex.ctfeInterpret();

        StringExp se = ex.toStringExp();
        if (!se || se.len == 0)
        {
            e.error("string expected as argument of __traits %s instead of %s", e.ident.toChars(), ex.toChars());
            return new ErrorExp();
        }

        se = se.toUTF8(sc);
        auto featureFound = traitsTargetHasFeature(Dstring(se.toPtr(), se.len));
        return new IntegerExp(e.loc, featureFound ? 1 : 0, Type.tbool);
    }
    return null;
}
