summaryrefslogtreecommitdiffstats
path: root/edify
diff options
context:
space:
mode:
Diffstat (limited to 'edify')
-rw-r--r--edify/expr.c161
-rw-r--r--edify/expr.h65
2 files changed, 166 insertions, 60 deletions
diff --git a/edify/expr.c b/edify/expr.c
index df3c1ab76..7a5b2fbf8 100644
--- a/edify/expr.c
+++ b/edify/expr.c
@@ -33,12 +33,39 @@ int BooleanString(const char* s) {
}
char* Evaluate(State* state, Expr* expr) {
+ Value* v = expr->fn(expr->name, state, expr->argc, expr->argv);
+ if (v == NULL) return NULL;
+ if (v->type != VAL_STRING) {
+ ErrorAbort(state, "expecting string, got value type %d", v->type);
+ FreeValue(v);
+ return NULL;
+ }
+ char* result = v->data;
+ free(v);
+ return result;
+}
+
+Value* EvaluateValue(State* state, Expr* expr) {
return expr->fn(expr->name, state, expr->argc, expr->argv);
}
-char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
+Value* StringValue(char* str) {
+ Value* v = malloc(sizeof(Value));
+ v->type = VAL_STRING;
+ v->size = strlen(str);
+ v->data = str;
+ return v;
+}
+
+void FreeValue(Value* v) {
+ if (v == NULL) return;
+ free(v->data);
+ free(v);
+}
+
+Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc == 0) {
- return strdup("");
+ return StringValue(strdup(""));
}
char** strings = malloc(argc * sizeof(char*));
int i;
@@ -68,10 +95,10 @@ char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
free(strings[i]);
}
free(strings);
- return result;
+ return StringValue(result);
}
-char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
+Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2 && argc != 3) {
free(state->errmsg);
state->errmsg = strdup("ifelse expects 2 or 3 arguments");
@@ -84,18 +111,18 @@ char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]) {
if (BooleanString(cond) == true) {
free(cond);
- return Evaluate(state, argv[1]);
+ return EvaluateValue(state, argv[1]);
} else {
if (argc == 3) {
free(cond);
- return Evaluate(state, argv[2]);
+ return EvaluateValue(state, argv[2]);
} else {
- return cond;
+ return StringValue(cond);
}
}
}
-char* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
+Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
char* msg = NULL;
if (argc > 0) {
msg = Evaluate(state, argv[0]);
@@ -109,7 +136,7 @@ char* AbortFn(const char* name, State* state, int argc, Expr* argv[]) {
return NULL;
}
-char* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
+Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
int i;
for (i = 0; i < argc; ++i) {
char* v = Evaluate(state, argv[i]);
@@ -131,20 +158,20 @@ char* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
return NULL;
}
}
- return strdup("");
+ return StringValue(strdup(""));
}
-char* SleepFn(const char* name, State* state, int argc, Expr* argv[]) {
+Value* SleepFn(const char* name, State* state, int argc, Expr* argv[]) {
char* val = Evaluate(state, argv[0]);
if (val == NULL) {
return NULL;
}
int v = strtol(val, NULL, 10);
sleep(v);
- return val;
+ return StringValue(val);
}
-char* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
+Value* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
int i;
for (i = 0; i < argc; ++i) {
char* v = Evaluate(state, argv[i]);
@@ -154,48 +181,44 @@ char* StdoutFn(const char* name, State* state, int argc, Expr* argv[]) {
fputs(v, stdout);
free(v);
}
- return strdup("");
+ return StringValue(strdup(""));
}
-char* LogicalAndFn(const char* name, State* state,
+Value* LogicalAndFn(const char* name, State* state,
int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
if (BooleanString(left) == true) {
free(left);
- return Evaluate(state, argv[1]);
+ return EvaluateValue(state, argv[1]);
} else {
- return left;
+ return StringValue(left);
}
}
-char* LogicalOrFn(const char* name, State* state,
- int argc, Expr* argv[]) {
+Value* LogicalOrFn(const char* name, State* state,
+ int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
if (BooleanString(left) == false) {
free(left);
- return Evaluate(state, argv[1]);
+ return EvaluateValue(state, argv[1]);
} else {
- return left;
+ return StringValue(left);
}
}
-char* LogicalNotFn(const char* name, State* state,
- int argc, Expr* argv[]) {
+Value* LogicalNotFn(const char* name, State* state,
+ int argc, Expr* argv[]) {
char* val = Evaluate(state, argv[0]);
if (val == NULL) return NULL;
bool bv = BooleanString(val);
free(val);
- if (bv) {
- return strdup("");
- } else {
- return strdup("t");
- }
+ return StringValue(strdup(bv ? "" : "t"));
}
-char* SubstringFn(const char* name, State* state,
- int argc, Expr* argv[]) {
+Value* SubstringFn(const char* name, State* state,
+ int argc, Expr* argv[]) {
char* needle = Evaluate(state, argv[0]);
if (needle == NULL) return NULL;
char* haystack = Evaluate(state, argv[1]);
@@ -207,10 +230,10 @@ char* SubstringFn(const char* name, State* state,
char* result = strdup(strstr(haystack, needle) ? "t" : "");
free(needle);
free(haystack);
- return result;
+ return StringValue(result);
}
-char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
+Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
char* right = Evaluate(state, argv[1]);
@@ -222,10 +245,10 @@ char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = strdup(strcmp(left, right) == 0 ? "t" : "");
free(left);
free(right);
- return result;
+ return StringValue(result);
}
-char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
+Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* left = Evaluate(state, argv[0]);
if (left == NULL) return NULL;
char* right = Evaluate(state, argv[1]);
@@ -237,17 +260,17 @@ char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = strdup(strcmp(left, right) != 0 ? "t" : "");
free(left);
free(right);
- return result;
+ return StringValue(result);
}
-char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) {
- char* left = Evaluate(state, argv[0]);
+Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]) {
+ Value* left = EvaluateValue(state, argv[0]);
if (left == NULL) return NULL;
- free(left);
- return Evaluate(state, argv[1]);
+ FreeValue(left);
+ return EvaluateValue(state, argv[1]);
}
-char* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
+Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 2) {
free(state->errmsg);
state->errmsg = strdup("less_than_int expects 2 arguments");
@@ -278,10 +301,11 @@ char* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
done:
free(left);
free(right);
- return strdup(result ? "t" : "");
+ return StringValue(strdup(result ? "t" : ""));
}
-char* GreaterThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
+Value* GreaterThanIntFn(const char* name, State* state,
+ int argc, Expr* argv[]) {
if (argc != 2) {
free(state->errmsg);
state->errmsg = strdup("greater_than_int expects 2 arguments");
@@ -295,8 +319,8 @@ char* GreaterThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
return LessThanIntFn(name, state, 2, temp);
}
-char* Literal(const char* name, State* state, int argc, Expr* argv[]) {
- return strdup(name);
+Value* Literal(const char* name, State* state, int argc, Expr* argv[]) {
+ return StringValue(strdup(name));
}
Expr* Build(Function fn, YYLTYPE loc, int count, ...) {
@@ -400,6 +424,32 @@ int ReadArgs(State* state, Expr* argv[], int count, ...) {
return 0;
}
+// Evaluate the expressions in argv, giving 'count' Value* (the ... is
+// zero or more Value** to put them in). If any expression evaluates
+// to NULL, free the rest and return -1. Return 0 on success.
+int ReadValueArgs(State* state, Expr* argv[], int count, ...) {
+ Value** args = malloc(count * sizeof(Value*));
+ va_list v;
+ va_start(v, count);
+ int i;
+ for (i = 0; i < count; ++i) {
+ args[i] = EvaluateValue(state, argv[i]);
+ if (args[i] == NULL) {
+ va_end(v);
+ int j;
+ for (j = 0; j < i; ++j) {
+ FreeValue(args[j]);
+ }
+ free(args);
+ return -1;
+ }
+ *(va_arg(v, Value**)) = args[i];
+ }
+ va_end(v);
+ free(args);
+ return 0;
+}
+
// Evaluate the expressions in argv, returning an array of char*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
@@ -421,9 +471,30 @@ char** ReadVarArgs(State* state, int argc, Expr* argv[]) {
return args;
}
+// Evaluate the expressions in argv, returning an array of Value*
+// results. If any evaluate to NULL, free the rest and return NULL.
+// The caller is responsible for freeing the returned array and the
+// Values it contains.
+Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) {
+ Value** args = (Value**)malloc(argc * sizeof(Value*));
+ int i = 0;
+ for (i = 0; i < argc; ++i) {
+ args[i] = EvaluateValue(state, argv[i]);
+ if (args[i] == NULL) {
+ int j;
+ for (j = 0; j < i; ++j) {
+ FreeValue(args[j]);
+ }
+ free(args);
+ return NULL;
+ }
+ }
+ return args;
+}
+
// Use printf-style arguments to compose an error message to put into
// *state. Returns NULL.
-char* ErrorAbort(State* state, char* format, ...) {
+Value* ErrorAbort(State* state, char* format, ...) {
char* buffer = malloc(4096);
va_list v;
va_start(v, format);
diff --git a/edify/expr.h b/edify/expr.h
index d2e739201..1462531b0 100644
--- a/edify/expr.h
+++ b/edify/expr.h
@@ -39,8 +39,17 @@ typedef struct {
char* errmsg;
} State;
-typedef char* (*Function)(const char* name, State* state,
- int argc, Expr* argv[]);
+#define VAL_STRING 1 // data will be NULL-terminated; size doesn't count null
+#define VAL_BLOB 2
+
+typedef struct {
+ int type;
+ ssize_t size;
+ char* data;
+} Value;
+
+typedef Value* (*Function)(const char* name, State* state,
+ int argc, Expr* argv[]);
struct Expr {
Function fn;
@@ -50,31 +59,41 @@ struct Expr {
int start, end;
};
+// Take one of the Expr*s passed to the function as an argument,
+// evaluate it, return the resulting Value. The caller takes
+// ownership of the returned Value.
+Value* EvaluateValue(State* state, Expr* expr);
+
+// Take one of the Expr*s passed to the function as an argument,
+// evaluate it, assert that it is a string, and return the resulting
+// char*. The caller takes ownership of the returned char*. This is
+// a convenience function for older functions that want to deal only
+// with strings.
char* Evaluate(State* state, Expr* expr);
// Glue to make an Expr out of a literal.
-char* Literal(const char* name, State* state, int argc, Expr* argv[]);
+Value* Literal(const char* name, State* state, int argc, Expr* argv[]);
// Functions corresponding to various syntactic sugar operators.
// ("concat" is also available as a builtin function, to concatenate
// more than two strings.)
-char* ConcatFn(const char* name, State* state, int argc, Expr* argv[]);
-char* LogicalAndFn(const char* name, State* state, int argc, Expr* argv[]);
-char* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]);
-char* LogicalNotFn(const char* name, State* state, int argc, Expr* argv[]);
-char* SubstringFn(const char* name, State* state, int argc, Expr* argv[]);
-char* EqualityFn(const char* name, State* state, int argc, Expr* argv[]);
-char* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
-char* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* LogicalAndFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* LogicalOrFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* LogicalNotFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* SubstringFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* EqualityFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* InequalityFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* SequenceFn(const char* name, State* state, int argc, Expr* argv[]);
// Convenience function for building expressions with a fixed number
// of arguments.
Expr* Build(Function fn, YYLTYPE loc, int count, ...);
// Global builtins, registered by RegisterBuiltins().
-char* IfElseFn(const char* name, State* state, int argc, Expr* argv[]);
-char* AssertFn(const char* name, State* state, int argc, Expr* argv[]);
-char* AbortFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* IfElseFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]);
+Value* AbortFn(const char* name, State* state, int argc, Expr* argv[]);
// For setting and getting the global error string (when returning
@@ -112,15 +131,31 @@ Function FindFunction(const char* name);
// to NULL, free the rest and return -1. Return 0 on success.
int ReadArgs(State* state, Expr* argv[], int count, ...);
+// Evaluate the expressions in argv, giving 'count' Value* (the ... is
+// zero or more Value** to put them in). If any expression evaluates
+// to NULL, free the rest and return -1. Return 0 on success.
+int ReadValueArgs(State* state, Expr* argv[], int count, ...);
+
// Evaluate the expressions in argv, returning an array of char*
// results. If any evaluate to NULL, free the rest and return NULL.
// The caller is responsible for freeing the returned array and the
// strings it contains.
char** ReadVarArgs(State* state, int argc, Expr* argv[]);
+// Evaluate the expressions in argv, returning an array of Value*
+// results. If any evaluate to NULL, free the rest and return NULL.
+// The caller is responsible for freeing the returned array and the
+// Values it contains.
+Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]);
+
// Use printf-style arguments to compose an error message to put into
// *state. Returns NULL.
-char* ErrorAbort(State* state, char* format, ...);
+Value* ErrorAbort(State* state, char* format, ...);
+
+// Wrap a string into a Value, taking ownership of the string.
+Value* StringValue(char* str);
+// Free a Value object.
+void FreeValue(Value* v);
#endif // _EXPRESSION_H