mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 22:03:26 +00:00
Estimated hours taken: 80 Branches: main Improvements for bitmap.m, to make it useable as a general container for binary data. library/bitmap.m: runtime/mercury_bitmap.c: runtime/mercury_bitmap.h: Specialize the representation of bitmaps to an array of unsigned bytes defined as a foreign type. This is better than building on top of array(int) because it: - is better for interfacing with foreign code - has a more sensible machine-independent comparison order (same as array(bool)) - avoids storing the size twice - has more efficient copying, unification, comparison and tabling (although we should probably specialize the handling of array(int) and isomorphic types as well) - uses GC_MALLOC_ATOMIC to avoid problems with bit patterns that look like pointers (although we should do that for array(int) as well) XXX The code for the Java and IL backends is untested. Building the library in grade Java with Sun JDK 1.6 failed (but at least passed error checking), and I don't have access to a copy of MSVS.NET. The foreign code that needs to be tested is trivial. Add fields `bit', `bits' and `byte' to get/set a single bit, multiple bits (from an int) or an 8 bit byte. Add functions for converting bitmaps to hex strings and back, for use by stream.string_writer.write and deconstruct.functor/4. bitmap.intersect was buggy in the case where the input bitmaps had a different size. Given that bitmaps are implemented with a fixed domain (lookups out of range throw an exception), it makes more sense to throw an exception in that case anyway, so all of the set operations do that now. The difference operation actually performed xor. Fix it and add an xor function. library/version_bitmap.m: This hasn't been fully updated to be the same as bitmap.m. The payoff would be much less because foreign code can't really do anything with version_bitmaps. Add a `bit' field. Deprecate the `get/2' function in favour of the `bit' field. Fix the union, difference, intersection and xor functions as for bitmap.m. Fix comparison of version_arrays so that it uses the same method as array.m: compare size then elements in order. The old code found version_arrays to be equal if one was a suffix of the other. library/char.m: Add predicates for converting between hex digits and integers. library/io.m: library/stream.string_writer.m: library/term.m: Read and write bitmaps. runtime/mercury_type_info.h: runtime/mercury_deep_copy_body.h: runtime/mercury_mcpp.h: runtime/mercury_table_type_body.h: runtime/mercury_tabling_macros.h: runtime/mercury_unify_compare_body.h: runtime/mercury_construct.c: runtime/mercury_deconstruct.c: runtime/mercury_term_size.c: runtime/mercury_string.h: library/construct.m: library/deconstruct.m compiler/prog_type.m: compiler/mlds_to_gcc.m: compiler/rtti.m: Add a MR_TypeCtorRep for bitmaps, and handle it in the library and runtinme. library/Mercury.options: Compile bitmap.m with `--no-warn-insts-without-matching-type'. runtime/mercury_type_info.h: Bump MR_RTTI_VERSION. NEWS: Document the changes. tests/hard_coded/Mmakefile: tests/hard_coded/bitmap_test.m: tests/hard_coded/bitmap_simple.m: tests/hard_coded/bitmap_tester.m: tests/hard_coded/bitmap_test.exp: tests/tabling/Mmakefile: tests/tabling/expand_bitmap.m: tests/tabling/expand_bitmap.exp: tests/hard_coded/version_array_test.m: tests/hard_coded/version_array_test.exp: Test cases.
778 lines
30 KiB
Mathematica
778 lines
30 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2006-2007 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: stream.string_writer.m.
|
|
% Authors: trd, fjh, stayl
|
|
%
|
|
% Predicates to write to streams that accept strings.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module stream.string_writer.
|
|
:- interface.
|
|
|
|
:- import_module char.
|
|
:- import_module deconstruct.
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module string.
|
|
:- import_module univ.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred put_int(Stream::in, int::in, State::di, State::uo) is det
|
|
<= stream.writer(Stream, string, State).
|
|
|
|
:- pred put_float(Stream::in, float::in, State::di, State::uo) is det
|
|
<= stream.writer(Stream, string, State).
|
|
|
|
:- pred put_char(Stream::in, char::in, State::di, State::uo) is det
|
|
<= stream.writer(Stream, string, State).
|
|
|
|
% A version of io.format that works for arbitrary string writers.
|
|
%
|
|
:- pred format(Stream::in, string::in, list(string.poly_type)::in,
|
|
State::di, State::uo) is det <= stream.writer(Stream, string, State).
|
|
|
|
:- pred nl(Stream::in, State::di, State::uo) is det
|
|
<= stream.writer(Stream, string, State).
|
|
|
|
% print/3 writes its argument to the standard output stream.
|
|
% print/4 writes its second argument to the output stream specified
|
|
% in its first argument. In all cases, the argument to output can be
|
|
% of any type. It is output in a format that is intended to be human
|
|
% readable.
|
|
%
|
|
% If the argument is just a single string or character, it will be printed
|
|
% out exactly as is (unquoted). If the argument is of type univ, then
|
|
% it will print out the value stored in the univ, but not the type.
|
|
%
|
|
% print/5 is the same as print/4 except that it allows the caller
|
|
% to specify how non-canonical types should be handled. print/3 and
|
|
% print/4 implicitly specify `canonicalize' as the method for handling
|
|
% non-canonical types. This means that for higher-order types, or types
|
|
% with user-defined equality axioms, or types defined using the foreign
|
|
% language interface (i.e. pragma foreign_type), the text output will
|
|
% only describe the type that is being printed, not the value.
|
|
%
|
|
% print_cc/3 is the same as print/3 except that it specifies
|
|
% `include_details_cc' rather than `canonicalize'. This means that it will
|
|
% print the details of non-canonical types. However, it has determinism
|
|
% `cc_multi'.
|
|
%
|
|
% Note that even if `include_details_cc' is specified, some implementations
|
|
% may not be able to print all the details for higher-order types or types
|
|
% defined using the foreign language interface.
|
|
%
|
|
:- pred print(Stream::in, T::in, State::di, State::uo) is det
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
|
|
:- pred print(Stream, deconstruct.noncanon_handling, T, State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode print(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode print(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode print(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode print(in, in, in, di, uo) is cc_multi.
|
|
|
|
:- pred print_cc(Stream::in, T::in, State::di, State::uo) is cc_multi
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
|
|
% write/4 writes its second argument to the output stream specified
|
|
% in its first argument. In all cases, the argument to output may be
|
|
% of any type. The argument is written in a format that is intended to
|
|
% be valid Mercury syntax whenever possible.
|
|
%
|
|
% Strings and characters are always printed out in quotes, using backslash
|
|
% escapes if necessary. For higher-order types, or for types defined
|
|
% using the foreign language interface (pragma foreign_code), the text
|
|
% output will only describe the type that is being printed, not the value,
|
|
% and the result may not be parsable by `read'. For the types
|
|
% containing existential quantifiers, the type `type_desc' and closure
|
|
% types, the result may not be parsable by `read', either. But in all
|
|
% other cases the format used is standard Mercury syntax, and if you append
|
|
% a period and newline (".\n"), then the results can be read in again
|
|
% using `read'.
|
|
%
|
|
% write/5 is the same as write/4 except that it allows the caller
|
|
% to specify how non-canonical types should be handled. write_cc/4
|
|
% is the same as write/4 except that it specifies `include_details_cc'
|
|
% rather than `canonicalize'.
|
|
%
|
|
:- pred write(Stream::in, T::in, State::di, State::uo) is det
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
|
|
:- pred write(Stream, deconstruct.noncanon_handling, T, State, State) is det
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode write(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode write(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode write(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode write(in, in, in, di, uo) is cc_multi.
|
|
|
|
:- pred write_cc(Stream::in, T::in, State::di, State::uo) is cc_multi
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- interface.
|
|
|
|
:- import_module ops.
|
|
|
|
%
|
|
% For use by term_io.m
|
|
%
|
|
|
|
:- pred maybe_write_paren(Stream::in, char::in, ops.priority::in,
|
|
ops.priority::in, State::di, State::uo) is det
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- pragma type_spec(maybe_write_paren/6,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
%
|
|
% For use by browser/browse.m
|
|
%
|
|
|
|
% Predicates for writing out univs.
|
|
|
|
:- pred write_univ(Stream::in, univ::in, State::di, State::uo) is det
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
|
|
:- pred write_univ(Stream, deconstruct.noncanon_handling,
|
|
univ, State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode write_univ(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode write_univ(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode write_univ(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode write_univ(in, in, in, di, uo) is cc_multi.
|
|
|
|
:- pragma type_spec(write/4, (Stream = io.output_stream, State = io.state)).
|
|
:- pragma type_spec(write/5, (Stream = io.output_stream, State = io.state)).
|
|
:- pragma type_spec(write_univ/4,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
:- pragma type_spec(write_univ/5,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
:- pragma type_spec(put_int/4, (Stream = io.output_stream, State = io.state)).
|
|
:- pragma type_spec(put_float/4, (Stream = io.output_stream, State = io.state)).
|
|
:- pragma type_spec(put_char/4, (Stream = io.output_stream, State = io.state)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module array.
|
|
:- import_module bitmap.
|
|
:- import_module int.
|
|
:- import_module require.
|
|
:- import_module rtti_implementation.
|
|
:- import_module term_io.
|
|
:- import_module type_desc.
|
|
|
|
put_int(Stream, Int, !State) :-
|
|
(
|
|
% Handle the common I/O case more efficiently.
|
|
dynamic_cast(!.State, IOState0),
|
|
dynamic_cast(Stream, IOStream)
|
|
->
|
|
io.write_int(IOStream, Int, unsafe_promise_unique(IOState0), IOState),
|
|
( dynamic_cast(IOState, !:State) ->
|
|
!:State = unsafe_promise_unique(!.State)
|
|
;
|
|
error("stream.string_writer.put_int: unexpected type error")
|
|
)
|
|
;
|
|
put(Stream, string.int_to_string(Int), !State)
|
|
).
|
|
|
|
put_float(Stream, Float, !State) :-
|
|
(
|
|
% Handle the common I/O case more efficiently.
|
|
dynamic_cast(!.State, IOState0),
|
|
dynamic_cast(Stream, IOStream)
|
|
->
|
|
io.write_float(IOStream, Float,
|
|
unsafe_promise_unique(IOState0), IOState),
|
|
( dynamic_cast(IOState, !:State) ->
|
|
!:State = unsafe_promise_unique(!.State)
|
|
;
|
|
error("stream.string_writer.put_float: unexpected type error")
|
|
)
|
|
;
|
|
put(Stream, string.float_to_string(Float), !State)
|
|
).
|
|
|
|
put_char(Stream, Char, !State) :-
|
|
(
|
|
% Handle the common I/O case more efficiently.
|
|
dynamic_cast(!.State, IOState0),
|
|
dynamic_cast(Stream, IOStream)
|
|
->
|
|
io.write_char(IOStream, Char,
|
|
unsafe_promise_unique(IOState0), IOState),
|
|
( dynamic_cast(IOState, !:State) ->
|
|
!:State = unsafe_promise_unique(!.State)
|
|
;
|
|
error("stream.string_writer.put_char: unexpected type error")
|
|
)
|
|
;
|
|
put(Stream, string.char_to_string(Char), !State)
|
|
).
|
|
|
|
format(Stream, FormatString, Arguments, !State) :-
|
|
string.format(FormatString, Arguments, String),
|
|
put(Stream, String, !State).
|
|
|
|
nl(Stream, !State) :-
|
|
put(Stream, "\n", !State).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Various different versions of print
|
|
%
|
|
|
|
print(Stream, Term, !State) :-
|
|
print(Stream, canonicalize, Term, !State).
|
|
|
|
print_cc(Stream, Term, !State) :-
|
|
print(Stream, include_details_cc, Term, !State).
|
|
|
|
print(Stream, NonCanon, Term, !State) :-
|
|
% `string', `char' and `univ' are special cases for print
|
|
( dynamic_cast(Term, String : string) ->
|
|
put(Stream, String, !State)
|
|
; dynamic_cast(Term, Char : char) ->
|
|
put(Stream, Char, !State)
|
|
; dynamic_cast(Term, OrigUniv) ->
|
|
write_univ(Stream, OrigUniv, !State)
|
|
;
|
|
print_quoted(Stream, NonCanon, Term, !State)
|
|
).
|
|
|
|
:- pred print_quoted(Stream, deconstruct.noncanon_handling, T, State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode print_quoted(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode print_quoted(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode print_quoted(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode print_quoted(in, in, in, di, uo) is cc_multi.
|
|
|
|
print_quoted(Stream, NonCanon, Term, !State) :-
|
|
write(Stream, NonCanon, Term, !State).
|
|
% When we have runtime type classes membership tests, then instead
|
|
% of write(Term), we will want to do something like
|
|
% ( univ_to_type_class(Univ, Portrayable) ->
|
|
% portray(Stream, Portrayable, !State)
|
|
% ;
|
|
% ... code like write, but which prints the arguments
|
|
% using print_quoted, rather than write ...
|
|
% )
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Various different versions of write
|
|
%
|
|
|
|
write(Stream, X, !State) :-
|
|
write(Stream, canonicalize, X, !State).
|
|
|
|
write_cc(Stream, X, !State) :-
|
|
write(Stream, include_details_cc, X, !State).
|
|
|
|
write(Stream, NonCanon, Term, !State) :-
|
|
type_to_univ(Term, Univ),
|
|
do_write_univ(Stream, NonCanon, Univ, !State).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Various different versions of write_univ
|
|
%
|
|
|
|
write_univ(Stream, Univ, !State) :-
|
|
do_write_univ(Stream, canonicalize, Univ, !State).
|
|
|
|
write_univ(Stream, NonCanon, Univ, !State) :-
|
|
do_write_univ(Stream, NonCanon, Univ, !State).
|
|
|
|
:- pred do_write_univ(Stream, deconstruct.noncanon_handling, univ,
|
|
State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode do_write_univ(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode do_write_univ(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode do_write_univ(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode do_write_univ(in, in, in, di, uo) is cc_multi.
|
|
:- pragma type_spec(do_write_univ/5,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
do_write_univ(Stream, NonCanon, Univ, !State) :-
|
|
do_write_univ_prio(Stream, NonCanon, Univ,
|
|
ops.mercury_max_priority(ops.init_mercury_op_table) + 1, !State).
|
|
|
|
:- pred do_write_univ_prio(Stream, deconstruct.noncanon_handling, univ,
|
|
ops.priority, State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode do_write_univ_prio(in, in(do_not_allow), in, in, di, uo) is det.
|
|
:- mode do_write_univ_prio(in, in(canonicalize), in, in, di, uo) is det.
|
|
:- mode do_write_univ_prio(in, in(include_details_cc), in, in, di, uo)
|
|
is cc_multi.
|
|
:- mode do_write_univ_prio(in, in, in, in, di, uo) is cc_multi.
|
|
:- pragma type_spec(do_write_univ_prio/6,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
% We only use the io.stream_db we read impurely when we have
|
|
% the io.state.
|
|
:- pragma promise_pure(do_write_univ_prio/6).
|
|
|
|
do_write_univ_prio(Stream, NonCanon, Univ, Priority, !State) :-
|
|
% We need to special-case the builtin types:
|
|
% int, char, float, string
|
|
% type_info, univ, c_pointer, array
|
|
% and private_builtin.type_info
|
|
%
|
|
( univ_to_type(Univ, String) ->
|
|
term_io.quote_string(Stream, String, !State)
|
|
; univ_to_type(Univ, Char) ->
|
|
term_io.quote_char(Stream, Char, !State)
|
|
; univ_to_type(Univ, Int) ->
|
|
put_int(Stream, Int, !State)
|
|
; univ_to_type(Univ, Float) ->
|
|
put_float(Stream, Float, !State)
|
|
; univ_to_type(Univ, Bitmap) ->
|
|
% Bitmaps are converted to strings of hex digits.
|
|
put_char(Stream, '"', !State),
|
|
put(Stream, bitmap.to_string(Bitmap), !State),
|
|
put_char(Stream, '"', !State)
|
|
; univ_to_type(Univ, TypeDesc) ->
|
|
write_type_desc(Stream, TypeDesc, !State)
|
|
; univ_to_type(Univ, TypeCtorDesc) ->
|
|
write_type_ctor_desc(Stream, TypeCtorDesc, !State)
|
|
; univ_to_type(Univ, C_Pointer) ->
|
|
write_c_pointer(Stream, C_Pointer, !State)
|
|
;
|
|
impure io.get_stream_db_with_locking(StreamDB),
|
|
StreamInfo = get_io_stream_info(StreamDB, univ_value(Univ))
|
|
->
|
|
type_to_univ(StreamInfo, StreamInfoUniv),
|
|
do_write_univ_prio(Stream, NonCanon, StreamInfoUniv, Priority,
|
|
!.State, !:State)
|
|
;
|
|
% Check if the type is array.array/1. We can't just use univ_to_type
|
|
% here since array.array/1 is a polymorphic type.
|
|
%
|
|
% The calls to type_ctor_name and type_ctor_module_name are not really
|
|
% necessary -- we could use univ_to_type in the condition instead
|
|
% of det_univ_to_type in the body. However, this way of doing things
|
|
% is probably more efficient in the common case when the thing being
|
|
% printed is *not* of type array.array/1.
|
|
%
|
|
% The ordering of the tests here (arity, then name, then module name,
|
|
% rather than the reverse) is also chosen for efficiency, to find
|
|
% failure cheaply in the common cases, rather than for readability.
|
|
%
|
|
type_ctor_and_args(univ_type(Univ), TypeCtor, ArgTypes),
|
|
ArgTypes = [ElemType],
|
|
type_ctor_name(TypeCtor) = "array",
|
|
type_ctor_module_name(TypeCtor) = "array"
|
|
->
|
|
% Now that we know the element type, we can constrain the type
|
|
% of the variable `Array' so that we can use det_univ_to_type.
|
|
|
|
has_type(Elem, ElemType),
|
|
same_array_elem_type(Array, Elem),
|
|
det_univ_to_type(Univ, Array),
|
|
write_array(Stream, Array, !State)
|
|
;
|
|
% Check if the type is private_builtin.type_info/1.
|
|
% See the comments above for array.array/1.
|
|
|
|
type_ctor_and_args(univ_type(Univ), TypeCtor, ArgTypes),
|
|
ArgTypes = [ElemType],
|
|
type_ctor_name(TypeCtor) = "type_info",
|
|
type_ctor_module_name(TypeCtor) = "private_builtin"
|
|
->
|
|
has_type(Elem, ElemType),
|
|
same_private_builtin_type(PrivateBuiltinTypeInfo, Elem),
|
|
det_univ_to_type(Univ, PrivateBuiltinTypeInfo),
|
|
write_private_builtin_type_info(Stream, PrivateBuiltinTypeInfo, !State)
|
|
;
|
|
write_ordinary_term(Stream, NonCanon, Univ, Priority, !State)
|
|
).
|
|
|
|
:- pred same_array_elem_type(array(T)::unused, T::unused) is det.
|
|
|
|
same_array_elem_type(_, _).
|
|
|
|
:- pred same_private_builtin_type(private_builtin.type_info::unused,
|
|
T::unused) is det.
|
|
|
|
same_private_builtin_type(_, _).
|
|
|
|
:- pred write_ordinary_term(Stream, deconstruct.noncanon_handling, univ,
|
|
ops.priority, State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode write_ordinary_term(in, in(do_not_allow), in, in, di, uo) is det.
|
|
:- mode write_ordinary_term(in, in(canonicalize), in, in, di, uo) is det.
|
|
:- mode write_ordinary_term(in, in(include_details_cc), in, in, di, uo)
|
|
is cc_multi.
|
|
:- mode write_ordinary_term(in, in, in, in, di, uo) is cc_multi.
|
|
:- pragma type_spec(write_ordinary_term/6,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
write_ordinary_term(Stream, NonCanon, Univ, Priority, !State) :-
|
|
univ_value(Univ) = Term,
|
|
deconstruct.deconstruct(Term, NonCanon, Functor, _Arity, Args),
|
|
(
|
|
Functor = "[|]",
|
|
Args = [ListHead, ListTail]
|
|
->
|
|
put(Stream, '[', !State),
|
|
write_arg(Stream, NonCanon, ListHead, !State),
|
|
write_list_tail(Stream, NonCanon, ListTail, !State),
|
|
put(Stream, ']', !State)
|
|
;
|
|
Functor = "[]",
|
|
Args = []
|
|
->
|
|
put(Stream, "[]", !State)
|
|
;
|
|
Functor = "{}",
|
|
Args = [BracedHead | BracedTail]
|
|
->
|
|
(
|
|
BracedTail = [],
|
|
put(Stream, "{ ", !State),
|
|
do_write_univ(Stream, NonCanon, BracedHead, !State),
|
|
put(Stream, " }", !State)
|
|
;
|
|
BracedTail = [_ | _],
|
|
put(Stream, '{', !State),
|
|
write_arg(Stream, NonCanon, BracedHead, !State),
|
|
write_term_args(Stream, NonCanon, BracedTail, !State),
|
|
put(Stream, '}', !State)
|
|
)
|
|
;
|
|
ops.lookup_op_infos(ops.init_mercury_op_table, Functor,
|
|
FirstOpInfo, OtherOpInfos)
|
|
->
|
|
select_op_info_and_print(Stream, NonCanon, FirstOpInfo, OtherOpInfos,
|
|
Priority, Functor, Args, !State)
|
|
;
|
|
write_functor_and_args(Stream, NonCanon, Functor, Args, !State)
|
|
).
|
|
|
|
:- pred select_op_info_and_print(Stream, deconstruct.noncanon_handling,
|
|
op_info, list(op_info), ops.priority, string, list(univ), State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode select_op_info_and_print(in, in(do_not_allow), in, in, in, in, in,
|
|
di, uo) is det.
|
|
:- mode select_op_info_and_print(in, in(canonicalize), in, in, in, in, in,
|
|
di, uo) is det.
|
|
:- mode select_op_info_and_print(in, in(include_details_cc), in, in, in, in,
|
|
in, di, uo) is cc_multi.
|
|
:- mode select_op_info_and_print(in, in, in, in, in, in, in,
|
|
di, uo) is cc_multi.
|
|
:- pragma type_spec(select_op_info_and_print/9,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
select_op_info_and_print(Stream, NonCanon, OpInfo, OtherOpInfos, Priority,
|
|
Functor, Args, !State) :-
|
|
OpInfo = op_info(OpClass, _),
|
|
(
|
|
OpClass = prefix(_OpAssoc),
|
|
( Args = [Arg] ->
|
|
OpInfo = op_info(_, OpPriority),
|
|
maybe_write_paren(Stream, '(', Priority, OpPriority, !State),
|
|
term_io.quote_atom(Stream, Functor, !State),
|
|
put(Stream, " ", !State),
|
|
OpClass = prefix(OpAssoc),
|
|
adjust_priority_for_assoc(OpPriority, OpAssoc, NewPriority),
|
|
do_write_univ_prio(Stream, NonCanon, Arg, NewPriority, !State),
|
|
maybe_write_paren(Stream, ')', Priority, OpPriority, !State)
|
|
;
|
|
select_remaining_op_info_and_print(Stream, NonCanon, OtherOpInfos,
|
|
Priority, Functor, Args, !State)
|
|
)
|
|
;
|
|
OpClass = postfix(_OpAssoc),
|
|
( Args = [PostfixArg] ->
|
|
OpInfo = op_info(_, OpPriority),
|
|
maybe_write_paren(Stream, '(', Priority, OpPriority, !State),
|
|
OpClass = postfix(OpAssoc),
|
|
adjust_priority_for_assoc(OpPriority, OpAssoc, NewPriority),
|
|
do_write_univ_prio(Stream, NonCanon, PostfixArg,
|
|
NewPriority, !State),
|
|
put(Stream, " ", !State),
|
|
term_io.quote_atom(Stream, Functor, !State),
|
|
maybe_write_paren(Stream, ')', Priority, OpPriority, !State)
|
|
;
|
|
select_remaining_op_info_and_print(Stream, NonCanon, OtherOpInfos,
|
|
Priority, Functor, Args, !State)
|
|
)
|
|
;
|
|
OpClass = infix(_LeftAssoc, _RightAssoc),
|
|
( Args = [Arg1, Arg2] ->
|
|
OpInfo = op_info(_, OpPriority),
|
|
maybe_write_paren(Stream, '(', Priority, OpPriority, !State),
|
|
OpClass = infix(LeftAssoc, _),
|
|
adjust_priority_for_assoc(OpPriority, LeftAssoc, LeftPriority),
|
|
do_write_univ_prio(Stream, NonCanon, Arg1, LeftPriority, !State),
|
|
( Functor = "," ->
|
|
put(Stream, ", ", !State)
|
|
;
|
|
put(Stream, " ", !State),
|
|
term_io.quote_atom(Stream, Functor, !State),
|
|
put(Stream, " ", !State)
|
|
),
|
|
OpClass = infix(_, RightAssoc),
|
|
adjust_priority_for_assoc(OpPriority, RightAssoc, RightPriority),
|
|
do_write_univ_prio(Stream, NonCanon, Arg2, RightPriority, !State),
|
|
maybe_write_paren(Stream, ')', Priority, OpPriority, !State)
|
|
;
|
|
select_remaining_op_info_and_print(Stream, NonCanon, OtherOpInfos,
|
|
Priority, Functor, Args, !State)
|
|
)
|
|
;
|
|
OpClass = binary_prefix(_FirstAssoc, _SecondAssoc),
|
|
( Args = [Arg1, Arg2] ->
|
|
OpInfo = op_info(_, OpPriority),
|
|
maybe_write_paren(Stream, '(', Priority, OpPriority, !State),
|
|
term_io.quote_atom(Stream, Functor, !State),
|
|
put(Stream, " ", !State),
|
|
OpClass = binary_prefix(FirstAssoc, _),
|
|
adjust_priority_for_assoc(OpPriority, FirstAssoc, FirstPriority),
|
|
do_write_univ_prio(Stream, NonCanon, Arg1, FirstPriority, !State),
|
|
put(Stream, " ", !State),
|
|
OpClass = binary_prefix(_, SecondAssoc),
|
|
adjust_priority_for_assoc(OpPriority, SecondAssoc,
|
|
SecondPriority),
|
|
do_write_univ_prio(Stream, NonCanon, Arg2, SecondPriority, !State),
|
|
maybe_write_paren(Stream, ')', Priority, OpPriority, !State)
|
|
;
|
|
select_remaining_op_info_and_print(Stream, NonCanon, OtherOpInfos,
|
|
Priority, Functor, Args, !State)
|
|
)
|
|
).
|
|
|
|
:- pred select_remaining_op_info_and_print(Stream,
|
|
deconstruct.noncanon_handling, list(op_info), ops.priority, string,
|
|
list(univ), State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode select_remaining_op_info_and_print(in, in(do_not_allow), in, in, in,
|
|
in, di, uo) is det.
|
|
:- mode select_remaining_op_info_and_print(in, in(canonicalize), in, in, in,
|
|
in, di, uo) is det.
|
|
:- mode select_remaining_op_info_and_print(in(include_details_cc), in, in, in,
|
|
in, in, di, uo) is cc_multi.
|
|
:- mode select_remaining_op_info_and_print(in, in, in, in, in, in, di, uo)
|
|
is cc_multi.
|
|
:- pragma type_spec(select_remaining_op_info_and_print/8,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
select_remaining_op_info_and_print(Stream, NonCanon,
|
|
[FirstOpInfo | MoreOpInfos], Priority, Functor, Args, !State) :-
|
|
select_op_info_and_print(Stream, NonCanon, FirstOpInfo, MoreOpInfos,
|
|
Priority, Functor, Args, !State).
|
|
select_remaining_op_info_and_print(Stream, NonCanon, [],
|
|
Priority, Functor, Args, !State) :-
|
|
(
|
|
Args = [],
|
|
Priority =< ops.mercury_max_priority(ops.init_mercury_op_table)
|
|
->
|
|
put(Stream, '(', !State),
|
|
term_io.quote_atom(Stream, Functor, !State),
|
|
put(Stream, ')', !State)
|
|
;
|
|
write_functor_and_args(Stream, NonCanon, Functor, Args, !State)
|
|
).
|
|
|
|
:- pred write_functor_and_args(Stream, deconstruct.noncanon_handling, string,
|
|
list(univ), State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode write_functor_and_args(in, in(do_not_allow), in, in, di, uo) is det.
|
|
:- mode write_functor_and_args(in, in(canonicalize), in, in, di, uo) is det.
|
|
:- mode write_functor_and_args(in, in(include_details_cc), in, in, di, uo)
|
|
is cc_multi.
|
|
:- mode write_functor_and_args(in, in, in, in, di, uo) is cc_multi.
|
|
:- pragma type_spec(write_functor_and_args/6,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
:- pragma inline(write_functor_and_args/6).
|
|
|
|
write_functor_and_args(Stream, NonCanon, Functor, Args, !State) :-
|
|
term_io.quote_atom_agt(Stream, Functor,
|
|
maybe_adjacent_to_graphic_token, !State),
|
|
(
|
|
Args = [X | Xs],
|
|
put(Stream, '(', !State),
|
|
write_arg(Stream, NonCanon, X, !State),
|
|
write_term_args(Stream, NonCanon, Xs, !State),
|
|
put(Stream, ')', !State)
|
|
;
|
|
Args = []
|
|
).
|
|
|
|
:- pragma inline(maybe_write_paren/6).
|
|
|
|
maybe_write_paren(Stream, String, Priority, OpPriority, !State) :-
|
|
( OpPriority > Priority ->
|
|
put(Stream, String, !State)
|
|
;
|
|
true
|
|
).
|
|
|
|
:- pred write_list_tail(Stream, deconstruct.noncanon_handling, univ,
|
|
State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode write_list_tail(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode write_list_tail(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode write_list_tail(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode write_list_tail(in, in, in, di, uo) is cc_multi.
|
|
:- pragma type_spec(write_list_tail/5,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
write_list_tail(Stream, NonCanon, Univ, !State) :-
|
|
Term = univ_value(Univ),
|
|
deconstruct.deconstruct(Term, NonCanon, Functor, _Arity, Args),
|
|
(
|
|
Functor = "[|]",
|
|
Args = [ListHead, ListTail]
|
|
->
|
|
put(Stream, ", ", !State),
|
|
write_arg(Stream, NonCanon, ListHead, !State),
|
|
write_list_tail(Stream, NonCanon, ListTail, !State)
|
|
;
|
|
Functor = "[]",
|
|
Args = []
|
|
->
|
|
true
|
|
;
|
|
put(Stream, " | ", !State),
|
|
do_write_univ(Stream, NonCanon, Univ, !State)
|
|
).
|
|
|
|
% Write the remaining arguments.
|
|
%
|
|
:- pred write_term_args(Stream, deconstruct.noncanon_handling, list(univ),
|
|
State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode write_term_args(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode write_term_args(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode write_term_args(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode write_term_args(in, in, in, di, uo) is cc_multi.
|
|
:- pragma type_spec(write_term_args/5,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
write_term_args(_Stream, _, [], !State).
|
|
write_term_args(Stream, NonCanon, [X | Xs], !State) :-
|
|
put(Stream, ", ", !State),
|
|
write_arg(Stream, NonCanon, X, !State),
|
|
write_term_args(Stream, NonCanon, Xs, !State).
|
|
|
|
:- pred write_arg(Stream, deconstruct.noncanon_handling, univ, State, State)
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- mode write_arg(in, in(do_not_allow), in, di, uo) is det.
|
|
:- mode write_arg(in, in(canonicalize), in, di, uo) is det.
|
|
:- mode write_arg(in, in(include_details_cc), in, di, uo) is cc_multi.
|
|
:- mode write_arg(in, in, in, di, uo) is cc_multi.
|
|
:- pragma type_spec(write_arg/5,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
write_arg(Stream, NonCanon, X, !State) :-
|
|
arg_priority(ArgPriority, !State),
|
|
do_write_univ_prio(Stream, NonCanon, X, ArgPriority, !State).
|
|
|
|
:- pred arg_priority(int::out, State::di, State::uo) is det.
|
|
|
|
% arg_priority(ArgPriority, !State) :-
|
|
% ( ops.lookup_infix_op(ops.init_mercury_op_table, ",", Priority, _, _) ->
|
|
% ArgPriority = Priority
|
|
% ;
|
|
% error("arg_priority: can't find the priority of `,'")
|
|
% ).
|
|
%
|
|
% We could implement this as above, but it's more efficient to just
|
|
% hard-code it.
|
|
arg_priority(1000, !State).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred write_type_desc(Stream::in, type_desc::in, State::di, State::uo) is det
|
|
<= stream.writer(Stream, string, State).
|
|
|
|
write_type_desc(Stream, TypeDesc, !State) :-
|
|
put(Stream, type_name(TypeDesc), !State).
|
|
|
|
:- pred write_type_ctor_desc(Stream::in, type_ctor_desc::in,
|
|
State::di, State::uo) is det <= stream.writer(Stream, string, State).
|
|
|
|
write_type_ctor_desc(Stream, TypeCtorDesc, !State) :-
|
|
type_ctor_name_and_arity(TypeCtorDesc, ModuleName, Name, Arity0),
|
|
(
|
|
ModuleName = "builtin",
|
|
Name = "func"
|
|
->
|
|
% The type ctor that we call `builtin:func/N' takes N + 1
|
|
% type parameters: N arguments plus one return value.
|
|
% So we need to subtract one from the arity here.
|
|
Arity = Arity0 - 1
|
|
;
|
|
Arity = Arity0
|
|
),
|
|
( ModuleName = "builtin" ->
|
|
format(Stream, "%s/%d", [s(Name), i(Arity)], !State)
|
|
;
|
|
format(Stream, "%s.%s/%d", [s(ModuleName), s(Name), i(Arity)], !State)
|
|
).
|
|
|
|
:- pred write_c_pointer(Stream::in, c_pointer::in, State::di, State::uo) is det
|
|
<= stream.writer(Stream, string, State).
|
|
|
|
write_c_pointer(Stream, C_Pointer, !State) :-
|
|
put(Stream, c_pointer_to_string(C_Pointer), !State).
|
|
|
|
:- pred write_array(Stream::in, array(T)::in, State::di, State::uo) is det
|
|
<= (stream.writer(Stream, string, State),
|
|
stream.writer(Stream, char, State)).
|
|
:- pragma type_spec(write_array/4,
|
|
(Stream = io.output_stream, State = io.state)).
|
|
|
|
write_array(Stream, Array, !State) :-
|
|
put(Stream, "array(", !State),
|
|
array.to_list(Array, List),
|
|
write(Stream, List, !State),
|
|
put(Stream, ")", !State).
|
|
|
|
:- pred write_private_builtin_type_info(Stream::in,
|
|
private_builtin.type_info::in, State::di, State::uo) is det
|
|
<= stream.writer(Stream, string, State).
|
|
|
|
write_private_builtin_type_info(Stream, PrivateBuiltinTypeInfo, !State) :-
|
|
TypeInfo = rtti_implementation.unsafe_cast(PrivateBuiltinTypeInfo),
|
|
write_type_desc(Stream, TypeInfo, !State).
|
|
|
|
%-----------------------------------------------------------------------------%
|