381 lines · 13.2 KB · C
RawDownload
//// Dis VM// File: vm_asm_sigkind.h// Author: arr// #ifndef _DISVM_SRC_INCLUDE_VM_ASM_SIGKIND_H_#define _DISVM_SRC_INCLUDE_VM_ASM_SIGKIND_H_ #include <iosfwd>#include <sstream>#include <cassert>#include <cstdint>#include "runtime.h" namespace disvm{    namespace assembly    {        // Namespace named after enum type in Limbo compiler        // Source: limbo/types.c        namespace sigkind        {            // Signature stream            class sig_stream_t final            {            public: // static                static uint32_t compute_signature_hash(const char *);                 // Type delimiter                static constexpr char delim();             public:                std::string get_signature() const;                 uint32_t get_signature_hash() const;                 sig_stream_t &operator<<(const char);                sig_stream_t &operator<<(const char *);                sig_stream_t &operator<<(const uint32_t);                sig_stream_t &operator<<(const sig_stream_t &);             private:                mutable std::stringstream _ss;            };             constexpr char sig_stream_t::delim() { return ','; }             // Type context modifiers            enum class modifier_id_t : uint8_t            {                self = 'S',                cycle = 'y',            };             sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::modifier_id_t &);             // Instrinsic VM types            enum class type_id_t : uint8_t            {                unknown = 0, // This will be interpreted as a 'null' value which will help debug where the type building failed.                none = 'n',                byte = 'b',                integer = 'i',                real = 'r',                big = 'B',                string = 's',                poly = 'P',                fixed = 'x',                array = 'A',                ref = 'R',                list = 'L',                channel = 'C',                adt = 'a',                adt_pick_tag = 'p',                tuple = 't',                module = 'm',                function = 'f',                function_varargs = 0xff, // "f*"            };             sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::type_id_t &);             template<type_id_t T>            struct Tbasic_type            {                static const type_id_t id;                 constexpr operator type_id_t() const                {                    return Tbasic_type::id;                }            };             template<type_id_t T>            const type_id_t Tbasic_type<T>::id = T;             using Tnone = Tbasic_type<type_id_t::none>;            using Tbyte = Tbasic_type<type_id_t::byte>;            using Tinteger = Tbasic_type<type_id_t::integer>;            using Treal = Tbasic_type<type_id_t::real>;            using Tbig = Tbasic_type<type_id_t::big>;            using Tstring = Tbasic_type<type_id_t::string>;            using Tpoly = Tbasic_type<type_id_t::poly>;             class Tfixed final : public Tbasic_type<type_id_t::fixed>            {            public:                Tfixed(double scale);                 friend sig_stream_t &operator<<(sig_stream_t &os, const Tfixed &);             private:                const double _scale;            };             sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfixed &);             // Type that contains/modifies another type            template <type_id_t ID>            class Tbasic_aggregate_type : public Tbasic_type<ID>            {            public:                template<typename U>                static Tbasic_aggregate_type create(const U &type)                {                    sig_stream_t ss;                    ss << Tbasic_type<ID>::id << type;                     return Tbasic_aggregate_type{ ss };                }                 friend sig_stream_t &operator<<(sig_stream_t &, const Tbasic_aggregate_type &);             private:                sig_stream_t _s;                Tbasic_aggregate_type(sig_stream_t &s) : _s{ std::move(s) } { }            };             using Tarray = Tbasic_aggregate_type<type_id_t::array>;            using Tref = Tbasic_aggregate_type<type_id_t::ref>;            using Tlist = Tbasic_aggregate_type<type_id_t::list>;            using Tchannel = Tbasic_aggregate_type<type_id_t::channel>;             sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tarray &);            sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tref &);            sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tlist &);            sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tchannel &);             // Reference to another previously defined type in the current signature            class Ttype_ref final            {            public: // static                static const char id;             public:                Ttype_ref(uint32_t num);                 friend sig_stream_t &operator<<(sig_stream_t &os, const Ttype_ref &);             private:                const uint32_t _num;            };             sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Ttype_ref &);             // Named member type            class Tm final            {            public:                template <typename T>                Tm(const char *name, const T &type)                {                    _s << name << ':' << type;                }                 friend sig_stream_t &operator<<(sig_stream_t &os, const Tm &);             private:                sig_stream_t _s;            };             sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tm &);             inline void nested_type(const sig_stream_t &)            {                return;            }             template<typename T, typename ...S>            void nested_type(sig_stream_t &ss, const T &t, const S&...s)            {                ss << t;                nested_type(ss, s...);            }             template<typename T1, typename T2, typename ...S>            void nested_type(sig_stream_t &ss, const T1 &t1, const T2 &t2, const S&...s)            {                ss << t1 << sig_stream_t::delim();                nested_type(ss, t2, s...);            }             // Type whose definition depends on contained types            template <type_id_t ID>            class Tnested_aggregate_type : public Tbasic_type<ID>            {            public: // static                static constexpr char begin();                static constexpr char end();                 template<typename ...NT>                static Tnested_aggregate_type create(const NT&... nestedTypes)                {                    sig_stream_t ss;                    ss << Tbasic_type<ID>::id << Tnested_aggregate_type::begin();                     nested_type(ss, nestedTypes...);                     ss << Tnested_aggregate_type::end();                     return Tnested_aggregate_type{ ss };                }             public:                Tnested_aggregate_type(sig_stream_t &s)                    : _s{ std::move(s) }                { }                 friend sig_stream_t &operator<<(sig_stream_t &, const Tnested_aggregate_type &);             private:                sig_stream_t _s;            };             using Ttuple = Tnested_aggregate_type<type_id_t::tuple>;            using Tmodule = Tnested_aggregate_type<type_id_t::module>;            using _Tadt = Tnested_aggregate_type<type_id_t::adt>;             template<> constexpr char Ttuple::begin() { return '('; }            template<> constexpr char Ttuple::end() { return ')'; }             template<> constexpr char Tmodule::begin() { return '{'; }            template<> constexpr char Tmodule::end() { return '}'; }             template<> constexpr char _Tadt::begin() { return '('; }            template<> constexpr char _Tadt::end() { return ')'; }             sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Ttuple &);            sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tmodule &);             // Abstract data type (ADT) pick tag            // Note: This type should only be a part of an ADT instance.            class Tadt_pick_tag final : public Tbasic_type<type_id_t::adt_pick_tag>            {            public:  // static                static constexpr const char *tag_delim();                static constexpr char begin();                static constexpr char end();                 static Tadt_pick_tag create(const char *pick_tag, uint32_t adt_ref, std::initializer_list<const Tm> tms);                 friend sig_stream_t &operator<<(sig_stream_t &, const Tadt_pick_tag &);             private:                sig_stream_t _s;                Tadt_pick_tag(sig_stream_t &s) : _s{ std::move(s) } { }            };             constexpr const char *Tadt_pick_tag::tag_delim() { return "=>"; }            constexpr char Tadt_pick_tag::begin() { return '('; }            constexpr char Tadt_pick_tag::end() { return ')'; }             sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tadt_pick_tag &);             // Abstract data type (ADT)            class Tadt final : public _Tadt            {            public: // static                // Unhide base class version of function                using _Tadt::create;                 // Create an ADT with a single pick tag                static Tadt create(const Tadt_pick_tag &p)                {                    sig_stream_t ss;                    ss << Tbasic_type::id                        << Tadt::begin()                        << sig_stream_t::delim()                        << p                        << Tadt::end();                     return Tadt{ ss };                }                 template<typename T, typename ...NT>                static Tadt create(const Tadt_pick_tag &p, const T &t, const NT&... nestedTypes)                {                    // [SPEC] When generating type signatures, the Limbo compiler                    // doesn't identify the case where a pick tag is the first type                    // so it always prefixes the nested signature with a leading ','.                    // We special case this scenario to maintain compatibility. The                    // single pick tag for an ADT must also be handled (above).                    sig_stream_t ss;                    ss << Tbasic_type::id                        << Tadt::begin()                        << sig_stream_t::delim()                        << p                        << sig_stream_t::delim();                     nested_type(ss, t, nestedTypes...);                     ss << Tadt::end();                     return Tadt{ ss };                }             private:                Tadt(sig_stream_t &s) : _Tadt{ s } { }            };             sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tnested_aggregate_type<type_id_t::adt> &);             // Function type            template<type_id_t T>            class Tfunction_base_type final : public Tbasic_type<T>            {            public: // static                static constexpr char begin();                static constexpr char end();                 template<typename ...AT>                static Tfunction_base_type create(AT... argTypes)                {                    Tfunction_base_type a;                    a._s << Tfunction_base_type::id << Tfunction_base_type::begin();                     nested_type(a._s, argTypes...);                     a._s << Tfunction_base_type::end();                    return a;                }             public:                template<typename RT>                Tfunction_base_type &returns(RT r)                {                    assert(!_fully_defined && "Function type already complete");                    _s << r;                    _fully_defined = true;                     return *this;                }                 friend sig_stream_t &operator<<(sig_stream_t &, Tfunction_base_type &);                friend sig_stream_t &operator<<(sig_stream_t &, const Tfunction_base_type &);             private:                bool _fully_defined;                sig_stream_t _s;                Tfunction_base_type() : _fully_defined{ false } { }            };             template<type_id_t T>            constexpr char Tfunction_base_type<T>::begin() { return '('; }             template<type_id_t T>            constexpr char Tfunction_base_type<T>::end() { return ')'; }             using Tfunction = Tfunction_base_type<type_id_t::function>;            using Tfunction_varargs = Tfunction_base_type<type_id_t::function_varargs>;             sig_stream_t &operator<<(sig_stream_t &, disvm::assembly::sigkind::Tfunction &);            sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfunction &);            sig_stream_t &operator<<(sig_stream_t &, disvm::assembly::sigkind::Tfunction_varargs &);            sig_stream_t &operator<<(sig_stream_t &, const disvm::assembly::sigkind::Tfunction_varargs &);        }    }} #endif // _DISVM_SRC_INCLUDE_VM_ASM_SIGKIND_H_