diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-03-30 17:27:52 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-03-30 17:27:52 -0400 |
| commit | 8cba6c3c24c2122c843aa0feaa26fd6e5c2412e2 (patch) | |
| tree | ae0583da790de2416f03a27e9f94953be7d4a803 /src | |
| parent | d853d7b8dc1586f6b2fad3bf05998bfbe935b8f3 (diff) | |
Deprecate built-in Moment datatype in favor of a `time` module
Diffstat (limited to 'src')
| -rw-r--r-- | src/ast.c | 1 | ||||
| -rw-r--r-- | src/ast.h | 4 | ||||
| -rw-r--r-- | src/compile.c | 39 | ||||
| -rw-r--r-- | src/environment.c | 41 | ||||
| -rw-r--r-- | src/parse.c | 55 | ||||
| -rw-r--r-- | src/stdlib/datatypes.h | 3 | ||||
| -rw-r--r-- | src/stdlib/integers.c | 16 | ||||
| -rw-r--r-- | src/stdlib/integers.h | 2 | ||||
| -rw-r--r-- | src/stdlib/moments.c | 323 | ||||
| -rw-r--r-- | src/stdlib/moments.h | 44 | ||||
| -rw-r--r-- | src/stdlib/optionals.c | 1 | ||||
| -rw-r--r-- | src/stdlib/optionals.h | 1 | ||||
| -rw-r--r-- | src/stdlib/paths.c | 18 | ||||
| -rw-r--r-- | src/stdlib/paths.h | 6 | ||||
| -rw-r--r-- | src/stdlib/tomo.h | 1 | ||||
| -rw-r--r-- | src/typecheck.c | 3 | ||||
| -rw-r--r-- | src/types.c | 8 | ||||
| -rw-r--r-- | src/types.h | 3 |
18 files changed, 38 insertions, 531 deletions
@@ -163,7 +163,6 @@ CORD ast_to_xml(ast_t *ast) T(FieldAccess, "<FieldAccess field=\"%s\">%r</FieldAccess>", data.field, ast_to_xml(data.fielded)) T(Optional, "<Optional>%r</Optional>", ast_to_xml(data.value)) T(NonOptional, "<NonOptional>%r</NonOptional>", ast_to_xml(data.value)) - T(Moment, "<Moment/>") T(DocTest, "<DocTest>%r%r</DocTest>", optional_tagged("expression", data.expr), optional_tagged("expected", data.expected)) T(Use, "<Use>%r%r</Use>", optional_tagged("var", data.var), xml_escape(data.path)) T(InlineCCode, "<InlineCode>%r</InlineCode>", xml_escape(data.code)) @@ -140,7 +140,6 @@ typedef enum { Extern, StructDef, EnumDef, LangDef, Index, FieldAccess, Optional, NonOptional, - Moment, DocTest, Use, InlineCCode, @@ -319,9 +318,6 @@ struct ast_s { ast_t *value; } Optional, NonOptional; struct { - Moment_t moment; - } Moment; - struct { ast_t *expr, *expected; bool skip_source:1; } DocTest; diff --git a/src/compile.c b/src/compile.c index 18a1e9a1..9073de5e 100644 --- a/src/compile.c +++ b/src/compile.c @@ -39,18 +39,18 @@ static CORD compile_string_literal(CORD literal); CORD promote_to_optional(type_t *t, CORD code) { - if (t == THREAD_TYPE || t == PATH_TYPE || t == PATH_TYPE_TYPE || t == MATCH_TYPE || t->tag == MomentType) { + if (t == THREAD_TYPE || t == PATH_TYPE || t == PATH_TYPE_TYPE || t == MATCH_TYPE) { return code; } else if (t->tag == IntType) { switch (Match(t, IntType)->bits) { - case TYPE_IBITS8: return CORD_all("((OptionalInt8_t){", code, "})"); - case TYPE_IBITS16: return CORD_all("((OptionalInt16_t){", code, "})"); - case TYPE_IBITS32: return CORD_all("((OptionalInt32_t){", code, "})"); - case TYPE_IBITS64: return CORD_all("((OptionalInt64_t){", code, "})"); + case TYPE_IBITS8: return CORD_all("((OptionalInt8_t){.value=", code, "})"); + case TYPE_IBITS16: return CORD_all("((OptionalInt16_t){.value=", code, "})"); + case TYPE_IBITS32: return CORD_all("((OptionalInt32_t){.value=", code, "})"); + case TYPE_IBITS64: return CORD_all("((OptionalInt64_t){.value=", code, "})"); default: errx(1, "Unsupported in type: ", type_to_str(t)); } } else if (t->tag == ByteType) { - return CORD_all("((OptionalByte_t){", code, "})"); + return CORD_all("((OptionalByte_t){.value=", code, "})"); } else if (t->tag == StructType) { return CORD_all("({ ", compile_type(Type(OptionalType, .type=t)), " nonnull = {.value=", code, "}; nonnull.is_none = false; nonnull; })"); } else { @@ -516,7 +516,6 @@ CORD compile_type(type_t *t) case BoolType: return "Bool_t"; case ByteType: return "Byte_t"; case CStringType: return "const char*"; - case MomentType: return "Moment_t"; case BigIntType: return "Int_t"; case IntType: return CORD_asprintf("Int%ld_t", Match(t, IntType)->bits); case NumType: return Match(t, NumType)->bits == TYPE_NBITS64 ? "Num_t" : CORD_asprintf("Num%ld_t", Match(t, NumType)->bits); @@ -563,7 +562,7 @@ CORD compile_type(type_t *t) case TextType: return Match(nonnull, TextType)->lang ? compile_type(nonnull) : "OptionalText_t"; case IntType: case BigIntType: case NumType: case BoolType: case ByteType: - case ArrayType: case TableType: case SetType: case MomentType: + case ArrayType: case TableType: case SetType: return CORD_all("Optional", compile_type(nonnull)); case StructType: { if (nonnull == THREAD_TYPE) @@ -688,7 +687,7 @@ CORD optional_into_nonnone(type_t *t, CORD value) if (t->tag == OptionalType) t = Match(t, OptionalType)->type; switch (t->tag) { case IntType: - return CORD_all(value, ".i"); + return CORD_all(value, ".value"); case StructType: if (t == THREAD_TYPE || t == MATCH_TYPE || t == PATH_TYPE || t == PATH_TYPE_TYPE) return value; @@ -730,8 +729,6 @@ CORD check_none(type_t *t, CORD value) return CORD_all("(", value, ").is_none"); else if (t->tag == EnumType) return CORD_all("({(", value, ").$tag == 0;})"); - else if (t->tag == MomentType) - return CORD_all("({(", value, ").tv_usec < 0;})"); else if (t->tag == MutexedType) return CORD_all("({", value, " == NULL;})"); print_err("Optional check not implemented for: ", type_to_str(t)); @@ -1803,7 +1800,6 @@ CORD expr_as_text(CORD expr, type_t *t, CORD color) // NOTE: this cannot use stack(), since bools may actually be bit fields: return CORD_asprintf("Bool$as_text((Bool_t[1]){%r}, %r, &Bool$info)", expr, color); case CStringType: return CORD_asprintf("CString$as_text(stack(%r), %r, &CString$info)", expr, color); - case MomentType: return CORD_asprintf("Moment$as_text(stack(%r), %r, &Moment$info)", expr, color); case BigIntType: case IntType: case ByteType: case NumType: { CORD name = type_to_cord(t); return CORD_asprintf("%r$as_text(stack(%r), %r, &%r$info)", name, expr, color, name); @@ -2227,7 +2223,6 @@ CORD compile_none(type_t *t) case SetType: return "NONE_TABLE"; case TextType: return "NONE_TEXT"; case CStringType: return "NULL"; - case MomentType: return "NONE_MOMENT"; case PointerType: return CORD_all("((", compile_type(t), ")NULL)"); case ClosureType: return "NONE_CLOSURE"; case NumType: return "nan(\"null\")"; @@ -2268,10 +2263,6 @@ CORD compile(env_t *env, ast_t *ast) return compile_none(t); } case Bool: return Match(ast, Bool)->b ? "yes" : "no"; - case Moment: { - auto moment = Match(ast, Moment)->moment; - return CORD_asprintf("((Moment_t){.tv_sec=%ld, .tv_usec=%ld})", moment.tv_sec, moment.tv_usec); - } case Var: { binding_t *b = get_binding(env, Match(ast, Var)->name); if (b) @@ -3748,14 +3739,6 @@ CORD compile(env_t *env, ast_t *ast) env_t *module_env = Table$str_get(*env->imports, name); return compile(module_env, WrapAST(ast, Var, f->field)); } - case MomentType: { - if (streq(f->field, "seconds")) { - return CORD_all("I64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").tv_sec)"); - } else if (streq(f->field, "microseconds")) { - return CORD_all("I64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").tv_usec)"); - } - code_err(ast, "There is no '", f->field, "' field on Moments"); - } default: code_err(ast, "Field accesses are not supported on ", type_to_str(fielded_t), " values"); } @@ -3853,7 +3836,7 @@ CORD compile_type_info(type_t *t) else if (t == PATH_TYPE_TYPE) return "&PathType$info"; switch (t->tag) { - case BoolType: case ByteType: case IntType: case BigIntType: case NumType: case CStringType: case MomentType: + case BoolType: case ByteType: case IntType: case BigIntType: case NumType: case CStringType: return CORD_all("&", type_to_cord(t), "$info"); case TextType: { auto text = Match(t, TextType); @@ -4134,8 +4117,8 @@ CORD compile_function(env_t *env, CORD name_code, ast_t *ast, CORD *staticdefs) assert(args); OptionalInt64_t cache_size = Int64$parse(Text$from_str(Match(cache, Int)->str)); CORD pop_code = CORD_EMPTY; - if (cache->tag == Int && !cache_size.is_none && cache_size.i > 0) { - pop_code = CORD_all("if (cache.entries.length > ", CORD_asprintf("%ld", cache_size.i), + if (cache->tag == Int && !cache_size.is_none && cache_size.value > 0) { + pop_code = CORD_all("if (cache.entries.length > ", CORD_asprintf("%ld", cache_size.value), ") Table$remove(&cache, cache.entries.data + cache.entries.stride*RNG$int64(default_rng, 0, cache.entries.length-1), table_type);\n"); } diff --git a/src/environment.c b/src/environment.c index 97672f2d..77f91f10 100644 --- a/src/environment.c +++ b/src/environment.c @@ -288,41 +288,13 @@ env_t *global_env(void) {"escape_int", "Int$value_as_text", "func(i:Int -> Pattern)"}, {"escape_text", "Pattern$escape_text", "func(text:Text -> Pattern)"}, )}, - {"Moment", Type(MomentType), "Moment_t", "Moment", TypedArray(ns_entry_t, - // Used as a default for functions below: - {"now", "Moment$now", "func(->Moment)"}, - - {"after", "Moment$after", "func(moment:Moment,seconds,minutes,hours=0.0,days,weeks,months,years=0,timezone=none:Text -> Moment)"}, - {"date", "Moment$date", "func(moment:Moment,timezone=none:Text -> Text)"}, - {"day_of_month", "Moment$day_of_month", "func(moment:Moment,timezone=none:Text -> Int)"}, - {"day_of_week", "Moment$day_of_week", "func(moment:Moment,timezone=none:Text -> Int)"}, - {"day_of_year", "Moment$day_of_year", "func(moment:Moment,timezone=none:Text -> Int)"}, - {"format", "Moment$format", "func(moment:Moment,format=\"%Y-%m-%dT%H:%M:%S%z\",timezone=none:Text -> Text)"}, - {"from_unix_timestamp", "Moment$from_unix_timestamp", "func(timestamp:Int64 -> Moment)"}, - {"get_local_timezone", "Moment$get_local_timezone", "func(->Text)"}, - {"hour", "Moment$hour", "func(moment:Moment,timezone=none:Text -> Int)"}, - {"hours_till", "Moment$hours_till", "func(now,then:Moment -> Num)"}, - {"minute", "Moment$minute", "func(moment:Moment,timezone=none:Text -> Int)"}, - {"minutes_till", "Moment$minutes_till", "func(now,then:Moment -> Num)"}, - {"month", "Moment$month", "func(moment:Moment,timezone=none:Text -> Int)"}, - {"microsecond", "Moment$microsecond", "func(moment:Moment,timezone=none:Text -> Int)"}, - {"new", "Moment$new", "func(year,month,day:Int,hour,minute=0,second=0.0,timezone=none:Text -> Moment)"}, - {"parse", "Moment$parse", "func(text:Text, format=\"%Y-%m-%dT%H:%M:%S%z\" -> Moment?)"}, - {"relative", "Moment$relative", "func(moment:Moment,relative_to=Moment.now(),timezone=none:Text -> Text)"}, - {"second", "Moment$second", "func(moment:Moment,timezone=none:Text -> Int)"}, - {"seconds_till", "Moment$seconds_till", "func(now:Moment,then:Moment -> Num)"}, - {"set_local_timezone", "Moment$set_local_timezone", "func(timezone=none:Text)"}, - {"time", "Moment$time", "func(moment:Moment,seconds=no,am_pm=yes,timezone=none:Text -> Text)"}, - {"unix_timestamp", "Moment$unix_timestamp", "func(moment:Moment -> Int64)"}, - {"year", "Moment$year", "func(moment:Moment,timezone=none:Text -> Int)"}, - )}, {"PathType", PATH_TYPE_TYPE, "PathType_t", "PathType$info", TypedArray(ns_entry_t, {"Relative", "((PathType_t){.$tag=PATH_RELATIVE})", "PathType"}, {"Absolute", "((PathType_t){.$tag=PATH_ABSOLUTE})", "PathType"}, {"Home", "((PathType_t){.$tag=PATH_HOME})", "PathType"}, )}, {"Path", PATH_TYPE, "Path_t", "Path$info", TypedArray(ns_entry_t, - {"accessed", "Path$accessed", "func(path:Path, follow_symlinks=yes -> Moment?)"}, + {"accessed", "Path$accessed", "func(path:Path, follow_symlinks=yes -> Int64?)"}, {"append", "Path$append", "func(path:Path, text:Text, permissions=Int32(0o644))"}, {"append_bytes", "Path$append_bytes", "func(path:Path, bytes:[Byte], permissions=Int32(0o644))"}, {"base_name", "Path$base_name", "func(path:Path -> Text)"}, @@ -330,7 +302,7 @@ env_t *global_env(void) {"can_execute", "Path$can_execute", "func(path:Path -> Bool)"}, {"can_read", "Path$can_read", "func(path:Path -> Bool)"}, {"can_write", "Path$can_write", "func(path:Path -> Bool)"}, - {"changed", "Path$changed", "func(path:Path, follow_symlinks=yes -> Moment?)"}, + {"changed", "Path$changed", "func(path:Path, follow_symlinks=yes -> Int64?)"}, {"child", "Path$with_component", "func(path:Path, child:Text -> Path)"}, {"children", "Path$children", "func(path:Path, include_hidden=no -> [Path])"}, {"concatenated_with", "Path$concat", "func(a,b:Path -> Path)"}, @@ -347,7 +319,7 @@ env_t *global_env(void) {"is_pipe", "Path$is_pipe", "func(path:Path, follow_symlinks=yes -> Bool)"}, {"is_socket", "Path$is_socket", "func(path:Path, follow_symlinks=yes -> Bool)"}, {"is_symlink", "Path$is_symlink", "func(path:Path -> Bool)"}, - {"modified", "Path$modified", "func(path:Path, follow_symlinks=yes -> Moment?)"}, + {"modified", "Path$modified", "func(path:Path, follow_symlinks=yes -> Int64?)"}, {"owner", "Path$owner", "func(path:Path, follow_symlinks=yes -> Text?)"}, {"parent", "Path$parent", "func(path:Path -> Path)"}, {"read", "Path$read", "func(path:Path -> Text?)"}, @@ -562,10 +534,6 @@ env_t *global_env(void) {"Path$escape_path", "func(path:Path -> Path)"}, {"Int$value_as_text", "func(i:Int -> Path)"}); ADD_CONSTRUCTORS("CString", {"Text$as_c_string", "func(text:Text -> CString)"}); - ADD_CONSTRUCTORS("Moment", - {"Moment$now", "func(-> Moment)"}, - {"Moment$new", "func(year,month,day:Int,hour,minute=0,second=0.0,timezone=none:Text -> Moment)"}, - {"Moment$from_unix_timestamp", "func(timestamp:Int64 -> Moment)"}); ADD_CONSTRUCTORS("RNG", {"RNG$new", "func(-> RNG)"}); ADD_CONSTRUCTORS("Thread", {"Thread$new", "func(fn:func() -> Thread)"}); #undef ADD_CONSTRUCTORS @@ -591,7 +559,6 @@ env_t *global_env(void) {"exit", "tomo_exit", "func(message=none:Text, code=Int32(1) -> Abort)"}, {"fail", "fail_text", "func(message:Text -> Abort)"}, {"sleep", "sleep_num", "func(seconds:Num)"}, - {"now", "Moment$now", "func(->Moment)"}, }; for (size_t i = 0; i < sizeof(global_vars)/sizeof(global_vars[0]); i++) { @@ -756,7 +723,7 @@ env_t *get_namespace_by_type(env_t *env, type_t *t) switch (t->tag) { case ArrayType: return NULL; case TableType: return NULL; - case CStringType: case MomentType: + case CStringType: case BoolType: case IntType: case BigIntType: case NumType: case ByteType: { binding_t *b = get_binding(env, CORD_to_const_char_star(type_to_cord(t))); assert(b); diff --git a/src/parse.c b/src/parse.c index 5e2894f0..5190d92c 100644 --- a/src/parse.c +++ b/src/parse.c @@ -120,7 +120,6 @@ static PARSER(parse_holding); static PARSER(parse_if); static PARSER(parse_inline_c); static PARSER(parse_int); -static PARSER(parse_moment); static PARSER(parse_lambda); static PARSER(parse_lang_def); static PARSER(parse_mutexed); @@ -498,59 +497,6 @@ PARSER(parse_int) { return NewAST(ctx->file, start, pos, Int, .str=str); } -PARSER(parse_moment) { - const char *start = pos; - bool negative = match(&pos, "-"); - if (!isdigit(*pos)) return NULL; - - struct tm info = {.tm_isdst=-1}; - char *after = strptime(pos, "%Y-%m-%d", &info); - if (!after) return NULL; - if (negative) info.tm_year = -(info.tm_year + 1900) - 1900; - pos = after; - if (match(&pos, "T") || spaces(&pos) >= 1) { - after = strptime(pos, "%H:%M", &info); - if (after) { - pos = after; - after = strptime(pos, ":%S", &info); - if (after) pos = after; - // TODO parse nanoseconds - } - } - - const char *before_spaces = pos; - spaces(&pos); - Moment_t moment; - if (match(&pos, "[")) { - size_t tz_len = strcspn(pos, "\r\n]"); - const char *tz = heap_strf("%.*s", tz_len, pos); - // TODO: check that tz is a valid timezone - pos += tz_len; - expect_closing(ctx, &pos, "]", "I wasn't able to parse the rest of this moment timezone"); - const char *old_tz = getenv("TZ"); - setenv("TZ", tz, 1); - tzset(); - moment = (Moment_t){.tv_sec=mktime(&info)}; - if (old_tz) setenv("TZ", old_tz, 1); - else unsetenv("TZ"); - } else if (*pos == 'Z' || *pos == '-' || *pos == '+') { - after = strptime(pos, "%z", &info); - if (after) { - pos = after; - long offset = info.tm_gmtoff; // Need to cache this because mktime() mutates it to local timezone >:( - time_t t = mktime(&info); - moment = (Moment_t){.tv_sec=t + offset - info.tm_gmtoff}; - } else { - moment = (Moment_t){.tv_sec=mktime(&info)}; - } - } else { - pos = before_spaces; - moment = (Moment_t){.tv_sec=mktime(&info)}; - } - - return NewAST(ctx->file, start, pos, Moment, .moment=moment); -} - type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos) { const char *start = pos; if (!match(&pos, "{")) return NULL; @@ -1590,7 +1536,6 @@ PARSER(parse_term_no_suffix) { ast_t *term = NULL; (void)( false - || (term=parse_moment(ctx, pos)) // Must come before num/int || (term=parse_none(ctx, pos)) || (term=parse_num(ctx, pos)) // Must come before int || (term=parse_int(ctx, pos)) diff --git a/src/stdlib/datatypes.h b/src/stdlib/datatypes.h index 40b4712a..22cee673 100644 --- a/src/stdlib/datatypes.h +++ b/src/stdlib/datatypes.h @@ -109,9 +109,6 @@ typedef struct { } Path_t; #define OptionalPath_t Path_t -typedef struct timeval Moment_t; -#define OptionalMoment_t Moment_t - typedef struct RNGState_t* RNG_t; typedef struct MutexedData_s { diff --git a/src/stdlib/integers.c b/src/stdlib/integers.c index c5764d46..8086239d 100644 --- a/src/stdlib/integers.c +++ b/src/stdlib/integers.c @@ -597,24 +597,24 @@ public void Int32$deserialize(FILE *in, void *outval, Array_t*, const TypeInfo_t { \ Optional##KindOfInt##_t i = info->current; \ if (!i.is_none) { \ - KindOfInt##_t next; bool overflow = __builtin_add_overflow(i.i, info->step, &next); \ - if (overflow || (!info->last.is_none && (info->step >= 0 ? next > info->last.i : next < info->last.i))) \ + KindOfInt##_t next; bool overflow = __builtin_add_overflow(i.value, info->step, &next); \ + if (overflow || (!info->last.is_none && (info->step >= 0 ? next > info->last.value : next < info->last.value))) \ info->current = (Optional##KindOfInt##_t){.is_none=true}; \ else \ - info->current = (Optional##KindOfInt##_t){.i=next}; \ + info->current = (Optional##KindOfInt##_t){.value=next}; \ } \ return i; \ } \ public to_attr Closure_t KindOfInt ## $to(c_type first, c_type last, Optional ## KindOfInt ## _t step) { \ KindOfInt##Range_t *range = GC_MALLOC(sizeof(KindOfInt##Range_t)); \ - range->current = (Optional##KindOfInt##_t){.i=first}; \ - range->last = (Optional##KindOfInt##_t){.i=last}; \ - range->step = step.is_none ? (last >= first ? 1 : -1) : step.i; \ + range->current = (Optional##KindOfInt##_t){.value=first}; \ + range->last = (Optional##KindOfInt##_t){.value=last}; \ + range->step = step.is_none ? (last >= first ? 1 : -1) : step.value; \ return (Closure_t){.fn=_next_##KindOfInt, .userdata=range}; \ } \ public to_attr Closure_t KindOfInt ## $onward(c_type first, c_type step) { \ KindOfInt##Range_t *range = GC_MALLOC(sizeof(KindOfInt##Range_t)); \ - range->current = (Optional##KindOfInt##_t){.i=first}; \ + range->current = (Optional##KindOfInt##_t){.value=first}; \ range->last = (Optional##KindOfInt##_t){.is_none=true}; \ range->step = step; \ return (Closure_t){.fn=_next_##KindOfInt, .userdata=range}; \ @@ -628,7 +628,7 @@ public void Int32$deserialize(FILE *in, void *outval, Array_t*, const TypeInfo_t if (Int$compare_value(full_int, I(max_val)) > 0) { \ return (Optional ## KindOfInt ## _t){.is_none=true}; \ } \ - return (Optional ## KindOfInt ## _t){.i=KindOfInt##$from_int(full_int, true)}; \ + return (Optional ## KindOfInt ## _t){.value=KindOfInt##$from_int(full_int, true)}; \ } \ public CONSTFUNC c_type KindOfInt ## $gcd(c_type x, c_type y) { \ if (x == 0 || y == 0) return 0; \ diff --git a/src/stdlib/integers.h b/src/stdlib/integers.h index 779bee1f..a057327b 100644 --- a/src/stdlib/integers.h +++ b/src/stdlib/integers.h @@ -20,7 +20,7 @@ #define DEFINE_INT_TYPE(c_type, type_name) \ typedef struct { \ - c_type i; \ + c_type value; \ bool is_none:1; \ } Optional ## type_name ## _t; \ Text_t type_name ## $as_text(const void *i, bool colorize, const TypeInfo_t *type); \ diff --git a/src/stdlib/moments.c b/src/stdlib/moments.c deleted file mode 100644 index d1abdfbe..00000000 --- a/src/stdlib/moments.c +++ /dev/null @@ -1,323 +0,0 @@ -// Moment methods/type info -#include <ctype.h> -#include <gc.h> -#include <err.h> -#include <stdio.h> -#include <stdlib.h> -#include <time.h> -#include <unistd.h> - -#include "datatypes.h" -#include "math.h" -#include "moments.h" -#include "optionals.h" -#include "patterns.h" -#include "stdlib.h" -#include "text.h" -#include "util.h" - -static OptionalText_t _local_timezone = NONE_TEXT; - -#define WITH_TIMEZONE(tz, body) ({ if (tz.length >= 0) { \ - OptionalText_t old_timezone = _local_timezone; \ - Moment$set_local_timezone(tz); \ - body; \ - Moment$set_local_timezone(old_timezone); \ - } else { \ - body; \ - }}) - -public Text_t Moment$as_text(const void *moment, bool colorize, const TypeInfo_t*) -{ - if (!moment) - return Text("Moment"); - - struct tm info; - struct tm *final_info = localtime_r(&((Moment_t*)moment)->tv_sec, &info); - static char buf[256]; - size_t len = strftime(buf, sizeof(buf), "%c %Z", final_info); - Text_t text = Text$format("%.*s", (int)len, buf); - if (colorize) - text = Text$concat(Text("\x1b[36m"), text, Text("\x1b[m")); - return text; -} - -PUREFUNC public int32_t Moment$compare(const void *va, const void *vb, const TypeInfo_t*) -{ - Moment_t *a = (Moment_t*)va, *b = (Moment_t*)vb; - if (a->tv_sec != b->tv_sec) - return (a->tv_sec > b->tv_sec) - (a->tv_sec < b->tv_sec); - return (a->tv_usec > b->tv_usec) - (a->tv_usec < b->tv_usec); -} - -CONSTFUNC public bool Moment$is_none(const void *m, const TypeInfo_t*) -{ - return ((Moment_t*)m)->tv_usec < 0; -} - -public Moment_t Moment$now(void) -{ - struct timespec ts; - if (clock_gettime(CLOCK_REALTIME, &ts) != 0) - fail("Couldn't get the time!"); - return (Moment_t){.tv_sec=ts.tv_sec, .tv_usec=ts.tv_nsec/1000}; -} - -public Moment_t Moment$new(Int_t year, Int_t month, Int_t day, Int_t hour, Int_t minute, double second, OptionalText_t tz) -{ - struct tm info = { - .tm_min=Int32$from_int(minute, false), - .tm_hour=Int32$from_int(hour, false), - .tm_mday=Int32$from_int(day, false), - .tm_mon=Int32$from_int(month, false) - 1, - .tm_year=Int32$from_int(year, false) - 1900, - .tm_isdst=-1, - }; - - time_t t; - WITH_TIMEZONE(tz, t = mktime(&info)); - return (Moment_t){.tv_sec=t + (time_t)second, .tv_usec=(suseconds_t)(fmod(second, 1.0) * 1e9)}; -} - -public Moment_t Moment$after(Moment_t moment, double seconds, double minutes, double hours, Int_t days, Int_t weeks, Int_t months, Int_t years, OptionalText_t tz) -{ - double offset = seconds + 60.*minutes + 3600.*hours; - moment.tv_sec += (time_t)offset; - - struct tm info = {}; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - - info.tm_mday += Int32$from_int(days, false) + 7*Int32$from_int(weeks, false); - info.tm_mon += Int32$from_int(months, false); - info.tm_year += Int32$from_int(years, false); - - time_t t = mktime(&info); - return (Moment_t){ - .tv_sec=t, - .tv_usec=moment.tv_usec + (suseconds_t)(fmod(offset, 1.0) * 1e9), - }; -} - -CONSTFUNC public double Moment$seconds_till(Moment_t now, Moment_t then) -{ - return (double)(then.tv_sec - now.tv_sec) + 1e-9*(double)(then.tv_usec - now.tv_usec); -} - -CONSTFUNC public double Moment$minutes_till(Moment_t now, Moment_t then) -{ - return Moment$seconds_till(now, then)/60.; -} - -CONSTFUNC public double Moment$hours_till(Moment_t now, Moment_t then) -{ - return Moment$seconds_till(now, then)/3600.; -} - -public void Moment$get( - Moment_t moment, Int_t *year, Int_t *month, Int_t *day, Int_t *hour, Int_t *minute, Int_t *second, - Int_t *nanosecond, Int_t *weekday, OptionalText_t tz) -{ - struct tm info = {}; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - - if (year) *year = I(info.tm_year + 1900); - if (month) *month = I(info.tm_mon + 1); - if (day) *day = I(info.tm_mday); - if (hour) *hour = I(info.tm_hour); - if (minute) *minute = I(info.tm_min); - if (second) *second = I(info.tm_sec); - if (nanosecond) *nanosecond = I(moment.tv_usec); - if (weekday) *weekday = I(info.tm_wday + 1); -} - -public Int_t Moment$year(Moment_t moment, OptionalText_t tz) -{ - struct tm info = {}; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - return I(info.tm_year + 1900); -} - -public Int_t Moment$month(Moment_t moment, OptionalText_t tz) -{ - struct tm info = {}; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - return I(info.tm_mon + 1); -} - -public Int_t Moment$day_of_week(Moment_t moment, OptionalText_t tz) -{ - struct tm info = {}; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - return I(info.tm_wday + 1); -} - -public Int_t Moment$day_of_month(Moment_t moment, OptionalText_t tz) -{ - struct tm info = {}; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - return I(info.tm_mday); -} - -public Int_t Moment$day_of_year(Moment_t moment, OptionalText_t tz) -{ - struct tm info = {}; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - return I(info.tm_yday); -} - -public Int_t Moment$hour(Moment_t moment, OptionalText_t tz) -{ - struct tm info = {}; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - return I(info.tm_hour); -} - -public Int_t Moment$minute(Moment_t moment, OptionalText_t tz) -{ - struct tm info = {}; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - return I(info.tm_min); -} - -public Int_t Moment$second(Moment_t moment, OptionalText_t tz) -{ - struct tm info = {}; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - return I(info.tm_sec); -} - -public Int_t Moment$microsecond(Moment_t moment, OptionalText_t tz) -{ - (void)tz; - return I(moment.tv_usec); -} - -public Text_t Moment$format(Moment_t moment, Text_t fmt, OptionalText_t tz) -{ - struct tm info; - WITH_TIMEZONE(tz, localtime_r(&moment.tv_sec, &info)); - static char buf[256]; - size_t len = strftime(buf, sizeof(buf), Text$as_c_string(fmt), &info); - return Text$format("%.*s", (int)len, buf); -} - -public Text_t Moment$date(Moment_t moment, OptionalText_t tz) -{ - return Moment$format(moment, Text("%F"), tz); -} - -public Text_t Moment$time(Moment_t moment, bool seconds, bool am_pm, OptionalText_t tz) -{ - Text_t text; - if (seconds) - text = Moment$format(moment, am_pm ? Text("%l:%M:%S%P") : Text("%T"), tz); - else - text = Moment$format(moment, am_pm ? Text("%l:%M%P") : Text("%H:%M"), tz); - return Text$trim(text, Pattern(" "), true, true); -} - -public OptionalMoment_t Moment$parse(Text_t text, Text_t format) -{ - struct tm info = {.tm_isdst=-1}; - const char *str = Text$as_c_string(text); - const char *fmt = Text$as_c_string(format); - if (strstr(fmt, "%Z")) - fail("The %Z specifier is not supported for time parsing!"); - - char *invalid = strptime(str, fmt, &info); - if (!invalid || invalid[0] != '\0') - return NONE_MOMENT; - - long offset = info.tm_gmtoff; // Need to cache this because mktime() mutates it to local tz >:( - time_t t = mktime(&info); - return (Moment_t){.tv_sec=t + offset - info.tm_gmtoff}; -} - -static INLINE Text_t num_format(long n, const char *unit) -{ - if (n == 0) - return Text("now"); - return Text$format((n == 1 || n == -1) ? "%ld %s %s" : "%ld %ss %s", n < 0 ? -n : n, unit, n < 0 ? "ago" : "later"); -} - -public Text_t Moment$relative(Moment_t moment, Moment_t relative_to, OptionalText_t tz) -{ - struct tm info = {}; - struct tm relative_info = {}; - WITH_TIMEZONE(tz, { - localtime_r(&moment.tv_sec, &info); - localtime_r(&relative_to.tv_sec, &relative_info); - }); - - double second_diff = Moment$seconds_till(relative_to, moment); - if (info.tm_year != relative_info.tm_year && fabs(second_diff) > 365.*24.*60.*60.) - return num_format((long)info.tm_year - (long)relative_info.tm_year, "year"); - else if (info.tm_mon != relative_info.tm_mon && fabs(second_diff) > 31.*24.*60.*60.) - return num_format(12*((long)info.tm_year - (long)relative_info.tm_year) + (long)info.tm_mon - (long)relative_info.tm_mon, "month"); - else if (info.tm_yday != relative_info.tm_yday && fabs(second_diff) > 24.*60.*60.) - return num_format(round(second_diff/(24.*60.*60.)), "day"); - else if (info.tm_hour != relative_info.tm_hour && fabs(second_diff) > 60.*60.) - return num_format(round(second_diff/(60.*60.)), "hour"); - else if (info.tm_min != relative_info.tm_min && fabs(second_diff) > 60.) - return num_format(round(second_diff/(60.)), "minute"); - else { - if (fabs(second_diff) < 1e-6) - return num_format((long)(second_diff*1e9), "nanosecond"); - else if (fabs(second_diff) < 1e-3) - return num_format((long)(second_diff*1e6), "microsecond"); - else if (fabs(second_diff) < 1.0) - return num_format((long)(second_diff*1e3), "millisecond"); - else - return num_format((long)(second_diff), "second"); - } -} - -CONSTFUNC public Int64_t Moment$unix_timestamp(Moment_t moment) -{ - return (Int64_t)moment.tv_sec; -} - -CONSTFUNC public Moment_t Moment$from_unix_timestamp(Int64_t timestamp) -{ - return (Moment_t){.tv_sec=(time_t)timestamp}; -} - -public void Moment$set_local_timezone(OptionalText_t tz) -{ - if (tz.length >= 0) { - setenv("TZ", Text$as_c_string(tz), 1); - } else { - unsetenv("TZ"); - } - _local_timezone = tz; - tzset(); -} - -public Text_t Moment$get_local_timezone(void) -{ - if (_local_timezone.length < 0) { - static char buf[PATH_MAX]; - ssize_t len = readlink("/etc/localtime", buf, sizeof(buf)); - if (len < 0) - fail("Could not get local tz!"); - - char *zoneinfo = strstr(buf, "/zoneinfo/"); - if (zoneinfo) - _local_timezone = Text$from_str(zoneinfo + strlen("/zoneinfo/")); - else - fail("Could not resolve local tz!"); - } - return _local_timezone; -} - -public const TypeInfo_t Moment$info = { - .size=sizeof(Moment_t), - .align=__alignof__(Moment_t), - .metamethods={ - .as_text=Moment$as_text, - .compare=Moment$compare, - .is_none=Moment$is_none, - }, -}; - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 diff --git a/src/stdlib/moments.h b/src/stdlib/moments.h deleted file mode 100644 index ff6d4119..00000000 --- a/src/stdlib/moments.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -// Moment objects - -#include <stdint.h> - -#include "datatypes.h" -#include "integers.h" -#include "optionals.h" -#include "types.h" -#include "util.h" - -Text_t Moment$as_text(const void *moment, bool colorize, const TypeInfo_t *type); -PUREFUNC int32_t Moment$compare(const void *a, const void *b, const TypeInfo_t *type); -CONSTFUNC public bool Moment$is_none(const void *m, const TypeInfo_t*); -Moment_t Moment$now(void); -Moment_t Moment$new(Int_t year, Int_t month, Int_t day, Int_t hour, Int_t minute, double second, OptionalText_t timezone); -Moment_t Moment$after(Moment_t moment, double seconds, double minutes, double hours, Int_t days, Int_t weeks, Int_t months, Int_t years, OptionalText_t timezone); -CONSTFUNC double Moment$seconds_till(Moment_t now, Moment_t then); -CONSTFUNC double Moment$minutes_till(Moment_t now, Moment_t then); -CONSTFUNC double Moment$hours_till(Moment_t now, Moment_t then); -Int_t Moment$year(Moment_t moment, OptionalText_t timezone); -Int_t Moment$month(Moment_t moment, OptionalText_t timezone); -Int_t Moment$day_of_week(Moment_t moment, OptionalText_t timezone); -Int_t Moment$day_of_month(Moment_t moment, OptionalText_t timezone); -Int_t Moment$day_of_year(Moment_t moment, OptionalText_t timezone); -Int_t Moment$hour(Moment_t moment, OptionalText_t timezone); -Int_t Moment$minute(Moment_t moment, OptionalText_t timezone); -Int_t Moment$second(Moment_t moment, OptionalText_t timezone); -Int_t Moment$microsecond(Moment_t moment, OptionalText_t timezone); -Text_t Moment$format(Moment_t moment, Text_t fmt, OptionalText_t timezone); -Text_t Moment$date(Moment_t moment, OptionalText_t timezone); -Text_t Moment$time(Moment_t moment, bool seconds, bool am_pm, OptionalText_t timezone); -OptionalMoment_t Moment$parse(Text_t text, Text_t format); -Text_t Moment$relative(Moment_t moment, Moment_t relative_to, OptionalText_t timezone); -CONSTFUNC Int64_t Moment$unix_timestamp(Moment_t moment); -CONSTFUNC Moment_t Moment$from_unix_timestamp(Int64_t timestamp); -void Moment$set_local_timezone(OptionalText_t timezone); -Text_t Moment$get_local_timezone(void); - -extern const TypeInfo_t Moment$info; - -// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0 - diff --git a/src/stdlib/optionals.c b/src/stdlib/optionals.c index 462b2df2..db2c477f 100644 --- a/src/stdlib/optionals.c +++ b/src/stdlib/optionals.c @@ -7,7 +7,6 @@ #include "datatypes.h" #include "integers.h" #include "metamethods.h" -#include "moments.h" #include "nums.h" #include "patterns.h" #include "text.h" diff --git a/src/stdlib/optionals.h b/src/stdlib/optionals.h index 94e4d900..8d25c5f1 100644 --- a/src/stdlib/optionals.h +++ b/src/stdlib/optionals.h @@ -16,7 +16,6 @@ #define NONE_TABLE ((OptionalTable_t){.entries.length=-1}) #define NONE_CLOSURE ((OptionalClosure_t){.fn=NULL}) #define NONE_TEXT ((OptionalText_t){.length=-1}) -#define NONE_MOMENT ((OptionalMoment_t){.tv_usec=-1}) #define NONE_PATH ((Path_t){.type=PATH_NONE}) PUREFUNC bool is_null(const void *obj, const TypeInfo_t *non_optional_type); diff --git a/src/stdlib/paths.c b/src/stdlib/paths.c index c7b560b9..05575620 100644 --- a/src/stdlib/paths.c +++ b/src/stdlib/paths.c @@ -255,28 +255,28 @@ public bool Path$can_execute(Path_t path) #endif } -public OptionalMoment_t Path$modified(Path_t path, bool follow_symlinks) +public OptionalInt64_t Path$modified(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); - if (status != 0) return NONE_MOMENT; - return (Moment_t){.tv_sec=sb.st_mtime}; + if (status != 0) return NONE_INT64; + return (OptionalInt64_t){.value=(int64_t)sb.st_mtime}; } -public OptionalMoment_t Path$accessed(Path_t path, bool follow_symlinks) +public OptionalInt64_t Path$accessed(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); - if (status != 0) return NONE_MOMENT; - return (Moment_t){.tv_sec=sb.st_atime}; + if (status != 0) return NONE_INT64; + return (OptionalInt64_t){.value=(int64_t)sb.st_atime}; } -public OptionalMoment_t Path$changed(Path_t path, bool follow_symlinks) +public OptionalInt64_t Path$changed(Path_t path, bool follow_symlinks) { struct stat sb; int status = path_stat(path, follow_symlinks, &sb); - if (status != 0) return NONE_MOMENT; - return (Moment_t){.tv_sec=sb.st_ctime}; + if (status != 0) return NONE_INT64; + return (OptionalInt64_t){.value=(int64_t)sb.st_ctime}; } static void _write(Path_t path, Array_t bytes, int mode, int permissions) diff --git a/src/stdlib/paths.h b/src/stdlib/paths.h index 02afc494..9be81bdf 100644 --- a/src/stdlib/paths.h +++ b/src/stdlib/paths.h @@ -28,9 +28,9 @@ bool Path$is_symlink(Path_t path); bool Path$can_read(Path_t path); bool Path$can_write(Path_t path); bool Path$can_execute(Path_t path); -OptionalMoment_t Path$modified(Path_t path, bool follow_symlinks); -OptionalMoment_t Path$accessed(Path_t path, bool follow_symlinks); -OptionalMoment_t Path$changed(Path_t path, bool follow_symlinks); +OptionalInt64_t Path$modified(Path_t path, bool follow_symlinks); +OptionalInt64_t Path$accessed(Path_t path, bool follow_symlinks); +OptionalInt64_t Path$changed(Path_t path, bool follow_symlinks); void Path$write(Path_t path, Text_t text, int permissions); void Path$write_bytes(Path_t path, Array_t bytes, int permissions); void Path$append(Path_t path, Text_t text, int permissions); diff --git a/src/stdlib/tomo.h b/src/stdlib/tomo.h index 567e5d14..16e5ec57 100644 --- a/src/stdlib/tomo.h +++ b/src/stdlib/tomo.h @@ -17,7 +17,6 @@ #include "integers.h" #include "memory.h" #include "metamethods.h" -#include "moments.h" #include "mutexeddata.h" #include "nums.h" #include "optionals.h" diff --git a/src/typecheck.c b/src/typecheck.c index ba03e968..5da84442 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -852,7 +852,7 @@ type_t *get_type(env_t *env, ast_t *ast) if (constructor) return t; else if (t->tag == StructType || t->tag == IntType || t->tag == BigIntType || t->tag == NumType - || t->tag == ByteType || t->tag == TextType || t->tag == CStringType || t->tag == MomentType) + || t->tag == ByteType || t->tag == TextType || t->tag == CStringType) return t; // Constructor code_err(call->fn, "This is not a type that has a constructor"); } @@ -1408,7 +1408,6 @@ type_t *get_type(env_t *env, ast_t *ast) type_ast_t *type_ast = inline_code->type_ast; return type_ast ? parse_type_ast(env, type_ast) : Type(VoidType); } - case Moment: return Type(MomentType); case Unknown: code_err(ast, "I can't figure out the type of: ", ast_to_str(ast)); case Deserialize: return parse_type_ast(env, Match(ast, Deserialize)->type); } diff --git a/src/types.c b/src/types.c index 8b9289cb..07b6ced0 100644 --- a/src/types.c +++ b/src/types.c @@ -29,7 +29,6 @@ CORD type_to_cord(type_t *t) { case BoolType: return "Bool"; case ByteType: return "Byte"; case CStringType: return "CString"; - case MomentType: return "Moment"; case TextType: return Match(t, TextType)->lang ? Match(t, TextType)->lang : "Text"; case BigIntType: return "Int"; case IntType: return CORD_asprintf("Int%d", Match(t, IntType)->bits); @@ -497,7 +496,6 @@ PUREFUNC size_t type_size(type_t *t) case BoolType: return sizeof(bool); case ByteType: return sizeof(uint8_t); case CStringType: return sizeof(char*); - case MomentType: return sizeof(Moment_t); case BigIntType: return sizeof(Int_t); case IntType: { switch (Match(t, IntType)->bits) { @@ -590,7 +588,6 @@ PUREFUNC size_t type_align(type_t *t) case BoolType: return __alignof__(bool); case ByteType: return __alignof__(uint8_t); case CStringType: return __alignof__(char*); - case MomentType: return __alignof__(Moment_t); case BigIntType: return __alignof__(Int_t); case IntType: { switch (Match(t, IntType)->bits) { @@ -704,11 +701,6 @@ type_t *get_field_type(type_t *t, const char *field_name) if (streq(field_name, "length")) return INT_TYPE; return NULL; } - case MomentType: { - if (streq(field_name, "seconds")) return Type(IntType, .bits=TYPE_IBITS64); - else if (streq(field_name, "microseconds")) return Type(IntType, .bits=TYPE_IBITS64); - return NULL; - } default: return NULL; } } diff --git a/src/types.h b/src/types.h index eec3fac2..ae34c217 100644 --- a/src/types.h +++ b/src/types.h @@ -46,7 +46,6 @@ struct type_s { IntType, NumType, CStringType, - MomentType, TextType, ArrayType, SetType, @@ -76,7 +75,7 @@ struct type_s { struct { enum { TYPE_NBITS32=32, TYPE_NBITS64=64 } bits; } NumType; - struct {} CStringType, MomentType; + struct {} CStringType; struct { const char *lang; struct env_s *env; |
