Replace all remaining C code with V in the compiler and vlib (hoorah!)

pull/726/head
Alexander Medvednikov 2019-06-27 19:02:47 +02:00
parent 554f083543
commit 6824e6e7db
19 changed files with 391 additions and 685 deletions

View File

@ -57,6 +57,7 @@ pub fn print(s string) {
C.printf('%.*s', s.len, s.str)
}
__global total_m i64 = 0
pub fn malloc(n int) byteptr {
if n < 0 {
panic('malloc(<0)')
@ -67,10 +68,8 @@ pub fn malloc(n int) byteptr {
}
#endif
#ifdef DEBUG_ALLOC
total := i64(0)
# total_m += n;
# total = total_m;
println('\n\n\nmalloc($n) total=$total')
total_m += n
println('\n\n\nmalloc($n) total=$total_m')
print_backtrace()
#endif
ptr := C.malloc(n)

View File

@ -496,15 +496,17 @@ pub fn (ar[]int) contains(val int) bool {
return false
}
/*
pub fn (a[]string) to_c() voidptr {
# char ** res = malloc(sizeof(char*) * a.len);
char ** res = malloc(sizeof(char*) * a.len);
for i := 0; i < a.len; i++ {
val := a[i]
# res[i] = val.str;
}
# return res;
return res;
return 0
}
*/
fn is_space(c byte) bool {
return C.isspace(c)
@ -619,8 +621,8 @@ pub fn (s string) ustring() ustring {
runes: new_array(0, s.len, sizeof(int))
}
for i := 0; i < s.len; i++ {
char_len := 0
# char_len =UTF8_CHAR_LEN(s.str[i]);
char_len := utf8_char_len(s.str[i])
//# char_len =UTF8_CHAR_LEN(s.str[i]);
// println('cl=$char_len')
res.runes << i
i += char_len - 1
@ -632,18 +634,19 @@ pub fn (s string) ustring() ustring {
// A hack that allows to create ustring without allocations.
// It's called from functions like draw_text() where we know that the string is going to be freed
// right away. Uses global buffer for storing runes []int array.
# array_int g_ustring_runes;
__global g_ustring_runes []int
pub fn (s string) ustring_tmp() ustring {
mut res := ustring {
s: s
runes: 0
}
# res.runes = g_ustring_runes ;
# res.runes.len = s.len ;
res.runes = g_ustring_runes
res.runes.len = s.len
mut j := 0
for i := 0; i < s.len; i++ {
char_len := 0
# char_len =UTF8_CHAR_LEN(s.str[i]);
//char_len := 0
//# char_len =UTF8_CHAR_LEN(s.str[i]);
char_len := utf8_char_len(s.str[i])
res.runes[j] = i
j++
i += char_len - 1

View File

@ -4,250 +4,10 @@
module builtin
pub fn (s string) is_utf8() int {
faulty_bytes := 0
len := s.len
i := 0
// # size_t i = 0;
# byte * str = s.str;
#
# while (i < len) {
# if (str[i] <= 0x7F) /* 00..7F */ {
# i += 1;
# }
#else if (str[i] >= 0xC2 && str[i] <= 0xDF) /* C2..DF 80..BF */ {
# if (i + 1 < len) /* Expect a 2nd byte */ {
# if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
# printf( "After a first byte between C2 and DF, expecting a 2nd byte between 80 and BF");
# faulty_bytes = 2;
# goto end;
# }
# }
#else {
# printf( "After a first byte between C2 and DF, expecting a 2nd byte.");
# faulty_bytes = 1;
# goto end;
# }
# i += 2;
# }
#else if (str[i] == 0xE0) /* E0 A0..BF 80..BF */ {
# if (i + 2 < len) /* Expect a 2nd and 3rd byte */ {
# if (str[i + 1] < 0xA0 || str[i + 1] > 0xBF) {
# printf( "After a first byte of E0, expecting a 2nd byte between A0 and BF.");
# faulty_bytes = 2;
# goto end;
# }
# if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
# printf( "After a first byte of E0, expecting a 3nd byte between 80 and BF.");
# faulty_bytes = 3;
# goto end;
# }
# }
#else {
# printf( "After a first byte of E0, expecting two following bytes.");
# faulty_bytes = 1;
# goto end;
# }
# i += 3;
# }
#else if (str[i] >= 0xE1 && str[i] <= 0xEC) /* E1..EC 80..BF 80..BF */ {
# if (i + 2 < len) /* Expect a 2nd and 3rd byte */ {
# if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
# printf( "After a first byte between E1 and EC, expecting the 2nd byte between 80 and BF.");
# faulty_bytes = 2;
# goto end;
# }
# if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
# printf( "After a first byte between E1 and EC, expecting the 3rd byte between 80 and BF.");
# faulty_bytes = 3;
# goto end;
# }
# }
#else {
# printf( "After a first byte between E1 and EC, expecting two following bytes.");
# faulty_bytes = 1;
# goto end;
# }
# i += 3;
# }
#else if (str[i] == 0xED) /* ED 80..9F 80..BF */ {
# if (i + 2 < len) /* Expect a 2nd and 3rd byte */ {
# if (str[i + 1] < 0x80 || str[i + 1] > 0x9F) {
# printf( "After a first byte of ED, expecting 2nd byte between 80 and 9F.");
# faulty_bytes = 2;
# goto end;
# }
# if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
# printf( "After a first byte of ED, expecting 3rd byte between 80 and BF.");
# faulty_bytes = 3;
# goto end;
# }
# }
#else {
# printf( "After a first byte of ED, expecting two following bytes.");
# faulty_bytes = 1;
# goto end;
# }
# i += 3;
# }
#else if (str[i] >= 0xEE && str[i] <= 0xEF) /* EE..EF 80..BF 80..BF */ {
# if (i + 2 < len) /* Expect a 2nd and 3rd byte */ {
# if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
# printf( "After a first byte between EE and EF, expecting 2nd byte between 80 and BF.");
# faulty_bytes = 2;
# goto end;
# }
# if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
# printf( "After a first byte between EE and EF, expecting 3rd byte between 80 and BF.");
# faulty_bytes = 3;
# goto end;
# }
# }
#else {
# printf( "After a first byte between EE and EF, two following bytes.");
# faulty_bytes = 1;
# goto end;
# }
# i += 3;
# }
#else if (str[i] == 0xF0) /* F0 90..BF 80..BF 80..BF */ {
# if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */ {
# if (str[i + 1] < 0x90 || str[i + 1] > 0xBF) {
# printf( "After a first byte of F0, expecting 2nd byte between 90 and BF.");
# faulty_bytes = 2;
# goto end;
# }
# if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
# printf( "After a first byte of F0, expecting 3rd byte between 80 and BF.");
# faulty_bytes = 3;
# goto end;
# }
# if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) {
# printf( "After a first byte of F0, expecting 4th byte between 80 and BF.");
# faulty_bytes = 4;
# goto end;
# }
# }
#else {
# printf( "After a first byte of F0, expecting three following bytes.");
# faulty_bytes = 1;
# goto end;
# }
# i += 4;
# }
#else if (str[i] >= 0xF1 && str[i] <= 0xF3) /* F1..F3 80..BF 80..BF 80..BF */ {
# if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */ {
# if (str[i + 1] < 0x80 || str[i + 1] > 0xBF) {
# printf( "After a first byte of F1, F2, or F3, expecting a 2nd byte between 80 and BF.");
# faulty_bytes = 2;
# goto end;
# }
# if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
# printf( "After a first byte of F1, F2, or F3, expecting a 3rd byte between 80 and BF.");
# faulty_bytes = 3;
# goto end;
# }
# if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) {
# printf( "After a first byte of F1, F2, or F3, expecting a 4th byte between 80 and BF.");
# faulty_bytes = 4;
# goto end;
# }
# }
#else {
# printf( "After a first byte of F1, F2, or F3, expecting three following bytes.");
# faulty_bytes = 1;
# goto end;
# }
# i += 4;
# }
#else if (str[i] == 0xF4) /* F4 80..8F 80..BF 80..BF */ {
# if (i + 3 < len) /* Expect a 2nd, 3rd 3th byte */ {
# if (str[i + 1] < 0x80 || str[i + 1] > 0x8F) {
# printf( "After a first byte of F4, expecting 2nd byte between 80 and 8F.");
# faulty_bytes = 2;
# goto end;
# }
# if (str[i + 2] < 0x80 || str[i + 2] > 0xBF) {
# printf( "After a first byte of F4, expecting 3rd byte between 80 and BF.");
# faulty_bytes = 3;
# goto end;
# }
# if (str[i + 3] < 0x80 || str[i + 3] > 0xBF) {
# printf( "After a first byte of F4, expecting 4th byte between 80 and BF.");
# faulty_bytes = 4;
# goto end;
# }
# }
#else {
# printf( "After a first byte of F4, expecting three following bytes.");
# faulty_bytes = 1;
# goto end;
# }
# i += 4;
# }
#else {
# printf( "i=%d Expecting bytes in the following ranges: 00..7F C2..F4.",
# i);
# faulty_bytes = 1;
# goto end;
# }
# }
#
# end: ;
// println('faulty bytes=$faulty_bytes i=$i')
// # printf("c='%c'\n", str[i]);
ok := faulty_bytes == 0
if ok {
return -1
}
if !ok {
println('utf is bad dalen=$len KEK $s sdf')
// s = s.left(i)
}
return i
// return ok
pub fn utf8_char_len(b byte) int {
return (( 0xe5000000 >> (( b >> 3 ) & 0x1e )) & 3 ) + 1
}
/*
fn (s string) runes() []string {
res2 := []string{}
// res := new_empty_array_with_cap_string(s.len)
res := []string{}
if !s.is_utf8() {
mys := s
println('string.me runes bad utf $mys HAHA')
return res
}
for i := 0; i < s.len; i++ {
char_len := 0
# char_len =UTF8_CHAR_LEN(s.str[i]);
switch char_len {
case 1:
// println('ONE')
res <<(char2string(s[i]))
case 2:
// println('TWO')
rune2 := s.substr(i, i + 2)
res <<(rune2)
i++
case 3:
// println('TWO')
rune3 := s.substr(i, i + 3)
res <<(rune3)
i++
i++
case 4:
// println('TWO')
rune4 := s.substr(i, i + 4)
res <<(rune4)
i++
i++
i++
}
}
return res
}
*/
// Convert utf32 to utf8
// utf32 == Codepoint
pub fn utf32_to_str(code u32) string {

View File

@ -517,14 +517,6 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
// If we have a method placeholder,
// we need to preappend "method(receiver, ...)"
else {
// C only knows about functions "array_get", "array_set" etc
// TODO I don't need this?
// mut cgen_typ := receiver_type.replace('*', '')
// if cgen_typ.starts_with('array_') {
// cgen_typ = 'array'
// }
// println('METHOD fn_call name=$cgen_name')
// mut method_call := '${cgen_typ}_${cgen_name}('
mut method_call := '${cgen_name}('
receiver := f.args.first()
if receiver.is_mut && !p.expr_var.is_mut {
@ -550,10 +542,8 @@ fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type strin
p.cgen.set_placeholder(method_ph, '$cast $method_call')
}
p.next()
// p.check(LPAR)
p.fn_call_args(f)
p.gen(')')
// p.check(RPAR)
p.calling_c = false
if is_print {
p.cgen.nogen = false

View File

@ -257,7 +257,8 @@ void init_consts();')
if c.build_mode == EMBED_VLIB || c.build_mode == DEFAULT_MODE {
// If we declare these for all modes, then when running `v a.v` we'll get
// `/usr/bin/ld: multiple definition of 'total_m'`
cgen.genln('i64 total_m = 0; // For counting total RAM allocated')
// TODO
//cgen.genln('i64 total_m = 0; // For counting total RAM allocated')
cgen.genln('int g_test_ok = 1; ')
if c.table.imports.contains('json') {
cgen.genln('

View File

@ -72,6 +72,7 @@ mut:
returns bool
vroot string
is_c_struct_init bool
can_chash bool
}
const (
@ -141,6 +142,7 @@ fn (p mut Parser) parse() {
}
p.fgenln('\n')
p.builtin_pkg = p.pkg == 'builtin'
p.can_chash = p.pkg == 'gg' || p.pkg == 'glm' || p.pkg == 'gl' || p.pkg == 'glfw' // TODO tmp remove
// Import pass - the first and the smallest pass that only analyzes imports
p.table.register_package(p.pkg)
if p.run == RUN_IMPORTS {
@ -203,7 +205,7 @@ fn (p mut Parser) parse() {
// $if, $else
p.comp_time()
case GLOBAL:
if !p.translated {
if !p.translated && !p.builtin_pkg && !p.building_v() {
p.error('__global is only allowed in translated code')
}
p.next()
@ -419,7 +421,7 @@ fn (p mut Parser) struct_decl() {
if !is_c {
kind := if is_union{'union'} else { 'struct'}
p.gen_typedef('typedef $kind $name $name;')
p.gen_type('$kind $name {')
p.gen_type('$kind /*kind*/ $name {')
}
}
// V used to have 'type Foo struct', many Go users might use this syntax
@ -1010,15 +1012,8 @@ fn (p mut Parser) statement(add_semi bool) string {
// this can be `user = ...` or `user.field = ...`, in both cases `v` is `user`
fn (p mut Parser) assign_statement(v Var, ph int, is_map bool) {
p.log('assign_statement() name=$v.name tok=')
// p.print_tok()
// p.gen(name)
// p.assigned_var = name
tok := p.tok
if !v.is_mut && !v.is_arg && !p.translated {
p.error('`$v.name` is immutable')
}
if !v.is_mut && p.is_play && !p.builtin_pkg && !p.translated {
// no mutable args in play
if !v.is_mut && !v.is_arg && !p.translated && !v.is_global{
p.error('`$v.name` is immutable')
}
is_str := v.typ == 'string'
@ -1232,7 +1227,7 @@ fn (p mut Parser) name_expr() string {
// //////////////////////////
// module ?
// Allow shadowing (gg = gg.newcontext(); gg.draw_triangle())
if p.table.known_pkg(name) && !p.cur_fn.known_var(name) {
if p.table.known_pkg(name) && !p.cur_fn.known_var(name) && !is_c {
// println('"$name" is a known pkg')
pkg := name
p.next()
@ -2344,21 +2339,25 @@ fn (p mut Parser) register_array(typ string) {
}
}
// name == 'User'
fn (p mut Parser) struct_init(is_c_struct_init bool) string {
p.is_struct_init = true
mut typ := p.get_type()
p.scanner.fmt_out.cut(typ.len)
ptr := typ.contains('*')
// TODO tm struct struct bug
if typ == 'tm' {
p.cgen.lines[p.cgen.lines.len-1] = ''
p.cgen.lines[p.cgen.lines.len-2] = ''
}
p.check(LCBR)
// tmp := p.get_tmp()
if !ptr {
if p.is_c_struct_init {
p.gen('(struct $typ){')
p.gen('(struct $typ) {')
p.is_c_struct_init = false
}
else {
p.gen('($typ){')
p.gen('($typ) {')
}
}
else {
@ -2370,12 +2369,6 @@ fn (p mut Parser) struct_init(is_c_struct_init bool) string {
p.check(RCBR)
return typ
}
mut type_gen := typ.replace('*', '')
// All V types are typedef'ed, C structs aren't, so we need to prepend "struct "
if is_c_struct_init {
type_gen = 'struct $type_gen'
}
// p.gen('malloc(sizeof($type_gen)); \n')
no_star := typ.replace('*', '')
p.gen('ALLOC_INIT($no_star, {')
}
@ -2463,7 +2456,6 @@ fn (p mut Parser) struct_init(is_c_struct_init bool) string {
}
p.check(RCBR)
p.is_struct_init = false
// println('struct init typ=$typ')
return typ
}
@ -2668,13 +2660,15 @@ fn (p mut Parser) chash() {
}
}
else {
if !p.can_chash {
p.error('bad token `#` (embedding C code is no longer supported)')
}
//println('HASH!!! $p.file_name $p.scanner.line_nr')
if p.cur_fn.name == '' {
// p.error('# outside of fn')
}
p.genln(hash)
}
// p.cgen.nogen = false
// println('HASH=$hash')
}
fn is_c_pre(hash string) bool {
@ -3134,6 +3128,14 @@ fn is_compile_time_const(s string) bool {
return true
}
fn (p &Parser) building_v() bool {
cur_dir := os.getwd()
return p.file_path.contains('v/compiler') || cur_dir.contains('v/compiler')
}
///////////////////////////////////////////////////////////////////////////////
// fmt helpers
fn (scanner mut Scanner) fgen(s string) {
/*
@ -3167,3 +3169,4 @@ fn (p mut Parser) fgenln(s string) {
//p.scanner.fgenln(s)
}

View File

@ -644,7 +644,7 @@ fn (table &Table) cgen_name_type_pair(name, typ string) string {
}
// TODO tm hack, do this for all C struct args
else if typ == 'tm' {
return 'struct tm $name'
return 'struct /*TM*/ tm $name'
}
return '$typ $name'
}

View File

@ -73,7 +73,7 @@ fn main() {
}
field = new_field
print_field(field)
time.sleep(time.milliseconds(100))
time.sleep_ms(100)
}
}

View File

@ -53,6 +53,6 @@ fn main() {
go fetcher.fetch()
}
println(fetcher.ids)
time.sleep(time.seconds(5))
time.sleep(5)
}

View File

@ -17,7 +17,7 @@ const (
TetroSize = 4
WinWidth = BlockSize * FieldWidth
WinHeight = BlockSize * FieldHeight
TimerPeriod = time.milliseconds(250) // 250ms
TimerPeriod = 250 // ms
)
const (
@ -168,7 +168,7 @@ fn (g mut Game) run() {
g.move_tetro()
g.delete_completed_lines()
glfw.post_empty_event() // force window redraw
time.sleep(TimerPeriod)
time.sleep_ms(TimerPeriod)
}
}

21
os/os.v
View File

@ -26,17 +26,30 @@ import const (
SEEK_END
SA_SIGINFO
SIGSEGV
S_IFMT
S_IFDIR
)
struct C.stat {
st_size int
st_mode int
}
struct C.DIR {
}
struct C.dirent {
d_name byteptr
}
struct C.sigaction {
mut:
sa_mask int
sa_sigaction int
sa_flags int
mut:
sa_mask int
sa_sigaction int
sa_flags int
}
fn C.getline(voidptr, voidptr, voidptr) int

View File

@ -13,15 +13,14 @@ module os
fn log(s string) {
}
fn is_dir(path string) bool {
# struct stat statbuf;
pub fn is_dir(path string) bool {
statbuf := C.stat{}
cstr := path.cstr()
# if (stat(cstr, &statbuf) != 0)
{
if C.stat(cstr, &statbuf) != 0 {
return false
}
# return S_ISDIR(statbuf.st_mode);
return false
return statbuf.st_mode & S_IFMT == S_IFDIR
}
fn chdir(path string) {
@ -29,35 +28,33 @@ fn chdir(path string) {
}
pub fn getwd() string {
cwd := malloc(1024)
# if (getcwd(cwd, 1024)) return tos2(cwd);
return ''
cwd := malloc(512)
if C.getcwd(cwd, 512) == 0 {
return ''
}
return string(cwd)
}
pub fn ls(path string) []string {
mut res := []string
# DIR *dir;
# struct dirent *ent;
# if ((dir = opendir (path.str)) == NULL)
{
dir := C.opendir(path.str)
if isnil(dir) {
println('ls() couldnt open dir "$path"')
print_c_errno()
return res
}
// print all the files and directories within directory */
# while ((ent = readdir (dir)) != NULL) {
name := ''
# name = tos_clone(ent->d_name);//, strlen(ent->d_name));
// # printf ("printf ls() %s\n", ent->d_name);
// println(name)
if name != '.' && name != '..' && name != '' {
res << name
mut ent := &C.dirent{!}
for {
ent = C.readdir(dir)
if isnil(ent) {
break
}
name := tos_clone(ent.d_name)
if name != '.' && name != '..' && name != '' {
res << name
}
}
# }
# closedir (dir);
// res.sort()
// println('sorted res')
// print_strings(res)
C.closedir(dir)
return res
}

View File

@ -4,19 +4,15 @@
module rand
#include <time.h>
import time
pub fn seed() {
# time_t t;
# srand((unsigned) time(&t));
C.srand(time.now().uni)
}
pub fn next(max int) int {
r := 0
# r = rand(); // TODO parser bug `rand` module name conflict
return r % max
return C.rand() % max
}
struct C.time_t{}
fn C.rand() int

View File

@ -1,17 +0,0 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module time
struct Info {
pub:
year int
month int
day int
hour int
minute int
second int
yday int
wday int
}

View File

@ -4,104 +4,277 @@
module time
import rand
#include <time.h>
struct Time {
sec i64
nsec i32
mono i64
pub:
year int
month int
day int
hour int
minute int
second int
uni int // TODO it's safe to use "unix" now
}
fn (a Time) + (b Time) Time {
sec := a.sec + b.sec
nsec := a.nsec + b.nsec
return Time{
sec: sec + i64(nsec)/i64(1000000000)
nsec: nsec % i32(1000000000)
fn C.localtime(int) *C.tm
fn remove_me_when_c_bug_is_fixed() { // TODO
}
struct C.tm {
tm_year int
tm_mon int
tm_mday int
tm_hour int
tm_min int
tm_sec int
}
pub fn now() Time {
t := C.time(0)
mut now := &C.tm{!}
now = C.localtime(&t)
return convert_ctime(now)
}
pub fn random() Time {
return Time {
year: rand.next(2) + 201
month: rand.next(12) + 1
day: rand.next(30) + 1
hour: rand.next(24)
minute: rand.next(60)
second: rand.next(60)
}
}
fn (a Time) - (b Time) Time {
sec := a.sec - b.sec - i64(1)
nsec := a.nsec - b.nsec + i32(1000000000)
t := Time{
sec: sec + i64(nsec)/i64(1000000000)
nsec: nsec % i32(1000000000)
}
if a.mono <= i64(0) || b.mono <= i64(0) {
return t
}
mono := a.mono - b.mono
if mono > i64(0) && t.sec >= i64(0) && t.nsec >= i32(0) {
return t
}
if mono < i64(0) && t.sec <= i64(0) && t.nsec <= i32(0) {
return t
}
if mono == i64(0) {
return Time{}
}
return Time{
sec: mono / i64(1000000000)
nsec: i32(mono%i64(1000000000))
}
pub fn unix(u int) Time {
mut t := &C.tm{!}
t = C.localtime(&u)
return convert_ctime(t)
}
fn (t Time) days() f64 {
return f64(t.sec)/86400.0
}
fn (t Time) hours() f64 {
return f64(t.sec)/3600.0
}
fn (t Time) minutes() f64 {
return f64(t.sec)/60.0
}
fn (t Time) seconds() f64 {
return f64(t.sec) + f64(t.nsec)/1000000000.0
}
fn (t Time) milliseconds() f64 {
return 1000.0*f64(t.sec) + f64(t.nsec)/1000000.0
}
fn (t Time) microseconds() f64 {
return 1000000.0*f64(t.sec) + f64(t.nsec)/1000.0
}
fn (t Time) nanoseconds() f64 {
return 1000000000.0*f64(t.sec) + f64(t.nsec)
}
fn (t Time) str() string {
if t.sec == i64(0) {
if t.nsec == i32(0) {
return '0s'
}
if t.nsec < i32(1000) && t.nsec > i32(-1000) {
return '${t.nsec}ns'
}
if t.nsec < i32(1000000) && t.nsec > i32(-1000000) {
return '${f64(t.nsec)/1000.0:.1f}µs'
}
if t.nsec < i32(1000000000) && t.nsec > i32(-1000000000) {
return '${f64(t.nsec)/1000000.0:.1f}ms'
}
pub fn convert_ctime(t tm) Time {
return Time {
year: t.tm_year + 1900
month: t.tm_mon + 1
day: t.tm_mday
hour: t.tm_hour
minute: t.tm_min
second: t.tm_sec
}
if t.sec < i64(60) && t.sec > i64(-60) {
return '${f64(t.sec)+f64(t.nsec)/1000000000.0:.1f}s'
}
if t.sec < i64(3600) && t.sec > i64(-3600) {
return '${f64(t.sec)/60.0:.1f}m'
}
if t.sec < i64(86400) && t.sec > i64(-86400) {
return '${f64(t.sec)/3600.0:.1f}h'
}
if t.sec < i64(864000) && t.sec > i64(-864000) {
return '${f64(t.sec)/86400.0:.1f}d'
}
return '${f64(t.sec)/86400.0:.0f}d'
// uni = uni;
}
fn (t Time) format_ss() string {
return '${t.year}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}'
}
pub fn (t Time) format() string {
return '${t.year}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}'
}
const (
Months = 'JanFebMarAprMayJunJulAugSepOctNovDec'
Days = 'MonTueWedThuFriSatSun'
)
pub fn (t Time) smonth() string {
i := t.month - 1
return Months.substr(i * 3, (i + 1) * 3)
}
// 21:04
pub fn (t Time) hhmm() string {
return '${t.hour:02d}:${t.minute:02d}'
}
/*
fn (t Time) hhmm_tmp() string {
return '${t.hour:02d}:${t.minute:02d}'
}
*/
// 9:04pm
pub fn (t Time) hhmm12() string {
mut am := 'am'
mut hour = t.hour
if t.hour > 11 {
am = 'pm'
}
if t.hour > 12 {
hour = hour - 12
}
if t.hour == 0 {
hour = 12
}
return '$hour:${t.minute:02d} $am'
}
// 21:04:03
fn (t Time) hhmmss() string {
return '${t.hour:02d}:${t.minute:02d}:${t.second:02d}'
}
// 2012-01-05
fn (t Time) ymmdd() string {
return '${t.year}-${t.month:02d}-${t.day:02d}'
}
// Jul 3
fn (t Time) md() string {
// jl := t.smonth()
s := '${t.smonth()} $t.day'
return s
}
pub fn (t Time) clean() string {
nowe := time.now()
// if amtime {
// hm = t.Format("3:04 pm")
// }
// Today
if t.month == nowe.month && t.year == nowe.year && t.day == nowe.day {
return t.hhmm()
}
// This week
// if time.Since(t) < 24*7*time.Hour {
// return t.Weekday().String()[:3] + " " + hm
// }
// This year
if t.year == nowe.year {
return '${t.smonth()} ${t.day} ${t.hhmm()}'
}
return t.format()
// return fmt.Sprintf("%4d/%02d/%02d", t.Year(), t.Month(), t.Day()) + " " + hm
}
fn (t Time) clean12() string {
nowe := time.now()
// if amtime {
// hm = t.Format("3:04 pm")
// }
// Today
if t.month == nowe.month && t.year == nowe.year && t.day == nowe.day {
return t.hhmm12()
}
// This week
// if time.Since(t) < 24*7*time.Hour {
// return t.Weekday().String()[:3] + " " + hm
// }
// This year
if t.year == nowe.year {
return '${t.smonth()} ${t.day} ${t.hhmm12()}'
}
return t.format()
// return fmt.Sprintf("%4d/%02d/%02d", t.Year(), t.Month(), t.Day()) + " " + hm
}
/*
// in ms
fn ticks() double {
return 0
}
*/
// `parse` parses time in the following format: "2018-01-27 12:48:34"
pub fn parse(s string) Time {
// println('parse="$s"')
pos := s.index(' ')
if pos <= 0 {
println('bad time format')
return now()
}
symd := s.left(pos)
ymd := symd.split('-')
if ymd.len != 3 {
println('bad time format')
return now()
}
shms := s.right(pos)
hms := shms.split(':')
hour := hms[0]
minute := hms[1]
second := hms[2]
// //////////
return new_time(Time {
year: ymd[0].int()
month: ymd[1].int()
day: ymd[2].int()
hour: hour.int()
minute: minute.int()
second: second.int()
})
}
fn new_time(t Time) Time {
return{t | uni: t.calc_unix()}
}
fn (t &Time) calc_unix() int {
if t.uni != 0 {
return t.uni
}
tt := C.tm{
tm_sec : t.second
tm_min : t.minute
tm_hour : t.hour
tm_mday : t.day
tm_mon : t.month-1
tm_year : t.year - 1900
}
return C.mktime(&tt)
}
// TODO add(d time.Duration)
pub fn (t Time) add_seconds(seconds int) Time {
return unix(t.uni + seconds)
}
// TODO use time.Duration instead of seconds
fn since(t Time) int {
return 0
}
pub fn (t Time) relative() string {
now := time.now()
secs := now.uni - t.uni
if secs <= 30 {
// right now or in the future
// TODO handle time in the future
return 'now'
}
if secs < 60 {
return '1m'
}
if secs < 3600 {
return '${secs/60}m'
}
if secs < 3600 * 24 {
return '${secs/3600}h'
}
if secs < 3600 * 24 * 5 {
return '${secs/3600/24}d'
}
if secs > 3600 * 24 * 10000 {
return ''
}
return t.md()
}
fn day_of_week(y, m, d int) int {
// TODO please no
//# return (d += m < 3 ? y-- : y - 2, 23*m/9 + d + 4 + y/4- y/100 + y/400)%7;
return 0
}
pub fn (t Time) day_of_week() int {
return day_of_week(t.year, t.month, t.day)
}
// weekday_str() returns the current day in string (upto 3 characters)
pub fn (t Time) weekday_str() string {
i := t.day_of_week() - 1
return Days.substr(i * 3, (i + 1) * 3)
}

View File

@ -4,84 +4,16 @@
module time
pub fn now() Time {
# struct timespec t = {0, 0};
# struct timespec m = {0, 0};
# clock_gettime(CLOCK_REALTIME, &t);
# clock_gettime(CLOCK_MONOTONIC_RAW, &m);
res := Time{}
# res.sec = t.tv_sec;
# res.nsec = t.tv_nsec;
# res.mono = 1000000000*m.tv_sec + m.tv_nsec;
return res
// in ms
pub fn ticks() f64 {
return f64(0)
}
pub fn sleep(t Time) {
if t.sec > i64(0) {
C.sleep(t.sec)
}
if t.nsec > i32(0) {
C.usleep((t.nsec+i32(999))/i32(1000))
}
pub fn sleep(seconds int) {
C.sleep(seconds)
}
fn (t Time) local() Info {
info := Info{}
# struct tm tm;
# localtime_r(&t.sec, &tm);
# info.year = tm.tm_year + 1900;
# info.month = tm.tm_mon + 1;
# info.day = tm.tm_mday;
# info.hour = tm.tm_hour;
# info.minute = tm.tm_min;
# info.second = tm.tm_sec;
# info.yday = tm.tm_yday;
# info.wday = tm.tm_wday;
return info
pub fn sleep_ms(seconds int) {
C.usleep(seconds * 1000)
}
fn (t Time) utc() Info {
info := Info{}
# struct tm tm;
# gmtime_r(&t.sec, &tm);
# info.year = tm.tm_year + 1900;
# info.month = tm.tm_mon + 1;
# info.day = tm.tm_mday;
# info.hour = tm.tm_hour;
# info.minute = tm.tm_min;
# info.second = tm.tm_sec;
# info.yday = tm.tm_yday;
# info.wday = tm.tm_wday;
return info
}
fn (t Time) format(fmt string) string {
res := ''
cfmt := fmt.cstr()
# char buf[1024];
# struct tm tm;
# localtime_r(&t.sec, &tm);
# strftime(buf, 1024, cfmt, &tm);
# res = tos2(buf);
return res
}
pub fn parse(s, fmt string) ?Time {
t := Time{}
cs := s.cstr()
cfmt := fmt.cstr()
ok := 0
# struct tm tm;
# memset(&tm, 0, sizeof(struct tm));
# ok = strptime(cs, cfmt, &tm);
if ok == 0 {
return error('time.parse: invalid time string')
}
# t.sec = mktime(&tm);
if t.sec < i64(0) {
return error('time.parse: invalid time string')
}
return t
}

View File

@ -4,66 +4,30 @@
module time
// TODO: nanosecond and monotonic
pub fn now() Time {
# time_t t = time(0);
//#flag -framework CoreServices
//#include <CoreServices/CoreServices.h>
//#include <mach/mach_time.h>
res := Time{}
# res.sec = t;
return res
// in ms
pub fn ticks() f64 {
panic('not implemented')
/*
t := i64(C.mach_absolute_time())
# Nanoseconds elapsedNano = AbsoluteToNanoseconds( *(AbsoluteTime *) &t );
# return (double)(* (uint64_t *) &elapsedNano) / 1000000;
*/
return f64(0)
}
pub fn sleep(t Time) {
if t.sec > i64(0) {
C.sleep(t.sec)
}
if t.nsec > i32(0) {
C.usleep((t.nsec+i32(999))/i32(1000))
}
pub fn sleep(seconds int) {
C.sleep(seconds)
}
// TODO: Thread safety
fn (t Time) local() Info {
info := Info{}
# struct tm *tm = localtime(&t.sec);
# info.year = tm->tm_year + 1900;
# info.month = tm->tm_mon + 1;
# info.day = tm->tm_mday;
# info.hour = tm->tm_hour;
# info.minute = tm->tm_min;
# info.second = tm->tm_sec;
# info.yday = tm->tm_yday;
# info.wday = tm->tm_wday;
return info
pub fn usleep(seconds int) {
C.usleep(seconds)
}
// TODO: Thread safety
fn (t Time) utc() Info {
info := Info{}
# struct tm *tm = gmtime(&t.sec);
# info.year = tm->tm_year + 1900;
# info.month = tm->tm_mon + 1;
# info.day = tm->tm_mday;
# info.hour = tm->tm_hour;
# info.minute = tm->tm_min;
# info.second = tm->tm_sec;
# info.yday = tm->tm_yday;
# info.wday = tm->tm_wday;
return info
pub fn sleep_ms(seconds int) {
C.usleep(seconds * 1000)
}
// TODO: Thread safety
fn (t Time) format(fmt string) string {
res := ''
cfmt := fmt.cstr()
# char buf[1024];
# struct tm *tm = localtime(&t.sec);
# strftime(buf, 1024, cfmt, tm);
# res = tos2(buf);
return res
}
// TODO: Not implemented yet
pub fn parse(s string) ?Time {
return Time{}
}

View File

@ -4,63 +4,21 @@
module time
// TODO: nanosecond and monotonic
pub fn now() Time {
# time_t t = time(0);
res := Time{}
# res.sec = t;
return res
// in ms
fn ticks() double {
return C.GetTickCount()
}
pub fn sleep(t Time) {
if t.sec > i64(0) || t.nsec > i32(0) {
C.Sleep(i64(1000)*t.sec+(i64(t.nsec)+i64(999999))/i64(1000000))
}
fn sleep(seconds int) {
C._sleep(seconds * 1000)
}
// TODO: Thread safety
fn (t Time) local() Info {
info := Info{}
# struct tm *tm = localtime(&t.sec);
# info.year = tm->tm_year + 1900;
# info.month = tm->tm_mon + 1;
# info.day = tm->tm_mday;
# info.hour = tm->tm_hour;
# info.minute = tm->tm_min;
# info.second = tm->tm_sec;
# info.yday = tm->tm_yday;
# info.wday = tm->tm_wday;
return info
fn usleep(seconds int) {
panic('usleep not impl')
// C._usleep(seconds)
}
// TODO: Thread safety
fn (t Time) utc() Info {
info := Info{}
# struct tm *tm = gmtime(&t.sec);
# info.year = tm->tm_year + 1900;
# info.month = tm->tm_mon + 1;
# info.day = tm->tm_mday;
# info.hour = tm->tm_hour;
# info.minute = tm->tm_min;
# info.second = tm->tm_sec;
# info.yday = tm->tm_yday;
# info.wday = tm->tm_wday;
return info
fn sleep_ms(n int) {
C.Sleep(n)
}
// TODO: Thread safety
fn (t Time) format(fmt string) string {
res := ''
cfmt := fmt.cstr()
# char buf[1024];
# struct tm *tm = localtime(&t.sec);
# strftime(buf, 1024, cfmt, tm);
# res = tos2(buf);
return res
}
// TODO: Not implemented yet
pub fn parse(s string) ?Time {
return Time{}
}

View File

@ -1,66 +0,0 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module time
pub fn make(i Info) ?Time {
t := Time{}
# struct tm tm;
# tm.tm_year = i.year - 1900;
# tm.tm_mon = i.month - 1;
# tm.tm_mday = i.day;
# tm.tm_hour = i.hour;
# tm.tm_min = i.minute;
# tm.tm_sec = i.second;
# tm.tm_yday = i.yday;
# tm.tm_wday = i.wday;
# tm.tm_isdst = 0;
# t.sec = mktime(&tm);
if t.sec < i64(0) {
return error('time.make: invalid time infomation')
}
return t
}
pub fn days(n int) Time {
return Time{
sec: 86400*n
}
}
pub fn hours(n int) Time {
return Time{
sec: 3600*n
}
}
pub fn minutes(n int) Time {
return Time{
sec: 60*n
}
}
pub fn seconds(n int) Time {
return Time{
sec: n
}
}
pub fn milliseconds(n int) Time {
return Time{
nsec: 1000000*n
}
}
pub fn microseconds(n int) Time {
return Time{
nsec: 1000*n
}
}
pub fn nanoseconds(n int) Time {
return Time{
nsec: n
}
}