summaryrefslogtreecommitdiff
path: root/pez.h
blob: 063905c6351a8ab825fb167c103b639c003bc3a9 (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
#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_TFn,
    PEZ_TTuple,
    PEZ_TRecord,
    PEZ_TArray,
};

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);
void pez_del(PezContext *);

/*
 * opts:
 *   NULL -> reset debug options
 *   'b': enable print bytecode to stderr
 */
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);
const char *pez_typename(PezContext *, int idx);

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)
{
    if (b == 0) {
        return a >= 0 ? INT32_MAX : INT32_MIN;
    }
    int64_t 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