aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-09-09 22:16:40 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-09-09 22:16:40 -0400
commitd356309023fce996a549440aa14e3239f909fe33 (patch)
tree1c797f41be25c457a09b9187550136afd8550d96
parent36572573300eaba9d0adbb63fc55067aa0fe5e0c (diff)
Add (/path):by_line()
-rw-r--r--Makefile2
-rw-r--r--builtins/nextline.c108
-rw-r--r--builtins/nextline.h31
-rw-r--r--builtins/path.c52
-rw-r--r--builtins/path.h1
-rw-r--r--builtins/siphash.h1
-rw-r--r--builtins/tomo.h1
-rw-r--r--environment.c12
8 files changed, 205 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 03e1436e..21f65d7e 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,7 @@ CFLAGS_PLACEHOLDER="$$(echo -e '\033[2m<flags...>\033[m')"
LDLIBS=-lgc -lcord -lm -lunistring -lgmp -ldl
BUILTIN_OBJS=builtins/siphash.o builtins/array.o builtins/bool.o builtins/channel.o builtins/nums.o builtins/functions.o builtins/integers.o \
builtins/pointer.o builtins/memory.o builtins/text.o builtins/thread.o builtins/c_string.o builtins/table.o \
- builtins/types.o builtins/util.o builtins/files.o builtins/range.o builtins/shell.o builtins/path.o
+ builtins/types.o builtins/util.o builtins/files.o builtins/range.o builtins/shell.o builtins/path.o builtins/nextline.o
TESTS=$(patsubst %.tm,%.tm.testresult,$(wildcard test/*.tm))
all: libtomo.so tomo
diff --git a/builtins/nextline.c b/builtins/nextline.c
new file mode 100644
index 00000000..3fa37412
--- /dev/null
+++ b/builtins/nextline.c
@@ -0,0 +1,108 @@
+// An enum used for iterating over lines in a file
+// Most of the code here was generated by compiling:
+// enum NextLine(Done, Next(line:Text))
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "siphash.h"
+#include "datatypes.h"
+#include "nextline.h"
+#include "text.h"
+#include "util.h"
+
+static Text_t NextLine$Next$as_text(NextLine$Next_t *obj, bool use_color)
+{
+ if (!obj)
+ return Text("Next");
+ return Text$concat(use_color ? Text("\x1b[0;1mNext\x1b[m(") : Text("Next("), Text("line="),
+ Text$as_text((Text_t[1]){obj->$line}, use_color, &Text$info), Text(")"));
+}
+
+public inline NextLine_t NextLine$tagged$Next(Text_t $line)
+{
+ return (NextLine_t) {
+ .tag = NextLine$tag$Next,.$Next = { $line }
+ };
+}
+
+static Text_t NextLine$as_text(NextLine_t *obj, bool use_color)
+{
+ if (!obj)
+ return Text("NextLine");
+ switch (obj->tag) {
+ case NextLine$tag$Done:
+ return use_color ? Text("\x1b[36;1mNextLine.Done\x1b[m") : Text("NextLine.Done");
+ case NextLine$tag$Next:
+ return Text$concat(use_color ? Text("\x1b[36;1mNextLine.Next\x1b[m(") :
+ Text("NextLine.Next("), Text("line="),
+ Text$as_text((Text_t[1]){obj->$Next.$line}, use_color, &Text$info), Text(")"));
+ default:
+ return (Text_t) {
+ .length = 0};
+ }
+}
+
+static bool NextLine$equal(const NextLine_t *x, const NextLine_t *y,
+ const TypeInfo *info)
+{
+ (void) info;
+ if (x->tag != y->tag)
+ return false;
+ switch (x->tag) {
+ case NextLine$tag$Done:
+ return false;
+ case NextLine$tag$Next:
+ return generic_equal(&x->$Next, &y->$Next, (&NextLine$Next));
+ default:
+ return 0;
+ }
+}
+
+static int NextLine$compare(const NextLine_t *x, const NextLine_t *y,
+ const TypeInfo *info)
+{
+ (void) info;
+ int diff = (int)x->tag - (int)y->tag;
+ if (diff)
+ return diff;
+ switch (x->tag) {
+ case NextLine$tag$Done:
+ return 0;
+ case NextLine$tag$Next:
+ return generic_compare(&x->$Next, &y->$Next, (&NextLine$Next));
+ default:
+ return 0;
+ }
+}
+
+static uint64_t NextLine$hash(const NextLine_t *obj, const TypeInfo *info)
+{
+ (void) info;
+ uint64_t hashes[2] = { (uint64_t) obj->tag, 0 };
+ switch (obj->tag) {
+ case NextLine$tag$Done:
+ break;
+ case NextLine$tag$Next:
+ hashes[1] = generic_hash(&obj->$Next, (&NextLine$Next));
+ break;
+ default: break;
+ }
+ return siphash24((void *) &hashes, sizeof(hashes));
+}
+
+public const TypeInfo NextLine$Done = { 0, 0, {.tag = EmptyStruct,.EmptyStruct.name =
+ "NextLine$Done" } };
+public const TypeInfo NextLine$Next = { 24, 8, {.tag = CustomInfo,.CustomInfo =
+ {.as_text =
+ (void *) NextLine$Next$as_text,.hash =
+ (void *) Text$hash,.compare =
+ (void *) Text$compare,.equal =
+ (void *) Text$equal,} } };
+public const TypeInfo NextLine = { 32, 8, {.tag = CustomInfo,.CustomInfo =
+ {.as_text = (void *) NextLine$as_text,.equal =
+ (void *) NextLine$equal,.hash =
+ (void *) NextLine$hash,.compare =
+ (void *) NextLine$compare} } };
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/nextline.h b/builtins/nextline.h
new file mode 100644
index 00000000..ce4c9fab
--- /dev/null
+++ b/builtins/nextline.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "datatypes.h"
+#include "types.h"
+
+// An enum used for iterating over lines in a file
+// Most of the code here was generated by compiling:
+// enum NextLine(Done, Next(line:Text))
+
+typedef struct NextLine_s NextLine_t;
+typedef struct NextLine$Done_s NextLine$Done_t;
+#pragma GCC diagnostic ignored "-Wpedantic"
+struct NextLine$Done_s {
+};
+typedef struct NextLine$Next_s NextLine$Next_t;
+struct NextLine$Next_s {
+ Text_t $line;
+};
+struct NextLine_s {
+ enum { NextLine$tag$Done = 0, NextLine$tag$Next = 1 } tag;
+ union {
+ NextLine$Done_t $Done;
+ NextLine$Next_t $Next;
+ };
+};
+extern const TypeInfo NextLine;
+extern const TypeInfo NextLine$Done;
+extern const TypeInfo NextLine$Next;
+NextLine_t NextLine$tagged$Next(Text_t $line);
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/path.c b/builtins/path.c
index 7c2198cf..096cbdd0 100644
--- a/builtins/path.c
+++ b/builtins/path.c
@@ -1,10 +1,11 @@
// A lang for filesystem paths
#include <dirent.h>
-#include <fcntl.h>
#include <errno.h>
-#include <string.h>
+#include <fcntl.h>
+#include <gc.h>
#include <stdbool.h>
#include <stdint.h>
+#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -15,6 +16,7 @@
#include "files.h"
#include "functions.h"
#include "integers.h"
+#include "nextline.h"
#include "path.h"
#include "text.h"
#include "types.h"
@@ -423,6 +425,51 @@ public Text_t Path$extension(Path_t path, bool full)
return Text("");
}
+static void _line_reader_cleanup(FILE **f)
+{
+ if (f && *f) {
+ fclose(*f);
+ *f = NULL;
+ }
+}
+
+static NextLine_t _next_line(FILE **f)
+{
+ if (!f || !*f) return (NextLine_t){NextLine$tag$Done};
+
+ char *line = NULL;
+ size_t size = 0;
+ ssize_t len = getline(&line, &size, *f);
+ if (len <= 0) {
+ _line_reader_cleanup(f);
+ return (NextLine_t){NextLine$tag$Done};
+ }
+
+ while (len > 0 && (line[len-1] == '\r' || line[len-1] == '\n'))
+ --len;
+
+ if (u8_check((uint8_t*)line, (size_t)len) != NULL)
+ fail("Invalid UTF8!");
+
+ Text_t line_text = Text$format("%.*s", len, line);
+ free(line);
+ return NextLine$tagged$Next(line_text);
+}
+
+public closure_t Path$by_line(Path_t path)
+{
+ path = Path$_expand_home(path);
+
+ FILE *f = fopen(Text$as_c_string(path), "r");
+ if (f == NULL)
+ fail("Could not read file: %k (%s)", &path, strerror(errno));
+
+ FILE **wrapper = GC_MALLOC(sizeof(FILE*));
+ *wrapper = f;
+ GC_register_finalizer(wrapper, (void*)_line_reader_cleanup, NULL, NULL, NULL);
+ return (closure_t){.fn=(void*)_next_line, .userdata=wrapper};
+}
+
public const TypeInfo Path$info = {
.size=sizeof(Path_t),
.align=__alignof__(Path_t),
@@ -430,4 +477,5 @@ public const TypeInfo Path$info = {
.TextInfo={.lang="Path"},
};
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/path.h b/builtins/path.h
index 6772f72d..dd42af85 100644
--- a/builtins/path.h
+++ b/builtins/path.h
@@ -39,6 +39,7 @@ Text_t Path$write_unique(Path_t path, Text_t text);
Path_t Path$parent(Path_t path);
Text_t Path$base_name(Path_t path);
Text_t Path$extension(Path_t path, bool full);
+closure_t Path$by_line(Path_t path);
#define Path$hash Text$hash
#define Path$compare Text$compare
diff --git a/builtins/siphash.h b/builtins/siphash.h
index a466200c..0fc7614c 100644
--- a/builtins/siphash.h
+++ b/builtins/siphash.h
@@ -3,6 +3,7 @@
// An implementation of the SipHash algorithm.
#include <stdint.h>
+#include <stddef.h>
uint64_t siphash24(const uint8_t *src, size_t src_sz);
diff --git a/builtins/tomo.h b/builtins/tomo.h
index c7814376..29f71f71 100644
--- a/builtins/tomo.h
+++ b/builtins/tomo.h
@@ -17,6 +17,7 @@
#include "datatypes.h"
#include "functions.h"
#include "integers.h"
+#include "nextline.h"
#include "macros.h"
#include "memory.h"
#include "nums.h"
diff --git a/environment.c b/environment.c
index 45207da1..94401ec9 100644
--- a/environment.c
+++ b/environment.c
@@ -69,6 +69,16 @@ env_t *new_compilation_unit(CORD *libname)
.next=new(arg_t, .name="step", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1")))));
}
+ type_t *next_line_type;
+ {
+ next_line_type = Type(
+ EnumType, .name="NextLine", .env=namespace_env(env, "NextLine"),
+ .tags=new(tag_t, .name="Done", .tag_value=0, .type=Type(StructType, .name="NextLine$Done"),
+ .next=new(tag_t, .name="Next", .tag_value=1, .type=Type(StructType, .name="NextLine$Next",
+ .env=namespace_env(env, "NextLine$Next"),
+ .fields=new(arg_t, .name="line", .type=TEXT_TYPE)))));
+ }
+
{
env_t *thread_env = namespace_env(env, "Thread");
THREAD_TYPE = Type(StructType, .name="Thread", .env=thread_env, .opaque=true);
@@ -245,12 +255,14 @@ env_t *new_compilation_unit(CORD *libname)
{"reversed", "Range$reversed", "func(range:Range)->Range"},
{"by", "Range$by", "func(range:Range, step:Int)->Range"},
)},
+ {"NextLine", next_line_type, "NextLine_t", "NextLine", {}},
{"Pattern", Type(TextType, .lang="Pattern", .env=namespace_env(env, "Pattern")), "Pattern_t", "Pattern$info", TypedArray(ns_entry_t,
{"escape_text", "Pattern$escape_text", "func(text:Text)->Pattern"},
)},
{"Path", Type(TextType, .lang="Path", .env=namespace_env(env, "Path")), "Text_t", "Text$info", TypedArray(ns_entry_t,
{"append", "Path$append", "func(path:Path, text:Text, permissions=0o644_i32)"},
{"base_name", "Path$base_name", "func(path:Path)->Text"},
+ {"by_line", "Path$by_line", "func(path:Path)->func()->NextLine"},
{"children", "Path$children", "func(path:Path, include_hidden=no)->[Path]"},
{"create_directory", "Path$create_directory", "func(path:Path, permissions=0o644_i32)"},
{"escape_path", "Path$escape_path", "func(path:Path)->Path"},