/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifndef HYMN_H
#define HYMN_H
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#define HYMN_VERSION "0.11.0"
// #define HYMN_NO_REPL
// #define HYMN_NO_DYNAMIC_LIBS
// #define HYMN_NO_OPTIMIZE
// #define HYMN_NO_MEMORY
#ifdef _MSC_VER
#include <Windows.h>
#include <corecrt.h>
#include <direct.h>
#include <stdio.h>
#define getcwd _getcwd
#define PATH_MAX FILENAME_MAX
#define PATH_SEP '\\'
#define PATH_SEP_STRING "\\"
#define PATH_SEP_OTHER '/'
#define PATH_SEP_OTHER_STRING "/"
#define HYMN_DLIB_EXTENSION ".dll"
#define UNREACHABLE() __assume(0)
#define PACK(expr) __pragma(pack(push, 1)) expr __pragma(pack(pop))
#ifdef HYMN_NO_DYNAMIC_LIBS
#define export
#else
#define export __declspec(dllexport)
#endif
#else
#include <dirent.h>
#ifdef __APPLE__
#include <limits.h>
#else
#include <linux/limits.h>
#endif
#include <unistd.h>
#define PATH_SEP '/'
#define PATH_SEP_STRING "/"
#define PATH_SEP_OTHER '\\'
#define PATH_SEP_OTHER_STRING "\\"
#define HYMN_DLIB_EXTENSION ".so"
#define UNREACHABLE() __builtin_unreachable()
#define PACK(expr) expr __attribute__((__packed__))
#define export
#endif
#define HYMN_UINT8_COUNT (UINT8_MAX + 1)
#define HYMN_FRAMES_MAX 64
#define HYMN_STACK_MAX (HYMN_FRAMES_MAX * HYMN_UINT8_COUNT)
#define hymn_string_head(string) ((HymnStringHead *)((char *)string - sizeof(HymnStringHead)))
#define hymn_string_len(string) (hymn_string_head(string)->length)
#define hymn_string_equal(a, b) (strcmp(a, b) == 0)
typedef long long HymnInt;
typedef double HymnFloat;
enum HymnValueType {
HYMN_VALUE_UNDEFINED,
HYMN_VALUE_NONE,
HYMN_VALUE_BOOL,
HYMN_VALUE_INTEGER,
HYMN_VALUE_FLOAT,
HYMN_VALUE_STRING,
HYMN_VALUE_ARRAY,
HYMN_VALUE_TABLE,
HYMN_VALUE_FUNC,
HYMN_VALUE_FUNC_NATIVE,
HYMN_VALUE_POINTER,
};
typedef char HymnString;
typedef struct HymnStringHead HymnStringHead;
PACK(struct HymnStringHead {
size_t length;
size_t capacity;
char **chars;
});
#undef PACK
export void *hymn_malloc(size_t size);
export void *hymn_calloc(size_t count, size_t size);
export void *hymn_realloc(void *mem, size_t size);
export void *hymn_malloc_int(int count, size_t size);
export void *hymn_calloc_int(int count, size_t size);
export void *hymn_realloc_int(void *mem, int count, size_t size);
export FILE *hymn_open_file(const char *path, const char *mode);
typedef struct HymnValue HymnValue;
typedef struct HymnObjectString HymnObjectString;
typedef struct HymnArray HymnArray;
typedef struct HymnTable HymnTable;
typedef struct HymnTableItem HymnTableItem;
typedef struct HymnSet HymnSet;
typedef struct HymnSetItem HymnSetItem;
typedef struct HymnExceptList HymnExceptList;
typedef struct HymnFunction HymnFunction;
typedef struct HymnNativeFunction HymnNativeFunction;
typedef struct HymnFrame HymnFrame;
typedef struct HymnValuePool HymnValuePool;
typedef struct HymnByteCode HymnByteCode;
typedef struct Hymn Hymn;
typedef struct HymnValue (*HymnNativeCall)(Hymn *H, int count, HymnValue *arguments);
struct HymnValue {
union {
bool b;
HymnInt i;
HymnFloat f;
void *o;
void *p;
} as;
enum HymnValueType is;
char padding[4];
};
struct HymnObjectString {
int count;
unsigned int hash;
HymnString *string;
};
struct HymnArray {
int count;
char padding[4];
HymnValue *items;
HymnInt length;
HymnInt capacity;
};
struct HymnTableItem {
HymnObjectString *key;
HymnValue value;
HymnTableItem *next;
};
struct HymnTable {
int count;
int size;
unsigned int bins;
char padding[4];
HymnTableItem **items;
};
struct HymnSetItem {
HymnObjectString *string;
HymnSetItem *next;
};
struct HymnSet {
int size;
unsigned int bins;
HymnSetItem **items;
};
struct HymnNativeFunction {
int count;
char padding[4];
HymnObjectString *name;
HymnNativeCall func;
};
struct HymnValuePool {
int count;
int capacity;
HymnValue *values;
};
struct HymnByteCode {
int count;
int capacity;
uint8_t *instructions;
int *lines;
HymnValuePool constants;
};
struct HymnExceptList {
int start;
int end;
int locals;
char padding[4];
struct HymnExceptList *next;
};
struct HymnFunction {
int count;
int arity;
HymnString *name;
HymnString *script;
HymnString *source;
HymnExceptList *except;
HymnFunction *parent;
HymnByteCode code;
};
struct HymnFrame {
HymnFunction *func;
uint8_t *ip;
HymnValue *stack;
};
#ifndef HYMN_NO_DYNAMIC_LIBS
typedef struct HymnLibList HymnLibList;
struct HymnLibList {
void *lib;
HymnLibList *next;
};
#endif
struct Hymn {
HymnValue stack[HYMN_STACK_MAX];
HymnValue *stack_top;
HymnFrame frames[HYMN_FRAMES_MAX];
int frame_count;
char padding[4];
HymnSet strings;
HymnTable globals;
HymnArray *paths;
HymnTable *imports;
HymnString *error;
HymnString *exception;
#ifndef HYMN_NO_DYNAMIC_LIBS
HymnLibList *libraries;
#endif
void (*print)(const char *format, ...);
void (*print_error)(const char *format, ...);
};
export HymnString *hymn_working_directory(void);
export HymnString *hymn_path_convert(HymnString *path);
export HymnString *hymn_path_normalize(HymnString *path);
export HymnString *hymn_path_parent(HymnString *path);
export HymnString *hymn_path_absolute(HymnString *path);
export size_t hymn_file_size(const char *path);
export HymnString *hymn_read_file(const char *path);
export bool hymn_file_exists(const char *path);
export HymnString *hymn_new_string_with_capacity(size_t capacity);
export HymnString *hymn_new_string_with_length(const char *init, size_t length);
export HymnString *hymn_new_empty_string(size_t length);
export HymnString *hymn_new_string(const char *init);
export HymnObjectString *hymn_intern_string(Hymn *H, HymnString *string);
export HymnObjectString *hymn_new_intern_string(Hymn *H, const char *value);
export HymnString *hymn_string_copy(HymnString *string);
export void hymn_string_delete(HymnString *string);
export void hymn_string_zero(HymnString *string);
export HymnString *hymn_string_append_char(HymnString *string, const char b);
export HymnString *hymn_string_append_substring(HymnString *string, const char *b, size_t start, size_t end);
export bool hymn_string_starts_with(HymnString *s, const char *start);
export HymnString *hymn_string_replace(HymnString *string, const char *find, const char *replace);
export HymnString *hymn_string_append(HymnString *string, const char *b);
export HymnString *hymn_string_format(const char *format, ...);
export HymnString *hymn_substring(const char *init, size_t start, size_t end);
export void hymn_string_trim(HymnString *string);
export HymnString *hymn_quote_string(HymnString *string);
export HymnString *hymn_int_to_string(HymnInt number);
export HymnString *hymn_float_to_string(HymnFloat number);
export HymnArray *hymn_new_array(HymnInt length);
export void hymn_array_push(HymnArray *array, HymnValue value);
export void hymn_array_insert(HymnArray *array, HymnInt index, HymnValue value);
export HymnValue hymn_array_get(HymnArray *array, HymnInt index);
export HymnInt hymn_array_index_of(HymnArray *array, HymnValue match);
export HymnValue hymn_array_pop(HymnArray *array);
export HymnValue hymn_array_remove_index(HymnArray *array, HymnInt index);
export void hymn_array_clear(Hymn *H, HymnArray *array);
export void hymn_array_delete(Hymn *H, HymnArray *array);
export HymnTable *hymn_new_table(void);
export HymnValue hymn_table_get(HymnTable *table, const char *key);
export HymnValue hymn_new_undefined(void);
export HymnValue hymn_new_none(void);
export HymnValue hymn_new_bool(bool v);
export HymnValue hymn_new_int(HymnInt v);
export HymnValue hymn_new_float(HymnFloat v);
export HymnValue hymn_new_native(HymnNativeFunction *v);
export HymnValue hymn_new_pointer(void *v);
export HymnValue hymn_new_string_value(HymnObjectString *v);
export HymnValue hymn_new_array_value(HymnArray *v);
export HymnValue hymn_new_table_value(HymnTable *v);
export HymnValue hymn_new_func_value(HymnFunction *v);
export HymnObjectString *hymn_new_string_object(HymnString *string);
export HymnString *hymn_value_to_string(HymnValue value);
export bool hymn_as_bool(HymnValue v);
export HymnInt hymn_as_int(HymnValue v);
export HymnFloat hymn_as_float(HymnValue v);
export HymnNativeFunction *hymn_as_native(HymnValue v);
export void *hymn_as_pointer(HymnValue v);
export void *hymn_as_object(HymnValue v);
export HymnObjectString *hymn_as_hymn_string(HymnValue v);
export HymnString *hymn_as_string(HymnValue v);
export HymnArray *hymn_as_array(HymnValue v);
export HymnTable *hymn_as_table(HymnValue v);
export HymnFunction *hymn_as_func(HymnValue v);
export bool hymn_is_undefined(HymnValue v);
export bool hymn_is_none(HymnValue v);
export bool hymn_is_bool(HymnValue v);
export bool hymn_is_int(HymnValue v);
export bool hymn_is_float(HymnValue v);
export bool hymn_is_native(HymnValue v);
export bool hymn_is_pointer(HymnValue v);
export bool hymn_is_string(HymnValue v);
export bool hymn_is_array(HymnValue v);
export bool hymn_is_table(HymnValue v);
export bool hymn_is_func(HymnValue v);
export bool hymn_value_false(HymnValue value);
export bool hymn_values_equal(HymnValue a, HymnValue b);
export bool hymn_match_values(HymnValue a, HymnValue b);
export const char *hymn_value_type(enum HymnValueType type);
export void hymn_reference_string(HymnObjectString *string);
export void hymn_reference(HymnValue value);
export void hymn_dereference_string(Hymn *H, HymnObjectString *string);
export void hymn_dereference(Hymn *H, HymnValue value);
export void hymn_set_property(Hymn *H, HymnTable *table, HymnObjectString *name, HymnValue value);
export void hymn_set_property_const(Hymn *H, HymnTable *table, const char *name, HymnValue value);
export HymnValue hymn_new_exception(Hymn *H, const char *error);
export HymnValue hymn_arity_exception(Hymn *H, int expected, int actual);
export HymnValue hymn_type_exception(Hymn *H, enum HymnValueType expected, enum HymnValueType actual);
export Hymn *new_hymn(void);
export char *hymn_call(Hymn *H, const char *name, int arguments);
export char *hymn_debug(Hymn *H, const char *script, const char *source);
export char *hymn_run(Hymn *H, const char *script, const char *source);
export char *hymn_do(Hymn *H, const char *source);
export char *hymn_direct(Hymn *H, const char *source);
export char *hymn_script(Hymn *H, const char *script);
export HymnValue hymn_get(Hymn *H, const char *name);
export void hymn_add(Hymn *H, const char *name, HymnValue value);
export void hymn_add_string(Hymn *H, const char *name, const char *string);
export void hymn_add_table(Hymn *H, const char *name, HymnTable *table);
export void hymn_add_pointer(Hymn *H, const char *name, void *pointer);
export void hymn_add_string_to_table(Hymn *H, HymnTable *table, const char *name, const char *string);
export void hymn_add_function_to_table(Hymn *H, HymnTable *table, const char *name, HymnNativeCall func);
export void hymn_add_function(Hymn *H, const char *name, HymnNativeCall func);
export void hymn_delete(Hymn *H);
#ifndef HYMN_NO_REPL
export void hymn_repl(Hymn *H);
#endif
#ifndef HYMN_NO_DYNAMIC_LIBS
export void hymn_add_dlib(Hymn *H, void *library);
export void hymn_close_dlib(void *library);
export HymnString *hymn_use_dlib(Hymn *hymn, const char *path, const char *func);
#endif
export char *hymn_format(HymnString *source);
#endif