aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2014-12-06 03:57:17 +0100
committerMattias Andrée <maandree@operamail.com>2014-12-06 03:57:17 +0100
commit60421e2e9b7cc5d47ed2c7db1d5f817d63922130 (patch)
treec12c407ad6c9f057ddce632f06a71ebc0aa73fe8
parentmds-kbdc: m (diff)
downloadmds-60421e2e9b7cc5d47ed2c7db1d5f817d63922130.tar.gz
mds-60421e2e9b7cc5d47ed2c7db1d5f817d63922130.tar.bz2
mds-60421e2e9b7cc5d47ed2c7db1d5f817d63922130.tar.xz
mds-kbdc: callables
Signed-off-by: Mattias Andrée <maandree@operamail.com>
-rw-r--r--Makefile3
-rw-r--r--TODO1
-rw-r--r--src/mds-kbdc/callables.c188
-rw-r--r--src/mds-kbdc/callables.h58
-rw-r--r--src/mds-kbdc/compile-layout.c124
-rw-r--r--src/mds-kbdc/variables.h2
6 files changed, 336 insertions, 40 deletions
diff --git a/Makefile b/Makefile
index ee56ac2..d08fda8 100644
--- a/Makefile
+++ b/Makefile
@@ -33,7 +33,8 @@ OBJ_mds-registry_ = mds-registry util globals reexec registry signals \
OBJ_mds-kbdc_ = mds-kbdc globals raw-data builtin-functions string \
tree make-tree parse-error simplify-tree parsed \
process-includes validate-tree eliminate-dead-code \
- paths include-stack compile-layout variables
+ paths include-stack compile-layout variables \
+ callables
OBJ_mds-server = $(foreach O,$(OBJ_mds-server_),obj/mds-server/$(O).o)
OBJ_mds-registry = $(foreach O,$(OBJ_mds-registry_),obj/mds-registry/$(O).o)
diff --git a/TODO b/TODO
index d374c89..2cf21fd 100644
--- a/TODO
+++ b/TODO
@@ -16,6 +16,7 @@ Extra servers:
tray retro-crt kbd2rat multikey
keystick posmem nest mds
meta keybounce slowkey keycue
+ a speech-to-keyboard server
some server that hides the cursor when appropriate, such
as when the user starts typing
diff --git a/src/mds-kbdc/callables.c b/src/mds-kbdc/callables.c
new file mode 100644
index 0000000..4a87fd2
--- /dev/null
+++ b/src/mds-kbdc/callables.c
@@ -0,0 +1,188 @@
+/**
+ * mds — A micro-display server
+ * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "callables.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+
+/**
+ * Map, by index, from argument count, to list of callable's names
+ */
+static char*** restrict names = NULL;
+
+/**
+ * If `callable_list[callabes[i][j]]` and `callable_include_stack_list[callabes[i][j]]`
+ * describe the callable named by `named[i][j]` with either `i` parameters, or the
+ * number of parameters specified by the suffix in `named[i][j]`
+ */
+static size_t** restrict callables = NULL;
+
+/**
+ * Map the the number of elements in the, by index, corresponding element in `names`
+ */
+static size_t* restrict bucket_sizes = NULL;
+
+/**
+ * List of callables
+ */
+static mds_kbdc_tree_t** restrict callable_list = NULL;
+
+/**
+ * List of callables' include-stacks
+ */
+static mds_kbdc_include_stack_t** restrict callable_include_stack_list = NULL;
+
+/**
+ * The number of buckets in `names` and `bucket_sizes`
+ */
+static size_t buckets = 0;
+
+/**
+ * The index of the next item in `callable_list` and `callable_include_stack_list`
+ */
+static size_t list_ptr = 0;
+
+
+
+/**
+ * Destroy the callable storage
+ */
+void callables_terminate(void)
+{
+ size_t i, j, n;
+ char** bucket;
+ for (i = 0; i < list_ptr; i++)
+ {
+ bucket = names[i];
+ for (j = 0, n = bucket_sizes[i]; j < n; j++)
+ free(bucket[j]);
+ free(bucket);
+ }
+ for (i = 0; i < list_ptr; i++)
+ mds_kbdc_include_stack_free(callable_include_stack_list[i]);
+ free(names), names = NULL;
+ free(bucket_sizes), bucket_sizes = NULL;
+ free(callable_list), callable_list = NULL;
+ free(callable_include_stack_list), callable_include_stack_list = NULL;
+ buckets = list_ptr = 0;
+}
+
+
+/**
+ * Store a callable
+ *
+ * @param name The name of the callable
+ * @param arg_count The number of arguments the callable takes
+ * if `name` is suffixless, otherwise zero
+ * @param callable The callable
+ * @param callable_include_stack The include-stack for the callable
+ * @return Zero on success, -1 on error
+ */
+int callables_set(const char* restrict name, size_t arg_count, mds_kbdc_tree_t* restrict callable,
+ mds_kbdc_include_stack_t* restrict callable_include_stack)
+{
+#define yrealloc(var, elements, type) \
+ (new_##var = realloc(var, (elements) * sizeof(type)), \
+ (new_##var == NULL) ? -1 : (var = new_##var, new_##var = NULL, 0))
+
+ char* dupname = NULL;
+ char*** new_names = NULL;
+ size_t** new_callables = NULL;
+ size_t* new_bucket_sizes = NULL;
+ char** old_names = NULL;
+ size_t* old_callables = NULL;
+ mds_kbdc_tree_t** new_callable_list = NULL;
+ mds_kbdc_include_stack_t** new_callable_include_stack_list = NULL;
+ int saved_errno;
+
+ fail_if ((dupname = strdup(name), dupname == NULL));
+
+ if (arg_count >= buckets)
+ {
+ fail_if (yrealloc(names, arg_count + 1, char**));
+ fail_if (yrealloc(callables, arg_count + 1, size_t*));
+ fail_if (yrealloc(bucket_sizes, arg_count + 1, size_t));
+ memset(names, 0, (arg_count + 1 - buckets) * sizeof(char**));
+ memset(callables, 0, (arg_count + 1 - buckets) * sizeof(size_t*));
+ memset(bucket_sizes, 0, (arg_count + 1 - buckets) * sizeof(size_t));
+ buckets = arg_count + 1;
+ }
+
+ fail_if (xxrealloc(old_names, names[arg_count], bucket_sizes[arg_count] + 1, char*));
+ fail_if (xxrealloc(old_callables, callables[arg_count], bucket_sizes[arg_count] + 1, size_t));
+
+ names[arg_count][bucket_sizes[arg_count]] = dupname, dupname = NULL;;
+ callables[arg_count][bucket_sizes[arg_count]] = list_ptr;
+ bucket_sizes[arg_count]++;
+
+ fail_if (yrealloc(callable_list, list_ptr + 1, mds_kbdc_tree_t*));
+ fail_if (yrealloc(callable_include_stack_list, list_ptr + 1, mds_kbdc_include_stack_t*));
+
+ callable_list[list_ptr] = callable;
+ callable_include_stack_list[list_ptr] = callable_include_stack;
+ list_ptr++;
+
+ return 0;
+ pfail:
+ saved_errno = errno;
+ free(dupname);
+ free(new_names);
+ free(new_callables);
+ free(new_bucket_sizes);
+ free(new_callable_list);
+ free(new_callable_include_stack_list);
+ if (old_names)
+ names[arg_count] = old_names;
+ if (old_callables)
+ callables[arg_count] = old_callables;
+ return errno = saved_errno, -1;
+#undef yrealloc
+}
+
+
+/**
+ * Get a stored callable
+ *
+ * @param name The name of the callable
+ * @param arg_count The number of arguments the callable takes
+ * if `name` is suffixless, otherwise zero
+ * @param callable Output parameter for the callable, `NULL` if not found
+ * @param callable_include_stack Output parameter for the include-stack for the callable
+ */
+void callables_get(const char* restrict name, size_t arg_count, mds_kbdc_tree_t** restrict callable,
+ mds_kbdc_include_stack_t** restrict callable_include_stack)
+{
+ char** restrict names_ = names[arg_count];
+ size_t i, n = bucket_sizes[arg_count];
+
+ *callable = NULL;
+ *callable_include_stack = NULL;
+
+ for (i = 0; i < n; i++)
+ {
+ if (strcmp(names_[i], name))
+ continue;
+ i = callables[arg_count][i];
+ *callable = callable_list[i];
+ *callable_include_stack = callable_include_stack_list[i];
+ return;
+ }
+}
+
diff --git a/src/mds-kbdc/callables.h b/src/mds-kbdc/callables.h
new file mode 100644
index 0000000..32b5467
--- /dev/null
+++ b/src/mds-kbdc/callables.h
@@ -0,0 +1,58 @@
+/**
+ * mds — A micro-display server
+ * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef MDS_MDS_KBDC_CALLABLES_H
+#define MDS_MDS_KBDC_CALLABLES_H
+
+
+#include "tree.h"
+#include "include-stack.h"
+
+
+/**
+ * Destroy the callable storage
+ */
+void callables_terminate(void);
+
+/**
+ * Store a callable
+ *
+ * @param name The name of the callable
+ * @param arg_count The number of arguments the callable takes
+ * if `name` is suffixless, otherwise zero
+ * @param callable The callable
+ * @param callable_include_stack The include-stack for the callable
+ * @return Zero on success, -1 on error
+ */
+int callables_set(const char* restrict name, size_t arg_count, mds_kbdc_tree_t* restrict callable,
+ mds_kbdc_include_stack_t* restrict callable_include_stack);
+
+/**
+ * Get a stored callable
+ *
+ * @param name The name of the callable
+ * @param arg_count The number of arguments the callable takes
+ * if `name` is suffixless, otherwise zero
+ * @param callable Output parameter for the callable
+ * @param callable_include_stack Output parameter for the include-stack for the callable
+ */
+void callables_get(const char* restrict name, size_t arg_count, mds_kbdc_tree_t** restrict callable,
+ mds_kbdc_include_stack_t** restrict callable_include_stack);
+
+
+#endif
+
diff --git a/src/mds-kbdc/compile-layout.c b/src/mds-kbdc/compile-layout.c
index 01eb7e2..16d93a8 100644
--- a/src/mds-kbdc/compile-layout.c
+++ b/src/mds-kbdc/compile-layout.c
@@ -22,6 +22,7 @@
#include "builtin-functions.h"
#include "string.h"
#include "variables.h"
+#include "callables.h"
#include <stdlib.h>
#include <errno.h>
@@ -193,57 +194,103 @@ static int let(size_t variable, const char32_t* restrict string, const mds_kbdc_
}
-static int set_macro(const mds_kbdc_tree_macro_t* restrict macro,
+/**
+ * Store a macro
+ *
+ * @param macro The macro
+ * @param macro_include_stack The include-stack for the macro
+ * @return Zero on success, -1 on error
+ */
+static int set_macro(mds_kbdc_tree_macro_t* restrict macro,
mds_kbdc_include_stack_t* macro_include_stack)
{
- (void) macro;
- (void) macro_include_stack;
- mds_kbdc_include_stack_free(macro_include_stack);
- return 0; /* TODO */
+ return callables_set(macro->name, 0, (mds_kbdc_tree_t*)macro, macro_include_stack);
}
-static int get_macro_lax(const char* restrict macro_name, const mds_kbdc_tree_macro_t** restrict macro,
- mds_kbdc_include_stack_t** restrict macro_include_stack)
+
+/**
+ * Get a stored macro
+ *
+ * @param name The name of the macro, with suffix
+ * @param macro Output parameter for the macro, `NULL` if not found
+ * @param macro_include_stack Output parameter for the include-stack for the macro
+ */
+static void get_macro_lax(const char* restrict macro_name, mds_kbdc_tree_macro_t** restrict macro,
+ mds_kbdc_include_stack_t** restrict macro_include_stack)
{
- (void) macro_name;
- (void) macro;
- (void) macro_include_stack;
- return 0; /* TODO */
+ callables_get(macro_name, 0, (mds_kbdc_tree_t**)macro, macro_include_stack);
}
-static int get_macro(const mds_kbdc_tree_macro_call_t* restrict macro_call,
- const mds_kbdc_tree_macro_t** restrict macro,
+
+/**
+ * Get a stored macro
+ *
+ * The function is similar to `get_macro_lax`, however, this fucntion
+ * will report an error if the macro has not yet been defined, and it
+ * will pretend that it has not yet been defined if the macro contained
+ * an error in an earlier called to it
+ *
+ * @param macro_call The macro-call
+ * @param macro Output parameter for the macro, `NULL` if not found or has an error
+ * @param macro_include_stack Output parameter for the include-stack for the macro
+ * @return Zero on success, -1 on error
+ */
+static int get_macro(mds_kbdc_tree_macro_call_t* restrict macro_call,
+ mds_kbdc_tree_macro_t** restrict macro,
mds_kbdc_include_stack_t** restrict macro_include_stack)
{
- NEW_ERROR(macro_call, ERROR, "macro ‘%s’ as not been defined yet", macro_call->name);
- /* return set `*macro = NULL` if `(*macro)->processed == PROCESS_LEVEL` */
- (void) macro;
- (void) macro_include_stack;
- return 0; /* TODO */
+ get_macro_lax(macro_call->name, macro, macro_include_stack);
+ if (*macro == NULL)
+ {
+ NEW_ERROR(macro_call, ERROR, "macro ‘%s’ as not been defined yet", macro_call->name);
+ macro_call->processed = PROCESS_LEVEL;
+ return 0;
+ }
+ if ((*macro)->processed == PROCESS_LEVEL)
+ *macro = NULL;
+ return 0;
pfail:
return -1;
}
-static int set_function(const mds_kbdc_tree_function_t* restrict function,
+
+/**
+ * Store a function
+ *
+ * @param function The function
+ * @param function_include_stack The include-stack for the function
+ * @return Zero on success, -1 on error
+ */
+static int set_function(mds_kbdc_tree_function_t* restrict function,
mds_kbdc_include_stack_t* function_include_stack)
{
- (void) function;
- (void) function_include_stack;
- mds_kbdc_include_stack_free(function_include_stack);
- return 0; /* TODO */
+ char* suffixless = function->name;
+ char* suffix_start = strchr(suffixless, '/');
+ size_t arg_count = (size_t)atoll(suffix_start + 1);
+ int r;
+
+ *suffix_start = '\0';
+ r = callables_set(suffixless, arg_count, (mds_kbdc_tree_t*)function, function_include_stack);
+ return *suffix_start = '/', r;
}
-static int get_function_lax(const char* restrict function_name, size_t arg_count,
- const mds_kbdc_tree_function_t** restrict function,
- mds_kbdc_include_stack_t** restrict function_include_stack)
+
+/**
+ * Get a stored function
+ *
+ * @param name The name of the function, suffixless
+ * @param arg_count The number of arguments the function takes
+ * @param function Output parameter for the function, `NULL` if not found
+ * @param function_include_stack Output parameter for the include-stack for the function
+ */
+static void get_function_lax(const char* restrict function_name, size_t arg_count,
+ mds_kbdc_tree_function_t** restrict function,
+ mds_kbdc_include_stack_t** restrict function_include_stack)
{
- (void) function_name;
- (void) arg_count;
- (void) function;
- (void) function_include_stack;
- return 0; /* TODO */
+ callables_get(function_name, arg_count, (mds_kbdc_tree_t**)function, function_include_stack);
}
+
static int set_return_value(char32_t* restrict value)
{
free(value);
@@ -610,10 +657,10 @@ static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tr
* @param tree The tree to evaluate
* @return Zero on success, -1 on error, 1 if an undefined macro is used
*/
-static int check_marco_calls(const mds_kbdc_tree_t* restrict tree)
+static int check_marco_calls(mds_kbdc_tree_t* restrict tree)
{
#define t(...) if (rc |= r = (__VA_ARGS__), r < 0) return r
- const mds_kbdc_tree_macro_t* _macro;
+ mds_kbdc_tree_macro_t* _macro;
mds_kbdc_include_stack_t* _macro_include_stack;
void* data;
int r, rc = 0;
@@ -830,7 +877,7 @@ static int check_name_suffix(struct mds_kbdc_tree_callable* restrict tree)
static int compile_function(mds_kbdc_tree_function_t* restrict tree)
{
#define t(expr) fail_if ((r = (expr), r < 0)); if (r) tree->processed = PROCESS_LEVEL
- const mds_kbdc_tree_function_t* function;
+ mds_kbdc_tree_function_t* function;
mds_kbdc_include_stack_t* function_include_stack;
mds_kbdc_include_stack_t* our_include_stack = NULL;
char* suffixless;
@@ -857,7 +904,7 @@ static int compile_function(mds_kbdc_tree_function_t* restrict tree)
/* Check that the function is not already defined,
the include-stack is used in the error-clause as
well as later when we list the function as defined. */
- fail_if (get_function_lax(suffixless, arg_count, &function, &function_include_stack));
+ get_function_lax(suffixless, arg_count, &function, &function_include_stack);
fail_if ((our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL));
if (function)
{
@@ -899,7 +946,7 @@ static int compile_function(mds_kbdc_tree_function_t* restrict tree)
static int compile_macro(mds_kbdc_tree_macro_t* restrict tree)
{
#define t(expr) fail_if ((r = (expr), r < 0)); if (r) tree->processed = PROCESS_LEVEL
- const mds_kbdc_tree_macro_t* macro;
+ mds_kbdc_tree_macro_t* macro;
mds_kbdc_include_stack_t* macro_include_stack;
mds_kbdc_include_stack_t* our_include_stack = NULL;
int r, saved_errno;
@@ -911,7 +958,7 @@ static int compile_macro(mds_kbdc_tree_macro_t* restrict tree)
the include-stack is used in the error-clause as
well as later when we list the macro as defined. */
fail_if ((our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL));
- t (get_macro_lax(tree->name, &macro, &macro_include_stack));
+ get_macro_lax(tree->name, &macro, &macro_include_stack);
if (macro)
{
NEW_ERROR(tree, ERROR, "macro ‘%s’ is already defined", tree->name);
@@ -1341,7 +1388,7 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree)
{
mds_kbdc_tree_t* arg = NULL;
mds_kbdc_tree_t* arg_;
- const mds_kbdc_tree_macro_t* macro;
+ mds_kbdc_tree_macro_t* macro;
mds_kbdc_include_stack_t* macro_include_stack;
mds_kbdc_include_stack_t* our_include_stack = NULL;
size_t variable;
@@ -1479,6 +1526,7 @@ int compile_layout(mds_kbdc_parsed_t* restrict result_)
saved_errno = errno;
mds_kbdc_include_stack_end();
variables_terminate();
+ callables_terminate();
errno = saved_errno;
return r;
}
diff --git a/src/mds-kbdc/variables.h b/src/mds-kbdc/variables.h
index 26d3c72..c01c163 100644
--- a/src/mds-kbdc/variables.h
+++ b/src/mds-kbdc/variables.h
@@ -19,7 +19,7 @@
#define MDS_MDS_KBDC_VARIABLES_H
-#include "parsed.h"
+#include "tree.h"
#include "string.h"