Errors can have context to make them more useful.
External: Error changes. User windows will show string reps of all object types Internal: Some re-org and renames in calc. Add stringNObj for more controlled string-receiving. Note: currently aplite has a hard time with larger scripts, possibly because of recent changes. Not sure how much can be done about it, but I'm investigating.
This commit is contained in:
parent
cadb57c0f2
commit
c142730837
30
src/calc.c
30
src/calc.c
|
@ -2,6 +2,7 @@
|
|||
#include <limits.h>
|
||||
|
||||
#include "pebcom.h"
|
||||
#include "object.h"
|
||||
#include "pebbleobject.h"
|
||||
#include "calc.h"
|
||||
|
||||
|
@ -205,9 +206,14 @@ static void add_token()
|
|||
static void calculate()
|
||||
{
|
||||
Object obj = parseEval(current_code_text, &env);
|
||||
char temp[RESULT_LENGTH-2] = "";
|
||||
char temp[RESULT_LENGTH + 2] = "";
|
||||
|
||||
stringObj(temp, &obj);
|
||||
stringNObj(temp, &obj, RESULT_LENGTH);
|
||||
if(obj.type == TYPE_ERROR) {
|
||||
text_layer_set_font(s_result_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD));
|
||||
} else {
|
||||
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);
|
||||
text_layer_set_text(s_result_text_layer, result_text);
|
||||
}
|
||||
|
@ -230,8 +236,11 @@ static void click_select(ClickRecognizerRef recognizer, void *context)
|
|||
static void click_save(ClickRecognizerRef recognizer, void *context)
|
||||
{
|
||||
int8_t i = strlen(displayed_code);
|
||||
for(unsigned j = 0; j < strlen(getToken(selected_token)); j++) {
|
||||
unsigned token_len = strlen(getToken(selected_token));
|
||||
printf("%s", displayed_code);
|
||||
for(unsigned j = 0; j < token_len; j++) {
|
||||
displayed_code[i-(1 + j)] = '\0';
|
||||
printf("%s", displayed_code);
|
||||
}
|
||||
|
||||
persist_write_string(current_script_num, displayed_code);
|
||||
|
@ -374,7 +383,7 @@ static int16_t get_cell_height_callback(struct MenuLayer *menu_layer,
|
|||
return CELL_HEIGHT;
|
||||
}
|
||||
|
||||
static void menu_load(Window *window)
|
||||
static void script_menu_load(Window *window)
|
||||
{
|
||||
Layer *window_layer = window_get_root_layer(window);
|
||||
GRect bounds = layer_get_bounds(window_layer);
|
||||
|
@ -396,7 +405,7 @@ static void menu_load(Window *window)
|
|||
layer_add_child(window_layer, menu_layer_get_layer(s_script_select_layer));
|
||||
}
|
||||
|
||||
static void menu_unload(Window *window)
|
||||
static void script_menu_unload(Window *window)
|
||||
{
|
||||
menu_layer_destroy(s_script_select_layer);
|
||||
}
|
||||
|
@ -426,9 +435,7 @@ static void custom_load(Window *window)
|
|||
Object add_window(Object obj1, Object _, struct Environment *env)
|
||||
{
|
||||
printf("ADD_WINDOW\n");
|
||||
if(obj1.type == TYPE_STRING) {
|
||||
strcpy(header, obj1.string);
|
||||
}
|
||||
stringObj(header, &obj1);
|
||||
|
||||
if(!s_custom_window) {
|
||||
s_custom_window = window_create();
|
||||
|
@ -483,12 +490,14 @@ static void init(void)
|
|||
env = pebbleEnv();
|
||||
s_script_menu_window = window_create();
|
||||
window_set_window_handlers(s_script_menu_window, (WindowHandlers) {
|
||||
.load = menu_load,
|
||||
.unload = menu_unload
|
||||
.load = script_menu_load,
|
||||
.unload = script_menu_unload
|
||||
});
|
||||
window_stack_push(s_script_menu_window, true);
|
||||
app_message_open(inbox_size, outbox_size);
|
||||
app_message_register_inbox_received(inbox_received_callback);
|
||||
tiny_font = fonts_load_custom_font(
|
||||
resource_get_handle(RESOURCE_ID_FONT_TINY_11));
|
||||
}
|
||||
|
||||
static void deinit(void)
|
||||
|
@ -501,7 +510,6 @@ static void deinit(void)
|
|||
int main(void)
|
||||
{
|
||||
init();
|
||||
tiny_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_TINY_11));
|
||||
app_event_loop();
|
||||
deinit();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "pebblisp.h"
|
||||
|
||||
#define SMAX_LENGTH 256
|
||||
#define RESULT_LENGTH 20
|
||||
#define CELL_HEIGHT 44
|
||||
|
||||
#define SCRIPT_COUNT 5
|
||||
|
|
12
src/env.c
12
src/env.c
|
@ -42,7 +42,7 @@ Object fetchFromEnvironment(const char *name, struct Environment *env)
|
|||
return fetchFromEnvironment(name, env->outer);
|
||||
}
|
||||
|
||||
return errorObject(DID_NOT_FIND_SYMBOL);
|
||||
return errorWithContext(DID_NOT_FIND_SYMBOL, name);
|
||||
}
|
||||
|
||||
struct Environment envForLambda(const Object *params, const Object *arg_forms,
|
||||
|
@ -200,11 +200,15 @@ struct symFunc {
|
|||
|
||||
struct Environment defaultEnv()
|
||||
{
|
||||
char** strings = calloc(sizeof(char*), MAX_ENV_ELM);
|
||||
Object* objects = malloc(sizeof(Object) * MAX_ENV_ELM);
|
||||
char size = MAX_ENV_ELM;
|
||||
|
||||
struct Environment e = {
|
||||
.outer = NULL,
|
||||
.strings = calloc(sizeof(char*), MAX_ENV_ELM),
|
||||
.objects = malloc(sizeof(Object) * MAX_ENV_ELM),
|
||||
.size = MAX_ENV_ELM
|
||||
.strings = strings,
|
||||
.objects = objects,
|
||||
.size = size,
|
||||
};
|
||||
|
||||
struct symFunc symFuncs[] = {
|
||||
|
|
75
src/object.c
75
src/object.c
|
@ -1,10 +1,7 @@
|
|||
#include "object.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define RESULT_LENGTH 30
|
||||
|
||||
#ifdef DEBUG
|
||||
#define printd(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
|
@ -108,7 +105,7 @@ inline int isEmpty(const Object *obj)
|
|||
case TYPE_OTHER:
|
||||
return obj->other == NULL;
|
||||
case TYPE_ERROR:
|
||||
return obj->err == 0;
|
||||
return obj->error->code == 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -122,8 +119,6 @@ inline int isEmpty(const Object *obj)
|
|||
*/
|
||||
void allocObject(Object **spot, const Object src)
|
||||
{
|
||||
if(!spot)
|
||||
return;
|
||||
*spot = malloc(sizeof(struct Object));
|
||||
**spot = src;
|
||||
(*spot)->forward = NULL;
|
||||
|
@ -232,8 +227,6 @@ void printErr(const Object *obj)
|
|||
{
|
||||
if(!obj || obj->type != TYPE_ERROR)
|
||||
return;
|
||||
|
||||
printf("%s\n", errorText[(int)(obj->err)]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -276,49 +269,55 @@ void stringList(char *dest, const Object *obj)
|
|||
* @param dest The string to copy the list text into
|
||||
* @param obj The list Object to make a string from
|
||||
*/
|
||||
char* stringObj(char *dest, const Object *obj)
|
||||
{
|
||||
char* stringNObj(char *dest, const Object *obj, const size_t len) {
|
||||
if(!dest || !obj)
|
||||
return NULL;
|
||||
|
||||
switch(obj->type) {
|
||||
case TYPE_NUMBER:
|
||||
snprintf(dest, RESULT_LENGTH, "%d", obj->number);
|
||||
snprintf(dest, len, "%d", obj->number);
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
snprintf(dest, RESULT_LENGTH, "%s", obj->number ? "T" : "F");
|
||||
snprintf(dest, len, "%s", obj->number ? "T" : "F");
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
snprintf(dest, RESULT_LENGTH, "%s", obj->string);
|
||||
snprintf(dest, len, "%s", obj->string);
|
||||
break;
|
||||
case TYPE_SYMBOL:
|
||||
snprintf(dest, RESULT_LENGTH, "`%s`", obj->string);
|
||||
snprintf(dest, len, "`%s`", obj->string);
|
||||
break;
|
||||
case TYPE_LIST:
|
||||
stringList(dest, obj);
|
||||
break;
|
||||
case TYPE_ERROR:
|
||||
#ifdef STANDALONE
|
||||
snprintf(dest, RESULT_LENGTH, "%s", errorText[(int)(obj->err)]);
|
||||
#else
|
||||
snprintf(dest, RESULT_LENGTH, "E%d", obj->err);
|
||||
#endif
|
||||
case TYPE_ERROR: {
|
||||
int code = obj->error->code;
|
||||
if (obj->error->context && obj->error->context[0] != '\0') {
|
||||
snprintf(dest, len, "'%s': %s",
|
||||
errorText[code], obj->error->context);
|
||||
} else {
|
||||
snprintf(dest, len, "%s", errorText[code]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_FUNC:
|
||||
case TYPE_LAMBDA:
|
||||
snprintf(dest, RESULT_LENGTH, "X%d", obj->number);
|
||||
snprintf(dest, len, "X%d", obj->number);
|
||||
break;
|
||||
case TYPE_OTHER:
|
||||
snprintf(dest, RESULT_LENGTH, "%p", obj->other->data);
|
||||
snprintf(dest, len, "%p", obj->other->data);
|
||||
break;
|
||||
}
|
||||
|
||||
if(!isValidType(*obj))
|
||||
snprintf(dest, RESULT_LENGTH, "BAD_TYPE(%d) X%d", obj->type, obj->number);
|
||||
snprintf(dest, len, "BAD_TYPE(%d) X%d", obj->type, obj->number);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
char* stringObj(char *dest, const Object *obj) {
|
||||
return stringNObj(dest, obj, RESULT_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a given Object only if the DEBUG flag is set
|
||||
* @param obj The Object to debug
|
||||
|
@ -451,16 +450,19 @@ void cleanObject(Object *target)
|
|||
cleanObject(&target->lambda->body);
|
||||
free(target->lambda);
|
||||
break;
|
||||
case TYPE_ERROR:
|
||||
free(target->error->context);
|
||||
free(target->error);
|
||||
target->error = NULL;
|
||||
break;
|
||||
case TYPE_OTHER:
|
||||
if(target->other->cleanup) {
|
||||
target->other->cleanup(target);
|
||||
}
|
||||
//free(target->other);
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
case TYPE_NUMBER:
|
||||
case TYPE_FUNC:
|
||||
case TYPE_ERROR:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -650,11 +652,12 @@ inline Object cloneObject(const Object src)
|
|||
case TYPE_STRING:
|
||||
case TYPE_SYMBOL:
|
||||
return cloneString(src);
|
||||
case TYPE_ERROR:
|
||||
return errorWithContext(src.error->code, src.error->context);
|
||||
case TYPE_BOOL:
|
||||
case TYPE_NUMBER:
|
||||
case TYPE_FUNC:
|
||||
case TYPE_OTHER:
|
||||
case TYPE_ERROR:
|
||||
; // Fall through to plain return
|
||||
}
|
||||
|
||||
|
@ -715,7 +718,7 @@ inline Object constructLambda(const Object *params, const Object *body)
|
|||
|
||||
inline int isError(const Object obj, const enum errorCode err)
|
||||
{
|
||||
return obj.type == TYPE_ERROR && obj.err == err;
|
||||
return obj.type == TYPE_ERROR && obj.error->code == err;
|
||||
}
|
||||
|
||||
inline int bothAre(const enum Type type, const Object *obj1, const Object *obj2)
|
||||
|
@ -743,7 +746,23 @@ inline Object otherObject()
|
|||
inline Object errorObject(enum errorCode err)
|
||||
{
|
||||
Object o = newObject(TYPE_ERROR);
|
||||
o.err = err;
|
||||
o.error = malloc(sizeof(struct Error));
|
||||
o.error->code = err;
|
||||
o.error->context = NULL;
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
inline void errorAddContext(Object *o, const char* context)
|
||||
{
|
||||
o->error->context = calloc(sizeof(char), RESULT_LENGTH);
|
||||
strncpy(o->error->context, context, RESULT_LENGTH);
|
||||
}
|
||||
|
||||
inline Object errorWithContext(enum errorCode err, const char* context)
|
||||
{
|
||||
Object o = errorObject(err);
|
||||
errorAddContext(&o, context);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
|
18
src/object.h
18
src/object.h
|
@ -1,8 +1,11 @@
|
|||
#ifndef OBJECT_H
|
||||
#define OBJECT_H
|
||||
|
||||
#define MAX_TOK_CNT 1024 // 128
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_TOK_CNT 1024
|
||||
#define MAX_ENV_ELM 100
|
||||
#define RESULT_LENGTH 128
|
||||
|
||||
#define FOR_POINTER_IN_LIST(_list) \
|
||||
if(_list && _list->type == TYPE_LIST) \
|
||||
|
@ -44,8 +47,6 @@ enum errorCode {
|
|||
INDEX_PAST_END,
|
||||
};
|
||||
|
||||
#define MALLOC_FLAG 64
|
||||
|
||||
typedef enum Type {
|
||||
TYPE_NUMBER,
|
||||
TYPE_BOOL,
|
||||
|
@ -63,6 +64,7 @@ struct Lambda;
|
|||
struct Environment;
|
||||
struct Slice;
|
||||
struct Other;
|
||||
struct Error;
|
||||
|
||||
struct Object {
|
||||
Type type;
|
||||
|
@ -74,10 +76,15 @@ struct Object {
|
|||
Object (*func)(Object, Object, struct Environment *);
|
||||
struct Lambda *lambda;
|
||||
struct Other *other;
|
||||
enum errorCode err;
|
||||
struct Error *error;
|
||||
};
|
||||
};
|
||||
|
||||
struct Error {
|
||||
enum errorCode code;
|
||||
char* context;
|
||||
};
|
||||
|
||||
struct Lambda {
|
||||
Object params;
|
||||
Object body;
|
||||
|
@ -89,6 +96,7 @@ struct Other {
|
|||
void *data;
|
||||
};
|
||||
|
||||
char* stringNObj(char *dest, const Object *obj, size_t len);
|
||||
char* stringObj(char *dest, const Object *obj);
|
||||
void printList(const Object *list);
|
||||
void printType(const Object *obj);
|
||||
|
@ -135,6 +143,8 @@ Object boolObject(int b);
|
|||
Object numberObject(int num);
|
||||
Object otherObject();
|
||||
Object errorObject(enum errorCode err);
|
||||
Object errorWithContext(enum errorCode err, const char* context);
|
||||
void errorAddContext(Object *o, const char* context);
|
||||
Object constructLambda(const Object *params, const Object *body);
|
||||
|
||||
// Object version of listLength()
|
||||
|
|
|
@ -171,14 +171,21 @@ Object listEvalFunc(
|
|||
|
||||
Object func_result = rest[0];
|
||||
if(length == 1) {
|
||||
Object oneArg = errorObject(ONLY_ONE_ARGUMENT);
|
||||
func_result = function->func(
|
||||
func_result, errorObject(ONLY_ONE_ARGUMENT), env);
|
||||
func_result, oneArg, env);
|
||||
// Return a partial function if more parameters are required
|
||||
// Otherwise, return the function result
|
||||
cleanObject(&rest[0]);
|
||||
return isError(func_result, ONLY_ONE_ARGUMENT) ?
|
||||
cloneObject(*list) :
|
||||
func_result;
|
||||
if (isError(func_result, ONLY_ONE_ARGUMENT)) {
|
||||
// These functions modify their second argument,
|
||||
// so we don't clean oneArg here
|
||||
cleanObject(&func_result);
|
||||
return cloneObject(*list);
|
||||
} else {
|
||||
cleanObject(&oneArg);
|
||||
return func_result;
|
||||
}
|
||||
} else {
|
||||
// With two args, will apply function once
|
||||
// With more than two args, apply the function repeatedly
|
||||
|
@ -251,13 +258,13 @@ Object evalList(const Object *obj, struct Environment *env)
|
|||
Object *first_form = obj->list;
|
||||
|
||||
{ // Try to eval built-ins
|
||||
const 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) &&
|
||||
!isError(builtIn, NOT_A_SYMBOL)) {
|
||||
return builtIn;
|
||||
}
|
||||
cleanObject(&builtIn);
|
||||
}
|
||||
|
||||
// Evaluate the list based on the first element's type
|
||||
|
@ -288,10 +295,8 @@ Object evalList(const Object *obj, struct Environment *env)
|
|||
Object eval(const Object *obj, struct Environment *env)
|
||||
{
|
||||
switch(obj->type) {
|
||||
case TYPE_ERROR:
|
||||
case TYPE_FUNC:
|
||||
return *obj;
|
||||
|
||||
case TYPE_ERROR:
|
||||
case TYPE_OTHER:
|
||||
case TYPE_NUMBER:
|
||||
case TYPE_BOOL:
|
||||
|
@ -702,9 +707,12 @@ Object parseAtom(struct Slice *s)
|
|||
|
||||
Object parseEval(const char *input, struct Environment *env)
|
||||
{
|
||||
struct Slice *tokens = nf_tokenize(input);
|
||||
if(!tokens) {
|
||||
return errorObject(MISMATCHED_PARENS);
|
||||
char *err;
|
||||
struct Slice *tokens = nf_tokenize(input, &err);
|
||||
if(err) {
|
||||
Object o = errorWithContext(MISMATCHED_PARENS, err);
|
||||
free(err);
|
||||
return o;
|
||||
}
|
||||
if(!tokens->text) {
|
||||
return symFromSlice(" ", 1);
|
||||
|
@ -738,10 +746,11 @@ Object parseEval(const char *input, struct Environment *env)
|
|||
cleanObject(&obj);
|
||||
Object parsed = parse(tok).obj;
|
||||
if(parsed.type == TYPE_ERROR) {
|
||||
obj = parsed;
|
||||
obj = parsed; // TODO Check necessity
|
||||
break;
|
||||
}
|
||||
if(tok[i].text[0] == ')') {
|
||||
// Skip `tok` past end of list that just closed
|
||||
tok = &tok[i + 1];
|
||||
i = -1;
|
||||
}
|
||||
|
@ -829,8 +838,8 @@ int main(int argc, const char* argv[])
|
|||
{
|
||||
struct Environment env = defaultEnv();
|
||||
readFile(SCRIPTDIR "/lib.pbl", &env);
|
||||
FILE *file = fopen(argv[1], "r");
|
||||
if(argc >= 2) {
|
||||
FILE *file = fopen(argv[1], "r");
|
||||
if(file) {
|
||||
// Executing a file
|
||||
loadArgsIntoEnv(argc, argv, &env);
|
||||
|
|
19
src/tests.sh
19
src/tests.sh
|
@ -51,9 +51,9 @@ check() {
|
|||
fi
|
||||
if $VALGRIND; then
|
||||
echo -ne "\n $1\r"
|
||||
local output=$($VALCOM ./pl "(loadfile \"examples/lib.pbl\") $2")
|
||||
local output="$($VALCOM ./pl "(loadfile \"examples/lib.pbl\") $2")"
|
||||
else
|
||||
local output=$(./pl "(loadfile \"examples/lib.pbl\") $2")
|
||||
local output="$(./pl "(loadfile \"examples/lib.pbl\") $2")"
|
||||
fi
|
||||
|
||||
if [ "$output" == "$3" ]; then
|
||||
|
@ -186,11 +186,16 @@ check "UnevenLists" "(+ (1 2) (1 2 3))" "LISTS_NOT_SAME_SIZE"
|
|||
check "BadNumber" "(5df)" "BAD_NUMBER"
|
||||
check "BadHex" "(0x0zf)" "BAD_NUMBER"
|
||||
check "BadBinary" "(0b01120)" "BAD_NUMBER"
|
||||
check "BadParens" "(hey()" "MISMATCHED_PARENS"
|
||||
check "BadParens2" "(hey)(" "MISMATCHED_PARENS"
|
||||
check "BadParens3" "((hey(" "MISMATCHED_PARENS"
|
||||
check "BadParens4" ")))hey" "MISMATCHED_PARENS"
|
||||
check "BadParens5" "hey))(" "MISMATCHED_PARENS"
|
||||
check "BadParens" "(hey()" \
|
||||
"'MISMATCHED_PARENS': (loadfile \"examples/lib.pbl\") (hey()"
|
||||
check "BadParens2" "(hey)(" \
|
||||
"'MISMATCHED_PARENS': (loadfile \"examples/lib.pbl\") (hey)("
|
||||
check "BadParens3" "((hey(" \
|
||||
"'MISMATCHED_PARENS': (loadfile \"examples/lib.pbl\") ((hey("
|
||||
check "BadParens4" ")))hey" \
|
||||
"'MISMATCHED_PARENS': (loadfile \"examples/lib.pbl\") )))hey"
|
||||
check "BadParens5" "hey))(" \
|
||||
"'MISMATCHED_PARENS': (loadfile \"examples/lib.pbl\") hey))("
|
||||
endBlock
|
||||
|
||||
title "Eval"
|
||||
|
|
29
src/tokens.c
29
src/tokens.c
|
@ -1,5 +1,6 @@
|
|||
#include "tokens.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef STANDALONE
|
||||
#include <stdio.h>
|
||||
|
@ -8,9 +9,13 @@
|
|||
#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
|
||||
|
||||
/*
|
||||
* Grammar:
|
||||
* token
|
||||
|
@ -48,12 +53,20 @@ int notWhitespace(const char c) {
|
|||
}
|
||||
|
||||
// Return needs to be freed, if not null
|
||||
struct Slice *nf_tokenize(const char *input)
|
||||
struct Slice *nf_tokenize(const char *input, char **err)
|
||||
{
|
||||
if(!input)
|
||||
if(!input) {
|
||||
*err = malloc(sizeof(char) * ERR_LEN);
|
||||
strcpy(*err, "no input");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct Slice *slices = malloc(sizeof(struct Slice) * MAX_TOK_CNT);
|
||||
int token_count = MAX_TOK_CNT;
|
||||
struct Slice *slices = malloc(sizeof(struct Slice) * token_count);
|
||||
while(slices == NULL) {
|
||||
token_count /= 2;
|
||||
slices = malloc(sizeof(struct Slice) * token_count);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
int slice = 0;
|
||||
|
@ -73,6 +86,9 @@ struct Slice *nf_tokenize(const char *input)
|
|||
} else if (input[i] == ')') {
|
||||
parens--;
|
||||
if(parens < 0) {
|
||||
*err = malloc(sizeof(char) * ERR_LEN);
|
||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
||||
strncpy(*err, &input[start], ERR_LEN);
|
||||
free(slices);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -82,7 +98,6 @@ struct Slice *nf_tokenize(const char *input)
|
|||
|
||||
if(isSingle(input[i])) {
|
||||
i++;
|
||||
|
||||
} else if(input[i] == '"' || input[i] == '\'') {
|
||||
const char quote = input[i];
|
||||
while(input[++i] != quote && input[i] != '\0') {
|
||||
|
@ -99,7 +114,10 @@ struct Slice *nf_tokenize(const char *input)
|
|||
slice++;
|
||||
}
|
||||
|
||||
if(parens){
|
||||
if(parens != 0){
|
||||
*err = malloc(sizeof(char) * ERR_LEN);
|
||||
int start = i > ERR_LEN ? i - ERR_LEN : 0;
|
||||
strncpy(*err, &input[start], ERR_LEN);
|
||||
free(slices);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -107,5 +125,6 @@ struct Slice *nf_tokenize(const char *input)
|
|||
slices[slice].text = NULL;
|
||||
slices[slice].length = 0;
|
||||
|
||||
*err = NULL;
|
||||
return slices;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
int isSingle(const char c);
|
||||
int isDigit(const char c);
|
||||
int isHex(const char c);
|
||||
struct Slice *nf_tokenize(const char *input);
|
||||
struct Slice *nf_tokenize(const char *input, char **err);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue