Finally some consistent styling.
Centralized printf/printd defines in object.h Removed null/isList checking from FOR_POINTER_IN_LIST
This commit is contained in:
parent
8d22bf575c
commit
e2c977e95a
197
src/calc.c
197
src/calc.c
|
@ -7,18 +7,18 @@
|
||||||
#include "calc.h"
|
#include "calc.h"
|
||||||
|
|
||||||
// Custom layers that users can build
|
// Custom layers that users can build
|
||||||
Window *s_custom_window;
|
Window* s_custom_window;
|
||||||
TextLayer *s_heading_text_layer;
|
TextLayer* s_heading_text_layer;
|
||||||
char header[30] = "";
|
char header[30] = "";
|
||||||
|
|
||||||
// Code display
|
// Code display
|
||||||
Window *s_code_window;
|
Window* s_code_window;
|
||||||
TextLayer *s_input_text_layer;
|
TextLayer* s_input_text_layer;
|
||||||
TextLayer *s_result_text_layer;
|
TextLayer* s_result_text_layer;
|
||||||
|
|
||||||
// Script selection
|
// Script selection
|
||||||
Window *s_script_menu_window;
|
Window* s_script_menu_window;
|
||||||
MenuLayer *s_script_select_layer;
|
MenuLayer* s_script_select_layer;
|
||||||
int current_script_num;
|
int current_script_num;
|
||||||
|
|
||||||
// PebbLisp environment
|
// PebbLisp environment
|
||||||
|
@ -32,12 +32,12 @@ int excess_chars = 1;
|
||||||
#define RESULT_PREFIX "R:"
|
#define RESULT_PREFIX "R:"
|
||||||
char result_text[RESULT_LENGTH] = RESULT_PREFIX;
|
char result_text[RESULT_LENGTH] = RESULT_PREFIX;
|
||||||
|
|
||||||
const char *tokens[] = {
|
const char* tokens[] = {
|
||||||
" ", "(", ")",
|
" ", "(", ")",
|
||||||
"+ ", "- ", "* ", "/ ",
|
"+ ", "- ", "* ", "/ ",
|
||||||
"1","2","3",
|
"1", "2", "3",
|
||||||
"4","5","6",
|
"4", "5", "6",
|
||||||
"7","8","9", "0", "x",
|
"7", "8", "9", "0", "x",
|
||||||
"a", "b", "c", "d", "e",
|
"a", "b", "c", "d", "e",
|
||||||
"= ", "< ", "> ",
|
"= ", "< ", "> ",
|
||||||
"\"",
|
"\"",
|
||||||
|
@ -51,7 +51,7 @@ const char *tokens[] = {
|
||||||
// Currently selected button, starts on '('
|
// Currently selected button, starts on '('
|
||||||
static int8_t selected_token = 1;
|
static int8_t selected_token = 1;
|
||||||
|
|
||||||
const char *func_tokens[] = {
|
const char* func_tokens[] = {
|
||||||
"window ",
|
"window ",
|
||||||
"sc ", "cw ", "pw ", "rw ", "atl ", "utl ",
|
"sc ", "cw ", "pw ", "rw ", "atl ", "utl ",
|
||||||
"sec ", "mnt ", "hr ", "hrt ", "vibe ", "sub "
|
"sec ", "mnt ", "hr ", "hrt ", "vibe ", "sub "
|
||||||
|
@ -68,7 +68,7 @@ const uint32_t outbox_size = 1024;
|
||||||
// Get the number of tokens in the current list
|
// Get the number of tokens in the current list
|
||||||
static inline int8_t tokenCount()
|
static inline int8_t tokenCount()
|
||||||
{
|
{
|
||||||
return using_func_tokens?
|
return using_func_tokens ?
|
||||||
sizeof(func_tokens) / sizeof(func_tokens[0]) :
|
sizeof(func_tokens) / sizeof(func_tokens[0]) :
|
||||||
sizeof(tokens) / sizeof(tokens[0]);
|
sizeof(tokens) / sizeof(tokens[0]);
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ static inline int8_t tokenCount()
|
||||||
static inline const char* getToken(int8_t n)
|
static inline const char* getToken(int8_t n)
|
||||||
{
|
{
|
||||||
int8_t t = n % tokenCount();
|
int8_t t = n % tokenCount();
|
||||||
return using_func_tokens? func_tokens[t] : tokens[t];
|
return using_func_tokens ? func_tokens[t] : tokens[t];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void trim(size_t len)
|
static void trim(size_t len)
|
||||||
|
@ -93,11 +93,11 @@ static void trim(size_t len)
|
||||||
static void updateText()
|
static void updateText()
|
||||||
{
|
{
|
||||||
trim(excess_chars);
|
trim(excess_chars);
|
||||||
const char *token = getToken(selected_token);
|
const char* token = getToken(selected_token);
|
||||||
|
|
||||||
const char* add =
|
const char* add =
|
||||||
token[0] == ' ' ? "_": // Display space as underscore
|
token[0] == ' ' ? "_" : // Display space as underscore
|
||||||
token[0] == '\n'? "\\n": // Display newline as \n
|
token[0] == '\n' ? "\\n" : // Display newline as \n
|
||||||
token; // Display others literally
|
token; // Display others literally
|
||||||
|
|
||||||
strcat(displayed_code, add);
|
strcat(displayed_code, add);
|
||||||
|
@ -107,19 +107,19 @@ static void updateText()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cycle through the current list of tokens
|
// Cycle through the current list of tokens
|
||||||
static void cycle_tokens(ClickRecognizerRef recognizer, void *context)
|
static void cycle_tokens(ClickRecognizerRef recognizer, void* context)
|
||||||
{
|
{
|
||||||
// Change current token
|
// Change current token
|
||||||
if(click_recognizer_get_button_id(recognizer) == BUTTON_ID_DOWN) {
|
if (click_recognizer_get_button_id(recognizer) == BUTTON_ID_DOWN) {
|
||||||
selected_token++;
|
selected_token++;
|
||||||
} else {
|
} else {
|
||||||
selected_token--;
|
selected_token--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If selected token is outside of range, wrap around
|
// If selected token is outside of range, wrap around
|
||||||
if(selected_token < 0) {
|
if (selected_token < 0) {
|
||||||
selected_token = tokenCount() - 1;
|
selected_token = tokenCount() - 1;
|
||||||
} else if(selected_token >= tokenCount()) {
|
} else if (selected_token >= tokenCount()) {
|
||||||
selected_token = 0;
|
selected_token = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ static void cycle_tokens(ClickRecognizerRef recognizer, void *context)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GFont tiny_font;
|
static GFont tiny_font;
|
||||||
static const char *fonts[] = {
|
static const char* fonts[] = {
|
||||||
FONT_KEY_GOTHIC_28_BOLD,
|
FONT_KEY_GOTHIC_28_BOLD,
|
||||||
FONT_KEY_GOTHIC_24_BOLD,
|
FONT_KEY_GOTHIC_24_BOLD,
|
||||||
FONT_KEY_GOTHIC_18_BOLD,
|
FONT_KEY_GOTHIC_18_BOLD,
|
||||||
|
@ -140,26 +140,28 @@ static void adjustFont()
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
while(displayed_code[i++]) {
|
while (displayed_code[i++]) {
|
||||||
if(displayed_code[i] == '\n')
|
if (displayed_code[i] == '\n') {
|
||||||
size += 10;
|
size += 10;
|
||||||
|
}
|
||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
// Use various system fonts for most text
|
// Use various system fonts for most text
|
||||||
if(size <= 100) {
|
if (size <= 100) {
|
||||||
int f = size < 50 ? smallestFont - 3 :
|
const char* f = fonts[
|
||||||
|
size < 50 ? smallestFont - 3 :
|
||||||
size < 80 ? smallestFont - 2 :
|
size < 80 ? smallestFont - 2 :
|
||||||
size < 100 ? smallestFont - 1 :
|
size < 100 ? smallestFont - 1 :
|
||||||
smallestFont;
|
smallestFont
|
||||||
text_layer_set_font(s_input_text_layer,
|
];
|
||||||
fonts_get_system_font(fonts[f]));
|
text_layer_set_font(s_input_text_layer, fonts_get_system_font(f));
|
||||||
} else {
|
} else {
|
||||||
// Use custom extra small font for lots of text
|
// Use custom extra small font for lots of text
|
||||||
text_layer_set_font(s_input_text_layer, tiny_font);
|
text_layer_set_font(s_input_text_layer, tiny_font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void custom_unload(Window *window)
|
static void custom_unload(Window* window)
|
||||||
{
|
{
|
||||||
text_layer_destroy(s_heading_text_layer);
|
text_layer_destroy(s_heading_text_layer);
|
||||||
|
|
||||||
|
@ -171,15 +173,15 @@ static void custom_unload(Window *window)
|
||||||
* In normal token list, backspace if possible, otherwise return to script list
|
* In normal token list, backspace if possible, otherwise return to script list
|
||||||
* In function token list, return to normal token list
|
* In function token list, return to normal token list
|
||||||
*/
|
*/
|
||||||
static void click_backspace(ClickRecognizerRef recognizer, void *context)
|
static void click_backspace(ClickRecognizerRef recognizer, void* context)
|
||||||
{
|
{
|
||||||
if(s_custom_window) {
|
if (s_custom_window) {
|
||||||
window_stack_remove(s_custom_window, true);
|
window_stack_remove(s_custom_window, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!using_func_tokens) {
|
if (!using_func_tokens) {
|
||||||
if(displayed_code[0] == '\0') {
|
if (displayed_code[0] == '\0') {
|
||||||
window_stack_remove(window_stack_get_top_window(), true);
|
window_stack_remove(window_stack_get_top_window(), true);
|
||||||
} else {
|
} else {
|
||||||
trim(excess_chars + 1);
|
trim(excess_chars + 1);
|
||||||
|
@ -198,7 +200,7 @@ static void add_token()
|
||||||
{
|
{
|
||||||
strcat(displayed_code, getToken(selected_token));
|
strcat(displayed_code, getToken(selected_token));
|
||||||
selected_token = 0;
|
selected_token = 0;
|
||||||
if(using_func_tokens) {
|
if (using_func_tokens) {
|
||||||
using_func_tokens = false;
|
using_func_tokens = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,21 +221,23 @@ static void calculate()
|
||||||
updateText();
|
updateText();
|
||||||
|
|
||||||
stringNObj(temp, &obj, RESULT_LENGTH);
|
stringNObj(temp, &obj, RESULT_LENGTH);
|
||||||
if(obj.type == TYPE_ERROR) {
|
if (obj.type == TYPE_ERROR) {
|
||||||
text_layer_set_font(s_result_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD));
|
text_layer_set_font(s_result_text_layer,
|
||||||
|
fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD));
|
||||||
} else {
|
} else {
|
||||||
text_layer_set_font(s_result_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
|
text_layer_set_font(s_result_text_layer,
|
||||||
|
fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
|
||||||
}
|
}
|
||||||
snprintf(result_text, RESULT_LENGTH, RESULT_PREFIX "%s", temp);
|
snprintf(result_text, RESULT_LENGTH, RESULT_PREFIX "%s", temp);
|
||||||
text_layer_set_text(s_result_text_layer, result_text);
|
text_layer_set_text(s_result_text_layer, result_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Button press handler
|
// Button press handler
|
||||||
static void click_select(ClickRecognizerRef recognizer, void *context)
|
static void click_select(ClickRecognizerRef recognizer, void* context)
|
||||||
{
|
{
|
||||||
if(!using_func_tokens && selected_token == tokenCount() - 1) {
|
if (!using_func_tokens && selected_token == tokenCount() - 1) {
|
||||||
calculate();
|
calculate();
|
||||||
} else if(!using_func_tokens && selected_token == tokenCount() - 2) {
|
} else if (!using_func_tokens && selected_token == tokenCount() - 2) {
|
||||||
using_func_tokens = true;
|
using_func_tokens = true;
|
||||||
selected_token = 0;
|
selected_token = 0;
|
||||||
updateText();
|
updateText();
|
||||||
|
@ -243,13 +247,13 @@ static void click_select(ClickRecognizerRef recognizer, void *context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saves text in editor to persistent storage
|
// Saves text in editor to persistent storage
|
||||||
static void click_save(ClickRecognizerRef recognizer, void *context)
|
static void click_save(ClickRecognizerRef recognizer, void* context)
|
||||||
{
|
{
|
||||||
int8_t i = strlen(displayed_code);
|
int8_t i = strlen(displayed_code);
|
||||||
unsigned token_len = strlen(getToken(selected_token));
|
unsigned token_len = strlen(getToken(selected_token));
|
||||||
printf("%s", displayed_code);
|
printf("%s", displayed_code);
|
||||||
for(unsigned j = 0; j < token_len; j++) {
|
for (unsigned j = 0; j < token_len; j++) {
|
||||||
displayed_code[i-(1 + j)] = '\0';
|
displayed_code[i - (1 + j)] = '\0';
|
||||||
printf("%s", displayed_code);
|
printf("%s", displayed_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +262,7 @@ static void click_save(ClickRecognizerRef recognizer, void *context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the code_window click functions
|
// Sets the code_window click functions
|
||||||
static void code_click_subscribe(void *context)
|
static void code_click_subscribe(void* context)
|
||||||
{
|
{
|
||||||
window_single_repeating_click_subscribe(BUTTON_ID_UP, 100, cycle_tokens);
|
window_single_repeating_click_subscribe(BUTTON_ID_UP, 100, cycle_tokens);
|
||||||
window_single_repeating_click_subscribe(BUTTON_ID_DOWN, 100, cycle_tokens);
|
window_single_repeating_click_subscribe(BUTTON_ID_DOWN, 100, cycle_tokens);
|
||||||
|
@ -268,13 +272,13 @@ static void code_click_subscribe(void *context)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOW_MEM
|
#ifdef LOW_MEM
|
||||||
#define TIME_FUNC \
|
#define TIME_FUNC \
|
||||||
"(def time (fn ()(utl tt \n"\
|
"(def time (fn ()(utl tt \n"\
|
||||||
" (cat \"Hey, it's \" \n"\
|
" (cat \"Hey, it's \" \n"\
|
||||||
" (hrt) \":\" (mnt)\n" \
|
" (hrt) \":\" (mnt)\n" \
|
||||||
"))))\n"
|
"))))\n"
|
||||||
#else
|
#else
|
||||||
#define TIME_FUNC \
|
#define TIME_FUNC \
|
||||||
"(def time (fn () ((def m (mnt)) (utl tt \n"\
|
"(def time (fn () ((def m (mnt)) (utl tt \n"\
|
||||||
" (cat \"Hey, it's \"\n"\
|
" (cat \"Hey, it's \"\n"\
|
||||||
" (hrt) \":\" (if (< m 10) \"0\" \"\") m)\n"\
|
" (hrt) \":\" (if (< m 10) \"0\" \"\") m)\n"\
|
||||||
|
@ -290,9 +294,9 @@ static void code_click_subscribe(void *context)
|
||||||
// Remove to re-enable
|
// Remove to re-enable
|
||||||
#undef FORCE_TEXT
|
#undef FORCE_TEXT
|
||||||
|
|
||||||
static void code_window_load(Window *window)
|
static void code_window_load(Window* window)
|
||||||
{
|
{
|
||||||
Layer *window_layer = window_get_root_layer(window);
|
Layer* window_layer = window_get_root_layer(window);
|
||||||
GRect bounds = layer_get_bounds(window_layer);
|
GRect bounds = layer_get_bounds(window_layer);
|
||||||
|
|
||||||
// Register click config provider
|
// Register click config provider
|
||||||
|
@ -301,44 +305,51 @@ static void code_window_load(Window *window)
|
||||||
// Input text layer setup
|
// Input text layer setup
|
||||||
s_input_text_layer = text_layer_create(bounds);
|
s_input_text_layer = text_layer_create(bounds);
|
||||||
text_layer_set_text(s_input_text_layer, getToken(1));
|
text_layer_set_text(s_input_text_layer, getToken(1));
|
||||||
text_layer_set_font(s_input_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD));
|
text_layer_set_font(s_input_text_layer,
|
||||||
layer_add_child(window_get_root_layer(s_code_window), text_layer_get_layer(s_input_text_layer));
|
fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD));
|
||||||
|
layer_add_child(window_get_root_layer(s_code_window),
|
||||||
|
text_layer_get_layer(s_input_text_layer));
|
||||||
|
|
||||||
// Result text layer setup
|
// Result text layer setup
|
||||||
GRect result_bounds = GRect(6, 148, 132, 132);
|
GRect result_bounds = GRect(6, 148, 132, 132);
|
||||||
s_result_text_layer = text_layer_create(result_bounds);
|
s_result_text_layer = text_layer_create(result_bounds);
|
||||||
text_layer_set_text(s_result_text_layer, result_text);
|
text_layer_set_text(s_result_text_layer, result_text);
|
||||||
text_layer_set_font(s_result_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
|
text_layer_set_font(s_result_text_layer,
|
||||||
|
fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
|
||||||
text_layer_set_text_alignment(s_result_text_layer, GTextAlignmentRight);
|
text_layer_set_text_alignment(s_result_text_layer, GTextAlignmentRight);
|
||||||
layer_add_child(window_get_root_layer(s_code_window), text_layer_get_layer(s_result_text_layer));
|
layer_add_child(window_get_root_layer(s_code_window),
|
||||||
|
text_layer_get_layer(s_result_text_layer));
|
||||||
|
|
||||||
// Push the window, setting the window animation to 'true'
|
// Push the window, setting the window animation to 'true'
|
||||||
window_stack_push(s_code_window, true);
|
window_stack_push(s_code_window, true);
|
||||||
|
|
||||||
// If possible, load the previous code text
|
// If possible, load the previous code text
|
||||||
#ifdef FORCE_TEXT
|
#ifdef FORCE_TEXT
|
||||||
strncpy(displayed_code, FORCE_TEXT, SMAX_LENGTH);
|
strncpy(displayed_code, FORCE_TEXT, SMAX_LENGTH);
|
||||||
updateText();
|
updateText();
|
||||||
adjustFont();
|
adjustFont();
|
||||||
#else
|
#else
|
||||||
if(persist_exists(current_script_num)) {
|
if (persist_exists(current_script_num)) {
|
||||||
persist_read_string(current_script_num, displayed_code, SMAX_LENGTH);
|
persist_read_string(current_script_num, displayed_code, SMAX_LENGTH);
|
||||||
updateText();
|
updateText();
|
||||||
adjustFont();
|
adjustFont();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug_result(const char* d) {
|
void debug_result(const char* d)
|
||||||
|
{
|
||||||
snprintf(result_text, RESULT_LENGTH, "%s", d);
|
snprintf(result_text, RESULT_LENGTH, "%s", d);
|
||||||
text_layer_set_text(s_result_text_layer, result_text);
|
text_layer_set_text(s_result_text_layer, result_text);
|
||||||
psleep(300);
|
psleep(300);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object run_script(Object script_num, Object obj, struct Environment *e) {
|
static Object run_script(Object script_num, Object obj,
|
||||||
|
struct Environment* e)
|
||||||
|
{
|
||||||
int n = script_num.number - 1;
|
int n = script_num.number - 1;
|
||||||
if(persist_exists(n)) {
|
if (persist_exists(n)) {
|
||||||
char *code = malloc(sizeof(char) * SMAX_LENGTH);
|
char* code = malloc(sizeof(char) * SMAX_LENGTH);
|
||||||
persist_read_string(n, code, SMAX_LENGTH);
|
persist_read_string(n, code, SMAX_LENGTH);
|
||||||
Object o = parseEval(code, e);
|
Object o = parseEval(code, e);
|
||||||
free(code);
|
free(code);
|
||||||
|
@ -347,7 +358,7 @@ static Object run_script(Object script_num, Object obj, struct Environment *e) {
|
||||||
return errorObject(SCRIPT_NOT_FOUND);
|
return errorObject(SCRIPT_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void code_window_unload(Window *window)
|
static void code_window_unload(Window* window)
|
||||||
{
|
{
|
||||||
// Save the current code text
|
// Save the current code text
|
||||||
persist_write_string(current_script_num, displayed_code);
|
persist_write_string(current_script_num, displayed_code);
|
||||||
|
@ -361,11 +372,11 @@ static void code_window_unload(Window *window)
|
||||||
|
|
||||||
void code_window_push()
|
void code_window_push()
|
||||||
{
|
{
|
||||||
if(!s_code_window) {
|
if (!s_code_window) {
|
||||||
s_code_window = window_create();
|
s_code_window = window_create();
|
||||||
WindowHandlers wh = {
|
WindowHandlers wh = {
|
||||||
.load = code_window_load,
|
.load = code_window_load,
|
||||||
.unload = code_window_unload };
|
.unload = code_window_unload};
|
||||||
window_set_window_handlers(s_code_window, wh);
|
window_set_window_handlers(s_code_window, wh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,47 +385,50 @@ void code_window_push()
|
||||||
|
|
||||||
/** Menu Window **/
|
/** Menu Window **/
|
||||||
|
|
||||||
static void select_callback(struct MenuLayer *menu_layer,
|
static void select_callback(MenuLayer* menu_layer, MenuIndex* cell_index,
|
||||||
MenuIndex *cell_index, void *context)
|
void* context)
|
||||||
{
|
{
|
||||||
current_script_num = cell_index->row;
|
current_script_num = cell_index->row;
|
||||||
code_window_push();
|
code_window_push();
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t get_num_rows_callback(MenuLayer *menu_layer,
|
static uint16_t get_num_rows_callback(MenuLayer* menu_layer,
|
||||||
uint16_t section_index, void *context)
|
uint16_t section_index, void* context)
|
||||||
{
|
{
|
||||||
return SCRIPT_COUNT;
|
return SCRIPT_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_row_callback(GContext *ctx, const Layer *cell_layer,
|
static void draw_row_callback(GContext* ctx, const Layer* cell_layer,
|
||||||
MenuIndex *cell_index, void *context)
|
MenuIndex* cell_index, void* context)
|
||||||
{
|
{
|
||||||
static char s_buff[16];
|
static char s_buff[16];
|
||||||
snprintf(s_buff, sizeof(s_buff), "Script %d", 1 + (int)cell_index->row);
|
snprintf(s_buff, sizeof(s_buff), "Script %d", 1 + (int) cell_index->row);
|
||||||
|
|
||||||
// Draw this row's index
|
// Draw this row's index
|
||||||
menu_cell_basic_draw(ctx, cell_layer, s_buff, NULL, NULL);
|
menu_cell_basic_draw(ctx, cell_layer, s_buff, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16_t get_cell_height_callback(struct MenuLayer *menu_layer,
|
static int16_t get_cell_height_callback(MenuLayer* menu_layer,
|
||||||
MenuIndex *cell_index, void *context)
|
MenuIndex* cell_index, void* context)
|
||||||
{
|
{
|
||||||
return CELL_HEIGHT;
|
return CELL_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void script_menu_load(Window *window)
|
static void script_menu_load(Window* window)
|
||||||
{
|
{
|
||||||
Layer *window_layer = window_get_root_layer(window);
|
Layer* window_layer = window_get_root_layer(window);
|
||||||
GRect bounds = layer_get_bounds(window_layer);
|
GRect bounds = layer_get_bounds(window_layer);
|
||||||
|
|
||||||
s_script_select_layer = menu_layer_create(bounds);
|
s_script_select_layer = menu_layer_create(bounds);
|
||||||
menu_layer_set_click_config_onto_window(s_script_select_layer, window);
|
menu_layer_set_click_config_onto_window(s_script_select_layer, window);
|
||||||
|
|
||||||
#if defined(PBL_COLOR)
|
#if defined(PBL_COLOR)
|
||||||
menu_layer_set_normal_colors(s_script_select_layer, GColorBlack, GColorWhite);
|
menu_layer_set_normal_colors(s_script_select_layer,
|
||||||
menu_layer_set_highlight_colors(s_script_select_layer, GColorDukeBlue, GColorWhite);
|
GColorBlack, GColorWhite);
|
||||||
#endif
|
|
||||||
|
menu_layer_set_highlight_colors(s_script_select_layer,
|
||||||
|
GColorDukeBlue, GColorWhite);
|
||||||
|
#endif
|
||||||
|
|
||||||
menu_layer_set_callbacks(s_script_select_layer, NULL, (MenuLayerCallbacks) {
|
menu_layer_set_callbacks(s_script_select_layer, NULL, (MenuLayerCallbacks) {
|
||||||
.get_num_rows = get_num_rows_callback,
|
.get_num_rows = get_num_rows_callback,
|
||||||
|
@ -422,19 +436,20 @@ static void script_menu_load(Window *window)
|
||||||
.get_cell_height = get_cell_height_callback,
|
.get_cell_height = get_cell_height_callback,
|
||||||
.select_click = select_callback,
|
.select_click = select_callback,
|
||||||
});
|
});
|
||||||
|
|
||||||
layer_add_child(window_layer, menu_layer_get_layer(s_script_select_layer));
|
layer_add_child(window_layer, menu_layer_get_layer(s_script_select_layer));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void script_menu_unload(Window *window)
|
static void script_menu_unload(Window* window)
|
||||||
{
|
{
|
||||||
menu_layer_destroy(s_script_select_layer);
|
menu_layer_destroy(s_script_select_layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Custom Window **/
|
/** Custom Window **/
|
||||||
|
|
||||||
static void custom_load(Window *window)
|
static void custom_load(Window* window)
|
||||||
{
|
{
|
||||||
Layer *window_layer = window_get_root_layer(window);
|
Layer* window_layer = window_get_root_layer(window);
|
||||||
GRect bounds = layer_get_bounds(window_layer);
|
GRect bounds = layer_get_bounds(window_layer);
|
||||||
|
|
||||||
// Register click config provider
|
// Register click config provider
|
||||||
|
@ -452,16 +467,17 @@ static void custom_load(Window *window)
|
||||||
window_stack_push(s_custom_window, true);
|
window_stack_push(s_custom_window, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object add_window(Object obj1, Object _, struct Environment *env)
|
Object add_window(Object obj1, Object _, struct Environment* env)
|
||||||
{
|
{
|
||||||
printf("ADD_WINDOW\n");
|
printf("ADD_WINDOW\n");
|
||||||
stringObj(header, &obj1);
|
stringObj(header, &obj1);
|
||||||
|
|
||||||
if(!s_custom_window) {
|
if (!s_custom_window) {
|
||||||
s_custom_window = window_create();
|
s_custom_window = window_create();
|
||||||
WindowHandlers wh = {
|
WindowHandlers wh = {
|
||||||
.load = custom_load,
|
.load = custom_load,
|
||||||
.unload = custom_unload };
|
.unload = custom_unload
|
||||||
|
};
|
||||||
window_set_window_handlers(s_custom_window, wh);
|
window_set_window_handlers(s_custom_window, wh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,14 +486,15 @@ Object add_window(Object obj1, Object _, struct Environment *env)
|
||||||
return numberObject(1);
|
return numberObject(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inbox_received_callback(DictionaryIterator *iter, void *context) {
|
static void inbox_received_callback(DictionaryIterator* iter, void* context)
|
||||||
Tuple *script_tuple = dict_find(iter, MESSAGE_KEY_ScriptText);
|
{
|
||||||
if(script_tuple) {
|
Tuple* script_tuple = dict_find(iter, MESSAGE_KEY_ScriptText);
|
||||||
if(!s_code_window) {
|
if (script_tuple) {
|
||||||
|
if (!s_code_window) {
|
||||||
current_script_num = 0;
|
current_script_num = 0;
|
||||||
code_window_push();
|
code_window_push();
|
||||||
}
|
}
|
||||||
char *script_text = script_tuple->value->cstring;
|
char* script_text = script_tuple->value->cstring;
|
||||||
snprintf(displayed_code, sizeof(displayed_code), "%s", script_text);
|
snprintf(displayed_code, sizeof(displayed_code), "%s", script_text);
|
||||||
updateText();
|
updateText();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,6 @@
|
||||||
|
|
||||||
#define SCRIPT_COUNT 5
|
#define SCRIPT_COUNT 5
|
||||||
|
|
||||||
void debug_result(const char *d);
|
void debug_result(const char* d);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
131
src/env.c
131
src/env.c
|
@ -1,21 +1,18 @@
|
||||||
#include "env.h"
|
#include "env.h"
|
||||||
#include "pebblisp.h"
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#ifndef STANDALONE
|
#include "pebblisp.h"
|
||||||
#include <pebble.h>
|
|
||||||
#undef printf
|
|
||||||
#define printf(...) APP_LOG(APP_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Object fetchFromEnvironment(const char *name, struct Environment *env)
|
Object fetchFromEnvironment(const char* name, struct Environment* env)
|
||||||
{
|
{
|
||||||
if(!env)
|
if (!env) {
|
||||||
return errorObject(NULL_ENV);
|
return errorObject(NULL_ENV);
|
||||||
|
}
|
||||||
|
|
||||||
if(env->size == 0) {
|
if (env->size == 0) {
|
||||||
if (env->outer) {
|
if (env->outer) {
|
||||||
return fetchFromEnvironment(name, env->outer);
|
return fetchFromEnvironment(name, env->outer);
|
||||||
} else {
|
} else {
|
||||||
|
@ -23,49 +20,48 @@ Object fetchFromEnvironment(const char *name, struct Environment *env)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < env->size; i++) {
|
for (int i = 0; i < env->size; i++) {
|
||||||
if(env->strings[i] == NULL) {
|
if (env->strings[i] == NULL) {
|
||||||
printd("Try %d (NULL)\n", i);
|
printd("Try %d (NULL)\n", i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printd("Try %d (%s)\n", i, env->strings[i]);
|
printd("Try %d (%s)\n", i, env->strings[i]);
|
||||||
debugObj(&env->objects[i]);
|
debugObj(&env->objects[i]);
|
||||||
if(strcmp(name, env->strings[i]) == 0) {
|
if (strcmp(name, env->strings[i]) == 0) {
|
||||||
printd("Returning!\n");
|
printd("Returning!\n");
|
||||||
return cloneObject(env->objects[i]);
|
return cloneObject(env->objects[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printd("Trying outer %p\n", env->outer);
|
printd("Trying outer %p\n", env->outer);
|
||||||
if(env->outer) {
|
if (env->outer) {
|
||||||
return fetchFromEnvironment(name, env->outer);
|
return fetchFromEnvironment(name, env->outer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorWithContext(DID_NOT_FIND_SYMBOL, name);
|
return errorWithContext(DID_NOT_FIND_SYMBOL, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Environment envForLambda(const Object *params, const Object *arg_forms,
|
struct Environment envForLambda(const Object* params, const Object* arg_forms,
|
||||||
struct Environment *outer)
|
struct Environment* outer)
|
||||||
{
|
{
|
||||||
int paramCount = listLength(params);
|
int paramCount = listLength(params);
|
||||||
|
|
||||||
struct Environment env = {
|
struct Environment env = {.outer = outer,
|
||||||
.outer = outer,
|
|
||||||
.strings = NULL,
|
.strings = NULL,
|
||||||
.objects = NULL,
|
.objects = NULL,
|
||||||
.size = paramCount
|
.size = paramCount};
|
||||||
};
|
|
||||||
|
|
||||||
if(paramCount == 0)
|
if (paramCount == 0) {
|
||||||
return env;
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
env.strings = calloc(sizeof(char*), paramCount + 1);
|
env.strings = calloc(sizeof(char*), paramCount + 1);
|
||||||
env.objects = malloc(sizeof(Object) * (paramCount + 1));
|
env.objects = malloc(sizeof(Object) * (paramCount + 1));
|
||||||
|
|
||||||
const Object *march = arg_forms;
|
const Object* march = arg_forms;
|
||||||
for(int i = 0; i < paramCount; i++) {
|
for (int i = 0; i < paramCount; i++) {
|
||||||
const char *newObjName = itemAt(params, i)->string;
|
const char* newObjName = itemAt(params, i)->string;
|
||||||
// Eval the `march` list
|
// Eval the `march` list
|
||||||
Object newEnvObj = eval(march, outer);
|
Object newEnvObj = eval(march, outer);
|
||||||
addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms?
|
addToEnv(&env, newObjName, newEnvObj); // Could use eval_forms?
|
||||||
|
@ -82,15 +78,15 @@ struct Environment envForLambda(const Object *params, const Object *arg_forms,
|
||||||
// symbol was found
|
// symbol was found
|
||||||
//
|
//
|
||||||
// Returns the index of the symbol in the environment, if found. Otherwise, -1
|
// Returns the index of the symbol in the environment, if found. Otherwise, -1
|
||||||
int findInEnv(struct Environment **env, const char *name)
|
int findInEnv(struct Environment** env, const char* name)
|
||||||
{
|
{
|
||||||
struct Environment *temp_env = *env;
|
struct Environment* temp_env = *env;
|
||||||
while(temp_env) {
|
while (temp_env) {
|
||||||
for(int i = 0; i < temp_env->size; i++) {
|
for (int i = 0; i < temp_env->size; i++) {
|
||||||
if(temp_env->strings[i] == NULL) {
|
if (temp_env->strings[i] == NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(strcmp(temp_env->strings[i], name) == 0) {
|
if (strcmp(temp_env->strings[i], name) == 0) {
|
||||||
*env = temp_env;
|
*env = temp_env;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +97,7 @@ int findInEnv(struct Environment **env, const char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Maybe extend environment using a new outer, instead of realloc
|
// TODO Maybe extend environment using a new outer, instead of realloc
|
||||||
void addToEnv(struct Environment *env, const char *name, const Object obj)
|
void addToEnv(struct Environment* env, const char* name, const Object obj)
|
||||||
{
|
{
|
||||||
// int sym_pos = findInEnv(&env, name);
|
// int sym_pos = findInEnv(&env, name);
|
||||||
// if(sym_pos != -1) {
|
// if(sym_pos != -1) {
|
||||||
|
@ -112,20 +108,21 @@ void addToEnv(struct Environment *env, const char *name, const Object obj)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
struct Environment *temp_env = env;
|
struct Environment* temp_env = env;
|
||||||
int is_local = 1;
|
int is_local = 1;
|
||||||
while(temp_env) {
|
while (temp_env) {
|
||||||
for(i = 0; i < temp_env->size; i++) {
|
for (i = 0; i < temp_env->size; i++) {
|
||||||
// Add *new* item to env only if we're in the local scope
|
// Add *new* item to env only if we're in the local scope
|
||||||
if(temp_env->strings[i] == NULL) {
|
if (temp_env->strings[i] == NULL) {
|
||||||
if (is_local) {
|
if (is_local) {
|
||||||
temp_env->strings[i] = calloc(sizeof(char), strlen(name) + 1);
|
temp_env->strings[i] =
|
||||||
|
calloc(sizeof(char), strlen(name) + 1);
|
||||||
strncpy(temp_env->strings[i], name, strlen(name));
|
strncpy(temp_env->strings[i], name, strlen(name));
|
||||||
temp_env->objects[i] = cloneObject(obj);
|
temp_env->objects[i] = cloneObject(obj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else if(strcmp(temp_env->strings[i], name) == 0) {
|
} else if (strcmp(temp_env->strings[i], name) == 0) {
|
||||||
Object o = cloneObject(obj);
|
Object o = cloneObject(obj);
|
||||||
cleanObject(&temp_env->objects[i]);
|
cleanObject(&temp_env->objects[i]);
|
||||||
temp_env->objects[i] = o;
|
temp_env->objects[i] = o;
|
||||||
|
@ -143,7 +140,7 @@ void addToEnv(struct Environment *env, const char *name, const Object obj)
|
||||||
env->strings = realloc(env->strings, sizeof(char*) * env->size);
|
env->strings = realloc(env->strings, sizeof(char*) * env->size);
|
||||||
env->objects = realloc(env->objects, sizeof(Object) * env->size);
|
env->objects = realloc(env->objects, sizeof(Object) * env->size);
|
||||||
|
|
||||||
for(int j = 0; j < inc; j++) {
|
for (int j = 0; j < inc; j++) {
|
||||||
env->strings[old_size + j] = NULL;
|
env->strings[old_size + j] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,14 +149,14 @@ void addToEnv(struct Environment *env, const char *name, const Object obj)
|
||||||
env->objects[old_size] = cloneObject(obj);
|
env->objects[old_size] = cloneObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printEnv(struct Environment *env)
|
void printEnv(struct Environment* env)
|
||||||
{
|
{
|
||||||
if(!env) {
|
if (!env) {
|
||||||
printf("NULL env\n");
|
printf("NULL env\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(int i = 0; i < env->size; i++) {
|
for (int i = 0; i < env->size; i++) {
|
||||||
if(env->strings[i] == NULL) {
|
if (env->strings[i] == NULL) {
|
||||||
printf("env[%d]: NULL %p\n", i, env->strings[i]);
|
printf("env[%d]: NULL %p\n", i, env->strings[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -170,19 +167,20 @@ void printEnv(struct Environment *env)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFunc(const char *name, Object (*func)(Object, Object, struct Environment*),
|
void addFunc(const char* name,
|
||||||
struct Environment *env)
|
Object (* func)(Object, Object, struct Environment*),
|
||||||
|
struct Environment* env)
|
||||||
{
|
{
|
||||||
Object o = newObject(TYPE_FUNC);
|
Object o = newObject(TYPE_FUNC);
|
||||||
o.func = func;
|
o.func = func;
|
||||||
addToEnv(env, name, o);
|
addToEnv(env, name, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteEnv(struct Environment *e)
|
void deleteEnv(struct Environment* e)
|
||||||
{
|
{
|
||||||
if (e->strings) {
|
if (e->strings) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(e->strings[i]) {
|
while (e->strings[i]) {
|
||||||
free(e->strings[i]);
|
free(e->strings[i]);
|
||||||
cleanObject(&e->objects[i]);
|
cleanObject(&e->objects[i]);
|
||||||
i++;
|
i++;
|
||||||
|
@ -196,8 +194,9 @@ void deleteEnv(struct Environment *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct symFunc {
|
struct symFunc {
|
||||||
const char *sym;
|
const char* sym;
|
||||||
Object (*func)(Object, Object, struct Environment*);
|
|
||||||
|
Object (* func)(Object, Object, struct Environment*);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Environment defaultEnv()
|
struct Environment defaultEnv()
|
||||||
|
@ -214,27 +213,43 @@ struct Environment defaultEnv()
|
||||||
};
|
};
|
||||||
|
|
||||||
struct symFunc symFuncs[] = {
|
struct symFunc symFuncs[] = {
|
||||||
{"+", &add}, {"-", &sub}, {"*", &mul}, {"/", &dvi}, {"%", &mod},
|
{"+", &add},
|
||||||
{"=", &equ}, {">", >h}, {"<", <h},
|
{"-", &sub},
|
||||||
{"cat", &catObjects}, {"fil", &filter}, {"len", &len},
|
{"*", &mul},
|
||||||
{"ap", &append}, {"pre", &prepend},
|
{"/", &dvi},
|
||||||
{"at", &at}, {"rest", &rest},
|
{"%", &mod},
|
||||||
|
{"=", &equ},
|
||||||
|
{">", >h},
|
||||||
|
{"<", <h},
|
||||||
|
{"&", &and},
|
||||||
|
{"|", &or},
|
||||||
|
{"cat", &catObjects},
|
||||||
|
{"fil", &filter},
|
||||||
|
{"len", &len},
|
||||||
|
{"ap", &append},
|
||||||
|
{"pre", &prepend},
|
||||||
|
{"at", &at},
|
||||||
|
{"rest", &rest},
|
||||||
{"chat", &charAt},
|
{"chat", &charAt},
|
||||||
#ifndef LOW_MEM
|
#ifndef LOW_MEM
|
||||||
{"rev", &reverse},
|
{"rev", &reverse},
|
||||||
#endif
|
#endif
|
||||||
{"isnum", &isNum}, {"isstr", &isString}, {"iserr", &isErr},
|
{"isnum", &isNum},
|
||||||
|
{"isstr", &isString},
|
||||||
|
{"iserr", &isErr},
|
||||||
{"char", &charVal},
|
{"char", &charVal},
|
||||||
{"eval", &parseEvalO},
|
{"eval", &parseEvalO},
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
{"prn", &print}, {"pch", &pChar}, {"penv", &printEnvO},
|
{"prn", &print},
|
||||||
|
{"pch", &pChar},
|
||||||
|
{"penv", &printEnvO},
|
||||||
{"sys", &systemCall},
|
{"sys", &systemCall},
|
||||||
{"loadfile", &loadFile},
|
{"loadfile", &loadFile},
|
||||||
{"inp", &takeInput},
|
{"inp", &takeInput},
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
for(unsigned i = 0; i < sizeof(symFuncs)/sizeof(symFuncs[0]); i++) {
|
for (unsigned i = 0; i < sizeof(symFuncs) / sizeof(symFuncs[0]); i++) {
|
||||||
addFunc(symFuncs[i].sym, symFuncs[i].func, &e);
|
addFunc(symFuncs[i].sym, symFuncs[i].func, &e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
src/env.h
31
src/env.h
|
@ -5,20 +5,27 @@
|
||||||
|
|
||||||
struct Environment;
|
struct Environment;
|
||||||
struct Environment {
|
struct Environment {
|
||||||
char **strings;
|
char** strings;
|
||||||
Object *objects;
|
Object* objects;
|
||||||
struct Environment *outer;
|
struct Environment* outer;
|
||||||
char size;
|
int size;
|
||||||
};
|
};
|
||||||
|
|
||||||
Object fetchFromEnvironment(const char *name, struct Environment *env);
|
Object fetchFromEnvironment(const char* name, struct Environment* env);
|
||||||
struct Environment envForLambda(const Object *params, const Object *arg_forms,
|
|
||||||
struct Environment *outer);
|
struct Environment envForLambda(const Object* params, const Object* arg_forms,
|
||||||
void addToEnv(struct Environment *env, const char *name, const Object obj);
|
struct Environment* outer);
|
||||||
void printEnv(struct Environment *env);
|
|
||||||
void addFunc(const char *name, Object (*func)(Object, Object, struct Environment*),
|
void addToEnv(struct Environment* env, const char* name, const Object obj);
|
||||||
struct Environment *env);
|
|
||||||
void deleteEnv(struct Environment *e);
|
void printEnv(struct Environment* env);
|
||||||
|
|
||||||
|
void addFunc(const char* name,
|
||||||
|
Object (* func)(Object, Object, struct Environment*),
|
||||||
|
struct Environment* env);
|
||||||
|
|
||||||
|
void deleteEnv(struct Environment* e);
|
||||||
|
|
||||||
struct Environment defaultEnv();
|
struct Environment defaultEnv();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
244
src/object.c
244
src/object.c
|
@ -1,40 +1,30 @@
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#ifdef DEBUG
|
|
||||||
#define printd(...) printf(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define printd(...) ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef STANDALONE
|
|
||||||
#include <pebble.h>
|
|
||||||
#undef printf
|
|
||||||
#undef printd
|
|
||||||
#define printf(...) ;
|
|
||||||
#define printd(...) APP_LOG(APP_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the length of a given list Object
|
* Returns the length of a given list Object
|
||||||
* @param listObj The list to get the length of
|
* @param listObj The list to get the length of
|
||||||
* @return Length of the list if non-null and of the list type. Otherwise -1
|
* @return Length of the list if non-null and of the list type. Otherwise -1
|
||||||
*/
|
*/
|
||||||
int listLength(const Object *listObj)
|
int listLength(const Object* listObj)
|
||||||
{
|
{
|
||||||
if(!listObj || !isListy(*listObj))
|
if (!listObj || !isListy(*listObj)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
FOR_POINTER_IN_LIST(listObj) { len++; }
|
FOR_POINTER_IN_LIST(listObj) {
|
||||||
|
len++;
|
||||||
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object len(Object obj1, Object o_ignore, struct Environment *e_ignore)
|
Object len(Object obj1, Object o_ignore, struct Environment* e_ignore)
|
||||||
{
|
{
|
||||||
Object o = numberObject(listLength(&obj1));
|
Object o = numberObject(listLength(&obj1));
|
||||||
if(o.number < 0) {
|
if (o.number < 0) {
|
||||||
return errorObject(NOT_A_LIST);
|
return errorObject(NOT_A_LIST);
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
|
@ -46,17 +36,20 @@ Object len(Object obj1, Object o_ignore, struct Environment *e_ignore)
|
||||||
* @param n The index to to fetch from the list
|
* @param n The index to to fetch from the list
|
||||||
* @return A pointer to the Object, if it is found, or NULL on an error
|
* @return A pointer to the Object, if it is found, or NULL on an error
|
||||||
*/
|
*/
|
||||||
Object *itemAt(const Object *listObj, int n)
|
Object* itemAt(const Object* listObj, int n)
|
||||||
{
|
{
|
||||||
if(!listObj || !isListy(*listObj))
|
if (!listObj || !isListy(*listObj)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
FOR_POINTER_IN_LIST(listObj) {
|
FOR_POINTER_IN_LIST(listObj) {
|
||||||
if(POINTER == NULL)
|
if (POINTER == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
if(n-- == 0)
|
}
|
||||||
|
if (n-- == 0) {
|
||||||
return POINTER;
|
return POINTER;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,12 +58,13 @@ Object *itemAt(const Object *listObj, int n)
|
||||||
* @param listObj The list to find the tail of
|
* @param listObj The list to find the tail of
|
||||||
* @return A pointer to the last Object if it is found, or NULL on an error
|
* @return A pointer to the last Object if it is found, or NULL on an error
|
||||||
*/
|
*/
|
||||||
Object *tail(const Object *listObj)
|
Object* tail(const Object* listObj)
|
||||||
{
|
{
|
||||||
if(!listObj || !isListy(*listObj))
|
if (!listObj || !isListy(*listObj)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Object *tail = NULL;
|
Object* tail = NULL;
|
||||||
FOR_POINTER_IN_LIST(listObj) {
|
FOR_POINTER_IN_LIST(listObj) {
|
||||||
tail = POINTER;
|
tail = POINTER;
|
||||||
}
|
}
|
||||||
|
@ -86,12 +80,13 @@ Object *tail(const Object *listObj)
|
||||||
* @param obj A pointer to the object to check
|
* @param obj A pointer to the object to check
|
||||||
* @return True only if the non-null Object is empty/non-zero
|
* @return True only if the non-null Object is empty/non-zero
|
||||||
*/
|
*/
|
||||||
inline int isEmpty(const Object *obj)
|
inline int isEmpty(const Object* obj)
|
||||||
{
|
{
|
||||||
if(obj == NULL)
|
if (obj == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
switch(obj->type) {
|
switch (obj->type) {
|
||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
return obj->number == 0;
|
return obj->number == 0;
|
||||||
|
@ -120,7 +115,7 @@ inline int isEmpty(const Object *obj)
|
||||||
* @param spot A pointer to the Object pointer that needs allocating
|
* @param spot A pointer to the Object pointer that needs allocating
|
||||||
* @param src The Object to copy from
|
* @param src The Object to copy from
|
||||||
*/
|
*/
|
||||||
void allocObject(Object **spot, const Object src)
|
void allocObject(Object** spot, const Object src)
|
||||||
{
|
{
|
||||||
*spot = malloc(sizeof(struct Object));
|
*spot = malloc(sizeof(struct Object));
|
||||||
**spot = src;
|
**spot = src;
|
||||||
|
@ -138,20 +133,21 @@ void allocObject(Object **spot, const Object src)
|
||||||
|
|
||||||
* @warning UNTESTED
|
* @warning UNTESTED
|
||||||
*/
|
*/
|
||||||
void insertIntoList(Object *dest, int ind, const Object src)
|
void insertIntoList(Object* dest, int ind, const Object src)
|
||||||
{
|
{
|
||||||
if(!dest || !isListy(*dest))
|
if (!dest || !isListy(*dest)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Merely append, when possible
|
// Merely append, when possible
|
||||||
if(ind >= listLength(dest)) {
|
if (ind >= listLength(dest)) {
|
||||||
nf_addToList(dest, src);
|
nf_addToList(dest, src);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Objects to preceed and follow the new one
|
// The Objects to preceed and follow the new one
|
||||||
Object *beforeNew = itemAt(dest, ind - 1);
|
Object* beforeNew = itemAt(dest, ind - 1);
|
||||||
Object *afterNew = beforeNew->forward;
|
Object* afterNew = beforeNew->forward;
|
||||||
|
|
||||||
// Replace the `before` Object's pointer
|
// Replace the `before` Object's pointer
|
||||||
allocObject(&beforeNew->forward, src);
|
allocObject(&beforeNew->forward, src);
|
||||||
|
@ -167,12 +163,13 @@ void insertIntoList(Object *dest, int ind, const Object src)
|
||||||
* @param i The index of the element to replace
|
* @param i The index of the element to replace
|
||||||
* @param src The Object to copy into the list
|
* @param src The Object to copy into the list
|
||||||
*/
|
*/
|
||||||
void replaceListing(Object *list, int i, const Object src)
|
void replaceListing(Object* list, int i, const Object src)
|
||||||
{
|
{
|
||||||
if(!list || isListy(*list))
|
if (!list || isListy(*list)) {
|
||||||
return;
|
return;
|
||||||
Object *replace = itemAt(list, i);
|
}
|
||||||
Object *oldForward = replace->forward;
|
Object* replace = itemAt(list, i);
|
||||||
|
Object* oldForward = replace->forward;
|
||||||
cleanObject(replace);
|
cleanObject(replace);
|
||||||
*replace = src;
|
*replace = src;
|
||||||
replace->forward = oldForward;
|
replace->forward = oldForward;
|
||||||
|
@ -184,12 +181,13 @@ void replaceListing(Object *list, int i, const Object src)
|
||||||
* @param dest The list to append to
|
* @param dest The list to append to
|
||||||
* @param src The Object to copy into the list
|
* @param src The Object to copy into the list
|
||||||
*/
|
*/
|
||||||
void nf_addToList(Object *dest, const Object src)
|
void nf_addToList(Object* dest, const Object src)
|
||||||
{
|
{
|
||||||
if(!dest || !isListy(*dest))
|
if (!dest || !isListy(*dest)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(isEmpty(dest)) {
|
if (isEmpty(dest)) {
|
||||||
allocObject(&dest->list, src);
|
allocObject(&dest->list, src);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -198,8 +196,7 @@ void nf_addToList(Object *dest, const Object src)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SIMPLE_ERRORS
|
#ifndef SIMPLE_ERRORS
|
||||||
static const char *errorText[] = {
|
static const char* errorText[] = {"MISMATCHED_PARENS",
|
||||||
"MISMATCHED_PARENS",
|
|
||||||
"BAD_LIST_OF_SYMBOL_STRINGS",
|
"BAD_LIST_OF_SYMBOL_STRINGS",
|
||||||
"TYPE_LIST_NOT_CAUGHT",
|
"TYPE_LIST_NOT_CAUGHT",
|
||||||
"NULL_ENV",
|
"NULL_ENV",
|
||||||
|
@ -222,8 +219,7 @@ static const char *errorText[] = {
|
||||||
"NO_CLONE_SPECIFIED",
|
"NO_CLONE_SPECIFIED",
|
||||||
"CAN_ONLY_EVAL_STRINGS",
|
"CAN_ONLY_EVAL_STRINGS",
|
||||||
"UNEXPECTED_EOF",
|
"UNEXPECTED_EOF",
|
||||||
"INDEX_PAST_END"
|
"INDEX_PAST_END"};
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -233,10 +229,11 @@ static const char *errorText[] = {
|
||||||
* @param dest The string to copy the list text into
|
* @param dest The string to copy the list text into
|
||||||
* @param obj The list Object to make a string from
|
* @param obj The list Object to make a string from
|
||||||
*/
|
*/
|
||||||
void stringList(char *dest, const Object *obj)
|
void stringList(char* dest, const Object* obj)
|
||||||
{
|
{
|
||||||
if(!dest || !isListy(*obj))
|
if (!dest || !isListy(*obj)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dest[0] = '(';
|
dest[0] = '(';
|
||||||
dest[1] = '\0';
|
dest[1] = '\0';
|
||||||
|
@ -266,11 +263,13 @@ void stringList(char *dest, const Object *obj)
|
||||||
* @param dest The string to copy the list text into
|
* @param dest The string to copy the list text into
|
||||||
* @param obj The list Object to make a string from
|
* @param obj The list Object to make a string from
|
||||||
*/
|
*/
|
||||||
char* stringNObj(char *dest, const Object *obj, const size_t len) {
|
char* stringNObj(char* dest, const Object* obj, const size_t len)
|
||||||
if(!dest || !obj)
|
{
|
||||||
|
if (!dest || !obj) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
switch(obj->type) {
|
switch (obj->type) {
|
||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
snprintf(dest, len, "%d", obj->number);
|
snprintf(dest, len, "%d", obj->number);
|
||||||
break;
|
break;
|
||||||
|
@ -289,16 +288,16 @@ char* stringNObj(char *dest, const Object *obj, const size_t len) {
|
||||||
break;
|
break;
|
||||||
case TYPE_ERROR: {
|
case TYPE_ERROR: {
|
||||||
int code = getErrorCode(*obj);
|
int code = getErrorCode(*obj);
|
||||||
#ifdef SIMPLE_ERRORS
|
#ifdef SIMPLE_ERRORS
|
||||||
snprintf(dest, len, "E[%d]", (int)code);
|
snprintf(dest, len, "E[%d]", (int)code);
|
||||||
#else
|
#else
|
||||||
if (obj->error->context && obj->error->context[0] != '\0') {
|
if (obj->error->context && obj->error->context[0] != '\0') {
|
||||||
snprintf(dest, len, "'%s': %s",
|
snprintf(dest, len, "'%s': %s", errorText[code],
|
||||||
errorText[code], obj->error->context);
|
obj->error->context);
|
||||||
} else {
|
} else {
|
||||||
snprintf(dest, len, "%s", errorText[code]);
|
snprintf(dest, len, "%s", errorText[code]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
|
@ -310,13 +309,15 @@ char* stringNObj(char *dest, const Object *obj, const size_t len) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isValidType(*obj))
|
if (!isValidType(*obj)) {
|
||||||
snprintf(dest, len, "BAD_TYPE(%d) X%d", obj->type, obj->number);
|
snprintf(dest, len, "BAD_TYPE(%d) X%d", obj->type, obj->number);
|
||||||
|
}
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* stringObj(char *dest, const Object *obj) {
|
char* stringObj(char* dest, const Object* obj)
|
||||||
|
{
|
||||||
return stringNObj(dest, obj, RESULT_LENGTH);
|
return stringNObj(dest, obj, RESULT_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +325,7 @@ char* stringObj(char *dest, const Object *obj) {
|
||||||
* Prints a given Object only if the DEBUG flag is set
|
* Prints a given Object only if the DEBUG flag is set
|
||||||
* @param obj The Object to debug
|
* @param obj The Object to debug
|
||||||
*/
|
*/
|
||||||
void debugObj(const Object *obj)
|
void debugObj(const Object* obj)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printObj(obj);
|
printObj(obj);
|
||||||
|
@ -333,9 +334,10 @@ void debugObj(const Object *obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(DEBUG) || defined(STANDALONE)
|
#if defined(DEBUG) || defined(STANDALONE)
|
||||||
void printType(const Object *obj)
|
|
||||||
|
void printType(const Object* obj)
|
||||||
{
|
{
|
||||||
switch(obj->type) {
|
switch (obj->type) {
|
||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
printf("TYPE_NUMBER");
|
printf("TYPE_NUMBER");
|
||||||
return;
|
return;
|
||||||
|
@ -367,16 +369,18 @@ void printType(const Object *obj)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isValidType(*obj))
|
if (!isValidType(*obj)) {
|
||||||
printf("UNKNOWN TYPE (%d)", obj->type);
|
printf("UNKNOWN TYPE (%d)", obj->type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _printList(const Object *list, int newline);
|
void nestedPrintList(const Object* list, int newline);
|
||||||
void _printObj(const Object *obj, int newline)
|
|
||||||
|
void _printObj(const Object* obj, int newline)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printType(obj);
|
printType(obj);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (obj->type == TYPE_LAMBDA) {
|
if (obj->type == TYPE_LAMBDA) {
|
||||||
printObj(&obj->lambda->params);
|
printObj(&obj->lambda->params);
|
||||||
|
@ -387,10 +391,11 @@ void _printObj(const Object *obj, int newline)
|
||||||
|
|
||||||
char temp[100] = "";
|
char temp[100] = "";
|
||||||
stringObj(temp, obj);
|
stringObj(temp, obj);
|
||||||
if(newline)
|
if (newline) {
|
||||||
printf("%s\n", temp);
|
printf("%s\n", temp);
|
||||||
else
|
} else {
|
||||||
printf("%s", temp);
|
printf("%s", temp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -399,32 +404,36 @@ void _printObj(const Object *obj, int newline)
|
||||||
* If the DEBUG flag is set, the Object's type will be printed first
|
* If the DEBUG flag is set, the Object's type will be printed first
|
||||||
* @param obj The Object to print
|
* @param obj The Object to print
|
||||||
*/
|
*/
|
||||||
inline void printObj(const Object *obj)
|
inline void printObj(const Object* obj)
|
||||||
{
|
{
|
||||||
_printObj(obj, 1);
|
_printObj(obj, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _printList(const Object *list, int newline)
|
void nestedPrintList(const Object* list, int newline)
|
||||||
{
|
{
|
||||||
printf("(");
|
printf("(");
|
||||||
|
if (list && isListy(*list)) {
|
||||||
FOR_POINTER_IN_LIST(list) {
|
FOR_POINTER_IN_LIST(list) {
|
||||||
printf(" ");
|
printf(" ");
|
||||||
_printObj(POINTER, 0);
|
_printObj(POINTER, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
printf(" )");
|
printf(" )");
|
||||||
|
|
||||||
if(newline)
|
if (newline) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints each Object in a given list, surrounded by parentheses
|
* Prints each Object in a given list, surrounded by parentheses
|
||||||
* @param list The list Object to print
|
* @param list The list Object to print
|
||||||
*/
|
*/
|
||||||
void printList(const Object *list)
|
void printList(const Object* list)
|
||||||
{
|
{
|
||||||
_printList(list, 1);
|
nestedPrintList(list, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -437,12 +446,13 @@ void printList(const Object *list)
|
||||||
*
|
*
|
||||||
* @param target The object to clean
|
* @param target The object to clean
|
||||||
*/
|
*/
|
||||||
void cleanObject(Object *target)
|
void cleanObject(Object* target)
|
||||||
{
|
{
|
||||||
if(target == NULL)
|
if (target == NULL) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch(target->type) {
|
switch (target->type) {
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
case TYPE_SYMBOL:
|
case TYPE_SYMBOL:
|
||||||
free(target->string);
|
free(target->string);
|
||||||
|
@ -465,7 +475,7 @@ void cleanObject(Object *target)
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case TYPE_OTHER:
|
case TYPE_OTHER:
|
||||||
if(target->other->cleanup) {
|
if (target->other->cleanup) {
|
||||||
target->other->cleanup(target);
|
target->other->cleanup(target);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -483,11 +493,13 @@ void cleanObject(Object *target)
|
||||||
* @param target The object to print and clean
|
* @param target The object to print and clean
|
||||||
*/
|
*/
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
void printAndClean(Object *target)
|
|
||||||
|
void printAndClean(Object* target)
|
||||||
{
|
{
|
||||||
printObj(target);
|
printObj(target);
|
||||||
cleanObject(target);
|
cleanObject(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -496,19 +508,20 @@ void printAndClean(Object *target)
|
||||||
*
|
*
|
||||||
* @param dest The list object to clean up
|
* @param dest The list object to clean up
|
||||||
*/
|
*/
|
||||||
void deleteList(Object *dest)
|
void deleteList(Object* dest)
|
||||||
{
|
{
|
||||||
if(!dest)
|
if (!dest) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(!isListy(*dest)) {
|
if (!isListy(*dest)) {
|
||||||
printf("Tried to delete something other than a list\n");
|
printf("Tried to delete something other than a list\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *march = dest->list;
|
Object* march = dest->list;
|
||||||
while(march != NULL) {
|
while (march != NULL) {
|
||||||
Object *prevMarch = march;
|
Object* prevMarch = march;
|
||||||
march = march->forward;
|
march = march->forward;
|
||||||
cleanObject(prevMarch);
|
cleanObject(prevMarch);
|
||||||
free(prevMarch);
|
free(prevMarch);
|
||||||
|
@ -516,22 +529,23 @@ void deleteList(Object *dest)
|
||||||
dest->list = NULL;
|
dest->list = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _copyList(Object *dest, const Object *src, int delete)
|
void _copyList(Object* dest, const Object* src, int delete)
|
||||||
{
|
{
|
||||||
if(!dest || !src) {
|
if (!dest || !src) {
|
||||||
printd("NULL\n");
|
printd("NULL\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!isListy(*dest) || !isListy(*src)) {
|
if (!isListy(*dest) || !isListy(*src)) {
|
||||||
printd("NOT A LIST\n");
|
printd("NOT A LIST\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(delete)
|
if (delete) {
|
||||||
deleteList(dest);
|
deleteList(dest);
|
||||||
|
}
|
||||||
|
|
||||||
FOR_POINTER_IN_LIST(src) {
|
FOR_POINTER_IN_LIST(src) {
|
||||||
if(isListy(*POINTER)) {
|
if (isListy(*POINTER)) {
|
||||||
nf_addToList(dest, *POINTER);
|
nf_addToList(dest, *POINTER);
|
||||||
tail(dest)->list = NULL;
|
tail(dest)->list = NULL;
|
||||||
_copyList(tail(dest), POINTER, 0);
|
_copyList(tail(dest), POINTER, 0);
|
||||||
|
@ -552,7 +566,7 @@ void _copyList(Object *dest, const Object *src, int delete)
|
||||||
* @param dest The list to copy to
|
* @param dest The list to copy to
|
||||||
* @param src The list to copy from
|
* @param src The list to copy from
|
||||||
*/
|
*/
|
||||||
void copyList(Object *dest, const Object *src)
|
void copyList(Object* dest, const Object* src)
|
||||||
{
|
{
|
||||||
_copyList(dest, src, 1);
|
_copyList(dest, src, 1);
|
||||||
}
|
}
|
||||||
|
@ -565,7 +579,7 @@ void copyList(Object *dest, const Object *src)
|
||||||
* @param dest The list to copy to
|
* @param dest The list to copy to
|
||||||
* @param src The list to copy from
|
* @param src The list to copy from
|
||||||
*/
|
*/
|
||||||
void appendList(Object *dest, const Object *src)
|
void appendList(Object* dest, const Object* src)
|
||||||
{
|
{
|
||||||
_copyList(dest, src, 0);
|
_copyList(dest, src, 0);
|
||||||
}
|
}
|
||||||
|
@ -611,7 +625,7 @@ inline int isStringy(const Object test)
|
||||||
|
|
||||||
inline int isValidType(const Object test)
|
inline int isValidType(const Object test)
|
||||||
{
|
{
|
||||||
switch(test.type) {
|
switch (test.type) {
|
||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
case TYPE_LIST:
|
case TYPE_LIST:
|
||||||
|
@ -654,15 +668,14 @@ inline Object cloneList(const Object src)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Object cloneOther(const Object src) {
|
inline Object cloneOther(const Object src)
|
||||||
return src.other->clone?
|
{
|
||||||
src.other->clone(src.other) :
|
return src.other->clone ? src.other->clone(src.other) : src;
|
||||||
src;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Object cloneObject(const Object src)
|
inline Object cloneObject(const Object src)
|
||||||
{
|
{
|
||||||
switch(src.type) {
|
switch (src.type) {
|
||||||
case TYPE_SLIST:
|
case TYPE_SLIST:
|
||||||
case TYPE_LIST:
|
case TYPE_LIST:
|
||||||
return cloneList(src);
|
return cloneList(src);
|
||||||
|
@ -677,7 +690,7 @@ inline Object cloneObject(const Object src)
|
||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_OTHER:
|
case TYPE_OTHER:
|
||||||
; // Fall through to plain return
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
return src;
|
return src;
|
||||||
|
@ -698,19 +711,19 @@ inline Object boolObject(int b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skips first and last chars! Assumed to be '"'
|
// Skips first and last chars! Assumed to be '"'
|
||||||
inline Object objFromSlice(const char *string, int len)
|
inline Object objFromSlice(const char* string, int len)
|
||||||
{
|
{
|
||||||
return stringFromSlice(&string[1], len - 1);
|
return stringFromSlice(&string[1], len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Object stringFromSlice(const char *string, int len)
|
inline Object stringFromSlice(const char* string, int len)
|
||||||
{
|
{
|
||||||
Object o = symFromSlice(string, len);
|
Object o = symFromSlice(string, len);
|
||||||
o.type = TYPE_STRING;
|
o.type = TYPE_STRING;
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Object symFromSlice(const char *string, int len)
|
inline Object symFromSlice(const char* string, int len)
|
||||||
{
|
{
|
||||||
Object o = newObject(TYPE_SYMBOL);
|
Object o = newObject(TYPE_SYMBOL);
|
||||||
o.string = calloc(sizeof(char), len + 1);
|
o.string = calloc(sizeof(char), len + 1);
|
||||||
|
@ -718,13 +731,15 @@ inline Object symFromSlice(const char *string, int len)
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Object constructLambda(const Object *params, const Object *body)
|
inline Object constructLambda(const Object* params, const Object* body)
|
||||||
{
|
{
|
||||||
if(!params || !body)
|
if (!params || !body) {
|
||||||
return errorObject(NULL_LAMBDA_LIST);
|
return errorObject(NULL_LAMBDA_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
if(params->type != TYPE_LIST || body->type != TYPE_LIST)
|
if (params->type != TYPE_LIST || body->type != TYPE_LIST) {
|
||||||
return errorObject(LAMBDA_ARGS_NOT_LIST);
|
return errorObject(LAMBDA_ARGS_NOT_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
Object o = newObject(TYPE_LAMBDA);
|
Object o = newObject(TYPE_LAMBDA);
|
||||||
o.lambda = malloc(sizeof(struct Lambda));
|
o.lambda = malloc(sizeof(struct Lambda));
|
||||||
|
@ -740,17 +755,17 @@ inline int isError(const Object obj, const enum errorCode err)
|
||||||
return obj.type == TYPE_ERROR && getErrorCode(obj) == err;
|
return obj.type == TYPE_ERROR && getErrorCode(obj) == err;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int bothAre(const enum Type type, const Object *obj1, const Object *obj2)
|
inline int bothAre(const enum Type type, const Object* obj1, const Object* obj2)
|
||||||
{
|
{
|
||||||
return (obj1->type == type) && (obj2->type == type);
|
return (obj1->type == type) && (obj2->type == type);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int eitherIs(const enum Type type, const Object *o1, const Object *o2)
|
inline int eitherIs(const enum Type type, const Object* o1, const Object* o2)
|
||||||
{
|
{
|
||||||
return (o1->type == type) || (o2->type == type);
|
return (o1->type == type) || (o2->type == type);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int areSameType(const Object *obj1, const Object *obj2)
|
inline int areSameType(const Object* obj1, const Object* obj2)
|
||||||
{
|
{
|
||||||
return obj1->type == obj2->type;
|
return obj1->type == obj2->type;
|
||||||
}
|
}
|
||||||
|
@ -786,12 +801,13 @@ inline enum errorCode getErrorCode(const Object obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SIMPLE_ERRORS
|
#ifndef SIMPLE_ERRORS
|
||||||
inline void errorAddContext(Object *o, const char* context)
|
|
||||||
|
inline void errorAddContext(Object* o, const char* context)
|
||||||
{
|
{
|
||||||
//printf("o: %p\n", o);
|
// printf("o: %p\n", o);
|
||||||
//printf("o->error: %s\n", o->error);
|
// printf("o->error: %s\n", o->error);
|
||||||
o->error->context = calloc(sizeof(char), RESULT_LENGTH);
|
o->error->context = calloc(sizeof(char), RESULT_LENGTH);
|
||||||
//printf("context: %p\n", context);
|
// printf("context: %p\n", context);
|
||||||
strncpy(o->error->context, context, RESULT_LENGTH);
|
strncpy(o->error->context, context, RESULT_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,6 +819,7 @@ inline Object errorWithContext(enum errorCode code, const char* context)
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Error noError()
|
struct Error noError()
|
||||||
|
@ -814,7 +831,8 @@ struct Error noError()
|
||||||
|
|
||||||
inline Object toBool(const Object test)
|
inline Object toBool(const Object test)
|
||||||
{
|
{
|
||||||
if(test.number == 0)
|
if (test.number == 0) {
|
||||||
return boolObject(0);
|
return boolObject(0);
|
||||||
|
}
|
||||||
return boolObject(1);
|
return boolObject(1);
|
||||||
}
|
}
|
||||||
|
|
91
src/object.h
91
src/object.h
|
@ -3,30 +3,41 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifndef STANDALONE
|
||||||
|
#include <pebble.h>
|
||||||
|
#undef printf
|
||||||
|
#define printf(...) APP_LOG(APP_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define printd(...) printf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define printd(...) (0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MAX_TOK_CNT 1024
|
#define MAX_TOK_CNT 1024
|
||||||
#define MAX_ENV_ELM 100
|
#define MAX_ENV_ELM 100
|
||||||
#define RESULT_LENGTH 128
|
#define RESULT_LENGTH 128
|
||||||
|
|
||||||
#define FOR_POINTER_IN_LIST(_list) \
|
#define FOR_POINTER_IN_LIST(_list) \
|
||||||
if(_list && isListy(*_list)) \
|
for(Object *_element = (_list)->list; \
|
||||||
for(Object *_element = _list->list; \
|
|
||||||
_element != NULL;\
|
_element != NULL;\
|
||||||
_element = _element->forward)
|
_element = _element->forward)
|
||||||
#define POINTER _element
|
#define POINTER _element
|
||||||
|
|
||||||
#define FOR_POINTERS_IN_LISTS(_list, _list2) \
|
#define FOR_POINTERS_IN_LISTS(_list, _list2) \
|
||||||
for(Object *_element = _list->list, *_element2 = _list2->list; \
|
for(Object *_element = (_list)->list, *_element2 = (_list2)->list; \
|
||||||
_element != NULL && _element2 != NULL; \
|
_element != NULL && _element2 != NULL; \
|
||||||
_element = _element->forward, _element2 = _element2->forward)
|
_element = _element->forward, _element2 = _element2->forward)
|
||||||
#define P1 POINTER
|
#define P1 POINTER
|
||||||
#define P2 _element2
|
#define P2 _element2
|
||||||
|
|
||||||
#ifdef PBL_PLATFORM_APLITE
|
#ifdef PBL_PLATFORM_APLITE
|
||||||
#define LOW_MEM
|
#define LOW_MEM
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LOW_MEM
|
#ifdef LOW_MEM
|
||||||
#define SIMPLE_ERRORS
|
#define SIMPLE_ERRORS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum errorCode {
|
enum errorCode {
|
||||||
|
@ -76,24 +87,27 @@ struct Slice;
|
||||||
struct Other;
|
struct Other;
|
||||||
struct Error {
|
struct Error {
|
||||||
enum errorCode code;
|
enum errorCode code;
|
||||||
char* context;
|
char *context;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Object {
|
struct Object {
|
||||||
Type type;
|
Type type;
|
||||||
Object *forward;
|
Object *forward;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
int number;
|
int number;
|
||||||
Object *list;
|
Object *list;
|
||||||
char *string;
|
char *string;
|
||||||
|
|
||||||
Object (*func)(Object, Object, struct Environment *);
|
Object (*func)(Object, Object, struct Environment *);
|
||||||
|
|
||||||
struct Lambda *lambda;
|
struct Lambda *lambda;
|
||||||
struct Other *other;
|
struct Other *other;
|
||||||
#ifdef SIMPLE_ERRORS
|
#ifdef SIMPLE_ERRORS
|
||||||
enum errorCode error;
|
enum errorCode error;
|
||||||
#else
|
#else
|
||||||
struct Error *error;
|
struct Error *error;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -103,67 +117,110 @@ struct Lambda {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Other {
|
struct Other {
|
||||||
void (*cleanup)(Object*);
|
void (*cleanup)(Object *);
|
||||||
Object (*clone)(struct Other*);
|
|
||||||
|
Object (*clone)(struct Other *);
|
||||||
|
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
char* stringNObj(char *dest, const Object *obj, size_t len);
|
char *stringNObj(char *dest, const Object *obj, size_t len);
|
||||||
char* stringObj(char *dest, const Object *obj);
|
|
||||||
|
char *stringObj(char *dest, const Object *obj);
|
||||||
|
|
||||||
void printList(const Object *list);
|
void printList(const Object *list);
|
||||||
|
|
||||||
void printType(const Object *obj);
|
void printType(const Object *obj);
|
||||||
|
|
||||||
void printObj(const Object *obj);
|
void printObj(const Object *obj);
|
||||||
|
|
||||||
void _printObj(const Object *obj, int newline);
|
void _printObj(const Object *obj, int newline);
|
||||||
|
|
||||||
void debugObj(const Object *obj);
|
void debugObj(const Object *obj);
|
||||||
|
|
||||||
void printErr(const Object *obj);
|
void printErr(const Object *obj);
|
||||||
|
|
||||||
int isEmpty(const Object *obj);
|
int isEmpty(const Object *obj);
|
||||||
|
|
||||||
Object *tail(const Object *listObj);
|
Object *tail(const Object *listObj);
|
||||||
|
|
||||||
void insertIntoList(Object *dest, int ind, const Object src);
|
void insertIntoList(Object *dest, int ind, const Object src);
|
||||||
|
|
||||||
void replaceListing(Object *list, int i, const Object src);
|
void replaceListing(Object *list, int i, const Object src);
|
||||||
|
|
||||||
void nf_addToList(Object *dest, Object src);
|
void nf_addToList(Object *dest, Object src);
|
||||||
|
|
||||||
void deleteList(Object *dest);
|
void deleteList(Object *dest);
|
||||||
|
|
||||||
int listLength(const Object *listObj);
|
int listLength(const Object *listObj);
|
||||||
|
|
||||||
Object *itemAt(const Object *listObj, int n);
|
Object *itemAt(const Object *listObj, int n);
|
||||||
|
|
||||||
void copyList(Object *dest, const Object *src);
|
void copyList(Object *dest, const Object *src);
|
||||||
|
|
||||||
void cleanObject(Object *target);
|
void cleanObject(Object *target);
|
||||||
|
|
||||||
void printAndClean(Object *target);
|
void printAndClean(Object *target);
|
||||||
|
|
||||||
void allocObject(Object **spot, const Object src);
|
void allocObject(Object **spot, const Object src);
|
||||||
|
|
||||||
void appendList(Object *dest, const Object *src);
|
void appendList(Object *dest, const Object *src);
|
||||||
|
|
||||||
int isListy(const Object test);
|
int isListy(const Object test);
|
||||||
|
|
||||||
int isStringy(const Object test);
|
int isStringy(const Object test);
|
||||||
|
|
||||||
int isValidType(const Object test);
|
int isValidType(const Object test);
|
||||||
|
|
||||||
int isError(const Object obj, const enum errorCode err);
|
int isError(const Object obj, const enum errorCode err);
|
||||||
|
|
||||||
int bothAre(const enum Type type, const Object *obj1, const Object *obj2);
|
int bothAre(const enum Type type, const Object *obj1, const Object *obj2);
|
||||||
|
|
||||||
int eitherIs(const enum Type type, const Object *obj1, const Object *obj2);
|
int eitherIs(const enum Type type, const Object *obj1, const Object *obj2);
|
||||||
|
|
||||||
int areSameType(const Object *obj1, const Object *obj2);
|
int areSameType(const Object *obj1, const Object *obj2);
|
||||||
|
|
||||||
Object cloneList(const Object src);
|
Object cloneList(const Object src);
|
||||||
|
|
||||||
Object cloneString(Object obj);
|
Object cloneString(Object obj);
|
||||||
|
|
||||||
Object cloneLambda(const Object old);
|
Object cloneLambda(const Object old);
|
||||||
|
|
||||||
Object cloneObject(const Object src);
|
Object cloneObject(const Object src);
|
||||||
|
|
||||||
Object newObject(Type type);
|
Object newObject(Type type);
|
||||||
|
|
||||||
Object listObject();
|
Object listObject();
|
||||||
|
|
||||||
Object startList(const Object start);
|
Object startList(const Object start);
|
||||||
|
|
||||||
Object objFromSlice(const char *string, int len);
|
Object objFromSlice(const char *string, int len);
|
||||||
|
|
||||||
Object stringFromSlice(const char *string, int len);
|
Object stringFromSlice(const char *string, int len);
|
||||||
|
|
||||||
Object symFromSlice(const char *string, int len);
|
Object symFromSlice(const char *string, int len);
|
||||||
|
|
||||||
Object boolObject(int b);
|
Object boolObject(int b);
|
||||||
|
|
||||||
Object numberObject(int num);
|
Object numberObject(int num);
|
||||||
|
|
||||||
Object otherObject();
|
Object otherObject();
|
||||||
|
|
||||||
Object errorObject(enum errorCode err);
|
Object errorObject(enum errorCode err);
|
||||||
|
|
||||||
enum errorCode getErrorCode(const Object obj);
|
enum errorCode getErrorCode(const Object obj);
|
||||||
|
|
||||||
#ifdef SIMPLE_ERRORS
|
#ifdef SIMPLE_ERRORS
|
||||||
#define errorWithContext(code, context) errorObject(code)
|
#define errorWithContext(code, context) errorObject(code)
|
||||||
#define errorAddContext(x, y) ;
|
#define errorAddContext(x, y) ;
|
||||||
#else
|
#else
|
||||||
Object errorWithContext(enum errorCode err, const char* context);
|
|
||||||
void errorAddContext(Object *o, const char* context);
|
Object errorWithContext(enum errorCode err, const char *context);
|
||||||
|
|
||||||
|
void errorAddContext(Object *o, const char *context);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Error noError();
|
struct Error noError();
|
||||||
|
|
||||||
Object constructLambda(const Object *params, const Object *body);
|
Object constructLambda(const Object *params, const Object *body);
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
#include "pebbleobject.h"
|
#include "pebbleobject.h"
|
||||||
|
|
||||||
#include "calc.h"
|
#include "calc.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
|
||||||
Object pebbleOther(
|
Object pebbleOther(enum PebbleType type, void* data, void (* cleanup)(Object*),
|
||||||
enum PebbleType type,
|
Object (* clone)(struct Other*))
|
||||||
void* data,
|
|
||||||
void (*cleanup)(Object*),
|
|
||||||
Object (*clone)(struct Other*))
|
|
||||||
{
|
{
|
||||||
struct Object o = otherObject();
|
struct Object o = otherObject();
|
||||||
struct PebbleObject *po = malloc(sizeof(struct PebbleObject));
|
struct PebbleObject* po = malloc(sizeof(struct PebbleObject));
|
||||||
o.other->data = po;
|
o.other->data = po;
|
||||||
o.other->cleanup = cleanup;
|
o.other->cleanup = cleanup;
|
||||||
o.other->clone = clone;
|
o.other->clone = clone;
|
||||||
|
@ -20,57 +18,63 @@ Object pebbleOther(
|
||||||
|
|
||||||
enum PebbleType getPebbleType(const Object o1)
|
enum PebbleType getPebbleType(const Object o1)
|
||||||
{
|
{
|
||||||
if(o1.type == TYPE_OTHER) {
|
if (o1.type == TYPE_OTHER) {
|
||||||
struct PebbleObject *po = o1.other->data;
|
struct PebbleObject* po = o1.other->data;
|
||||||
enum PebbleType t = po->type;
|
enum PebbleType t = po->type;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
return P_ERROR;
|
return P_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PebbleObject* accessPebbleObject(Object obj) {
|
struct PebbleObject* accessPebbleObject(Object obj)
|
||||||
if(getPebbleType(obj) != P_ERROR) {
|
{
|
||||||
|
if (getPebbleType(obj) != P_ERROR) {
|
||||||
return obj.other->data;
|
return obj.other->data;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void custom_window_load(Window *window) {
|
void custom_window_load(Window* window)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void custom_window_unload(Window *window) {
|
void custom_window_unload(Window* window)
|
||||||
|
{
|
||||||
window_destroy(window);
|
window_destroy(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object createWindow(Object o1, Object o2, struct Environment *env) {
|
Object createWindow(Object o1, Object o2, struct Environment* env)
|
||||||
Window *window = window_create();
|
{
|
||||||
WindowHandlers wh = {
|
Window* window = window_create();
|
||||||
.load = custom_window_load,
|
WindowHandlers wh = {.load = custom_window_load,
|
||||||
.unload = custom_window_unload };
|
.unload = custom_window_unload};
|
||||||
window_set_window_handlers(window, wh);
|
window_set_window_handlers(window, wh);
|
||||||
return pebbleOther(WINDOW, window, NULL, NULL);
|
return pebbleOther(WINDOW, window, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object deleteWindow(Object window, Object o2, struct Environment *env) {
|
Object deleteWindow(Object window, Object o2, struct Environment* env)
|
||||||
|
{
|
||||||
/* Maintain a list of layers to delete? */
|
/* Maintain a list of layers to delete? */
|
||||||
if(getPebbleType(window) == WINDOW) {
|
if (getPebbleType(window) == WINDOW) {
|
||||||
window_stack_remove(accessPebbleObject(window)->window, true);
|
window_stack_remove(accessPebbleObject(window)->window, true);
|
||||||
return boolObject(1);
|
return boolObject(1);
|
||||||
}
|
}
|
||||||
return boolObject(0);
|
return boolObject(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object pushWindow(Object window, Object o2, struct Environment *env) {
|
Object pushWindow(Object window, Object o2, struct Environment* env)
|
||||||
if(getPebbleType(window) == WINDOW) {
|
{
|
||||||
|
if (getPebbleType(window) == WINDOW) {
|
||||||
window_stack_push(accessPebbleObject(window)->window, true);
|
window_stack_push(accessPebbleObject(window)->window, true);
|
||||||
return boolObject(1);
|
return boolObject(1);
|
||||||
}
|
}
|
||||||
return boolObject(0);
|
return boolObject(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object updateTextLayer(Object textLayer, Object text, struct Environment *env) {
|
Object updateTextLayer(Object textLayer, Object text, struct Environment* env)
|
||||||
if(getPebbleType(textLayer) == TEXT_LAYER) {
|
{
|
||||||
struct PebbleObject *po = accessPebbleObject(textLayer);
|
if (getPebbleType(textLayer) == TEXT_LAYER) {
|
||||||
|
struct PebbleObject* po = accessPebbleObject(textLayer);
|
||||||
stringObj(po->textLayer->text, &text);
|
stringObj(po->textLayer->text, &text);
|
||||||
text_layer_set_text(po->textLayer->layer, po->textLayer->text);
|
text_layer_set_text(po->textLayer->layer, po->textLayer->text);
|
||||||
return boolObject(1);
|
return boolObject(1);
|
||||||
|
@ -78,14 +82,16 @@ Object updateTextLayer(Object textLayer, Object text, struct Environment *env) {
|
||||||
return boolObject(0);
|
return boolObject(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object addTextLayer(Object window, Object text, struct Environment *env) {
|
Object addTextLayer(Object window, Object text, struct Environment* env)
|
||||||
if(getPebbleType(window) != WINDOW) {
|
{
|
||||||
|
if (getPebbleType(window) != WINDOW) {
|
||||||
return errorObject(0);
|
return errorObject(0);
|
||||||
}
|
}
|
||||||
Layer *window_layer = window_get_root_layer(accessPebbleObject(window)->window);
|
Layer* window_layer =
|
||||||
|
window_get_root_layer(accessPebbleObject(window)->window);
|
||||||
GRect bounds = layer_get_bounds(window_layer);
|
GRect bounds = layer_get_bounds(window_layer);
|
||||||
|
|
||||||
struct PLTextLayer *textLayer = malloc(sizeof(struct PLTextLayer));
|
struct PLTextLayer* textLayer = malloc(sizeof(struct PLTextLayer));
|
||||||
textLayer->text = calloc(sizeof(char), 100);
|
textLayer->text = calloc(sizeof(char), 100);
|
||||||
|
|
||||||
textLayer->layer = text_layer_create(bounds);
|
textLayer->layer = text_layer_create(bounds);
|
||||||
|
@ -98,29 +104,33 @@ Object addTextLayer(Object window, Object text, struct Environment *env) {
|
||||||
return pebbleOther(TEXT_LAYER, textLayer, NULL, NULL);
|
return pebbleOther(TEXT_LAYER, textLayer, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Object subscription;
|
Object subscription;
|
||||||
struct Environment *subscriptionEnv;
|
struct Environment* subscriptionEnv;
|
||||||
|
|
||||||
static void subscriptionHandler(struct tm *tick_time, TimeUnits changed) {
|
static void subscriptionHandler(struct tm* tick_time, TimeUnits changed)
|
||||||
|
{
|
||||||
eval(&subscription, subscriptionEnv);
|
eval(&subscription, subscriptionEnv);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object subscribe(Object function, Object time, struct Environment *env) {
|
Object subscribe(Object function, Object time, struct Environment* env)
|
||||||
if(function.type == TYPE_LAMBDA) {
|
{
|
||||||
|
if (function.type == TYPE_LAMBDA) {
|
||||||
subscription = cloneObject(function);
|
subscription = cloneObject(function);
|
||||||
subscriptionEnv = env;
|
subscriptionEnv = env;
|
||||||
int unit = time.type != TYPE_NUMBER ? MINUTE_UNIT :
|
int unit = time.type != TYPE_NUMBER ? MINUTE_UNIT
|
||||||
time.number == 1 ? SECOND_UNIT :
|
: time.number == 1 ? SECOND_UNIT
|
||||||
time.number == 2 ? MINUTE_UNIT :
|
: time.number == 2 ? MINUTE_UNIT
|
||||||
time.number == 3 ? HOUR_UNIT :
|
: time.number == 3 ? HOUR_UNIT
|
||||||
time.number == 4 ? DAY_UNIT :
|
: time.number == 4
|
||||||
time.number == 5 ? MONTH_UNIT :
|
? DAY_UNIT
|
||||||
time.number == 6 ? YEAR_UNIT :
|
: time.number ==
|
||||||
MINUTE_UNIT;
|
5 ? MONTH_UNIT
|
||||||
|
:
|
||||||
|
time.number ==
|
||||||
|
6 ? YEAR_UNIT
|
||||||
|
: MINUTE_UNIT;
|
||||||
tick_timer_service_subscribe(unit, subscriptionHandler);
|
tick_timer_service_subscribe(unit, subscriptionHandler);
|
||||||
return boolObject(1);
|
return boolObject(1);
|
||||||
}
|
}
|
||||||
return boolObject(0);
|
return boolObject(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,34 @@
|
||||||
#include <pebble.h>
|
#include <pebble.h>
|
||||||
|
|
||||||
#include "pebblisp.h"
|
#include "pebblisp.h"
|
||||||
|
|
||||||
enum PebbleType {
|
enum PebbleType {
|
||||||
WINDOW,
|
WINDOW, TEXT_LAYER, P_ERROR
|
||||||
TEXT_LAYER,
|
|
||||||
P_ERROR
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PLTextLayer {
|
struct PLTextLayer {
|
||||||
TextLayer *layer;
|
TextLayer* layer;
|
||||||
char *text;
|
char* text;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct PebbleObject PebbleObject;
|
typedef struct PebbleObject PebbleObject;
|
||||||
struct PebbleObject {
|
struct PebbleObject {
|
||||||
enum PebbleType type;
|
enum PebbleType type;
|
||||||
union {
|
union {
|
||||||
Window *window;
|
Window* window;
|
||||||
struct PLTextLayer *textLayer;
|
struct PLTextLayer* textLayer;
|
||||||
void *ptr;
|
void* ptr;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
Object createWindow(Object o1, Object o2, struct Environment *env);
|
Object createWindow(Object o1, Object o2, struct Environment* env);
|
||||||
Object deleteWindow(Object window, Object o2, struct Environment *env);
|
|
||||||
Object pushWindow(Object o1, Object o2, struct Environment *env);
|
Object deleteWindow(Object window, Object o2, struct Environment* env);
|
||||||
Object addTextLayer(Object window, Object text, struct Environment *env);
|
|
||||||
Object updateTextLayer(Object textLayer, Object text, struct Environment *env);
|
Object pushWindow(Object o1, Object o2, struct Environment* env);
|
||||||
Object subscribe(Object function, Object time, struct Environment *env);
|
|
||||||
|
Object addTextLayer(Object window, Object text, struct Environment* env);
|
||||||
|
|
||||||
|
Object updateTextLayer(Object textLayer, Object text, struct Environment* env);
|
||||||
|
|
||||||
|
Object subscribe(Object function, Object time, struct Environment* env);
|
||||||
|
|
423
src/pebblisp.c
423
src/pebblisp.c
|
@ -1,14 +1,12 @@
|
||||||
|
#pragma ide diagnostic ignored "misc-no-recursion"
|
||||||
|
|
||||||
#include "pebblisp.h"
|
#include "pebblisp.h"
|
||||||
#include "tokens.h"
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#ifndef STANDALONE
|
#include "tokens.h"
|
||||||
#undef printf
|
|
||||||
#define printf(...) APP_LOG(APP_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
|
||||||
#include <pebble.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a variable into the environment with a given name and value.
|
* Inserts a variable into the environment with a given name and value.
|
||||||
|
@ -21,16 +19,14 @@
|
||||||
* @param env The environment to add the new definition to
|
* @param env The environment to add the new definition to
|
||||||
* @return The symbol(s) defined
|
* @return The symbol(s) defined
|
||||||
*/
|
*/
|
||||||
Object evalDefArgs(
|
Object evalDefArgs(const Object* symbol, const Object* value,
|
||||||
const Object *symbol,
|
struct Environment* env)
|
||||||
const Object *value,
|
{
|
||||||
struct Environment *env
|
const char* name = symbol->string;
|
||||||
) {
|
|
||||||
const char *name = symbol->string;
|
|
||||||
|
|
||||||
// Handles multi-definitions
|
// Handles multi-definitions
|
||||||
if(bothAre(TYPE_LIST, symbol, value)
|
if (bothAre(TYPE_LIST, symbol, value) &&
|
||||||
&& listLength(symbol) == listLength(value)) {
|
listLength(symbol) == listLength(value)) {
|
||||||
FOR_POINTERS_IN_LISTS(symbol, value) {
|
FOR_POINTERS_IN_LISTS(symbol, value) {
|
||||||
Object finalValue = eval(P2, env);
|
Object finalValue = eval(P2, env);
|
||||||
addToEnv(env, P1->string, finalValue);
|
addToEnv(env, P1->string, finalValue);
|
||||||
|
@ -47,44 +43,43 @@ Object evalDefArgs(
|
||||||
return cloneObject(*symbol);
|
return cloneObject(*symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object evalIfArgs(const Object *argForms, struct Environment *env)
|
Object evalIfArgs(const Object* argForms, struct Environment* env)
|
||||||
{
|
{
|
||||||
Object condition = eval(argForms, env);
|
Object condition = eval(argForms, env);
|
||||||
Object result = condition.number ?
|
Object result = condition.number ? eval(argForms->forward, env)
|
||||||
eval(argForms->forward, env) :
|
: eval(argForms->forward->forward, env);
|
||||||
eval(argForms->forward->forward, env);
|
|
||||||
cleanObject(&condition);
|
cleanObject(&condition);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object evalLambdaArgs(const Object *argForms)
|
Object evalLambdaArgs(const Object* argForms)
|
||||||
{
|
{
|
||||||
return constructLambda(
|
return constructLambda(argForms, // Params
|
||||||
argForms, // Params
|
|
||||||
argForms ? argForms->forward : NULL // Body
|
argForms ? argForms->forward : NULL // Body
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object evalMapArgs(const Object *argForms, struct Environment *env)
|
Object evalMapArgs(const Object* argForms, struct Environment* env)
|
||||||
{
|
{
|
||||||
if(!argForms) {
|
if (!argForms) {
|
||||||
return errorObject(NULL_MAP_ARGS);
|
return errorObject(NULL_MAP_ARGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object lambda = eval(argForms, env);
|
Object lambda = eval(argForms, env);
|
||||||
const Object *inputList = argForms->forward;
|
const Object* inputList = argForms->forward;
|
||||||
Object outputList = listObject();
|
Object outputList = listObject();
|
||||||
|
|
||||||
if(lambda.type != TYPE_LAMBDA) {
|
if (lambda.type != TYPE_LAMBDA) {
|
||||||
return errorObject(BAD_TYPE);
|
return errorObject(BAD_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inputList) {
|
||||||
FOR_POINTER_IN_LIST(inputList) {
|
FOR_POINTER_IN_LIST(inputList) {
|
||||||
// Create a new list for each element,
|
// Create a new list for each element,
|
||||||
// since lambda evaluation looks for a list
|
// since lambda evaluation looks for a list
|
||||||
Object tempList = startList(cloneObject(*POINTER));
|
Object tempList = startList(cloneObject(*POINTER));
|
||||||
|
|
||||||
Object *params = &lambda.lambda->params;
|
Object* params = &lambda.lambda->params;
|
||||||
struct Environment newEnv = envForLambda(params, &tempList, env);
|
struct Environment newEnv = envForLambda(params, &tempList, env);
|
||||||
|
|
||||||
// Add the lambda evaluation to the list
|
// Add the lambda evaluation to the list
|
||||||
|
@ -95,32 +90,33 @@ Object evalMapArgs(const Object *argForms, struct Environment *env)
|
||||||
cleanObject(&tempList);
|
cleanObject(&tempList);
|
||||||
cleanObject(&lambda_output);
|
cleanObject(&lambda_output);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
cleanObject(&lambda);
|
cleanObject(&lambda);
|
||||||
|
|
||||||
return outputList;
|
return outputList;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object evalBuiltIns(const Object *first, const Object *rest,
|
Object evalBuiltIns(const Object* first, const Object* rest,
|
||||||
struct Environment *env)
|
struct Environment* env)
|
||||||
{
|
{
|
||||||
if(first->type != TYPE_SYMBOL) {
|
if (first->type != TYPE_SYMBOL) {
|
||||||
return errorObject(NOT_A_SYMBOL);
|
return errorObject(NOT_A_SYMBOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strcmp(first->string, "def") == 0) {
|
if (strcmp(first->string, "def") == 0) {
|
||||||
return evalDefArgs(rest, rest->forward, env);
|
return evalDefArgs(rest, rest->forward, env);
|
||||||
#ifndef LOW_MEM
|
#ifndef LOW_MEM
|
||||||
} else if(strcmp(first->string, "defe") == 0) {
|
} else if (strcmp(first->string, "defe") == 0) {
|
||||||
Object symbol = eval(rest, env);
|
Object symbol = eval(rest, env);
|
||||||
Object e = evalDefArgs(&symbol, rest->forward, env);
|
Object e = evalDefArgs(&symbol, rest->forward, env);
|
||||||
cleanObject(&symbol);
|
cleanObject(&symbol);
|
||||||
return e;
|
return e;
|
||||||
#endif
|
#endif
|
||||||
} else if(strcmp(first->string, "if") == 0) {
|
} else if (strcmp(first->string, "if") == 0) {
|
||||||
return evalIfArgs(rest, env);
|
return evalIfArgs(rest, env);
|
||||||
} else if(strcmp(first->string, "fn") == 0) {
|
} else if (strcmp(first->string, "fn") == 0) {
|
||||||
return evalLambdaArgs(rest);
|
return evalLambdaArgs(rest);
|
||||||
} else if(strcmp(first->string, "map") == 0) {
|
} else if (strcmp(first->string, "map") == 0) {
|
||||||
return evalMapArgs(rest, env);
|
return evalMapArgs(rest, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,10 +134,10 @@ Object evalBuiltIns(const Object *first, const Object *rest,
|
||||||
* @param start The Object element to start with
|
* @param start The Object element to start with
|
||||||
* @param env The environment to use while evaluating
|
* @param env The environment to use while evaluating
|
||||||
*/
|
*/
|
||||||
void evalForms(Object *destArr, const Object *start, struct Environment *env)
|
void evalForms(Object* destArr, const Object* start, struct Environment* env)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(start) {
|
while (start) {
|
||||||
destArr[i] = eval(start, env);
|
destArr[i] = eval(start, env);
|
||||||
start = start->forward;
|
start = start->forward;
|
||||||
i++;
|
i++;
|
||||||
|
@ -159,13 +155,10 @@ void evalForms(Object *destArr, const Object *start, struct Environment *env)
|
||||||
* @param length Length of `list` - 1, to exclude the already-evaluated element
|
* @param length Length of `list` - 1, to exclude the already-evaluated element
|
||||||
* @param env The environment to evaluate in
|
* @param env The environment to evaluate in
|
||||||
*/
|
*/
|
||||||
Object listEvalFunc(
|
Object listEvalFunc(const Object* list, const Object* function,
|
||||||
const Object *list,
|
const int length, struct Environment* env)
|
||||||
const Object *function,
|
|
||||||
const int length,
|
|
||||||
struct Environment *env)
|
|
||||||
{
|
{
|
||||||
if(length == 0) {
|
if (length == 0) {
|
||||||
return function->func(boolObject(0), boolObject(0), env);
|
return function->func(boolObject(0), boolObject(0), env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,10 +166,9 @@ Object listEvalFunc(
|
||||||
evalForms(rest, list->list->forward, env);
|
evalForms(rest, list->list->forward, env);
|
||||||
|
|
||||||
Object func_result = rest[0];
|
Object func_result = rest[0];
|
||||||
if(length == 1) {
|
if (length == 1) {
|
||||||
Object oneArg = errorObject(ONLY_ONE_ARGUMENT);
|
Object oneArg = errorObject(ONLY_ONE_ARGUMENT);
|
||||||
func_result = function->func(
|
func_result = function->func(func_result, oneArg, env);
|
||||||
func_result, oneArg, env);
|
|
||||||
// Return a partial function if more parameters are required
|
// Return a partial function if more parameters are required
|
||||||
// Otherwise, return the function result
|
// Otherwise, return the function result
|
||||||
cleanObject(&rest[0]);
|
cleanObject(&rest[0]);
|
||||||
|
@ -192,7 +184,7 @@ Object listEvalFunc(
|
||||||
} else {
|
} else {
|
||||||
// With two args, will apply function once
|
// With two args, will apply function once
|
||||||
// With more than two args, apply the function repeatedly
|
// With more than two args, apply the function repeatedly
|
||||||
for(int i = 1; i < length; i++) {
|
for (int i = 1; i < length; i++) {
|
||||||
Object toClean = func_result;
|
Object toClean = func_result;
|
||||||
func_result = function->func(func_result, rest[i], env);
|
func_result = function->func(func_result, rest[i], env);
|
||||||
cleanObject(&toClean);
|
cleanObject(&toClean);
|
||||||
|
@ -212,23 +204,18 @@ Object listEvalFunc(
|
||||||
* @param remaining The first element after `lambda`
|
* @param remaining The first element after `lambda`
|
||||||
* @param env The environment to evaluate in
|
* @param env The environment to evaluate in
|
||||||
*/
|
*/
|
||||||
Object listEvalLambda(
|
Object listEvalLambda(Object* lambda, const Object* remaining,
|
||||||
Object *lambda,
|
struct Environment* env)
|
||||||
const Object *remaining,
|
{
|
||||||
struct Environment *env
|
struct Environment newEnv =
|
||||||
) {
|
envForLambda(&lambda->lambda->params, remaining, env);
|
||||||
struct Environment newEnv = envForLambda(
|
|
||||||
&lambda->lambda->params,
|
|
||||||
remaining,
|
|
||||||
env
|
|
||||||
);
|
|
||||||
Object ret = eval(&lambda->lambda->body, &newEnv);
|
Object ret = eval(&lambda->lambda->body, &newEnv);
|
||||||
|
|
||||||
deleteEnv(&newEnv);
|
deleteEnv(&newEnv);
|
||||||
cleanObject(lambda);
|
cleanObject(lambda);
|
||||||
|
|
||||||
Object *t = tail(&ret);
|
Object* t = tail(&ret);
|
||||||
if(t) {
|
if (t) {
|
||||||
Object o = cloneObject(*t);
|
Object o = cloneObject(*t);
|
||||||
cleanObject(&ret);
|
cleanObject(&ret);
|
||||||
return o;
|
return o;
|
||||||
|
@ -250,20 +237,20 @@ Object listEvalLambda(
|
||||||
* @param obj The list to be evaluated
|
* @param obj The list to be evaluated
|
||||||
* @param env The environment to evaluate in
|
* @param env The environment to evaluate in
|
||||||
*/
|
*/
|
||||||
Object evalList(const Object *obj, struct Environment *env)
|
Object evalList(const Object* obj, struct Environment* env)
|
||||||
{
|
{
|
||||||
const int evalLength = listLength(obj);
|
const int evalLength = listLength(obj);
|
||||||
|
|
||||||
if(evalLength == 0) {
|
if (evalLength == 0) {
|
||||||
return cloneObject(*obj);
|
return cloneObject(*obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *first_form = obj->list;
|
Object* first_form = obj->list;
|
||||||
|
|
||||||
{ // Try to eval built-ins
|
{ // Try to eval built-ins
|
||||||
Object builtIn = evalBuiltIns(first_form, first_form->forward, env);
|
Object builtIn = evalBuiltIns(first_form, first_form->forward, env);
|
||||||
|
|
||||||
if(!isError(builtIn, BUILT_IN_NOT_FOUND) &&
|
if (!isError(builtIn, BUILT_IN_NOT_FOUND) &&
|
||||||
!isError(builtIn, NOT_A_SYMBOL)) {
|
!isError(builtIn, NOT_A_SYMBOL)) {
|
||||||
return builtIn;
|
return builtIn;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +259,7 @@ Object evalList(const Object *obj, struct Environment *env)
|
||||||
|
|
||||||
// Evaluate the list based on the first element's type
|
// Evaluate the list based on the first element's type
|
||||||
Object first_eval = eval(first_form, env);
|
Object first_eval = eval(first_form, env);
|
||||||
switch(first_eval.type) {
|
switch (first_eval.type) {
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
// Passes evalLength - 1, because we skip the first form
|
// Passes evalLength - 1, because we skip the first form
|
||||||
return listEvalFunc(obj, &first_eval, evalLength - 1, env);
|
return listEvalFunc(obj, &first_eval, evalLength - 1, env);
|
||||||
|
@ -285,7 +272,7 @@ Object evalList(const Object *obj, struct Environment *env)
|
||||||
int i = 0;
|
int i = 0;
|
||||||
nf_addToList(&list, first_eval);
|
nf_addToList(&list, first_eval);
|
||||||
FOR_POINTER_IN_LIST(obj) {
|
FOR_POINTER_IN_LIST(obj) {
|
||||||
if(i != 0) {
|
if (i != 0) {
|
||||||
nf_addToList(&list, eval(POINTER, env));
|
nf_addToList(&list, eval(POINTER, env));
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
|
@ -295,9 +282,9 @@ Object evalList(const Object *obj, struct Environment *env)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object eval(const Object *obj, struct Environment *env)
|
Object eval(const Object* obj, struct Environment* env)
|
||||||
{
|
{
|
||||||
switch(obj->type) {
|
switch (obj->type) {
|
||||||
case TYPE_FUNC:
|
case TYPE_FUNC:
|
||||||
case TYPE_ERROR:
|
case TYPE_ERROR:
|
||||||
case TYPE_OTHER:
|
case TYPE_OTHER:
|
||||||
|
@ -325,7 +312,7 @@ Object eval(const Object *obj, struct Environment *env)
|
||||||
return errorObject(BAD_TYPE);
|
return errorObject(BAD_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object catObjects(const Object obj1, const Object obj2, struct Environment *env)
|
Object catObjects(const Object obj1, const Object obj2, struct Environment* env)
|
||||||
{
|
{
|
||||||
Object evalObj1 = eval(&obj1, env);
|
Object evalObj1 = eval(&obj1, env);
|
||||||
Object evalObj2 = eval(&obj2, env);
|
Object evalObj2 = eval(&obj2, env);
|
||||||
|
@ -346,25 +333,25 @@ Object catObjects(const Object obj1, const Object obj2, struct Environment *env)
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object listEquality(const Object *list1, const Object *list2)
|
Object listEquality(const Object* list1, const Object* list2)
|
||||||
{
|
{
|
||||||
FOR_POINTERS_IN_LISTS(list1, list2) {
|
FOR_POINTERS_IN_LISTS(list1, list2) {
|
||||||
if(P1->type != P2->type || P1->number != P2->number) {
|
if (P1->type != P2->type || P1->number != P2->number) {
|
||||||
return boolObject(0);
|
return boolObject(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return boolObject(1);
|
return boolObject(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object _basicOp(const Object *obj1, const Object *obj2, const char op,
|
Object _basicOp(const Object* obj1, const Object* obj2, const char op,
|
||||||
struct Environment *env)
|
struct Environment* env)
|
||||||
{
|
{
|
||||||
const int n1 = obj1->number;
|
const int n1 = obj1->number;
|
||||||
const int n2 = obj2->number;
|
const int n2 = obj2->number;
|
||||||
|
|
||||||
switch(op){
|
switch (op) {
|
||||||
case '+':
|
case '+':
|
||||||
if(eitherIs(TYPE_STRING, obj1, obj2)) {
|
if (eitherIs(TYPE_STRING, obj1, obj2)) {
|
||||||
return catObjects(*obj1, *obj2, env);
|
return catObjects(*obj1, *obj2, env);
|
||||||
}
|
}
|
||||||
return numberObject(n1 + n2);
|
return numberObject(n1 + n2);
|
||||||
|
@ -377,11 +364,16 @@ Object _basicOp(const Object *obj1, const Object *obj2, const char op,
|
||||||
case '%':
|
case '%':
|
||||||
return numberObject(n1 % n2);
|
return numberObject(n1 % n2);
|
||||||
|
|
||||||
|
case '&':
|
||||||
|
return boolObject(n1 != 0 && n2 != 0);
|
||||||
|
case '|':
|
||||||
|
return boolObject(n1 != 0 || n2 != 0);
|
||||||
|
|
||||||
case '=':
|
case '=':
|
||||||
if(bothAre(TYPE_STRING, obj1, obj2)) {
|
if (bothAre(TYPE_STRING, obj1, obj2)) {
|
||||||
return boolObject(!strcmp(obj1->string, obj2->string));
|
return boolObject(!strcmp(obj1->string, obj2->string));
|
||||||
}
|
}
|
||||||
if(bothAre(TYPE_LIST, obj1, obj2)) {
|
if (bothAre(TYPE_LIST, obj1, obj2)) {
|
||||||
return listEquality(obj1, obj2);
|
return listEquality(obj1, obj2);
|
||||||
}
|
}
|
||||||
return boolObject(n1 == n2 && areSameType(obj1, obj2));
|
return boolObject(n1 == n2 && areSameType(obj1, obj2));
|
||||||
|
@ -394,20 +386,21 @@ Object _basicOp(const Object *obj1, const Object *obj2, const char op,
|
||||||
return *obj1;
|
return *obj1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object basicOp(const Object *obj1, const Object *obj2, const char op,
|
Object basicOp(const Object* obj1, const Object* obj2, const char op,
|
||||||
struct Environment *env)
|
struct Environment* env)
|
||||||
{
|
{
|
||||||
if(isError(*obj2, ONLY_ONE_ARGUMENT)) {
|
if (isError(*obj2, ONLY_ONE_ARGUMENT)) {
|
||||||
return *obj2;
|
return *obj2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST);
|
int lists = (obj1->type == TYPE_LIST) + (obj2->type == TYPE_LIST);
|
||||||
if(lists == 0) {
|
if (lists == 0) {
|
||||||
return _basicOp(obj1, obj2, op, env);
|
return _basicOp(obj1, obj2, op, env);
|
||||||
|
|
||||||
} else if(lists == 1) { // Single operand is applied to each element in list
|
} else if (lists ==
|
||||||
const Object *listObj = (obj1->type == TYPE_LIST)? obj1 : obj2;
|
1) { // Single operand is applied to each element in list
|
||||||
const Object *singleObj = (obj1->type == TYPE_LIST)? obj2 : obj1;
|
const Object* listObj = (obj1->type == TYPE_LIST) ? obj1 : obj2;
|
||||||
|
const Object* singleObj = (obj1->type == TYPE_LIST) ? obj2 : obj1;
|
||||||
|
|
||||||
Object newList = listObject();
|
Object newList = listObject();
|
||||||
FOR_POINTER_IN_LIST(listObj) {
|
FOR_POINTER_IN_LIST(listObj) {
|
||||||
|
@ -417,7 +410,7 @@ Object basicOp(const Object *obj1, const Object *obj2, const char op,
|
||||||
return newList;
|
return newList;
|
||||||
|
|
||||||
} else { // 2 lists with the op applied to matching indices of both lists
|
} else { // 2 lists with the op applied to matching indices of both lists
|
||||||
if(listLength(obj1) == listLength(obj2)) {
|
if (listLength(obj1) == listLength(obj2)) {
|
||||||
Object newList = listObject();
|
Object newList = listObject();
|
||||||
FOR_POINTERS_IN_LISTS(obj1, obj2) {
|
FOR_POINTERS_IN_LISTS(obj1, obj2) {
|
||||||
const Object ev1 = eval(P1, env);
|
const Object ev1 = eval(P1, env);
|
||||||
|
@ -432,44 +425,57 @@ Object basicOp(const Object *obj1, const Object *obj2, const char op,
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BASIC_OP(_name, _char) \
|
#define BASIC_OP(_name, _char) \
|
||||||
Object _name(Object obj1, Object obj2, struct Environment *env) \
|
Object _name(Object obj1, Object obj2, struct Environment *env) \
|
||||||
{ return basicOp(&obj1, &obj2, _char, env); }
|
{ \
|
||||||
|
return basicOp(&obj1, &obj2, _char, env); \
|
||||||
|
}
|
||||||
|
|
||||||
BASIC_OP(add, '+');
|
BASIC_OP(add, '+');
|
||||||
|
|
||||||
BASIC_OP(sub, '-');
|
BASIC_OP(sub, '-');
|
||||||
|
|
||||||
BASIC_OP(mul, '*');
|
BASIC_OP(mul, '*');
|
||||||
|
|
||||||
BASIC_OP(dvi, '/');
|
BASIC_OP(dvi, '/');
|
||||||
|
|
||||||
BASIC_OP(mod, '%');
|
BASIC_OP(mod, '%');
|
||||||
|
|
||||||
BASIC_OP(equ, '=');
|
BASIC_OP(equ, '=');
|
||||||
|
|
||||||
BASIC_OP(gth, '>');
|
BASIC_OP(gth, '>');
|
||||||
|
|
||||||
BASIC_OP(lth, '<');
|
BASIC_OP(lth, '<');
|
||||||
|
|
||||||
|
BASIC_OP(and, '&');
|
||||||
|
|
||||||
|
BASIC_OP(or, '|');
|
||||||
|
|
||||||
#undef BASIC_OP
|
#undef BASIC_OP
|
||||||
|
|
||||||
Object filter(Object obj1, Object obj2, struct Environment *env)
|
Object filter(Object obj1, Object obj2, struct Environment* env)
|
||||||
{
|
{
|
||||||
Object filteredList = listObject();
|
Object filteredList = listObject();
|
||||||
Object *filteringList = &obj2;
|
Object* filteringList = &obj2;
|
||||||
FOR_POINTER_IN_LIST(filteringList) {
|
FOR_POINTER_IN_LIST(filteringList) {
|
||||||
Object conditional = cloneObject(obj1);
|
Object conditional = cloneObject(obj1);
|
||||||
nf_addToList(&conditional, *POINTER); // cloneObject()?
|
nf_addToList(&conditional, *POINTER); // cloneObject()?
|
||||||
Object result = eval(&conditional, env);
|
Object result = eval(&conditional, env);
|
||||||
cleanObject(&conditional);
|
cleanObject(&conditional);
|
||||||
if(result.number == 1) {
|
if (result.number == 1) {
|
||||||
nf_addToList(&filteredList, *POINTER);
|
nf_addToList(&filteredList, *POINTER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return filteredList;
|
return filteredList;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object append(Object list, Object newElement, struct Environment *env)
|
Object append(Object list, Object newElement, struct Environment* env)
|
||||||
{
|
{
|
||||||
Object newList = cloneObject(list);
|
Object newList = cloneObject(list);
|
||||||
nf_addToList(&newList, cloneObject(newElement));
|
nf_addToList(&newList, cloneObject(newElement));
|
||||||
return newList;
|
return newList;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object prepend(Object list, Object newElement, struct Environment *env)
|
Object prepend(Object list, Object newElement, struct Environment* env)
|
||||||
{
|
{
|
||||||
Object newList = listObject();
|
Object newList = listObject();
|
||||||
nf_addToList(&newList, cloneObject(newElement));
|
nf_addToList(&newList, cloneObject(newElement));
|
||||||
|
@ -477,22 +483,22 @@ Object prepend(Object list, Object newElement, struct Environment *env)
|
||||||
return newList;
|
return newList;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object at(Object index, Object list, struct Environment *env)
|
Object at(Object index, Object list, struct Environment* env)
|
||||||
{
|
{
|
||||||
const Object *found = itemAt(&list, index.number);
|
const Object* found = itemAt(&list, index.number);
|
||||||
if(found) {
|
if (found) {
|
||||||
return cloneObject(*found);
|
return cloneObject(*found);
|
||||||
} else {
|
} else {
|
||||||
return errorObject(INDEX_PAST_END);
|
return errorObject(INDEX_PAST_END);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object rest(Object list, Object ignore, struct Environment *env)
|
Object rest(Object list, Object ignore, struct Environment* env)
|
||||||
{
|
{
|
||||||
Object ret = listObject();
|
Object ret = listObject();
|
||||||
Object *l = &list;
|
Object* l = &list;
|
||||||
FOR_POINTER_IN_LIST(l) {
|
FOR_POINTER_IN_LIST(l) {
|
||||||
if(POINTER == l->list) {
|
if (POINTER == l->list) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
nf_addToList(&ret, cloneObject(*POINTER));
|
nf_addToList(&ret, cloneObject(*POINTER));
|
||||||
|
@ -500,16 +506,16 @@ Object rest(Object list, Object ignore, struct Environment *env)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object reverse(Object _list, Object ignore, struct Environment *ignore2)
|
Object reverse(Object _list, Object ignore, struct Environment* ignore2)
|
||||||
{
|
{
|
||||||
const Object *list = &_list;
|
const Object* list = &_list;
|
||||||
Object rev = listObject();
|
Object rev = listObject();
|
||||||
|
|
||||||
Object *tail = NULL;
|
Object* tail = NULL;
|
||||||
FOR_POINTER_IN_LIST(list) {
|
FOR_POINTER_IN_LIST(list) {
|
||||||
Object *oldTail = tail;
|
Object* oldTail = tail;
|
||||||
allocObject(&tail, cloneObject(*POINTER));
|
allocObject(&tail, cloneObject(*POINTER));
|
||||||
if(oldTail) {
|
if (oldTail) {
|
||||||
tail->forward = oldTail;
|
tail->forward = oldTail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,33 +524,30 @@ Object reverse(Object _list, Object ignore, struct Environment *ignore2)
|
||||||
return rev;
|
return rev;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object isNum(Object test, Object ignore, struct Environment *ignore2)
|
Object isNum(Object test, Object ignore, struct Environment* ignore2)
|
||||||
{
|
{
|
||||||
return test.type == TYPE_NUMBER ?
|
return test.type == TYPE_NUMBER ? boolObject(1) : boolObject(0);
|
||||||
boolObject(1) : boolObject(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object isString(Object test, Object ignore, struct Environment *ignore2)
|
Object isString(Object test, Object ignore, struct Environment* ignore2)
|
||||||
{
|
{
|
||||||
return test.type == TYPE_STRING ?
|
return test.type == TYPE_STRING ? boolObject(1) : boolObject(0);
|
||||||
boolObject(1) : boolObject(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the int value of a string's first character
|
// Get the int value of a string's first character
|
||||||
Object charVal(Object test, Object ignore, struct Environment *ignore2)
|
Object charVal(Object test, Object ignore, struct Environment* ignore2)
|
||||||
{
|
{
|
||||||
return numberObject(test.string[0]);
|
return numberObject(test.string[0]);
|
||||||
// return test.type == TYPE_STRING && test.string[0] == '\0' ?
|
// return test.type == TYPE_STRING && test.string[0] == '\0' ?
|
||||||
// boolObject(1) : boolObject(0);
|
// boolObject(1) : boolObject(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object isErr(Object test, Object ignore, struct Environment *ignore2)
|
Object isErr(Object test, Object ignore, struct Environment* ignore2)
|
||||||
{
|
{
|
||||||
return test.type == TYPE_ERROR ?
|
return test.type == TYPE_ERROR ? boolObject(1) : boolObject(0);
|
||||||
boolObject(1) : boolObject(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object charAt(Object string, Object at, struct Environment *ignore)
|
Object charAt(Object string, Object at, struct Environment* ignore)
|
||||||
{
|
{
|
||||||
char* c = malloc(sizeof(char) * 2);
|
char* c = malloc(sizeof(char) * 2);
|
||||||
c[0] = string.string[at.number];
|
c[0] = string.string[at.number];
|
||||||
|
@ -554,7 +557,8 @@ Object charAt(Object string, Object at, struct Environment *ignore)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
Object print(Object p, Object ignore, struct Environment *env)
|
|
||||||
|
Object print(Object p, Object ignore, struct Environment* env)
|
||||||
{
|
{
|
||||||
p = cloneObject(p);
|
p = cloneObject(p);
|
||||||
p = eval(&p, env);
|
p = eval(&p, env);
|
||||||
|
@ -562,67 +566,71 @@ Object print(Object p, Object ignore, struct Environment *env)
|
||||||
return numberObject(0);
|
return numberObject(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object pChar(Object c, Object i1, struct Environment *i2)
|
Object pChar(Object c, Object i1, struct Environment* i2)
|
||||||
{
|
{
|
||||||
if(c.type != TYPE_NUMBER) {
|
if (c.type != TYPE_NUMBER) {
|
||||||
return errorObject(BAD_NUMBER);
|
return errorObject(BAD_NUMBER);
|
||||||
}
|
}
|
||||||
printf("%c", c.number % 256);
|
printf("%c", c.number % 256);
|
||||||
return numberObject(0);
|
return numberObject(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object printEnvO(Object i1, Object i2, struct Environment *env) {
|
Object printEnvO(Object i1, Object i2, struct Environment* env)
|
||||||
while(env->outer) {
|
{
|
||||||
env = env-> outer;
|
while (env->outer) {
|
||||||
|
env = env->outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
printEnv(env);
|
printEnv(env);
|
||||||
return numberObject(0);
|
return numberObject(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Object parseEvalO(Object text, Object ignore, struct Environment *env)
|
Object parseEvalO(Object text, Object ignore, struct Environment* env)
|
||||||
{
|
{
|
||||||
if(text.type == TYPE_SYMBOL) {
|
if (text.type == TYPE_SYMBOL) {
|
||||||
Object string = eval(&text, env);
|
Object string = eval(&text, env);
|
||||||
Object parsed = parseEval(string.string, env);
|
Object parsed = parseEval(string.string, env);
|
||||||
cleanObject(&string);
|
cleanObject(&string);
|
||||||
return parsed;
|
return parsed;
|
||||||
} else if(text.type != TYPE_STRING) {
|
} else if (text.type != TYPE_STRING) {
|
||||||
return errorObject(CAN_ONLY_EVAL_STRINGS);
|
return errorObject(CAN_ONLY_EVAL_STRINGS);
|
||||||
}
|
}
|
||||||
return parseEval(text.string, env);
|
return parseEval(text.string, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
Object takeInput(Object i1, Object i2, struct Environment *i3)
|
|
||||||
|
Object takeInput(Object i1, Object i2, struct Environment* i3)
|
||||||
{
|
{
|
||||||
char input[256] = "";
|
char input[256] = "";
|
||||||
fgets(input, 256, stdin);
|
fgets(input, 256, stdin);
|
||||||
return stringFromSlice(input, strlen(input) - 1);
|
return stringFromSlice(input, strlen(input) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void copySlice(char * dest, struct Slice *src)
|
void copySlice(char* dest, struct Slice* src)
|
||||||
{
|
{
|
||||||
if(!dest || !src) {
|
if (!dest || !src) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
strncpy(dest, src->text, src->length);
|
strncpy(dest, src->text, src->length);
|
||||||
dest[(int)src->length] = '\0';
|
dest[(int) src->length] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void debugSlice(struct Slice *s)
|
void debugSlice(struct Slice* s)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if(!s) {
|
if (!s) {
|
||||||
printf("NULL SLICE\n");
|
printf("NULL SLICE\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printf("Debug Slice\n text:'");
|
printf("Debug Slice\n text:'");
|
||||||
for(int i = 0; i < s->length; i++) {
|
for (int i = 0; i < s->length; i++) {
|
||||||
printf("%c", s->text[i]);
|
printf("%c", s->text[i]);
|
||||||
if(s->text[i] == '\0') {
|
if (s->text[i] == '\0') {
|
||||||
printf("NULLCHAR\n");
|
printf("NULLCHAR\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -631,37 +639,37 @@ void debugSlice(struct Slice *s)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Result parse(struct Slice *slices)
|
Result parse(struct Slice* slices)
|
||||||
{
|
{
|
||||||
struct Slice *token = slices;
|
struct Slice* token = slices;
|
||||||
if(token && token->text) {
|
if (token && token->text) {
|
||||||
struct Slice *rest = &slices[1];
|
struct Slice* rest = &slices[1];
|
||||||
if(token->text[0] == '\'' && token->text[1] == '(') {
|
if (token->text[0] == '\'' && token->text[1] == '(') {
|
||||||
Result r = readSeq(&slices[2]);
|
Result r = readSeq(&slices[2]);
|
||||||
r.obj.type = TYPE_SLIST;
|
r.obj.type = TYPE_SLIST;
|
||||||
return r;
|
return r;
|
||||||
} else if(token->text[0] == '(') {
|
} else if (token->text[0] == '(') {
|
||||||
// todo check for null rest
|
// todo check for null rest
|
||||||
return readSeq(rest);
|
return readSeq(rest);
|
||||||
} else { // todo error on missing close paren
|
} else { // todo error on missing close paren
|
||||||
return (Result){parseAtom(token), rest};
|
return (Result) {parseAtom(token), rest};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return (Result){errorObject(NULL_PARSE), NULL};
|
return (Result) {errorObject(NULL_PARSE), NULL};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result readSeq(struct Slice *tokens)
|
Result readSeq(struct Slice* tokens)
|
||||||
{
|
{
|
||||||
Object res = listObject();
|
Object res = listObject();
|
||||||
for(;;) {
|
for (;;) {
|
||||||
struct Slice *next = tokens;
|
struct Slice* next = tokens;
|
||||||
struct Slice *rest = next->text? &next[1] : NULL;
|
struct Slice* rest = next->text ? &next[1] : NULL;
|
||||||
if(next->text[0] == ')') {
|
if (next->text[0] == ')') {
|
||||||
return (Result){res, rest};
|
return (Result) {res, rest};
|
||||||
}
|
}
|
||||||
Result r = parse(tokens);
|
Result r = parse(tokens);
|
||||||
if(r.obj.type == TYPE_ERROR) {
|
if (r.obj.type == TYPE_ERROR) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
nf_addToList(&res, cloneObject(r.obj));
|
nf_addToList(&res, cloneObject(r.obj));
|
||||||
|
@ -670,11 +678,11 @@ Result readSeq(struct Slice *tokens)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object parseDecimal(struct Slice *s)
|
Object parseDecimal(struct Slice* s)
|
||||||
{
|
{
|
||||||
int num = 0;
|
int num = 0;
|
||||||
for(int i = 0; i < s->length; i++) {
|
for (int i = 0; i < s->length; i++) {
|
||||||
if(!isDigit(s->text[i])) {
|
if (!isDigit(s->text[i])) {
|
||||||
return errorObject(BAD_NUMBER);
|
return errorObject(BAD_NUMBER);
|
||||||
}
|
}
|
||||||
num *= 10;
|
num *= 10;
|
||||||
|
@ -683,16 +691,16 @@ Object parseDecimal(struct Slice *s)
|
||||||
return numberObject(num);
|
return numberObject(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object parseHex(struct Slice *s)
|
Object parseHex(struct Slice* s)
|
||||||
{
|
{
|
||||||
int num = 0;
|
int num = 0;
|
||||||
for(int i = 2; i < s->length; i++) {
|
for (int i = 2; i < s->length; i++) {
|
||||||
const char c = s->text[i];
|
const char c = s->text[i];
|
||||||
if(!isHex(c)) {
|
if (!isHex(c)) {
|
||||||
return errorObject(BAD_NUMBER);
|
return errorObject(BAD_NUMBER);
|
||||||
}
|
}
|
||||||
num *= 16;
|
num *= 16;
|
||||||
if(isDigit(c)) {
|
if (isDigit(c)) {
|
||||||
num += c - '0';
|
num += c - '0';
|
||||||
} else /* is hex */ {
|
} else /* is hex */ {
|
||||||
num += c - 'a' + 10;
|
num += c - 'a' + 10;
|
||||||
|
@ -701,12 +709,12 @@ Object parseHex(struct Slice *s)
|
||||||
return numberObject(num);
|
return numberObject(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object parseBin(struct Slice *s)
|
Object parseBin(struct Slice* s)
|
||||||
{
|
{
|
||||||
int num = 0;
|
int num = 0;
|
||||||
for(int i = 2; i < s->length; i++) {
|
for (int i = 2; i < s->length; i++) {
|
||||||
const char c = s->text[i];
|
const char c = s->text[i];
|
||||||
if(c != '0' && c != '1') {
|
if (c != '0' && c != '1') {
|
||||||
return errorObject(BAD_NUMBER);
|
return errorObject(BAD_NUMBER);
|
||||||
}
|
}
|
||||||
num *= 2;
|
num *= 2;
|
||||||
|
@ -715,18 +723,18 @@ Object parseBin(struct Slice *s)
|
||||||
return numberObject(num);
|
return numberObject(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object parseAtom(struct Slice *s)
|
Object parseAtom(struct Slice* s)
|
||||||
{
|
{
|
||||||
const char c = s->text[0];
|
const char c = s->text[0];
|
||||||
if(isDigit(c)) {
|
if (isDigit(c)) {
|
||||||
if(c != '0' || s->length == 1) {
|
if (c != '0' || s->length == 1) {
|
||||||
return parseDecimal(s);
|
return parseDecimal(s);
|
||||||
#ifndef LOW_MEM
|
#ifndef LOW_MEM
|
||||||
} else if(c == '0' && s->text[1] == 'x') {
|
} else if (c == '0' && s->text[1] == 'x') {
|
||||||
return parseHex(s);
|
return parseHex(s);
|
||||||
} else if(c == '0' && s->text[1] == 'b') {
|
} else if (c == '0' && s->text[1] == 'b') {
|
||||||
return parseBin(s);
|
return parseBin(s);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
return errorObject(UNSUPPORTED_NUMBER_TYPE);
|
return errorObject(UNSUPPORTED_NUMBER_TYPE);
|
||||||
}
|
}
|
||||||
|
@ -741,52 +749,52 @@ Object parseAtom(struct Slice *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object parseEval(const char *input, struct Environment *env)
|
Object parseEval(const char* input, struct Environment* env)
|
||||||
{
|
{
|
||||||
struct Error err = noError();
|
struct Error err = noError();
|
||||||
|
|
||||||
struct Slice *tokens = nf_tokenize(input, &err);
|
struct Slice* tokens = nf_tokenize(input, &err);
|
||||||
if(err.context != NULL) {
|
if (err.context != NULL) {
|
||||||
Object o = errorWithContext(err.code, err.context);
|
Object o = errorWithContext(err.code, err.context);
|
||||||
free(err.context);
|
free(err.context);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
if(!tokens->text) {
|
if (!tokens->text) {
|
||||||
return symFromSlice(" ", 1);
|
return symFromSlice(" ", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
struct Slice *debug = tokens;
|
struct Slice *debug = tokens;
|
||||||
printd("start slice\n");
|
printd("start slice\n");
|
||||||
if(debug) {
|
if (debug) {
|
||||||
while(debug->text) {
|
while (debug->text) {
|
||||||
char tok[100];
|
char tok[100];
|
||||||
copySlice(tok, debug);
|
copySlice(tok, debug);
|
||||||
printd("slice: '%s'\n", tok);
|
printd("slice: '%s'\n", tok);
|
||||||
debug++;
|
debug++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int parens = 0;
|
int parens = 0;
|
||||||
Object obj = numberObject(0);
|
Object obj = numberObject(0);
|
||||||
struct Slice *tok = tokens;
|
struct Slice* tok = tokens;
|
||||||
while(tok[i].text != NULL) {
|
while (tok[i].text != NULL) {
|
||||||
if(tok[i].text[0] == '(') {
|
if (tok[i].text[0] == '(') {
|
||||||
parens++;
|
parens++;
|
||||||
} else if(tok[i].text[0] == ')') {
|
} else if (tok[i].text[0] == ')') {
|
||||||
parens--;
|
parens--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(parens == 0) {
|
if (parens == 0) {
|
||||||
cleanObject(&obj);
|
cleanObject(&obj);
|
||||||
Object parsed = parse(tok).obj;
|
Object parsed = parse(tok).obj;
|
||||||
if(parsed.type == TYPE_ERROR) {
|
if (parsed.type == TYPE_ERROR) {
|
||||||
obj = parsed; // TODO Check necessity
|
obj = parsed; // TODO Check necessity
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(tok[i].text[0] == ')') {
|
if (tok[i].text[0] == ')') {
|
||||||
// Skip `tok` past end of list that just closed
|
// Skip `tok` past end of list that just closed
|
||||||
tok = &tok[i + 1];
|
tok = &tok[i + 1];
|
||||||
i = -1;
|
i = -1;
|
||||||
|
@ -806,26 +814,28 @@ Object parseEval(const char *input, struct Environment *env)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
int _readFile(FILE *input, struct Environment *env) {
|
|
||||||
|
int _readFile(FILE* input, struct Environment* env)
|
||||||
|
{
|
||||||
Object r = numberObject(0);
|
Object r = numberObject(0);
|
||||||
char page[4096] = "";
|
char page[4096] = "";
|
||||||
const unsigned LINE_MAX = 256;
|
const int LINE_MAX = 256;
|
||||||
char line[LINE_MAX];
|
char line[LINE_MAX];
|
||||||
if(fgets(line, LINE_MAX, input)){
|
if (fgets(line, LINE_MAX, input)) {
|
||||||
if(line[0] != '#' || line[1] != '!') {
|
if (line[0] != '#' || line[1] != '!') {
|
||||||
strncat(page, line, strlen(line) - 1);
|
strncat(page, line, strlen(line) - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(fgets(line, LINE_MAX, input)) {
|
while (fgets(line, LINE_MAX, input)) {
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < LINE_MAX; i++) {
|
for (i = 0; i < LINE_MAX; i++) {
|
||||||
if(line[i] != ' ') {
|
if (line[i] != ' ') {
|
||||||
if(line[i] == ';') {
|
if (line[i] == ';') {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for(j = i; j < LINE_MAX; j++) {
|
for (j = i; j < LINE_MAX; j++) {
|
||||||
if(line[j] == ';' || line[j] == '\0') {
|
if (line[j] == ';' || line[j] == '\0') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -843,16 +853,19 @@ int _readFile(FILE *input, struct Environment *env) {
|
||||||
fclose(input);
|
fclose(input);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int readFile(const char *filename, struct Environment *env) {
|
|
||||||
FILE *input = fopen(filename, "r");
|
int readFile(const char* filename, struct Environment* env)
|
||||||
if(!input) {
|
{
|
||||||
|
FILE* input = fopen(filename, "r");
|
||||||
|
if (!input) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
_readFile(input, env);
|
_readFile(input, env);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object loadFile(Object filename, Object _, struct Environment *env) {
|
Object loadFile(Object filename, Object _, struct Environment* env)
|
||||||
|
{
|
||||||
if (isStringy(filename)) {
|
if (isStringy(filename)) {
|
||||||
readFile(filename.string, env);
|
readFile(filename.string, env);
|
||||||
return numberObject(0);
|
return numberObject(0);
|
||||||
|
@ -860,23 +873,26 @@ Object loadFile(Object filename, Object _, struct Environment *env) {
|
||||||
return numberObject(1);
|
return numberObject(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object systemCall(Object process, Object _, struct Environment *env) {
|
Object systemCall(Object process, Object _, struct Environment* env)
|
||||||
|
{
|
||||||
if (isStringy(process)) {
|
if (isStringy(process)) {
|
||||||
return numberObject(system(process.string));
|
return numberObject(system(process.string));
|
||||||
}
|
}
|
||||||
return numberObject(255);
|
return numberObject(255);
|
||||||
}
|
}
|
||||||
|
|
||||||
void repl(struct Environment *env) {
|
void repl(struct Environment* env)
|
||||||
|
{
|
||||||
if (readFile(SCRIPTDIR "/repl.pbl", env) == 1) {
|
if (readFile(SCRIPTDIR "/repl.pbl", env) == 1) {
|
||||||
fprintf(stderr, "Could not read '%s'\n", SCRIPTDIR "/repl.pbl");
|
fprintf(stderr, "Could not read '%s'\n", SCRIPTDIR "/repl.pbl");
|
||||||
fprintf(stderr, "Consider installing or reinstalling pebblisp.\n");
|
fprintf(stderr, "Consider installing or reinstalling pebblisp.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadArgsIntoEnv(int argc, const char* argv[], struct Environment* env) {
|
void loadArgsIntoEnv(int argc, const char* argv[], struct Environment* env)
|
||||||
|
{
|
||||||
Object args = listObject();
|
Object args = listObject();
|
||||||
for(int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
nf_addToList(&args, stringFromSlice(argv[i], strlen(argv[i])));
|
nf_addToList(&args, stringFromSlice(argv[i], strlen(argv[i])));
|
||||||
}
|
}
|
||||||
addToEnv(env, "args", args);
|
addToEnv(env, "args", args);
|
||||||
|
@ -886,16 +902,16 @@ int main(int argc, const char* argv[])
|
||||||
{
|
{
|
||||||
struct Environment env = defaultEnv();
|
struct Environment env = defaultEnv();
|
||||||
readFile(SCRIPTDIR "/lib.pbl", &env);
|
readFile(SCRIPTDIR "/lib.pbl", &env);
|
||||||
if(argc >= 2) {
|
if (argc >= 2) {
|
||||||
FILE *file = fopen(argv[1], "r");
|
FILE* file = fopen(argv[1], "r");
|
||||||
if(file) {
|
if (file) {
|
||||||
// Executing a file
|
// Executing a file
|
||||||
loadArgsIntoEnv(argc, argv, &env);
|
loadArgsIntoEnv(argc, argv, &env);
|
||||||
_readFile(file, &env);
|
_readFile(file, &env);
|
||||||
} else {
|
} else {
|
||||||
// Running arguments directly as pl code
|
// Running arguments directly as pl code
|
||||||
Object r = numberObject(0);
|
Object r = numberObject(0);
|
||||||
for(int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
r = parseEval(argv[i], &env);
|
r = parseEval(argv[i], &env);
|
||||||
printAndClean(&r);
|
printAndClean(&r);
|
||||||
}
|
}
|
||||||
|
@ -907,4 +923,5 @@ int main(int argc, const char* argv[])
|
||||||
}
|
}
|
||||||
deleteEnv(&env);
|
deleteEnv(&env);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
125
src/pebblisp.h
125
src/pebblisp.h
|
@ -1,76 +1,105 @@
|
||||||
#ifndef PEBBLISP_H
|
#ifndef PEBBLISP_H
|
||||||
#define PEBBLISP_H
|
#define PEBBLISP_H
|
||||||
|
|
||||||
#include "object.h"
|
|
||||||
#include "env.h"
|
#include "env.h"
|
||||||
|
#include "object.h"
|
||||||
#ifndef STANDALONE
|
|
||||||
#include <pebble.h>
|
|
||||||
#define printd(...) ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
#define printd(...) printf(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define printd(...) ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct Slice {
|
struct Slice {
|
||||||
const char *text;
|
const char* text;
|
||||||
char length;
|
char length;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Result {
|
typedef struct Result {
|
||||||
Object obj;
|
Object obj;
|
||||||
struct Slice *slices;
|
struct Slice* slices;
|
||||||
} Result;
|
} Result;
|
||||||
|
|
||||||
Object eval(const Object *obj, struct Environment *env);
|
Object eval(const Object* obj, struct Environment* env);
|
||||||
Result parse(struct Slice *slices);
|
|
||||||
Result readSeq(struct Slice *slices);
|
|
||||||
Object parseAtom(struct Slice *slice);
|
|
||||||
Object parseEval(const char *input, struct Environment *env);
|
|
||||||
void evalForms(Object *destList, const Object *src, struct Environment *env);
|
|
||||||
void copySlice(char * dest, struct Slice *src);
|
|
||||||
|
|
||||||
Object evalLambdaArgs(const Object *arg_forms);
|
Result parse(struct Slice* slices);
|
||||||
|
|
||||||
|
Result readSeq(struct Slice* slices);
|
||||||
|
|
||||||
|
Object parseAtom(struct Slice* slice);
|
||||||
|
|
||||||
|
Object parseEval(const char* input, struct Environment* env);
|
||||||
|
|
||||||
|
void evalForms(Object* destList, const Object* src, struct Environment* env);
|
||||||
|
|
||||||
|
void copySlice(char* dest, struct Slice* src);
|
||||||
|
|
||||||
|
Object evalLambdaArgs(const Object* arg_forms);
|
||||||
|
|
||||||
// Slices
|
// Slices
|
||||||
void copySlice(char * dest, struct Slice *src);
|
void copySlice(char* dest, struct Slice* src);
|
||||||
void debugSlice(struct Slice *s);
|
|
||||||
|
void debugSlice(struct Slice* s);
|
||||||
|
|
||||||
#define BASIC_OP(_name) \
|
#define BASIC_OP(_name) \
|
||||||
Object _name(Object obj1, Object obj2, struct Environment *env);
|
Object _name(Object obj1, Object obj2, struct Environment *env);
|
||||||
BASIC_OP(add); BASIC_OP(sub);
|
|
||||||
BASIC_OP(mul); BASIC_OP(dvi);
|
BASIC_OP(add);
|
||||||
BASIC_OP(mod); BASIC_OP(equ);
|
|
||||||
BASIC_OP(gth); BASIC_OP(lth);
|
BASIC_OP(sub);
|
||||||
|
|
||||||
|
BASIC_OP(mul);
|
||||||
|
|
||||||
|
BASIC_OP(dvi);
|
||||||
|
|
||||||
|
BASIC_OP(mod);
|
||||||
|
|
||||||
|
BASIC_OP(equ);
|
||||||
|
|
||||||
|
BASIC_OP(gth);
|
||||||
|
|
||||||
|
BASIC_OP(lth);
|
||||||
|
|
||||||
|
BASIC_OP(and);
|
||||||
|
|
||||||
|
BASIC_OP(or);
|
||||||
#undef BASIC_OP
|
#undef BASIC_OP
|
||||||
|
|
||||||
Object catObjects(const Object obj1, const Object obj2, struct Environment *env);
|
Object catObjects(const Object obj1, const Object obj2,
|
||||||
Object filter(Object obj1, Object obj2, struct Environment *env);
|
struct Environment* env);
|
||||||
Object append(Object list, Object newElement, struct Environment *env);
|
|
||||||
Object prepend(Object list, Object newElement, struct Environment *env);
|
|
||||||
Object at(Object index, Object list, struct Environment *env);
|
|
||||||
Object rest(Object list, Object ignore, struct Environment *env);
|
|
||||||
Object reverse(Object _list, Object ignore, struct Environment *ignore2);
|
|
||||||
|
|
||||||
Object isNum(Object test, Object ignore, struct Environment *ignore2);
|
Object filter(Object obj1, Object obj2, struct Environment* env);
|
||||||
Object isString(Object test, Object ignore, struct Environment *ignore2);
|
|
||||||
Object isErr(Object test, Object ignore, struct Environment *ignore2);
|
|
||||||
|
|
||||||
Object charAt(Object string, Object at, struct Environment *ignore);
|
Object append(Object list, Object newElement, struct Environment* env);
|
||||||
Object charVal(Object test, Object ignore, struct Environment *ignore2);
|
|
||||||
|
|
||||||
Object print(Object p, Object ignore, struct Environment *ignore2);
|
Object prepend(Object list, Object newElement, struct Environment* env);
|
||||||
Object pChar(Object c, Object i1, struct Environment *i2);
|
|
||||||
Object printEnvO(Object i1, Object i2, struct Environment *env);
|
Object at(Object index, Object list, struct Environment* env);
|
||||||
Object parseEvalO(Object text, Object ignore, struct Environment *env);
|
|
||||||
|
Object rest(Object list, Object ignore, struct Environment* env);
|
||||||
|
|
||||||
|
Object reverse(Object _list, Object ignore, struct Environment* ignore2);
|
||||||
|
|
||||||
|
Object isNum(Object test, Object ignore, struct Environment* ignore2);
|
||||||
|
|
||||||
|
Object isString(Object test, Object ignore, struct Environment* ignore2);
|
||||||
|
|
||||||
|
Object isErr(Object test, Object ignore, struct Environment* ignore2);
|
||||||
|
|
||||||
|
Object charAt(Object string, Object at, struct Environment* ignore);
|
||||||
|
|
||||||
|
Object charVal(Object test, Object ignore, struct Environment* ignore2);
|
||||||
|
|
||||||
|
Object print(Object p, Object ignore, struct Environment* ignore2);
|
||||||
|
|
||||||
|
Object pChar(Object c, Object i1, struct Environment* i2);
|
||||||
|
|
||||||
|
Object printEnvO(Object i1, Object i2, struct Environment* env);
|
||||||
|
|
||||||
|
Object parseEvalO(Object text, Object ignore, struct Environment* env);
|
||||||
|
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
Object takeInput(Object i1, Object i2, struct Environment *i3);
|
|
||||||
Object systemCall(Object call, Object _, struct Environment *i3);
|
Object takeInput(Object i1, Object i2, struct Environment* i3);
|
||||||
Object loadFile(Object filename, Object _, struct Environment *env);
|
|
||||||
|
Object systemCall(Object call, Object _, struct Environment* i3);
|
||||||
|
|
||||||
|
Object loadFile(Object filename, Object _, struct Environment* env);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
33
src/pebcom.c
33
src/pebcom.c
|
@ -1,44 +1,49 @@
|
||||||
#include <pebble.h>
|
|
||||||
#include "pebcom.h"
|
#include "pebcom.h"
|
||||||
|
|
||||||
struct tm* getTime() {
|
#include <pebble.h>
|
||||||
|
|
||||||
|
struct tm* getTime()
|
||||||
|
{
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
return localtime(&t);
|
return localtime(&t);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object getSeconds(Object o1, Object o2, struct Environment *env) {
|
Object getSeconds(Object o1, Object o2, struct Environment* env)
|
||||||
|
{
|
||||||
return numberObject(getTime()->tm_sec);
|
return numberObject(getTime()->tm_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object getMinutes(Object o1, Object o2, struct Environment *env) {
|
Object getMinutes(Object o1, Object o2, struct Environment* env)
|
||||||
|
{
|
||||||
return numberObject(getTime()->tm_min);
|
return numberObject(getTime()->tm_min);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object getHours(Object o1, Object o2, struct Environment *env) {
|
Object getHours(Object o1, Object o2, struct Environment* env)
|
||||||
|
{
|
||||||
return numberObject(getTime()->tm_hour);
|
return numberObject(getTime()->tm_hour);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object getTwelveHours(Object o1, Object o2, struct Environment *env) {
|
Object getTwelveHours(Object o1, Object o2, struct Environment* env)
|
||||||
|
{
|
||||||
int hour = (getTime()->tm_hour % 12) ?: 12;
|
int hour = (getTime()->tm_hour % 12) ?: 12;
|
||||||
return numberObject(hour);
|
return numberObject(hour);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object doVibe(Object patternList, Object o2, struct Environment *env) {
|
Object doVibe(Object patternList, Object o2, struct Environment* env)
|
||||||
|
{
|
||||||
int length = listLength(&patternList);
|
int length = listLength(&patternList);
|
||||||
uint32_t pattern[length];
|
uint32_t pattern[length];
|
||||||
if(length > 0) {
|
if (length > 0) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
Object *pl = &patternList;
|
Object* pl = &patternList;
|
||||||
FOR_POINTER_IN_LIST(pl) {
|
FOR_POINTER_IN_LIST(pl) {
|
||||||
if(POINTER->type == TYPE_NUMBER) {
|
if (POINTER->type == TYPE_NUMBER) {
|
||||||
pattern[i] = POINTER->number;
|
pattern[i] = POINTER->number;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
vibes_enqueue_custom_pattern((VibePattern) {
|
vibes_enqueue_custom_pattern(
|
||||||
.durations = pattern,
|
(VibePattern) {.durations = pattern, .num_segments = length});
|
||||||
.num_segments = length
|
|
||||||
});
|
|
||||||
return boolObject(1);
|
return boolObject(1);
|
||||||
} else {
|
} else {
|
||||||
return errorObject(NOT_A_LIST);
|
return errorObject(NOT_A_LIST);
|
||||||
|
|
13
src/pebcom.h
13
src/pebcom.h
|
@ -1,8 +1,11 @@
|
||||||
#include "pebblisp.h"
|
#include "pebblisp.h"
|
||||||
|
|
||||||
Object getSeconds(Object o1, Object o2, struct Environment *env);
|
Object getSeconds(Object o1, Object o2, struct Environment* env);
|
||||||
Object getMinutes(Object o1, Object o2, struct Environment *env);
|
|
||||||
Object getHours(Object o1, Object o2, struct Environment *env);
|
|
||||||
Object getTwelveHours(Object o1, Object o2, struct Environment *env);
|
|
||||||
|
|
||||||
Object doVibe(Object patternList, Object o2, struct Environment *env);
|
Object getMinutes(Object o1, Object o2, struct Environment* env);
|
||||||
|
|
||||||
|
Object getHours(Object o1, Object o2, struct Environment* env);
|
||||||
|
|
||||||
|
Object getTwelveHours(Object o1, Object o2, struct Environment* env);
|
||||||
|
|
||||||
|
Object doVibe(Object patternList, Object o2, struct Environment* env);
|
||||||
|
|
71
src/tokens.c
71
src/tokens.c
|
@ -1,19 +1,8 @@
|
||||||
#include "tokens.h"
|
#include "tokens.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifdef STANDALONE
|
|
||||||
#include <stdio.h>
|
|
||||||
#undef printd
|
|
||||||
#define printd(...) fprintf(stderr, __VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#include <pebble.h>
|
|
||||||
#undef printd
|
|
||||||
#undef printf
|
|
||||||
#define printf(...) APP_LOG(APP_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
|
||||||
#define printd(...) printf(__VA_ARGS__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ERR_LEN 256
|
#define ERR_LEN 256
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -26,44 +15,51 @@
|
||||||
|
|
||||||
// Is the char a standalone token?
|
// Is the char a standalone token?
|
||||||
static const char singleTokens[] = "()+-*/='";
|
static const char singleTokens[] = "()+-*/='";
|
||||||
int isSingle(const char c) {
|
|
||||||
|
int isSingle(const char c)
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(singleTokens[i] != '\0'){
|
while (singleTokens[i] != '\0') {
|
||||||
if(singleTokens[i] == c)
|
if (singleTokens[i] == c) {
|
||||||
return singleTokens[i];
|
return singleTokens[i];
|
||||||
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int isDigit(const char c) {
|
int isDigit(const char c)
|
||||||
|
{
|
||||||
return c >= '0' && c <= '9';
|
return c >= '0' && c <= '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
int isHex(const char c) {
|
int isHex(const char c)
|
||||||
|
{
|
||||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
|
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
|
||||||
}
|
}
|
||||||
|
|
||||||
int isWhitespace(const char c) {
|
int isWhitespace(const char c)
|
||||||
|
{
|
||||||
return c == ' ' || c == '\t' || c == '\n';
|
return c == ' ' || c == '\t' || c == '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
int notWhitespace(const char c) {
|
int notWhitespace(const char c)
|
||||||
|
{
|
||||||
return !isWhitespace(c);
|
return !isWhitespace(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return needs to be freed, if not null
|
// Return needs to be freed, if not null
|
||||||
struct Slice *nf_tokenize(const char *input, struct Error *err)
|
struct Slice* nf_tokenize(const char* input, struct Error* err)
|
||||||
{
|
{
|
||||||
if(!input) {
|
if (!input) {
|
||||||
err->context = malloc(sizeof(char) * ERR_LEN);
|
err->context = malloc(sizeof(char) * ERR_LEN);
|
||||||
strcpy(err->context, "no input");
|
strcpy(err->context, "no input");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int token_count = MAX_TOK_CNT;
|
int token_count = MAX_TOK_CNT;
|
||||||
struct Slice *slices = malloc(sizeof(struct Slice) * token_count);
|
struct Slice* slices = malloc(sizeof(struct Slice) * token_count);
|
||||||
while(slices == NULL) {
|
while (slices == NULL) {
|
||||||
token_count /= 2;
|
token_count /= 2;
|
||||||
slices = malloc(sizeof(struct Slice) * token_count);
|
slices = malloc(sizeof(struct Slice) * token_count);
|
||||||
}
|
}
|
||||||
|
@ -72,20 +68,20 @@ struct Slice *nf_tokenize(const char *input, struct Error *err)
|
||||||
int slice = 0;
|
int slice = 0;
|
||||||
|
|
||||||
int parens = 0;
|
int parens = 0;
|
||||||
while(input[i] != '\0') {
|
while (input[i] != '\0') {
|
||||||
int l = 1;
|
int l = 1;
|
||||||
// printd("input: '%c'\n", input[i]);
|
// printd("input: '%c'\n", input[i]);
|
||||||
|
|
||||||
if(isWhitespace(input[i]) || input[i] == ';') {
|
if (isWhitespace(input[i]) || input[i] == ';') {
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(input[i] == '(') {
|
if (input[i] == '(') {
|
||||||
parens++;
|
parens++;
|
||||||
} else if (input[i] == ')') {
|
} else if (input[i] == ')') {
|
||||||
parens--;
|
parens--;
|
||||||
if(parens < 0) {
|
if (parens < 0) {
|
||||||
err->context = malloc(sizeof(char) * ERR_LEN + 1);
|
err->context = malloc(sizeof(char) * ERR_LEN + 1);
|
||||||
err->code = MISMATCHED_PARENS;
|
err->code = MISMATCHED_PARENS;
|
||||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
||||||
|
@ -97,19 +93,21 @@ struct Slice *nf_tokenize(const char *input, struct Error *err)
|
||||||
|
|
||||||
slices[slice].text = &input[i];
|
slices[slice].text = &input[i];
|
||||||
|
|
||||||
if(isSingle(input[i])) {
|
if (isSingle(input[i])) {
|
||||||
i++;
|
i++;
|
||||||
} else if(input[i] == '"') {
|
} else if (input[i] == '"') {
|
||||||
if(input[i + 1] == '"' && input [i + 2] == '"') {
|
if (input[i + 1] == '"' && input[i + 2] == '"') {
|
||||||
// Triple-quoted block
|
// Triple-quoted block
|
||||||
i += 2;
|
i += 2;
|
||||||
slices[slice].text += 2;
|
slices[slice].text += 2;
|
||||||
for(;;) {
|
for (;;) {
|
||||||
i++;
|
i++;
|
||||||
if(input[i] == '"' && input[i + 1] == '"' && input[i + 2] == '"') {
|
if (input[i] == '"' && input[i + 1] == '"' &&
|
||||||
|
input[i + 2] == '"') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(input[i] == '\0' || input[i + 1] == '\0' || input[i + 2] == '\0') {
|
if (input[i] == '\0' || input[i + 1] == '\0' ||
|
||||||
|
input[i + 2] == '\0') {
|
||||||
err->context = malloc(sizeof(char) * ERR_LEN + 1);
|
err->context = malloc(sizeof(char) * ERR_LEN + 1);
|
||||||
err->code = UNEXPECTED_EOF;
|
err->code = UNEXPECTED_EOF;
|
||||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
||||||
|
@ -120,13 +118,14 @@ struct Slice *nf_tokenize(const char *input, struct Error *err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Simple string
|
// Simple string
|
||||||
while(input[++i] != '"' && input[i] != '\0') {
|
while (input[++i] != '"' && input[i] != '\0') {
|
||||||
l++;
|
l++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
while(!isWhitespace(input[++i]) && !isSingle(input[i]) && input[i] != '\0') {
|
while (!isWhitespace(input[++i]) && !isSingle(input[i]) &&
|
||||||
|
input[i] != '\0') {
|
||||||
l++;
|
l++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +134,7 @@ struct Slice *nf_tokenize(const char *input, struct Error *err)
|
||||||
slice++;
|
slice++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(parens != 0){
|
if (parens != 0) {
|
||||||
err->context = malloc(sizeof(char) * ERR_LEN);
|
err->context = malloc(sizeof(char) * ERR_LEN);
|
||||||
err->code = MISMATCHED_PARENS;
|
err->code = MISMATCHED_PARENS;
|
||||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
||||||
|
|
|
@ -4,8 +4,11 @@
|
||||||
#include "pebblisp.h"
|
#include "pebblisp.h"
|
||||||
|
|
||||||
int isSingle(const char c);
|
int isSingle(const char c);
|
||||||
|
|
||||||
int isDigit(const char c);
|
int isDigit(const char c);
|
||||||
|
|
||||||
int isHex(const char c);
|
int isHex(const char c);
|
||||||
struct Slice *nf_tokenize(const char *input, struct Error *err);
|
|
||||||
|
struct Slice* nf_tokenize(const char* input, struct Error* err);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue