commit 698df4516bb7a9224a726dc5117ae60ae156d21a
parent 520534baedc529ed128876adbf70be26eb0de73e
Author: Demonstrandum <moi@knutsen.co>
Date: Thu, 25 Jun 2020 01:15:17 +0100
Added functions 'sin' and 'factorial'
Diffstat:
7 files changed, 160 insertions(+), 19 deletions(-)
diff --git a/src/builtin.c b/src/builtin.c
@@ -75,6 +75,56 @@ NumberNode *upcast_pair(NumberNode lhs, NumberNode rhs)
return pair;
}
+DataValue *builtin_sin(DataValue input)
+{
+ NumberNode *num = type_check("sin", ARG, T_NUMBER, &input);
+ if (num == NULL)
+ return NULL;
+ DataValue *result = wrap_data(T_NUMBER, num);
+
+ NumberNode tmp = num_to_float(*num);
+ memcpy(num, &tmp, sizeof(NumberNode));
+ num->value.f = sin(num->value.f);
+ num->type = FLOAT;
+ result->value = num;
+ return result;
+}
+
+DataValue *builtin_factorial(DataValue input)
+{
+ NumberNode *num = type_check("!", LHS, T_NUMBER, &input);
+ if (num == NULL)
+ return NULL;
+
+ if (num->type != INT || num->value.i < 0) {
+ ERROR_TYPE = EXECUTION_ERROR;
+ strcpy(ERROR_MSG,
+ "factorial (`!') is only defined for positve integers.");
+ }
+
+ NumberNode tmp = num_to_int(*num);
+ memcpy(num, &tmp, sizeof(NumberNode));
+
+ DataValue *result = wrap_data(T_NUMBER, num);
+ if (num->value.i == 0) {
+ num->value.i = 1;
+ result->value = num;
+ return result;
+ }
+ ssize i = num->value.i - 1;
+ while (i > 1) {
+ num->value.i *= i;
+ --i;
+ }
+ result->value = num;
+ return result;
+}
+
+FnPtr builtin_fns[] = {
+ { builtin_sin },
+ { builtin_factorial },
+};
+
#define BINARY_FUNCTION(NAME, OP) \
NumberNode *num_ ## NAME (NumberNode lhs, NumberNode rhs) \
{ \
diff --git a/src/builtin.h b/src/builtin.h
@@ -1,13 +1,20 @@
#pragma once
+#include <math.h>
+
#include "prelude.h"
#include "parse.h"
+#include "execute.h"
#include "error.h"
NumberNode num_to_float(NumberNode);
NumberNode num_to_int(NumberNode);
NumberNode *upcast_pair(NumberNode, NumberNode);
+DataValue *builtin_sin(DataValue);
+
+extern FnPtr builtin_fns[];
+
NumberNode *num_add(NumberNode, NumberNode);
NumberNode *num_sub(NumberNode, NumberNode);
NumberNode *num_mul(NumberNode, NumberNode);
diff --git a/src/execute.c b/src/execute.c
@@ -4,7 +4,9 @@
#include "builtin.h"
#include "displays.h"
-#define BINARY_OPERATION(OPERATION) do { \
+#include <math.h>
+
+#define NUMERICAL_BINARY_OPERATION(OPERATION) do { \
NumberNode *l_num = type_check("+", LHS, T_NUMBER, lhs); \
NumberNode *r_num = type_check("+", RHS, T_NUMBER, rhs); \
if (l_num == NULL || r_num == NULL) \
@@ -35,28 +37,24 @@ DataValue *execute(Context *ctx, const ParseNode *stmt)
// throw an execution error.
char *ident_name = stmt->node.ident.value;
- free(data);
- data = NULL;
-
Context *current_ctx = ctx;
while (current_ctx != NULL) {
for (usize i = 0; i < current_ctx->locals_count; ++i) {
Local *local = ¤t_ctx->locals[i];
if (strcmp(local->name, ident_name) == 0) {
- data = &local->value;
+ *data = local->value;
goto finished_search;
}
}
current_ctx = current_ctx->superior;
}
+ ERROR_TYPE = EXECUTION_ERROR;
+ sprintf(ERROR_MSG, "Could not find variable `%s'\n"
+ " in any local or superior scope.", ident_name);
+ return NULL;
+
finished_search:
- if (data == NULL) {
- ERROR_TYPE = EXECUTION_ERROR;
- sprintf(ERROR_MSG, "Could not find variable `%s'\n"
- " in any local or superior scope.", ident_name);
- return NULL;
- }
break;
}
case NUMBER_NODE: {
@@ -65,6 +63,32 @@ finished_search:
memcpy(data->value, &stmt->node.number, sizeof(NumberNode));
break;
}
+ case UNARY_NODE: { // Functions, essentially.
+ DataValue *callee = execute(ctx, stmt->node.unary.callee);
+ DataValue *operand = execute(ctx, stmt->node.unary.operand);
+
+ if (callee == NULL || operand == NULL)
+ return NULL;
+
+ // Juxtaposition of numbers, implies multiplication.
+ if (callee->type == T_NUMBER && operand->type == T_NUMBER) {
+ data->type = T_NUMBER;
+ data->value = num_mul(*(NumberNode *)callee->value,
+ *(NumberNode *)operand->value);
+ break;
+ }
+
+ // Otheriwse, we expect a function pointer as callee.
+ FnPtr *func = type_check("function", ARG, T_FUNCTION_PTR, callee);
+ if (func == NULL)
+ return NULL;
+
+ FUNC_PTR(fn) = func->fn;
+ free(data);
+ data = fn(*operand);
+
+ break;
+ }
case BINARY_NODE: {
IdentNode ident = stmt->node.binary.callee->node.ident;
if (stmt->node.binary.callee->type != IDENT_NODE) {
@@ -78,13 +102,13 @@ finished_search:
DataValue *rhs = execute(ctx, stmt->node.binary.right);
if (strcmp(op, "+") == 0) {
- BINARY_OPERATION(add);
+ NUMERICAL_BINARY_OPERATION(add);
} else if (strcmp(op, "-") == 0) {
- BINARY_OPERATION(sub);
+ NUMERICAL_BINARY_OPERATION(sub);
} else if (strcmp(op, "*") == 0) {
- BINARY_OPERATION(mul);
+ NUMERICAL_BINARY_OPERATION(mul);
} else if (strcmp(op, "/") == 0) {
- BINARY_OPERATION(div);
+ NUMERICAL_BINARY_OPERATION(div);
} else {
ERROR_TYPE = EXECUTION_ERROR;
sprintf(ERROR_MSG, "Do not know how to evaluate"
@@ -140,6 +164,25 @@ Local *make_local(char *name, DataType type, void *value)
return local;
}
+void bind_local(Context *ctx, char *name, DataType type, void *value)
+{
+ Local *local = make_local(name, type, value);
+ ctx->locals[ctx->locals_count] = *local;
+ ++ctx->locals_count;
+}
+
+void bind_builtin_functions(Context *ctx)
+{
+ bind_local(ctx, "sin", T_FUNCTION_PTR, &builtin_fns[0]);
+ bind_local(ctx, "!", T_FUNCTION_PTR, &builtin_fns[1]);
+}
+
+void bind_default_globals(Context *ctx)
+{
+ fsize pi = M_PI;
+ bind_local(ctx, "pi", T_NUMBER, make_number(FLOAT, &pi));
+}
+
Context *init_context()
{
Context *ctx = malloc(sizeof(Context));
@@ -157,13 +200,21 @@ Context *init_context()
// name of the function/scope.
Local *scope_name = make_local(
"__this_scope", T_STRING, ctx->function);
- ctx->locals = scope_name;
+ ctx->locals[0] = *scope_name;
// ^ Sets the first variable, default in every scope
// (good for debuggin purposes).
return ctx;
}
+Context *base_context()
+{
+ Context *ctx = init_context();
+ bind_default_globals(ctx);
+ bind_builtin_functions(ctx);
+ return ctx;
+}
+
Context *make_context(char *scope_name, Context *super_scope)
{
Context *ctx = init_context();
diff --git a/src/execute.h b/src/execute.h
@@ -5,8 +5,8 @@
typedef enum {
T_NUMBER, // NumberNode (ParsNode).
- T_STRING, // (Native?) char pointer.
- T_FUNCTION_PTR, // Native function pointer.
+ T_STRING, // Native char pointer.
+ T_FUNCTION_PTR, // Wrapper of native function pointer.
} DataType;
typedef struct {
@@ -14,6 +14,13 @@ typedef struct {
void *value;
} DataValue;
+#define FUNC_PTR(FUNC_NAME) \
+ DataValue *(*FUNC_NAME)(DataValue)
+
+typedef struct {
+ FUNC_PTR(fn);
+} FnPtr;
+
typedef struct {
char *name;
DataValue value;
@@ -37,6 +44,10 @@ typedef enum {
void free_datavalue(DataValue *);
void *type_check(char *, ParamPos, DataType, DataValue *);
DataValue *execute(Context *, const ParseNode *);
+DataValue *wrap_data(DataType, void *);
Local *make_local(char *, DataType, void *);
+void bind_local(Context *, char *name, DataType, void*);
+void bind_builtin_functions(Context *);
Context *init_context();
+Context *base_context();
Context *make_context(char *, Context *);
diff --git a/src/main.c b/src/main.c
@@ -63,7 +63,7 @@ int main(int argc, char **argv)
printf("Reading history from `%s'.\n", cache_loc);
}
- Context *ctx = init_context();
+ Context *ctx = base_context();
char *response = NULL;
do {
diff --git a/src/parse.c b/src/parse.c
@@ -178,6 +178,27 @@ void node_into_ident(const char *str, ParseNode *node)
node->node.ident = *ident;
}
+NumberNode *make_number(NumberType type, void *val)
+{
+ NumberNode *num = malloc(sizeof(NumberNode));
+ num->type = type;
+ num->value.i = -1;
+ switch (type) {
+ case INT: {
+ num->value.i = *(ssize *)val;
+ break;
+ }
+ case FLOAT: {
+ num->value.f = *((fsize *)val);
+ break;
+ }
+ default:
+ printf("Never get here!\n\n");
+ break;
+ }
+ return num;
+}
+
NumberNode *parse_number(const char *str)
{
NumberNode *number = malloc(sizeof(NumberNode));
diff --git a/src/parse.h b/src/parse.h
@@ -123,6 +123,7 @@ void free_parsenode(ParseNode *);
Token *lex(char **);
Token *peek(char **);
+NumberNode *make_number(NumberType, void *);
NumberNode *parse_number(const char *);
ParseNode *parse_prefix(const Token *, char **);
ParseNode *parse_infix(const ParseNode *, const Token *, char **, u16);