Pairs are 2-tuples of values that are constructed and matched with the `::`
operator. They can also be matched with a `:` operator, the LHS is an
expression then, the pair will then only match, if the LHS matches the
result of that expression.
Pairs should be useful to do something similar what sum types / tagged
unions do in statically typed languages, e.g. you could write something
like:
some := (symbol) # Somthing that creates a unique value
filter-map := {
_ [] -> []
f [x ~xs] ->
{
some:y -> [y ~(filter-map f xs)]
nil -> filter-map f xs
} (f x)
}
filter-map {
x?even -> some :: (* x 10)
_ -> nil
} some-list
125 lines
4.5 KiB
C
125 lines
4.5 KiB
C
#ifndef APFL_BYTECODE_H
|
|
#define APFL_BYTECODE_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include "apfl.h"
|
|
|
|
#include "gc.h"
|
|
|
|
enum matcher_instruction {
|
|
MATCHER_IGNORE,
|
|
MATCHER_CAPTURE_TO_VAR, // with name
|
|
MATCHER_CAPTURE_TO_VAR_LOCAL, // with name
|
|
MATCHER_CAPTURE_TO_VAR_WITH_PATH, // with name, index and len
|
|
MATCHER_CAPTURE_TO_VAR_LOCAL_WITH_PATH, // with name, index and len
|
|
MATCHER_CHECK_CONST, // with index as values index
|
|
MATCHER_CHECK_PRED, // with index as values index
|
|
MATCHER_ENTER_LIST,
|
|
MATCHER_LEAVE_LIST,
|
|
MATCHER_CONTINUE_FROM_END,
|
|
MATCHER_REMAINDING,
|
|
MATCHER_UNPACK_PAIR,
|
|
};
|
|
|
|
union matcher_instruction_or_arg {
|
|
enum matcher_instruction instruction;
|
|
size_t index;
|
|
size_t len;
|
|
struct apfl_string *string;
|
|
};
|
|
|
|
struct matcher_instruction_list {
|
|
union matcher_instruction_or_arg *instructions;
|
|
size_t len;
|
|
size_t cap;
|
|
size_t value_count;
|
|
size_t capture_count;
|
|
};
|
|
|
|
enum instruction {
|
|
INSN_NIL, // ( -- nil)
|
|
INSN_TRUE, // ( -- true)
|
|
INSN_FALSE, // ( -- false)
|
|
INSN_NUMBER, // ( -- number), arg: number
|
|
INSN_STRING, // ( -- string), arg: string
|
|
INSN_LIST, // ( -- list), arg: count (preallocation hint)
|
|
INSN_LIST_APPEND, // ( list val -- list' )
|
|
INSN_LIST_EXPAND_INTO, // ( list list -- list' )
|
|
INSN_DICT, // ( -- dict )
|
|
INSN_DICT_APPEND_KVPAIR, // ( dict key value -- dict' )
|
|
INSN_GET_MEMBER, // ( list/dict key -- value )
|
|
INSN_GET_BY_INDEX_KEEP, // ( list/dict -- list/dict value ), arg: index
|
|
INSN_VAR_GET, // ( -- value ), arg: string
|
|
INSN_VAR_SET, // ( value -- value ), arg: string
|
|
INSN_VAR_SET_LOCAL, // ( value -- value ), arg: string
|
|
INSN_VAR_NEW, // ( -- ), arg: string
|
|
INSN_VAR_NEW_LOCAL, // ( -- ), arg: string
|
|
INSN_MOVE_TO_LOCAL_VAR, // ( value -- ), arg: string
|
|
INSN_NEXT_LINE, // ( -- )
|
|
INSN_SET_LINE, // ( -- ), arg: count (new line number)
|
|
INSN_DROP, // ( value -- )
|
|
INSN_DUP, // ( value -- value value)
|
|
INSN_CALL, // ( func list -- value )
|
|
INSN_FUNC, // ( -- func ), arg: count
|
|
INSN_FUNC_ADD_SUBFUNC, // ( func -- func' ), arg: body; pops a matcher from the matcher stack
|
|
INSN_FUNC_ADD_SUBFUNC_ANYARGS, // ( func -- func' ), arg: body
|
|
INSN_FUNC_SET_NAME, // ( func -- func' ), arg: string
|
|
INSN_MATCHER_PUSH, // ( -- ), arg: matcher; pushes a matcher onto the matcher stack
|
|
INSN_MATCHER_SET_VAL, // ( val -- ), arg: index
|
|
INSN_MATCHER_MUST_MATCH, // ( val -- ); pops a matcher from the matcher stack
|
|
INSN_BUILD_PAIR, // ( val val -- pair )
|
|
};
|
|
|
|
union instruction_or_arg {
|
|
enum instruction instruction;
|
|
struct apfl_string *string;
|
|
apfl_number number;
|
|
size_t count;
|
|
size_t index;
|
|
struct instruction_list *body;
|
|
struct matcher_instruction_list *matcher;
|
|
};
|
|
|
|
struct instruction_list {
|
|
union instruction_or_arg *instructions;
|
|
size_t len;
|
|
size_t cap;
|
|
|
|
size_t line;
|
|
struct apfl_string *filename;
|
|
};
|
|
|
|
const char *apfl_instruction_to_string(enum instruction);
|
|
const char *apfl_matcher_instruction_to_string(enum matcher_instruction);
|
|
|
|
struct instruction_list *apfl_instructions_new(struct gc *, size_t line, struct apfl_string *filename);
|
|
void apfl_instructions_deinit(struct apfl_allocator, struct instruction_list *);
|
|
|
|
void apfl_gc_instructions_traverse(struct instruction_list *, gc_visitor, void *);
|
|
void apfl_gc_matcher_instructions_traverse(struct matcher_instruction_list *, gc_visitor, void *);
|
|
|
|
struct matcher_instruction_list *apfl_matcher_instructions_new(struct gc *);
|
|
void apfl_matcher_instructions_deinit(struct apfl_allocator, struct matcher_instruction_list *);
|
|
|
|
bool apfl_bytecode_dump_matcher(unsigned indent, struct apfl_io_writer w, struct matcher_instruction_list *milist);
|
|
bool apfl_bytecode_dump(unsigned indent, struct apfl_io_writer w, struct instruction_list *ilist);
|
|
|
|
bool apfl_bytecode_serialize(
|
|
struct apfl_allocator,
|
|
struct apfl_io_writer,
|
|
struct instruction_list *
|
|
);
|
|
|
|
struct instruction_list *apfl_bytecode_unserialize(
|
|
struct gc *gc,
|
|
struct apfl_io_reader r
|
|
);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|