summaryrefslogtreecommitdiff
path: root/pez.h
blob: b372e0e862f69c9a6ad496d22a7634eb2d08dff5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#ifndef PEZ_H_
#define PEZ_H_

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

typedef int32_t PezNumber;

enum {
    PEZ_TVoid,
    PEZ_TObject,
    PEZ_TNumber,
    PEZ_TBool,
    PEZ_TString,
    PEZ_TFnProto,
    PEZ_TUpval,
    PEZ_TFn,
    PEZ_TTuple,
    PEZ_TRecord,
    PEZ_TArray,
    PEZ_TDilambda
};

typedef enum PezError {
    PEZ_EStack = 1,
    PEZ_ENoMem,
    PEZ_ESyntax,
    PEZ_ERuntime,
} PezError;


typedef struct PezContext PezContext;
typedef void *PezAllocFn(void *userdata, void *ptr, size_t oldsize, size_t newsize);
typedef bool PezCFn(PezContext *, int argc);

PezContext *pez_new(PezAllocFn *alloc, void *userdata, size_t stacksize);
void pez_del(PezContext *);

/*
 * opts:
 *   NULL -> reset debug options
 *   'b': enable print bytecode to stderr
 *   'G': stress GC
 *   'g': print GC debug info
 */
void pez_debug(PezContext *, const char *opts);

int pez_geterrno(PezContext *);
const char *pez_geterr(PezContext *cx);

bool pez_eval_cb(PezContext *, const char *fname, int (*cb)(void *), void *);
bool pez_eval_str(PezContext *, const char *fname, const char *);
bool pez_eval_file(PezContext *, const char *path, FILE *);

int pez_top(PezContext *);

void pez_pop(PezContext *cx);
bool pez_push(PezContext *cx, int idx);
bool pez_pushvoid(PezContext *cx);
bool pez_pushnumber(PezContext *, PezNumber);
bool pez_pushint(PezContext *, int);
bool pez_pushstring(PezContext *, const char *str, int len);
bool pez_pushglobal(PezContext *, const char *name);

bool pez_isvoid(PezContext *, int idx);
bool pez_isnumber(PezContext *, int idx);
bool pez_isbool(PezContext *, int idx);
bool pez_isstring(PezContext *, int idx);
bool pez_isfunction(PezContext *, int idx);
bool pez_isarray(PezContext *, int idx);
int pez_typeof(PezContext *, int idx);
const char *pez_typename(PezContext *, int idx);

bool pez_checksig(PezContext *, int argc, const char *fn, const char *sig);

bool pez_getnumber(PezContext *, PezNumber *, int idx);
bool pez_getbool(PezContext *, bool *, int idx);
const char *pez_getstring(PezContext *, char buf[8], int idx);
const char *pez_fnname(PezContext *, int idx);
int pez_length(PezContext *cx, int idx);

void pez_error(PezContext *cx, const char *fn, const char *fmt, ...);

bool pez_apply(PezContext *cx, int argc);
bool pez_setapply(PezContext *cx, int argc);
bool pez_iget(PezContext *cx, int idx, int arg);

static inline double
pez_numtof(PezNumber x) { return x / 4096.0; }

static inline PezNumber
pez_ftonum(double x) { return x * 4096.0; }

static inline PezNumber
pez_fixmul(PezNumber a, PezNumber b)
{
    int64_t tmp = (int64_t)a * b;
    // tmp += (1 << 11); // rounding
    return tmp >> 12;
}

static inline PezNumber
pez_fixdiv(PezNumber a, PezNumber b)
{
    int64_t tmp;
    if (b == 0) {
        return a >= 0 ? INT32_MAX : INT32_MIN;
    }
    tmp = (uint64_t)a << 12;
    /*
    if ((tmp < 0) == (b < 0)) {
        tmp += b >> 1;
    } else {
        tmp -= b >> 1;
    }
    */
    return tmp / b;
}

static inline PezNumber
pez_fixmod(PezNumber a, PezNumber b)
{
    if (b == 0) {
        return 0;
    } else if (b < 0) {
        return -a % -b;
    }
    return a % b;
}

#endif