/** @file PrimitiveExprInterface.hpp
 *
 *  Author: Roland Conybeare
 **/

#pragma once

#include "ProcedureExprInterface.hpp"
#include "llvmintrinsic.hpp"
#include "xo/reflect/TaggedPtr.hpp"
#include <type_traits>

namespace xo {
    namespace scm {
        class PrimitiveExprInterface : public ProcedureExprInterface {
        public:
            using TaggedPtr = xo::reflect::TaggedPtr;
            using void_function_type = void (*)();

        public:
            explicit PrimitiveExprInterface(TypeDescr fn_type)
                : ProcedureExprInterface(exprtype::primitive, fn_type) {}

            /** downcast from Expression **/
            static bp<PrimitiveExprInterface> from(bp<Expression> x) {
                return bp<PrimitiveExprInterface>::from(x);
            }

            /** @return executable function as tagged pointer.
             *  Load-bearing for xo-interpreter.
             **/
            virtual TaggedPtr value_tp() const = 0;

            /** if true,  Jit will try to explicitly symbol for this primitive
             *  (instead of looking it up in host process).
             *  Don't know if this works.
             *  Do know it's not needed for ::sin(), ::sqrt().
             *  Do know that my extern "C" functions like ::mul_i32(), ::mul_f64()
             *  need something else.
             **/
            virtual bool explicit_symbol_def() const = 0;

            /** function address for this primitive **/
            virtual void_function_type function_address() const = 0;

            /** get llvm intrinsic hint for this primitive **/
            virtual llvmintrinsic intrinsic() const = 0;

            // virtual const std::string & name() const;
            // virtual int n_arg() const;
            // virtual TypeDescr fn_retval() const;
            // virtual TypeDescr fn_arg(uint32_t i) const;

            // ----- Expression -----

            virtual std::set<std::string> get_free_variables() const override {
                return std::set<std::string>();
            }

            virtual std::size_t visit_preorder(VisitFn visitor_fn) override {
                visitor_fn(this);
                return 1;
            }

            virtual std::size_t visit_layer(VisitFn visitor_fn) override {
                visitor_fn(this);
                return 1;
            }

            virtual rp<Expression> xform_layer(TransformFn xform_fn) override {
                return xform_fn(this);
            }

            virtual void attach_envs(bp<SymbolTable> /*p*/) override {}

        private:
        }; /*PrimitiveInterface*/
    } /*namespace scm*/
} /*namespace xo*/


/** end PrimitiveInterface.hpp **/
