Login
7 branches 0 tags
Ben(Parabola/X220) Minor termed improvements 9e49b2d 2 years ago 1014 Commits
nujel / lib / nujel.h
/*
 | nujel.h
 |
 | This file contains the public interface to the Nujel runtime.
 | While it is still not stable, it shouldn't change as often anymore.
 */
#ifndef NUJEL_LIB_NUJEL_PUBLIC
#define NUJEL_LIB_NUJEL_PUBLIC

#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

#if defined(_MSC_VER)
#define likely(x) x
#define unlikely(x) x
#else
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif

#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define countof(x) (sizeof(x) / sizeof(*x))

/*
 | Now for some type/struct definitions
 */

typedef unsigned int uint;

typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;

typedef int64_t i64;
typedef int32_t i32;
typedef int16_t i16;
typedef int8_t i8;

/*
 | And some Windows workarounds
 */
#ifdef _MSC_VER
typedef int64_t ssize_t;
#endif

typedef enum {
    ltNil = 0,

    ltSymbol,
    ltKeyword,
    ltBool,
    ltInt,
    ltFloat,

    ltPair,
    ltArray,
    ltTree,

    ltLambda,
    ltMacro,
    ltNativeFunc,
    ltEnvironment,

    ltString,
    ltBuffer,
    ltBufferView,
    ltBytecodeArr,

    ltFileHandle,
    ltComment,
    ltException
} lType;

typedef struct lBuffer lBuffer;
typedef struct lBufferView lBufferView;
typedef struct lArray lArray;
typedef struct lClosure lClosure;
typedef struct lThread lThread;
typedef struct lNFunc lNFunc;
typedef struct lSymbol lSymbol;
typedef struct lTree lTree;
typedef struct lTreeRoot lTreeRoot;
typedef struct lVec lVec;
typedef struct lVal lVal;
typedef struct lPair lPair;
typedef struct lBytecodeArray lBytecodeArray;
typedef uint8_t lBytecodeOp;
typedef lBuffer lString;

struct lTreeRoot {
    union {
        lTree *root;
        lTreeRoot *nextFree;
    };
};

struct lVal {
    u32 type;
    union {
        bool vBool;
        i64 vInt;
        double vFloat;
        lPair *vList;
        const lSymbol *vSymbol;
        FILE *vFileHandle;
        lBytecodeArray *vBytecodeArr;
        lArray *vArray;
        lTreeRoot *vTree;
        lString *vString;
        lClosure *vClosure;
        lNFunc *vNFunc;
        void *vPointer;
        lBuffer *vBuffer;
        lBufferView *vBufferView;
    };
};

extern lVal NIL;

static inline lVal lValAlloc(lType T, void *v) { return (lVal){T, .vPointer = v}; }

struct lPair {
    lVal car;
    union {
        lPair *nextFree;
        lVal cdr;
    };
};

/*
 | Some pretty core Nujel procedures
 */
void lInit();
lClosure *lNewRoot();
lVal lApply(lClosure *c, lVal args, lVal fun);
lVal lLambda(lClosure *c, lVal args, lVal lambda);
lClosure *lLoad(lClosure *c, const char *expr);

const void *lBufferData(lBuffer *v);
void *lBufferDataMutable(lBuffer *v);
size_t lBufferLength(const lBuffer *v);
const void *lBufferViewData(lBufferView *v);
void *lBufferViewDataMutable(lBufferView *v);
size_t lBufferViewLength(const lBufferView *v);

lPair *lPairAllocRaw();
static inline lVal lCons(lVal car, lVal cdr) {
    lPair *cons = lPairAllocRaw();
    cons->car = car;
    cons->cdr = cdr;
    return lValAlloc(ltPair, cons);
}

static inline lVal lCar(lVal v) { return likely(v.type == ltPair) ? v.vList->car : NIL; }

static inline lVal lCdr(lVal v) { return likely(v.type == ltPair) ? v.vList->cdr : NIL; }

static inline lVal lCaar(lVal v) { return lCar(lCar(v)); }
static inline lVal lCadr(lVal v) { return lCar(lCdr(v)); }
static inline lVal lCdar(lVal v) { return lCdr(lCar(v)); }
static inline lVal lCddr(lVal v) { return lCdr(lCdr(v)); }
static inline lVal lCaddr(lVal v) { return lCar(lCdr(lCdr(v))); }
static inline lVal lCadddr(lVal v) { return lCar(lCdr(lCdr(lCdr(v)))); }

lVal lValException(const char *symbol, const char *error, lVal v);

/*
 | Reader/Printer
 */
lVal lRead(lClosure *c, const char *str);

/*
 | Type related procedores
 */
i64 castToInt(const lVal v, i64 fallback);
bool castToBool(const lVal v);
const char *castToString(const lVal v, const char *fallback);

lVal lValExceptionType(lVal v, lType T);
lVal lValExceptionArity(lVal v, int arity);
lVal lValExceptionNonNumeric(lVal v);
lVal lValExceptionFloat(lVal v);
lVal requireInt(lVal v);
lVal requireNaturalInt(lVal v);
lVal requireFloat(lVal v);
lVal optionalSymbolic(lVal v, const lSymbol *fallback);
lVal requireSymbol(lVal v);
lVal requireKeyword(lVal v);
lVal requireSymbolic(lVal v);
lVal requireFileHandle(lVal v);
lVal requireArray(lVal v);
lVal requireMutableArray(lVal v);
lVal requireTree(lVal v);
lVal requireMutableTree(lVal v);
lVal requireString(lVal v);
lVal requireCallable(lVal v);
lVal requirePair(lVal v);
lVal requireBuffer(lVal v);
lVal requireMutableBuffer(lVal v);
lVal requireBufferView(lVal v);
lVal requireMutableBufferView(lVal v);

/*
 | Closure related procedores
 */
lVal lDefineAliased(lClosure *c, lVal lNF, const char *sym);

lVal lGetClosureSym(lClosure *c, const lSymbol *s);
void lDefineClosureSym(lClosure *c, const lSymbol *s, lVal v);
bool lSetClosureSym(lClosure *c, const lSymbol *s, lVal v);
void lDefineVal(lClosure *c, const char *str, lVal v);

lVal lAddNativeFunc(lClosure *c, const char *sym, const char *args, const char *doc, lVal (*func)(lClosure *, lVal));
lVal lAddNativeFuncFold(lClosure *c, const char *sym, const char *args, const char *doc,
                        lVal (*func)(lClosure *, lVal));
lVal lAddNativeFuncPure(lClosure *c, const char *sym, const char *args, const char *doc,
                        lVal (*func)(lClosure *, lVal));
lVal lAddNativeFuncPureFold(lClosure *c, const char *sym, const char *args, const char *doc,
                            lVal (*func)(lClosure *, lVal));

/*
 | Tree related procedures
 */
lTree *lTreeNew(const lSymbol *s, lVal v);
lTree *lTreeDup(const lTree *t);

lVal lTreeRef(const lTree *t, const lSymbol *s);
bool lTreeSet(lTree *t, const lSymbol *s, lVal v);
lTree *lTreeInsert(lTree *t, const lSymbol *s, lVal v);

/*
 | Symbolic routines
 */
lSymbol *lSymS(const char *s);
lSymbol *lSymSM(const char *s);
lSymbol *lSymSL(const char *s, uint len);

/*
 | lVal related procedures
 */
static inline lVal lValFloat(double v) {
    if (unlikely(isnan(v))) {
        return lValException("float-nan", "NaN is disallowed in Nujel", NIL);
    }
    if (unlikely(isinf(v))) {
        return lValException("float-inf", "INF is disallowed in Nujel", NIL);
    }
    return (lVal){ltFloat, .vFloat = v};
}

static inline lVal lValExceptionSimple() { return (lVal){ltException, .vList = NULL}; }

static inline lVal lValInt(i64 v) { return (lVal){ltInt, .vInt = v}; }

static inline lVal lValBool(bool v) { return (lVal){ltBool, .vBool = v}; }

lTreeRoot *lTreeRootAllocRaw();
static inline lVal lValTree(lTree *v) {
    lTreeRoot *root = lTreeRootAllocRaw();
    root->root = v;
    return (lVal){ltTree, .vTree = root};
}

static inline lVal lValEnvironment(lClosure *v) { return (lVal){ltEnvironment, .vClosure = v}; }

static inline lVal lValLambda(lClosure *v) { return (lVal){ltLambda, .vClosure = v}; }

/* Return a newly allocated nujel symbol of value S */
static inline lVal lValSymS(const lSymbol *s) {
    if (unlikely(s == NULL)) {
        return NIL;
    }
    return (lVal){ltSymbol, .vSymbol = s};
}

/* Return a nujel value for the symbol within S */
static inline lVal lValSym(const char *s) { return lValSymS(lSymS(s)); }

/* Return a newly allocated nujel keyword of value S */
static inline lVal lValKeywordS(const lSymbol *s) {
    if (unlikely(s == NULL)) {
        return NIL;
    }
    return (lVal){ltKeyword, .vSymbol = s};
}

/* Return a nujel value for the keyword within S */
static inline lVal lValKeyword(const char *s) { return lValKeywordS(lSymS(s)); }

static inline lVal lValFileHandle(FILE *fh) { return (lVal){ltFileHandle, .vFileHandle = fh}; }

lVal lValString(const char *s);
lVal lValStringLen(const char *s, int len);
lVal lValStringNoCopy(const char *s, int len);

/*
 | Allocator related procedures
 */
lArray *lArrayAlloc(size_t len);
lBuffer *lBufferAlloc(size_t length, bool immutable);
lString *lStringNew(const char *str, uint len);
lString *lStringDup(const lString *s);

#endif