xo-interpreter: add Primitive object, to expose builtin functions

This commit is contained in:
Roland Conybeare 2025-11-27 11:03:41 -05:00
commit 2526dcc9b1
23 changed files with 277 additions and 135 deletions

View file

@ -1,7 +1,7 @@
/** @file ex1.cpp **/
#include "xo/expression/Constant.hpp"
#include "xo/expression/Primitive.hpp"
#include "xo/expression/PrimitiveExpr.hpp"
#include "xo/expression/llvmintrinsic.hpp"
#include <iostream>
#include <cmath>

View file

@ -1,4 +1,4 @@
/** @file Primitive.hpp
/** @file PrimitiveExpr.hpp
*
* Author: Roland Conybeare
**/
@ -20,7 +20,7 @@ extern "C" {
namespace xo {
namespace scm {
/** @class Primitive
/** @class PrimitiveExpr
* @brief syntax for a constant that refers to a known function.
*
* Two cases here:
@ -38,7 +38,7 @@ namespace xo {
* won't work here.
**/
template <typename FunctionPointer>
class Primitive: public PrimitiveExprInterface {
class PrimitiveExpr: public PrimitiveExprInterface {
public:
using Reflect = xo::reflect::Reflect;
using TaggedPtr = xo::reflect::TaggedPtr;
@ -46,13 +46,13 @@ namespace xo {
using fptr_type = FunctionPointer;
public:
static rp<Primitive> make(const std::string & name,
static rp<PrimitiveExpr> make(const std::string & name,
FunctionPointer fnptr,
bool explicit_symbol_def,
llvmintrinsic intrinsic) {
TypeDescr fn_type = Reflect::require<FunctionPointer>();
return new Primitive(fn_type, name, fnptr, explicit_symbol_def, intrinsic);
return new PrimitiveExpr(fn_type, name, fnptr, explicit_symbol_def, intrinsic);
}
/** see classes below for intrinsics **/
@ -68,7 +68,7 @@ namespace xo {
return TaggedPtr(value_td_, erased_ptr);
}
// ----- PrimitiveInterface -----
// ----- PrimitiveExprInterface -----
virtual llvmintrinsic intrinsic() const override { return intrinsic_; }
virtual bool explicit_symbol_def() const override { return explicit_symbol_def_; }
@ -84,7 +84,7 @@ namespace xo {
// ----- Expression -----
virtual void display(std::ostream & os) const override {
os << "<Primitive"
os << "<PrimitiveExpr"
<< xtag("name", name_)
<< xtag("type", this->value_td()->short_name())
<< xtag("value", this->value())
@ -99,14 +99,14 @@ namespace xo {
* we don't have pretty printer for native function pointers anyway
* + simplifies ppdetail_atomic
*/
return ppii.pps()->pretty_struct(ppii, "Primitive",
return ppii.pps()->pretty_struct(ppii, "PrimitiveExpr",
refrtag("name", name_),
rtag("type", print::quot(this->valuetype()->short_name())),
refrtag("value", (void*)(this->value())));
}
private:
Primitive(TypeDescr fn_type,
PrimitiveExpr(TypeDescr fn_type,
const std::string & name,
FunctionPointer fnptr,
bool explicit_symbol_def,
@ -119,9 +119,9 @@ namespace xo {
intrinsic_{intrinsic}
{
if (!value_td_->is_function())
throw std::runtime_error("Primitive: expected function pointer");
throw std::runtime_error("PrimitiveExpr: expected function pointer");
if (!value_td_->fn_retval())
throw std::runtime_error("Primitive: expected non-null function return value");
throw std::runtime_error("PrimitiveExpr: expected non-null function return value");
}
@ -145,75 +145,75 @@ namespace xo {
* all others: generate direct use of LLVM intrinsic
**/
llvmintrinsic intrinsic_;
}; /*Primitive*/
}; /*PrimitiveExpr*/
/** adopt function @p x as a callable primitive function named @p name **/
template <typename FunctionPointer>
rp<Primitive<FunctionPointer>>
rp<PrimitiveExpr<FunctionPointer>>
make_primitive(const std::string & name,
FunctionPointer x,
bool explicit_symbol_def,
llvmintrinsic intrinsic)
{
return Primitive<FunctionPointer>::make(name, x, explicit_symbol_def, intrinsic);
return PrimitiveExpr<FunctionPointer>::make(name, x, explicit_symbol_def, intrinsic);
}
// NOTE: see xo-reader/src/reader/progress_xs.cpp
// binding operators to primitive applications.
/** builtin primitives :: i64 x i64 -> bool **/
class Primitive_cmp_i64 : public Primitive<bool (*)(std::int64_t, std::int64_t)> {
class PrimitiveExpr_cmp_i64 : public PrimitiveExpr<bool (*)(std::int64_t, std::int64_t)> {
public:
using PrimitiveType = Primitive<bool (*)(std::int64_t, std::int64_t)>;
using PrimitiveExprType = PrimitiveExpr<bool (*)(std::int64_t, std::int64_t)>;
public:
/** eq2_i64: compare two 64-bit integers for equality **/
static rp<PrimitiveType> make_cmp_eq2_i64();
static rp<PrimitiveExprType> make_cmp_eq2_i64();
/** ne2_i64: compare two 64-bit integers for inequality **/
static rp<PrimitiveType> make_cmp_ne2_i64();
static rp<PrimitiveExprType> make_cmp_ne2_i64();
/** lt2_i64: compare two 64-bit integers for lessthan **/
static rp<PrimitiveType> make_cmp_lt2_i64();
static rp<PrimitiveExprType> make_cmp_lt2_i64();
/** lt2_i64: compare two 64-bit integers for lessthanorequal **/
static rp<PrimitiveType> make_cmp_le2_i64();
static rp<PrimitiveExprType> make_cmp_le2_i64();
/** gt2_i64: compare two 64-bit integers for greaterthan **/
static rp<PrimitiveType> make_cmp_gt2_i64();
static rp<PrimitiveExprType> make_cmp_gt2_i64();
/** ge2_i64: compare two 64-bit integers for greaterthan **/
static rp<PrimitiveType> make_cmp_ge2_i64();
static rp<PrimitiveExprType> make_cmp_ge2_i64();
};
/** builtin primitives :: i64 x i64 -> i64 **/
class Primitive_i64 : public Primitive<std::int64_t (*)(std::int64_t, std::int64_t)> {
class PrimitiveExpr_i64 : public PrimitiveExpr<std::int64_t (*)(std::int64_t, std::int64_t)> {
public:
using PrimitiveType = Primitive<std::int64_t (*)(std::int64_t, std::int64_t)>;
using PrimitiveExprType = PrimitiveExpr<std::int64_t (*)(std::int64_t, std::int64_t)>;
public:
/** add2_i64: add two 64-bit integers **/
static rp<PrimitiveType> make_add2_i64();
static rp<PrimitiveExprType> make_add2_i64();
/** sub2_i64: subtract two 64-bit integers **/
static rp<PrimitiveType> make_sub2_i64();
static rp<PrimitiveExprType> make_sub2_i64();
/** mul2_i64: multiply two 64-bit integers **/
static rp<PrimitiveType> make_mul2_i64();
static rp<PrimitiveExprType> make_mul2_i64();
/** div2_i64: divide two 64-bit integers **/
static rp<PrimitiveType> make_div2_i64();
static rp<PrimitiveExprType> make_div2_i64();
};
/** builtin primitives :: f64 x f64 -> f64 **/
class Primitive_f64 : public Primitive<double (*)(double, double)> {
class PrimitiveExpr_f64 : public PrimitiveExpr<double (*)(double, double)> {
public:
using PrimitiveType = Primitive<double (*)(double, double)>;
using PrimitiveExprType = PrimitiveExpr<double (*)(double, double)>;
public:
/** add2_f64: add two 64-bit floating-point numbers **/
static rp<PrimitiveType> make_add2_f64();
static rp<PrimitiveExprType> make_add2_f64();
/** sub2_f64: subtract two 64-bit floating-point numbers **/
static rp<PrimitiveType> make_sub2_f64();
static rp<PrimitiveExprType> make_sub2_f64();
/** mul2_f64: multiply two 64-bit floating-point numbers **/
static rp<PrimitiveType> make_mul2_f64();
static rp<PrimitiveExprType> make_mul2_f64();
/** div2_f64: divide two 64-bit floating-point numbers **/
static rp<PrimitiveType> make_div2_f64();
static rp<PrimitiveExprType> make_div2_f64();
};
} /*namespace scm*/
} /*namespace xo*/
/** end Primitive.hpp **/
/** end PrimitiveExpr.hpp **/

View file

@ -1,7 +1,7 @@
/* @file Apply.cpp */
#include "Apply.hpp"
#include "Primitive.hpp"
#include "PrimitiveExpr.hpp"
#include "exprtype.hpp"
#include "pretty_expression.hpp"
#include "xo/indentlog/print/vector.hpp"
@ -36,7 +36,7 @@ namespace xo {
Apply::make_cmp_eq_i64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_cmp_i64::make_cmp_eq2_i64(),
return Apply::make(PrimitiveExpr_cmp_i64::make_cmp_eq2_i64(),
{lhs, rhs});
}
@ -44,7 +44,7 @@ namespace xo {
Apply::make_cmp_ne_i64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_cmp_i64::make_cmp_ne2_i64(),
return Apply::make(PrimitiveExpr_cmp_i64::make_cmp_ne2_i64(),
{lhs, rhs});
}
@ -52,7 +52,7 @@ namespace xo {
Apply::make_cmp_lt_i64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_cmp_i64::make_cmp_lt2_i64(),
return Apply::make(PrimitiveExpr_cmp_i64::make_cmp_lt2_i64(),
{lhs, rhs});
}
@ -60,7 +60,7 @@ namespace xo {
Apply::make_cmp_le_i64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_cmp_i64::make_cmp_le2_i64(),
return Apply::make(PrimitiveExpr_cmp_i64::make_cmp_le2_i64(),
{lhs, rhs});
}
@ -68,7 +68,7 @@ namespace xo {
Apply::make_cmp_gt_i64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_cmp_i64::make_cmp_gt2_i64(),
return Apply::make(PrimitiveExpr_cmp_i64::make_cmp_gt2_i64(),
{lhs, rhs});
}
@ -76,7 +76,7 @@ namespace xo {
Apply::make_cmp_ge_i64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_cmp_i64::make_cmp_ge2_i64(),
return Apply::make(PrimitiveExpr_cmp_i64::make_cmp_ge2_i64(),
{lhs, rhs});
}
@ -86,7 +86,7 @@ namespace xo {
Apply::make_add2_i64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_i64::make_add2_i64(),
return Apply::make(PrimitiveExpr_i64::make_add2_i64(),
{lhs, rhs});
}
@ -94,7 +94,7 @@ namespace xo {
Apply::make_sub2_i64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_i64::make_sub2_i64(),
return Apply::make(PrimitiveExpr_i64::make_sub2_i64(),
{lhs, rhs});
}
@ -102,7 +102,7 @@ namespace xo {
Apply::make_mul2_i64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_i64::make_mul2_i64(),
return Apply::make(PrimitiveExpr_i64::make_mul2_i64(),
{lhs, rhs});
}
@ -110,7 +110,7 @@ namespace xo {
Apply::make_div2_i64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_i64::make_div2_i64(),
return Apply::make(PrimitiveExpr_i64::make_div2_i64(),
{lhs, rhs});
}
@ -120,7 +120,7 @@ namespace xo {
Apply::make_add2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_f64::make_add2_f64(),
return Apply::make(PrimitiveExpr_f64::make_add2_f64(),
{lhs, rhs});
}
@ -128,7 +128,7 @@ namespace xo {
Apply::make_sub2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_f64::make_sub2_f64(),
return Apply::make(PrimitiveExpr_f64::make_sub2_f64(),
{lhs, rhs});
}
@ -136,7 +136,7 @@ namespace xo {
Apply::make_mul2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_f64::make_mul2_f64(),
return Apply::make(PrimitiveExpr_f64::make_mul2_f64(),
{lhs, rhs});
}
@ -144,7 +144,7 @@ namespace xo {
Apply::make_div2_f64(const rp<Expression> & lhs,
const rp<Expression> & rhs)
{
return Apply::make(Primitive_f64::make_div2_f64(),
return Apply::make(PrimitiveExpr_f64::make_div2_f64(),
{lhs, rhs});
}

View file

@ -14,7 +14,7 @@ set(SELF_SRCS
GlobalSymtab.cpp
LocalSymtab.cpp
ConvertExpr.cpp
Primitive.cpp
PrimitiveExpr.cpp
typeinf/type_ref.cpp
typeinf/type_unifier.cpp
typeinf/TypeBlueprint.cpp

View file

@ -1,6 +1,6 @@
/* @file Primitive.cpp */
/* @file PrimitiveExpr.cpp */
#include "Primitive.hpp"
#include "PrimitiveExpr.hpp"
#include <cstdint>
extern "C" {
@ -86,12 +86,12 @@ extern "C" {
namespace xo {
namespace scm {
auto
Primitive_cmp_i64::make_cmp_eq2_i64() -> rp<PrimitiveType>
PrimitiveExpr_cmp_i64::make_cmp_eq2_i64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("cmp_eq2_i64",
s_retval = PrimitiveExpr::make("cmp_eq2_i64",
&cmp_eq2_i64,
true /*explicit_symbol_def*/,
llvmintrinsic::i_eq);
@ -100,12 +100,12 @@ namespace xo {
}
auto
Primitive_cmp_i64::make_cmp_ne2_i64() -> rp<PrimitiveType>
PrimitiveExpr_cmp_i64::make_cmp_ne2_i64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("cmp_ne2_i64",
s_retval = PrimitiveExpr::make("cmp_ne2_i64",
&cmp_ne2_i64,
true /*explicit_symbol_def*/,
llvmintrinsic::i_ne);
@ -114,12 +114,12 @@ namespace xo {
}
auto
Primitive_cmp_i64::make_cmp_lt2_i64() -> rp<PrimitiveType>
PrimitiveExpr_cmp_i64::make_cmp_lt2_i64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("cmp_lt2_i64",
s_retval = PrimitiveExpr::make("cmp_lt2_i64",
&cmp_lt2_i64,
true /*explicit_symbol_def*/,
llvmintrinsic::i_slt);
@ -128,12 +128,12 @@ namespace xo {
}
auto
Primitive_cmp_i64::make_cmp_le2_i64() -> rp<PrimitiveType>
PrimitiveExpr_cmp_i64::make_cmp_le2_i64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("cmp_le2_i64",
s_retval = PrimitiveExpr::make("cmp_le2_i64",
&cmp_le2_i64,
true /*explicit_symbol_def*/,
llvmintrinsic::i_sle);
@ -142,12 +142,12 @@ namespace xo {
}
auto
Primitive_cmp_i64::make_cmp_gt2_i64() -> rp<PrimitiveType>
PrimitiveExpr_cmp_i64::make_cmp_gt2_i64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("cmp_gt2_i64",
s_retval = PrimitiveExpr::make("cmp_gt2_i64",
&cmp_gt2_i64,
true /*explicit_symbol_def*/,
llvmintrinsic::i_sgt);
@ -156,12 +156,12 @@ namespace xo {
}
auto
Primitive_cmp_i64::make_cmp_ge2_i64() -> rp<PrimitiveType>
PrimitiveExpr_cmp_i64::make_cmp_ge2_i64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("cmp_ge2_i64",
s_retval = PrimitiveExpr::make("cmp_ge2_i64",
&cmp_ge2_i64,
true /*explicit_symbol_def*/,
llvmintrinsic::i_sge);
@ -172,12 +172,12 @@ namespace xo {
/* TODO: remaining integer arithmetic */
auto
Primitive_i64::make_add2_i64() -> rp<PrimitiveType>
PrimitiveExpr_i64::make_add2_i64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("add2_i64",
s_retval = PrimitiveExpr::make("add2_i64",
&add2_i64,
true /*explicit_symbol_def*/,
llvmintrinsic::i_add);
@ -186,12 +186,12 @@ namespace xo {
}
auto
Primitive_i64::make_sub2_i64() -> rp<PrimitiveType>
PrimitiveExpr_i64::make_sub2_i64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("sub2_i64",
s_retval = PrimitiveExpr::make("sub2_i64",
&sub2_i64,
true /*explicit_symbol_def*/,
llvmintrinsic::i_sub);
@ -200,12 +200,12 @@ namespace xo {
}
auto
Primitive_i64::make_mul2_i64() -> rp<PrimitiveType>
PrimitiveExpr_i64::make_mul2_i64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("mul2_i64",
s_retval = PrimitiveExpr::make("mul2_i64",
&mul2_i64,
true /*explicit_symbol_def*/,
llvmintrinsic::i_mul);
@ -214,12 +214,12 @@ namespace xo {
}
auto
Primitive_i64::make_div2_i64() -> rp<PrimitiveType>
PrimitiveExpr_i64::make_div2_i64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("div2_i64",
s_retval = PrimitiveExpr::make("div2_i64",
&div2_i64,
true /*explicit_symbol+def*/,
llvmintrinsic::i_sdiv);
@ -229,12 +229,12 @@ namespace xo {
// ----- floating-point arithmetic -----
auto
Primitive_f64::make_add2_f64() -> rp<PrimitiveType>
PrimitiveExpr_f64::make_add2_f64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("add2_f64",
s_retval = PrimitiveExpr::make("add2_f64",
&add2_f64,
true /*explicit_symbol_def*/,
llvmintrinsic::fp_add);
@ -243,12 +243,12 @@ namespace xo {
}
auto
Primitive_f64::make_sub2_f64() -> rp<PrimitiveType>
PrimitiveExpr_f64::make_sub2_f64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("sub2_f64",
s_retval = PrimitiveExpr::make("sub2_f64",
&sub2_f64,
true /*explicit_symbol_def*/,
llvmintrinsic::fp_sub);
@ -257,12 +257,12 @@ namespace xo {
}
auto
Primitive_f64::make_mul2_f64() -> rp<PrimitiveType>
PrimitiveExpr_f64::make_mul2_f64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("mul2_f64",
s_retval = PrimitiveExpr::make("mul2_f64",
&mul2_f64,
true /*explicit_symbol_def*/,
llvmintrinsic::fp_mul);
@ -271,12 +271,12 @@ namespace xo {
}
auto
Primitive_f64::make_div2_f64() -> rp<PrimitiveType>
PrimitiveExpr_f64::make_div2_f64() -> rp<PrimitiveExprType>
{
static rp<PrimitiveType> s_retval;
static rp<PrimitiveExprType> s_retval;
if (!s_retval)
s_retval = Primitive::make("div2_f64",
s_retval = PrimitiveExpr::make("div2_f64",
&div2_f64,
true /*explicit_symbol_def*/,
llvmintrinsic::fp_div);
@ -288,4 +288,4 @@ namespace xo {
} /*namespace xo*/
/* end Primitive.cpp */
/* end PrimitiveExpr.cpp */

View file

@ -0,0 +1,18 @@
/** @file BuiltinPrimitives.hpp
*
* @author Roland Conybeare, Nov 2025
**/
#include "xo/alloc/IAlloc.hpp"
#include "GlobalEnv.hpp"
namespace xo {
namespace scm {
struct BuiltinPrimitives {
public:
static void install(gc::IAlloc * mm, gp<GlobalEnv> env);
};
}
}
/* end BuiltinPrimitives.hpp */

View file

@ -87,7 +87,7 @@ namespace xo {
**/
rp<LocalSymtab> symtab_;
/** environment contents **/
CVector<gp<Object>> slot_v_;
obj::CVector<gp<Object>> slot_v_;
};
} /*namespace scm*/
} /*namespace xo*/

View file

@ -6,7 +6,7 @@
#pragma once
#include "VsmInstr.hpp"
#include "CVector.hpp"
#include "xo/object/CVector.hpp"
#include "xo/alloc/Object.hpp"
namespace xo {
@ -73,7 +73,7 @@ namespace xo {
gp<VsmStackFrame> parent_;
/** stored state **/
CVector<gp<Object>> slot_v_;
obj::CVector<gp<Object>> slot_v_;
/** proceed to this continuation when popping this frame **/
const VsmInstr * cont_ = nullptr;

View file

@ -0,0 +1,39 @@
/** @file BuiltinPrimitives.cpp
*
* @author Roland Conybeare, Nov 2025
**/
#include "BuiltinPrimitives.hpp"
#include "ObjectConversion.hpp"
#include "Integer.hpp"
#include "Primitive.hpp"
#include "xo/reflect/Reflect.hpp"
#include <cstdint>
namespace xo {
using xo::reflect::Reflect;
using xo::reflect::TypeDescr;
namespace scm {
int64_t
add64(int64_t x, int64_t y)
{
return x + y;
}
void
BuiltinPrimitives::install(gc::IAlloc * mm, gp<GlobalEnv> env)
{
{
gp<Object> rhs = xo::obj::make_primitive(mm, add64);
TypeDescr td = Reflect::require<decltype(add64)>();
rp<Variable> lhs = Variable::make("add", td);
gp<Object> * addr = env->establish_var(lhs.borrow());
*addr = rhs;
}
}
}
}
/* end BuiltinPrimitives.cpp */

View file

@ -4,6 +4,7 @@ set(SELF_LIB xo_interpreter)
set(SELF_SRCS
init_interpreter.cpp
Schematika.cpp
BuiltinPrimitives.cpp
LocalEnv.cpp
GlobalEnv.cpp
VirtualSchematikaMachine.cpp

View file

@ -162,7 +162,7 @@ namespace xo {
*
* note: placement here works b/c CVector<T> not used anywhere else
*/
using VectorType = CVector<gp<Object>>;
using VectorType = obj::CVector<gp<Object>>;
/* custom reflection for array of Object pointers.
* Can use StlVectorTdx here, treating CVector<T> as a vector

View file

@ -5,6 +5,7 @@
#include "Schematika.hpp"
#include "VirtualSchematikaMachine.hpp"
#include "BuiltinPrimitives.hpp"
#include "GlobalEnv.hpp"
#include "xo/reader/reader.hpp"
#include <replxx.hxx>
@ -69,7 +70,9 @@ namespace xo {
{
up<IAlloc> mm = GC::make(cfg.gc_config_);
rp<GlobalSymtab> symtab = GlobalSymtab::make_empty();
gp<Env> env = GlobalEnv::make_empty(mm.get(), symtab);
gp<GlobalEnv> env = GlobalEnv::make_empty(mm.get(), symtab);
BuiltinPrimitives::install(mm.get(), env);
return std::make_unique<Impl>(cfg, std::move(mm), env);
}

View file

@ -140,7 +140,7 @@ namespace xo {
/* reflect CVector<gp<Object>>.
* duplicates similar code in LocalEnv::reflect_self()
*/
using VectorType = CVector<gp<Object>>;
using VectorType = obj::CVector<gp<Object>>;
/* custom reflection for array of Object pointers.
* Can use StlVectorTdx here, treating CVector<T> as a vector

View file

@ -2,7 +2,7 @@
#include "xo/jit/MachPipeline.hpp"
#include "xo/expression/Constant.hpp"
#include "xo/expression/Primitive.hpp"
#include "xo/expression/PrimitiveExpr.hpp"
#include "xo/expression/Apply.hpp"
#include "xo/expression/Lambda.hpp"
#include "xo/expression/Variable.hpp"

View file

@ -3,7 +3,7 @@
#include "xo/jit/MachPipeline.hpp"
#include "xo/jit/activation_record.hpp"
#include "xo/expression/Constant.hpp"
#include "xo/expression/Primitive.hpp"
#include "xo/expression/PrimitiveExpr.hpp"
#include "xo/expression/Apply.hpp"
#include "xo/expression/Lambda.hpp"
#include "xo/expression/Variable.hpp"

View file

@ -9,7 +9,7 @@
#include <cstdint>
namespace xo {
namespace scm {
namespace obj {
/** gc-only vector.
* Used in both LocalEnv and VsmStackFrame
**/
@ -33,18 +33,13 @@ namespace xo {
ElementType operator[](std::size_t i) const { return v_[i]; }
ElementType & operator[](std::size_t i) { return v_[i]; }
friend class LocalEnv;
friend class VsmStackFrame;
private:
public:
/** number of elements in @ref v_ **/
std::size_t n_ = 0;
/** contiguous array of pointers **/
ElementType * v_ = nullptr;
};
} /*namespace scm*/
} /*namespace obj*/
} /*namespace xo*/
/* end CVector.hpp */

View file

@ -6,6 +6,8 @@
#pragma once
#include "Number.hpp"
#include "ObjectConversion.hpp"
#include "xo/indentlog/print/tag.hpp"
namespace xo {
namespace obj {
@ -37,6 +39,29 @@ namespace xo {
private:
int_type value_ = 0;
};
template <typename IntType>
struct ObjectConversion_Integer {
static gp<Object> to_object(gc::IAlloc * mm, IntType x) {
return new (MMPtr(mm)) Integer(x);
}
static IntType from_object(gc::IAlloc *, gp<Object> x) {
gp<Integer> x_int = Integer::from(x);
if (x_int.get()) {
return x_int->value();
} else {
throw std::runtime_error(tostr("ObjectConversion_Integer: x found where Integer expected", xtag("x", x)));
}
}
};
template <>
struct ObjectConversion<int64_t> : public ObjectConversion_Integer<int64_t> {};
template <>
struct ObjectConversion<int32_t> : public ObjectConversion_Integer<int32_t> {};
template <>
struct ObjectConversion<int16_t> : public ObjectConversion_Integer<int16_t> {};
} /*namespace obj*/
} /*namespace xo*/

View file

@ -0,0 +1,20 @@
/** @file ObjectConversion.hpp
*
* @author Roland Conybeare, Nov 2025
**/
#pragma once
#include "Object.hpp"
namespace xo {
namespace obj {
template <typename T>
struct ObjectConversion {
static gp<Object> to_object(gc::IAlloc * mm, const T & x) = delete;
static T from_object(gc::IAlloc * mm, gp<Object> x) = delete;
};
}
}
/* end ObjectConversion.hpp */

View file

@ -6,7 +6,8 @@
#pragma once
#include "Procedure.hpp"
#include "CVector.hpp"
#include "ObjectConversion.hpp"
#include "xo/reflect/Reflect.hpp"
namespace xo {
namespace obj {
@ -25,15 +26,14 @@ namespace xo {
using function_type = Fn;
public:
explicit PrimitiveBase(Converter & cvt, Fn impl) : converter_{cvt}, impl_{std::move(impl)} {}
explicit PrimitiveBase(Fn impl) : impl_{std::move(impl)} {}
// inherited from Procedure..
virtual std::size_t n_args() const override = 0;
virtual gp<Object> apply_nocheck(const CVector<gp<Object>> & args) override = 0;
virtual gp<Object> apply_nocheck(gc::IAlloc * mm, const CVector<gp<Object>> & args) override = 0;
protected:
Converter & converter_;
Fn impl_;
};
@ -41,29 +41,60 @@ namespace xo {
class Primitive : public PrimitiveBase<Fn> {
};
template <Ret, Arg1, Arg2>
template <typename Ret, typename Arg1, typename Arg2>
class Primitive<Ret (*)(Arg1, Arg2)> : public PrimitiveBase<Ret (*)(Arg1, Arg2)> {
public:
using Super = PrimitiveBase<Ret (*)(Arg1, Arg2)>;
using function_type = Ret (*)(Arg1, Arg2);
using TaggedPtr = xo::reflect::TaggedPtr;
public:
explicit Primitive(Converter & cvt, function_type fn) : PrimitiveBase<Ret (*)(Arg1, Arg2)>{cvt, fn} {}
explicit Primitive(function_type fn) : PrimitiveBase<Ret (*)(Arg1, Arg2)>{fn} {}
// inherited from Procedure..
virtual std::size_t n_args() const final override { return 2; }
virtual gp<Object> apply_nocheck(const CVector<gp<Object>> & args) final override {
/* note: args[0] will be this procedure. actual i'th function argument in args[i+1]
*/
args[1]
virtual gp<Object> apply_nocheck(gc::IAlloc * mm,
const CVector<gp<Object>> & args) final override {
/* note: args[0] will be this procedure.
* actual i'th function argument in args[i+1]
*/
Arg1 arg1 = ObjectConversion<Arg1>::from_object(mm, args[1]);
Arg2 arg2 = ObjectConversion<Arg2>::from_object(mm, args[2]);
Ret retval = (*Super::impl_)(arg1, arg2);
return ObjectConversion<Ret>::to_object(mm, retval);
}
private:
// inherited from Object..
virtual TaggedPtr self_tp() const final override {
using xo::reflect::Reflect;
return Reflect::make_tp(const_cast<Primitive*>(this));
}
virtual void display(std::ostream & os) const final override {
os << "<primitive>";
}
virtual std::size_t _shallow_size() const final override {
return sizeof(*this);
}
virtual Object *_shallow_copy(gc::IAlloc * mm) const final override {
Cpof cpof(mm, this);
return new (cpof) Primitive(*this);
}
std::size_t _forward_children(gc::IAlloc *) final override {
return _shallow_size();
}
};
template <typename Fn>
gp<Primitive<Fn>>
make_primitive(gc::IAlloc * mm, Fn fn) {
return new (MMPtr(mm)) Primitive<Fn>(fn);
}
}
}

View file

@ -6,8 +6,11 @@
#pragma once
#include "Object.hpp"
#include "CVector.hpp"
namespace xo {
namespace gc { class IAlloc; }; // see xo-alloc: xo/alloc/IAlloc.hpp
namespace obj {
/** @class ProcedureInterface
* @brief Interface to a dynamically-typed procedure
@ -15,7 +18,7 @@ namespace xo {
class Procedure : public Object {
public:
virtual std::size_t n_args() const = 0;
virtual gp<Object> apply_nocheck(const CVector<gp<Object>> & args) = 0;
virtual gp<Object> apply_nocheck(gc::IAlloc * mm, const CVector<gp<Object>> & args) = 0;
// inherited from Object..

View file

@ -5,7 +5,7 @@
#include "xo/expression/Expression.hpp"
#include "xo/expression/Apply.hpp"
#include "xo/expression/PrimitiveExprInterface.hpp"
#include "xo/expression/Primitive.hpp"
#include "xo/expression/PrimitiveExpr.hpp"
#include "xo/expression/ConstantInterface.hpp"
#include "xo/expression/Constant.hpp"
#include "xo/expression/Variable.hpp"
@ -22,7 +22,7 @@ namespace xo {
using xo::scm::Expression;
using xo::scm::make_apply;
using xo::scm::PrimitiveExprInterface;
using xo::scm::Primitive;
using xo::scm::PrimitiveExpr;
using xo::scm::make_primitive;
using xo::scm::ConstantInterface;
using xo::scm::Constant;
@ -106,14 +106,14 @@ namespace xo {
using int32_t = std::int32_t;
py::class_<Primitive<int32_t (*)(int32_t, int32_t)>,
py::class_<PrimitiveExpr<int32_t (*)(int32_t, int32_t)>,
PrimitiveExprInterface,
rp<Primitive<int32_t (*)(int32_t, int32_t)>>>(m, "Primitive_i32_i32")
rp<PrimitiveExpr<int32_t (*)(int32_t, int32_t)>>>(m, "PrimitiveExpr_i32_i32")
;
py::class_<Primitive<double (*)(double)>,
py::class_<PrimitiveExpr<double (*)(double)>,
PrimitiveExprInterface,
rp<Primitive<double (*)(double)>>>(m, "Primitive_double_double")
rp<PrimitiveExpr<double (*)(double)>>>(m, "PrimitiveExpr_double_double")
;
using Fn_dbl_dbl_type = double (*)(double);
@ -135,9 +135,9 @@ namespace xo {
llvmintrinsic::fp_cos); },
py::doc("create primitive representing the ::cos() function"));
py::class_<Primitive<double (*)(double, double)>,
py::class_<PrimitiveExpr<double (*)(double, double)>,
PrimitiveExprInterface,
rp<Primitive<double (*)(double, double)>>>(m, "Primitive_double_double_double")
rp<PrimitiveExpr<double (*)(double, double)>>>(m, "PrimitiveExpr_double_double_double")
;
m.def("make_pow_pm",

View file

@ -4,7 +4,7 @@
#include "xo/pyexpression/pyexpression.hpp"
#include "xo/jit/MachPipeline.hpp"
#include "xo/jit/intrinsics.hpp"
#include "xo/expression/Primitive.hpp"
#include "xo/expression/PrimitiveExpr.hpp"
#include "xo/pyutil/pycaller.hpp"
#include "xo/pyutil/pyutil.hpp"
#include <llvm/Config/llvm-config.h>

View file

@ -99,21 +99,28 @@ namespace xo {
*
* Example
* T * p = new T(...);
* DestructorAux<T>::dtor(p);
* InvokerAux<T>::dtor(p);
**/
template <typename T>
struct InvokerAux : public Invoker {
virtual void dtor(void * addr) const override {
T * obj = static_cast<T *>(addr);
T * obj = reinterpret_cast<T *>(addr);
obj->~T();
}
};
/** no dtor for void **/
template<>
struct InvokerAux<void> : public Invoker {
virtual void dtor(void *) const override {}
};
/** no dtor for function types **/
template <typename Ret, typename... Args>
struct InvokerAux<Ret(Args...)> : public Invoker {
virtual void dtor(void *) const override {}
};
} /*namespace detail*/
} /*namespace reflect*/
} /*namespace xo*/