aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-05-18 14:38:41 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-05-18 14:38:41 -0400
commita1d18fd4225f67275ea4173532969e4ddf55b39f (patch)
tree6473f7cee0e829783bd64cc3d52af53f5089340f
parentee9a40f9102f12357e7a46c3b48a486c62c2311e (diff)
Add C string type
-rw-r--r--Makefile3
-rw-r--r--builtins/c_string.c52
-rw-r--r--builtins/c_string.h18
-rw-r--r--builtins/functions.c20
-rw-r--r--builtins/functions.h5
-rw-r--r--builtins/tomo.h1
-rw-r--r--compile.c19
-rw-r--r--environment.c5
-rw-r--r--typecheck.c2
-rw-r--r--types.c3
-rw-r--r--types.h2
11 files changed, 126 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index d8a659fd..637d0bf0 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,8 @@ O=-Og
CFLAGS=$(CCONFIG) $(EXTRA) $(CWARN) $(G) $(O) $(OSFLAGS)
LDLIBS=-lgc -lcord -lm -lunistring -ldl -L. -ltomo
BUILTIN_OBJS=builtins/array.o builtins/bool.o builtins/nums.o builtins/functions.o builtins/integers.o \
- builtins/pointer.o builtins/memory.o builtins/text.o builtins/table.o builtins/types.o builtins/util.o builtins/files.o
+ builtins/pointer.o builtins/memory.o builtins/text.o builtins/c_string.o builtins/table.o \
+ builtins/types.o builtins/util.o builtins/files.o
all: libtomo.so tomo
diff --git a/builtins/c_string.c b/builtins/c_string.c
new file mode 100644
index 00000000..f74d6da2
--- /dev/null
+++ b/builtins/c_string.c
@@ -0,0 +1,52 @@
+// Type info and methods for CString datatype (char*)
+#include <ctype.h>
+#include <err.h>
+#include <gc.h>
+#include <gc/cord.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "functions.h"
+#include "halfsiphash.h"
+#include "text.h"
+#include "types.h"
+#include "util.h"
+
+public CORD CString$as_text(const void *c_string, bool colorize, const TypeInfo *info)
+{
+ (void)info;
+ if (!c_string) return "CString";
+ CORD text = CORD_from_char_star(*(char**)c_string);
+ return CORD_all(colorize ? "\x1b[34mCString\x1b[m(" : "CString(", Text$quoted(text, colorize), ")");
+}
+
+public int CString$compare(const char **x, const char **y)
+{
+ if (!*x != !*y)
+ return (!*y) - (!*x);
+ return strcmp(*x, *y);
+}
+
+public bool CString$equal(const char **x, const char **y)
+{
+ return CString$compare(x, y) == 0;
+}
+
+public uint32_t CString$hash(const char **c_str)
+{
+ if (!*c_str) return 0;
+
+ uint32_t hash;
+ halfsiphash(*c_str, strlen(*c_str), TOMO_HASH_VECTOR, (uint8_t*)&hash, sizeof(hash));
+ return hash;
+}
+
+public const TypeInfo $CString = {
+ .size=sizeof(char*),
+ .align=__alignof__(char*),
+ .tag=CustomInfo,
+ .CustomInfo={.as_text=(void*)CString$as_text, .compare=(void*)CString$compare, .equal=(void*)CString$equal, .hash=(void*)CString$hash},
+};
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/c_string.h b/builtins/c_string.h
new file mode 100644
index 00000000..6b4b0aad
--- /dev/null
+++ b/builtins/c_string.h
@@ -0,0 +1,18 @@
+#pragma once
+
+// Type info and methods for CString datatype, which represents C's `char*`
+
+#include <gc/cord.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "types.h"
+
+CORD CString$as_text(const void *str, bool colorize, const TypeInfo *info);
+int CString$compare(const char **x, const char **y);
+bool CString$equal(const char **x, const char **y);
+uint32_t CString$hash(const char **str);
+
+extern const TypeInfo $CString;
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/functions.c b/builtins/functions.c
index f668b253..eedcc9fb 100644
--- a/builtins/functions.c
+++ b/builtins/functions.c
@@ -240,4 +240,24 @@ public bool pop_flag(char **argv, int *i, const char *flag, CORD *result)
}
}
+public void *xfopen(CORD path, CORD flags)
+{
+ return fopen(CORD_to_const_char_star(path), CORD_to_const_char_star(flags));
+}
+
+public CORD xfread_all(void *fp)
+{
+ return CORD_from_file_eager(fp);
+}
+
+public void xfputs(CORD text, void *fp)
+{
+ CORD_put(text, fp);
+}
+
+public void xfclose(void *fp)
+{
+ fclose(fp);
+}
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/functions.h b/builtins/functions.h
index f1a2867e..e62fc441 100644
--- a/builtins/functions.h
+++ b/builtins/functions.h
@@ -26,4 +26,9 @@ bool generic_equal(const void *x, const void *y, const TypeInfo *type);
CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type);
bool pop_flag(char **argv, int *i, const char *flag, CORD *result);
+void *xfopen(CORD path, CORD flags);
+CORD xfread_all(void *fp);
+void xfputs(CORD text, void *fp);
+void xfclose(void *fp);
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/builtins/tomo.h b/builtins/tomo.h
index f0455ad1..ded82945 100644
--- a/builtins/tomo.h
+++ b/builtins/tomo.h
@@ -17,6 +17,7 @@
#include "array.h"
#include "bool.h"
+#include "c_string.h"
#include "datatypes.h"
#include "functions.h"
#include "halfsiphash.h"
diff --git a/compile.c b/compile.c
index 7692e106..99e7d77b 100644
--- a/compile.c
+++ b/compile.c
@@ -89,6 +89,7 @@ CORD compile_type(env_t *env, type_t *t)
case VoidType: return "void";
case MemoryType: return "void";
case BoolType: return "Bool_t";
+ case CStringType: return "char*";
case IntType: return Match(t, IntType)->bits == 64 ? "Int_t" : CORD_asprintf("Int%ld_t", Match(t, IntType)->bits);
case NumType: return Match(t, NumType)->bits == 64 ? "Num_t" : CORD_asprintf("Num%ld_t", Match(t, NumType)->bits);
case TextType: {
@@ -854,6 +855,7 @@ CORD expr_as_text(env_t *env, CORD expr, type_t *t, CORD color)
switch (t->tag) {
case MemoryType: return CORD_asprintf("Memory$as_text(stack(%r), %r, &$Memory)", expr, color);
case BoolType: return CORD_asprintf("Bool$as_text(stack(%r), %r, &$Bool)", expr, color);
+ case CStringType: return CORD_asprintf("CString$as_text(stack(%r), %r, &$CString)", expr, color);
case IntType: {
CORD name = type_to_cord(t);
return CORD_asprintf("%r$as_text(stack(%r), %r, &$%r)", name, expr, color, name);
@@ -1705,6 +1707,18 @@ CORD compile(env_t *env, ast_t *ast)
if (actual->tag != IntType && actual->tag != NumType)
code_err(call->args->value, "This %T value cannot be converted to a %T", actual, t);
return CORD_all("((", compile_type(env, t), ")(", compile(env, call->args->value), "))");
+ } else if (t->tag == TextType) {
+ // Text constructor:
+ if (!call->args || call->args->next)
+ code_err(call->fn, "This constructor takes exactly 1 argument");
+ type_t *actual = get_type(env, call->args->value);
+ return expr_as_text(env, compile(env, call->args->value), actual, "no");
+ } else if (t->tag == CStringType) {
+ // C String constructor:
+ if (!call->args || call->args->next)
+ code_err(call->fn, "This constructor takes exactly 1 argument");
+ type_t *actual = get_type(env, call->args->value);
+ return CORD_all("CORD_to_char_star(", expr_as_text(env, compile(env, call->args->value), actual, "no"), ")");
} else {
code_err(call->fn, "This is not a type that has a constructor");
}
@@ -1929,7 +1943,7 @@ CORD compile(env_t *env, ast_t *ast)
case InlineCCode: return Match(ast, InlineCCode)->code;
case Use: return CORD_EMPTY;
case LinkerDirective: code_err(ast, "Linker directives are not supported yet");
- case Extern: code_err(ast, "Externs are not supported yet");
+ case Extern: code_err(ast, "Externs are not supported as expressions");
case TableEntry: code_err(ast, "Table entries should not be compiled directly");
case Declare: case Assign: case UpdateAssign: case For: case While: case StructDef: case LangDef:
case EnumDef: case FunctionDef: case Skip: case Stop: case Pass: case Return: case DocTest:
@@ -1975,7 +1989,8 @@ void compile_namespace(env_t *env, const char *ns_name, ast_t *block)
CORD compile_type_info(env_t *env, type_t *t)
{
switch (t->tag) {
- case BoolType: case IntType: case NumType: return CORD_asprintf("&$%r", type_to_cord(t));
+ case BoolType: case IntType: case NumType: case CStringType:
+ return CORD_asprintf("&$%r", type_to_cord(t));
case TextType: {
auto text = Match(t, TextType);
return text->lang ? CORD_all("(&", text->env->file_prefix, text->lang, ")") : "&$Text";
diff --git a/environment.c b/environment.c
index 2767340f..d5ece261 100644
--- a/environment.c
+++ b/environment.c
@@ -151,6 +151,9 @@ env_t *new_compilation_unit(void)
F(tan), F(tanh), F(tgamma), F(trunc), F(y0), F(y1),
F2(atan2), F2(copysign), F2(fdim), F2(hypot), F2(nextafter), F2(pow), F2(remainder),
)},
+ {"CString", Type(CStringType), "char*", "$CString", TypedArray(ns_entry_t,
+ {"as_text", "CORD_from_char_star", "func(str:CString)->Text"},
+ )},
#undef F2
#undef F
#undef C
@@ -159,6 +162,8 @@ env_t *new_compilation_unit(void)
{"upper", "Text$upper", "func(text:Text)->Text"},
{"lower", "Text$lower", "func(text:Text)->Text"},
{"title", "Text$title", "func(text:Text)->Text"},
+ {"as_c_string", "CORD_to_char_star", "func(text:Text)->CString"},
+ {"from_c_string", "CORD_from_char_star", "func(str:CString)->Text"},
// {"has", "Text$has", "func(text:Text, target:Text, where=ANYWHERE)->Bool"},
// {"without", "Text$without", "func(text:Text, target:Text, where=ANYWHERE)->Text"},
// {"trimmed", "Text$without", "func(text:Text, skip:Text, where=ANYWHERE)->Text"},
diff --git a/typecheck.c b/typecheck.c
index 937a0bff..d60a84ea 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -617,7 +617,7 @@ type_t *get_type(env_t *env, ast_t *ast)
if (fn_type_t->tag == TypeInfoType) {
type_t *t = Match(fn_type_t, TypeInfoType)->type;
- if (t->tag == StructType || t->tag == IntType || t->tag == NumType)
+ if (t->tag == StructType || t->tag == IntType || t->tag == NumType || t->tag == TextType || t->tag == CStringType)
return t; // Constructor
code_err(call->fn, "This is not a type that has a constructor");
}
diff --git a/types.c b/types.c
index 1c1f4fd5..788eba4c 100644
--- a/types.c
+++ b/types.c
@@ -16,6 +16,7 @@ CORD type_to_cord(type_t *t) {
case VoidType: return "Void";
case MemoryType: return "Memory";
case BoolType: return "Bool";
+ case CStringType: return "CString";
case TextType: return Match(t, TextType)->lang ? Match(t, TextType)->lang : "Text";
case IntType: return Match(t, IntType)->bits == 64 ? "Int" : CORD_asprintf("Int%ld", Match(t, IntType)->bits);
case NumType: return Match(t, NumType)->bits == 64 ? "Num" : CORD_asprintf("Num%ld", Match(t, NumType)->bits);
@@ -398,6 +399,7 @@ size_t type_size(type_t *t)
case UnknownType: case AbortType: case VoidType: return 0;
case MemoryType: errx(1, "Memory has undefined type size");
case BoolType: return sizeof(bool);
+ case CStringType: return sizeof(char*);
case IntType: return Match(t, IntType)->bits/8;
case NumType: return Match(t, NumType)->bits/8;
case TextType: return sizeof(CORD);
@@ -449,6 +451,7 @@ size_t type_align(type_t *t)
case UnknownType: case AbortType: case VoidType: return 0;
case MemoryType: errx(1, "Memory has undefined type alignment");
case BoolType: return __alignof__(bool);
+ case CStringType: return __alignof__(char*);
case IntType: return Match(t, IntType)->bits/8;
case NumType: return Match(t, NumType)->bits/8;
case TextType: return __alignof__(CORD);
diff --git a/types.h b/types.h
index df913de5..6d667c31 100644
--- a/types.h
+++ b/types.h
@@ -44,6 +44,7 @@ struct type_s {
BoolType,
IntType,
NumType,
+ CStringType,
TextType,
ArrayType,
TableType,
@@ -65,6 +66,7 @@ struct type_s {
struct {
int64_t bits;
} NumType;
+ struct {} CStringType;
struct {
const char *lang;
struct env_s *env;