/* Byte code fragment construction functions */

typedef struct frag Frag;

struct frag {
	unsigned char *start;
	ptrdiff_t len;
	ptrdiff_t size;
	ptrdiff_t align;
};

/* Initialize a fragment: 'alignment' sets the natural alignment of
 * the fragment.  After any emit or fetch function is called, the
 * fragment is filled to the next multiple of 'alignment'.
 */

void iz_frag(Frag *, ptrdiff_t alignmnet);

void clr_frag(Frag *);

/* Generate byte offset you need to add to p so that
 * it is an exact multiple of size (which is a power of 2).
 */

#define align_o(p, size) (((size) - 1) & -(ptrdiff_t)(p))

/* Align frag to next multiple of n */

void align_frag(Frag *f, ptrdiff_t n);

/* Append data to a fragment: return byte offset to data.
 * These do two alignments: one before and one after the emit.  Before,
 * it fills the fragment until its size is a multiple of the size of
 * the emitted data.  After the emit, it fills the fragment until its
 * size is a multiple of the natural alignment specified in iz_frag.
 */


ptrdiff_t emitb_noalign(Frag *f, char c);
ptrdiff_t emitb(Frag *f, char c);
ptrdiff_t emith(Frag *f, short n);
ptrdiff_t emiti(Frag *f, int n);
ptrdiff_t emitd(Frag *f, double d);
ptrdiff_t emitp(Frag *f, void *p);
ptrdiff_t emits(Frag *f, unsigned char *s, int len);

ptrdiff_t emit_branch(Frag *f, ptrdiff_t target);
void fixup_branch(Frag *f, ptrdiff_t pos);
void frag_link(Frag *f, ptrdiff_t chain);

/* Access data in a fragment */

#define fragc(f, ofst) (*((f)->start + (ofst)))
#define fragh(f, ofst) (*(short *)((f)->start + (ofst)))
#define fragi(f, ofst) (*(int *)((f)->start + (ofst)))
#define fragd(f, ofst) (*(double *)((f)->start + (ofst)))
#define fragp(f, ofst) (*(void **)((f)->start + (ofst)))

/* Fetch an datum from a fragment and advance the "PC" */

int fetchi(Frag *f, ptrdiff_t *pc);
short fetchh(Frag *f, ptrdiff_t *pc);
void *fetchp(Frag *f, ptrdiff_t *pc);
void fin_code(Frag *f);
