summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpeter <peter@pmikkelsen.com>2026-08-25 20:56:55 +0000
committerpeter <peter@pmikkelsen.com>2026-08-25 20:56:55 +0000
commit86a65e695b9dc1fb7a20094204339f5bf168fb92 (patch)
treec4ab839a70c830097103d33797fedf01261d1800
parent956cfb9ac26f44d05ffc446f30f84174865685a4 (diff)
Start working on modules, including a built-in "boot" module
FossilOrigin-Name: 4829dbeb2071fe0be41ded66a61ba2e156119a47def8a23415b8227a00d53ce7
-rw-r--r--CMakeLists.txt12
-rw-r--r--src/include/aplwc.h3
-rw-r--r--src/lib/aplwc_internal.h15
-rw-r--r--src/lib/boot.aplwc13
-rw-r--r--src/lib/main.c43
-rw-r--r--src/lib/module.c65
-rw-r--r--src/lib/string.c4
-rw-r--r--src/lib/syntax.c48
-rw-r--r--tests/aplwc_new.c5
9 files changed, 188 insertions, 20 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f59b019..d3450d7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -48,13 +48,25 @@ target_link_options(common INTERFACE
)
add_library(aplwc
+ ${CMAKE_CURRENT_BINARY_DIR}/generated_headers/boot.h
src/lib/eval.c
src/lib/main.c
src/lib/memory.c
+ src/lib/module.c
src/lib/string.c
src/lib/syntax.c
)
target_link_libraries(aplwc PRIVATE common)
+target_include_directories(aplwc PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}/generated_headers/"
+)
+
+add_custom_command(
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/generated_headers/boot.h"
+ COMMAND xxd -i -n boot_src "${CMAKE_CURRENT_SOURCE_DIR}/src/lib/boot.aplwc" "${CMAKE_CURRENT_BINARY_DIR}/generated_headers/boot.h"
+ DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/lib/boot.aplwc"
+ COMMENT "Generate boot.h from boot.aplwc"
+)
add_executable(aplwc-repl
src/bin/main.c
diff --git a/src/include/aplwc.h b/src/include/aplwc.h
index 58db819..a22bd8d 100644
--- a/src/include/aplwc.h
+++ b/src/include/aplwc.h
@@ -28,7 +28,8 @@ void aplwc_free_line(struct aplwc_line *);
struct aplwc_value *aplwc_eval(struct aplwc_line *);
void aplwc_free_value(struct aplwc_value *);
const char *aplwc_value_string(struct aplwc_value *);
+enum aplwc_rc aplwc_load_module(struct aplwc *, const char *, const char *, int n);
-#define APLWC_MIN_MEM (64)
+#define APLWC_MIN_MEM (2048)
#endif /* APLWC_H */
diff --git a/src/lib/aplwc_internal.h b/src/lib/aplwc_internal.h
index 33feafb..b027073 100644
--- a/src/lib/aplwc_internal.h
+++ b/src/lib/aplwc_internal.h
@@ -36,7 +36,13 @@ enum token_tag {
TOKEN_TAG_NEWLINE,
TOKEN_TAG_NUMBER,
TOKEN_TAG_LEFT_ARROW,
- TOKEN_TAG_DIAMOND
+ TOKEN_TAG_DIAMOND,
+ TOKEN_TAG_KEYWORD,
+ TOKEN_TAG_TEXT,
+ TOKEN_TAG_DEL,
+ TOKEN_TAG_LEFT_PAREN,
+ TOKEN_TAG_RIGHT_PAREN,
+ TOKEN_TAG_IBEAM
};
struct token {
@@ -77,11 +83,14 @@ void memory_free_token_list(struct memory *, struct token_list *);
void memory_free_aplwc_value(struct memory *, struct aplwc_value *);
/* string.c */
-struct string *chars_to_string(struct aplwc *, const char *);
+struct string *chars_to_string(struct aplwc *, const char *, int len);
uint32_t string_char(struct string *, size_t);
size_t char_length(struct string *, size_t);
/* syntax.c */
-struct token_list *scan_line(struct aplwc *, struct string *);
+struct token_list *scan_string(struct aplwc *, struct string *, int);
+
+/* module.c */
+enum aplwc_rc load_module(struct aplwc *, struct string *, struct token_list *);
#endif /* APLWC_INTERNAL_H */
diff --git a/src/lib/boot.aplwc b/src/lib/boot.aplwc
new file mode 100644
index 0000000..6248427
--- /dev/null
+++ b/src/lib/boot.aplwc
@@ -0,0 +1,13 @@
+:module Boot
+:symbol plus '+'
+:symbol minus '-'
+:export '+' '-'
+
+∇ r←a plus b
+ r←a (1⌶) b
+∇
+
+∇ r←a minus b
+ r←a (2⌶) b
+∇
+
diff --git a/src/lib/main.c b/src/lib/main.c
index e9d33cb..ae17f34 100644
--- a/src/lib/main.c
+++ b/src/lib/main.c
@@ -1,4 +1,5 @@
#include "aplwc_internal.h"
+#include "boot.h"
enum aplwc_rc
aplwc_new(struct aplwc **p, uint8_t *data, size_t size)
@@ -12,7 +13,7 @@ aplwc_new(struct aplwc **p, uint8_t *data, size_t size)
return APLWC_OUT_OF_MEMORY;
(*p)->memory = m;
- return APLWC_OK;
+ return aplwc_load_module(*p, "Boot", (const char *)boot_src, boot_src_len);
}
void
@@ -70,11 +71,11 @@ aplwc_read(struct aplwc *aplwc, const char *line)
struct token_list *tokens;
struct aplwc_line *ret;
- text = chars_to_string(aplwc, line);
+ text = chars_to_string(aplwc, line, -1);
if(text == NULL)
return NULL;
- tokens = scan_line(aplwc, text);
+ tokens = scan_string(aplwc, text, 1);
if(tokens == NULL)
return NULL;
@@ -124,3 +125,39 @@ aplwc_value_string(struct aplwc_value *value)
return "???";
}
}
+
+enum aplwc_rc
+aplwc_load_module(struct aplwc *aplwc, const char *name, const char *src, int srclen)
+{
+ struct string *text, *namestr;
+ struct token_list *tokens;
+
+ namestr = NULL;
+ text = NULL;
+ tokens = NULL;
+
+ namestr = chars_to_string(aplwc, name, -1);
+ if(namestr == NULL)
+ goto error;
+
+ text = chars_to_string(aplwc, src, srclen);
+ if(text == NULL)
+ goto error;
+
+ tokens = scan_string(aplwc, text, 0);
+ if(tokens == NULL)
+ goto error;
+
+ if(load_module(aplwc, namestr, tokens) == APLWC_OK)
+ return APLWC_OK;
+ else{
+error:
+ if(tokens != NULL)
+ memory_free_token_list(&aplwc->memory, tokens);
+ if(text != NULL)
+ memory_free_string(&aplwc->memory, text);
+ if(namestr != NULL)
+ memory_free_string(&aplwc->memory, namestr);
+ return aplwc_last_error(aplwc);
+ }
+}
diff --git a/src/lib/module.c b/src/lib/module.c
new file mode 100644
index 0000000..4ce9f8c
--- /dev/null
+++ b/src/lib/module.c
@@ -0,0 +1,65 @@
+#include "aplwc_internal.h"
+
+static int
+read_keyword_decl(struct token_list *tokens, size_t offset)
+{
+ int len;
+
+ for(len = 1; (offset + len) < tokens->length; len++)
+ if(tokens->tokens[offset+len].tag == TOKEN_TAG_NEWLINE)
+ break;
+ return len;
+}
+
+static int
+read_function_decl(struct token_list *tokens, size_t offset)
+{
+ int len;
+
+ for(len = 1; (offset + len) < tokens->length; len++)
+ if(tokens->tokens[offset+len].tag == TOKEN_TAG_DEL)
+ break;
+ return len;
+}
+
+static int
+read_decl(struct token_list *tokens, size_t offset)
+{
+ UNUSED_PARAMETER(tokens);
+ UNUSED_PARAMETER(offset);
+
+ switch(tokens->tokens[offset].tag){
+ case TOKEN_TAG_NEWLINE:
+ return 0;
+ case TOKEN_TAG_KEYWORD:
+ return read_keyword_decl(tokens, offset);
+ case TOKEN_TAG_DEL:
+ return read_function_decl(tokens, offset);
+ default:
+ return -1;
+ }
+}
+
+static enum aplwc_rc
+read_decls(struct token_list *tokens)
+{
+ size_t offset;
+ int skip;
+
+ for(offset = 0; offset < tokens->length; offset++){
+ skip = read_decl(tokens, offset);
+ if(skip == -1)
+ return APLWC_INVALID_SYNTAX;
+ offset += skip;
+ }
+ return APLWC_OK;
+}
+
+enum aplwc_rc
+load_module(struct aplwc *aplwc, struct string *name, struct token_list *tokens)
+{
+ UNUSED_PARAMETER(aplwc);
+ UNUSED_PARAMETER(name);
+
+ return read_decls(tokens);
+}
diff --git a/src/lib/string.c b/src/lib/string.c
index 123e81b..ecac9d7 100644
--- a/src/lib/string.c
+++ b/src/lib/string.c
@@ -1,7 +1,7 @@
#include "aplwc_internal.h"
struct string *
-chars_to_string(struct aplwc *aplwc, const char *chars)
+chars_to_string(struct aplwc *aplwc, const char *chars, int len)
{
const uint8_t *utf8;
size_t bytecount, charcount;
@@ -12,7 +12,7 @@ chars_to_string(struct aplwc *aplwc, const char *chars)
utf8 = (const uint8_t *)chars;
seqlen = extra = 0;
- for(bytecount = 0, charcount = 0; utf8[bytecount]; bytecount++){
+ for(bytecount = 0, charcount = 0; ((bytecount < (unsigned int)len) || (len == -1)) && utf8[bytecount]; bytecount++){
b = utf8[bytecount];
if(extra == 0){
c = 0;
diff --git a/src/lib/syntax.c b/src/lib/syntax.c
index c3452f2..f930973 100644
--- a/src/lib/syntax.c
+++ b/src/lib/syntax.c
@@ -59,6 +59,11 @@ single_sym(struct scan_state *state, struct token *token)
switch(peek(state)){
case 0x2190: token->tag = TOKEN_TAG_LEFT_ARROW; break;
case 0x22C4: token->tag = TOKEN_TAG_DIAMOND; break;
+ case 0x2207: token->tag = TOKEN_TAG_DEL; break;
+ case 0x2336: token->tag = TOKEN_TAG_IBEAM; break;
+ case '\n': token->tag = TOKEN_TAG_NEWLINE; break;
+ case '(': token->tag = TOKEN_TAG_LEFT_PAREN; break;
+ case ')': token->tag = TOKEN_TAG_RIGHT_PAREN; break;
default:
return 0;
}
@@ -83,6 +88,21 @@ identifier(struct scan_state *state, struct token *token)
return 1;
}
+static int
+keyword(struct scan_state *state, struct token *token)
+{
+ uint32_t c;
+ if(peek(state) != ':')
+ return 0;
+
+ do
+ c = advance(state);
+ while(is_letter(c));
+
+ token->tag = TOKEN_TAG_KEYWORD;
+ return 1;
+}
+
static int
number(struct scan_state *state, struct token *token)
{
@@ -125,14 +145,25 @@ number(struct scan_state *state, struct token *token)
return 1;
}
-static int
-newline(struct scan_state *state, struct token *token)
+static int
+text(struct scan_state *state, struct token *token)
{
- if(peek(state) != '\n')
+ uint32_t c;
+
+ c = peek(state);
+ if(c != '\'')
return 0;
- advance(state);
- token->tag = TOKEN_TAG_NEWLINE;
+ do
+ c = advance(state);
+ while((c != '\n') && (c != 0) && (c != '\''));
+
+ if(c == '\'')
+ advance(state);
+ else
+ return 0;
+
+ token->tag = TOKEN_TAG_TEXT;
return 1;
}
@@ -143,8 +174,9 @@ next_token(struct scan_state *state, struct token *token)
int (*scans[])(struct scan_state *, struct token *token) = {
single_sym,
identifier,
+ keyword,
number,
- newline
+ text,
};
skip_space(state);
@@ -198,7 +230,7 @@ scan(struct string *text, struct token_list *tokens)
}
struct token_list *
-scan_line(struct aplwc *aplwc, struct string *text)
+scan_string(struct aplwc *aplwc, struct string *text, int oneline)
{
enum aplwc_rc rc;
struct token_list *tokens;
@@ -218,7 +250,7 @@ scan_line(struct aplwc *aplwc, struct string *text)
tokens->length = n;
scan(text, tokens);
- for(i = 0; i < n; i++){
+ for(i = 0; oneline && (i < n); i++){
if(tokens->tokens[i].tag != TOKEN_TAG_NEWLINE)
continue;
diff --git a/tests/aplwc_new.c b/tests/aplwc_new.c
index 55e742f..8d57ecd 100644
--- a/tests/aplwc_new.c
+++ b/tests/aplwc_new.c
@@ -11,15 +11,14 @@ main(void)
for(i = 0; i < 32; i++){
for(j = 0; j <= sizeof(data)-i; j++){
ret = aplwc_new(&aplwc, data+i, j);
+ aplwc_destroy(aplwc);
if(ret){
if(ret != APLWC_OUT_OF_MEMORY)
return 1;
- if(aplwc != NULL)
- return 1;
if(j >= APLWC_MIN_MEM)
return 1;
+ break;
}
- aplwc_destroy(aplwc);
}
}