This commit is contained in:
Mark Thom
2020-05-22 14:50:51 -06:00
4 changed files with 64 additions and 1 deletions

View File

@@ -353,7 +353,7 @@ The modules that ship with Scryer Prolog are also called
* [`format`](src/prolog/lib/format.pl) * [`format`](src/prolog/lib/format.pl)
The nonterminal `format_//2` is used to describe formatted output, The nonterminal `format_//2` is used to describe formatted output,
arranging arguments according to a given format string. arranging arguments according to a given format string.
The predicates `format/2`, `portray_clause/1` and `listing/1` The predicates `format/[2,3]`, `portray_clause/1` and `listing/1`
provide formatted *impure* output. provide formatted *impure* output.
* [`assoc`](src/prolog/lib/assoc.pl) * [`assoc`](src/prolog/lib/assoc.pl)
providing `empty_assoc/1`, `get_assoc/3`, `put_assoc/4` etc. providing `empty_assoc/1`, `get_assoc/3`, `put_assoc/4` etc.

View File

@@ -229,6 +229,7 @@ pub enum SystemClauseType {
PeekCode, PeekCode,
PointsToContinuationResetMarker, PointsToContinuationResetMarker,
PutByte, PutByte,
PutBytes,
PutChar, PutChar,
PutCode, PutCode,
REPL(REPLCodePtr), REPL(REPLCodePtr),
@@ -415,6 +416,9 @@ impl SystemClauseType {
&SystemClauseType::PutByte => { &SystemClauseType::PutByte => {
clause_name!("$put_byte") clause_name!("$put_byte")
} }
&SystemClauseType::PutBytes => {
clause_name!("$put_bytes")
}
&SystemClauseType::PutChar => { &SystemClauseType::PutChar => {
clause_name!("$put_char") clause_name!("$put_char")
} }
@@ -552,6 +556,9 @@ impl SystemClauseType {
("$put_byte", 2) => { ("$put_byte", 2) => {
Some(SystemClauseType::PutByte) Some(SystemClauseType::PutByte)
} }
("$put_bytes", 2) => {
Some(SystemClauseType::PutBytes)
}
("$put_char", 2) => { ("$put_char", 2) => {
Some(SystemClauseType::PutChar) Some(SystemClauseType::PutChar)
} }

View File

@@ -49,6 +49,10 @@
The predicate format/2 is like format_//2, except that it outputs The predicate format/2 is like format_//2, except that it outputs
the text on the terminal instead of describing it declaratively. the text on the terminal instead of describing it declaratively.
format/3, used as format(Stream, FormatString, Arguments), outputs
the described string to the given Stream. If Stream is a binary
stream, then the code of each emitted character must be in 0..255.
If at all possible, format_//2 should be used, to stress pure parts If at all possible, format_//2 should be used, to stress pure parts
that enable easy testing etc. If necessary, you can emit the list Ls that enable easy testing etc. If necessary, you can emit the list Ls
with maplist(write, Ls). with maplist(write, Ls).
@@ -68,6 +72,7 @@
:- module(format, [format_//2, :- module(format, [format_//2,
format/2, format/2,
format/3,
portray_clause/1, portray_clause/1,
listing/1 listing/1
]). ]).
@@ -359,6 +364,26 @@ format(Fs, Args) :-
phrase(format_(Fs, Args), Cs), phrase(format_(Fs, Args), Cs),
maplist(write, Cs). maplist(write, Cs).
format(Stream, Fs, Args) :-
phrase(format_(Fs, Args), Cs),
( stream_property(Stream, type(binary)) ->
% maplist(char_code, Cs, Bytes) is currently a lot slower
% than first converting Cs to an atom, and then to codes.
% In the future, we can ideally avoid creating an atom here,
% since an atom leaves traces in the system.
atom_chars(A, Cs),
atom_codes(A, Bytes),
( member(NonByte, Bytes), NonByte > 255 ->
char_code(Char, NonByte),
throw(error(representation_error(Char), format/3))
; true
),
% For binary streams, we use a specialised internal predicate
% that uses only a single "write" operation for efficiency.
'$put_bytes'(Stream, Bytes)
; maplist(put_char(Stream), Cs)
).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- phrase(cells("hello", [], 0, []), Cs). ?- phrase(cells("hello", [], 0, []), Cs).

View File

@@ -2153,6 +2153,37 @@ impl MachineState {
} }
} }
} }
&SystemClauseType::PutBytes => {
let mut stream =
self.get_stream_or_alias(self[temp_v!(1)], indices, "$put_bytes", 2)?;
let stub = MachineError::functor_stub(clause_name!("$put_bytes"), 2);
let bytes = self.integers_to_bytevec(temp_v!(2), stub);
match stream.write(&bytes) {
Ok(_) => {
return return_from_clause!(self.last_call, self);
}
_ => {
let stub = MachineError::functor_stub(
clause_name!("$put_bytes"),
2,
);
let addr = self.heap.to_unifiable(
HeapCellValue::Stream(stream.clone()),
);
return Err(self.error_form(
MachineError::existence_error(
self.heap.h(),
ExistenceError::Stream(addr),
),
stub,
));
}
}
}
&SystemClauseType::GetByte => { &SystemClauseType::GetByte => {
let mut stream = let mut stream =
self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?; self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;