commit 2371441cbf6ff1ee4ebbbcece350721798bb8b57
parent 544607481e0d7f0a5b595fd4c30d0481e46a446b
Author: Demonstrandum <moi@knutsen.co>
Date:   Mon, 17 Aug 2020 01:37:37 +0100
Ability to cancel execution.
Diffstat:
7 files changed, 107 insertions(+), 46 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
 CC := gcc
 OPT := -O3
-WARN := -Wall -Wpedantic -Wextra -Wshadow -fcompare-debug-second
-LINKS := -lm -lreadline
+WARN := -Wall -Wpedantic -Wextra -Wshadow -Wno-psabi
+LINKS := -lm -lreadline -lpthread
 CFLAGS := $(WARN) $(OPT)
 TARGET := crepl
 OBJS := main.o defaults.o error.o parse.o displays.o builtin.o execute.o prelude.o
diff --git a/src/builtin.c b/src/builtin.c
@@ -76,6 +76,19 @@ NumberNode *upcast_pair(NumberNode lhs, NumberNode rhs)
 	return pair;
 }
 
+DataValue *builtin_sleep(DataValue seconds)
+{
+	NumberNode *num = type_check("sleep", ARG, T_NUMBER, &seconds);
+	if (num == NULL) return NULL;
+
+	NumberNode *time = malloc(sizeof(NumberNode));
+	*time = num_to_int(*num);
+	if (time->value.i < 0) time->value.i = 0;
+
+	sleep((unsigned)time->value.i);
+	return wrap_data(T_NUMBER, time);
+}
+
 #define MATH_WRAPPER(NAME, FUNC)\
 DataValue *builtin_ ##NAME (DataValue input) \
 { \
diff --git a/src/builtin.h b/src/builtin.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <math.h>
+#include <unistd.h>
 
 #include "defaults.h"
 #include "parse.h"
@@ -13,6 +14,7 @@ NumberNode *upcast_pair(NumberNode, NumberNode);
 
 fsize gamma_func(float, fsize);
 fsize gammae(fsize);
+DataValue *builtin_sleep(DataValue);
 DataValue *builtin_sin(DataValue);
 DataValue *builtin_sinh(DataValue);
 DataValue *builtin_cos(DataValue);
@@ -52,6 +54,7 @@ struct _func_name_pair {
 };
 
 static const struct _func_name_pair builtin_fns[] = {
+	FUNC_PAIR(sleep),
 	FUNC_PAIR(sin),
 	FUNC_PAIR(sinh),
 	FUNC_PAIR(cos),
diff --git a/src/defaults.c b/src/defaults.c
@@ -15,7 +15,20 @@ ssize ipow(ssize base, usize exp)
     return result;
 }
 
-char *trim(char *str)
+char *remove_all_char(const char *str, char chr)
+{
+	char *new = strdup(str);
+	size_t str_len = strlen(str);
+	size_t new_len = 0;
+
+	for (size_t i = 0; i < str_len; ++i)
+		if (str[i] != chr) new[new_len++] = str[i];
+
+	new[new_len] = '\0';
+	return new;
+}
+
+char *trim(const char *str)
 {
 	char *p = strdup(str);
 	while (isspace(*p))
@@ -30,7 +43,7 @@ char *trim(char *str)
 }
 
 
-char *downcase(char *str)
+char *downcase(const char *str)
 {
 	char *p = strdup(str);
 	char *start = p;
diff --git a/src/defaults.h b/src/defaults.h
@@ -38,8 +38,9 @@ typedef long double fsize;
 
 ssize ipow(ssize, usize);
 
-char *trim(char *);
-char *downcase(char *);
+char *remove_all_char(const char *, char);
+char *trim(const char *);
+char *downcase(const char *);
 
 #define STR_HELPER(x) #x
 #define STR(x) STR_HELPER(x)
diff --git a/src/main.c b/src/main.c
@@ -1,7 +1,9 @@
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <string.h>
 #include <signal.h>
+#include <pthread.h>
 #include <sys/stat.h>
 #include <wchar.h>
 
@@ -16,13 +18,61 @@
 
 static const char *PROMPT = "::> ";
 
+char *response = NULL;
+pthread_t thread_id = 0;
+
 void sigint_handle(int sig)
 {
 	printf("\b\b  ");  // Obsucre '^C' output.
-	printf("\nInterrupted (%d), [Ctrl-D] to stop inputting.\n", sig);
-    rl_on_new_line();
-	rl_replace_line("", 0);
-    rl_redisplay();
+	if (thread_id == 0) {
+		puts("\b\b\033[90m//----\033[0m");
+		printf("\033[1m");
+		printf("Signal (%d), [Ctrl-D] to stop inputting.\n", sig);
+		printf("\033[0m");
+		rl_on_new_line();
+		rl_replace_line("", 0);
+		rl_redisplay();
+	} else {
+		pthread_cancel(thread_id);
+		printf("\b\b\033[1mInterrputed expression evaluation");
+		printf(" (thread 0x%lX).\033[0m\n", thread_id);
+		thread_id = 0;
+	}
+
+}
+
+void *evaluation_thread(void *ctx_void)
+{
+	Context *ctx = ctx_void;
+
+	ParseNode *tree   = NULL;
+	DataValue *result = NULL;
+
+	tree = parse(response);
+
+	if (tree == NULL || ERROR_TYPE != NO_ERROR) {
+		handle_error();
+		return (void *)EXIT_FAILURE;
+	}
+
+	printf("\033[%luC\033[1A",
+		strlen(PROMPT)
+		+ strlen(response));
+	printf("\033[2m ≡ %s\033[0m\n", display_parsetree(tree));
+
+	result = execute(ctx, tree);
+
+	if (result == NULL || ERROR_TYPE != NO_ERROR) {
+		handle_error();
+		return (void *)EXIT_FAILURE;
+	}
+
+	if (result != NULL)
+		printf("#=> %s\n", display_datavalue(result));
+	if (tree != NULL)
+		free_parsenode(tree);
+
+	return (void *)EXIT_SUCCESS;
 }
 
 int main(int argc, char **argv)
@@ -65,7 +115,6 @@ int main(int argc, char **argv)
 
 	Context *ctx = base_context();
 
-	char *response = NULL;
 	do {
 		char *line = readline(PROMPT);
 
@@ -77,29 +126,10 @@ int main(int argc, char **argv)
 			add_history(line);
 		response = line;
 
-		// Try to lex & parse the input.
-		ParseNode *tree = parse(response);
-
-		if (tree == NULL || ERROR_TYPE != NO_ERROR) {
-			handle_error();
-			continue;
-		}
-
-		printf("\033[%luC\033[1A",
-			strlen(PROMPT)
-			+ strlen(response));
-		printf("\033[2m ≡ %s\033[0m\n", display_parsetree(tree));
-
-		DataValue *result = execute(ctx, tree);
-
-		if (result == NULL || ERROR_TYPE != NO_ERROR) {
-			handle_error();
-			continue;
-		}
-
-		printf("#=> %s\n", display_datavalue(result));
-
-		free_parsenode(tree);
+		// Evaluation of input is done in thread.
+		pthread_create(&thread_id, NULL, evaluation_thread, ctx);
+		pthread_join(thread_id, NULL);
+		thread_id = 0;
 	} while (true);
 
 	write_history(cache_loc);
diff --git a/src/parse.c b/src/parse.c
@@ -49,23 +49,22 @@ TokenType char_token_type(char c, char last_char, TokenType last_token_type)
 	if (c <= '9' && c >= '0') {
 		if (last_token_type == TT_IDENTIFIER)
 			return TT_IDENTIFIER;
-		else
-			return TT_NUMERIC;
+		return TT_NUMERIC;
 	}
 	if (c == '_'
-	&& (last_token_type	== TT_IDENTIFIER
+	&& (last_token_type == TT_IDENTIFIER
 	|| last_token_type == TT_NUMERIC))
 		return last_token_type;
 	if (c == '.'
 	&& (last_token_type == TT_OPERATOR
 	|| last_token_type == TT_NONE))
 		return TT_NUMERIC;
-	if ((c == '.' || c == 'E')  // Scientific notation.
+	if ((c == '.' || c == 'E' || c == 'P')  // Scientific notation.
 	&& last_token_type == TT_NUMERIC)
 		return TT_NUMERIC;
 	if ((c == '+' || c == '-') && last_char == 'E')
 		return TT_NUMERIC;
-	if ((c == 'x' || c == 'o') && last_char == '0')
+	if ((c == 'x' || c == 'X' || c == 'o' || c == 'O') && last_char == '0')
 		return TT_NUMERIC;
 	if (c == '(')
 		return TT_LPAREN;
@@ -75,12 +74,11 @@ TokenType char_token_type(char c, char last_char, TokenType last_token_type)
 		return TT_NONE;
 
 	// All possible operator/special-symbol characters:
-	if ((c >= '!' && c <= '/')
-	||  (c >= ':' && c <= '@')
-	||  (c >= '{' && c <= '~')
-	||  (c >= '[' && c <= '`')) {
-		return TT_OPERATOR;
-	}
+	if (((c >= '!' && c <= '/')
+	 || (c >= ':' && c <= '@')
+	 || (c >= '{' && c <= '~')
+	 || (c >= '[' && c <= '`'))
+	&& c != '_') return TT_OPERATOR;
 
 	// Anything else is treated as an identifier.
 	return TT_IDENTIFIER;
@@ -200,11 +198,14 @@ NumberNode *make_number(NumberType type, void *val)
 
 // Parse number literals:
 // e.g. 3, 8.2, 2E32, 3E+4, 1.6E-19, 0b010110, 0xff32a1, 0o0774, etc.
-// TODO: Parse binary, hexadecimal and octal literals (0b, 0x, 0o).
+// TODO: Parse binary, hexadecimal and octal literals (0b, 0x, 0o)
+//       as well as hex/binary `P' power notation..
 NumberNode *parse_number(const char *str)
 {
 	NumberNode *number = malloc(sizeof(NumberNode));
 
+	str = remove_all_char(str, '_');
+
 	char *exponent_ptr = strstr(str, "E");
 	char *neg_exponent_ptr = strstr(str, "E-");
 	char *decimal_point_ptr = strstr(str, ".");