diff --git a/Makefile b/Makefile index d8a659f..637d0bf 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 0000000..f74d6da --- /dev/null +++ b/builtins/c_string.c @@ -0,0 +1,52 @@ +// Type info and methods for CString datatype (char*) +#include +#include +#include +#include +#include +#include +#include + +#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 0000000..6b4b0aa --- /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 +#include +#include + +#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 f668b25..eedcc9f 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 f1a2867..e62fc44 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 f0455ad..ded8294 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 7692e10..99e7d77 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 2767340..d5ece26 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 937a0bf..d60a84e 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 1c1f4fd..788eba4 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 df913de..6d667c3 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;