Add (/path):by_line()

This commit is contained in:
Bruce Hill 2024-09-09 22:16:40 -04:00
parent 3657257330
commit d356309023
8 changed files with 205 additions and 3 deletions

View File

@ -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

108
builtins/nextline.c Normal file
View File

@ -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

31
builtins/nextline.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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"

View File

@ -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"},