diff --git a/src/env.c b/src/env.c index 2c18351..8067002 100644 --- a/src/env.c +++ b/src/env.c @@ -409,9 +409,10 @@ Object help(Object* params, int length, struct Environment* env) return text; } } + Object* object = fetch(symbol, env); if (object) { - size_t len; + size_t len = 0; char* string = stringObj(object, &len); Object text = stringFromSlice(string, len); free(string); diff --git a/src/examples/pebblisp.pbl b/src/examples/pebblisp.pbl index 37ac328..0f33e3d 100644 --- a/src/examples/pebblisp.pbl +++ b/src/examples/pebblisp.pbl @@ -35,9 +35,10 @@ (Alias "r" "(reloadConfig)") )) -(def alias (fn () ( - (reduce (map (fn (a) (cat nl a.name " -> " a.value)) aliases) cat "") -))) +(def alias (fn () + "Get a string that lists all current aliases." ( + (reduce (map (fn (a) (cat nl a.name " -> " a.value)) aliases) cat "") + ))) (def commRunning F) diff --git a/src/object.c b/src/object.c index 9bc7a52..7e77123 100644 --- a/src/object.c +++ b/src/object.c @@ -294,6 +294,11 @@ int stringNObj(struct string* s, const Object* obj) #ifdef DEBUG s->cursor += sprintf(s->cursor, "\\x%d", obj->number); #endif + char* docString = obj->lambda->params.docString; + if (docString) { + inflate(s, strlen(docString)); + s->cursor += sprintf(s->cursor, "%s\n", docString); + } stringNObj(s, &obj->lambda->params); s->cursor += sprintf(s->cursor, " -> "); stringNObj(s, &obj->lambda->body); @@ -418,6 +423,7 @@ void cleanObject(Object* target) cleanObject(&target->lambda->params); cleanObject(&target->lambda->body); free(target->lambda); + free(target->lambda->params.docString); } break; case TYPE_STRUCT: @@ -728,7 +734,7 @@ inline Object withLen(size_t len, enum Type type) return o; } -inline Object constructLambda(const Object* params, const Object* body, struct Environment* env) +inline Object constructLambda(const Object* params, const Object* docs, const Object* body, struct Environment* env) { if (!params || !body) { return errorObject(NULL_LAMBDA_LIST); @@ -738,12 +744,23 @@ inline Object constructLambda(const Object* params, const Object* body, struct E return errorObject(LAMBDA_ARGS_NOT_LIST); } + if (docs && docs->type != TYPE_STRING) { + return errorWithContext(BAD_TYPE, "fn docstring must be a string"); + } + Object o = newObject(TYPE_LAMBDA); o.lambda = malloc(sizeof(struct Lambda)); o.lambda->params = copyList(params); o.lambda->body = copyList(body); o.lambda->refs = 1; + if (docs) { + o.lambda->params.docString = malloc(sizeof(char) * (strlen(docs->string) + 1)); + strcpy(o.lambda->params.docString, docs->string); + } else { + o.lambda->params.docString = NULL; + } + Object* dest = &o.lambda->body; FOR_POINTER_IN_LIST(dest) { if (POINTER->type == TYPE_SYMBOL) { diff --git a/src/object.h b/src/object.h index 5a2ce86..d7743d6 100644 --- a/src/object.h +++ b/src/object.h @@ -125,6 +125,7 @@ struct StructObject { struct Lambda { int refs; + /// Note: params.docstring can contain details about the constructed lambda. Object params; Object body; }; @@ -250,7 +251,7 @@ void errorAddContext(Object* o, const char* context, int lineNo, const char* fil struct Error noError(); -Object constructLambda(const Object* params, const Object* body, struct Environment* env); +Object constructLambda(const Object* params, const Object* docs, const Object* body, struct Environment* env); #ifdef STANDALONE diff --git a/src/pebblisp.c b/src/pebblisp.c index d12e7c9..d01badb 100644 --- a/src/pebblisp.c +++ b/src/pebblisp.c @@ -226,8 +226,13 @@ Object evalList(const Object* obj, struct Environment* env) return evalIfArgs(first_form->forward, env); } else if (strcmp(first_form->string, "fn") == 0) { Object* params = first_form->forward; - Object* body = params ? params->forward : NULL; - return constructLambda(params, body, env); + Object* doc = NULL; + Object* body = NULL; + if (params) { + doc = params->forward && params->forward->forward ? params->forward : NULL; + body = doc ? params->forward->forward : params->forward; + } + return constructLambda(params, doc, body, env); } else if (strcmp(first_form->string, "struct") == 0) { return evalStructArgs(first_form->forward, first_form->forward->forward, env); }