From 2fc887724bb1b5540f36a7f3efa95216e56a5a46 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Wed, 10 Jun 2020 23:13:14 +0200 Subject: [PATCH] ADDED: format_time//2 for describing strings involving dates and times current_time/1 yields the current system time as an opaque time stamp. --- Cargo.toml | 1 + README.md | 8 ++-- src/prolog/clause_types.rs | 3 ++ src/prolog/lib/time.pl | 67 +++++++++++++++++++++++++++--- src/prolog/machine/system_calls.rs | 18 +++++++- 5 files changed, 88 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5bf5abdc..a7cc588b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,3 +43,4 @@ sha3 = "0.8.2" blake2 = "0.8.1" openssl = { version = "0.10.29", features = ["vendored"] } native-tls = "0.2.4" +chrono = "0.4.11" diff --git a/README.md b/README.md index 2a631129..2762b86f 100644 --- a/README.md +++ b/README.md @@ -400,9 +400,11 @@ The modules that ship with Scryer Prolog are also called * [`arithmetic`](src/prolog/lib/arithmetic.pl) Arithmetic predicates such as `lsb/2`, `msb/2` and `number_to_rational/2`. -* [`time`](src/prolog/lib/time.pl) - `time/1` reports the CPU time of a goal. It is useful - for measuring the performance of your code. +* [`time`](src/prolog/lib/time.pl) Predicates for reasoning about + time, including `time/1` to measure the CPU time of a goal, + `current_time/1` to obtain the current system time, the nonterminal + `format_time//2` to describe strings with dates and times, and + `sleep/1` to slow down a computation. * [`cont`](src/prolog/lib/cont.pl) Provides *delimited continuations* via `reset/3` and `shift/1`. * [`random`](src/prolog/lib/random.pl) diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 1d901068..a6257082 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -261,6 +261,7 @@ pub enum SystemClauseType { InstallNewBlock, Maybe, CpuNow, + CurrentTime, QuotedToken, ReadTermFromChars, ResetBlock, @@ -398,6 +399,7 @@ impl SystemClauseType { &SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"), &SystemClauseType::Maybe => clause_name!("maybe"), &SystemClauseType::CpuNow => clause_name!("$cpu_now"), + &SystemClauseType::CurrentTime => clause_name!("$current_time"), &SystemClauseType::ModuleAssertDynamicPredicateToFront => { clause_name!("$module_asserta") } @@ -589,6 +591,7 @@ impl SystemClauseType { ("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength), ("$maybe", 0) => Some(SystemClauseType::Maybe), ("$cpu_now", 1) => Some(SystemClauseType::CpuNow), + ("$current_time", 1) => Some(SystemClauseType::CurrentTime), ("$module_exists", 1) => Some(SystemClauseType::ModuleExists), ("$module_of", 2) => Some(SystemClauseType::ModuleOf), ("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause), diff --git a/src/prolog/lib/time.pl b/src/prolog/lib/time.pl index ccf45bdf..d6b0ebae 100644 --- a/src/prolog/lib/time.pl +++ b/src/prolog/lib/time.pl @@ -1,19 +1,73 @@ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Written April 2020 by Markus Triska (triska@metalevel.at) + Written 2020 by Markus Triska (triska@metalevel.at) Part of Scryer Prolog. This library provides predicates for reasoning about time. - Reasoning about time stamps would be a useful addition, for example - by obtaining the current time, comparing and formatting it. - '$cpu_now' can be replaced by statistics/2 once that is implemented. + current_time(T) yields the current system time in an opaque form, + called a time stamp. Use format_time//2 to describe strings that + contain attributes of the time stamp. + + The nonterminal format_time//2 describes a list of characters that + are formatted according to a format string. Usage: + + phrase(format_time(FormatString, TimeStamp), Cs) + + TimeStamp represents a moment in time in an opaque form, as for + example obtained by current_time/1. + + FormatString is a list of characters that are interpreted literally, + except for the following specifiers (and possibly more in the future): + + %Y year of the time stamp. Example: 2020. + %m month number (01-12), zero-padded to 2 digits + %d day number (01-31), zero-padded to 2 digits + %H hour number (00-24), zero-padded to 2 digits + %M minute number (00-59), zero-padded to 2 digits + %S second number (00-60), zero-padded to 2 digits + %b abbreviated month name, always 3 letters + %a abbreviated weekday name, always 3 letters + %A full weekday name + %j day of the year (001-366), zero-padded to 3 digits + %% the literal % + + Example: + + ?- current_time(T), phrase(format_time("%d.%m.%Y (%H:%M:%S)", T), Cs). + T = [...], Cs = "11.06.2020 (00:24:32)" + ; false. + + sleep(S) sleeps for S seconds (a floating point number). + + time(Goal) reports the execution time of Goal. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -:- module(time, [max_sleep_time/1, sleep/1, time/1]). +:- module(time, [max_sleep_time/1, sleep/1, time/1, current_time/1, format_time//2]). :- use_module(library(format)). :- use_module(library(iso_ext)). :- use_module(library(error)). +:- use_module(library(dcgs)). +:- use_module(library(lists)). +:- use_module(library(charsio), [read_term_from_chars/2]). + +current_time(T) :- + '$current_time'(T0), + read_term_from_chars(T0, T). + +format_time([], _) --> []. +format_time(['%','%'|Fs], T) --> !, "%", format_time(Fs, T). +format_time(['%',Spec|Fs], T) --> !, + ( { member(Spec=Value, T) } -> + list(Value) + ; { domain_error(time_specifier, Spec, format_time//2) } + ), + format_time(Fs, T). +format_time([F|Fs], T) --> [F], format_time(Fs, T). + +list([]) --> []. +list([L|Ls]) --> [L], list(Ls). max_sleep_time(0xfffffffffffffbff). @@ -26,6 +80,9 @@ sleep(T) :- ; '$sleep'(T) ). + +% '$cpu_now' can be replaced by statistics/2 once that is implemented. + time(Goal) :- '$cpu_now'(T0), setup_call_cleanup(true, diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 887163a0..d4607c59 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -33,8 +33,9 @@ use std::ops::Sub; use std::rc::Rc; use std::num::NonZeroU32; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use cpu_time::ProcessTime; +use chrono::{offset::Local,DateTime}; use crate::crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers}; use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode}; @@ -3137,6 +3138,21 @@ impl MachineState { self.unify(a1, addr); } + &SystemClauseType::CurrentTime => { + let system_time = SystemTime::now(); + let datetime: DateTime = system_time.into(); + + let mut fstr = "[".to_string(); + let specifiers = vec!["d","m","Y","y","H","M","S","b","B","a","A","w","u","U","W","j","D","x","v"]; + for spec in specifiers { + fstr.push_str(&format!("'{}'=\"%{}\", ", spec, spec).to_string()); + } + fstr.push_str("finis]."); + let str = { let s = datetime.format(&fstr).to_string(); + self.heap.put_complete_string(&s) + }; + self.unify(self[temp_v!(1)], str); + } &SystemClauseType::OpDeclaration => { let priority = self[temp_v!(1)]; let specifier = self[temp_v!(2)]; -- 2.54.0