Add simple Promise type.
A bit unstable. Almost certainly needs some locking on struct Promise fields.
This commit is contained in:
parent
fc4f0bef28
commit
b54b93c7d1
|
@ -1,5 +1,5 @@
|
|||
files = main.c pebblisp.c tokens.c object.c env.c web.c plfunc.c hash.c
|
||||
libs = -lreadline -lmicrohttpd
|
||||
files = main.c pebblisp.c tokens.c object.c env.c web.c plfunc.c hash.c threads.c
|
||||
libs = -lreadline -lmicrohttpd -lpthread
|
||||
exe = pl
|
||||
|
||||
file_libs := $(files) $(libs)
|
||||
|
|
11
src/env.c
11
src/env.c
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "pebblisp.h"
|
||||
#include "web.h"
|
||||
#include "threads.h"
|
||||
#include "plfunc.h"
|
||||
|
||||
struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object*, int, struct Environment*), const char* help,
|
||||
|
@ -57,6 +58,7 @@ struct symFunc {
|
|||
#endif
|
||||
|
||||
#ifndef HASHLESS_ENV // Hash-based env
|
||||
|
||||
Object* fetch(const char* name, struct Environment* env)
|
||||
{
|
||||
while (env) {
|
||||
|
@ -207,6 +209,8 @@ struct Environment defaultEnv()
|
|||
pf(takeInput),
|
||||
pf(readFileToObject),
|
||||
pf(getEnvVar),
|
||||
pf(async),
|
||||
pf(await),
|
||||
pf(help)
|
||||
#endif
|
||||
};
|
||||
|
@ -471,6 +475,8 @@ struct Environment defaultEnvPreAllocated(struct EnvElement* elements)
|
|||
pf(takeInput),
|
||||
pf(readFileToObject),
|
||||
pf(getEnvVar),
|
||||
pf(async),
|
||||
pf(await),
|
||||
pf(help)
|
||||
#endif
|
||||
};
|
||||
|
@ -554,6 +560,7 @@ void shredDictionary()
|
|||
}
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
||||
struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object*, int, struct Environment*), const char* help,
|
||||
const char* const* tests, size_t testLength)
|
||||
{
|
||||
|
@ -570,6 +577,7 @@ struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object*, int, st
|
|||
.sym = symbol,
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
struct symFunc buildFuncSym(const char* symbol, Object (* func)(Object*, int, struct Environment*))
|
||||
{
|
||||
|
@ -699,7 +707,7 @@ int runTests(int detailed)
|
|||
char* result = stringObj(&o, &length);
|
||||
cleanObject(&o);
|
||||
int expectedLen = 0;
|
||||
while(expected[expectedLen] && expected[expectedLen] != ';') {
|
||||
while (expected[expectedLen] && expected[expectedLen] != ';') {
|
||||
expectedLen++;
|
||||
}
|
||||
if (strncmp(result, expected, expectedLen) != 0) {
|
||||
|
@ -733,6 +741,7 @@ int runTests(int detailed)
|
|||
// fprintf(stderr, "TOTAL BYTES: %zu\n", getBytes());
|
||||
return failureCount;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int getStructIndex(const char* name)
|
||||
|
|
17
src/object.c
17
src/object.c
|
@ -6,6 +6,9 @@
|
|||
#include <string.h>
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
||||
#include "threads.h"
|
||||
|
||||
size_t bytes = 0;
|
||||
|
||||
size_t getBytes()
|
||||
|
@ -148,7 +151,7 @@ static const char* errorText[] = {
|
|||
"NO_CLONE_SPECIFIED",
|
||||
"CAN_ONLY_EVAL_STRINGS",
|
||||
"UNEXPECTED_EOF",
|
||||
"INDEX_PAST_END"};
|
||||
"INDEX_PAST_END" };
|
||||
#endif
|
||||
|
||||
size_t inflate(struct string* s, size_t additional)
|
||||
|
@ -172,7 +175,7 @@ size_t inflate(struct string* s, size_t additional)
|
|||
return s->capacity;
|
||||
}
|
||||
|
||||
int stringNObj(struct string *s, const Object* obj);
|
||||
int stringNObj(struct string* s, const Object* obj);
|
||||
|
||||
/**
|
||||
* Creates a string from a given list Object
|
||||
|
@ -263,6 +266,9 @@ int stringNObj(struct string* s, const Object* obj)
|
|||
case TYPE_LIST:
|
||||
stringList(s, obj);
|
||||
break;
|
||||
case TYPE_PROMISE:
|
||||
s->cursor += sprintf(s->cursor, isDone(obj->promise) ? "<DONE>" : "<PENDING>");
|
||||
break;
|
||||
case TYPE_ERROR: {
|
||||
int code = getErrorCode(*obj);
|
||||
#ifdef SIMPLE_ERRORS
|
||||
|
@ -344,6 +350,7 @@ void printType(const Object* obj)
|
|||
SIMPLE_TYPE(TYPE_FUNC);
|
||||
SIMPLE_TYPE(TYPE_SYMBOL);
|
||||
SIMPLE_TYPE(TYPE_STRING);
|
||||
SIMPLE_TYPE(TYPE_PROMISE);
|
||||
SIMPLE_TYPE(TYPE_OTHER);
|
||||
SIMPLE_TYPE(TYPE_ERROR);
|
||||
case TYPE_LAMBDA:
|
||||
|
@ -426,6 +433,9 @@ void cleanObject(Object* target)
|
|||
free(target->structObject->fields);
|
||||
free(target->structObject);
|
||||
break;
|
||||
case TYPE_PROMISE:
|
||||
cleanPromise(target->promise);
|
||||
break;
|
||||
case TYPE_ERROR:
|
||||
#ifndef SIMPLE_ERRORS
|
||||
free(target->error->plContext);
|
||||
|
@ -603,6 +613,7 @@ inline int isValidType(const Object test)
|
|||
case TYPE_SYMBOL:
|
||||
case TYPE_LAMBDA:
|
||||
case TYPE_STRING:
|
||||
case TYPE_PROMISE:
|
||||
case TYPE_OTHER:
|
||||
case TYPE_ERROR:
|
||||
return 1;
|
||||
|
@ -648,6 +659,8 @@ inline Object cloneObject(const Object src)
|
|||
case TYPE_STRING:
|
||||
case TYPE_SYMBOL:
|
||||
return cloneString(src);
|
||||
case TYPE_PROMISE:
|
||||
return clonePromise(src);
|
||||
case TYPE_ERROR:
|
||||
return errorWithContext(getErrorCode(src), src.error->context);
|
||||
case TYPE_OTHER:
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#define sprintf(_dest, args...) snprintf(_dest, 999, args)
|
||||
|
||||
#else
|
||||
|
||||
#ifdef DEBUG
|
||||
#define printd(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
|
@ -67,6 +68,7 @@ typedef enum Type {
|
|||
TYPE_SYMBOL,
|
||||
TYPE_LAMBDA,
|
||||
TYPE_STRING,
|
||||
TYPE_PROMISE,
|
||||
TYPE_OTHER,
|
||||
TYPE_ERROR
|
||||
} Type;
|
||||
|
@ -75,6 +77,7 @@ typedef struct Object Object;
|
|||
|
||||
struct Lambda;
|
||||
struct Environment;
|
||||
struct Promise;
|
||||
struct Other;
|
||||
struct Error {
|
||||
enum errorCode code;
|
||||
|
@ -95,6 +98,7 @@ struct Object {
|
|||
struct StructObject* structObject;
|
||||
struct Lambda* lambda;
|
||||
struct Other* other;
|
||||
struct Promise* promise;
|
||||
#ifdef SIMPLE_ERRORS
|
||||
enum errorCode error;
|
||||
#else
|
||||
|
@ -246,6 +250,7 @@ struct Error noError();
|
|||
Object constructLambda(const Object* params, const Object* body, struct Environment* env);
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
||||
int getAllocations();
|
||||
|
||||
size_t getBytes();
|
||||
|
|
|
@ -287,6 +287,7 @@ Object eval(const Object* obj, struct Environment* env)
|
|||
case TYPE_STRING:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_SLIST:
|
||||
case TYPE_PROMISE:
|
||||
return cloneObject(*obj);
|
||||
|
||||
case TYPE_SYMBOL:
|
||||
|
|
|
@ -187,7 +187,7 @@ Object chars(Object* params, unused int length, unused struct Environment* env)
|
|||
c[1] = '\0';
|
||||
int i = 0;
|
||||
Object list = listObject();
|
||||
while(params[0].string[i]) {
|
||||
while (params[0].string[i]) {
|
||||
c[0] = params[0].string[i];
|
||||
nf_addToList(&list, stringFromSlice(c, 1));
|
||||
i++;
|
||||
|
@ -198,7 +198,7 @@ Object chars(Object* params, unused int length, unused struct Environment* env)
|
|||
size_t literalLen(const char* pattern)
|
||||
{
|
||||
const char* cursor = pattern;
|
||||
while(*cursor != '*' && *cursor != '\0') {
|
||||
while (*cursor != '*' && *cursor != '\0') {
|
||||
cursor++;
|
||||
}
|
||||
return cursor - pattern;
|
||||
|
@ -457,7 +457,7 @@ Object numToChar(Object* params, unused int length, unused struct Environment* e
|
|||
checkTypes(numToChar)
|
||||
Object c = params[0];
|
||||
|
||||
if (c.type != TYPE_NUMBER) {
|
||||
if (c.type != TYPE_NUMBER || c.number > 255 || c.number < 0) {
|
||||
return errorObject(BAD_NUMBER);
|
||||
}
|
||||
char ch[1] = { c.number };
|
||||
|
@ -561,4 +561,5 @@ Object getEnvVar(Object* params, unused int length, unused struct Environment* e
|
|||
checkTypes(getEnvVar)
|
||||
return nullTerminated(getenv(params[0].string));
|
||||
}
|
||||
|
||||
#endif // STANDALONE
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#include "threads.h"
|
||||
#include "object.h"
|
||||
#include "pebblisp.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct Promise {
|
||||
int done;
|
||||
int refs;
|
||||
struct Environment* env;
|
||||
Object object;
|
||||
pthread_t thread;
|
||||
};
|
||||
|
||||
Object clonePromise(Object src)
|
||||
{
|
||||
src.promise->refs += 1;
|
||||
return src;
|
||||
}
|
||||
|
||||
int isDone(struct Promise* promise)
|
||||
{
|
||||
return promise->done;
|
||||
}
|
||||
|
||||
void cleanPromise(struct Promise* promise)
|
||||
{
|
||||
promise->refs -= 1;
|
||||
if (promise->refs == 0) {
|
||||
free(promise);
|
||||
}
|
||||
}
|
||||
|
||||
Object await(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
struct Promise* promise = params[0].promise;
|
||||
if (!promise->done) { // TODO: Does `done` need a mutex or other lock?
|
||||
pthread_join(promise->thread, NULL);
|
||||
}
|
||||
return cloneObject(promise->object);
|
||||
}
|
||||
|
||||
void* doAsync(void* args)
|
||||
{
|
||||
struct Promise* promise = args;
|
||||
|
||||
Object cloned = cloneObject(promise->object);
|
||||
Object first_eval = eval(&cloned, promise->env);
|
||||
Object e = listEvalLambda(&first_eval, NULL, 1, promise->env);
|
||||
|
||||
promise->object = e;
|
||||
promise->done = 1;
|
||||
cleanPromise(promise);
|
||||
|
||||
cleanObject(&cloned);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Object async(Object* params, int length, struct Environment* env)
|
||||
{
|
||||
Object promise = newObject(TYPE_PROMISE);
|
||||
promise.promise = malloc(sizeof(struct Promise));
|
||||
*promise.promise = (struct Promise) {
|
||||
.refs = 2,
|
||||
.done = 0,
|
||||
.env = env,
|
||||
.object = params[0], // TODO: Clone?
|
||||
};
|
||||
|
||||
pthread_create(&promise.promise->thread, NULL, doAsync, promise.promise);
|
||||
return promise;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#ifdef STANDALONE
|
||||
|
||||
#ifndef THREADS_H
|
||||
#define THREADS_H
|
||||
|
||||
#include "pebblisp.h"
|
||||
|
||||
Object clonePromise(Object src);
|
||||
|
||||
void cleanPromise(struct Promise* promise);
|
||||
|
||||
int isDone(struct Promise* promise);
|
||||
|
||||
fn(async, "async",
|
||||
"Run the given lambda on a separate thread.",
|
||||
"(def sleepy (fn () ((sys \"sleep 0.1\") \"Hiya\"))) (def x (async sleepy)) x", "<PENDING>",
|
||||
"(def sleepy (fn () ((sys \"sleep 0.1\") \"Hiya\"))) (def x (async sleepy)) (await x)", "Hiya",
|
||||
);
|
||||
|
||||
fn(await, "await",
|
||||
""
|
||||
);
|
||||
|
||||
#endif // PEBBLISP_THREADS_H
|
||||
|
||||
#endif // STANDALONE
|
Loading…
Reference in New Issue