From 1ea6ae9fd90ff0067e47a3e1190cbe112c9e5700 Mon Sep 17 00:00:00 2001 From: notoria Date: Sat, 18 Apr 2020 11:49:28 +0200 Subject: [PATCH 01/13] Added predicate for reading a single character --- src/prolog/clause_types.rs | 3 +++ src/prolog/lib/builtins.pl | 11 +++++++++-- src/prolog/machine/system_calls.rs | 25 +++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 7100855e..37c8f612 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -178,6 +178,7 @@ pub enum SystemClauseType { FetchGlobalVar, FetchGlobalVarWithOffset, GetChar, + GetSingleChar, ResetAttrVarState, TruncateIfNoLiftedHeapGrowthDiff, TruncateIfNoLiftedHeapGrowth, @@ -309,6 +310,7 @@ impl SystemClauseType { clause_name!("$fetch_global_var_with_offset") } &SystemClauseType::GetChar => clause_name!("$get_char"), + &SystemClauseType::GetSingleChar => clause_name!("$get_single_char"), &SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"), &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { clause_name!("$truncate_if_no_lh_growth") @@ -455,6 +457,7 @@ impl SystemClauseType { ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset), ("$get_char", 1) => Some(SystemClauseType::GetChar), + ("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar), ("$points_to_cont_reset_marker", 1) => { Some(SystemClauseType::PointsToContinuationResetMarker) } diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index 17235d3b..15c81403 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -47,8 +47,8 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :- current_input/1, current_output/1, current_op/3, current_predicate/1, current_prolog_flag/2, expand_goal/2, expand_term/2, fail/0, false/0, - findall/3, findall/4, get_char/1, halt/0, - max_arity/1, number_chars/2, number_codes/2, + findall/3, findall/4, get_char/1, get_single_char/1, + halt/0, max_arity/1, number_chars/2, number_codes/2, once/1, op/3, read_term/2, repeat/0, retract/1, set_prolog_flag/2, set_input/1, set_output/1, setof/3, sub_atom/5, subsumes_term/2, @@ -933,6 +933,13 @@ get_char(C) :- ; throw(error(type_error(in_character, C), get_char/1)) ). +get_single_char(C) :- + ( var(C) -> '$get_single_char'(C) + ; C == end_of_file -> '$get_single_char'(C) + ; atom_length(C, 1) -> '$get_single_char'(C) + ; throw(error(type_error(in_character, C), get_char/1)) + ). + can_be_number(N, PI) :- ( var(N) -> true ; must_be_number(N, PI) diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index cd9cc86f..bd35d6e6 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -67,6 +67,24 @@ pub fn next_keypress() -> ContinueResult { } } +pub fn get_single_char() -> char { + let c; + enable_raw_mode().expect("failed to enable raw mode"); + loop { + if let Ok(Event::Key(KeyEvent { code, .. })) = read() { + match code { + KeyCode::Char(ch) => { + c = ch; + break; + }, + _ => () + } + } + } + disable_raw_mode().expect("failed to disable raw mode"); + c +} + struct BrentAlgState { hare: Addr, tortoise: Addr, @@ -1463,6 +1481,13 @@ impl MachineState { } } } + &SystemClauseType::GetSingleChar => { + let c = get_single_char(); + + let a1 = self[temp_v!(1)]; + + self.unify(Addr::Char(c), a1); + } &SystemClauseType::GetModuleClause => { let module = self[temp_v!(3)]; let head = self[temp_v!(1)]; From 11ea92288d50a3f0a2fb3a90077abf559b1f5783 Mon Sep 17 00:00:00 2001 From: notoria Date: Sat, 18 Apr 2020 12:52:49 +0200 Subject: [PATCH 02/13] Moved get_single_char from builtins.pl to charsio.pl --- src/prolog/lib/builtins.pl | 11 ++--------- src/prolog/lib/charsio.pl | 11 ++++++++++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index 15c81403..17235d3b 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -47,8 +47,8 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :- current_input/1, current_output/1, current_op/3, current_predicate/1, current_prolog_flag/2, expand_goal/2, expand_term/2, fail/0, false/0, - findall/3, findall/4, get_char/1, get_single_char/1, - halt/0, max_arity/1, number_chars/2, number_codes/2, + findall/3, findall/4, get_char/1, halt/0, + max_arity/1, number_chars/2, number_codes/2, once/1, op/3, read_term/2, repeat/0, retract/1, set_prolog_flag/2, set_input/1, set_output/1, setof/3, sub_atom/5, subsumes_term/2, @@ -933,13 +933,6 @@ get_char(C) :- ; throw(error(type_error(in_character, C), get_char/1)) ). -get_single_char(C) :- - ( var(C) -> '$get_single_char'(C) - ; C == end_of_file -> '$get_single_char'(C) - ; atom_length(C, 1) -> '$get_single_char'(C) - ; throw(error(type_error(in_character, C), get_char/1)) - ). - can_be_number(N, PI) :- ( var(N) -> true ; must_be_number(N, PI) diff --git a/src/prolog/lib/charsio.pl b/src/prolog/lib/charsio.pl index 9cf5f325..5fde900c 100644 --- a/src/prolog/lib/charsio.pl +++ b/src/prolog/lib/charsio.pl @@ -1,4 +1,5 @@ -:- module(charsio, [read_term_from_chars/2, +:- module(charsio, [get_single_char/1, + read_term_from_chars/2, write_term_to_chars/3]). :- use_module(library(iso_ext)). @@ -56,6 +57,14 @@ extend_var_list_([V|Vs], N, VarList, NewVarList, VarType) :- ). +get_single_char(C) :- + ( var(C) -> '$get_single_char'(C) + ; C == end_of_file -> '$get_single_char'(C) + ; atom_length(C, 1) -> '$get_single_char'(C) + ; throw(error(type_error(in_character, C), get_char/1)) + ). + + read_term_from_chars(Chars, Term) :- ( var(Chars) -> throw(error(instantiation_error, read_term_from_chars/2)) From 5d064b18e61b4b7a6c2aa61b84fa8110c4429d76 Mon Sep 17 00:00:00 2001 From: notoria Date: Sat, 18 Apr 2020 13:30:52 +0200 Subject: [PATCH 03/13] get_single_char reads Enter as \n --- src/prolog/machine/system_calls.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index bd35d6e6..1b2f48f0 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -77,6 +77,10 @@ pub fn get_single_char() -> char { c = ch; break; }, + KeyCode::Enter => { + c = '\n'; + break; + }, _ => () } } From b35b49f7b3636a786d0f996f4189a36ab6883a3e Mon Sep 17 00:00:00 2001 From: notoria Date: Sat, 18 Apr 2020 13:33:42 +0200 Subject: [PATCH 04/13] get_single_char reads Tab as \t --- src/prolog/machine/system_calls.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 1b2f48f0..1a783ac9 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -81,6 +81,10 @@ pub fn get_single_char() -> char { c = '\n'; break; }, + KeyCode::Tab => { + c = '\t'; + break; + }, _ => () } } From 99e1a5f11749a519a2ecde8cc9d1ffe9bea925ad Mon Sep 17 00:00:00 2001 From: notoria Date: Sat, 18 Apr 2020 13:54:18 +0200 Subject: [PATCH 05/13] Removed $raw_input_read_char --- src/prolog/clause_types.rs | 3 -- src/prolog/machine/system_calls.rs | 56 ------------------------------ src/prolog/toplevel.pl | 5 +-- 3 files changed, 3 insertions(+), 61 deletions(-) diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 37c8f612..660de341 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -242,7 +242,6 @@ pub enum SystemClauseType { InstallNewBlock, Maybe, QuotedToken, - RawInputReadChar, ReadTermFromChars, ResetBlock, ReturnFromVerifyAttr, @@ -366,7 +365,6 @@ impl SystemClauseType { &SystemClauseType::QuotedToken => { clause_name!("$quoted_token") } - &SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"), &SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"), &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"), &SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"), @@ -509,7 +507,6 @@ impl SystemClauseType { ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint), ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), ("$quoted_token", 1) => Some(SystemClauseType::QuotedToken), - ("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar), ("$nextEP", 3) => Some(SystemClauseType::NextEP), ("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm), ("$read_term", 2) => Some(SystemClauseType::ReadTerm), diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 1a783ac9..e2cad96a 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -31,42 +31,6 @@ use std::rc::Rc; use crate::crossterm::event::{read, Event, KeyCode, KeyEvent}; use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode}; -pub enum ContinueResult { - ContinueQuery, - Conclude, - Help, - PrintWithoutMaxDepth, - PrintWithMaxDepth -} - -pub fn next_keypress() -> ContinueResult { - loop { - match read() { - Ok(Event::Key(KeyEvent { code, .. })) => { - match code { - KeyCode::Char('w') => { - return ContinueResult::PrintWithoutMaxDepth; - } - KeyCode::Char('p') => { - return ContinueResult::PrintWithMaxDepth; - } - KeyCode::Char(' ') | KeyCode::Char(';') | KeyCode::Char('n') => { - return ContinueResult::ContinueQuery; - } - KeyCode::Char('.') => { - return ContinueResult::Conclude; - } - KeyCode::Char('h') => { - return ContinueResult::Help; - } - _ => {} - } - } - _ => {} - } - } -} - pub fn get_single_char() -> char { let c; enable_raw_mode().expect("failed to enable raw mode"); @@ -2913,26 +2877,6 @@ impl MachineState { &SystemClauseType::InstallNewBlock => { self.install_new_block(temp_v!(1)); } - &SystemClauseType::RawInputReadChar => { - let keypress = { - enable_raw_mode().expect("failed to transition into raw mode"); - let result = next_keypress(); - disable_raw_mode().expect("failed to transition out of raw mode"); - - result - }; - - let c = match keypress { - ContinueResult::ContinueQuery => ';', - ContinueResult::Conclude => '.', - ContinueResult::Help => 'h', - ContinueResult::PrintWithoutMaxDepth => 'w', - ContinueResult::PrintWithMaxDepth => 'p', - }; - - let target = self[temp_v!(1)]; - self.unify(Addr::Char(c), target); - } &SystemClauseType::NextEP => { let first_arg = self.store(self.deref(self[temp_v!(1)])); diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 27bf71f5..e7eb3b7a 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -145,7 +145,7 @@ ). '$read_input'(ThreadedGoals, NewVarList) :- - '$raw_input_read_char'(C), + '$get_single_char'(C), ( C == w -> nl, write(' '), @@ -161,8 +161,9 @@ ; C == h -> '$help_message', '$read_input'(ThreadedGoals, NewVarList) - ; C == '.', + ; C == '.' -> nl, write('; ...'), nl + ; '$read_input'(ThreadedGoals, NewVarList) ). '$help_message' :- From 105e9c8e8887dbbb281454cabca323cb07dbe1b1 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sat, 18 Apr 2020 14:33:11 +0200 Subject: [PATCH 06/13] use get_single_char/1 --- src/prolog/toplevel.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index e7eb3b7a..dc58c386 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -145,7 +145,7 @@ ). '$read_input'(ThreadedGoals, NewVarList) :- - '$get_single_char'(C), + get_single_char(C), ( C == w -> nl, write(' '), From 1f7e18f2a9e9893d5a5f2199e1571cbcce80fc82 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sat, 18 Apr 2020 14:38:03 +0200 Subject: [PATCH 07/13] instead of a type error, use a domain error The preceding use of atom_length/2 already ensures that C has the correct type (i.e., atom). However, its domain may still be wrong, if its length is greater than 1. --- src/prolog/lib/charsio.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prolog/lib/charsio.pl b/src/prolog/lib/charsio.pl index 5fde900c..29a668fd 100644 --- a/src/prolog/lib/charsio.pl +++ b/src/prolog/lib/charsio.pl @@ -61,7 +61,7 @@ get_single_char(C) :- ( var(C) -> '$get_single_char'(C) ; C == end_of_file -> '$get_single_char'(C) ; atom_length(C, 1) -> '$get_single_char'(C) - ; throw(error(type_error(in_character, C), get_char/1)) + ; throw(error(domain_error(in_character, C), get_char/1)) ). From 98a37905b8fb4e267dd8038076e89920a6a07156 Mon Sep 17 00:00:00 2001 From: notoria Date: Sat, 18 Apr 2020 15:21:19 +0200 Subject: [PATCH 08/13] Fixed the predicate name when error is thrown --- src/prolog/lib/charsio.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prolog/lib/charsio.pl b/src/prolog/lib/charsio.pl index 29a668fd..11dc04b7 100644 --- a/src/prolog/lib/charsio.pl +++ b/src/prolog/lib/charsio.pl @@ -61,7 +61,7 @@ get_single_char(C) :- ( var(C) -> '$get_single_char'(C) ; C == end_of_file -> '$get_single_char'(C) ; atom_length(C, 1) -> '$get_single_char'(C) - ; throw(error(domain_error(in_character, C), get_char/1)) + ; throw(error(domain_error(in_character, C), get_single_char/1)) ). From 988366e37f06f599e36f2cc3193e80ebdc088182 Mon Sep 17 00:00:00 2001 From: notoria Date: Sat, 18 Apr 2020 16:57:45 +0200 Subject: [PATCH 09/13] Added Space for continuation --- src/prolog/toplevel.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index dc58c386..f2adba33 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -158,6 +158,8 @@ '$read_input'(ThreadedGoals, NewVarList) ; C == (';') -> nl, write('; '), false + ; C == (' ') -> + nl, write('; '), false ; C == h -> '$help_message', '$read_input'(ThreadedGoals, NewVarList) From 6dcefcfb716680437575ec19bfbe8d0b44d6a0ec Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sat, 18 Apr 2020 17:40:19 +0200 Subject: [PATCH 10/13] small simplifications --- src/prolog/toplevel.pl | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index f2adba33..09131d6d 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -146,24 +146,22 @@ '$read_input'(ThreadedGoals, NewVarList) :- get_single_char(C), - ( C == w -> + ( C = w -> nl, write(' '), '$write_eq'(ThreadedGoals, NewVarList, 0), '$read_input'(ThreadedGoals, NewVarList) - ; C == p -> + ; C = p -> nl, write(' '), '$write_eq'(ThreadedGoals, NewVarList, 20), '$read_input'(ThreadedGoals, NewVarList) - ; C == (';') -> + ; member(C, [';', ' ']) -> nl, write('; '), false - ; C == (' ') -> - nl, write('; '), false - ; C == h -> + ; C = h -> '$help_message', '$read_input'(ThreadedGoals, NewVarList) - ; C == '.' -> + ; C = '.' -> nl, write('; ...'), nl ; '$read_input'(ThreadedGoals, NewVarList) ). From 98a32790cd5991b3c438511178b5c34225e010ba Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sat, 18 Apr 2020 17:47:24 +0200 Subject: [PATCH 11/13] ENHANCED: the toplevel interaction now supports RETURN as a synonym for "." This is made possible due to the recent improvements by @notoria. --- README.md | 4 ++-- src/prolog/toplevel.pl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4fa1bab5..652e7b98 100644 --- a/README.md +++ b/README.md @@ -168,8 +168,8 @@ predicates it defines. For example, with the program shown above: ; What = pure_world. ``` -Press `SPACE` to show further answers, if any exist. Press `.` to -abort the search and return to the toplevel prompt. +Press `SPACE` to show further answers, if any exist. Press `RETURN` or + `.` to abort the search and return to the toplevel prompt. Press `h` to show a help message. To quit Scryer Prolog, use the standard predicate `halt/0`: diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 09131d6d..6cee5ecc 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -161,7 +161,7 @@ ; C = h -> '$help_message', '$read_input'(ThreadedGoals, NewVarList) - ; C = '.' -> + ; member(C, ['\n', .]) -> nl, write('; ...'), nl ; '$read_input'(ThreadedGoals, NewVarList) ). @@ -169,7 +169,7 @@ '$help_message' :- nl, nl, write('SPACE, "n" or ";": next solution, if any\n'), - write('".": stop enumeration\n'), + write('RETURN or ".": stop enumeration\n'), write('"h": display this help message\n'), write('"w": write terms without depth limit\n'), write('"p": print terms with depth limit\n\n'). From 2ae5472872b11110f014670edd548839c2f12da5 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sat, 18 Apr 2020 18:08:08 +0200 Subject: [PATCH 12/13] reintroduce "n" as a synonym for ";" and " " --- src/prolog/toplevel.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 6cee5ecc..aad24573 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -156,7 +156,7 @@ write(' '), '$write_eq'(ThreadedGoals, NewVarList, 20), '$read_input'(ThreadedGoals, NewVarList) - ; member(C, [';', ' ']) -> + ; member(C, [';', ' ', n]) -> nl, write('; '), false ; C = h -> '$help_message', From 2e15ab44ab473e49cb518b030da21ba27b7fed2c Mon Sep 17 00:00:00 2001 From: notoria Date: Sat, 18 Apr 2020 18:28:26 +0200 Subject: [PATCH 13/13] Removed a check in get_single_char --- src/prolog/lib/charsio.pl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/prolog/lib/charsio.pl b/src/prolog/lib/charsio.pl index 11dc04b7..4e3a4a22 100644 --- a/src/prolog/lib/charsio.pl +++ b/src/prolog/lib/charsio.pl @@ -59,7 +59,6 @@ extend_var_list_([V|Vs], N, VarList, NewVarList, VarType) :- get_single_char(C) :- ( var(C) -> '$get_single_char'(C) - ; C == end_of_file -> '$get_single_char'(C) ; atom_length(C, 1) -> '$get_single_char'(C) ; throw(error(domain_error(in_character, C), get_single_char/1)) ).