From 0288d5dc1950c55535c080a43a3ba04facd4fa2b Mon Sep 17 00:00:00 2001 From: Adrián Arroyo Calle Date: Fri, 31 Dec 2021 12:56:24 +0100 Subject: Add ugraphs library --- README.md | 1 + src/lib/ugraphs.pl | 634 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 635 insertions(+) create mode 100644 src/lib/ugraphs.pl diff --git a/README.md b/README.md index 09878933..2f4a812d 100644 --- a/README.md +++ b/README.md @@ -552,6 +552,7 @@ The modules that ship with Scryer Prolog are also called * [`uuid`](src/lib/uuid.pl) UUIDv4 generation and hex representation * [`tls`](src/lib/tls.pl) Predicates for negotiating TLS connections explicitly. +* [`ugraphs`](src/lib/ugraphs.pl) Graph manipulation library To use predicates provided by the `lists` library, write: diff --git a/src/lib/ugraphs.pl b/src/lib/ugraphs.pl new file mode 100644 index 00000000..257d4e01 --- /dev/null +++ b/src/lib/ugraphs.pl @@ -0,0 +1,634 @@ +/* Part of SWI-Prolog + + Author: R.A.O'Keefe, Vitor Santos Costa, Jan Wielemaker + E-mail: J.Wielemaker@vu.nl + WWW: http://www.swi-prolog.org + Copyright (c) 1984-2021, VU University Amsterdam + CWI, Amsterdam + SWI-Prolog Solutions .b.v + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +:- module(ugraphs, + [ add_edges/3, % +Graph, +Edges, -NewGraph + add_vertices/3, % +Graph, +Vertices, -NewGraph + complement/2, % +Graph, -NewGraph + compose/3, % +LeftGraph, +RightGraph, -NewGraph + del_edges/3, % +Graph, +Edges, -NewGraph + del_vertices/3, % +Graph, +Vertices, -NewGraph + edges/2, % +Graph, -Edges + neighbors/3, % +Vertex, +Graph, -Vertices + neighbours/3, % +Vertex, +Graph, -Vertices + reachable/3, % +Vertex, +Graph, -Vertices + top_sort/2, % +Graph, -Sort + top_sort/3, % +Graph, -Sort0, -Sort + transitive_closure/2, % +Graph, -Closure + transpose_ugraph/2, % +Graph, -NewGraph + vertices/2, % +Graph, -Vertices + vertices_edges_to_ugraph/3, % +Vertices, +Edges, -Graph + ugraph_union/3, % +Graph1, +Graph2, -Graph + connect_ugraph/3 % +Graph1, -Start, -Graph + ]). + +/** Graph manipulation library + +The S-representation of a graph is a list of (vertex-neighbours) pairs, +where the pairs are in standard order (as produced by keysort) and the +neighbours of each vertex are also in standard order (as produced by +sort). This form is convenient for many calculations. + +A new UGraph from raw data can be created using +vertices_edges_to_ugraph/3. + +Adapted to support some of the functionality of the SICStus ugraphs +library by Vitor Santos Costa. + +Ported from YAP 5.0.1 to SWI-Prolog by Jan Wielemaker. + +@author R.A.O'Keefe +@author Vitor Santos Costa +@author Jan Wielemaker +@license BSD-2 or Artistic 2.0 +*/ + +:- use_module(library(lists)). +:- use_module(library(pairs)). +:- use_module(library(ordsets)). + +%! vertices(+Graph, -Vertices) +% +% Unify Vertices with all vertices appearing in Graph. Example: +% +% ?- vertices([1-[3,5],2-[4],3-[],4-[5],5-[]], L). +% L = [1, 2, 3, 4, 5] + +vertices([], []) :- !. +vertices([Vertex-_|Graph], [Vertex|Vertices]) :- + vertices(Graph, Vertices). + + +%! vertices_edges_to_ugraph(+Vertices, +Edges, -UGraph) is det. +% +% Create a UGraph from Vertices and edges. Given a graph with a +% set of Vertices and a set of Edges, Graph must unify with the +% corresponding S-representation. Note that the vertices without +% edges will appear in Vertices but not in Edges. Moreover, it is +% sufficient for a vertice to appear in Edges. +% +% == +% ?- vertices_edges_to_ugraph([],[1-3,2-4,4-5,1-5], L). +% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[]] +% == +% +% In this case all vertices are defined implicitly. The next +% example shows three unconnected vertices: +% +% == +% ?- vertices_edges_to_ugraph([6,7,8],[1-3,2-4,4-5,1-5], L). +% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[], 6-[], 7-[], 8-[]] +% == + +vertices_edges_to_ugraph(Vertices, Edges, Graph) :- + sort(Edges, EdgeSet), + p_to_s_vertices(EdgeSet, IVertexBag), + append(Vertices, IVertexBag, VertexBag), + sort(VertexBag, VertexSet), + p_to_s_group(VertexSet, EdgeSet, Graph). + + +%! add_vertices(+Graph, +Vertices, -NewGraph) +% +% Unify NewGraph with a new graph obtained by adding the list of +% Vertices to Graph. Example: +% +% ``` +% ?- add_vertices([1-[3,5],2-[]], [0,1,2,9], NG). +% NG = [0-[], 1-[3,5], 2-[], 9-[]] +% ``` + +% replace with real msort/2 when available +msort_(List, Sorted) :- + maplist(item_pair, List, Pairs), + keysort(Pairs, SortedPairs), + pairs_keys(SortedPairs, Sorted). + +item_pair(X, X-X). + +add_vertices(Graph, Vertices, NewGraph) :- + % msort/2 not available in Scryer Prolog yet: msort(Vertices, V1), + msort_(Vertices, V1), + add_vertices_to_s_graph(V1, Graph, NewGraph). + +add_vertices_to_s_graph(L, [], NL) :- + !, + add_empty_vertices(L, NL). +add_vertices_to_s_graph([], L, L) :- !. +add_vertices_to_s_graph([V1|VL], [V-Edges|G], NGL) :- + compare(Res, V1, V), + add_vertices_to_s_graph(Res, V1, VL, V, Edges, G, NGL). + +add_vertices_to_s_graph(=, _, VL, V, Edges, G, [V-Edges|NGL]) :- + add_vertices_to_s_graph(VL, G, NGL). +add_vertices_to_s_graph(<, V1, VL, V, Edges, G, [V1-[]|NGL]) :- + add_vertices_to_s_graph(VL, [V-Edges|G], NGL). +add_vertices_to_s_graph(>, V1, VL, V, Edges, G, [V-Edges|NGL]) :- + add_vertices_to_s_graph([V1|VL], G, NGL). + +add_empty_vertices([], []). +add_empty_vertices([V|G], [V-[]|NG]) :- + add_empty_vertices(G, NG). + +%! del_vertices(+Graph, +Vertices, -NewGraph) is det. +% +% Unify NewGraph with a new graph obtained by deleting the list of +% Vertices and all the edges that start from or go to a vertex in +% Vertices to the Graph. Example: +% +% == +% ?- del_vertices([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[2,6],8-[]], +% [2,1], +% NL). +% NL = [3-[],4-[5],5-[],6-[],7-[6],8-[]] +% == +% +% @compat Upto 5.6.48 the argument order was (+Vertices, +Graph, +% -NewGraph). Both YAP and SWI-Prolog have changed the argument +% order for compatibility with recent SICStus as well as +% consistency with del_edges/3. + +del_vertices(Graph, Vertices, NewGraph) :- + sort(Vertices, V1), % JW: was msort + ( V1 = [] + -> Graph = NewGraph + ; del_vertices(Graph, V1, V1, NewGraph) + ). + +del_vertices(G, [], V1, NG) :- + !, + del_remaining_edges_for_vertices(G, V1, NG). +del_vertices([], _, _, []). +del_vertices([V-Edges|G], [V0|Vs], V1, NG) :- + compare(Res, V, V0), + split_on_del_vertices(Res, V,Edges, [V0|Vs], NVs, V1, NG, NGr), + del_vertices(G, NVs, V1, NGr). + +del_remaining_edges_for_vertices([], _, []). +del_remaining_edges_for_vertices([V0-Edges|G], V1, [V0-NEdges|NG]) :- + ord_subtract(Edges, V1, NEdges), + del_remaining_edges_for_vertices(G, V1, NG). + +split_on_del_vertices(<, V, Edges, Vs, Vs, V1, [V-NEdges|NG], NG) :- + ord_subtract(Edges, V1, NEdges). +split_on_del_vertices(>, V, Edges, [_|Vs], Vs, V1, [V-NEdges|NG], NG) :- + ord_subtract(Edges, V1, NEdges). +split_on_del_vertices(=, _, _, [_|Vs], Vs, _, NG, NG). + +%! add_edges(+Graph, +Edges, -NewGraph) +% +% Unify NewGraph with a new graph obtained by adding the list of Edges +% to Graph. Example: +% +% ``` +% ?- add_edges([1-[3,5],2-[4],3-[],4-[5], +% 5-[],6-[],7-[],8-[]], +% [1-6,2-3,3-2,5-7,3-2,4-5], +% NL). +% NL = [1-[3,5,6], 2-[3,4], 3-[2], 4-[5], +% 5-[7], 6-[], 7-[], 8-[]] +% ``` + +add_edges(Graph, Edges, NewGraph) :- + p_to_s_graph(Edges, G1), + ugraph_union(Graph, G1, NewGraph). + +%! ugraph_union(+Graph1, +Graph2, -NewGraph) +% +% NewGraph is the union of Graph1 and Graph2. Example: +% +% ``` +% ?- ugraph_union([1-[2],2-[3]],[2-[4],3-[1,2,4]],L). +% L = [1-[2], 2-[3,4], 3-[1,2,4]] +% ``` + +ugraph_union(Set1, [], Set1) :- !. +ugraph_union([], Set2, Set2) :- !. +ugraph_union([Head1-E1|Tail1], [Head2-E2|Tail2], Union) :- + compare(Order, Head1, Head2), + ugraph_union(Order, Head1-E1, Tail1, Head2-E2, Tail2, Union). + +ugraph_union(=, Head-E1, Tail1, _-E2, Tail2, [Head-Es|Union]) :- + ord_union(E1, E2, Es), + ugraph_union(Tail1, Tail2, Union). +ugraph_union(<, Head1, Tail1, Head2, Tail2, [Head1|Union]) :- + ugraph_union(Tail1, [Head2|Tail2], Union). +ugraph_union(>, Head1, Tail1, Head2, Tail2, [Head2|Union]) :- + ugraph_union([Head1|Tail1], Tail2, Union). + +%! del_edges(+Graph, +Edges, -NewGraph) +% +% Unify NewGraph with a new graph obtained by removing the list of +% Edges from Graph. Notice that no vertices are deleted. Example: +% +% ``` +% ?- del_edges([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[],8-[]], +% [1-6,2-3,3-2,5-7,3-2,4-5,1-3], +% NL). +% NL = [1-[5],2-[4],3-[],4-[],5-[],6-[],7-[],8-[]] +% ``` + +del_edges(Graph, Edges, NewGraph) :- + p_to_s_graph(Edges, G1), + graph_subtract(Graph, G1, NewGraph). + +%! graph_subtract(+Set1, +Set2, ?Difference) +% +% Is based on ord_subtract + +graph_subtract(Set1, [], Set1) :- !. +graph_subtract([], _, []). +graph_subtract([Head1-E1|Tail1], [Head2-E2|Tail2], Difference) :- + compare(Order, Head1, Head2), + graph_subtract(Order, Head1-E1, Tail1, Head2-E2, Tail2, Difference). + +graph_subtract(=, H-E1, Tail1, _-E2, Tail2, [H-E|Difference]) :- + ord_subtract(E1,E2,E), + graph_subtract(Tail1, Tail2, Difference). +graph_subtract(<, Head1, Tail1, Head2, Tail2, [Head1|Difference]) :- + graph_subtract(Tail1, [Head2|Tail2], Difference). +graph_subtract(>, Head1, Tail1, _, Tail2, Difference) :- + graph_subtract([Head1|Tail1], Tail2, Difference). + +%! edges(+Graph, -Edges) +% +% Unify Edges with all edges appearing in Graph. Example: +% +% ?- edges([1-[3,5],2-[4],3-[],4-[5],5-[]], L). +% L = [1-3, 1-5, 2-4, 4-5] + +edges(Graph, Edges) :- + s_to_p_graph(Graph, Edges). + +p_to_s_graph(P_Graph, S_Graph) :- + sort(P_Graph, EdgeSet), + p_to_s_vertices(EdgeSet, VertexBag), + sort(VertexBag, VertexSet), + p_to_s_group(VertexSet, EdgeSet, S_Graph). + + +p_to_s_vertices([], []). +p_to_s_vertices([A-Z|Edges], [A,Z|Vertices]) :- + p_to_s_vertices(Edges, Vertices). + + +p_to_s_group([], _, []). +p_to_s_group([Vertex|Vertices], EdgeSet, [Vertex-Neibs|G]) :- + p_to_s_group(EdgeSet, Vertex, Neibs, RestEdges), + p_to_s_group(Vertices, RestEdges, G). + + +p_to_s_group([V1-X|Edges], V2, [X|Neibs], RestEdges) :- V1 == V2, + !, + p_to_s_group(Edges, V2, Neibs, RestEdges). +p_to_s_group(Edges, _, [], Edges). + + + +s_to_p_graph([], []) :- !. +s_to_p_graph([Vertex-Neibs|G], P_Graph) :- + s_to_p_graph(Neibs, Vertex, P_Graph, Rest_P_Graph), + s_to_p_graph(G, Rest_P_Graph). + + +s_to_p_graph([], _, P_Graph, P_Graph) :- !. +s_to_p_graph([Neib|Neibs], Vertex, [Vertex-Neib|P], Rest_P) :- + s_to_p_graph(Neibs, Vertex, P, Rest_P). + +%! transitive_closure(+Graph, -Closure) +% +% Generate the graph Closure as the transitive closure of Graph. +% Example: +% +% ``` +% ?- transitive_closure([1-[2,3],2-[4,5],4-[6]],L). +% L = [1-[2,3,4,5,6], 2-[4,5,6], 4-[6]] +% ``` + +transitive_closure(Graph, Closure) :- + warshall(Graph, Graph, Closure). + +warshall([], Closure, Closure) :- !. +warshall([V-_|G], E, Closure) :- + memberchk(V-Y, E), % Y := E(v) + warshall(E, V, Y, NewE), + warshall(G, NewE, Closure). + + +warshall([X-Neibs|G], V, Y, [X-NewNeibs|NewG]) :- + memberchk(V, Neibs), + !, + ord_union(Neibs, Y, NewNeibs), + warshall(G, V, Y, NewG). +warshall([X-Neibs|G], V, Y, [X-Neibs|NewG]) :- + !, + warshall(G, V, Y, NewG). +warshall([], _, _, []). + +%! transpose_ugraph(Graph, NewGraph) is det. +% +% Unify NewGraph with a new graph obtained from Graph by replacing +% all edges of the form V1-V2 by edges of the form V2-V1. The cost +% is O(|V|*log(|V|)). Notice that an undirected graph is its own +% transpose. Example: +% +% == +% ?- transpose([1-[3,5],2-[4],3-[],4-[5], +% 5-[],6-[],7-[],8-[]], NL). +% NL = [1-[],2-[],3-[1],4-[2],5-[1,4],6-[],7-[],8-[]] +% == +% +% @compat This predicate used to be known as transpose/2. +% Following SICStus 4, we reserve transpose/2 for matrix +% transposition and renamed ugraph transposition to +% transpose_ugraph/2. + +transpose_ugraph(Graph, NewGraph) :- + edges(Graph, Edges), + vertices(Graph, Vertices), + flip_edges(Edges, TransposedEdges), + vertices_edges_to_ugraph(Vertices, TransposedEdges, NewGraph). + +flip_edges([], []). +flip_edges([Key-Val|Pairs], [Val-Key|Flipped]) :- + flip_edges(Pairs, Flipped). + +%! compose(+LeftGraph, +RightGraph, -NewGraph) +% +% Compose NewGraph by connecting the _drains_ of LeftGraph to the +% _sources_ of RightGraph. Example: +% +% ?- compose([1-[2],2-[3]],[2-[4],3-[1,2,4]],L). +% L = [1-[4], 2-[1,2,4], 3-[]] + +compose(G1, G2, Composition) :- + vertices(G1, V1), + vertices(G2, V2), + ord_union(V1, V2, V), + compose(V, G1, G2, Composition). + +compose([], _, _, []) :- !. +compose([Vertex|Vertices], [Vertex-Neibs|G1], G2, + [Vertex-Comp|Composition]) :- + !, + compose1(Neibs, G2, [], Comp), + compose(Vertices, G1, G2, Composition). +compose([Vertex|Vertices], G1, G2, [Vertex-[]|Composition]) :- + compose(Vertices, G1, G2, Composition). + + +compose1([V1|Vs1], [V2-N2|G2], SoFar, Comp) :- + compare(Rel, V1, V2), + !, + compose1(Rel, V1, Vs1, V2, N2, G2, SoFar, Comp). +compose1(_, _, Comp, Comp). + + +compose1(<, _, Vs1, V2, N2, G2, SoFar, Comp) :- + !, + compose1(Vs1, [V2-N2|G2], SoFar, Comp). +compose1(>, V1, Vs1, _, _, G2, SoFar, Comp) :- + !, + compose1([V1|Vs1], G2, SoFar, Comp). +compose1(=, V1, Vs1, V1, N2, G2, SoFar, Comp) :- + ord_union(N2, SoFar, Next), + compose1(Vs1, G2, Next, Comp). + +%! top_sort(+Graph, -Sorted) is semidet. +%! top_sort(+Graph, -Sorted, ?Tail) is semidet. +% +% Sorted is a topological sorted list of nodes in Graph. A +% toplogical sort is possible if the graph is connected and +% acyclic. In the example we show how topological sorting works +% for a linear graph: +% +% == +% ?- top_sort([1-[2], 2-[3], 3-[]], L). +% L = [1, 2, 3] +% == +% +% The predicate top_sort/3 is a difference list version of +% top_sort/2. + +top_sort(Graph, Sorted) :- + vertices_and_zeros(Graph, Vertices, Counts0), + count_edges(Graph, Vertices, Counts0, Counts1), + select_zeros(Counts1, Vertices, Zeros), + top_sort(Zeros, Sorted, Graph, Vertices, Counts1). + +top_sort(Graph, Sorted0, Sorted) :- + vertices_and_zeros(Graph, Vertices, Counts0), + count_edges(Graph, Vertices, Counts0, Counts1), + select_zeros(Counts1, Vertices, Zeros), + top_sort(Zeros, Sorted, Sorted0, Graph, Vertices, Counts1). + + +vertices_and_zeros([], [], []) :- !. +vertices_and_zeros([Vertex-_|Graph], [Vertex|Vertices], [0|Zeros]) :- + vertices_and_zeros(Graph, Vertices, Zeros). + + +count_edges([], _, Counts, Counts) :- !. +count_edges([_-Neibs|Graph], Vertices, Counts0, Counts2) :- + incr_list(Neibs, Vertices, Counts0, Counts1), + count_edges(Graph, Vertices, Counts1, Counts2). + + +incr_list([], _, Counts, Counts) :- !. +incr_list([V1|Neibs], [V2|Vertices], [M|Counts0], [N|Counts1]) :- + V1 == V2, + !, + N is M+1, + incr_list(Neibs, Vertices, Counts0, Counts1). +incr_list(Neibs, [_|Vertices], [N|Counts0], [N|Counts1]) :- + incr_list(Neibs, Vertices, Counts0, Counts1). + + +select_zeros([], [], []) :- !. +select_zeros([0|Counts], [Vertex|Vertices], [Vertex|Zeros]) :- + !, + select_zeros(Counts, Vertices, Zeros). +select_zeros([_|Counts], [_|Vertices], Zeros) :- + select_zeros(Counts, Vertices, Zeros). + + + +top_sort([], [], Graph, _, Counts) :- + !, + vertices_and_zeros(Graph, _, Counts). +top_sort([Zero|Zeros], [Zero|Sorted], Graph, Vertices, Counts1) :- + graph_memberchk(Zero-Neibs, Graph), + decr_list(Neibs, Vertices, Counts1, Counts2, Zeros, NewZeros), + top_sort(NewZeros, Sorted, Graph, Vertices, Counts2). + +top_sort([], Sorted0, Sorted0, Graph, _, Counts) :- + !, + vertices_and_zeros(Graph, _, Counts). +top_sort([Zero|Zeros], [Zero|Sorted], Sorted0, Graph, Vertices, Counts1) :- + graph_memberchk(Zero-Neibs, Graph), + decr_list(Neibs, Vertices, Counts1, Counts2, Zeros, NewZeros), + top_sort(NewZeros, Sorted, Sorted0, Graph, Vertices, Counts2). + +graph_memberchk(Element1-Edges, [Element2-Edges2|_]) :- + Element1 == Element2, + !, + Edges = Edges2. +graph_memberchk(Element, [_|Rest]) :- + graph_memberchk(Element, Rest). + + +decr_list([], _, Counts, Counts, Zeros, Zeros) :- !. +decr_list([V1|Neibs], [V2|Vertices], [1|Counts1], [0|Counts2], Zi, Zo) :- + V1 == V2, + !, + decr_list(Neibs, Vertices, Counts1, Counts2, [V2|Zi], Zo). +decr_list([V1|Neibs], [V2|Vertices], [N|Counts1], [M|Counts2], Zi, Zo) :- + V1 == V2, + !, + M is N-1, + decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo). +decr_list(Neibs, [_|Vertices], [N|Counts1], [N|Counts2], Zi, Zo) :- + decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo). + + +%! neighbors(+Vertex, +Graph, -Neigbours) is det. +%! neighbours(+Vertex, +Graph, -Neigbours) is det. +% +% Neigbours is a sorted list of the neighbours of Vertex in Graph. +% Example: +% +% ``` +% ?- neighbours(4,[1-[3,5],2-[4],3-[], +% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL). +% NL = [1,2,7,5] +% ``` + +neighbors(Vertex, Graph, Neig) :- + neighbours(Vertex, Graph, Neig). + +neighbours(V,[V0-Neig|_],Neig) :- + V == V0, + !. +neighbours(V,[_|G],Neig) :- + neighbours(V,G,Neig). + + +%! connect_ugraph(+UGraphIn, -Start, -UGraphOut) is det. +% +% Adds Start as an additional vertex that is connected to all vertices +% in UGraphIn. This can be used to create an topological sort for a +% not connected graph. Start is before any vertex in UGraphIn in the +% standard order of terms. No vertex in UGraphIn can be a variable. +% +% Can be used to order a not-connected graph as follows: +% +% ``` +% top_sort_unconnected(Graph, Vertices) :- +% ( top_sort(Graph, Vertices) +% -> true +% ; connect_ugraph(Graph, Start, Connected), +% top_sort(Connected, Ordered0), +% Ordered0 = [Start|Vertices] +% ). +% ``` + +connect_ugraph([], 0, []) :- !. +connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :- + vertices(Graph, Vertices), + Vertices = [First|_], + before(First, Start). + +%! before(+Term, -Before) is det. +% +% Unify Before to a term that comes before Term in the standard +% order of terms. +% +% @error instantiation_error if Term is unbound. + +before(X, _) :- + var(X), + !, + instantiation_error(X). +before(Number, Start) :- + number(Number), + !, + Start is Number - 1. +before(_, 0). + + +%! complement(+UGraphIn, -UGraphOut) +% +% UGraphOut is a ugraph with an edge between all vertices that are +% _not_ connected in UGraphIn and all edges from UGraphIn removed. +% Example: +% +% ``` +% ?- complement([1-[3,5],2-[4],3-[], +% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL). +% NL = [1-[2,4,6,7,8],2-[1,3,5,6,7,8],3-[1,2,4,5,6,7,8], +% 4-[3,5,6,8],5-[1,2,3,4,6,7,8],6-[1,2,3,4,5,7,8], +% 7-[1,2,3,4,5,6,8],8-[1,2,3,4,5,6,7]] +% ``` +% +% @tbd Simple two-step algorithm. You could be smarter, I suppose. + +complement(G, NG) :- + vertices(G,Vs), + complement(G,Vs,NG). + +complement([], _, []). +complement([V-Ns|G], Vs, [V-INs|NG]) :- + ord_add_element(Ns,V,Ns1), + ord_subtract(Vs,Ns1,INs), + complement(G, Vs, NG). + +%! reachable(+Vertex, +UGraph, -Vertices) +% +% True when Vertices is an ordered set of vertices reachable in +% UGraph, including Vertex. Example: +% +% ?- reachable(1,[1-[3,5],2-[4],3-[],4-[5],5-[]],V). +% V = [1, 3, 5] + +reachable(N, G, Rs) :- + reachable([N], G, [N], Rs). + +reachable([], _, Rs, Rs). +reachable([N|Ns], G, Rs0, RsF) :- + neighbours(N, G, Nei), + ord_union(Rs0, Nei, Rs1, D), + append(Ns, D, Nsi), + reachable(Nsi, G, Rs1, RsF). -- cgit v1.2.3-70-g09d2 From 0404c3bd949b09d6713d3869e37d30a6b8a77f97 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 14 Nov 2021 13:39:56 -0700 Subject: use new heap term representation --- .gitignore | 2 + Cargo.lock | 561 +-- Cargo.toml | 31 +- build.rs | 18 + crates/prolog_parser/Cargo.lock | 265 -- crates/prolog_parser/src/ast.rs | 782 ---- crates/prolog_parser/src/lexer.rs | 912 ----- crates/prolog_parser/src/lib.rs | 15 - crates/prolog_parser/src/macros.rs | 253 -- crates/prolog_parser/src/parser.rs | 1031 ----- crates/prolog_parser/src/put_back_n.rs | 71 - crates/prolog_parser/src/tabled_rc.rs | 154 - crates/prolog_parser/tests/bom.rs | 40 - crates/prolog_parser/tests/parse_tokens.rs | 112 - crates/static-string-indexing/Cargo.toml | 11 + crates/static-string-indexing/src/lib.rs | 161 + src/allocator.rs | 25 +- src/arena.rs | 797 ++++ src/arithmetic.rs | 574 ++- src/atom_table.rs | 366 ++ src/bin/scryer-prolog.rs | 8 +- src/clause_types.rs | 1145 +++--- src/codegen.rs | 213 +- src/debray_allocator.rs | 36 +- src/fixtures.rs | 20 +- src/forms.rs | 474 ++- src/heap_iter.rs | 2723 +++++++++++-- src/heap_print.rs | 1704 ++++---- src/indexing.rs | 312 +- src/instructions.rs | 448 +- src/iterators.rs | 208 +- src/lib.rs | 24 +- src/lib/atts.pl | 52 +- src/lib/between.pl | 17 +- src/lib/builtins.pl | 51 +- src/lib/iso_ext.pl | 9 +- src/lib/lists.pl | 2 +- src/lib/serialization/abnf.pl | 14 +- src/lib/serialization/json.pl | 18 +- src/lib/uuid.pl | 6 +- src/loader.pl | 4 +- src/machine/arithmetic_ops.rs | 2012 +++++---- src/machine/attributed_variables.rs | 113 +- src/machine/code_repo.rs | 2 +- src/machine/compile.rs | 463 ++- src/machine/copier.rs | 418 +- src/machine/gc.rs | 1101 +++++ src/machine/heap.rs | 580 ++- src/machine/load_state.rs | 542 ++- src/machine/loader.rs | 1923 ++++----- src/machine/machine_errors.rs | 830 ++-- src/machine/machine_indices.rs | 515 +-- src/machine/machine_state.rs | 1754 ++++---- src/machine/machine_state_impl.rs | 4466 +++++++++++--------- src/machine/mock_wam.rs | 766 ++++ src/machine/mod.rs | 294 +- src/machine/partial_string.rs | 1323 ++++-- src/machine/preprocessor.rs | 518 ++- src/machine/stack.rs | 202 +- src/machine/streams.rs | 1762 ++++---- src/machine/system_calls.rs | 6108 +++++++++++++--------------- src/machine/term_stream.rs | 89 +- src/macros.rs | 660 ++- src/parser/ast.rs | 631 +++ src/parser/char_reader.rs | 747 ++++ src/parser/lexer.rs | 1059 +++++ src/parser/macros.rs | 253 ++ src/parser/mod.rs | 17 + src/parser/parser.rs | 1080 +++++ src/raw_block.rs | 105 + src/read.rs | 466 ++- src/targets.rs | 54 +- src/toplevel.pl | 73 +- src/types.rs | 739 ++++ src/write.rs | 304 +- tests/scryer/helper.rs | 28 +- 76 files changed, 27466 insertions(+), 18200 deletions(-) delete mode 100644 crates/prolog_parser/Cargo.lock delete mode 100644 crates/prolog_parser/src/ast.rs delete mode 100644 crates/prolog_parser/src/lexer.rs delete mode 100644 crates/prolog_parser/src/lib.rs delete mode 100644 crates/prolog_parser/src/macros.rs delete mode 100644 crates/prolog_parser/src/parser.rs delete mode 100644 crates/prolog_parser/src/put_back_n.rs delete mode 100644 crates/prolog_parser/src/tabled_rc.rs delete mode 100644 crates/prolog_parser/tests/bom.rs delete mode 100644 crates/prolog_parser/tests/parse_tokens.rs create mode 100644 crates/static-string-indexing/Cargo.toml create mode 100644 crates/static-string-indexing/src/lib.rs create mode 100644 src/arena.rs create mode 100644 src/atom_table.rs create mode 100644 src/machine/gc.rs create mode 100644 src/machine/mock_wam.rs create mode 100644 src/parser/ast.rs create mode 100644 src/parser/char_reader.rs create mode 100644 src/parser/lexer.rs create mode 100644 src/parser/macros.rs create mode 100644 src/parser/mod.rs create mode 100644 src/parser/parser.rs create mode 100644 src/raw_block.rs create mode 100644 src/types.rs diff --git a/.gitignore b/.gitignore index eafdaf52..f63be9e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +src/static_atoms.rs target/ + diff --git a/Cargo.lock b/Cargo.lock index 7e94a23e..d5b4dc14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "arrayvec" version = "0.5.2" @@ -8,9 +10,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "assert_cmd" -version = "1.0.3" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2475b58cd94eb4f70159f4fd8844ba3b807532fe3131b3373fae060bbe30396" +checksum = "c98233c6673d8601ab23e77eb38f999c51100d46c5703b17288c57fddf3a1ffe" dependencies = [ "bstr", "doc-comment", @@ -34,9 +36,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "az" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84e1d907bfc5795a6addb95ef8666141ee73c8f2f5250ff2a46bf4e4f4aec8a" +checksum = "9d6dff4a1892b54d70af377bf7a17064192e822865791d812957f21e3108c325" [[package]] name = "base64" @@ -61,9 +63,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blake2" @@ -100,9 +102,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", @@ -111,9 +113,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.6.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" +checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" [[package]] name = "byte-tools" @@ -123,15 +125,15 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.66" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" [[package]] name = "cfg-if" @@ -153,7 +155,7 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ "libc", "num-integer", - "num-traits 0.2.14", + "num-traits", "time", "winapi 0.3.9", ] @@ -169,9 +171,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" dependencies = [ "core-foundation-sys", "libc", @@ -179,9 +181,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpu-time" @@ -229,10 +231,10 @@ dependencies = [ ] [[package]] -name = "difference" -version = "2.0.0" +name = "difflib" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "digest" @@ -282,6 +284,21 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d" +[[package]] +name = "ed25519" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc" +dependencies = [ + "signature", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + [[package]] name = "foreign-types" version = "0.3.2" @@ -341,18 +358,18 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" dependencies = [ "typenum", ] [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if 1.0.0", "libc", @@ -361,9 +378,9 @@ dependencies = [ [[package]] name = "git-version" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94918e83f1e01dedc2e361d00ce9487b14c58c7f40bab148026fa39d42cb41e2" +checksum = "f6b0decc02f4636b9ccad390dcbe77b722a77efedfa393caf8379a51d5c61899" dependencies = [ "git-version-macro", "proc-macro-hack", @@ -371,21 +388,21 @@ dependencies = [ [[package]] name = "git-version-macro" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34a97a52fdee1870a34fa6e4b77570cba531b27d1838874fef4429a791a3d657" +checksum = "fe69f1cbdb6e28af2bac214e943b99ce8a0a06b447d15d3e61161b0423139f3f" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.60", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", ] [[package]] name = "gmp-mpfr-sys" -version = "1.4.2" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57fdb339d49833021b1fded600ed240ae907e33909d5511a61dff884df7f16e" +checksum = "a146a7357ce9573bdcc416fc4a99b960e166e72d8eaffa7c59966d51866b5bfb" dependencies = [ "libc", "winapi 0.3.9", @@ -393,9 +410,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.9.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "hostname" @@ -424,9 +441,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ "autocfg 1.0.1", "hashbrown", @@ -441,17 +458,26 @@ dependencies = [ "libc", ] +[[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "js-sys" -version = "0.3.47" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" dependencies = [ "wasm-bindgen", ] @@ -503,19 +529,20 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.85" +version = "0.2.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" +checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" [[package]] name = "libsodium-sys" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a685b64f837b339074115f2e7f7b431ac73681d08d75b389db7498b8892b8a58" +checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" dependencies = [ "cc", "libc", "pkg-config", + "walkdir", ] [[package]] @@ -558,7 +585,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1af46a727284117e09780d05038b1ce6fc9c76cc6df183c3dae5a8955a25e21" dependencies = [ "log", - "phf", + "phf 0.7.24", "phf_codegen", "serde", "serde_derive", @@ -576,9 +603,9 @@ checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "mio" @@ -611,11 +638,30 @@ dependencies = [ "ws2_32-sys", ] +[[package]] +name = "modular-bitfield" +version = "0.11.2" +source = "git+https://github.com/mthom/modular-bitfield#213535c684af277563678179d8496f11b84a283f" +dependencies = [ + "modular-bitfield-impl", + "static_assertions", +] + +[[package]] +name = "modular-bitfield-impl" +version = "0.11.2" +source = "git+https://github.com/mthom/modular-bitfield#213535c684af277563678179d8496f11b84a283f" +dependencies = [ + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", +] + [[package]] name = "native-tls" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" dependencies = [ "lazy_static", "libc", @@ -679,7 +725,7 @@ checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ "autocfg 1.0.1", "num-integer", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -689,7 +735,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg 1.0.1", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -701,7 +747,7 @@ dependencies = [ "autocfg 1.0.1", "num-bigint", "num-integer", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -712,16 +758,7 @@ dependencies = [ "num-bigint", "num-integer", "num-rational", - "num-traits 0.2.14", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -735,9 +772,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.5.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "opaque-debug" @@ -747,38 +784,38 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "openssl" -version = "0.10.32" +version = "0.10.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" dependencies = [ "bitflags", "cfg-if 1.0.0", "foreign-types", - "lazy_static", "libc", + "once_cell", "openssl-sys", ] [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "openssl-src" -version = "111.13.0+1.1.1i" +version = "300.0.2+3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045e4dc48af57aad93d665885789b43222ae26f4886494da12d1ed58d309dcb6" +checksum = "14a760a11390b1a5daf72074d4f6ff1a6e772534ae191f999f57e9ee8146d1fb" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.60" +version = "0.9.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" +checksum = "c6517987b3f8226b5da3661dad65ff7f300cc59fb5ea8333ca191fc65fde3edf" dependencies = [ "autocfg 1.0.1", "cc", @@ -790,12 +827,11 @@ dependencies = [ [[package]] name = "ordered-float" -version = "0.5.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d" +checksum = "97c9d06878b3a851e8026ef94bf7fef9ba93062cd412601da4d9cf369b1cc62d" dependencies = [ - "num-traits 0.1.43", - "unreachable", + "num-traits", ] [[package]] @@ -828,7 +864,18 @@ version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" dependencies = [ - "phf_shared", + "phf_shared 0.7.24", +] + +[[package]] +name = "phf" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ac8b67553a7ca9457ce0e526948cad581819238f4a9d1ea74545851fa24f37" +dependencies = [ + "phf_macros", + "phf_shared 0.9.0", + "proc-macro-hack", ] [[package]] @@ -837,8 +884,8 @@ version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.7.24", + "phf_shared 0.7.24", ] [[package]] @@ -847,30 +894,63 @@ version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" dependencies = [ - "phf_shared", + "phf_shared 0.7.24", "rand 0.6.5", ] +[[package]] +name = "phf_generator" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43f3220d96e0080cc9ea234978ccd80d904eafb17be31bb0f76daaea6493082" +dependencies = [ + "phf_shared 0.9.0", + "rand 0.8.4", +] + +[[package]] +name = "phf_macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b706f5936eb50ed880ae3009395b43ed19db5bff2ebd459c95e7bf013a89ab86" +dependencies = [ + "phf_generator 0.9.1", + "phf_shared 0.9.0", + "proc-macro-hack", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", +] + [[package]] name = "phf_shared" version = "0.7.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" dependencies = [ - "siphasher", + "siphasher 0.2.3", +] + +[[package]] +name = "phf_shared" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a68318426de33640f02be62b4ae8eb1261be2efbc337b60c54d845bf4484e0d9" +dependencies = [ + "siphasher 0.3.7", ] [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "precomputed-hash" @@ -880,11 +960,12 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "1.0.7" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb433456c1a57cc93554dea3ce40b4c19c4057e41c55d4a0f3d84ea71c325aa" +checksum = "5c6ce811d0b2e103743eec01db1c50612221f173084ce2f7941053e94b6bb474" dependencies = [ - "difference", + "difflib", + "itertools", "predicates-core", ] @@ -896,12 +977,12 @@ checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451" [[package]] name = "predicates-tree" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f553275e5721409451eb85e15fd9a860a6e5ab4496eb215987502b5f5391f2" +checksum = "338c7be2905b732ae3984a2f40032b5e94fd8f52505b186c7d4d68d193445df7" dependencies = [ "predicates-core", - "treeline", + "termtree", ] [[package]] @@ -921,23 +1002,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ - "unicode-xid 0.2.1", -] - -[[package]] -name = "prolog_parser" -version = "0.8.68" -dependencies = [ - "indexmap", - "lexical", - "num-rug-adapter", - "ordered-float", - "rug", - "unicode_reader", + "unicode-xid 0.2.2", ] [[package]] @@ -951,11 +1020,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ - "proc-macro2 1.0.24", + "proc-macro2 1.0.32", ] [[package]] @@ -979,14 +1048,14 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.1", - "rand_hc 0.3.0", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", ] [[package]] @@ -1001,12 +1070,12 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.1", + "rand_core 0.6.3", ] [[package]] @@ -1026,9 +1095,9 @@ checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rand_core" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom", ] @@ -1044,11 +1113,11 @@ dependencies = [ [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.6.1", + "rand_core 0.6.3", ] [[package]] @@ -1121,9 +1190,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" -version = "0.2.4" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -1135,7 +1204,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom", - "redox_syscall 0.2.4", + "redox_syscall 0.2.10", ] [[package]] @@ -1146,12 +1215,9 @@ checksum = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6" [[package]] name = "regex-automata" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" -dependencies = [ - "byteorder", -] +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "remove_dir_all" @@ -1199,9 +1265,9 @@ dependencies = [ [[package]] name = "rug" -version = "1.11.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e538d00da450a8e48aac7e6322e67b2dc86ec71a1feeac0e3954c4f07f01bc45" +checksum = "ee0c6e98de59509e62e09f3456b23cebb75dad21928882016f169bb628843459" dependencies = [ "az", "gmp-mpfr-sys", @@ -1235,6 +1301,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.19" @@ -1253,7 +1328,7 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scryer-prolog" -version = "0.8.128" +version = "0.9.0" dependencies = [ "assert_cmd", "base64", @@ -1268,14 +1343,17 @@ dependencies = [ "hostname", "indexmap", "lazy_static", + "lexical", "libc", + "modular-bitfield", "native-tls", "nix 0.15.0", "num-rug-adapter", "openssl", "ordered-float", + "phf 0.9.0", "predicates-core", - "prolog_parser", + "proc-macro2 1.0.32", "ref_thread_local", "ring", "ripemd160", @@ -1285,15 +1363,17 @@ dependencies = [ "select", "sha3", "slice-deque", + "smallvec", "sodiumoxide", - "unicode_reader", + "static-string-indexing", + "static_assertions", ] [[package]] name = "security-framework" -version = "2.0.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" +checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" dependencies = [ "bitflags", "core-foundation", @@ -1304,9 +1384,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.0.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" dependencies = [ "core-foundation-sys", "libc", @@ -1324,26 +1404,26 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.123" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" [[package]] name = "serde_derive" -version = "1.0.123" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.60", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", ] [[package]] name = "serde_json" -version = "1.0.61" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +checksum = "e277c495ac6cd1a01a58d0a0c574568b4d1ddf14f59965c6a58b8d96400b54f3" dependencies = [ "itoa", "ryu", @@ -1376,24 +1456,36 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" + [[package]] name = "siphasher" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" +[[package]] +name = "siphasher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b" + [[package]] name = "slab" -version = "0.4.2" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "slice-deque" @@ -1408,16 +1500,17 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "sodiumoxide" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7038b67c941e23501573cb7242ffb08709abe9b11eb74bceff875bbda024a6a8" +checksum = "e26be3acb6c2d9a7aac28482586a7856436af4cfe7100031d219de2d2ecb0028" dependencies = [ + "ed25519", "libc", "libsodium-sys", "serde", @@ -1429,6 +1522,17 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "static-string-indexing" +version = "0.1.0" +dependencies = [ + "indexmap", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", + "walkdir", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -1443,7 +1547,7 @@ checksum = "89c058a82f9fd69b1becf8c274f412281038877c553182f1d02eb027045a2d67" dependencies = [ "lazy_static", "new_debug_unreachable", - "phf_shared", + "phf_shared 0.7.24", "precomputed-hash", "serde", "string_cache_codegen", @@ -1456,10 +1560,10 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6" dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2 1.0.24", - "quote 1.0.8", + "phf_generator 0.7.24", + "phf_shared 0.7.24", + "proc-macro2 1.0.32", + "quote 1.0.10", "string_cache_shared", ] @@ -1488,13 +1592,13 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.60" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "unicode-xid 0.2.1", + "proc-macro2 1.0.32", + "quote 1.0.10", + "unicode-xid 0.2.2", ] [[package]] @@ -1505,8 +1609,8 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.3", - "redox_syscall 0.2.4", + "rand 0.8.4", + "redox_syscall 0.2.10", "remove_dir_all", "winapi 0.3.9", ] @@ -1522,6 +1626,12 @@ dependencies = [ "utf-8", ] +[[package]] +name = "termtree" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" + [[package]] name = "time" version = "0.1.43" @@ -1532,29 +1642,23 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "treeline" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" - [[package]] name = "typenum" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" @@ -1564,28 +1668,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "unicode_reader" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b639121690b27acd92c97ed2b52c5e5e8d3d39482e943b4559695cef62f771a" -dependencies = [ - "smallvec", - "unicode-segmentation", -] - -[[package]] -name = "unreachable" -version = "1.0.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -dependencies = [ - "void", -] +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "untrusted" @@ -1595,9 +1680,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "utf-8" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "utf8parse" @@ -1607,9 +1692,9 @@ checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" [[package]] name = "vcpkg" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "void" @@ -1626,6 +1711,17 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi 0.3.9", + "winapi-util", +] + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -1634,9 +1730,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.70" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -1644,53 +1740,53 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.70" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.60", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.70" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" dependencies = [ - "quote 1.0.8", + "quote 1.0.10", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.70" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ - "proc-macro2 1.0.24", - "quote 1.0.8", - "syn 1.0.60", + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.70" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" [[package]] name = "web-sys" -version = "0.3.47" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" dependencies = [ "js-sys", "wasm-bindgen", @@ -1724,6 +1820,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 0e4b144e..ee785cb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scryer-prolog" -version = "0.8.128" +version = "0.9.0" authors = ["Mark Thom "] edition = "2021" description = "A modern Prolog implementation written mostly in Rust." @@ -12,14 +12,19 @@ categories = ["command-line-utilities"] build = "build.rs" [workspace] -members = ["crates/prolog_parser", "crates/num-rug-adapter"] +members = ["crates/num-rug-adapter", "crates/static-string-indexing"] + +[features] +num = ["num-rug-adapter"] +# no default features to make num tests work +# workaround for --no-default-features and --features not working intuitively for workspaces with a root package +# see rust-lang/cargo#7160 +default = ["rug"] [build-dependencies] indexmap = "1.0.2" - -[features] -default = ["rug", "prolog_parser/rug"] -num = ["num-rug-adapter", "prolog_parser/num"] +static-string-indexing = { path = "./crates/static-string-indexing" } +proc-macro2 = "*" [dependencies] cpu-time = "1.0.0" @@ -31,15 +36,17 @@ git-version = "0.3.4" hostname = "0.3.1" indexmap = "1.0.2" lazy_static = "1.4.0" +lexical = "5.2.2" libc = "0.2.62" +# temporary to remove unnecessary braces warnings. +modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } # modular-bitfield = "0.11.2" nix = "0.15.0" num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" } -ordered-float = "0.5.0" -prolog_parser = { path = "./crates/prolog_parser", default-features = false } +ordered-float = "2.1.1" +phf = { version = "0.9", features = ["macros"] } ref_thread_local = "0.0.0" -rug = { version = "1.4.0", optional = true } +rug = { version = "1.12.0", optional = true } rustyline = "7.0.0" -unicode_reader = "1.0.0" ring = "0.16.13" ripemd160 = "0.8.0" sha3 = "0.8.2" @@ -50,9 +57,11 @@ chrono = "0.4.11" select = "0.4.3" roxmltree = "0.11.0" base64 = "0.12.3" +smallvec = "*" sodiumoxide = "0.2.6" +static_assertions = "1.1.0" slice-deque = "0.3.0" [dev-dependencies] assert_cmd = "1.0.3" -predicates-core = "1.0.2" +predicates-core = "1.0.2" \ No newline at end of file diff --git a/build.rs b/build.rs index 0133c93e..88267cdc 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,11 @@ +use static_string_indexing::index_static_strings; + use std::env; use std::fs; use std::fs::File; use std::io::Write; use std::path::Path; +use std::process::Command; fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) { let entries = match current_dir.read_dir() { @@ -48,6 +51,21 @@ fn main() { let mut m = IndexMap::new();\n", ) .unwrap(); + find_prolog_files(&mut libraries, "", &lib_path); libraries.write_all(b"\n m\n };\n}\n").unwrap(); + + let static_atoms_path = Path::new("src/static_atoms.rs"); + let mut static_atoms_file = File::create(&static_atoms_path).unwrap(); + + let quoted_output = index_static_strings(); + + static_atoms_file + .write_all(quoted_output.to_string().as_bytes()) + .unwrap(); + + Command::new("rustfmt") + .arg(static_atoms_path.as_os_str()) + .spawn().unwrap() + .wait().unwrap(); } diff --git a/crates/prolog_parser/Cargo.lock b/crates/prolog_parser/Cargo.lock deleted file mode 100644 index 57d62880..00000000 --- a/crates/prolog_parser/Cargo.lock +++ /dev/null @@ -1,265 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "az" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84e1d907bfc5795a6addb95ef8666141ee73c8f2f5250ff2a46bf4e4f4aec8a" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "gmp-mpfr-sys" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57fdb339d49833021b1fded600ed240ae907e33909d5511a61dff884df7f16e" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "lexical" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e0d09e60c187a6d0a3fa418aec8587c6a4ae9de872f6126f2134f319b5ed10d" -dependencies = [ - "cfg-if", - "lexical-core", - "rustc_version", -] - -[[package]] -name = "lexical-core" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14" -dependencies = [ - "arrayvec", - "cfg-if", - "rustc_version", - "ryu", - "static_assertions", -] - -[[package]] -name = "libc" -version = "0.2.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg", - "num-integer", - "num-traits 0.2.14", -] - -[[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits 0.2.14", -] - -[[package]] -name = "num-rational" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits 0.2.14", -] - -[[package]] -name = "num-rug-adapter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7470b6acf85abce0771203112db4181d03f7b8a6be49f0e842a78030192f8a58" -dependencies = [ - "libc", - "num-bigint", - "num-integer", - "num-rational", - "num-traits 0.2.14", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.14", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - -[[package]] -name = "ordered-float" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d" -dependencies = [ - "num-traits 0.1.43", - "unreachable", -] - -[[package]] -name = "prolog_parser" -version = "0.8.68" -dependencies = [ - "lexical", - "num-rug-adapter", - "ordered-float", - "rug", - "unicode_reader", -] - -[[package]] -name = "rug" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e538d00da450a8e48aac7e6322e67b2dc86ec71a1feeac0e3954c4f07f01bc45" -dependencies = [ - "az", - "gmp-mpfr-sys", - "libc", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "smallvec" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" - -[[package]] -name = "static_assertions" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" - -[[package]] -name = "unicode-segmentation" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" - -[[package]] -name = "unicode_reader" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b639121690b27acd92c97ed2b52c5e5e8d3d39482e943b4559695cef62f771a" -dependencies = [ - "smallvec", - "unicode-segmentation", -] - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -dependencies = [ - "void", -] - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/crates/prolog_parser/src/ast.rs b/crates/prolog_parser/src/ast.rs deleted file mode 100644 index ac794e6e..00000000 --- a/crates/prolog_parser/src/ast.rs +++ /dev/null @@ -1,782 +0,0 @@ -use crate::rug::{Integer, Rational}; -use crate::tabled_rc::*; -use ordered_float::*; - -use crate::put_back_n::*; - -use std::cell::Cell; -use std::cmp::Ordering; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::io::{Bytes, Error as IOError, Read}; -use std::ops::Deref; -use std::rc::Rc; -use std::vec::Vec; - -use indexmap::IndexMap; -use unicode_reader::CodePoints; - -pub type Atom = String; - -pub type Var = String; - -pub type Specifier = u32; - -pub const MAX_ARITY: usize = 1023; - -pub const XFX: u32 = 0x0001; -pub const XFY: u32 = 0x0002; -pub const YFX: u32 = 0x0004; -pub const XF: u32 = 0x0010; -pub const YF: u32 = 0x0020; -pub const FX: u32 = 0x0040; -pub const FY: u32 = 0x0080; -pub const DELIMITER: u32 = 0x0100; -pub const TERM: u32 = 0x1000; -pub const LTERM: u32 = 0x3000; - -pub const NEGATIVE_SIGN: u32 = 0x0200; - -#[macro_export] -macro_rules! clause_name { - ($name: expr, $tbl: expr) => { - $crate::ast::ClauseName::User($crate::tabled_rc::TabledRc::new($name, $tbl.clone())) - }; - ($name: expr) => { - $crate::ast::ClauseName::BuiltIn($name) - }; -} - -#[macro_export] -macro_rules! atom { - ($e:expr, $tbl:expr) => { - $crate::ast::Constant::Atom( - $crate::ast::ClauseName::User($crate::tabled_rc!($e, $tbl)), - None, - ) - }; - ($e:expr) => { - $crate::ast::Constant::Atom($crate::clause_name!($e), None) - }; -} - -#[macro_export] -macro_rules! rc_atom { - ($e:expr) => { - Rc::new(String::from($e)) - }; -} -macro_rules! is_term { - ($x:expr) => { - ($x & $crate::ast::TERM) != 0 - }; -} - -macro_rules! is_lterm { - ($x:expr) => { - ($x & $crate::ast::LTERM) != 0 - }; -} - -macro_rules! is_op { - ($x:expr) => { - $x & ($crate::ast::XF - | $crate::ast::YF - | $crate::ast::FX - | $crate::ast::FY - | $crate::ast::XFX - | $crate::ast::XFY - | $crate::ast::YFX) - != 0 - }; -} - -macro_rules! is_negate { - ($x:expr) => { - ($x & $crate::ast::NEGATIVE_SIGN) != 0 - }; -} - -#[macro_export] -macro_rules! is_prefix { - ($x:expr) => { - $x & ($crate::ast::FX | $crate::ast::FY) != 0 - }; -} - -#[macro_export] -macro_rules! is_postfix { - ($x:expr) => { - $x & ($crate::ast::XF | $crate::ast::YF) != 0 - }; -} - -#[macro_export] -macro_rules! is_infix { - ($x:expr) => { - ($x & ($crate::ast::XFX | $crate::ast::XFY | $crate::ast::YFX)) != 0 - }; -} - -#[macro_export] -macro_rules! is_xfx { - ($x:expr) => { - ($x & $crate::ast::XFX) != 0 - }; -} - -#[macro_export] -macro_rules! is_xfy { - ($x:expr) => { - ($x & $crate::ast::XFY) != 0 - }; -} - -#[macro_export] -macro_rules! is_yfx { - ($x:expr) => { - ($x & $crate::ast::YFX) != 0 - }; -} - -#[macro_export] -macro_rules! is_yf { - ($x:expr) => { - ($x & $crate::ast::YF) != 0 - }; -} - -#[macro_export] -macro_rules! is_xf { - ($x:expr) => { - ($x & $crate::ast::XF) != 0 - }; -} - -#[macro_export] -macro_rules! is_fx { - ($x:expr) => { - ($x & $crate::ast::FX) != 0 - }; -} - -#[macro_export] -macro_rules! is_fy { - ($x:expr) => { - ($x & $crate::ast::FY) != 0 - }; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum RegType { - Perm(usize), - Temp(usize), -} - -impl Default for RegType { - fn default() -> Self { - RegType::Temp(0) - } -} - -impl RegType { - pub fn reg_num(self) -> usize { - match self { - RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num, - } - } - - pub fn is_perm(self) -> bool { - matches!(self, RegType::Perm(_)) - } -} - -impl fmt::Display for RegType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - RegType::Perm(val) => write!(f, "Y{}", val), - RegType::Temp(val) => write!(f, "X{}", val), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum VarReg { - ArgAndNorm(RegType, usize), - Norm(RegType), -} - -impl VarReg { - pub fn norm(self) -> RegType { - match self { - VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg, - } - } -} - -impl fmt::Display for VarReg { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg), - VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg), - VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg), - VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg), - } - } -} - -impl Default for VarReg { - fn default() -> Self { - VarReg::Norm(RegType::default()) - } -} - -#[macro_export] -macro_rules! temp_v { - ($x:expr) => { - $crate::ast::RegType::Temp($x) - }; -} - -#[macro_export] -macro_rules! perm_v { - ($x:expr) => { - $crate::ast::RegType::Perm($x) - }; -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub enum GenContext { - Head, - Mid(usize), - Last(usize), // Mid & Last: chunk_num -} - -impl GenContext { - pub fn chunk_num(self) -> usize { - match self { - GenContext::Head => 0, - GenContext::Mid(cn) | GenContext::Last(cn) => cn, - } - } -} - -pub type OpDirKey = (ClauseName, Fixity); - -#[derive(Debug, Clone)] -pub struct OpDirValue(pub SharedOpDesc); - -impl OpDirValue { - pub fn new(spec: Specifier, priority: usize) -> Self { - OpDirValue(SharedOpDesc::new(priority, spec)) - } - - #[inline] - pub fn shared_op_desc(&self) -> SharedOpDesc { - self.0.clone() - } -} - -// name and fixity -> operator type and precedence. -pub type OpDir = IndexMap; - -#[derive(Debug, Clone, Copy)] -pub struct MachineFlags { - pub double_quotes: DoubleQuotes, -} - -impl Default for MachineFlags { - fn default() -> Self { - MachineFlags { - double_quotes: DoubleQuotes::default(), - } - } -} - -#[derive(Debug, Clone, Copy)] -pub enum DoubleQuotes { - Atom, - Chars, - Codes, -} - -impl DoubleQuotes { - pub fn is_chars(self) -> bool { - matches!(self, DoubleQuotes::Chars) - } - - pub fn is_atom(self) -> bool { - matches!(self, DoubleQuotes::Atom) - } - - pub fn is_codes(self) -> bool { - matches!(self, DoubleQuotes::Codes) - } -} - -impl Default for DoubleQuotes { - fn default() -> Self { - DoubleQuotes::Chars - } -} - -pub fn default_op_dir() -> OpDir { - let mut op_dir = OpDir::new(); - - op_dir.insert((clause_name!(":-"), Fixity::In), OpDirValue::new(XFX, 1200)); - op_dir.insert((clause_name!(":-"), Fixity::Pre), OpDirValue::new(FX, 1200)); - op_dir.insert((clause_name!("?-"), Fixity::Pre), OpDirValue::new(FX, 1200)); - op_dir.insert((clause_name!(","), Fixity::In), OpDirValue::new(XFY, 1000)); - - op_dir -} - -#[derive(Debug, Clone)] -pub enum ArithmeticError { - NonEvaluableFunctor(Constant, usize), - UninstantiatedVar, -} - -#[derive(Debug)] -pub enum ParserError { - BackQuotedString(usize, usize), - UnexpectedChar(char, usize, usize), - UnexpectedEOF, - IO(IOError), - IncompleteReduction(usize, usize), - InvalidSingleQuotedCharacter(char), - MissingQuote(usize, usize), - NonPrologChar(usize, usize), - ParseBigInt(usize, usize), - Utf8Error(usize, usize), -} - -impl ParserError { - pub fn line_and_col_num(&self) -> Option<(usize, usize)> { - match self { - &ParserError::BackQuotedString(line_num, col_num) - | &ParserError::UnexpectedChar(_, line_num, col_num) - | &ParserError::IncompleteReduction(line_num, col_num) - | &ParserError::MissingQuote(line_num, col_num) - | &ParserError::NonPrologChar(line_num, col_num) - | &ParserError::ParseBigInt(line_num, col_num) - | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)), - _ => None, - } - } - - pub fn as_str(&self) -> &'static str { - match self { - ParserError::BackQuotedString(..) => "back_quoted_string", - ParserError::UnexpectedChar(..) => "unexpected_char", - ParserError::UnexpectedEOF => "unexpected_end_of_file", - ParserError::IncompleteReduction(..) => "incomplete_reduction", - ParserError::InvalidSingleQuotedCharacter(..) => "invalid_single_quoted_character", - ParserError::IO(_) => "input_output_error", - ParserError::MissingQuote(..) => "missing_quote", - ParserError::NonPrologChar(..) => "non_prolog_character", - ParserError::ParseBigInt(..) => "cannot_parse_big_int", - ParserError::Utf8Error(..) => "utf8_conversion_error", - } - } -} - -impl From for ParserError { - fn from(err: IOError) -> ParserError { - ParserError::IO(err) - } -} - -impl From<&IOError> for ParserError { - fn from(error: &IOError) -> ParserError { - if error.get_ref().filter(|e| e.is::()).is_some() { - ParserError::Utf8Error(0, 0) - } else { - ParserError::IO(error.kind().into()) - } - } -} - -#[derive(Debug, Clone, Copy)] -pub struct CompositeOpDir<'a, 'b> { - pub primary_op_dir: Option<&'b OpDir>, - pub secondary_op_dir: &'a OpDir, -} - -impl<'a, 'b> CompositeOpDir<'a, 'b> { - #[inline] - pub fn new(secondary_op_dir: &'a OpDir, primary_op_dir: Option<&'b OpDir>) -> Self { - CompositeOpDir { - primary_op_dir, - secondary_op_dir, - } - } - - #[inline] - pub(crate) fn get(&self, name: ClauseName, fixity: Fixity) -> Option<&OpDirValue> { - let entry = if let Some(ref primary_op_dir) = &self.primary_op_dir { - primary_op_dir.get(&(name.clone(), fixity)) - } else { - None - }; - - entry.or_else(move || self.secondary_op_dir.get(&(name, fixity))) - } -} - -#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)] -pub enum Fixity { - In, - Post, - Pre, -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct SharedOpDesc(Rc>); - -impl SharedOpDesc { - #[inline] - pub fn new(priority: usize, spec: Specifier) -> Self { - SharedOpDesc(Rc::new(Cell::new((priority, spec)))) - } - - #[inline] - pub fn ptr_eq(lop_desc: &SharedOpDesc, rop_desc: &SharedOpDesc) -> bool { - Rc::ptr_eq(&lop_desc.0, &rop_desc.0) - } - - #[inline] - pub fn arity(&self) -> usize { - if self.get().1 & (XFX | XFY | YFX) == 0 { - 1 - } else { - 2 - } - } - - #[inline] - pub fn get(&self) -> (usize, Specifier) { - self.0.get() - } - - #[inline] - pub fn set(&self, prec: usize, spec: Specifier) { - self.0.set((prec, spec)); - } - - #[inline] - pub fn prec(&self) -> usize { - self.0.get().0 - } - - #[inline] - pub fn assoc(&self) -> Specifier { - self.0.get().1 - } -} - -impl Deref for SharedOpDesc { - type Target = Cell<(usize, Specifier)>; - - #[inline] - fn deref(&self) -> &Self::Target { - self.0.deref() - } -} - -// this ensures that SharedOpDesc (which is not consistently placed in -// every atom!) doesn't affect the value of an atom hash. If -// SharedOpDesc values are to be indexed, a BTreeMap or BTreeSet -// should be used, obviously. -impl Hash for SharedOpDesc { - fn hash(&self, state: &mut H) { - 0.hash(state) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Constant { - Atom(ClauseName, Option), - Char(char), - EmptyList, - Fixnum(isize), - Integer(Rc), - Rational(Rc), - Float(OrderedFloat), - String(Rc), - Usize(usize), -} - -impl fmt::Display for Constant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Constant::Atom(ref atom, _) => { - if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) { - write!(f, "'{}'", atom.as_str()) - } else { - write!(f, "{}", atom.as_str()) - } - } - Constant::Char(c) => write!(f, "'{}'", *c as u32), - Constant::EmptyList => write!(f, "[]"), - Constant::Fixnum(n) => write!(f, "{}", n), - Constant::Integer(ref n) => write!(f, "{}", n), - Constant::Rational(ref n) => write!(f, "{}", n), - Constant::Float(ref n) => write!(f, "{}", n), - Constant::String(ref s) => write!(f, "\"{}\"", &s), - Constant::Usize(integer) => write!(f, "u{}", integer), - } - } -} - -impl Constant { - pub fn to_atom(&self) -> Option { - match self { - Constant::Atom(a, _) => Some(a.defrock_brackets()), - _ => None, - } - } -} - -#[derive(Debug, Clone)] -pub enum ClauseName { - BuiltIn(&'static str), - User(TabledRc), -} - -impl fmt::Display for ClauseName { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -impl Hash for ClauseName { - fn hash(&self, state: &mut H) { - (*self.as_str()).hash(state) - } -} - -impl PartialEq for ClauseName { - fn eq(&self, other: &ClauseName) -> bool { - *self.as_str() == *other.as_str() - } -} - -impl Eq for ClauseName {} - -impl Ord for ClauseName { - fn cmp(&self, other: &ClauseName) -> Ordering { - (*self.as_str()).cmp(other.as_str()) - } -} - -impl PartialOrd for ClauseName { - fn partial_cmp(&self, other: &ClauseName) -> Option { - Some(self.cmp(other)) - } -} - -impl<'a> From<&'a TabledRc> for ClauseName { - fn from(name: &'a TabledRc) -> ClauseName { - ClauseName::User(name.clone()) - } -} - -impl ClauseName { - #[inline] - pub fn owning_module(&self) -> Self { - match self { - ClauseName::User(ref name) => { - let module = name.owning_module(); - ClauseName::User(TabledRc { - atom: module.clone(), - table: TabledData::new(module), - }) - } - _ => clause_name!("user"), - } - } - - #[inline] - pub fn to_rc(&self) -> Rc { - match self { - ClauseName::BuiltIn(s) => Rc::new(s.to_string()), - ClauseName::User(ref rc) => rc.inner(), - } - } - - #[inline] - pub fn with_table(self, atom_tbl: TabledData) -> Self { - match self { - ClauseName::BuiltIn(_) => self, - ClauseName::User(mut name) => { - name.table = atom_tbl; - ClauseName::User(name) - } - } - } - - #[inline] - pub fn has_table(&self, atom_tbl: &TabledData) -> bool { - match self { - ClauseName::BuiltIn(_) => false, - ClauseName::User(ref name) => &name.table == atom_tbl, - } - } - - #[inline] - pub fn has_table_of(&self, other: &ClauseName) -> bool { - match self { - ClauseName::BuiltIn(_) => { - matches!(other, ClauseName::BuiltIn(_)) - } - ClauseName::User(ref name) => other.has_table(&name.table), - } - } - - #[inline] - pub fn as_str(&self) -> &str { - match self { - ClauseName::BuiltIn(s) => s, - ClauseName::User(ref name) => name.as_ref(), - } - } - - #[inline] - pub fn is_char(&self) -> bool { - !self.as_str().is_empty() && self.as_str().chars().nth(1).is_none() - } - - pub fn defrock_brackets(&self) -> Self { - fn defrock_brackets(s: &str) -> &str { - if s.starts_with('(') && s.ends_with(')') { - &s[1..s.len() - 1] - } else { - s - } - } - - match self { - ClauseName::BuiltIn(s) => ClauseName::BuiltIn(defrock_brackets(s)), - ClauseName::User(s) => { - ClauseName::User(tabled_rc!(defrock_brackets(s.as_str()).to_owned(), s.table)) - } - } - } -} - -impl AsRef for ClauseName { - #[inline] - fn as_ref(&self) -> &str { - self.as_str() - } -} - -#[derive(Debug, Clone)] -pub enum Term { - AnonVar, - Clause( - Cell, - ClauseName, - Vec>, - Option, - ), - Cons(Cell, Box, Box), - Constant(Cell, Constant), - Var(Cell, Rc), -} - -impl Term { - pub fn shared_op_desc(&self) -> Option { - match self { - Term::Clause(_, _, _, ref spec) => spec.clone(), - Term::Constant(_, Constant::Atom(_, ref spec)) => spec.clone(), - _ => None, - } - } - - pub fn into_constant(self) -> Option { - match self { - Term::Constant(_, c) => Some(c), - _ => None, - } - } - - pub fn first_arg(&self) -> Option<&Term> { - match self { - Term::Clause(_, _, ref terms, _) => terms.first().map(|bt| bt.as_ref()), - _ => None, - } - } - - pub fn set_name(&mut self, new_name: ClauseName) { - match self { - Term::Constant(_, Constant::Atom(ref mut atom, _)) - | Term::Clause(_, ref mut atom, ..) => { - *atom = new_name; - } - _ => {} - } - } - - pub fn name(&self) -> Option { - match self { - &Term::Constant(_, Constant::Atom(ref atom, _)) | &Term::Clause(_, ref atom, ..) => { - Some(atom.clone()) - } - _ => None, - } - } - - pub fn arity(&self) -> usize { - match self { - Term::Clause(_, _, ref child_terms, ..) => child_terms.len(), - _ => 0, - } - } -} - -fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)> { - if let Term::Clause(_, ref name, ref mut subterms, _) = term { - if name.as_str() == s && subterms.len() == 2 { - let snd = *subterms.pop().unwrap(); - let fst = *subterms.pop().unwrap(); - - return Some((fst, snd)); - } - } - - None -} - -pub fn unfold_by_str(mut term: Term, s: &str) -> Vec { - let mut terms = vec![]; - - while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) { - terms.push(fst); - term = snd; - } - - terms.push(term); - terms -} - -pub type ParsingStream = PutBackN>>; - -use unicode_reader::BadUtf8Error; - -#[inline] -pub fn parsing_stream(src: R) -> Result, ParserError> { - let mut stream = put_back_n(CodePoints::from(src.bytes())); - match stream.peek() { - None => Ok(stream), // empty stream is handled gracefully by Lexer::eof - Some(Err(error)) => Err(ParserError::from(error)), - Some(Ok(c)) => { - if *c == '\u{feff}' { - // skip UTF-8 BOM - stream.next(); - } - Ok(stream) - } - } -} diff --git a/crates/prolog_parser/src/lexer.rs b/crates/prolog_parser/src/lexer.rs deleted file mode 100644 index 8be50d36..00000000 --- a/crates/prolog_parser/src/lexer.rs +++ /dev/null @@ -1,912 +0,0 @@ -use crate::rug::Integer; -use lexical::parse_lossy; -use ordered_float::*; - -use crate::ast::*; -use crate::tabled_rc::*; - -use std::convert::TryFrom; -use std::fmt; -use std::io::Read; -use std::rc::Rc; - -macro_rules! is_not_eof { - ($c:expr) => { - match $c { - Ok(c) => c, - Err($crate::ast::ParserError::UnexpectedEOF) => return Ok(true), - Err(e) => return Err(e), - } - }; -} - -macro_rules! consume_chars_with { - ($token:expr, $e:expr) => { - loop { - match $e { - Ok(Some(c)) => $token.push(c), - Ok(None) => continue, - Err($crate::ast::ParserError::UnexpectedChar(..)) => break, - Err(e) => return Err(e), - } - } - }; -} - -#[derive(Debug, Clone, PartialEq)] -pub enum Token { - Constant(Constant), - Var(Rc), - Open, // '(' - OpenCT, // '(' - Close, // ')' - OpenList, // '[' - CloseList, // ']' - OpenCurly, // '{' - CloseCurly, // '}' - HeadTailSeparator, // '|' - Comma, // ',' - End, -} - -impl Token { - #[inline] - pub(super) fn is_end(&self) -> bool { - if let Token::End = self { - true - } else { - false - } - } -} - -pub struct Lexer<'a, R: Read> { - pub(crate) atom_tbl: TabledData, - pub(crate) reader: &'a mut ParsingStream, - pub(crate) flags: MachineFlags, - pub(crate) line_num: usize, - pub(crate) col_num: usize, -} - -impl<'a, R: Read + fmt::Debug> fmt::Debug for Lexer<'a, R> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Lexer") - .field("atom_tbl", &self.atom_tbl) - .field("reader", &"&'a mut ParsingStream") // Hacky solution. - .field("line_num", &self.line_num) - .field("col_num", &self.col_num) - .finish() - } -} - -impl<'a, R: Read> Lexer<'a, R> { - pub fn new( - atom_tbl: TabledData, - flags: MachineFlags, - src: &'a mut ParsingStream, - ) -> Self { - Lexer { - atom_tbl, - flags, - reader: src, - line_num: 0, - col_num: 0, - } - } - - fn return_char(&mut self, c: char) { - if new_line_char!(c) { - self.line_num -= 1; - self.col_num = 0; - } - - self.reader.put_back(Ok(c)); - } - - fn skip_char(&mut self) -> Result { - if let Some(Ok(c)) = self.reader.next() { - self.col_num += 1; - - if new_line_char!(c) { - self.line_num += 1; - self.col_num = 0; - } - - Ok(c) - } else { - Err(ParserError::UnexpectedEOF) - } - } - - pub fn eof(&mut self) -> Result { - if self.reader.peek().is_none() { - return Ok(true); - } - - let mut c = is_not_eof!(self.lookahead_char()); - - while layout_char!(c) { - self.skip_char()?; - - if self.reader.peek().is_none() { - return Ok(true); - } - - c = is_not_eof!(self.lookahead_char()); - } - - Ok(false) - } - - pub fn lookahead_char(&mut self) -> Result { - match self.reader.peek() { - Some(&Ok(c)) => Ok(c), - _ => Err(ParserError::UnexpectedEOF), - } - } - - fn single_line_comment(&mut self) -> Result<(), ParserError> { - loop { - if self.reader.peek().is_none() || new_line_char!(self.skip_char()?) { - break; - } - } - - Ok(()) - } - - fn bracketed_comment(&mut self) -> Result { - // we have already checked that the current lookahead_char is comment_1_char, just skip it - let c = self.skip_char()?; - - if comment_2_char!(self.lookahead_char()?) { - self.skip_char()?; - - // Keep reading until we find characters '*' and '/' - // Deliberately skip checks for prolog_char to allow comments to contain any characters, - // including so-called "extended characters", without having to explicitly add them to a character class. - let mut c = self.lookahead_char()?; - loop { - while !comment_2_char!(c) { - self.skip_char()?; - c = self.lookahead_char()?; - } - - self.skip_char()?; - - c = self.lookahead_char()?; - if comment_1_char!(c) { - break; - } - } - - if prolog_char!(c) { - self.skip_char()?; - Ok(true) - } else { - Err(ParserError::NonPrologChar(self.line_num, self.col_num)) - } - } else { - self.return_char(c); - Ok(false) - } - } - - fn get_back_quoted_char(&mut self) -> Result { - if back_quote_char!(self.lookahead_char()?) { - let c = self.skip_char()?; - - if !back_quote_char!(self.lookahead_char()?) { - self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) - } else { - self.skip_char() - } - } else if single_quote_char!(self.lookahead_char()?) { - self.skip_char() - } else { - self.get_non_quote_char() - } - } - - fn get_back_quoted_item(&mut self) -> Result, ParserError> { - if backslash_char!(self.lookahead_char()?) { - let c = self.skip_char()?; - - if new_line_char!(self.lookahead_char()?) { - self.skip_char()?; - Ok(None) - } else { - self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) - } - } else { - self.get_back_quoted_char().map(Some) - } - } - - fn get_back_quoted_string(&mut self) -> Result { - let c = self.lookahead_char()?; - - if back_quote_char!(c) { - self.skip_char()?; - - let mut token = String::new(); - consume_chars_with!(token, self.get_back_quoted_item()); - - if back_quote_char!(self.lookahead_char()?) { - self.skip_char()?; - Ok(token) - } else { - Err(ParserError::MissingQuote(self.line_num, self.col_num)) - } - } else { - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) - } - } - - fn get_single_quoted_item(&mut self) -> Result, ParserError> { - if backslash_char!(self.lookahead_char()?) { - let c = self.skip_char()?; - - if new_line_char!(self.lookahead_char()?) { - self.skip_char()?; - return Ok(None); - } else { - self.return_char(c); - } - } - - self.get_single_quoted_char().map(Some) - } - - fn get_single_quoted_char(&mut self) -> Result { - let c = self.lookahead_char()?; - - if single_quote_char!(c) { - self.skip_char()?; - - if !single_quote_char!(self.lookahead_char()?) { - self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) - } else { - self.skip_char() - } - } else if double_quote_char!(c) || back_quote_char!(c) { - self.skip_char() - } else { - self.get_non_quote_char() - } - } - - fn get_double_quoted_item(&mut self) -> Result, ParserError> { - if backslash_char!(self.lookahead_char()?) { - let c = self.skip_char()?; - - if new_line_char!(self.lookahead_char()?) { - self.skip_char()?; - return Ok(None); - } else { - self.return_char(c); - } - } - - self.get_double_quoted_char().map(Some) - } - - fn get_double_quoted_char(&mut self) -> Result { - if double_quote_char!(self.lookahead_char()?) { - let c = self.skip_char()?; - - if !double_quote_char!(self.lookahead_char()?) { - self.return_char(c); - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) - } else { - self.skip_char() - } - } else if single_quote_char!(self.lookahead_char()?) { - self.skip_char() - } else if back_quote_char!(self.lookahead_char()?) { - self.skip_char() - } else { - self.get_non_quote_char() - } - } - - fn get_control_escape_sequence(&mut self) -> Result { - let escaped = match self.lookahead_char()? { - 'a' => '\u{07}', // UTF-8 alert - 'b' => '\u{08}', // UTF-8 backspace - 'v' => '\u{0b}', // UTF-8 vertical tab - 'f' => '\u{0c}', // UTF-8 form feed - 't' => '\t', - 'n' => '\n', - 'r' => '\r', - c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)), - }; - - self.skip_char()?; - return Ok(escaped); - } - - fn get_octal_escape_sequence(&mut self) -> Result { - self.escape_sequence_to_char(|c| octal_digit_char!(c), 8) - } - - fn get_hexadecimal_escape_sequence(&mut self) -> Result { - self.skip_char()?; - let c = self.lookahead_char()?; - - if hexadecimal_digit_char!(c) { - self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16) - } else { - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) - } - } - - fn escape_sequence_to_char( - &mut self, - accept_char: impl Fn(char) -> bool, - radix: u32, - ) -> Result { - let mut c = self.lookahead_char()?; - let mut token = String::new(); - - loop { - token.push(c); - - self.skip_char()?; - c = self.lookahead_char()?; - - if !accept_char(c) { - break; - } - } - - if backslash_char!(c) { - self.skip_char()?; - u32::from_str_radix(&token, radix).map_or_else( - |_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)), - |n| { - char::try_from(n) - .map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num)) - }, - ) - } else { - // on failure, restore the token characters and backslash. - self.reader.put_back_all(token.chars().map(Ok)); - self.reader.put_back(Ok('\\')); - - Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) - } - } - - fn get_non_quote_char(&mut self) -> Result { - let c = self.lookahead_char()?; - - if graphic_char!(c) || alpha_numeric_char!(c) || solo_char!(c) || space_char!(c) { - self.skip_char() - } else { - if !backslash_char!(c) { - return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)); - } - - self.skip_char()?; - - let c = self.lookahead_char()?; - - if meta_char!(c) { - self.skip_char() - } else if octal_digit_char!(c) { - self.get_octal_escape_sequence() - } else if symbolic_hexadecimal_char!(c) { - self.get_hexadecimal_escape_sequence() - } else { - self.get_control_escape_sequence() - } - } - } - - fn char_code_list_token(&mut self) -> Result { - let mut token = String::new(); - - self.skip_char()?; - consume_chars_with!(token, self.get_double_quoted_item()); - - if double_quote_char!(self.lookahead_char()?) { - self.skip_char()?; - Ok(token) - } else { - Err(ParserError::MissingQuote(self.line_num, self.col_num)) - } - } - - fn hexadecimal_constant(&mut self) -> Result { - self.skip_char()?; - - if hexadecimal_digit_char!(self.lookahead_char()?) { - let mut token = String::new(); - - while hexadecimal_digit_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); - } - - isize::from_str_radix(&token, 16) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - Integer::from_str_radix(&token, 16) - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) - }) - } else { - self.return_char('x'); - Err(ParserError::ParseBigInt(self.line_num, self.col_num)) - } - } - - fn octal_constant(&mut self) -> Result { - self.skip_char()?; - - if octal_digit_char!(self.lookahead_char()?) { - let mut token = String::new(); - - while octal_digit_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); - } - - isize::from_str_radix(&token, 8) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - Integer::from_str_radix(&token, 8) - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) - }) - } else { - self.return_char('o'); - Err(ParserError::ParseBigInt(self.line_num, self.col_num)) - } - } - - fn binary_constant(&mut self) -> Result { - self.skip_char()?; - - if binary_digit_char!(self.lookahead_char()?) { - let mut token = String::new(); - - while binary_digit_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); - } - - isize::from_str_radix(&token, 2) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - Integer::from_str_radix(&token, 2) - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) - }) - } else { - self.return_char('b'); - Err(ParserError::ParseBigInt(self.line_num, self.col_num)) - } - } - - fn variable_token(&mut self) -> Result { - let mut s = String::new(); - s.push(self.skip_char()?); - - while alpha_numeric_char!(self.lookahead_char()?) { - s.push(self.skip_char()?); - } - - Ok(Token::Var(rc_atom!(s))) - } - - fn name_token(&mut self, c: char) -> Result { - let mut token = String::new(); - - if small_letter_char!(c) { - token.push(self.skip_char()?); - - while alpha_numeric_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); - } - } else if graphic_token_char!(c) { - token.push(self.skip_char()?); - - while graphic_token_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); - } - } else if cut_char!(c) { - token.push(self.skip_char()?); - } else if semicolon_char!(c) { - token.push(self.skip_char()?); - } else if single_quote_char!(c) { - self.skip_char()?; - - consume_chars_with!(token, self.get_single_quoted_item()); - - if single_quote_char!(self.lookahead_char()?) { - self.skip_char()?; - - if !token.is_empty() && token.chars().nth(1).is_none() { - if let Some(c) = token.chars().next() { - return Ok(Token::Constant(Constant::Char(c))); - } - } - } else { - return Err(ParserError::InvalidSingleQuotedCharacter( - self.lookahead_char()?, - )); - } - } else { - match self.get_back_quoted_string() { - Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)), - Err(e) => return Err(e), - } - } - - if token.as_str() == "[]" { - Ok(Token::Constant(Constant::EmptyList)) - } else { - Ok(Token::Constant(atom!(token, self.atom_tbl))) - } - } - - fn vacate_with_float(&mut self, mut token: String) -> Token { - self.return_char(token.pop().unwrap()); - - let result = OrderedFloat(parse_lossy::(token.as_bytes()).unwrap()); - Token::Constant(Constant::Float(result)) - } - - fn skip_underscore_in_number(&mut self) -> Result { - let mut c = self.lookahead_char()?; - - if c == '_' { - self.skip_char()?; - self.scan_for_layout()?; - c = self.lookahead_char()?; - - if decimal_digit_char!(c) { - Ok(c) - } else { - Err(ParserError::ParseBigInt(self.line_num, self.col_num)) - } - } else { - Ok(c) - } - } - - pub fn number_token(&mut self) -> Result { - let mut token = String::new(); - - token.push(self.skip_char()?); - let mut c = self.skip_underscore_in_number()?; - - while decimal_digit_char!(c) { - token.push(c); - self.skip_char()?; - c = self.skip_underscore_in_number()?; - } - - if decimal_point_char!(c) { - self.skip_char()?; - - if self.reader.peek().is_none() { - self.return_char('.'); - - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - token - .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) - }) - } else if decimal_digit_char!(self.lookahead_char()?) { - token.push('.'); - token.push(self.skip_char()?); - - let mut c = self.lookahead_char()?; - - while decimal_digit_char!(c) { - token.push(c); - self.skip_char()?; - c = self.lookahead_char()?; - } - - if exponent_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); - - let c = match self.lookahead_char() { - Err(_) => return Ok(self.vacate_with_float(token)), - Ok(c) => c, - }; - - if !sign_char!(c) && !decimal_digit_char!(c) { - return Ok(self.vacate_with_float(token)); - } - - if sign_char!(c) { - token.push(self.skip_char()?); - - let c = match self.lookahead_char() { - Err(_) => { - self.return_char(token.pop().unwrap()); - return Ok(self.vacate_with_float(token)); - } - Ok(c) => c, - }; - - if !decimal_digit_char!(c) { - self.return_char(token.pop().unwrap()); - return Ok(self.vacate_with_float(token)); - } - } - - if decimal_digit_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); - - while decimal_digit_char!(self.lookahead_char()?) { - token.push(self.skip_char()?); - } - - let n = OrderedFloat(parse_lossy::(token.as_bytes()).unwrap()); - Ok(Token::Constant(Constant::Float(n))) - } else { - return Ok(self.vacate_with_float(token)); - } - } else { - let n = OrderedFloat(parse_lossy::(token.as_bytes()).unwrap()); - Ok(Token::Constant(Constant::Float(n))) - } - } else { - self.return_char('.'); - - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - token - .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) - }) - } - } else { - if token.starts_with('0') && token.len() == 1 { - if c == 'x' { - self.hexadecimal_constant().or_else(|e| { - if let ParserError::ParseBigInt(..) = e { - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - token - .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| { - ParserError::ParseBigInt(self.line_num, self.col_num) - }) - }) - } else { - Err(e) - } - }) - } else if c == 'o' { - self.octal_constant().or_else(|e| { - if let ParserError::ParseBigInt(..) = e { - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - token - .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| { - ParserError::ParseBigInt(self.line_num, self.col_num) - }) - }) - } else { - Err(e) - } - }) - } else if c == 'b' { - self.binary_constant().or_else(|e| { - if let ParserError::ParseBigInt(..) = e { - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - token - .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| { - ParserError::ParseBigInt(self.line_num, self.col_num) - }) - }) - } else { - Err(e) - } - }) - } else if single_quote_char!(c) { - self.skip_char()?; - - if backslash_char!(self.lookahead_char()?) { - self.skip_char()?; - - if new_line_char!(self.lookahead_char()?) { - self.return_char('\\'); - self.return_char('\''); - - return Ok(Token::Constant(Constant::Fixnum(0))); - } else { - self.return_char('\\'); - } - } - - self.get_single_quoted_char() - .map(|c| Token::Constant(Constant::Fixnum(c as isize))) - .or_else(|_| { - self.return_char(c); - - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - token - .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| { - ParserError::ParseBigInt(self.line_num, self.col_num) - }) - }) - }) - } else { - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - token - .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) - }) - } - } else { - isize::from_str_radix(&token, 10) - .map(|n| Token::Constant(Constant::Fixnum(n))) - .or_else(|_| { - token - .parse::() - .map(|n| Token::Constant(Constant::Integer(Rc::new(n)))) - .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) - }) - } - } - } - - pub fn scan_for_layout(&mut self) -> Result { - let mut layout_inserted = false; - let mut more_layout = true; - - loop { - let cr = self.lookahead_char(); - - match cr { - Ok(c) if layout_char!(c) => { - self.skip_char()?; - layout_inserted = true; - } - Ok(c) if end_line_comment_char!(c) => { - self.single_line_comment()?; - layout_inserted = true; - } - Ok(c) if comment_1_char!(c) => { - if self.bracketed_comment()? { - layout_inserted = true; - } else { - more_layout = false; - } - } - _ => more_layout = false, - }; - - if !more_layout { - break; - } - } - - Ok(layout_inserted) - } - - pub fn next_token(&mut self) -> Result { - let layout_inserted = self.scan_for_layout()?; - let cr = self.lookahead_char(); - - match cr { - Ok(c) => { - if capital_letter_char!(c) || variable_indicator_char!(c) { - return self.variable_token(); - } - - if c == ',' { - self.skip_char()?; - return Ok(Token::Comma); - } - - if c == ')' { - self.skip_char()?; - return Ok(Token::Close); - } - - if c == '(' { - self.skip_char()?; - return Ok(if layout_inserted { - Token::Open - } else { - Token::OpenCT - }); - } - - if c == '.' { - self.skip_char()?; - - match self.lookahead_char() { - Ok(c) if layout_char!(c) || c == '%' => { - if new_line_char!(c) { - self.skip_char()?; - } - - return Ok(Token::End); - } - Err(ParserError::UnexpectedEOF) => { - return Ok(Token::End); - } - _ => { - self.return_char('.'); - } - }; - } - - if decimal_digit_char!(c) { - return self.number_token(); - } - - if c == ']' { - self.skip_char()?; - return Ok(Token::CloseList); - } - - if c == '[' { - self.skip_char()?; - return Ok(Token::OpenList); - } - - if c == '|' { - self.skip_char()?; - return Ok(Token::HeadTailSeparator); - } - - if c == '{' { - self.skip_char()?; - return Ok(Token::OpenCurly); - } - - if c == '}' { - self.skip_char()?; - return Ok(Token::CloseCurly); - } - - if c == '"' { - let s = self.char_code_list_token()?; - - if let DoubleQuotes::Atom = self.flags.double_quotes { - let s = clause_name!(s, self.atom_tbl); - return Ok(Token::Constant(Constant::Atom(s, None))); - } else { - let s = Rc::new(s); - return Ok(Token::Constant(Constant::String(s))); - } - } - - self.name_token(c) - } - Err(e) => Err(e), - } - } -} diff --git a/crates/prolog_parser/src/lib.rs b/crates/prolog_parser/src/lib.rs deleted file mode 100644 index 2c37cea6..00000000 --- a/crates/prolog_parser/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[cfg(feature = "num-rug-adapter")] -use num_rug_adapter as rug; -#[cfg(feature = "rug")] -use rug; - -#[macro_use] -pub mod tabled_rc; -#[macro_use] -pub mod ast; -#[macro_use] -pub mod macros; -pub mod parser; -pub mod put_back_n; - -pub mod lexer; diff --git a/crates/prolog_parser/src/macros.rs b/crates/prolog_parser/src/macros.rs deleted file mode 100644 index f8ec9072..00000000 --- a/crates/prolog_parser/src/macros.rs +++ /dev/null @@ -1,253 +0,0 @@ -#[macro_export] -macro_rules! char_class { - ($c: expr, [$head:expr]) => ($c == $head); - ($c: expr, [$head:expr $(, $cs:expr)+]) => ($c == $head || $crate::char_class!($c, [$($cs),*])); -} - -#[macro_export] -macro_rules! alpha_char { - ($c: expr) => { - match $c { - 'a'..='z' => true, - 'A'..='Z' => true, - '_' => true, - '\u{00A0}'..='\u{00BF}' => true, - '\u{00C0}'..='\u{00D6}' => true, - '\u{00D8}'..='\u{00F6}' => true, - '\u{00F8}'..='\u{00FF}' => true, - '\u{0100}'..='\u{017F}' => true, // Latin Extended-A - '\u{0180}'..='\u{024F}' => true, // Latin Extended-B - '\u{0250}'..='\u{02AF}' => true, // IPA Extensions - '\u{02B0}'..='\u{02FF}' => true, // Spacing Modifier Letters - '\u{0300}'..='\u{036F}' => true, // Combining Diacritical Marks - '\u{0370}'..='\u{03FF}' => true, // Greek/Coptic - '\u{0400}'..='\u{04FF}' => true, // Cyrillic - '\u{0500}'..='\u{052F}' => true, // Cyrillic Supplement - '\u{0530}'..='\u{058F}' => true, // Armenian - '\u{0590}'..='\u{05FF}' => true, // Hebrew - '\u{0600}'..='\u{06FF}' => true, // Arabic - '\u{0700}'..='\u{074F}' => true, // Syriac - _ => false, - } - }; -} - -#[macro_export] -macro_rules! alpha_numeric_char { - ($c: expr) => { - $crate::alpha_char!($c) || $crate::decimal_digit_char!($c) - }; -} - -#[macro_export] -macro_rules! backslash_char { - ($c: expr) => { - $c == '\\' - }; -} - -#[macro_export] -macro_rules! back_quote_char { - ($c: expr) => { - $c == '`' - }; -} - -#[macro_export] -macro_rules! binary_digit_char { - ($c: expr) => { - $c >= '0' && $c <= '1' - }; -} - -#[macro_export] -macro_rules! capital_letter_char { - ($c: expr) => { - ('A'..='Z').contains(&$c) - }; -} - -#[macro_export] -macro_rules! comment_1_char { - ($c: expr) => { - $c == '/' - }; -} - -#[macro_export] -macro_rules! comment_2_char { - ($c: expr) => { - $c == '*' - }; -} - -#[macro_export] -macro_rules! cut_char { - ($c: expr) => { - $c == '!' - }; -} - -#[macro_export] -macro_rules! decimal_digit_char { - ($c: expr) => { - ('0'..='9').contains(&$c) - }; -} - -#[macro_export] -macro_rules! decimal_point_char { - ($c: expr) => { - $c == '.' - }; -} - -#[macro_export] -macro_rules! double_quote_char { - ($c: expr) => { - $c == '"' - }; -} - -#[macro_export] -macro_rules! end_line_comment_char { - ($c: expr) => { - $c == '%' - }; -} - -#[macro_export] -macro_rules! exponent_char { - ($c: expr) => { - $c == 'e' || $c == 'E' - }; -} - -#[macro_export] -macro_rules! graphic_char { - ($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':', - '<', '=', '>', '?', '@', '^', '~'])) -} - -#[macro_export] -macro_rules! graphic_token_char { - ($c: expr) => { - $crate::graphic_char!($c) || $crate::backslash_char!($c) - }; -} - -#[macro_export] -macro_rules! hexadecimal_digit_char { - ($c: expr) => { - ('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c) - }; -} - -#[macro_export] -macro_rules! layout_char { - ($c: expr) => { - $crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}']) - }; -} - -#[macro_export] -macro_rules! meta_char { - ($c: expr) => { - $crate::char_class!($c, ['\\', '\'', '"', '`']) - }; -} - -#[macro_export] -macro_rules! new_line_char { - ($c: expr) => { - $c == '\n' - }; -} - -#[macro_export] -macro_rules! octal_digit_char { - ($c: expr) => { - ('0'..='7').contains(&$c) - }; -} - -#[macro_export] -macro_rules! octet_char { - ($c: expr) => { - ('\u{0000}'..='\u{00FF}').contains(&$c) - }; -} - -#[macro_export] -macro_rules! prolog_char { - ($c: expr) => { - $crate::graphic_char!($c) - || $crate::alpha_numeric_char!($c) - || $crate::solo_char!($c) - || $crate::layout_char!($c) - || $crate::meta_char!($c) - }; -} - -#[macro_export] -macro_rules! semicolon_char { - ($c: expr) => { - $c == ';' - }; -} - -#[macro_export] -macro_rules! sign_char { - ($c: expr) => { - $c == '-' || $c == '+' - }; -} - -#[macro_export] -macro_rules! single_quote_char { - ($c: expr) => { - $c == '\'' - }; -} - -#[macro_export] -macro_rules! small_letter_char { - ($c: expr) => { - ('a'..='z').contains(&$c) - }; -} - -#[macro_export] -macro_rules! solo_char { - ($c: expr) => { - $crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%']) - }; -} - -#[macro_export] -macro_rules! space_char { - ($c: expr) => { - $c == ' ' - }; -} - -#[macro_export] -macro_rules! symbolic_control_char { - ($c: expr) => { - $crate::char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0']) - }; -} - -#[macro_export] -macro_rules! symbolic_hexadecimal_char { - ($c: expr) => { - $c == 'x' - }; -} - -#[macro_export] -macro_rules! variable_indicator_char { - ($c: expr) => { - $c == '_' - }; -} diff --git a/crates/prolog_parser/src/parser.rs b/crates/prolog_parser/src/parser.rs deleted file mode 100644 index 43ee244c..00000000 --- a/crates/prolog_parser/src/parser.rs +++ /dev/null @@ -1,1031 +0,0 @@ -use crate::ast::*; -use crate::lexer::*; -use crate::tabled_rc::*; - -use ordered_float::OrderedFloat; - -use crate::rug::ops::NegAssign; - -use std::cell::Cell; -use std::io::Read; -use std::mem::swap; -use std::rc::Rc; - -#[derive(Debug, Clone, Copy, PartialEq)] -enum TokenType { - Term, - Open, - OpenCT, - OpenList, // '[' - OpenCurly, // '{' - HeadTailSeparator, // '|' - Comma, // ',' - Close, - CloseList, // ']' - CloseCurly, // '}' - End, -} - -impl TokenType { - fn is_sep(self) -> bool { - matches!( - self, - TokenType::HeadTailSeparator - | TokenType::OpenCT - | TokenType::Open - | TokenType::Close - | TokenType::OpenList - | TokenType::CloseList - | TokenType::OpenCurly - | TokenType::CloseCurly - | TokenType::Comma - ) - } -} - -#[derive(Debug, Clone, Copy)] -struct TokenDesc { - tt: TokenType, - priority: usize, - spec: u32, -} - -pub fn get_clause_spec( - name: ClauseName, - arity: usize, - op_dir: &CompositeOpDir, -) -> Option { - match arity { - 1 => { - /* This is a clause with an operator principal functor. Prefix operators - are supposed over post. - */ - if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) { - return Some(cell.clone()); - } - - if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::Post) { - return Some(cell.clone()); - } - } - 2 => { - if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::In) { - return Some(cell.clone()); - } - } - _ => {} - }; - - None -} - -pub fn get_op_desc(name: ClauseName, op_dir: &CompositeOpDir) -> Option { - let mut op_desc = OpDesc { - pre: 0, - inf: 0, - post: 0, - spec: 0, - }; - - if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) { - let (pri, spec) = cell.get(); - - if pri > 0 { - op_desc.pre = pri; - op_desc.spec |= spec; - } else if name.as_str() == "-" { - op_desc.spec |= NEGATIVE_SIGN; - } - } - - if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Post) { - let (pri, spec) = cell.get(); - - if pri > 0 { - op_desc.post = pri; - op_desc.spec |= spec; - } - } - - if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::In) { - let (pri, spec) = cell.get(); - - if pri > 0 { - op_desc.inf = pri; - op_desc.spec |= spec; - } - } - - if op_desc.pre + op_desc.post + op_desc.inf == 0 && !is_negate!(op_desc.spec) { - None - } else { - Some(op_desc) - } -} - -fn affirm_xfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool { - d2.priority <= priority - && is_term!(d3.spec) - && is_term!(d1.spec) - && d3.priority < d2.priority - && d1.priority < d2.priority -} - -fn affirm_yfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool { - d2.priority <= priority - && ((is_term!(d3.spec) && d3.priority < d2.priority) - || (is_lterm!(d3.spec) && d3.priority == d2.priority)) - && is_term!(d1.spec) - && d1.priority < d2.priority -} - -fn affirm_xfy(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool { - d2.priority < priority - && is_term!(d3.spec) - && d3.priority < d2.priority - && is_term!(d1.spec) - && d1.priority <= d2.priority -} - -fn affirm_yf(d1: TokenDesc, d2: TokenDesc) -> bool { - let is_valid_lterm = is_lterm!(d2.spec) && d2.priority == d1.priority; - (is_term!(d2.spec) && d2.priority < d1.priority) || is_valid_lterm -} - -fn affirm_xf(d1: TokenDesc, d2: TokenDesc) -> bool { - is_term!(d2.spec) && d2.priority < d1.priority -} - -fn affirm_fy(priority: usize, d1: TokenDesc, d2: TokenDesc) -> bool { - d2.priority < priority && is_term!(d1.spec) && d1.priority <= d2.priority -} - -fn affirm_fx(priority: usize, d1: TokenDesc, d2: TokenDesc) -> bool { - d2.priority <= priority && is_term!(d1.spec) && d1.priority < d2.priority -} - -fn sep_to_atom(tt: TokenType) -> Option { - match tt { - TokenType::Open | TokenType::OpenCT => Some(clause_name!("(")), - TokenType::Close => Some(clause_name!(")")), - TokenType::OpenList => Some(clause_name!("[")), - TokenType::CloseList => Some(clause_name!("]")), - TokenType::OpenCurly => Some(clause_name!("{")), - TokenType::CloseCurly => Some(clause_name!("}")), - TokenType::HeadTailSeparator => Some(clause_name!("|")), - TokenType::Comma => Some(clause_name!(",")), - TokenType::End => Some(clause_name!(".")), - _ => None, - } -} - -#[derive(Debug, Clone, Copy)] -pub struct OpDesc { - pub pre: usize, - pub inf: usize, - pub post: usize, - pub spec: Specifier, -} - -#[derive(Debug)] -pub struct Parser<'a, R: Read> { - lexer: Lexer<'a, R>, - tokens: Vec, - stack: Vec, - terms: Vec, -} - -fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> { - let mut tokens = vec![]; - - loop { - match lexer.next_token() { - Ok(token) => { - let at_end = token.is_end(); - tokens.push(token); - - if at_end { - break; - } - } - Err(ParserError::UnexpectedEOF) if !tokens.is_empty() => { - return Err(ParserError::IncompleteReduction(lexer.line_num, lexer.col_num)); - } - Err(e) => { - return Err(e); - } - } - } - - tokens.reverse(); - - Ok(tokens) -} - -impl<'a, R: Read> Parser<'a, R> { - pub fn new( - stream: &'a mut ParsingStream, - atom_tbl: TabledData, - flags: MachineFlags, - ) -> Self { - Parser { - lexer: Lexer::new(atom_tbl, flags, stream), - tokens: vec![], - stack: Vec::new(), - terms: Vec::new(), - } - } - - #[inline] - pub fn line_num(&self) -> usize { - self.lexer.line_num - } - - #[inline] - pub fn col_num(&self) -> usize { - self.lexer.col_num - } - - #[inline] - pub fn get_atom_tbl(&self) -> TabledData { - self.lexer.atom_tbl.clone() - } - - #[inline] - pub fn set_atom_tbl(&mut self, atom_tbl: TabledData) { - self.lexer.atom_tbl = atom_tbl; - } - - fn get_term_name(&mut self, td: TokenDesc) -> Option<(ClauseName, Option)> { - match td.tt { - TokenType::HeadTailSeparator => Some(( - clause_name!("|"), - Some(SharedOpDesc::new(td.priority, td.spec)), - )), - TokenType::Comma => Some((clause_name!(","), Some(SharedOpDesc::new(1000, XFY)))), - TokenType::Term => match self.terms.pop() { - Some(Term::Constant(_, Constant::Atom(atom, spec))) => Some((atom, spec)), - Some(term) => { - self.terms.push(term); - None - } - _ => None, - }, - _ => None, - } - } - - fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) { - if let Some(arg2) = self.terms.pop() { - if let Some((name, shared_op_desc)) = self.get_term_name(td) { - if let Some(arg1) = self.terms.pop() { - let term = Term::Clause( - Cell::default(), - name, - vec![Box::new(arg1), Box::new(arg2)], - shared_op_desc, - ); - - self.terms.push(term); - self.stack.push(TokenDesc { - tt: TokenType::Term, - priority: td.priority, - spec, - }); - } - } - } - } - - fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: u32) { - if let Some(mut arg1) = self.terms.pop() { - if let Some(mut name) = self.terms.pop() { - if is_postfix!(assoc) { - swap(&mut arg1, &mut name); - } - - if let Term::Constant(_, Constant::Atom(name, shared_op_desc)) = name { - let term = - Term::Clause(Cell::default(), name, vec![Box::new(arg1)], shared_op_desc); - - self.terms.push(term); - self.stack.push(TokenDesc { - tt: TokenType::Term, - priority: td.priority, - spec, - }); - } - } - } - } - - fn promote_atom_op( - &mut self, - atom: ClauseName, - priority: usize, - assoc: u32, - op_dir_val: Option<&OpDirValue>, - ) { - let spec = op_dir_val.map(|op_dir_val| op_dir_val.shared_op_desc()); - - self.terms - .push(Term::Constant(Cell::default(), Constant::Atom(atom, spec))); - self.stack.push(TokenDesc { - tt: TokenType::Term, - priority, - spec: assoc, - }); - } - - fn shift(&mut self, token: Token, priority: usize, spec: Specifier) { - let tt = match token { - Token::Constant(Constant::String(s)) if self.lexer.flags.double_quotes.is_codes() => { - let mut list = Term::Constant(Cell::default(), Constant::EmptyList); - - for c in s.chars().rev() { - list = Term::Cons( - Cell::default(), - Box::new(Term::Constant( - Cell::default(), - Constant::Fixnum(c as isize), - )), - Box::new(list), - ); - } - - self.terms.push(list); - TokenType::Term - } - Token::Constant(c) => { - self.terms.push(Term::Constant(Cell::default(), c)); - TokenType::Term - } - Token::Var(v) => { - if v.trim() == "_" { - self.terms.push(Term::AnonVar); - } else { - self.terms.push(Term::Var(Cell::default(), v)); - } - - TokenType::Term - } - Token::Comma => TokenType::Comma, - Token::Open => TokenType::Open, - Token::Close => TokenType::Close, - Token::OpenCT => TokenType::OpenCT, - Token::HeadTailSeparator => TokenType::HeadTailSeparator, - Token::OpenList => TokenType::OpenList, - Token::CloseList => TokenType::CloseList, - Token::OpenCurly => TokenType::OpenCurly, - Token::CloseCurly => TokenType::CloseCurly, - Token::End => TokenType::End, - }; - - self.stack.push(TokenDesc { tt, priority, spec }); - } - - fn reduce_op(&mut self, priority: usize) { - loop { - if let Some(desc1) = self.stack.pop() { - if let Some(desc2) = self.stack.pop() { - if let Some(desc3) = self.stack.pop() { - if is_xfx!(desc2.spec) && affirm_xfx(priority, desc2, desc3, desc1) { - self.push_binary_op(desc2, LTERM); - continue; - } else if is_yfx!(desc2.spec) && affirm_yfx(priority, desc2, desc3, desc1) { - self.push_binary_op(desc2, LTERM); - continue; - } else if is_xfy!(desc2.spec) && affirm_xfy(priority, desc2, desc3, desc1) { - self.push_binary_op(desc2, TERM); - continue; - } else { - self.stack.push(desc3); - } - } - - if is_yf!(desc1.spec) && affirm_yf(desc1, desc2) { - self.push_unary_op(desc1, LTERM, YF); - continue; - } else if is_xf!(desc1.spec) && affirm_xf(desc1, desc2) { - self.push_unary_op(desc1, LTERM, XF); - continue; - } else if is_fy!(desc2.spec) && affirm_fy(priority, desc1, desc2) { - self.push_unary_op(desc2, TERM, FY); - continue; - } else if is_fx!(desc2.spec) && affirm_fx(priority, desc1, desc2) { - self.push_unary_op(desc2, TERM, FX); - continue; - } else { - self.stack.push(desc2); - self.stack.push(desc1); - } - } else { - self.stack.push(desc1); - } - } - - break; - } - } - - fn compute_arity_in_brackets(&self) -> Option { - let mut arity = 0; - - for (i, desc) in self.stack.iter().rev().enumerate() { - if i % 2 == 0 { - // expect a term or non-comma operator. - if let TokenType::Comma = desc.tt { - return None; - } else if is_term!(desc.spec) || is_op!(desc.spec) || is_negate!(desc.spec) { - arity += 1; - } else { - return None; - } - } else { - if desc.tt == TokenType::OpenCT { - return Some(arity); - } - - if let TokenType::Comma = desc.tt { - continue; - } else { - return None; - } - } - } - - None - } - - fn reduce_term(&mut self, op_dir: &CompositeOpDir) -> bool { - if self.stack.is_empty() { - return false; - } - - self.reduce_op(999); - - let arity = match self.compute_arity_in_brackets() { - Some(arity) => arity, - None => return false, - }; - - if self.stack.len() > 2 * arity { - let idx = self.stack.len() - 2 * arity - 1; - - if is_infix!(self.stack[idx].spec) && idx > 0 { - if !is_op!(self.stack[idx - 1].spec) && !self.stack[idx - 1].tt.is_sep() { - return false; - } - } - } else { - return false; - } - - if self.terms.len() < 1 + arity { - return false; - } - - let stack_len = self.stack.len() - 2 * arity - 1; - let idx = self.terms.len() - arity; - - if TokenType::Term == self.stack[stack_len].tt { - if self.atomize_term(&self.terms[idx - 1]).is_some() { - self.stack.truncate(stack_len + 1); - - let mut subterms: Vec<_> = self.terms.drain(idx..).map(Box::new).collect(); - - if let Some(name) = self.terms.pop().and_then(|t| self.atomize_term(&t)) { - // reduce the '.' functor to a cons cell if it applies. - if name.as_str() == "." && subterms.len() == 2 { - let tail = subterms.pop().unwrap(); - let head = subterms.pop().unwrap(); - - self.terms.push(Term::Cons(Cell::default(), head, tail)); - } else { - let spec = get_clause_spec(name.clone(), subterms.len(), op_dir); - self.terms - .push(Term::Clause(Cell::default(), name, subterms, spec)); - } - - if let Some(&mut TokenDesc { - ref mut priority, - ref mut spec, - ref mut tt, - }) = self.stack.last_mut() - { - *tt = TokenType::Term; - *priority = 0; - *spec = TERM; - } - - return true; - } - } - } - - false - } - - pub fn devour_whitespace(&mut self) -> Result<(), ParserError> { - self.lexer.scan_for_layout()?; - Ok(()) - } - - pub fn reset(&mut self) { - self.stack.clear() - } - - fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { - if let Some(term) = self.terms.pop() { - let op_desc = self.stack[index - 1]; - - if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority { - /* '|' is a head-tail separator here, not - * an operator, so expand the - * terms it compacted out again. */ - match (term.name(), term.arity()) { - (Some(name), 2) if name.as_str() == "," => { - let terms = unfold_by_str(term, ","); - let arity = terms.len() - 1; - - self.terms.extend(terms.into_iter()); - return arity; - } - _ => {} - } - } - - self.terms.push(term); - } - - 0 - } - - fn compute_arity_in_list(&self) -> Option { - let mut arity = 0; - - for (i, desc) in self.stack.iter().rev().enumerate() { - if i % 2 == 0 { - // expect a term or non-comma operator. - if let TokenType::Comma = desc.tt { - return None; - } else if is_term!(desc.spec) || is_op!(desc.spec) { - arity += 1; - } else { - return None; - } - } else { - if desc.tt == TokenType::HeadTailSeparator { - if arity == 1 { - continue; - } - - return None; - } else if desc.tt == TokenType::OpenList { - return Some(arity); - } else if desc.tt != TokenType::Comma { - return None; - } - } - } - - None - } - - fn reduce_list(&mut self) -> Result { - if self.stack.is_empty() { - return Ok(false); - } - - if let Some(ref mut td) = self.stack.last_mut() { - if td.tt == TokenType::OpenList { - td.spec = TERM; - td.tt = TokenType::Term; - td.priority = 0; - - self.terms - .push(Term::Constant(Cell::default(), Constant::EmptyList)); - return Ok(true); - } - } - - self.reduce_op(1000); - - let mut arity = match self.compute_arity_in_list() { - Some(arity) => arity, - None => return Ok(false), - }; - - // we know that self.stack.len() >= 2 by this point. - let idx = self.stack.len() - 2; - let list_len = self.stack.len() - 2 * arity; - - let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { - Term::Constant(Cell::default(), Constant::EmptyList) - } else { - let term = match self.terms.pop() { - Some(term) => term, - _ => { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )) - } - }; - - if self.stack[idx].priority > 1000 { - arity += self.expand_comma_compacted_terms(idx); - } - - arity -= 1; - - term - }; - - if arity > self.terms.len() { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num - )) - } - - let idx = self.terms.len() - arity; - - let list = self.terms.drain(idx..).rev().fold(end_term, |acc, t| { - Term::Cons(Cell::default(), Box::new(t), Box::new(acc)) - }); - - self.stack.truncate(list_len); - - self.stack.push(TokenDesc { - tt: TokenType::Term, - priority: 0, - spec: TERM, - }); - self.terms.push(list); - - Ok(true) - } - - fn reduce_curly(&mut self) -> Result { - if self.stack.is_empty() { - return Ok(false); - } - - if let Some(ref mut td) = self.stack.last_mut() { - if td.tt == TokenType::OpenCurly { - td.tt = TokenType::Term; - td.priority = 0; - td.spec = TERM; - - let term = Term::Constant(Cell::default(), atom!("{}", self.lexer.atom_tbl)); - self.terms.push(term); - return Ok(true); - } - } - - self.reduce_op(1201); - - if self.stack.len() > 1 { - if let Some(td) = self.stack.pop() { - if let Some(ref mut oc) = self.stack.last_mut() { - if td.tt != TokenType::Term { - return Ok(false); - } - - if oc.tt == TokenType::OpenCurly { - oc.tt = TokenType::Term; - oc.priority = 0; - oc.spec = TERM; - - let term = match self.terms.pop() { - Some(term) => term, - _ => { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )) - } - }; - - self.terms.push(Term::Clause( - Cell::default(), - clause_name!("{}"), - vec![Box::new(term)], - None, - )); - - return Ok(true); - } - } - } - } - - Ok(false) - } - - fn reduce_brackets(&mut self) -> bool { - if self.stack.is_empty() { - return false; - } - - self.reduce_op(1400); - - if self.stack.len() == 1 { - return false; - } - - let idx = self.stack.len() - 2; - - let td = self.stack.remove(idx); - match td.tt { - TokenType::Open | TokenType::OpenCT => { - if self.stack[idx].tt == TokenType::Comma { - return false; - } - - if let Some(atom) = sep_to_atom(self.stack[idx].tt) { - self.terms - .push(Term::Constant(Cell::default(), Constant::Atom(atom, None))); - } - - self.stack[idx].spec = TERM; - self.stack[idx].tt = TokenType::Term; - self.stack[idx].priority = 0; - true - } - _ => false, - } - } - - fn shift_op(&mut self, name: ClauseName, op_dir: &CompositeOpDir) -> Result { - if let Some(OpDesc { - pre, - inf, - post, - spec, - }) = get_op_desc(name.clone(), op_dir) - { - if (pre > 0 && inf + post > 0) || is_negate!(spec) { - match self.tokens.last().ok_or(ParserError::UnexpectedEOF)? { - // do this when layout hasn't been inserted, - // ie. why we don't match on Token::Open. - Token::OpenCT => { - // can't be prefix, so either inf == 0 - // or post == 0. - self.reduce_op(inf + post); - - let fixity = if inf > 0 { Fixity::In } else { Fixity::Post }; - let op_dir_val = op_dir.get(name.clone(), fixity); - - self.promote_atom_op( - name, - inf + post, - spec & (XFX | XFY | YFX | YF | XF), - op_dir_val, - ); - } - _ => { - self.reduce_op(inf + post); - - if let Some(TokenDesc { spec: pspec, .. }) = self.stack.last().cloned() { - // rterm.c: 412 - if is_term!(pspec) { - let fixity = if inf > 0 { Fixity::In } else { Fixity::Post }; - let op_dir_val = op_dir.get(name.clone(), fixity); - - self.promote_atom_op( - name, - inf + post, - spec & (XFX | XFY | YFX | XF | YF), - op_dir_val, - ); - } else { - let op_dir_val = op_dir.get(name.clone(), Fixity::Pre); - self.promote_atom_op( - name, - pre, - spec & (FX | FY | NEGATIVE_SIGN), - op_dir_val, - ); - } - } else { - let op_dir_val = op_dir.get(name.clone(), Fixity::Pre); - self.promote_atom_op( - name, - pre, - spec & (FX | FY | NEGATIVE_SIGN), - op_dir_val, - ); - } - } - } - } else { - let op_dir_val = op_dir.get( - name.clone(), - if pre + inf == 0 { - Fixity::Post - } else if post + pre == 0 { - Fixity::In - } else { - Fixity::Pre - }, - ); - - self.reduce_op(pre + inf + post); // only one non-zero priority among these. - self.promote_atom_op(name, pre + inf + post, spec, op_dir_val); - } - - Ok(true) - } else { - // not an operator. - Ok(false) - } - } - - fn atomize_term(&self, term: &Term) -> Option { - match term { - Term::Constant(_, ref c) => self.atomize_constant(c), - _ => None, - } - } - - fn atomize_constant(&self, c: &Constant) -> Option { - match c { - Constant::Atom(ref name, _) => Some(name.clone()), - Constant::Char(c) => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)), - Constant::EmptyList => Some(clause_name!(c.to_string(), self.lexer.atom_tbl)), - _ => None, - } - } - - fn negate_number(&mut self, n: N, negator: Negator, constr: ToConstant) - where - Negator: Fn(N) -> N, - ToConstant: Fn(N) -> Constant, - { - if let Some(desc) = self.stack.last().cloned() { - if let Some(term) = self.terms.last().cloned() { - match term { - Term::Constant(_, Constant::Atom(ref name, _)) - if name.as_str() == "-" - && (is_prefix!(desc.spec) || is_negate!(desc.spec)) => - { - self.stack.pop(); - self.terms.pop(); - - self.shift(Token::Constant(constr(negator(n))), 0, TERM); - return; - } - _ => {} - } - } - } - - self.shift(Token::Constant(constr(n)), 0, TERM); - } - - fn shift_token(&mut self, token: Token, op_dir: &CompositeOpDir) -> Result<(), ParserError> { - fn negate_rc(mut t: Rc) -> Rc { - if let Some(t) = Rc::get_mut(&mut t) { - t.neg_assign(); - }; - - t - } - - match token { - Token::Constant(Constant::Fixnum(n)) => self.negate_number(n, |n| -n, Constant::Fixnum), - Token::Constant(Constant::Integer(n)) => { - self.negate_number(n, negate_rc, Constant::Integer) - } - Token::Constant(Constant::Rational(n)) => { - self.negate_number(n, negate_rc, Constant::Rational) - } - Token::Constant(Constant::Float(n)) => { - self.negate_number(n, |n| OrderedFloat(-n.into_inner()), Constant::Float) - } - Token::Constant(c) => { - if let Some(name) = self.atomize_constant(&c) { - if !self.shift_op(name, op_dir)? { - self.shift(Token::Constant(c), 0, TERM); - } - } else { - self.shift(Token::Constant(c), 0, TERM); - } - } - Token::Var(v) => self.shift(Token::Var(v), 0, TERM), - Token::Open => self.shift(Token::Open, 1300, DELIMITER), - Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER), - Token::Close => { - if !self.reduce_term(op_dir) { - if !self.reduce_brackets() { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )); - } - } - } - Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER), - Token::CloseList => { - if !self.reduce_list()? { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )); - } - } - Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER), - Token::CloseCurly => { - if !self.reduce_curly()? { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )); - } - } - Token::HeadTailSeparator => { - /* '|' as an operator must have priority > 1000 and can only be infix. - * See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78 - */ - let (priority, spec) = get_op_desc(clause_name!("|"), op_dir) - .map(|OpDesc { inf, spec, .. }| (inf, spec)) - .unwrap_or((1000, DELIMITER)); - - self.reduce_op(priority); - self.shift(Token::HeadTailSeparator, priority, spec); - } - Token::Comma => { - self.reduce_op(1000); - self.shift(Token::Comma, 1000, XFY); - } - Token::End => match self.stack.last().map(|t| t.tt) { - Some(TokenType::Open) - | Some(TokenType::OpenCT) - | Some(TokenType::OpenList) - | Some(TokenType::OpenCurly) - | Some(TokenType::HeadTailSeparator) - | Some(TokenType::Comma) => { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )) - } - _ => {} - }, - } - - Ok(()) - } - - #[inline] - pub fn eof(&mut self) -> Result { - self.lexer.eof() - } - - #[inline] - pub fn add_lines_read(&mut self, lines_read: usize) { - self.lexer.line_num += lines_read; - } - - #[inline] - pub fn num_lines_read(&self) -> usize { - self.lexer.line_num - } - - // on success, returns the parsed term and the number of lines read. - pub fn read_term(&mut self, op_dir: &CompositeOpDir) -> Result { - self.tokens = read_tokens(&mut self.lexer)?; - - while let Some(token) = self.tokens.pop() { - self.shift_token(token, op_dir)?; - } - - self.reduce_op(1400); - - if self.terms.len() > 1 || self.stack.len() > 1 { - return Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )); - } - - match self.terms.pop() { - Some(term) => { - if self.terms.is_empty() { - Ok(term) - } else { - Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )) - } - } - _ => Err(ParserError::IncompleteReduction( - self.lexer.line_num, - self.lexer.col_num, - )), - } - } -} diff --git a/crates/prolog_parser/src/put_back_n.rs b/crates/prolog_parser/src/put_back_n.rs deleted file mode 100644 index 8bef7f30..00000000 --- a/crates/prolog_parser/src/put_back_n.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::iter::Peekable; - -#[derive(Debug, Clone)] -pub struct PutBackN { - top: Vec, - iter: Peekable, -} - -pub fn put_back_n(iterable: I) -> PutBackN - where I: IntoIterator -{ - PutBackN { - top: Vec::new(), - iter: iterable.into_iter().peekable(), - } -} - -impl PutBackN { - #[inline] - pub(crate) - fn put_back(&mut self, item: I::Item) { - self.top.push(item); - } - - #[inline] - pub fn take_buf(&mut self) -> Vec { - std::mem::replace(&mut self.top, vec![]) - } - - #[inline] - pub(crate) - fn peek(&mut self) -> Option<&I::Item> { - if self.top.is_empty() { - /* This is a kludge for Ctrl-D not being - * handled properly if self.iter().peek() isn't called - * first. */ - match self.iter.peek() { - Some(_) => { - self.iter.next().and_then(move |item| { - self.top.push(item); - self.top.last() - }) - } - None => { - None - } - } - } else { - self.top.last() - } - } - - #[inline] - pub(crate) - fn put_back_all>(&mut self, iter: DEI) { - self.top.extend(iter.rev()); - } -} - -impl Iterator for PutBackN { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.top.is_empty() { - self.iter.next() - } else { - self.top.pop() - } - } -} diff --git a/crates/prolog_parser/src/tabled_rc.rs b/crates/prolog_parser/src/tabled_rc.rs deleted file mode 100644 index 47f87d30..00000000 --- a/crates/prolog_parser/src/tabled_rc.rs +++ /dev/null @@ -1,154 +0,0 @@ -use std::cell::{RefCell, RefMut}; -use std::cmp::Ordering; -use std::collections::HashSet; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::ops::Deref; -use std::rc::Rc; - -pub struct TabledData { - table: Rc>>>, - pub(crate) module_name: Rc, -} - -impl fmt::Debug for TabledData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TabledData") - .field("table", &self.table) - .field("module_name", &self.table) - .finish() - } -} - -impl Clone for TabledData { - fn clone(&self) -> Self { - TabledData { - table: self.table.clone(), - module_name: self.module_name.clone(), - } - } -} - -impl PartialEq for TabledData { - fn eq(&self, other: &TabledData) -> bool { - Rc::ptr_eq(&self.table, &other.table) && self.module_name == other.module_name - } -} - -impl TabledData { - #[inline] - pub fn new(module_name: Rc) -> Self { - TabledData { - table: Rc::new(RefCell::new(HashSet::new())), - module_name, - } - } - - #[inline] - pub fn borrow_mut(&self) -> RefMut>> { - self.table.borrow_mut() - } -} - -pub struct TabledRc { - pub(crate) atom: Rc, - pub table: TabledData, -} - -impl fmt::Debug for TabledRc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TabledRc") - .field("atom", &self.atom) - .field("table", &self.table) - .finish() - } -} - -// this Clone instance is manually defined to prevent the compiler -// from complaining when deriving Clone for StringList. -impl Clone for TabledRc { - fn clone(&self) -> Self { - TabledRc { - atom: self.atom.clone(), - table: self.table.clone(), - } - } -} - -impl PartialOrd for TabledRc { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.atom.cmp(&other.atom)) - } -} - -impl Ord for TabledRc { - fn cmp(&self, other: &Self) -> Ordering { - self.atom.cmp(&other.atom) - } -} - -impl PartialEq for TabledRc { - fn eq(&self, other: &TabledRc) -> bool { - self.atom == other.atom - } -} - -impl Eq for TabledRc {} - -impl Hash for TabledRc { - fn hash(&self, state: &mut H) { - self.atom.hash(state) - } -} - -impl TabledRc { - pub fn new(atom: T, table: TabledData) -> Self { - let atom = match table.borrow_mut().take(&atom) { - Some(atom) => atom, - None => Rc::new(atom), - }; - - table.borrow_mut().insert(atom.clone()); - - TabledRc { atom, table } - } - - #[inline] - pub fn inner(&self) -> Rc { - self.atom.clone() - } - - #[inline] - pub(crate) fn owning_module(&self) -> Rc { - self.table.module_name.clone() - } -} - -impl Drop for TabledRc { - fn drop(&mut self) { - if Rc::strong_count(&self.atom) == 2 { - self.table.borrow_mut().remove(&self.atom); - } - } -} - -impl Deref for TabledRc { - type Target = T; - - fn deref(&self) -> &Self::Target { - &*self.atom - } -} - -impl fmt::Display for TabledRc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", &*self.atom) - } -} - -#[macro_export] -macro_rules! tabled_rc { - ($e:expr, $tbl:expr) => { - $crate::tabled_rc::TabledRc::new(String::from($e), $tbl.clone()) - }; -} diff --git a/crates/prolog_parser/tests/bom.rs b/crates/prolog_parser/tests/bom.rs deleted file mode 100644 index 8a92c127..00000000 --- a/crates/prolog_parser/tests/bom.rs +++ /dev/null @@ -1,40 +0,0 @@ -use prolog_parser::ast::*; -use prolog_parser::lexer::{Lexer, Token}; -use prolog_parser::tabled_rc::TabledData; - -use std::rc::Rc; - -#[test] -fn valid_token() { - let stream = parsing_stream("valid text".as_bytes()); - assert!(stream.is_ok()); -} - -#[test] -fn empty_stream() { - let bytes: &[u8] = &[]; - assert!(parsing_stream(bytes).is_ok()); -} - -#[test] -fn skip_utf8_bom() { - let atom_tbl = TabledData::new(Rc::new("my_module".to_string())); - let flags = MachineFlags::default(); - let bytes: &[u8] = &[0xEF, 0xBB, 0xBF, '4' as u8, '\n' as u8]; - let mut stream = parsing_stream(bytes).expect("valid stream"); - let mut lexer = Lexer::new(atom_tbl, flags, &mut stream); - match lexer.next_token() { - Ok(Token::Constant(Constant::Fixnum(4))) => (), - _ => assert!(false), - } -} - -#[test] -fn invalid_utf16_bom() { - let bytes: &[u8] = &[0xFF, 0xFE, 'a' as u8, '\n' as u8]; - let stream = parsing_stream(bytes); - match stream { - Err(ParserError::Utf8Error(0, 0)) => (), - _ => assert!(false), - } -} diff --git a/crates/prolog_parser/tests/parse_tokens.rs b/crates/prolog_parser/tests/parse_tokens.rs deleted file mode 100644 index 69b63286..00000000 --- a/crates/prolog_parser/tests/parse_tokens.rs +++ /dev/null @@ -1,112 +0,0 @@ -use prolog_parser::ast::*; -use prolog_parser::lexer::{Lexer, Token}; -use prolog_parser::tabled_rc::TabledData; - -use std::rc::Rc; - -fn read_all_tokens(text: &str) -> Result, ParserError> { - let atom_tbl = TabledData::new(Rc::new("my_module".to_string())); - let flags = MachineFlags::default(); - let mut stream = parsing_stream(text.as_bytes())?; - let mut lexer = Lexer::new(atom_tbl, flags, &mut stream); - - let mut tokens = Vec::new(); - while !lexer.eof()? { - let token = lexer.next_token()?; - tokens.push(token); - } - Ok(tokens) -} - -#[test] -fn empty_multiline_comment() -> Result<(), ParserError> { - let tokens = read_all_tokens("/**/ 4\n")?; - assert_eq!(tokens, [Token::Constant(Constant::Fixnum(4))]); - Ok(()) -} - -#[test] -fn any_char_multiline_comment() -> Result<(), ParserError> { - let tokens = read_all_tokens("/* █╗╚═══╝ © */ 4\n")?; - assert_eq!(tokens, [Token::Constant(Constant::Fixnum(4))]); - Ok(()) -} - -#[test] -fn simple_char() -> Result<(), ParserError> { - let tokens = read_all_tokens("'a'\n")?; - assert_eq!(tokens, [Token::Constant(Constant::Char('a'))]); - Ok(()) -} - -#[test] -fn char_with_meta_seq() -> Result<(), ParserError> { - let tokens = read_all_tokens(r#"'\\' '\'' '\"' '\`' "#)?; // use literal string so \ are escaped - assert_eq!( - tokens, - [ - Token::Constant(Constant::Char('\\')), - Token::Constant(Constant::Char('\'')), - Token::Constant(Constant::Char('"')), - Token::Constant(Constant::Char('`')) - ] - ); - Ok(()) -} - -#[test] -fn char_with_control_seq() -> Result<(), ParserError> { - let tokens = read_all_tokens(r"'\a' '\b' '\r' '\f' '\t' '\n' '\v' ")?; - assert_eq!( - tokens, - [ - Token::Constant(Constant::Char('\u{07}')), - Token::Constant(Constant::Char('\u{08}')), - Token::Constant(Constant::Char('\r')), - Token::Constant(Constant::Char('\u{0c}')), - Token::Constant(Constant::Char('\t')), - Token::Constant(Constant::Char('\n')), - Token::Constant(Constant::Char('\u{0b}')), - ] - ); - Ok(()) -} - -#[test] -fn char_with_octseq() -> Result<(), ParserError> { - let tokens = read_all_tokens(r"'\60433\' ")?; - assert_eq!(tokens, [Token::Constant(Constant::Char('愛'))]); // Japanese character - Ok(()) -} - -#[test] -fn char_with_octseq_0() -> Result<(), ParserError> { - let tokens = read_all_tokens(r"'\0\' ")?; - assert_eq!(tokens, [Token::Constant(Constant::Char('\u{0000}'))]); - Ok(()) -} - -#[test] -fn char_with_hexseq() -> Result<(), ParserError> { - let tokens = read_all_tokens(r"'\x2124\' ")?; - assert_eq!(tokens, [Token::Constant(Constant::Char('ℤ'))]); // Z math symbol - Ok(()) -} - -#[test] -fn char_with_hexseq_invalid() { - assert!(read_all_tokens(r"'\x\' ").is_err()); -} - -#[test] -fn empty() -> Result<(), ParserError> { - let tokens = read_all_tokens("")?; - assert!(tokens.is_empty()); - Ok(()) -} - -#[test] -fn comment_then_eof() -> Result<(), ParserError> { - assert!(read_all_tokens("% only a comment").is_err()); - Ok(()) -} diff --git a/crates/static-string-indexing/Cargo.toml b/crates/static-string-indexing/Cargo.toml new file mode 100644 index 00000000..a6da96b9 --- /dev/null +++ b/crates/static-string-indexing/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "static-string-indexing" +version = "0.1.0" +edition = "2018" + +[dependencies] +proc-macro2 = "*" +syn = { version = "*", features = ['full', 'visit', 'extra-traits'] } +indexmap = "*" +walkdir = "2" +quote = "*" diff --git a/crates/static-string-indexing/src/lib.rs b/crates/static-string-indexing/src/lib.rs new file mode 100644 index 00000000..22b87cc0 --- /dev/null +++ b/crates/static-string-indexing/src/lib.rs @@ -0,0 +1,161 @@ +use proc_macro2::TokenStream; +use syn::*; +use syn::parse::*; +use syn::visit::*; + +use indexmap::IndexSet; + +struct StaticStrVisitor { + static_strs: IndexSet, +} + +impl StaticStrVisitor { + fn new() -> Self { + Self { static_strs: IndexSet::new() } + } +} + +struct MacroFnArgs { + args: Vec, +} + +struct ReadHeapCellExprAndArms { + expr: Expr, + arms: Vec, +} + +impl Parse for ReadHeapCellExprAndArms { + fn parse(input: ParseStream) -> Result { + let mut arms = vec![]; + let expr = input.parse()?; + + input.parse::()?; + arms.push(input.parse()?); + + while !input.is_empty() { + if let Ok(_) = input.parse::() {} + arms.push(input.parse()?); + } + + Ok(ReadHeapCellExprAndArms { expr, arms }) + } +} + +impl Parse for MacroFnArgs { + fn parse(input: ParseStream) -> Result { + let mut args = vec![]; + + if !input.is_empty() { + args.push(input.parse()?); + } + + while !input.is_empty() { + if let Ok(_) = input.parse::() {} + args.push(input.parse()?); + } + + Ok(MacroFnArgs { args }) + } +} + +impl<'ast> Visit<'ast> for StaticStrVisitor { + fn visit_macro(&mut self, m: &'ast Macro) { + let Macro { path, .. } = m; + + if path.is_ident("atom") { + if let Some(Lit::Str(string)) = m.parse_body::().ok() { + self.static_strs.insert(string.value()); + } + } else if path.is_ident("read_heap_cell") { + if let Some(m) = m.parse_body::().ok() { + self.visit_expr(&m.expr); + + for e in m.arms { + self.visit_arm(&e); + } + } + } else { + if let Some(m) = m.parse_body::().ok() { + for e in m.args { + self.visit_expr(&e); + } + } + } + } +} + +pub fn index_static_strings() -> TokenStream { + use quote::*; + + use std::ffi::OsStr; + use std::fs::File; + use std::io::Read; + + use walkdir::WalkDir; + + fn filter_rust_files(e: &walkdir::DirEntry) -> bool { + if e.path().is_dir() { + return true; + } + + e.path().extension().and_then(OsStr::to_str) == Some("rs") + } + + let mut visitor = StaticStrVisitor::new(); + + for entry in WalkDir::new("src/").into_iter().filter_entry(filter_rust_files) { + let entry = entry.unwrap(); + + if entry.path().is_dir() { + continue; + } + + let mut file = match File::open(entry.path()) { + Ok(file) => file, + Err(_) => continue, + }; + + let mut src = String::new(); + + match file.read_to_string(&mut src) { + Ok(_) => {} + Err(e) => { + panic!("error reading file: {:?}", e); + } + } + + let syntax = match syn::parse_file(&src) { + Ok(s) => s, + Err(e) => { + panic!("parse error: {} in file {:?}", e, entry.path()); + } + }; + + visitor.visit_file(&syntax); + } + + let indices = (0 .. visitor.static_strs.len()).map(|i| i << 3); + let indices_iter = indices.clone(); + + let static_strs_len = visitor.static_strs.len(); + let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect(); + + quote! { + use phf; + + static STRINGS: [&'static str; #static_strs_len] = [ + #( + #static_strs, + )* + ]; + + #[macro_export] + macro_rules! atom { + #((#static_strs) => { Atom { index: #indices_iter } };)* + } + + static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! { + #(#static_strs => { Atom { index: #indices } },)* + }; + } +} diff --git a/src/allocator.rs b/src/allocator.rs index cc8de305..c29adc92 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,10 +1,9 @@ -use prolog_parser::ast::*; -use prolog_parser::temp_v; +use crate::parser::ast::*; +use crate::temp_v; use crate::fixtures::*; use crate::forms::*; use crate::machine::machine_indices::*; -use crate::targets::*; use std::cell::Cell; use std::rc::Rc; @@ -14,7 +13,7 @@ pub(crate) trait Allocator<'a> { fn mark_anon_var(&mut self, _: Level, _: GenContext, _: &mut Vec) where - Target: CompilationTarget<'a>; + Target: crate::targets::CompilationTarget<'a>; fn mark_non_var( &mut self, _: Level, @@ -22,10 +21,10 @@ pub(crate) trait Allocator<'a> { _: &'a Cell, _: &mut Vec, ) where - Target: CompilationTarget<'a>; + Target: crate::targets::CompilationTarget<'a>; fn mark_reserved_var( &mut self, - _: Rc, + _: Rc, _: Level, _: &'a Cell, _: GenContext, @@ -33,21 +32,21 @@ pub(crate) trait Allocator<'a> { _: RegType, _: bool, ) where - Target: CompilationTarget<'a>; + Target: crate::targets::CompilationTarget<'a>; fn mark_var( &mut self, - _: Rc, + _: Rc, _: Level, _: &'a Cell, _: GenContext, _: &mut Vec, ) where - Target: CompilationTarget<'a>; + Target: crate::targets::CompilationTarget<'a>; fn reset(&mut self); fn reset_contents(&mut self) {} fn reset_arg(&mut self, _: usize); - fn reset_at_head(&mut self, _: &Vec>); + fn reset_at_head(&mut self, args: &Vec); fn advance_arg(&mut self); @@ -83,17 +82,17 @@ pub(crate) trait Allocator<'a> { perm_vs } - fn get(&self, var: Rc) -> RegType { + fn get(&self, var: Rc) -> RegType { self.bindings() .get(&var) .map_or(temp_v!(0), |v| v.as_reg_type()) } - fn is_unbound(&self, var: Rc) -> bool { + fn is_unbound(&self, var: Rc) -> bool { self.get(var).reg_num() == 0 } - fn record_register(&mut self, var: Rc, r: RegType) { + fn record_register(&mut self, var: Rc, r: RegType) { match self.bindings_mut().get_mut(&var).unwrap() { &mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(), &mut VarData::Perm(ref mut s) => *s = r.reg_num(), diff --git a/src/arena.rs b/src/arena.rs new file mode 100644 index 00000000..2ba73d27 --- /dev/null +++ b/src/arena.rs @@ -0,0 +1,797 @@ +use crate::machine::loader::LiveLoadState; +use crate::machine::machine_indices::*; +use crate::machine::streams::*; +use crate::read::*; + +use modular_bitfield::prelude::*; +use ordered_float::OrderedFloat; +use rug::{Integer, Rational}; + +use std::alloc; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::mem; +use std::net::TcpListener; +use std::ops::{Deref, DerefMut}; +use std::ptr; + +#[macro_export] +macro_rules! arena_alloc { + ($e:expr, $arena:expr) => {{ + let result = $e; + #[allow(unused_unsafe)] + unsafe { $arena.alloc(result) } + }}; +} + +#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)] +#[bits = 7] +pub enum ArenaHeaderTag { + F64 = 0b01, + Integer = 0b10, + Rational = 0b11, + OssifiedOpDir = 0b0000100, + LiveLoadState = 0b0001000, + InactiveLoadState = 0b1011000, + InputFileStream = 0b10000, + OutputFileStream = 0b10100, + NamedTcpStream = 0b011100, + NamedTlsStream = 0b100000, + // PausedPrologStream = 0b101100, + ReadlineStream = 0b110000, + StaticStringStream = 0b110100, + ByteStream = 0b111000, + // StandardInputStream = 0b100, + StandardOutputStream = 0b1100, + StandardErrorStream = 0b11000, + NullStream = 0b111100, + TcpListener = 0b1000000, + Dropped = 0b1000100, +} + +#[bitfield] +#[derive(Copy, Clone, Debug)] +pub struct ArenaHeader { + size: B56, + m: bool, + tag: ArenaHeaderTag, +} + +const_assert!(mem::size_of::() == 8); + +impl ArenaHeader { + #[inline] + pub fn build_with(size: u64, tag: ArenaHeaderTag) -> Self { + ArenaHeader::new() + .with_size(size) + .with_tag(tag) + .with_m(false) + } + + #[inline] + pub fn get_tag(self) -> ArenaHeaderTag { + self.tag() + } +} + +#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)] +pub struct TypedArenaPtr(ptr::NonNull); + +impl Hash for TypedArenaPtr { + #[inline(always)] + fn hash(&self, hasher: &mut H) { + (&*self as &T).hash(hasher) + } +} + +impl Clone for TypedArenaPtr { + fn clone(&self) -> Self { + TypedArenaPtr(self.0) + } +} + +impl Copy for TypedArenaPtr {} + +impl Deref for TypedArenaPtr { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { self.0.as_ref() } + } +} + +impl DerefMut for TypedArenaPtr { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { self.0.as_mut() } + } +} + +impl fmt::Display for TypedArenaPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", **self) + } +} + +impl TypedArenaPtr { + #[inline] + pub const fn new(data: *mut T) -> Self { + unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) } + } + + #[inline] + pub fn as_ptr(&self) -> *mut T { + self.0.as_ptr() + } + + #[inline] + pub fn header_ptr(&self) -> *const ArenaHeader { + let mut ptr = self.as_ptr() as *const u8 as usize; + ptr -= mem::size_of::<*const ArenaHeader>(); + ptr as *const ArenaHeader + } + + #[inline] + fn header_ptr_mut(&mut self) -> *mut ArenaHeader { + let mut ptr = self.as_ptr() as *const u8 as usize; + ptr -= mem::size_of::<*const ArenaHeader>(); + ptr as *mut ArenaHeader + } + + #[inline] + pub fn get_mark_bit(&self) -> bool { + unsafe { (*self.header_ptr()).m() } + } + + #[inline] + pub fn set_tag(&mut self, tag: ArenaHeaderTag) { + unsafe { (*self.header_ptr_mut()).set_tag(tag); } + } + + #[inline] + pub fn get_tag(&self) -> ArenaHeaderTag { + unsafe { (*self.header_ptr()).get_tag() } + } + + #[inline] + pub fn mark(&mut self) { + unsafe { + (*self.header_ptr_mut()).set_m(true); + } + } + + #[inline] + pub fn unmark(&mut self) { + unsafe { + (*self.header_ptr_mut()).set_m(false); + } + } +} + +pub trait ArenaAllocated { + type PtrToAllocated; + + fn tag() -> ArenaHeaderTag; + fn size(&self) -> usize; + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated + where + Self: Sized; +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct F64Ptr(pub TypedArenaPtr>); + +impl fmt::Display for F64Ptr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", *self) + } +} + +impl Deref for F64Ptr { + type Target = TypedArenaPtr>; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for F64Ptr { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl ArenaAllocated for OrderedFloat { + type PtrToAllocated = F64Ptr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::F64 + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + F64Ptr(TypedArenaPtr::new(dst as *mut Self)) + } + } +} + +impl ArenaAllocated for Integer { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::Integer + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } + } +} + +impl ArenaAllocated for Rational { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::Rational + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } + } +} + +impl ArenaAllocated for OssifiedOpDir { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::OssifiedOpDir + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } + } +} + +impl ArenaAllocated for LiveLoadState { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::LiveLoadState + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } + } +} + +impl ArenaAllocated for TcpListener { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::TcpListener + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } + } +} + +#[derive(Clone, Copy, Debug)] +struct AllocSlab { + next: *mut AllocSlab, + header: ArenaHeader, +} + +#[derive(Debug)] +pub struct Arena(*mut AllocSlab); + +unsafe impl Send for Arena {} +unsafe impl Sync for Arena {} + +impl Arena { + #[inline] + pub fn new() -> Self { + Arena(ptr::null_mut()) + } + + pub unsafe fn alloc(&mut self, value: T) -> T::PtrToAllocated { + let size = value.size() + mem::size_of::(); + + let align = mem::align_of::(); + let layout = alloc::Layout::from_size_align_unchecked(size, align); + + let slab = alloc::alloc(layout) as *mut AllocSlab; + + (*slab).next = self.0; + (*slab).header = ArenaHeader::build_with(value.size() as u64, T::tag()); + + let offset = (*slab).payload_offset(); + let result = value.copy_to_arena(offset as *mut T); + + self.0 = slab; + + result + } +} + +unsafe fn drop_slab_in_place(value: &mut AllocSlab) { + match value.header.tag() { + ArenaHeaderTag::Integer => { + ptr::drop_in_place(value.payload_offset() as *mut Integer); + } + ArenaHeaderTag::Rational => { + ptr::drop_in_place(value.payload_offset() as *mut Rational); + } + ArenaHeaderTag::InputFileStream => { + ptr::drop_in_place(value.payload_offset() as *mut InputFileStream); + } + ArenaHeaderTag::OutputFileStream => { + ptr::drop_in_place(value.payload_offset() as *mut OutputFileStream); + } + ArenaHeaderTag::NamedTcpStream => { + ptr::drop_in_place(value.payload_offset() as *mut NamedTcpStream); + } + ArenaHeaderTag::NamedTlsStream => { + ptr::drop_in_place(value.payload_offset() as *mut NamedTlsStream); + } + // ArenaHeaderTag::PausedPrologStream => { + // // idea: PausedPrologStream with only the buffer of unread characters. + // // no stream to be wrapped, no nuttin'. + // ptr::drop_in_place(value.payload_offset() as *mut PausedPrologStream); + // } + ArenaHeaderTag::ReadlineStream => { + ptr::drop_in_place(value.payload_offset() as *mut ReadlineStream); + } + ArenaHeaderTag::StaticStringStream => { + ptr::drop_in_place(value.payload_offset() as *mut StaticStringStream); + } + ArenaHeaderTag::ByteStream => { + ptr::drop_in_place(value.payload_offset() as *mut ByteStream); + } + ArenaHeaderTag::OssifiedOpDir => { + ptr::drop_in_place( + mem::transmute::<_, *mut OssifiedOpDir>(value.payload_offset()) + ); + } + ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => { + ptr::drop_in_place( + mem::transmute::<_, *mut LiveLoadState>(value.payload_offset()) + ); + } + ArenaHeaderTag::Dropped => { + } + ArenaHeaderTag::TcpListener => { + ptr::drop_in_place(value.payload_offset() as *mut TcpListener); + } + ArenaHeaderTag::F64 | ArenaHeaderTag::StandardOutputStream | + ArenaHeaderTag::StandardErrorStream | ArenaHeaderTag::NullStream => { + } + } +} + +impl Drop for Arena { + fn drop(&mut self) { + let mut ptr = self.0; + + while !ptr.is_null() { + unsafe { + let ptr_r = &*ptr; + + let layout = alloc::Layout::from_size_align_unchecked( + ptr_r.slab_size(), + mem::align_of::(), + ); + + drop_slab_in_place(&mut *ptr); + + let next_ptr = ptr_r.next; + alloc::dealloc(ptr as *mut u8, layout); + ptr = next_ptr; + } + } + + self.0 = ptr::null_mut(); + } +} + +const_assert!(mem::size_of::() == 16); + +impl AllocSlab { + #[inline] + fn slab_size(&self) -> usize { + self.header.size() as usize + mem::size_of::() + } + + fn payload_offset(&self) -> *const u8 { + let mut ptr = (self as *const AllocSlab) as usize; + ptr += mem::size_of::(); + ptr as *const u8 + } +} + +const_assert!(mem::size_of::>() == 8); + +#[cfg(test)] +mod tests { + use crate::machine::mock_wam::*; + use crate::machine::partial_string::*; + + use ordered_float::OrderedFloat; + use rug::{Integer, Rational}; + + #[test] + fn float_ptr_cast() { + let mut wam = MockWAM::new(); + + let f = OrderedFloat(0f64); + let mut fp = arena_alloc!(f, &mut wam.machine_st.arena); + let cell = HeapCellValue::from(fp); + + assert_eq!(cell.get_tag(), HeapCellValueTag::F64); + assert_eq!(fp.get_mark_bit(), false); + assert_eq!(**fp, f); + + fp.mark(); + + assert_eq!(fp.get_mark_bit(), true); + + read_heap_cell!(cell, + (HeapCellValueTag::F64, ptr) => { + assert_eq!(**ptr, f) + } + _ => { unreachable!() } + ); + } + + #[test] + fn heap_cell_value_const_cast() { + let mut wam = MockWAM::new(); + let const_value = HeapCellValue::from(ConsPtr::build_with( + 0x0000_5555_ff00_0431 as *const _, + ConsPtrMaskTag::Cons, + )); + + match const_value.to_untyped_arena_ptr() { + Some(arena_ptr) => { + assert_eq!(arena_ptr.into_bytes(), const_value.into_bytes()); + } + None => { + assert!(false); + } + } + + let stream = Stream::from_static_string("test", &mut wam.machine_st.arena); + let stream_cell = + HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons)); + + match stream_cell.to_untyped_arena_ptr() { + Some(arena_ptr) => { + assert_eq!(arena_ptr.into_bytes(), stream_cell.into_bytes()); + } + None => { + assert!(false); + } + } + } + + #[test] + fn heap_put_literal_tests() { + let mut wam = MockWAM::new(); + + // integer + + let big_int = 2 * Integer::from(1u64 << 63); + let big_int_ptr: TypedArenaPtr = arena_alloc!(big_int, &mut wam.machine_st.arena); + + assert!(!big_int_ptr.as_ptr().is_null()); + + let cell = HeapCellValue::from(Literal::Integer(big_int_ptr)); + assert_eq!(cell.get_tag(), HeapCellValueTag::Cons); + + let untyped_arena_ptr = match cell.to_untyped_arena_ptr() { + Some(ptr) => ptr, + None => { + assert!(false); + unreachable!() + } + }; + + match_untyped_arena_ptr!(untyped_arena_ptr, + (ArenaHeaderTag::Integer, n) => { + assert_eq!(&*n, &(2 * Integer::from(1u64 << 63))) + } + _ => unreachable!() + ); + + read_heap_cell!(cell, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Integer, n) => { + assert_eq!(&*n, &(2 * Integer::from(1u64 << 63))) + } + _ => { unreachable!() } + ) + } + _ => { unreachable!() } + ); + + // rational + + let big_rat = 2 * Rational::from(1u64 << 63); + let big_rat_ptr: TypedArenaPtr = arena_alloc!(big_rat, &mut wam.machine_st.arena); + + assert!(!big_rat_ptr.as_ptr().is_null()); + + let rat_cell = typed_arena_ptr_as_cell!(big_rat_ptr); + assert_eq!(cell.get_tag(), HeapCellValueTag::Cons); + + match rat_cell.to_untyped_arena_ptr() { + Some(untyped_arena_ptr) => { + assert_eq!( + Some(big_rat_ptr.header_ptr()), + Some(untyped_arena_ptr.into()), + ); + } + None => { + assert!(false); // we fail. + } + } + + // assert_eq!(wam.machine_st.heap[1usize].get_tag(), HeapCellValueTag::Cons); + + read_heap_cell!(rat_cell, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Rational, n) => { + assert_eq!(&*n, &(2 * Rational::from(1u64 << 63))); + } + _ => unreachable!() + ) + } + _ => { unreachable!() } + ); + + // atom + + let f_atom = atom!("f"); + let g_atom = atom!("g"); + + assert_eq!(f_atom.as_str(), "f"); + assert_eq!(g_atom.as_str(), "g"); + + let f_atom_cell = atom_as_cell!(f_atom); + let g_atom_cell = atom_as_cell!(g_atom); + + assert_eq!(f_atom_cell.get_tag(), HeapCellValueTag::Atom); + + match f_atom_cell.to_atom() { + Some(atom) => { + assert_eq!(f_atom, atom); + assert_eq!(atom.as_str(), "f"); + } + None => { + assert!(false); + } + } + + read_heap_cell!(f_atom_cell, + (HeapCellValueTag::Atom, (atom, arity)) => { + assert_eq!(f_atom, atom); + assert_eq!(arity, 0); + assert_eq!(atom.as_str(), "f"); + } + _ => { unreachable!() } + ); + + read_heap_cell!(g_atom_cell, + (HeapCellValueTag::Atom, (atom, arity)) => { + assert_eq!(g_atom, atom); + assert_eq!(arity, 0); + assert_eq!(atom.as_str(), "g"); + } + _ => { unreachable!() } + ); + + // complete string + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "ronan", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + assert_eq!(pstr_cell.get_tag(), HeapCellValueTag::PStr); + + match pstr_cell.to_pstr() { + Some(pstr) => { + assert_eq!(pstr.as_str_from(0), "ronan"); + } + None => { + assert!(false); + } + } + + read_heap_cell!(pstr_cell, + (HeapCellValueTag::PStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + assert_eq!(pstr.as_str_from(0), "ronan"); + } + _ => { unreachable!() } + ); + + // fixnum + + let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3)); + + assert_eq!(fixnum_cell.get_tag(), HeapCellValueTag::Fixnum); + + match fixnum_cell.to_fixnum() { + Some(n) => assert_eq!(n.get_num(), 3), + None => assert!(false), + } + + read_heap_cell!(fixnum_cell, + (HeapCellValueTag::Fixnum, n) => { + assert_eq!(n.get_num(), 3); + } + _ => { unreachable!() } + ); + + let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 55)); + + assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum); + + match fixnum_b_cell.to_fixnum() { + Some(n) => assert_eq!(n.get_num(), 1 << 55), + None => assert!(false), + } + + match Fixnum::build_with_checked(1 << 57) { + Ok(_) => assert!(false), + _ => assert!(true), + } + + match Fixnum::build_with_checked(i64::MAX) { + Ok(_) => assert!(false), + _ => assert!(true), + } + + match Fixnum::build_with_checked(i64::MIN) { + Ok(_) => assert!(false), + _ => assert!(true), + } + + match Fixnum::build_with_checked(-1) { + Ok(n) => assert_eq!(n.get_num(), -1), + _ => assert!(false), + } + + match Fixnum::build_with_checked((1 << 56) - 1) { + Ok(n) => assert_eq!(n.get_num(), (1 << 56) - 1), + _ => assert!(false), + } + + match Fixnum::build_with_checked(-(1 << 56)) { + Ok(n) => assert_eq!(n.get_num(), -(1 << 56)), + _ => assert!(false), + } + + match Fixnum::build_with_checked(-(1 << 56) - 1) { + Ok(_n) => assert!(false), + _ => assert!(true), + } + + match Fixnum::build_with_checked(-1) { + Ok(n) => assert_eq!(-n, Fixnum::build_with(1)), + _ => assert!(false), + } + + // float + + let float = OrderedFloat(3.1415926f64); + let float_ptr = arena_alloc!(float, &mut wam.machine_st.arena); + + assert!(!float_ptr.as_ptr().is_null()); + + let float_cell = typed_arena_ptr_as_cell!(float_ptr); + assert_eq!(cell.get_tag(), HeapCellValueTag::Cons); + + match float_cell.to_untyped_arena_ptr() { + Some(untyped_arena_ptr) => { + assert_eq!(Some(float_ptr.header_ptr()), Some(untyped_arena_ptr.into()),); + } + None => { + assert!(false); // we fail. + } + } + + // char + + let c = 'c'; + let char_cell = char_as_cell!(c); + + read_heap_cell!(char_cell, + (HeapCellValueTag::Char, c) => { + assert_eq!(c, 'c'); + } + _ => { unreachable!() } + ); + + let c = 'Ћ'; + let cyrillic_char_cell = char_as_cell!(c); + + read_heap_cell!(cyrillic_char_cell, + (HeapCellValueTag::Char, c) => { + assert_eq!(c, 'Ћ'); + } + _ => { unreachable!() } + ); + + // empty list + + let cell = empty_list_as_cell!(); + + read_heap_cell!(cell, + (HeapCellValueTag::Atom, (el, _arity)) => { + assert_eq!(el.flat_index() as usize, empty_list_as_cell!().get_value()); + assert_eq!(el.as_str(), "[]"); + } + _ => { unreachable!() } + ); + } +} diff --git a/src/arithmetic.rs b/src/arithmetic.rs index f5a3beeb..d09187f8 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -1,18 +1,19 @@ -use prolog_parser::ast::*; -use prolog_parser::{atom, clause_name}; - +use crate::arena::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::fixtures::*; use crate::forms::*; use crate::instructions::*; use crate::iterators::*; +use crate::types::*; + +use crate::parser::ast::*; +use crate::parser::rug::ops::PowAssign; +use crate::parser::rug::{Assign, Integer, Rational}; -use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; -use crate::rug::ops::PowAssign; -use crate::rug::{Assign, Integer, Rational}; use ordered_float::*; use std::cell::Cell; @@ -20,7 +21,7 @@ use std::cmp::{max, min, Ordering}; use std::convert::TryFrom; use std::f64; use std::num::FpCategory; -use std::ops::{Add, Div, Mul, Neg, Sub}; +use std::ops::Div; use std::rc::Rc; use std::vec::Vec; @@ -37,31 +38,30 @@ impl<'a> ArithInstructionIterator<'a> { .push(TermIterState::subterm_to_state(lvl, term)); } - fn new(term: &'a Term) -> Result { + fn from(term: &'a Term) -> Result { let state = match term { - &Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar), - &Term::Clause(ref cell, ref name, ref terms, ref fixity) => { - match ClauseType::from(name.clone(), terms.len(), fixity.clone()) { - ct @ ClauseType::Named(..) | ct @ ClauseType::Op(..) => { - Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) - } - ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => { - let ct = ClauseType::Named(clause_name!("float"), 1, CodeIndex::default()); - Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) - } - _ => Err(ArithmeticError::NonEvaluableFunctor( - Constant::Atom(name.clone(), fixity.clone()), - terms.len(), - )), - }? - } - &Term::Constant(ref cell, ref cons) => { - TermIterState::Constant(Level::Shallow, cell, cons) - } - &Term::Cons(_, _, _) => { - return Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2)) - } - &Term::Var(ref cell, ref var) => TermIterState::Var(Level::Shallow, cell, var.clone()), + Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar), + Term::Clause(cell, name, terms) => match ClauseType::from(*name, terms.len()) { + ct @ ClauseType::Named(..) => { + Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) + } + ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => { + let ct = ClauseType::Named(atom!("float"), 1, CodeIndex::default()); + Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) + } + _ => Err(ArithmeticError::NonEvaluableFunctor( + Literal::Atom(*name), + terms.len(), + )), + }?, + Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons), + Term::Cons(..) | Term::PartialString(..) => { + return Err(ArithmeticError::NonEvaluableFunctor( + Literal::Atom(atom!(".")), + 2, + )) + } + Term::Var(cell, var) => TermIterState::Var(Level::Shallow, cell, var.clone()), }; Ok(ArithInstructionIterator { @@ -72,9 +72,9 @@ impl<'a> ArithInstructionIterator<'a> { #[derive(Debug)] pub(crate) enum ArithTermRef<'a> { - Constant(&'a Constant), - Op(ClauseName, usize), // name, arity. - Var(&'a Cell, Rc), + Literal(&'a Literal), + Op(Atom, usize), // name, arity. + Var(&'a Cell, Rc), } impl<'a> Iterator for ArithInstructionIterator<'a> { @@ -97,14 +97,20 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { ct, subterms, )); - self.push_subterm(lvl, subterms[child_num].as_ref()); + + self.push_subterm(lvl, &subterms[child_num]); } } - TermIterState::Constant(_, _, c) => return Some(Ok(ArithTermRef::Constant(c))), + TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))), TermIterState::Var(_, cell, var) => { - return Some(Ok(ArithTermRef::Var(cell, var.clone()))) + return Some(Ok(ArithTermRef::Var(cell, var.clone()))); + } + _ => { + return Some(Err(ArithmeticError::NonEvaluableFunctor( + Literal::Atom(atom!(".")), + 2, + ))); } - _ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))), }; } @@ -129,8 +135,29 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term { type Iter = ArithInstructionIterator<'a>; fn iter(self) -> Result { - ArithInstructionIterator::new(self) + ArithInstructionIterator::from(self) + } +} + +fn push_literal(interm: &mut Vec, c: &Literal) -> Result<(), ArithmeticError> { + match c { + Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))), + Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))), + Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(***n))), + Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))), + Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(f64::consts::E)), + )), + Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(f64::consts::PI)), + )), + Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(f64::EPSILON)), + )), + _ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)), } + + Ok(()) } impl<'a> ArithmeticEvaluator<'a> { @@ -143,68 +170,64 @@ impl<'a> ArithmeticEvaluator<'a> { } fn get_unary_instr( - name: ClauseName, + &self, + name: Atom, a1: ArithmeticTerm, t: usize, ) -> Result { - match name.as_str() { - "abs" => Ok(ArithmeticInstruction::Abs(a1, t)), - "-" => Ok(ArithmeticInstruction::Neg(a1, t)), - "+" => Ok(ArithmeticInstruction::Plus(a1, t)), - "cos" => Ok(ArithmeticInstruction::Cos(a1, t)), - "sin" => Ok(ArithmeticInstruction::Sin(a1, t)), - "tan" => Ok(ArithmeticInstruction::Tan(a1, t)), - "log" => Ok(ArithmeticInstruction::Log(a1, t)), - "exp" => Ok(ArithmeticInstruction::Exp(a1, t)), - "sqrt" => Ok(ArithmeticInstruction::Sqrt(a1, t)), - "acos" => Ok(ArithmeticInstruction::ACos(a1, t)), - "asin" => Ok(ArithmeticInstruction::ASin(a1, t)), - "atan" => Ok(ArithmeticInstruction::ATan(a1, t)), - "float" => Ok(ArithmeticInstruction::Float(a1, t)), - "truncate" => Ok(ArithmeticInstruction::Truncate(a1, t)), - "round" => Ok(ArithmeticInstruction::Round(a1, t)), - "ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)), - "floor" => Ok(ArithmeticInstruction::Floor(a1, t)), - "sign" => Ok(ArithmeticInstruction::Sign(a1, t)), - "\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)), - _ => Err(ArithmeticError::NonEvaluableFunctor( - Constant::Atom(name, None), - 1, - )), + match name { + atom!("abs") => Ok(ArithmeticInstruction::Abs(a1, t)), + atom!("-") => Ok(ArithmeticInstruction::Neg(a1, t)), + atom!("+") => Ok(ArithmeticInstruction::Plus(a1, t)), + atom!("cos") => Ok(ArithmeticInstruction::Cos(a1, t)), + atom!("sin") => Ok(ArithmeticInstruction::Sin(a1, t)), + atom!("tan") => Ok(ArithmeticInstruction::Tan(a1, t)), + atom!("log") => Ok(ArithmeticInstruction::Log(a1, t)), + atom!("exp") => Ok(ArithmeticInstruction::Exp(a1, t)), + atom!("sqrt") => Ok(ArithmeticInstruction::Sqrt(a1, t)), + atom!("acos") => Ok(ArithmeticInstruction::ACos(a1, t)), + atom!("asin") => Ok(ArithmeticInstruction::ASin(a1, t)), + atom!("atan") => Ok(ArithmeticInstruction::ATan(a1, t)), + atom!("float") => Ok(ArithmeticInstruction::Float(a1, t)), + atom!("truncate") => Ok(ArithmeticInstruction::Truncate(a1, t)), + atom!("round") => Ok(ArithmeticInstruction::Round(a1, t)), + atom!("ceiling") => Ok(ArithmeticInstruction::Ceiling(a1, t)), + atom!("floor") => Ok(ArithmeticInstruction::Floor(a1, t)), + atom!("sign") => Ok(ArithmeticInstruction::Sign(a1, t)), + atom!("\\") => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)), + _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)), } } fn get_binary_instr( - name: ClauseName, + &self, + name: Atom, a1: ArithmeticTerm, a2: ArithmeticTerm, t: usize, ) -> Result { - match name.as_str() { - "+" => Ok(ArithmeticInstruction::Add(a1, a2, t)), - "-" => Ok(ArithmeticInstruction::Sub(a1, a2, t)), - "/" => Ok(ArithmeticInstruction::Div(a1, a2, t)), - "//" => Ok(ArithmeticInstruction::IDiv(a1, a2, t)), - "max" => Ok(ArithmeticInstruction::Max(a1, a2, t)), - "min" => Ok(ArithmeticInstruction::Min(a1, a2, t)), - "div" => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)), - "rdiv" => Ok(ArithmeticInstruction::RDiv(a1, a2, t)), - "*" => Ok(ArithmeticInstruction::Mul(a1, a2, t)), - "**" => Ok(ArithmeticInstruction::Pow(a1, a2, t)), - "^" => Ok(ArithmeticInstruction::IntPow(a1, a2, t)), - ">>" => Ok(ArithmeticInstruction::Shr(a1, a2, t)), - "<<" => Ok(ArithmeticInstruction::Shl(a1, a2, t)), - "/\\" => Ok(ArithmeticInstruction::And(a1, a2, t)), - "\\/" => Ok(ArithmeticInstruction::Or(a1, a2, t)), - "xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)), - "mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)), - "rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)), - "gcd" => Ok(ArithmeticInstruction::Gcd(a1, a2, t)), - "atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)), - _ => Err(ArithmeticError::NonEvaluableFunctor( - Constant::Atom(name, None), - 2, - )), + match name { + atom!("+") => Ok(ArithmeticInstruction::Add(a1, a2, t)), + atom!("-") => Ok(ArithmeticInstruction::Sub(a1, a2, t)), + atom!("/") => Ok(ArithmeticInstruction::Div(a1, a2, t)), + atom!("//") => Ok(ArithmeticInstruction::IDiv(a1, a2, t)), + atom!("max") => Ok(ArithmeticInstruction::Max(a1, a2, t)), + atom!("min") => Ok(ArithmeticInstruction::Min(a1, a2, t)), + atom!("div") => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)), + atom!("rdiv") => Ok(ArithmeticInstruction::RDiv(a1, a2, t)), + atom!("*") => Ok(ArithmeticInstruction::Mul(a1, a2, t)), + atom!("**") => Ok(ArithmeticInstruction::Pow(a1, a2, t)), + atom!("^") => Ok(ArithmeticInstruction::IntPow(a1, a2, t)), + atom!(">>") => Ok(ArithmeticInstruction::Shr(a1, a2, t)), + atom!("<<") => Ok(ArithmeticInstruction::Shl(a1, a2, t)), + atom!("/\\") => Ok(ArithmeticInstruction::And(a1, a2, t)), + atom!("\\/") => Ok(ArithmeticInstruction::Or(a1, a2, t)), + atom!("xor") => Ok(ArithmeticInstruction::Xor(a1, a2, t)), + atom!("mod") => Ok(ArithmeticInstruction::Mod(a1, a2, t)), + atom!("rem") => Ok(ArithmeticInstruction::Rem(a1, a2, t)), + atom!("gcd") => Ok(ArithmeticInstruction::Gcd(a1, a2, t)), + atom!("atan2") => Ok(ArithmeticInstruction::ATan2(a1, a2, t)), + _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)), } } @@ -219,7 +242,7 @@ impl<'a> ArithmeticEvaluator<'a> { fn instr_from_clause( &mut self, - name: ClauseName, + name: Atom, arity: usize, ) -> Result { match arity { @@ -233,7 +256,7 @@ impl<'a> ArithmeticEvaluator<'a> { a1.interm_or(0) }; - Self::get_unary_instr(name, a1, ninterm) + self.get_unary_instr(name, a1, ninterm) } 2 => { let a2 = self.interm.pop().unwrap(); @@ -257,60 +280,22 @@ impl<'a> ArithmeticEvaluator<'a> { min_interm }; - Self::get_binary_instr(name, a1, a2, ninterm) + self.get_binary_instr(name, a1, a2, ninterm) } _ => Err(ArithmeticError::NonEvaluableFunctor( - Constant::Atom(name, None), + Literal::Atom(name), arity, )), } } - fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> { - match c { - &Constant::Fixnum(n) => self.interm.push(ArithmeticTerm::Number(Number::Fixnum(n))), - &Constant::Integer(ref n) => self - .interm - .push(ArithmeticTerm::Number(Number::Integer(n.clone()))), - &Constant::Float(ref n) => self - .interm - .push(ArithmeticTerm::Number(Number::Float(n.clone()))), - &Constant::Rational(ref n) => self - .interm - .push(ArithmeticTerm::Number(Number::Rational(n.clone()))), - &Constant::Atom(ref name, _) if name.as_str() == "e" => { - self.interm - .push(ArithmeticTerm::Number(Number::Float(OrderedFloat( - f64::consts::E, - )))) - } - &Constant::Atom(ref name, _) if name.as_str() == "pi" => { - self.interm - .push(ArithmeticTerm::Number(Number::Float(OrderedFloat( - f64::consts::PI, - )))) - } - &Constant::Atom(ref name, _) if name.as_str() == "epsilon" => { - self.interm - .push(ArithmeticTerm::Number(Number::Float(OrderedFloat( - f64::EPSILON, - )))) - } - _ => return Err(ArithmeticError::NonEvaluableFunctor(c.clone(), 0)), - } - - Ok(()) - } - - pub(crate) fn eval(&mut self, src: Iter) -> Result - where - Iter: ArithmeticTermIter<'a>, - { + pub(crate) fn eval(&mut self, src: &'a Term) -> Result { let mut code = vec![]; + let mut iter = src.iter()?; - for term_ref in src.iter()? { + while let Some(term_ref) = iter.next() { match term_ref? { - ArithTermRef::Constant(c) => self.push_constant(c)?, + ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?, ArithTermRef::Var(cell, name) => { let r = if cell.get().norm().reg_num() == 0 { match self.bindings.get(&name) { @@ -335,27 +320,31 @@ impl<'a> ArithmeticEvaluator<'a> { } // integer division rounding function -- 9.1.3.1. -pub(crate) fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> { +pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number { match n { - &Number::Integer(_) => RefOrOwned::Borrowed(n), - &Number::Float(OrderedFloat(f)) => RefOrOwned::Owned(Number::from( - Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0)), - )), - &Number::Fixnum(n) => RefOrOwned::Owned(Number::from(n)), + &Number::Integer(_) | &Number::Fixnum(_) => *n, + &Number::Float(OrderedFloat(f)) => fixnum!(Number, f.round() as i64, arena), &Number::Rational(ref r) => { let r_ref = r.fract_floor_ref(); let (mut fract, mut floor) = (Rational::new(), Integer::new()); (&mut fract, &mut floor).assign(r_ref); - RefOrOwned::Owned(Number::from(floor)) + Number::Integer(arena_alloc!(floor, arena)) } } } +impl From for Integer { + #[inline] + fn from(n: Fixnum) -> Integer { + Integer::from(n.get_num()) + } +} + // floating point rounding function -- 9.1.4.1. pub(crate) fn rnd_f(n: &Number) -> f64 { match n { - &Number::Fixnum(n) => n as f64, + &Number::Fixnum(n) => n.get_num() as f64, &Number::Integer(ref n) => n.to_f64(), &Number::Float(OrderedFloat(f)) => f, &Number::Rational(ref r) => r.to_f64(), @@ -392,27 +381,27 @@ where } #[inline] -fn float_fn_to_f(n: isize) -> Result { +pub(crate) fn float_fn_to_f(n: i64) -> Result { classify_float(n as f64, rnd_f) } #[inline] -fn float_i_to_f(n: &Integer) -> Result { +pub(crate) fn float_i_to_f(n: &Integer) -> Result { classify_float(n.to_f64(), rnd_f) } #[inline] -fn float_r_to_f(r: &Rational) -> Result { +pub(crate) fn float_r_to_f(r: &Rational) -> Result { classify_float(r.to_f64(), rnd_f) } #[inline] -fn add_f(f1: f64, f2: f64) -> Result, EvalError> { +pub(crate) fn add_f(f1: f64, f2: f64) -> Result, EvalError> { Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?)) } #[inline] -fn mul_f(f1: f64, f2: f64) -> Result, EvalError> { +pub(crate) fn mul_f(f1: f64, f2: f64) -> Result, EvalError> { Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?)) } @@ -425,161 +414,36 @@ fn div_f(f1: f64, f2: f64) -> Result, EvalError> { } } -impl Add for Number { - type Output = Result; - - fn add(self, rhs: Number) -> Self::Output { - match (self, rhs) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - Ok(if let Some(result) = n1.checked_add(n2) { - Number::Fixnum(result) - } else { - Number::from(Integer::from(n1) + Integer::from(n2)) - }) - } - (Number::Fixnum(n1), Number::Integer(n2)) - | (Number::Integer(n2), Number::Fixnum(n1)) => { - Ok(Number::from(Integer::from(n1) + &*n2)) - } - (Number::Fixnum(n1), Number::Rational(n2)) - | (Number::Rational(n2), Number::Fixnum(n1)) => { - Ok(Number::from(Rational::from(n1) + &*n2)) - } - (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => { - Ok(Number::Float(add_f(float_fn_to_f(n1)?, n2)?)) - } - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(&*n1) + &*n2)) // add_i - } - (Number::Integer(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { - Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?)) - } - (Number::Integer(n1), Number::Rational(n2)) - | (Number::Rational(n2), Number::Integer(n1)) => { - Ok(Number::from(Rational::from(&*n1) + &*n2)) - } - (Number::Rational(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { - Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?)) - } - (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { - Ok(Number::Float(add_f(f1, f2)?)) - } - (Number::Rational(r1), Number::Rational(r2)) => { - Ok(Number::from(Rational::from(&*r1) + &*r2)) - } - } - } -} - -impl Neg for Number { - type Output = Number; - - fn neg(self) -> Self::Output { - match self { - Number::Fixnum(n) => { - if let Some(n) = n.checked_neg() { - Number::Fixnum(n) - } else { - Number::from(-Integer::from(n)) - } - } - Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))), - Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)), - Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))), - } - } -} - -impl Sub for Number { - type Output = Result; - - fn sub(self, rhs: Number) -> Self::Output { - self.add(-rhs) - } -} - -impl Mul for Number { - type Output = Result; - - fn mul(self, rhs: Number) -> Self::Output { - match (self, rhs) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - Ok(if let Some(result) = n1.checked_mul(n2) { - Number::Fixnum(result) - } else { - Number::from(Integer::from(n1) * Integer::from(n2)) - }) - } - (Number::Fixnum(n1), Number::Integer(n2)) - | (Number::Integer(n2), Number::Fixnum(n1)) => { - Ok(Number::from(Integer::from(n1) * &*n2)) - } - (Number::Fixnum(n1), Number::Rational(n2)) - | (Number::Rational(n2), Number::Fixnum(n1)) => { - Ok(Number::from(Rational::from(n1) * &*n2)) - } - (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => { - Ok(Number::Float(mul_f(float_fn_to_f(n1)?, n2)?)) - } - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::Integer(Rc::new(Integer::from(&*n1) * &*n2))) // mul_i - } - (Number::Integer(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { - Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?)) - } - (Number::Integer(n1), Number::Rational(n2)) - | (Number::Rational(n2), Number::Integer(n1)) => { - Ok(Number::Rational(Rc::new(Rational::from(&*n1) * &*n2))) - } - (Number::Rational(n1), Number::Float(OrderedFloat(n2))) - | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { - Ok(Number::Float(mul_f(float_r_to_f(&n1)?, n2)?)) - } - (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { - Ok(Number::Float(mul_f(f1, f2)?)) - } - (Number::Rational(r1), Number::Rational(r2)) => { - Ok(Number::Rational(Rc::new(Rational::from(&*r1) * &*r2))) - } - } - } -} - impl Div for Number { type Output = Result; fn div(self, rhs: Number) -> Self::Output { match (self, rhs) { (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f( - float_fn_to_f(n1)?, - float_fn_to_f(n2)?, + float_fn_to_f(n1.get_num())?, + float_fn_to_f(n2.get_num())?, )?)), (Number::Fixnum(n1), Number::Integer(n2)) => Ok(Number::Float(div_f( - float_fn_to_f(n1)?, + float_fn_to_f(n1.get_num())?, float_i_to_f(&n2)?, )?)), (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f( float_i_to_f(&n1)?, - float_fn_to_f(n2)?, + float_fn_to_f(n2.get_num())?, )?)), (Number::Fixnum(n1), Number::Rational(n2)) => Ok(Number::Float(div_f( - float_fn_to_f(n1)?, + float_fn_to_f(n1.get_num())?, float_r_to_f(&n2)?, )?)), (Number::Rational(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f( float_r_to_f(&n1)?, - float_fn_to_f(n2)?, + float_fn_to_f(n2.get_num())?, )?)), (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => { - Ok(Number::Float(div_f(float_fn_to_f(n1)?, n2)?)) + Ok(Number::Float(div_f(float_fn_to_f(n1.get_num())?, n2)?)) } (Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => { - Ok(Number::Float(div_f(n1, float_fn_to_f(n2)?)?)) + Ok(Number::Float(div_f(n1, float_fn_to_f(n2.get_num())?)?)) } (Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f( float_i_to_f(&n1)?, @@ -620,14 +484,14 @@ impl PartialEq for Number { fn eq(&self, rhs: &Self) -> bool { match (self, rhs) { (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2), - (&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.eq(&**n2), - (&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2), - (&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.eq(&**n2), - (&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2), - (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).eq(&n2), - (&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2 as f64)), + (&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.get_num().eq(&**n2), + (&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()), + (&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.get_num().eq(&**n2), + (&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()), + (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).eq(&n2), + (&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2.get_num() as f64)), (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.eq(n2), - (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(&n2), + (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(n2), (&Number::Float(n1), &Number::Integer(ref n2)) => n1.eq(&OrderedFloat(n2.to_f64())), (&Number::Integer(ref n1), &Number::Rational(ref n2)) => { #[cfg(feature = "num")] @@ -659,6 +523,46 @@ impl PartialEq for Number { impl Eq for Number {} +impl PartialOrd for Number { + #[inline] + fn partial_cmp(&self, rhs: &usize) -> Option { + match self { + Number::Fixnum(n) => { + let n = n.get_num(); + + if n < 0i64 { + Some(Ordering::Less) + } else { + (n as usize).partial_cmp(rhs) + } + } + Number::Integer(n) => (&**n).partial_cmp(rhs), + Number::Rational(r) => (&**r).partial_cmp(rhs), + Number::Float(f) => f.partial_cmp(&OrderedFloat(*rhs as f64)), + } + } +} + +impl PartialEq for Number { + #[inline] + fn eq(&self, rhs: &usize) -> bool { + match self { + Number::Fixnum(n) => { + let n = n.get_num(); + + if n < 0i64 { + false + } else { + (n as usize).eq(rhs) + } + } + Number::Integer(n) => (&**n).eq(rhs), + Number::Rational(r) => (&**r).eq(rhs), + Number::Float(f) => f.eq(&OrderedFloat(*rhs as f64)), + } + } +} + impl PartialOrd for Number { fn partial_cmp(&self, rhs: &Number) -> Option { Some(self.cmp(rhs)) @@ -668,15 +572,17 @@ impl PartialOrd for Number { impl Ord for Number { fn cmp(&self, rhs: &Number) -> Ordering { match (self, rhs) { - (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.cmp(&n2), - (&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1).cmp(&*n2), - (Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2)), - (&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1).cmp(&*n2), - (Number::Rational(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Rational::from(n2)), - (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).cmp(&n2), - (&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2 as f64)), + (&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.get_num().cmp(&n2.get_num()), + (&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1.get_num()).cmp(&*n2), + (Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2.get_num())), + (&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1.get_num()).cmp(&*n2), + (Number::Rational(n1), &Number::Fixnum(n2)) => { + (&**n1).cmp(&Rational::from(n2.get_num())) + } + (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).cmp(&n2), + (&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2.get_num() as f64)), (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2), - (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2), + (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(n2), (&Number::Float(n1), &Number::Integer(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())), (&Number::Integer(ref n1), &Number::Rational(ref n2)) => { #[cfg(feature = "num")] @@ -706,54 +612,38 @@ impl Ord for Number { } } -impl<'a> TryFrom<(Addr, &'a Heap)> for Number { +impl TryFrom for Number { type Error = (); - fn try_from((addr, heap): (Addr, &'a Heap)) -> Result { - match addr { - Addr::Fixnum(n) => Ok(Number::from(n)), - Addr::Float(n) => Ok(Number::Float(n)), - Addr::Usize(n) => { - if let Ok(n) = isize::try_from(n) { - Ok(Number::from(n)) - } else { - Ok(Number::from(Integer::from(n))) - } - } - Addr::Con(h) => Number::try_from(&heap[h]), - _ => Err(()), - } - } -} - -impl<'a> TryFrom<&'a HeapCellValue> for Number { - type Error = (); - - fn try_from(value: &'a HeapCellValue) -> Result { - match value { - HeapCellValue::Addr(addr) => match addr { - &Addr::Fixnum(n) => Ok(Number::from(n)), - &Addr::Float(n) => Ok(Number::Float(n)), - &Addr::Usize(n) => { - if let Ok(n) = isize::try_from(n) { - Ok(Number::from(n)) - } else { - Ok(Number::from(Integer::from(n))) - } - } - _ => Err(()), - }, - HeapCellValue::Integer(n) => Ok(Number::Integer(n.clone())), - HeapCellValue::Rational(n) => Ok(Number::Rational(n.clone())), - _ => Err(()), - } - } -} - -impl<'a> From<&'a Integer> for Number { #[inline] - fn from(src: &'a Integer) -> Self { - Number::Integer(Rc::new(Integer::from(src))) + fn try_from(value: HeapCellValue) -> Result { + read_heap_cell!(value, + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::F64, n) => { + Ok(Number::Float(*n)) + } + (ArenaHeaderTag::Integer, n) => { + Ok(Number::Integer(n)) + } + (ArenaHeaderTag::Rational, n) => { + Ok(Number::Rational(n)) + } + _ => { + Err(()) + } + ) + } + (HeapCellValueTag::F64, n) => { + Ok(Number::Float(**n)) + } + (HeapCellValueTag::Fixnum, n) => { + Ok(Number::Fixnum(n)) + } + _ => { + Err(()) + } + ) } } diff --git a/src/atom_table.rs b/src/atom_table.rs new file mode 100644 index 00000000..71771cc2 --- /dev/null +++ b/src/atom_table.rs @@ -0,0 +1,366 @@ +use crate::parser::ast::MAX_ARITY; +use crate::raw_block::*; +use crate::types::*; + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::hash::{Hash, Hasher}; +use std::mem; +use std::ptr; +use std::slice; +use std::str; + +use indexmap::IndexSet; + +use modular_bitfield::prelude::*; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Atom { + pub index: usize, +} + +const_assert!(mem::size_of::() == 8); + +include!("./static_atoms.rs"); + +impl<'a> From<&'a Atom> for Atom { + #[inline] + fn from(atom: &'a Atom) -> Self { + *atom + } +} + +impl From for Atom { + #[inline] + fn from(value: bool) -> Self { + if value { atom!("true") } else { atom!("false") } + } +} + +#[cfg(test)] +use std::cell::RefCell; + +const ATOM_TABLE_INIT_SIZE: usize = 1 << 16; +const ATOM_TABLE_ALIGN: usize = 8; + +#[cfg(test)] +thread_local! { + static ATOM_TABLE_BUF_BASE: RefCell<*const u8> = RefCell::new(ptr::null_mut()); +} + +#[cfg(not(test))] +static mut ATOM_TABLE_BUF_BASE: *const u8 = ptr::null_mut(); + +#[cfg(test)] +fn set_atom_tbl_buf_base(ptr: *const u8) { + ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| { + *atom_table_buf_base.borrow_mut() = ptr; + }); +} + +#[cfg(test)] +pub(crate) fn get_atom_tbl_buf_base() -> *const u8 { + ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| *atom_table_buf_base.borrow()) +} + +#[cfg(not(test))] +fn set_atom_tbl_buf_base(ptr: *const u8) { + unsafe { + ATOM_TABLE_BUF_BASE = ptr; + } +} + +#[cfg(not(test))] +pub(crate) fn get_atom_tbl_buf_base() -> *const u8 { + unsafe { ATOM_TABLE_BUF_BASE } +} + +impl RawBlockTraits for AtomTable { + #[inline] + fn init_size() -> usize { + ATOM_TABLE_INIT_SIZE + } + + #[inline] + fn align() -> usize { + ATOM_TABLE_ALIGN + } +} + +#[bitfield] +#[derive(Copy, Clone, Debug)] +struct AtomHeader { + #[allow(unused)] m: bool, + len: B50, + #[allow(unused)] padding: B13, +} + +impl AtomHeader { + fn build_with(len: u64) -> Self { + AtomHeader::new().with_len(len).with_m(false) + } +} + +impl Borrow for Atom { + #[inline] + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl Hash for Atom { + #[inline] + fn hash(&self, hasher: &mut H) { + self.as_str().hash(hasher) + // hasher.write_usize(self.index) + } +} + +#[macro_export] +macro_rules! is_char { + ($s:expr) => { + !$s.is_empty() && $s.chars().nth(1).is_none() + }; +} + +impl Atom { + #[inline] + pub fn buf(self) -> *const u8 { + let ptr = self.as_ptr(); + + if ptr.is_null() { + return ptr::null(); + } + + (ptr as usize + mem::size_of::()) as *const u8 + } + + #[inline(always)] + pub fn is_static(self) -> bool { + self.index < STRINGS.len() << 3 + } + + #[inline(always)] + pub fn as_ptr(self) -> *const u8 { + if self.is_static() { + ptr::null() + } else { + (get_atom_tbl_buf_base() as usize + self.index - (STRINGS.len() << 3)) as *const u8 + } + } + + #[inline(always)] + pub fn from(index: usize) -> Self { + Self { index } + } + + #[inline(always)] + pub fn len(self) -> usize { + if self.is_static() { + STRINGS[self.index >> 3].len() + } else { + unsafe { ptr::read(self.as_ptr() as *const AtomHeader).len() as _ } + } + } + + #[inline(always)] + pub fn flat_index(self) -> u64 { + (self.index >> 3) as u64 + } + + pub fn as_char(self) -> Option { + let s = self.as_str(); + let mut it = s.chars(); + + let c1 = it.next(); + let c2 = it.next(); + + if c2.is_none() { c1 } else { None } + } + + #[inline] + pub fn chars(&self) -> str::Chars { + self.as_str().chars() + } + + #[inline] + pub fn as_str(&self) -> &str { + unsafe { + let ptr = self.as_ptr(); + + if ptr.is_null() { + return STRINGS[self.index >> 3]; + } + + let header = ptr::read::(ptr as *const _); + let len = header.len() as usize; + let buf = (ptr as usize + mem::size_of::()) as *mut u8; + + str::from_utf8_unchecked(slice::from_raw_parts(buf, len)) + } + } + + pub fn defrock_brackets(&self, atom_tbl: &mut AtomTable) -> Self { + let s = self.as_str(); + + let s = if s.starts_with('(') && s.ends_with(')') { + &s['('.len_utf8()..s.len() - ')'.len_utf8()] + } else { + return *self; + }; + + atom_tbl.build_with(s) + } +} + +unsafe fn write_to_ptr(string: &str, ptr: *mut u8) { + ptr::write(ptr as *mut _, AtomHeader::build_with(string.len() as u64)); + let str_ptr = (ptr as usize + mem::size_of::()) as *mut u8; + ptr::copy_nonoverlapping(string.as_ptr(), str_ptr as *mut u8, string.len()); +} + +impl PartialOrd for Atom { + #[inline] + fn partial_cmp(&self, other: &Atom) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Atom { + #[inline] + fn cmp(&self, other: &Atom) -> Ordering { + self.as_str().cmp(other.as_str()) + } +} + +#[derive(Debug)] +pub struct AtomTable { + block: RawBlock, + pub table: IndexSet, +} + +impl Drop for AtomTable { + fn drop(&mut self) { + self.block.deallocate(); + } +} + +impl AtomTable { + #[inline] + pub fn new() -> Self { + let table = Self { + block: RawBlock::new(), + table: IndexSet::new(), + }; + + set_atom_tbl_buf_base(table.block.base); + table + } + + #[inline] + pub fn buf(&self) -> *const u8 { + self.block.base as *const u8 + } + + #[inline] + pub fn top(&self) -> *const u8 { + self.block.top + } + + #[inline(always)] + fn lookup_str(&self, string: &str) -> Option { + STATIC_ATOMS_MAP.get(string).or_else(|| self.table.get(string)).cloned() + } + + pub fn build_with(&mut self, string: &str) -> Atom { + if let Some(atom) = self.lookup_str(string) { + return atom; + } + + unsafe { + let size = mem::size_of::() + string.len(); + let align_offset = 8 * mem::align_of::(); + let size = (size & !(align_offset - 1)) + align_offset; + + let len_ptr = { + let mut ptr; + + loop { + ptr = self.block.alloc(size); + + if ptr.is_null() { + self.block.grow(); + set_atom_tbl_buf_base(self.block.base); + } else { + break; + } + } + + ptr + }; + + let ptr_base = self.block.base as usize; + + write_to_ptr(string, len_ptr); + + let atom = Atom { + index: (STRINGS.len() << 3) + len_ptr as usize - ptr_base, + }; + + self.table.insert(atom); + + atom + } + } +} + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug)] +pub struct AtomCell { + name: B46, + arity: B10, + #[allow(unused)] f: bool, + #[allow(unused)] m: bool, + #[allow(unused)] tag: B6, +} + +impl AtomCell { + #[inline] + pub fn build_with(name: u64, arity: u16, tag: HeapCellValueTag) -> Self { + if arity > 0 { + debug_assert!(arity as usize <= MAX_ARITY); + + AtomCell::new() + .with_name(name) + .with_arity(arity) + .with_f(false) + .with_tag(tag as u8) + } else { + AtomCell::new() + .with_name(name) + .with_f(false) + .with_tag(tag as u8) + } + } + + #[inline] + pub fn get_index(self) -> usize { + self.name() as usize + } + + #[inline] + pub fn get_name(self) -> Atom { + Atom::from(self.get_index() << 3) + } + + #[inline] + pub fn get_arity(self) -> usize { + self.arity() as usize + } + + #[inline] + pub fn get_name_and_arity(self) -> (Atom, usize) { + (Atom::from(self.get_index() << 3), self.get_arity()) + } +} diff --git a/src/bin/scryer-prolog.rs b/src/bin/scryer-prolog.rs index a1cf2a99..f8d3aa6e 100644 --- a/src/bin/scryer-prolog.rs +++ b/src/bin/scryer-prolog.rs @@ -1,16 +1,12 @@ fn main() { use nix::sys::signal; - use scryer_prolog::read::readline; use scryer_prolog::*; let handler = signal::SigHandler::Handler(handle_sigint); unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap(); - let mut wam = machine::Machine::new( - readline::input_stream(), - machine::Stream::stdout(), - machine::Stream::stderr(), - ); + let mut wam = machine::Machine::new(); + wam.run_top_level(); } diff --git a/src/clause_types.rs b/src/clause_types.rs index cb654867..e7c2c853 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -1,16 +1,15 @@ -use prolog_parser::ast::*; -use prolog_parser::{clause_name, temp_v}; - -use crate::forms::Number; +use crate::atom_table::*; use crate::machine::machine_indices::*; -use crate::rug::rand::RandState; +use crate::parser::ast::*; +use crate::parser::rug::rand::RandState; -use ref_thread_local::{ref_thread_local, RefThreadLocal}; +use crate::forms::Number; +use crate::temp_v; -use std::collections::BTreeMap; +use ref_thread_local::{ref_thread_local}; #[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub(crate) enum CompareNumberQT { +pub enum CompareNumberQT { GreaterThan, LessThan, GreaterThanOrEqual, @@ -20,20 +19,20 @@ pub(crate) enum CompareNumberQT { } impl CompareNumberQT { - fn name(self) -> &'static str { + fn name(self) -> Atom { match self { - CompareNumberQT::GreaterThan => ">", - CompareNumberQT::LessThan => "<", - CompareNumberQT::GreaterThanOrEqual => ">=", - CompareNumberQT::LessThanOrEqual => "=<", - CompareNumberQT::NotEqual => "=\\=", - CompareNumberQT::Equal => "=:=", + CompareNumberQT::GreaterThan => atom!(">"), + CompareNumberQT::LessThan => atom!("<"), + CompareNumberQT::GreaterThanOrEqual => atom!(">="), + CompareNumberQT::LessThanOrEqual => atom!("=<"), + CompareNumberQT::NotEqual => atom!("=\\="), + CompareNumberQT::Equal => atom!("=:="), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum CompareTermQT { +pub enum CompareTermQT { LessThan, LessThanOrEqual, GreaterThanOrEqual, @@ -41,18 +40,18 @@ pub(crate) enum CompareTermQT { } impl CompareTermQT { - fn name<'a>(self) -> &'a str { + fn name(self) -> Atom { match self { - CompareTermQT::GreaterThan => "@>", - CompareTermQT::LessThan => "@<", - CompareTermQT::GreaterThanOrEqual => "@>=", - CompareTermQT::LessThanOrEqual => "@=<", + CompareTermQT::GreaterThan => atom!("@>"), + CompareTermQT::LessThan => atom!("@<"), + CompareTermQT::GreaterThanOrEqual => atom!("@>="), + CompareTermQT::LessThanOrEqual => atom!("@=<"), } } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum ArithmeticTerm { +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ArithmeticTerm { Reg(RegType), Interm(usize), Number(Number), @@ -68,8 +67,8 @@ impl ArithmeticTerm { } } -#[derive(Debug, Clone, Eq, PartialEq)] -pub(crate) enum InlinedClauseType { +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum InlinedClauseType { CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm), IsAtom(RegType), IsAtomic(RegType), @@ -83,73 +82,106 @@ pub(crate) enum InlinedClauseType { } ref_thread_local! { - pub(crate)static managed RANDOM_STATE: RandState<'static> = RandState::new(); + pub(crate) static managed RANDOM_STATE: RandState<'static> = RandState::new(); } -ref_thread_local! { - pub(crate)static managed CLAUSE_TYPE_FORMS: BTreeMap<(&'static str, usize), ClauseType> = { - let mut m = BTreeMap::new(); - - let r1 = temp_v!(1); - let r2 = temp_v!(2); - - m.insert((">", 2), - ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThan, ar_reg!(r1), ar_reg!(r2)))); - m.insert(("<", 2), - ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::LessThan, ar_reg!(r1), ar_reg!(r2)))); - m.insert((">=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThanOrEqual, ar_reg!(r1), ar_reg!(r2)))); - m.insert(("=<", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::LessThanOrEqual, ar_reg!(r1), ar_reg!(r2)))); - m.insert(("=:=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::Equal, ar_reg!(r1), ar_reg!(r2)))); - m.insert(("=\\=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::NotEqual, ar_reg!(r1), ar_reg!(r2)))); - m.insert(("atom", 1), ClauseType::Inlined(InlinedClauseType::IsAtom(r1))); - m.insert(("atomic", 1), ClauseType::Inlined(InlinedClauseType::IsAtomic(r1))); - m.insert(("compound", 1), ClauseType::Inlined(InlinedClauseType::IsCompound(r1))); - m.insert(("integer", 1), ClauseType::Inlined(InlinedClauseType::IsInteger(r1))); - m.insert(("number", 1), ClauseType::Inlined(InlinedClauseType::IsNumber(r1))); - m.insert(("rational", 1), ClauseType::Inlined(InlinedClauseType::IsRational(r1))); - m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1))); - m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1))); - m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1))); - m.insert(("acyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm)); - m.insert(("arg", 3), ClauseType::BuiltIn(BuiltInClauseType::Arg)); - m.insert(("compare", 3), ClauseType::BuiltIn(BuiltInClauseType::Compare)); - m.insert(("@>", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThan))); - m.insert(("@<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThan))); - m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual))); - m.insert(("@=<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual))); - m.insert(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm)); - m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq)); - m.insert(("functor", 3), ClauseType::BuiltIn(BuiltInClauseType::Functor)); - m.insert(("ground", 1), ClauseType::BuiltIn(BuiltInClauseType::Ground)); - m.insert(("is", 2), ClauseType::BuiltIn(BuiltInClauseType::Is(r1, ar_reg!(r2)))); - m.insert(("keysort", 2), ClauseType::BuiltIn(BuiltInClauseType::KeySort)); - m.insert(("\\==", 2), ClauseType::BuiltIn(BuiltInClauseType::NotEq)); - m.insert(("read", 2), ClauseType::BuiltIn(BuiltInClauseType::Read)); - m.insert(("sort", 2), ClauseType::BuiltIn(BuiltInClauseType::Sort)); - - m - }; +pub fn clause_type_form(name: Atom, arity: usize) -> Option { + match (name, arity) { + (atom!(">"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::GreaterThan, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!("<"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::LessThan, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!(">="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::GreaterThanOrEqual, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!("=<"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::LessThanOrEqual, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!("=:="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::Equal, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!("=\\="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( + CompareNumberQT::NotEqual, + ar_reg!(temp_v!(1)), + ar_reg!(temp_v!(2)), + ))), + (atom!("atom"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsAtom(temp_v!(1)))), + (atom!("atomic"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsAtomic(temp_v!(1)))), + (atom!("compound"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsCompound(temp_v!( + 1 + )))), + (atom!("integer"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsInteger(temp_v!( + 1 + )))), + (atom!("number"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsNumber(temp_v!(1)))), + (atom!("rational"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsRational(temp_v!( + 1 + )))), + (atom!("float"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsFloat(temp_v!(1)))), + (atom!("nonvar"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsNonVar(temp_v!(1)))), + (atom!("var"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsVar(temp_v!(1)))), + (atom!("acyclic_term"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm)), + (atom!("arg"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Arg)), + (atom!("compare"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Compare)), + (atom!("@>"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( + CompareTermQT::GreaterThan, + ))), + (atom!("@<"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( + CompareTermQT::LessThan, + ))), + (atom!("@>="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( + CompareTermQT::GreaterThanOrEqual, + ))), + (atom!("@=<"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( + CompareTermQT::LessThanOrEqual, + ))), + (atom!("copy_term"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CopyTerm)), + (atom!("=="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Eq)), + (atom!("functor"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Functor)), + (atom!("ground"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::Ground)), + (atom!("is"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Is( + temp_v!(1), + ar_reg!(temp_v!(2)), + ))), + (atom!("keysort"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::KeySort)), + (atom!("\\=="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::NotEq)), + (atom!("read"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::Read)), + (atom!("sort"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Sort)), + _ => None, + } } impl InlinedClauseType { - pub(crate) fn name(&self) -> &'static str { + pub(crate) fn name(&self) -> Atom { match self { &InlinedClauseType::CompareNumber(qt, ..) => qt.name(), - &InlinedClauseType::IsAtom(..) => "atom", - &InlinedClauseType::IsAtomic(..) => "atomic", - &InlinedClauseType::IsCompound(..) => "compound", - &InlinedClauseType::IsNumber(..) => "number", - &InlinedClauseType::IsInteger(..) => "integer", - &InlinedClauseType::IsRational(..) => "rational", - &InlinedClauseType::IsFloat(..) => "float", - &InlinedClauseType::IsNonVar(..) => "nonvar", - &InlinedClauseType::IsVar(..) => "var", + &InlinedClauseType::IsAtom(..) => atom!("atom"), + &InlinedClauseType::IsAtomic(..) => atom!("atomic"), + &InlinedClauseType::IsCompound(..) => atom!("compound"), + &InlinedClauseType::IsNumber(..) => atom!("number"), + &InlinedClauseType::IsInteger(..) => atom!("integer"), + &InlinedClauseType::IsRational(..) => atom!("rational"), + &InlinedClauseType::IsFloat(..) => atom!("float"), + &InlinedClauseType::IsNonVar(..) => atom!("nonvar"), + &InlinedClauseType::IsVar(..) => atom!("var"), } } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub(crate) enum SystemClauseType { +pub enum SystemClauseType { AtomChars, AtomCodes, AtomLength, @@ -176,8 +208,8 @@ pub(crate) enum SystemClauseType { MakeDirectoryPath, DeleteFile, RenameFile, - DeleteDirectory, WorkingDirectory, + DeleteDirectory, PathCanonical, FileTime, DeleteAttribute, @@ -203,8 +235,6 @@ pub(crate) enum SystemClauseType { GetNextDBRef, GetNextOpDBRef, IsPartialString, - LookupDBRef, - LookupOpDBRef, Halt, GetLiftedHeapFromOffset, GetLiftedHeapFromOffsetDiff, @@ -278,11 +308,11 @@ pub(crate) enum SystemClauseType { Succeed, TermAttributedVariables, TermVariables, + TermVariablesUnderMaxDepth, TruncateLiftedHeapTo, UnifyWithOccursCheck, UnwindEnvironments, UnwindStack, - Variant, WAMInstructions, WriteTerm, WriteTermToChars, @@ -319,566 +349,509 @@ pub(crate) enum SystemClauseType { } impl SystemClauseType { - pub(crate) fn name(&self) -> ClauseName { + pub(crate) fn name(&self) -> Atom { match self { - &SystemClauseType::AtomChars => clause_name!("$atom_chars"), - &SystemClauseType::AtomCodes => clause_name!("$atom_codes"), - &SystemClauseType::AtomLength => clause_name!("$atom_length"), - &SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"), - &SystemClauseType::CallContinuation => clause_name!("$call_continuation"), - &SystemClauseType::CharCode => clause_name!("$char_code"), - &SystemClauseType::CharType => clause_name!("$char_type"), - &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), - &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"), - &SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"), + &SystemClauseType::AtomChars => atom!("$atom_chars"), + &SystemClauseType::AtomCodes => atom!("$atom_codes"), + &SystemClauseType::AtomLength => atom!("$atom_length"), + &SystemClauseType::BindFromRegister => atom!("$bind_from_register"), + &SystemClauseType::CallContinuation => atom!("$call_continuation"), + &SystemClauseType::CharCode => atom!("$char_code"), + &SystemClauseType::CharType => atom!("$char_type"), + &SystemClauseType::CharsToNumber => atom!("$chars_to_number"), + &SystemClauseType::CheckCutPoint => atom!("$check_cp"), + &SystemClauseType::CodesToNumber => atom!("$codes_to_number"), &SystemClauseType::CopyTermWithoutAttrVars => { - clause_name!("$copy_term_without_attr_vars") - } - &SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"), - &SystemClauseType::CurrentInput => clause_name!("$current_input"), - &SystemClauseType::CurrentHostname => clause_name!("$current_hostname"), - &SystemClauseType::CurrentOutput => clause_name!("$current_output"), - &SystemClauseType::DirectoryFiles => clause_name!("$directory_files"), - &SystemClauseType::FileSize => clause_name!("$file_size"), - &SystemClauseType::FileExists => clause_name!("$file_exists"), - &SystemClauseType::DirectoryExists => clause_name!("$directory_exists"), - &SystemClauseType::DirectorySeparator => clause_name!("$directory_separator"), - &SystemClauseType::MakeDirectory => clause_name!("$make_directory"), - &SystemClauseType::MakeDirectoryPath => clause_name!("$make_directory_path"), - &SystemClauseType::DeleteFile => clause_name!("$delete_file"), - &SystemClauseType::RenameFile => clause_name!("$rename_file"), - &SystemClauseType::DeleteDirectory => clause_name!("$delete_directory"), - &SystemClauseType::WorkingDirectory => clause_name!("$working_directory"), - &SystemClauseType::PathCanonical => clause_name!("$path_canonical"), - &SystemClauseType::FileTime => clause_name!("$file_time"), + atom!("$copy_term_without_attr_vars") + } + &SystemClauseType::CreatePartialString => atom!("$create_partial_string"), + &SystemClauseType::CurrentInput => atom!("$current_input"), + &SystemClauseType::CurrentHostname => atom!("$current_hostname"), + &SystemClauseType::CurrentOutput => atom!("$current_output"), + &SystemClauseType::DirectoryFiles => atom!("$directory_files"), + &SystemClauseType::FileSize => atom!("$file_size"), + &SystemClauseType::FileExists => atom!("$file_exists"), + &SystemClauseType::DirectoryExists => atom!("$directory_exists"), + &SystemClauseType::DirectorySeparator => atom!("$directory_separator"), + &SystemClauseType::MakeDirectory => atom!("$make_directory"), + &SystemClauseType::MakeDirectoryPath => atom!("$make_directory_path"), + &SystemClauseType::DeleteFile => atom!("$delete_file"), + &SystemClauseType::RenameFile => atom!("$rename_file"), + &SystemClauseType::DeleteDirectory => atom!("$delete_directory"), + &SystemClauseType::WorkingDirectory => atom!("$working_directory"), + &SystemClauseType::PathCanonical => atom!("$path_canonical"), + &SystemClauseType::FileTime => atom!("$file_time"), &SystemClauseType::REPL(REPLCodePtr::AddDiscontiguousPredicate) => { - clause_name!("$add_discontiguous_predicate") - } - &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => { - clause_name!("$add_dynamic_predicate") + atom!("$add_discontiguous_predicate") } + &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => atom!("$add_dynamic_predicate"), &SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate) => { - clause_name!("$add_multifile_predicate") + atom!("$add_multifile_predicate") } &SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause) => { - clause_name!("$add_goal_expansion_clause") + atom!("$add_goal_expansion_clause") } &SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause) => { - clause_name!("$add_term_expansion_clause") - } - &SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) => { - clause_name!("$clause_to_evacuable") + atom!("$add_term_expansion_clause") } + &SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) => atom!("$clause_to_evacuable"), &SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable) => { - clause_name!("$scoped_clause_to_evacuable") - } - &SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) => clause_name!("$conclude_load"), - &SystemClauseType::REPL(REPLCodePtr::DeclareModule) => clause_name!("$declare_module"), - &SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary) => { - clause_name!("$load_compiled_library") + atom!("$scoped_clause_to_evacuable") } + &SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) => atom!("$conclude_load"), + &SystemClauseType::REPL(REPLCodePtr::DeclareModule) => atom!("$declare_module"), + &SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary) => atom!("$load_compiled_library"), &SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload) => { - clause_name!("$push_load_state_payload") + atom!("$push_load_state_payload") } &SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule) => { - clause_name!("$add_in_situ_filename_module") - } - &SystemClauseType::REPL(REPLCodePtr::Asserta) => clause_name!("$asserta"), - &SystemClauseType::REPL(REPLCodePtr::Assertz) => clause_name!("$assertz"), - &SystemClauseType::REPL(REPLCodePtr::Retract) => clause_name!("$retract_clause"), - &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), - &SystemClauseType::REPL(REPLCodePtr::PushLoadContext) => { - clause_name!("$push_load_context") - } - &SystemClauseType::REPL(REPLCodePtr::PopLoadContext) => { - clause_name!("$pop_load_context") - } - &SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) => { - clause_name!("$pop_load_state_payload") - } - &SystemClauseType::REPL(REPLCodePtr::LoadContextSource) => { - clause_name!("$prolog_lc_source") - } - &SystemClauseType::REPL(REPLCodePtr::LoadContextFile) => { - clause_name!("$prolog_lc_file") - } - &SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) => { - clause_name!("$prolog_lc_dir") - } - &SystemClauseType::REPL(REPLCodePtr::LoadContextModule) => { - clause_name!("$prolog_lc_module") - } - &SystemClauseType::REPL(REPLCodePtr::LoadContextStream) => { - clause_name!("$prolog_lc_stream") - } + atom!("$add_in_situ_filename_module") + } + &SystemClauseType::REPL(REPLCodePtr::Asserta) => atom!("$asserta"), + &SystemClauseType::REPL(REPLCodePtr::Assertz) => atom!("$assertz"), + &SystemClauseType::REPL(REPLCodePtr::Retract) => atom!("$retract_clause"), + &SystemClauseType::REPL(REPLCodePtr::UseModule) => atom!("$use_module"), + &SystemClauseType::REPL(REPLCodePtr::PushLoadContext) => atom!("$push_load_context"), + &SystemClauseType::REPL(REPLCodePtr::PopLoadContext) => atom!("$pop_load_context"), + &SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) => atom!("$pop_load_state_payload"), + &SystemClauseType::REPL(REPLCodePtr::LoadContextSource) => atom!("$prolog_lc_source"), + &SystemClauseType::REPL(REPLCodePtr::LoadContextFile) => atom!("$prolog_lc_file"), + &SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) => atom!("$prolog_lc_dir"), + &SystemClauseType::REPL(REPLCodePtr::LoadContextModule) => atom!("$prolog_lc_module"), + &SystemClauseType::REPL(REPLCodePtr::LoadContextStream) => atom!("$prolog_lc_stream"), &SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty) => { - clause_name!("$cpp_meta_predicate_property") - } - &SystemClauseType::REPL(REPLCodePtr::BuiltInProperty) => { - clause_name!("$cpp_built_in_property") - } - &SystemClauseType::REPL(REPLCodePtr::DynamicProperty) => { - clause_name!("$cpp_dynamic_property") - } - &SystemClauseType::REPL(REPLCodePtr::MultifileProperty) => { - clause_name!("$cpp_multifile_property") + atom!("$cpp_meta_predicate_property") } + &SystemClauseType::REPL(REPLCodePtr::BuiltInProperty) => atom!("$cpp_built_in_property"), + &SystemClauseType::REPL(REPLCodePtr::DynamicProperty) => atom!("$cpp_dynamic_property"), + &SystemClauseType::REPL(REPLCodePtr::MultifileProperty) => atom!("$cpp_multifile_property"), &SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty) => { - clause_name!("$cpp_discontiguous_property") + atom!("$cpp_discontiguous_property") } - &SystemClauseType::REPL(REPLCodePtr::AbolishClause) => clause_name!("$abolish_clause"), + &SystemClauseType::REPL(REPLCodePtr::AbolishClause) => atom!("$abolish_clause"), &SystemClauseType::REPL(REPLCodePtr::IsConsistentWithTermQueue) => { - clause_name!("$is_consistent_with_term_queue") - } - &SystemClauseType::REPL(REPLCodePtr::FlushTermQueue) => { - clause_name!("$flush_term_queue") - } - &SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports) => { - clause_name!("$remove_module_exports") + atom!("$is_consistent_with_term_queue") } + &SystemClauseType::REPL(REPLCodePtr::FlushTermQueue) => atom!("$flush_term_queue"), + &SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports) => atom!("$remove_module_exports"), &SystemClauseType::REPL(REPLCodePtr::AddNonCountedBacktracking) => { - clause_name!("$add_non_counted_backtracking") - } - &SystemClauseType::Close => clause_name!("$close"), - &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"), - &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"), - &SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"), - &SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"), - &SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"), - &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"), - &SystemClauseType::FirstStream => clause_name!("$first_stream"), - &SystemClauseType::FlushOutput => clause_name!("$flush_output"), - &SystemClauseType::GetByte => clause_name!("$get_byte"), - &SystemClauseType::GetChar => clause_name!("$get_char"), - &SystemClauseType::GetNChars => clause_name!("$get_n_chars"), - &SystemClauseType::GetCode => clause_name!("$get_code"), - &SystemClauseType::GetSingleChar => clause_name!("$get_single_char"), - &SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"), - &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { - clause_name!("$truncate_if_no_lh_growth") - } - &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => { - clause_name!("$truncate_if_no_lh_growth_diff") - } - &SystemClauseType::GetAttributedVariableList => clause_name!("$get_attr_list"), - &SystemClauseType::GetAttrVarQueueDelimiter => { - clause_name!("$get_attr_var_queue_delim") - } - &SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"), - &SystemClauseType::GetContinuationChunk => clause_name!("$get_cont_chunk"), - &SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"), - &SystemClauseType::GetLiftedHeapFromOffsetDiff => { - clause_name!("$get_lh_from_offset_diff") - } - &SystemClauseType::GetBValue => clause_name!("$get_b_value"), - // &SystemClauseType::GetClause => clause_name!("$get_clause"), - &SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"), - &SystemClauseType::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"), - &SystemClauseType::LookupDBRef => clause_name!("$lookup_db_ref"), - &SystemClauseType::LookupOpDBRef => clause_name!("$lookup_op_db_ref"), - &SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"), - // &SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"), - &SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"), - &SystemClauseType::Halt => clause_name!("$halt"), - &SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"), - &SystemClauseType::Open => clause_name!("$open"), - &SystemClauseType::SetStreamOptions => clause_name!("$set_stream_options"), - &SystemClauseType::OpDeclaration => clause_name!("$op"), - &SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"), - &SystemClauseType::InstallInferenceCounter => { - clause_name!("$install_inference_counter") - } - &SystemClauseType::IsPartialString => clause_name!("$is_partial_string"), - &SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"), - &SystemClauseType::PeekByte => clause_name!("$peek_byte"), - &SystemClauseType::PeekChar => clause_name!("$peek_char"), - &SystemClauseType::PeekCode => clause_name!("$peek_code"), - &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") - // } - // &SystemClauseType::ModuleAssertDynamicPredicateToBack => { - // clause_name!("$module_assertz") - // } - // &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"), - &SystemClauseType::ModuleExists => clause_name!("$module_exists"), - &SystemClauseType::NextStream => clause_name!("$next_stream"), - &SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"), - &SystemClauseType::NumberToChars => clause_name!("$number_to_chars"), - &SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"), + atom!("$add_non_counted_backtracking") + } + &SystemClauseType::Close => atom!("$close"), + &SystemClauseType::CopyToLiftedHeap => atom!("$copy_to_lh"), + &SystemClauseType::DeleteAttribute => atom!("$del_attr_non_head"), + &SystemClauseType::DeleteHeadAttribute => atom!("$del_attr_head"), + &SystemClauseType::DynamicModuleResolution(_) => atom!("$module_call"), + &SystemClauseType::EnqueueAttributedVar => atom!("$enqueue_attr_var"), + &SystemClauseType::FetchGlobalVar => atom!("$fetch_global_var"), + &SystemClauseType::FirstStream => atom!("$first_stream"), + &SystemClauseType::FlushOutput => atom!("$flush_output"), + &SystemClauseType::GetByte => atom!("$get_byte"), + &SystemClauseType::GetChar => atom!("$get_char"), + &SystemClauseType::GetNChars => atom!("$get_n_chars"), + &SystemClauseType::GetCode => atom!("$get_code"), + &SystemClauseType::GetSingleChar => atom!("$get_single_char"), + &SystemClauseType::ResetAttrVarState => atom!("$reset_attr_var_state"), + &SystemClauseType::TruncateIfNoLiftedHeapGrowth => atom!("$truncate_if_no_lh_growth"), + &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => atom!("$truncate_if_no_lh_growth_diff"), + &SystemClauseType::GetAttributedVariableList => atom!("$get_attr_list"), + &SystemClauseType::GetAttrVarQueueDelimiter => atom!("$get_attr_var_queue_delim"), + &SystemClauseType::GetAttrVarQueueBeyond => atom!("$get_attr_var_queue_beyond"), + &SystemClauseType::GetContinuationChunk => atom!("$get_cont_chunk"), + &SystemClauseType::GetLiftedHeapFromOffset => atom!("$get_lh_from_offset"), + &SystemClauseType::GetLiftedHeapFromOffsetDiff => atom!("$get_lh_from_offset_diff"), + &SystemClauseType::GetBValue => atom!("$get_b_value"), + &SystemClauseType::GetNextDBRef => atom!("$get_next_db_ref"), + &SystemClauseType::GetNextOpDBRef => atom!("$get_next_op_db_ref"), + &SystemClauseType::GetDoubleQuotes => atom!("$get_double_quotes"), + &SystemClauseType::GetSCCCleaner => atom!("$get_scc_cleaner"), + &SystemClauseType::Halt => atom!("$halt"), + &SystemClauseType::HeadIsDynamic => atom!("$head_is_dynamic"), + &SystemClauseType::Open => atom!("$open"), + &SystemClauseType::OpDeclaration => atom!("$op"), + &SystemClauseType::InstallSCCCleaner => atom!("$install_scc_cleaner"), + &SystemClauseType::InstallInferenceCounter => atom!("$install_inference_counter"), + &SystemClauseType::IsPartialString => atom!("$is_partial_string"), + &SystemClauseType::PartialStringTail => atom!("$partial_string_tail"), + &SystemClauseType::PeekByte => atom!("$peek_byte"), + &SystemClauseType::PeekChar => atom!("$peek_char"), + &SystemClauseType::PeekCode => atom!("$peek_code"), + &SystemClauseType::LiftedHeapLength => atom!("$lh_length"), + &SystemClauseType::Maybe => atom!("maybe"), + &SystemClauseType::CpuNow => atom!("$cpu_now"), + &SystemClauseType::CurrentTime => atom!("$current_time"), + // &SystemClauseType::ModuleHeadIsDynamic => atom!("$module_head_is_dynamic"), + &SystemClauseType::ModuleExists => atom!("$module_exists"), + &SystemClauseType::NextStream => atom!("$next_stream"), + &SystemClauseType::NoSuchPredicate => atom!("$no_such_predicate"), + &SystemClauseType::NumberToChars => atom!("$number_to_chars"), + &SystemClauseType::NumberToCodes => atom!("$number_to_codes"), &SystemClauseType::PointsToContinuationResetMarker => { - clause_name!("$points_to_cont_reset_marker") + atom!("$points_to_cont_reset_marker") } &SystemClauseType::PutByte => { - clause_name!("$put_byte") + atom!("$put_byte") } &SystemClauseType::PutChar => { - clause_name!("$put_char") + atom!("$put_char") } &SystemClauseType::PutChars => { - clause_name!("$put_chars") + atom!("$put_chars") } &SystemClauseType::PutCode => { - clause_name!("$put_code") + atom!("$put_code") } &SystemClauseType::QuotedToken => { - clause_name!("$quoted_token") - } - &SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"), - &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"), - &SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"), - &SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"), - &SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"), - &SystemClauseType::SetInput => clause_name!("$set_input"), - &SystemClauseType::SetOutput => clause_name!("$set_output"), - &SystemClauseType::SetSeed => clause_name!("$set_seed"), - &SystemClauseType::StreamProperty => clause_name!("$stream_property"), - &SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"), + atom!("$quoted_token") + } + &SystemClauseType::RedoAttrVarBinding => atom!("$redo_attr_var_binding"), + &SystemClauseType::RemoveCallPolicyCheck => atom!("$remove_call_policy_check"), + &SystemClauseType::RemoveInferenceCounter => atom!("$remove_inference_counter"), + &SystemClauseType::RestoreCutPolicy => atom!("$restore_cut_policy"), + &SystemClauseType::SetCutPoint(_) => atom!("$set_cp"), + &SystemClauseType::SetInput => atom!("$set_input"), + &SystemClauseType::SetOutput => atom!("$set_output"), + &SystemClauseType::SetSeed => atom!("$set_seed"), + &SystemClauseType::StreamProperty => atom!("$stream_property"), + &SystemClauseType::SetStreamPosition => atom!("$set_stream_position"), + &SystemClauseType::SetStreamOptions => atom!("$set_stream_options"), &SystemClauseType::StoreBacktrackableGlobalVar => { - clause_name!("$store_back_trackable_global_var") - } - &SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"), - &SystemClauseType::InferenceLevel => clause_name!("$inference_level"), - &SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"), - &SystemClauseType::EraseBall => clause_name!("$erase_ball"), - &SystemClauseType::Fail => clause_name!("$fail"), - &SystemClauseType::GetBall => clause_name!("$get_ball"), - &SystemClauseType::GetCutPoint => clause_name!("$get_cp"), - &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"), - &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"), - &SystemClauseType::NextEP => clause_name!("$nextEP"), - &SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"), - &SystemClauseType::ReadTerm => clause_name!("$read_term"), - &SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"), - &SystemClauseType::ResetBlock => clause_name!("$reset_block"), - &SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"), - &SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"), - &SystemClauseType::SetBall => clause_name!("$set_ball"), - &SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"), - &SystemClauseType::SetDoubleQuotes => clause_name!("$set_double_quotes"), - &SystemClauseType::SkipMaxList => clause_name!("$skip_max_list"), - &SystemClauseType::Sleep => clause_name!("$sleep"), - &SystemClauseType::SocketClientOpen => clause_name!("$socket_client_open"), - &SystemClauseType::SocketServerOpen => clause_name!("$socket_server_open"), - &SystemClauseType::SocketServerAccept => clause_name!("$socket_server_accept"), - &SystemClauseType::SocketServerClose => clause_name!("$socket_server_close"), - &SystemClauseType::TLSAcceptClient => clause_name!("$tls_accept_client"), - &SystemClauseType::TLSClientConnect => clause_name!("$tls_client_connect"), - &SystemClauseType::Succeed => clause_name!("$succeed"), + atom!("$store_back_trackable_global_var") + } + &SystemClauseType::StoreGlobalVar => atom!("$store_global_var"), + &SystemClauseType::InferenceLevel => atom!("$inference_level"), + &SystemClauseType::CleanUpBlock => atom!("$clean_up_block"), + &SystemClauseType::EraseBall => atom!("$erase_ball"), + &SystemClauseType::Fail => atom!("$fail"), + &SystemClauseType::GetBall => atom!("$get_ball"), + &SystemClauseType::GetCutPoint => atom!("$get_cp"), + &SystemClauseType::GetCurrentBlock => atom!("$get_current_block"), + &SystemClauseType::InstallNewBlock => atom!("$install_new_block"), + &SystemClauseType::NextEP => atom!("$nextEP"), + &SystemClauseType::ReadQueryTerm => atom!("$read_query_term"), + &SystemClauseType::ReadTerm => atom!("$read_term"), + &SystemClauseType::ReadTermFromChars => atom!("$read_term_from_chars"), + &SystemClauseType::ResetBlock => atom!("$reset_block"), + &SystemClauseType::ResetContinuationMarker => atom!("$reset_cont_marker"), + &SystemClauseType::ReturnFromVerifyAttr => atom!("$return_from_verify_attr"), + &SystemClauseType::SetBall => atom!("$set_ball"), + &SystemClauseType::SetCutPointByDefault(_) => atom!("$set_cp_by_default"), + &SystemClauseType::SetDoubleQuotes => atom!("$set_double_quotes"), + &SystemClauseType::SkipMaxList => atom!("$skip_max_list"), + &SystemClauseType::Sleep => atom!("$sleep"), + &SystemClauseType::SocketClientOpen => atom!("$socket_client_open"), + &SystemClauseType::SocketServerOpen => atom!("$socket_server_open"), + &SystemClauseType::SocketServerAccept => atom!("$socket_server_accept"), + &SystemClauseType::SocketServerClose => atom!("$socket_server_close"), + &SystemClauseType::TLSAcceptClient => atom!("$tls_accept_client"), + &SystemClauseType::TLSClientConnect => atom!("$tls_client_connect"), + &SystemClauseType::Succeed => atom!("$succeed"), &SystemClauseType::TermAttributedVariables => { - clause_name!("$term_attributed_variables") - } - &SystemClauseType::TermVariables => clause_name!("$term_variables"), - &SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"), - &SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"), - &SystemClauseType::UnwindEnvironments => clause_name!("$unwind_environments"), - &SystemClauseType::UnwindStack => clause_name!("$unwind_stack"), - &SystemClauseType::Variant => clause_name!("$variant"), - &SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"), - &SystemClauseType::WriteTerm => clause_name!("$write_term"), - &SystemClauseType::WriteTermToChars => clause_name!("$write_term_to_chars"), - &SystemClauseType::ScryerPrologVersion => clause_name!("$scryer_prolog_version"), - &SystemClauseType::CryptoRandomByte => clause_name!("$crypto_random_byte"), - &SystemClauseType::CryptoDataHash => clause_name!("$crypto_data_hash"), - &SystemClauseType::CryptoDataHKDF => clause_name!("$crypto_data_hkdf"), - &SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"), - &SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"), - &SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"), - &SystemClauseType::CryptoCurveScalarMult => clause_name!("$crypto_curve_scalar_mult"), - &SystemClauseType::Ed25519Sign => clause_name!("$ed25519_sign"), - &SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"), - &SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"), + atom!("$term_attributed_variables") + } + &SystemClauseType::TermVariables => atom!("$term_variables"), + &SystemClauseType::TermVariablesUnderMaxDepth => atom!("$term_variables_under_max_depth"), + &SystemClauseType::TruncateLiftedHeapTo => atom!("$truncate_lh_to"), + &SystemClauseType::UnifyWithOccursCheck => atom!("$unify_with_occurs_check"), + &SystemClauseType::UnwindEnvironments => atom!("$unwind_environments"), + &SystemClauseType::UnwindStack => atom!("$unwind_stack"), + &SystemClauseType::WAMInstructions => atom!("$wam_instructions"), + &SystemClauseType::WriteTerm => atom!("$write_term"), + &SystemClauseType::WriteTermToChars => atom!("$write_term_to_chars"), + &SystemClauseType::ScryerPrologVersion => atom!("$scryer_prolog_version"), + &SystemClauseType::CryptoRandomByte => atom!("$crypto_random_byte"), + &SystemClauseType::CryptoDataHash => atom!("$crypto_data_hash"), + &SystemClauseType::CryptoDataHKDF => atom!("$crypto_data_hkdf"), + &SystemClauseType::CryptoPasswordHash => atom!("$crypto_password_hash"), + &SystemClauseType::CryptoDataEncrypt => atom!("$crypto_data_encrypt"), + &SystemClauseType::CryptoDataDecrypt => atom!("$crypto_data_decrypt"), + &SystemClauseType::CryptoCurveScalarMult => atom!("$crypto_curve_scalar_mult"), + &SystemClauseType::Ed25519Sign => atom!("$ed25519_sign"), + &SystemClauseType::Ed25519Verify => atom!("$ed25519_verify"), + &SystemClauseType::Ed25519NewKeyPair => atom!("$ed25519_new_keypair"), &SystemClauseType::Ed25519KeyPairPublicKey => { - clause_name!("$ed25519_keypair_public_key") - } - &SystemClauseType::Curve25519ScalarMult => clause_name!("$curve25519_scalar_mult"), - &SystemClauseType::FirstNonOctet => clause_name!("$first_non_octet"), - &SystemClauseType::LoadHTML => clause_name!("$load_html"), - &SystemClauseType::LoadXML => clause_name!("$load_xml"), - &SystemClauseType::GetEnv => clause_name!("$getenv"), - &SystemClauseType::SetEnv => clause_name!("$setenv"), - &SystemClauseType::UnsetEnv => clause_name!("$unsetenv"), - &SystemClauseType::Shell => clause_name!("$shell"), - &SystemClauseType::PID => clause_name!("$pid"), - &SystemClauseType::CharsBase64 => clause_name!("$chars_base64"), - &SystemClauseType::LoadLibraryAsStream => clause_name!("$load_library_as_stream"), - &SystemClauseType::DevourWhitespace => clause_name!("$devour_whitespace"), - &SystemClauseType::IsSTOEnabled => clause_name!("$is_sto_enabled"), - &SystemClauseType::SetSTOAsUnify => clause_name!("$set_sto_as_unify"), - &SystemClauseType::SetNSTOAsUnify => clause_name!("$set_nsto_as_unify"), - &SystemClauseType::HomeDirectory => clause_name!("$home_directory"), + atom!("$ed25519_keypair_public_key") + } + &SystemClauseType::Curve25519ScalarMult => atom!("$curve25519_scalar_mult"), + &SystemClauseType::FirstNonOctet => atom!("$first_non_octet"), + &SystemClauseType::LoadHTML => atom!("$load_html"), + &SystemClauseType::LoadXML => atom!("$load_xml"), + &SystemClauseType::GetEnv => atom!("$getenv"), + &SystemClauseType::SetEnv => atom!("$setenv"), + &SystemClauseType::UnsetEnv => atom!("$unsetenv"), + &SystemClauseType::Shell => atom!("$shell"), + &SystemClauseType::PID => atom!("$pid"), + &SystemClauseType::CharsBase64 => atom!("$chars_base64"), + &SystemClauseType::LoadLibraryAsStream => atom!("$load_library_as_stream"), + &SystemClauseType::DevourWhitespace => atom!("$devour_whitespace"), + &SystemClauseType::IsSTOEnabled => atom!("$is_sto_enabled"), + &SystemClauseType::SetSTOAsUnify => atom!("$set_sto_as_unify"), + &SystemClauseType::SetNSTOAsUnify => atom!("$set_nsto_as_unify"), + &SystemClauseType::HomeDirectory => atom!("$home_directory"), &SystemClauseType::SetSTOWithErrorAsUnify => { - clause_name!("$set_sto_with_error_as_unify") + atom!("$set_sto_with_error_as_unify") } - &SystemClauseType::DebugHook => clause_name!("$debug_hook"), - &SystemClauseType::PopCount => clause_name!("$popcount"), + &SystemClauseType::DebugHook => atom!("$debug_hook"), + &SystemClauseType::PopCount => atom!("$popcount"), } } - pub(crate) fn from(name: &str, arity: usize) -> Option { + pub(crate) fn from(name: Atom, arity: usize) -> Option { match (name, arity) { - ("$abolish_clause", 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)), - ("$add_dynamic_predicate", 4) => { + (atom!("$abolish_clause"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)), + (atom!("$add_dynamic_predicate"), 4) => { Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate)) } - ("$add_multifile_predicate", 4) => { + (atom!("$add_multifile_predicate"), 4) => { Some(SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate)) } - ("$add_discontiguous_predicate", 4) => Some(SystemClauseType::REPL( + (atom!("$add_discontiguous_predicate"), 4) => Some(SystemClauseType::REPL( REPLCodePtr::AddDiscontiguousPredicate, )), - ("$add_goal_expansion_clause", 3) => { + (atom!("$add_goal_expansion_clause"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause)) } - ("$add_term_expansion_clause", 2) => { + (atom!("$add_term_expansion_clause"), 2) => { Some(SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause)) } - ("$atom_chars", 2) => Some(SystemClauseType::AtomChars), - ("$atom_codes", 2) => Some(SystemClauseType::AtomCodes), - ("$atom_length", 2) => Some(SystemClauseType::AtomLength), - ("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister), - ("$call_continuation", 1) => Some(SystemClauseType::CallContinuation), - ("$char_code", 2) => Some(SystemClauseType::CharCode), - ("$char_type", 2) => Some(SystemClauseType::CharType), - ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), - ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), - ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), - ("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString), - ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), - ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), - ("$close", 2) => Some(SystemClauseType::Close), - ("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname), - ("$current_input", 1) => Some(SystemClauseType::CurrentInput), - ("$current_output", 1) => Some(SystemClauseType::CurrentOutput), - ("$first_stream", 1) => Some(SystemClauseType::FirstStream), - ("$next_stream", 2) => Some(SystemClauseType::NextStream), - ("$flush_output", 1) => Some(SystemClauseType::FlushOutput), - ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute), - ("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute), - ("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef), - ("$get_next_op_db_ref", 2) => Some(SystemClauseType::GetNextOpDBRef), - ("$lookup_db_ref", 3) => Some(SystemClauseType::LookupDBRef), - ("$lookup_op_db_ref", 4) => Some(SystemClauseType::LookupOpDBRef), - ("$module_call", _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)), - ("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar), - ("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail), - ("$peek_byte", 2) => Some(SystemClauseType::PeekByte), - ("$peek_char", 2) => Some(SystemClauseType::PeekChar), - ("$peek_code", 2) => Some(SystemClauseType::PeekCode), - ("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString), - ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), - ("$get_byte", 2) => Some(SystemClauseType::GetByte), - ("$get_char", 2) => Some(SystemClauseType::GetChar), - ("$get_n_chars", 3) => Some(SystemClauseType::GetNChars), - ("$get_code", 2) => Some(SystemClauseType::GetCode), - ("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar), - ("$points_to_cont_reset_marker", 1) => { + (atom!("$atom_chars"), 2) => Some(SystemClauseType::AtomChars), + (atom!("$atom_codes"), 2) => Some(SystemClauseType::AtomCodes), + (atom!("$atom_length"), 2) => Some(SystemClauseType::AtomLength), + (atom!("$bind_from_register"), 2) => Some(SystemClauseType::BindFromRegister), + (atom!("$call_continuation"), 1) => Some(SystemClauseType::CallContinuation), + (atom!("$char_code"), 2) => Some(SystemClauseType::CharCode), + (atom!("$char_type"), 2) => Some(SystemClauseType::CharType), + (atom!("$chars_to_number"), 2) => Some(SystemClauseType::CharsToNumber), + (atom!("$codes_to_number"), 2) => Some(SystemClauseType::CodesToNumber), + (atom!("$copy_term_without_attr_vars"), 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), + (atom!("$create_partial_string"), 3) => Some(SystemClauseType::CreatePartialString), + (atom!("$check_cp"), 1) => Some(SystemClauseType::CheckCutPoint), + (atom!("$copy_to_lh"), 2) => Some(SystemClauseType::CopyToLiftedHeap), + (atom!("$close"), 2) => Some(SystemClauseType::Close), + (atom!("$current_hostname"), 1) => Some(SystemClauseType::CurrentHostname), + (atom!("$current_input"), 1) => Some(SystemClauseType::CurrentInput), + (atom!("$current_output"), 1) => Some(SystemClauseType::CurrentOutput), + (atom!("$first_stream"), 1) => Some(SystemClauseType::FirstStream), + (atom!("$next_stream"), 2) => Some(SystemClauseType::NextStream), + (atom!("$flush_output"), 1) => Some(SystemClauseType::FlushOutput), + (atom!("$del_attr_non_head"), 1) => Some(SystemClauseType::DeleteAttribute), + (atom!("$del_attr_head"), 1) => Some(SystemClauseType::DeleteHeadAttribute), + (atom!("$get_next_db_ref"), 2) => Some(SystemClauseType::GetNextDBRef), + (atom!("$get_next_op_db_ref"), 2) => Some(SystemClauseType::GetNextOpDBRef), + (atom!("$module_call"), _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)), + (atom!("$enqueue_attr_var"), 1) => Some(SystemClauseType::EnqueueAttributedVar), + (atom!("$partial_string_tail"), 2) => Some(SystemClauseType::PartialStringTail), + (atom!("$peek_byte"), 2) => Some(SystemClauseType::PeekByte), + (atom!("$peek_char"), 2) => Some(SystemClauseType::PeekChar), + (atom!("$peek_code"), 2) => Some(SystemClauseType::PeekCode), + (atom!("$is_partial_string"), 1) => Some(SystemClauseType::IsPartialString), + (atom!("$fetch_global_var"), 2) => Some(SystemClauseType::FetchGlobalVar), + (atom!("$get_byte"), 2) => Some(SystemClauseType::GetByte), + (atom!("$get_char"), 2) => Some(SystemClauseType::GetChar), + (atom!("$get_n_chars"), 3) => Some(SystemClauseType::GetNChars), + (atom!("$get_code"), 2) => Some(SystemClauseType::GetCode), + (atom!("$get_single_char"), 1) => Some(SystemClauseType::GetSingleChar), + (atom!("$points_to_cont_reset_marker"), 1) => { Some(SystemClauseType::PointsToContinuationResetMarker) } - ("$put_byte", 2) => Some(SystemClauseType::PutByte), - ("$put_char", 2) => Some(SystemClauseType::PutChar), - ("$put_chars", 2) => Some(SystemClauseType::PutChars), - ("$put_code", 2) => Some(SystemClauseType::PutCode), - ("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState), - ("$truncate_if_no_lh_growth", 1) => { + (atom!("$put_byte"), 2) => Some(SystemClauseType::PutByte), + (atom!("$put_char"), 2) => Some(SystemClauseType::PutChar), + (atom!("$put_chars"), 2) => Some(SystemClauseType::PutChars), + (atom!("$put_code"), 2) => Some(SystemClauseType::PutCode), + (atom!("$reset_attr_var_state"), 0) => Some(SystemClauseType::ResetAttrVarState), + (atom!("$truncate_if_no_lh_growth"), 1) => { Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth) } - ("$truncate_if_no_lh_growth_diff", 2) => { + (atom!("$truncate_if_no_lh_growth_diff"), 2) => { Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff) } - ("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList), - ("$get_b_value", 1) => Some(SystemClauseType::GetBValue), - ("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset), - ("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff), - ("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes), - ("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner), - ("$halt", 1) => Some(SystemClauseType::Halt), - ("$head_is_dynamic", 2) => Some(SystemClauseType::HeadIsDynamic), - ("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner), - ("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter), - ("$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), - ("$no_such_predicate", 2) => Some(SystemClauseType::NoSuchPredicate), - ("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars), - ("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes), - ("$op", 3) => Some(SystemClauseType::OpDeclaration), - ("$open", 7) => Some(SystemClauseType::Open), - ("$set_stream_options", 5) => Some(SystemClauseType::SetStreamOptions), - ("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding), - ("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck), - ("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter), - ("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy), - ("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))), - ("$set_input", 1) => Some(SystemClauseType::SetInput), - ("$set_output", 1) => Some(SystemClauseType::SetOutput), - ("$stream_property", 3) => Some(SystemClauseType::StreamProperty), - ("$set_stream_position", 2) => Some(SystemClauseType::SetStreamPosition), - ("$inference_level", 2) => Some(SystemClauseType::InferenceLevel), - ("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock), - ("$erase_ball", 0) => Some(SystemClauseType::EraseBall), - ("$fail", 0) => Some(SystemClauseType::Fail), - ("$get_attr_var_queue_beyond", 2) => Some(SystemClauseType::GetAttrVarQueueBeyond), - ("$get_attr_var_queue_delim", 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter), - ("$get_ball", 1) => Some(SystemClauseType::GetBall), - ("$get_cont_chunk", 3) => Some(SystemClauseType::GetContinuationChunk), - ("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock), - ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint), - ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), - ("$quoted_token", 1) => Some(SystemClauseType::QuotedToken), - ("$nextEP", 3) => Some(SystemClauseType::NextEP), - ("$read_query_term", 5) => Some(SystemClauseType::ReadQueryTerm), - ("$read_term", 5) => Some(SystemClauseType::ReadTerm), - ("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars), - ("$reset_block", 1) => Some(SystemClauseType::ResetBlock), - ("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker), - ("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr), - ("$set_ball", 1) => Some(SystemClauseType::SetBall), - ("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))), - ("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes), - ("$set_seed", 1) => Some(SystemClauseType::SetSeed), - ("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList), - ("$sleep", 1) => Some(SystemClauseType::Sleep), - ("$socket_client_open", 7) => Some(SystemClauseType::SocketClientOpen), - ("$socket_server_open", 3) => Some(SystemClauseType::SocketServerOpen), - ("$socket_server_accept", 7) => Some(SystemClauseType::SocketServerAccept), - ("$socket_server_close", 1) => Some(SystemClauseType::SocketServerClose), - ("$tls_accept_client", 4) => Some(SystemClauseType::TLSAcceptClient), - ("$tls_client_connect", 3) => Some(SystemClauseType::TLSClientConnect), - ("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar), - ("$store_backtrackable_global_var", 2) => { + (atom!("$get_attr_list"), 2) => Some(SystemClauseType::GetAttributedVariableList), + (atom!("$get_b_value"), 1) => Some(SystemClauseType::GetBValue), + (atom!("$get_lh_from_offset"), 2) => Some(SystemClauseType::GetLiftedHeapFromOffset), + (atom!("$get_lh_from_offset_diff"), 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff), + (atom!("$get_double_quotes"), 1) => Some(SystemClauseType::GetDoubleQuotes), + (atom!("$get_scc_cleaner"), 1) => Some(SystemClauseType::GetSCCCleaner), + (atom!("$halt"), 1) => Some(SystemClauseType::Halt), + (atom!("$head_is_dynamic"), 2) => Some(SystemClauseType::HeadIsDynamic), + (atom!("$install_scc_cleaner"), 2) => Some(SystemClauseType::InstallSCCCleaner), + (atom!("$install_inference_counter"), 3) => Some(SystemClauseType::InstallInferenceCounter), + (atom!("$lh_length"), 1) => Some(SystemClauseType::LiftedHeapLength), + (atom!("$maybe"), 0) => Some(SystemClauseType::Maybe), + (atom!("$cpu_now"), 1) => Some(SystemClauseType::CpuNow), + (atom!("$current_time"), 1) => Some(SystemClauseType::CurrentTime), + (atom!("$module_exists"), 1) => Some(SystemClauseType::ModuleExists), + (atom!("$no_such_predicate"), 2) => Some(SystemClauseType::NoSuchPredicate), + (atom!("$number_to_chars"), 2) => Some(SystemClauseType::NumberToChars), + (atom!("$number_to_codes"), 2) => Some(SystemClauseType::NumberToCodes), + (atom!("$op"), 3) => Some(SystemClauseType::OpDeclaration), + (atom!("$open"), 7) => Some(SystemClauseType::Open), + (atom!("$set_stream_options"), 5) => Some(SystemClauseType::SetStreamOptions), + (atom!("$redo_attr_var_binding"), 2) => Some(SystemClauseType::RedoAttrVarBinding), + (atom!("$remove_call_policy_check"), 1) => Some(SystemClauseType::RemoveCallPolicyCheck), + (atom!("$remove_inference_counter"), 2) => Some(SystemClauseType::RemoveInferenceCounter), + (atom!("$restore_cut_policy"), 0) => Some(SystemClauseType::RestoreCutPolicy), + (atom!("$set_cp"), 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))), + (atom!("$set_input"), 1) => Some(SystemClauseType::SetInput), + (atom!("$set_output"), 1) => Some(SystemClauseType::SetOutput), + (atom!("$stream_property"), 3) => Some(SystemClauseType::StreamProperty), + (atom!("$set_stream_position"), 2) => Some(SystemClauseType::SetStreamPosition), + (atom!("$inference_level"), 2) => Some(SystemClauseType::InferenceLevel), + (atom!("$clean_up_block"), 1) => Some(SystemClauseType::CleanUpBlock), + (atom!("$erase_ball"), 0) => Some(SystemClauseType::EraseBall), + (atom!("$fail"), 0) => Some(SystemClauseType::Fail), + (atom!("$get_attr_var_queue_beyond"), 2) => Some(SystemClauseType::GetAttrVarQueueBeyond), + (atom!("$get_attr_var_queue_delim"), 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter), + (atom!("$get_ball"), 1) => Some(SystemClauseType::GetBall), + (atom!("$get_cont_chunk"), 3) => Some(SystemClauseType::GetContinuationChunk), + (atom!("$get_current_block"), 1) => Some(SystemClauseType::GetCurrentBlock), + (atom!("$get_cp"), 1) => Some(SystemClauseType::GetCutPoint), + (atom!("$install_new_block"), 1) => Some(SystemClauseType::InstallNewBlock), + (atom!("$quoted_token"), 1) => Some(SystemClauseType::QuotedToken), + (atom!("$nextEP"), 3) => Some(SystemClauseType::NextEP), + (atom!("$read_query_term"), 5) => Some(SystemClauseType::ReadQueryTerm), + (atom!("$read_term"), 5) => Some(SystemClauseType::ReadTerm), + (atom!("$read_term_from_chars"), 2) => Some(SystemClauseType::ReadTermFromChars), + (atom!("$reset_block"), 1) => Some(SystemClauseType::ResetBlock), + (atom!("$reset_cont_marker"), 0) => Some(SystemClauseType::ResetContinuationMarker), + (atom!("$return_from_verify_attr"), 0) => Some(SystemClauseType::ReturnFromVerifyAttr), + (atom!("$set_ball"), 1) => Some(SystemClauseType::SetBall), + (atom!("$set_cp_by_default"), 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))), + (atom!("$set_double_quotes"), 1) => Some(SystemClauseType::SetDoubleQuotes), + (atom!("$set_seed"), 1) => Some(SystemClauseType::SetSeed), + (atom!("$skip_max_list"), 4) => Some(SystemClauseType::SkipMaxList), + (atom!("$sleep"), 1) => Some(SystemClauseType::Sleep), + (atom!("$tls_accept_client"), 4) => Some(SystemClauseType::TLSAcceptClient), + (atom!("$tls_client_connect"), 3) => Some(SystemClauseType::TLSClientConnect), + (atom!("$socket_client_open"), 8) => Some(SystemClauseType::SocketClientOpen), + (atom!("$socket_server_open"), 3) => Some(SystemClauseType::SocketServerOpen), + (atom!("$socket_server_accept"), 7) => Some(SystemClauseType::SocketServerAccept), + (atom!("$socket_server_close"), 1) => Some(SystemClauseType::SocketServerClose), + (atom!("$store_global_var"), 2) => Some(SystemClauseType::StoreGlobalVar), + (atom!("$store_backtrackable_global_var"), 2) => { Some(SystemClauseType::StoreBacktrackableGlobalVar) } - ("$term_attributed_variables", 2) => Some(SystemClauseType::TermAttributedVariables), - ("$term_variables", 2) => Some(SystemClauseType::TermVariables), - ("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo), - ("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments), - ("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack), - ("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck), - ("$directory_files", 2) => Some(SystemClauseType::DirectoryFiles), - ("$file_size", 2) => Some(SystemClauseType::FileSize), - ("$file_exists", 1) => Some(SystemClauseType::FileExists), - ("$directory_exists", 1) => Some(SystemClauseType::DirectoryExists), - ("$directory_separator", 1) => Some(SystemClauseType::DirectorySeparator), - ("$make_directory", 1) => Some(SystemClauseType::MakeDirectory), - ("$make_directory_path", 1) => Some(SystemClauseType::MakeDirectoryPath), - ("$delete_file", 1) => Some(SystemClauseType::DeleteFile), - ("$rename_file", 2) => Some(SystemClauseType::RenameFile), - ("$delete_directory", 1) => Some(SystemClauseType::DeleteDirectory), - ("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory), - ("$path_canonical", 2) => Some(SystemClauseType::PathCanonical), - ("$file_time", 3) => Some(SystemClauseType::FileTime), - ("$clause_to_evacuable", 2) => { + (atom!("$term_attributed_variables"), 2) => Some(SystemClauseType::TermAttributedVariables), + (atom!("$term_variables"), 2) => Some(SystemClauseType::TermVariables), + (atom!("$term_variables_under_max_depth"), 3) => Some(SystemClauseType::TermVariablesUnderMaxDepth), + (atom!("$truncate_lh_to"), 1) => Some(SystemClauseType::TruncateLiftedHeapTo), + (atom!("$unwind_environments"), 0) => Some(SystemClauseType::UnwindEnvironments), + (atom!("$unwind_stack"), 0) => Some(SystemClauseType::UnwindStack), + (atom!("$unify_with_occurs_check"), 2) => Some(SystemClauseType::UnifyWithOccursCheck), + (atom!("$directory_files"), 2) => Some(SystemClauseType::DirectoryFiles), + (atom!("$file_size"), 2) => Some(SystemClauseType::FileSize), + (atom!("$file_exists"), 1) => Some(SystemClauseType::FileExists), + (atom!("$directory_exists"), 1) => Some(SystemClauseType::DirectoryExists), + (atom!("$directory_separator"), 1) => Some(SystemClauseType::DirectorySeparator), + (atom!("$make_directory"), 1) => Some(SystemClauseType::MakeDirectory), + (atom!("$make_directory_path"), 1) => Some(SystemClauseType::MakeDirectoryPath), + (atom!("$delete_file"), 1) => Some(SystemClauseType::DeleteFile), + (atom!("$rename_file"), 2) => Some(SystemClauseType::RenameFile), + (atom!("$delete_directory"), 1) => Some(SystemClauseType::DeleteDirectory), + (atom!("$working_directory"), 2) => Some(SystemClauseType::WorkingDirectory), + (atom!("$path_canonical"), 2) => Some(SystemClauseType::PathCanonical), + (atom!("$file_time"), 3) => Some(SystemClauseType::FileTime), + (atom!("$clause_to_evacuable"), 2) => { Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable)) } - ("$scoped_clause_to_evacuable", 3) => { + (atom!("$scoped_clause_to_evacuable"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable)) } - ("$conclude_load", 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)), - ("$use_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)), - ("$declare_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)), - ("$load_compiled_library", 3) => { + (atom!("$conclude_load"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)), + (atom!("$use_module"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)), + (atom!("$declare_module"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)), + (atom!("$load_compiled_library"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary)) } - ("$push_load_state_payload", 1) => { + (atom!("$push_load_state_payload"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload)) } - ("$add_in_situ_filename_module", 1) => { + (atom!("$add_in_situ_filename_module"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule)) } - ("$asserta", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Asserta)), - ("$assertz", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Assertz)), - ("$retract_clause", 4) => Some(SystemClauseType::REPL(REPLCodePtr::Retract)), - ("$is_consistent_with_term_queue", 4) => Some(SystemClauseType::REPL( + (atom!("$asserta"), 5) => Some(SystemClauseType::REPL(REPLCodePtr::Asserta)), + (atom!("$assertz"), 5) => Some(SystemClauseType::REPL(REPLCodePtr::Assertz)), + (atom!("$retract_clause"), 4) => Some(SystemClauseType::REPL(REPLCodePtr::Retract)), + (atom!("$is_consistent_with_term_queue"), 4) => Some(SystemClauseType::REPL( REPLCodePtr::IsConsistentWithTermQueue, )), - ("$flush_term_queue", 1) => Some(SystemClauseType::REPL(REPLCodePtr::FlushTermQueue)), - ("$remove_module_exports", 2) => { + (atom!("$flush_term_queue"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::FlushTermQueue)), + (atom!("$remove_module_exports"), 2) => { Some(SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports)) } - ("$add_non_counted_backtracking", 3) => Some(SystemClauseType::REPL( + (atom!("$add_non_counted_backtracking"), 3) => Some(SystemClauseType::REPL( REPLCodePtr::AddNonCountedBacktracking, )), - ("$variant", 2) => Some(SystemClauseType::Variant), - ("$wam_instructions", 4) => Some(SystemClauseType::WAMInstructions), - ("$write_term", 7) => Some(SystemClauseType::WriteTerm), - ("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars), - ("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion), - ("$crypto_random_byte", 1) => Some(SystemClauseType::CryptoRandomByte), - ("$crypto_data_hash", 4) => Some(SystemClauseType::CryptoDataHash), - ("$crypto_data_hkdf", 7) => Some(SystemClauseType::CryptoDataHKDF), - ("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash), - ("$crypto_data_encrypt", 7) => Some(SystemClauseType::CryptoDataEncrypt), - ("$crypto_data_decrypt", 6) => Some(SystemClauseType::CryptoDataDecrypt), - ("$crypto_curve_scalar_mult", 5) => Some(SystemClauseType::CryptoCurveScalarMult), - ("$ed25519_sign", 4) => Some(SystemClauseType::Ed25519Sign), - ("$ed25519_verify", 4) => Some(SystemClauseType::Ed25519Verify), - ("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair), - ("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey), - ("$curve25519_scalar_mult", 3) => Some(SystemClauseType::Curve25519ScalarMult), - ("$first_non_octet", 2) => Some(SystemClauseType::FirstNonOctet), - ("$load_html", 3) => Some(SystemClauseType::LoadHTML), - ("$load_xml", 3) => Some(SystemClauseType::LoadXML), - ("$getenv", 2) => Some(SystemClauseType::GetEnv), - ("$setenv", 2) => Some(SystemClauseType::SetEnv), - ("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv), - ("$shell", 2) => Some(SystemClauseType::Shell), - ("$pid", 1) => Some(SystemClauseType::PID), - ("$chars_base64", 4) => Some(SystemClauseType::CharsBase64), - ("$load_library_as_stream", 3) => Some(SystemClauseType::LoadLibraryAsStream), - ("$push_load_context", 2) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadContext)), - ("$pop_load_state_payload", 1) => { + (atom!("$wam_instructions"), 4) => Some(SystemClauseType::WAMInstructions), + (atom!("$write_term"), 7) => Some(SystemClauseType::WriteTerm), + (atom!("$write_term_to_chars"), 7) => Some(SystemClauseType::WriteTermToChars), + (atom!("$scryer_prolog_version"), 1) => Some(SystemClauseType::ScryerPrologVersion), + (atom!("$crypto_random_byte"), 1) => Some(SystemClauseType::CryptoRandomByte), + (atom!("$crypto_data_hash"), 4) => Some(SystemClauseType::CryptoDataHash), + (atom!("$crypto_data_hkdf"), 7) => Some(SystemClauseType::CryptoDataHKDF), + (atom!("$crypto_password_hash"), 4) => Some(SystemClauseType::CryptoPasswordHash), + (atom!("$crypto_data_encrypt"), 7) => Some(SystemClauseType::CryptoDataEncrypt), + (atom!("$crypto_data_decrypt"), 6) => Some(SystemClauseType::CryptoDataDecrypt), + (atom!("$crypto_curve_scalar_mult"), 5) => Some(SystemClauseType::CryptoCurveScalarMult), + (atom!("$ed25519_sign"), 4) => Some(SystemClauseType::Ed25519Sign), + (atom!("$ed25519_verify"), 4) => Some(SystemClauseType::Ed25519Verify), + (atom!("$ed25519_new_keypair"), 1) => Some(SystemClauseType::Ed25519NewKeyPair), + (atom!("$ed25519_keypair_public_key"), 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey), + (atom!("$curve25519_scalar_mult"), 3) => Some(SystemClauseType::Curve25519ScalarMult), + (atom!("$load_html"), 3) => Some(SystemClauseType::LoadHTML), + (atom!("$load_xml"), 3) => Some(SystemClauseType::LoadXML), + (atom!("$getenv"), 2) => Some(SystemClauseType::GetEnv), + (atom!("$setenv"), 2) => Some(SystemClauseType::SetEnv), + (atom!("$unsetenv"), 1) => Some(SystemClauseType::UnsetEnv), + (atom!("$pid"), 1) => Some(SystemClauseType::PID), + (atom!("$chars_base64"), 4) => Some(SystemClauseType::CharsBase64), + (atom!("$load_library_as_stream"), 3) => Some(SystemClauseType::LoadLibraryAsStream), + (atom!("$push_load_context"), 2) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadContext)), + (atom!("$pop_load_state_payload"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload)) } - ("$pop_load_context", 0) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadContext)), - ("$prolog_lc_source", 1) => { + (atom!("$pop_load_context"), 0) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadContext)), + (atom!("$prolog_lc_source"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::LoadContextSource)) } - ("$prolog_lc_file", 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextFile)), - ("$prolog_lc_dir", 1) => { + (atom!("$prolog_lc_file"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextFile)), + (atom!("$prolog_lc_dir"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory)) } - ("$prolog_lc_module", 1) => { + (atom!("$prolog_lc_module"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::LoadContextModule)) } - ("$prolog_lc_stream", 1) => { + (atom!("$prolog_lc_stream"), 1) => { Some(SystemClauseType::REPL(REPLCodePtr::LoadContextStream)) } - ("$cpp_meta_predicate_property", 4) => { + (atom!("$cpp_meta_predicate_property"), 4) => { Some(SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty)) } - ("$cpp_built_in_property", 2) => { + (atom!("$cpp_built_in_property"), 2) => { Some(SystemClauseType::REPL(REPLCodePtr::BuiltInProperty)) } - ("$cpp_dynamic_property", 3) => { + (atom!("$cpp_dynamic_property"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::DynamicProperty)) } - ("$cpp_multifile_property", 3) => { + (atom!("$cpp_multifile_property"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::MultifileProperty)) } - ("$cpp_discontiguous_property", 3) => { + (atom!("$cpp_discontiguous_property"), 3) => { Some(SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty)) } - ("$devour_whitespace", 1) => Some(SystemClauseType::DevourWhitespace), - ("$is_sto_enabled", 1) => Some(SystemClauseType::IsSTOEnabled), - ("$set_sto_as_unify", 0) => Some(SystemClauseType::SetSTOAsUnify), - ("$set_nsto_as_unify", 0) => Some(SystemClauseType::SetNSTOAsUnify), - ("$set_sto_with_error_as_unify", 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify), - ("$home_directory", 1) => Some(SystemClauseType::HomeDirectory), - ("$debug_hook", 0) => Some(SystemClauseType::DebugHook), - ("$popcount", 2) => Some(SystemClauseType::PopCount), + (atom!("$devour_whitespace"), 1) => Some(SystemClauseType::DevourWhitespace), + (atom!("$is_sto_enabled"), 1) => Some(SystemClauseType::IsSTOEnabled), + (atom!("$set_sto_as_unify"), 0) => Some(SystemClauseType::SetSTOAsUnify), + (atom!("$set_nsto_as_unify"), 0) => Some(SystemClauseType::SetNSTOAsUnify), + (atom!("$set_sto_with_error_as_unify"), 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify), + (atom!("$home_directory"), 1) => Some(SystemClauseType::HomeDirectory), + (atom!("$debug_hook"), 0) => Some(SystemClauseType::DebugHook), _ => None, } } } -#[derive(Debug, Clone, Eq, PartialEq)] -pub(crate) enum BuiltInClauseType { +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum BuiltInClauseType { AcyclicTerm, Arg, Compare, @@ -895,31 +868,30 @@ pub(crate) enum BuiltInClauseType { } #[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum ClauseType { +pub enum ClauseType { BuiltIn(BuiltInClauseType), CallN, Inlined(InlinedClauseType), - Named(ClauseName, usize, CodeIndex), // name, arity, index. - Op(ClauseName, SharedOpDesc, CodeIndex), + Named(Atom, usize, CodeIndex), // name, arity, index. System(SystemClauseType), } impl BuiltInClauseType { - pub(crate) fn name(&self) -> ClauseName { + pub(crate) fn name(&self) -> Atom { match self { - &BuiltInClauseType::AcyclicTerm => clause_name!("acyclic_term"), - &BuiltInClauseType::Arg => clause_name!("arg"), - &BuiltInClauseType::Compare => clause_name!("compare"), - &BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()), - &BuiltInClauseType::CopyTerm => clause_name!("copy_term"), - &BuiltInClauseType::Eq => clause_name!("=="), - &BuiltInClauseType::Functor => clause_name!("functor"), - &BuiltInClauseType::Ground => clause_name!("ground"), - &BuiltInClauseType::Is(..) => clause_name!("is"), - &BuiltInClauseType::KeySort => clause_name!("keysort"), - &BuiltInClauseType::NotEq => clause_name!("\\=="), - &BuiltInClauseType::Read => clause_name!("read"), - &BuiltInClauseType::Sort => clause_name!("sort"), + &BuiltInClauseType::AcyclicTerm => atom!("acyclic_term"), + &BuiltInClauseType::Arg => atom!("arg"), + &BuiltInClauseType::Compare => atom!("compare"), + &BuiltInClauseType::CompareTerm(qt) => qt.name(), + &BuiltInClauseType::CopyTerm => atom!("copy_term"), + &BuiltInClauseType::Eq => atom!("=="), + &BuiltInClauseType::Functor => atom!("functor"), + &BuiltInClauseType::Ground => atom!("ground"), + &BuiltInClauseType::Is(..) => atom!("is"), + &BuiltInClauseType::KeySort => atom!("keysort"), + &BuiltInClauseType::NotEq => atom!("\\=="), + &BuiltInClauseType::Read => atom!("read"), + &BuiltInClauseType::Sort => atom!("sort"), } } @@ -936,54 +908,35 @@ impl BuiltInClauseType { &BuiltInClauseType::Is(..) => 2, &BuiltInClauseType::KeySort => 2, &BuiltInClauseType::NotEq => 2, - &BuiltInClauseType::Read => 2, + &BuiltInClauseType::Read => 1, &BuiltInClauseType::Sort => 2, } } } impl ClauseType { - pub(crate) fn spec(&self) -> Option { - match self { - &ClauseType::Op(_, ref spec, _) => Some(spec.clone()), - &ClauseType::Inlined(InlinedClauseType::CompareNumber(..)) - | &ClauseType::BuiltIn(BuiltInClauseType::Is(..)) - | &ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(_)) - | &ClauseType::BuiltIn(BuiltInClauseType::NotEq) - | &ClauseType::BuiltIn(BuiltInClauseType::Eq) => Some(SharedOpDesc::new(700, XFX)), - _ => None, - } - } - - pub(crate) fn name(&self) -> ClauseName { + pub(crate) fn name(&self) -> Atom { match self { &ClauseType::BuiltIn(ref built_in) => built_in.name(), - &ClauseType::CallN => clause_name!("$call"), - &ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()), - &ClauseType::Op(ref name, ..) => name.clone(), - &ClauseType::Named(ref name, ..) => name.clone(), + &ClauseType::CallN => atom!("$call"), + &ClauseType::Inlined(ref inlined) => inlined.name(), + &ClauseType::Named(name, ..) => name, &ClauseType::System(ref system) => system.name(), } } - pub(crate) fn from(name: ClauseName, arity: usize, spec: Option) -> Self { - CLAUSE_TYPE_FORMS - .borrow() - .get(&(name.as_str(), arity)) - .cloned() - .unwrap_or_else(|| { - SystemClauseType::from(name.as_str(), arity) - .map(ClauseType::System) - .unwrap_or_else(|| { - if let Some(spec) = spec { - ClauseType::Op(name, spec, CodeIndex::default()) - } else if name.as_str() == "$call" { - ClauseType::CallN - } else { - ClauseType::Named(name, arity, CodeIndex::default()) - } - }) - }) + pub(crate) fn from(name: Atom, arity: usize) -> Self { + clause_type_form(name, arity).unwrap_or_else(|| { + SystemClauseType::from(name, arity) + .map(ClauseType::System) + .unwrap_or_else(|| { + if name == atom!("$call") { + ClauseType::CallN + } else { + ClauseType::Named(name, arity, CodeIndex::default()) + } + }) + }) } } diff --git a/src/codegen.rs b/src/codegen.rs index a678549b..243974aa 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,7 +1,6 @@ -/// Code generation to WAM-like instructions. -use prolog_parser::ast::*; -use prolog_parser::tabled_rc::TabledData; -use prolog_parser::{perm_v, temp_v}; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::{perm_v, temp_v}; use crate::allocator::*; use crate::arithmetic::*; @@ -12,6 +11,7 @@ use crate::indexing::*; use crate::instructions::*; use crate::iterators::*; use crate::targets::*; +use crate::types::*; use crate::machine::machine_errors::*; @@ -108,7 +108,11 @@ impl CodeGenSettings { ChoiceInstruction::DynamicInternalElse( global_clock_time, Death::Infinity, - if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) }, + if offset == 0 { + NextOrFail::Next(0) + } else { + NextOrFail::Next(offset) + }, ) } else { ChoiceInstruction::TryMeElse(offset) @@ -120,7 +124,11 @@ impl CodeGenSettings { ChoiceInstruction::DynamicElse( global_clock_tick, Death::Infinity, - if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) }, + if offset == 0 { + NextOrFail::Next(0) + } else { + NextOrFail::Next(offset) + }, ) } else { ChoiceInstruction::TryMeElse(offset) @@ -132,7 +140,11 @@ impl CodeGenSettings { ChoiceInstruction::DynamicInternalElse( global_clock_tick, Death::Infinity, - if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) }, + if offset == 0 { + NextOrFail::Next(0) + } else { + NextOrFail::Next(offset) + }, ) } else { ChoiceInstruction::RetryMeElse(offset) @@ -144,7 +156,11 @@ impl CodeGenSettings { ChoiceInstruction::DynamicElse( global_clock_tick, Death::Infinity, - if offset == 0 { NextOrFail::Next(0) } else { NextOrFail::Next(offset) }, + if offset == 0 { + NextOrFail::Next(0) + } else { + NextOrFail::Next(offset) + }, ) } else if self.non_counted_bt { ChoiceInstruction::DefaultRetryMeElse(offset) @@ -169,11 +185,7 @@ impl CodeGenSettings { pub(crate) fn trust_me(&self) -> ChoiceInstruction { if let Some(global_clock_tick) = self.global_clock_tick { - ChoiceInstruction::DynamicElse( - global_clock_tick, - Death::Infinity, - NextOrFail::Fail(0), - ) + ChoiceInstruction::DynamicElse(global_clock_tick, Death::Infinity, NextOrFail::Fail(0)) } else if self.non_counted_bt { ChoiceInstruction::DefaultTrustMe(0) } else { @@ -183,18 +195,18 @@ impl CodeGenSettings { } #[derive(Debug)] -pub(crate) struct CodeGenerator { - atom_tbl: TabledData, +pub(crate) struct CodeGenerator<'a, TermMarker> { + pub(crate) atom_tbl: &'a mut AtomTable, marker: TermMarker, - pub(crate) var_count: IndexMap, usize>, + pub(crate) var_count: IndexMap, usize>, settings: CodeGenSettings, pub(crate) skeleton: PredicateSkeleton, pub(crate) jmp_by_locs: Vec, global_jmp_by_locs_offset: usize, } -impl<'a, TermMarker: Allocator<'a>> CodeGenerator { - pub(crate) fn new(atom_tbl: TabledData, settings: CodeGenSettings) -> Self { +impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { + pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self { CodeGenerator { atom_tbl, marker: Allocator::new(), @@ -215,13 +227,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - fn get_var_count(&self, var: &'a Var) -> usize { + fn get_var_count(&self, var: &'a String) -> usize { *self.var_count.get(var).unwrap() } fn mark_var_in_non_callable( &mut self, - name: Rc, + name: Rc, term_loc: GenContext, vr: &'a Cell, code: &mut Code, @@ -239,7 +251,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { fn mark_non_callable( &mut self, - name: Rc, + name: Rc, arg: usize, term_loc: GenContext, vr: &'a Cell, @@ -261,7 +273,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { fn add_or_increment_void_instr(target: &mut Vec) where - Target: CompilationTarget<'a>, + Target: crate::targets::CompilationTarget<'a>, { if let Some(ref mut instr) = target.last_mut() { if Target::is_void_instr(&*instr) { @@ -273,10 +285,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { target.push(Target::to_void(1)); } - fn deep_var_instr>( + fn deep_var_instr>( &mut self, cell: &'a Cell, - var: &'a Rc, + var: &'a Rc, term_loc: GenContext, is_exposed: bool, target: &mut Vec, @@ -289,7 +301,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - fn subterm_to_instr>( + fn subterm_to_instr>( &mut self, subterm: &'a Term, term_loc: GenContext, @@ -303,12 +315,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { &Term::AnonVar => { Self::add_or_increment_void_instr(target); } - &Term::Cons(ref cell, _, _) | &Term::Clause(ref cell, _, _, _) => { + &Term::Cons(ref cell, ..) + | &Term::Clause(ref cell, ..) + | Term::PartialString(ref cell, ..) => { self.marker .mark_non_var(Level::Deep, term_loc, cell, target); target.push(Target::clause_arg_to_instr(cell.get())); } - &Term::Constant(_, ref constant) => { + &Term::Literal(_, ref constant) => { target.push(Target::constant_subterm(constant.clone())); } &Term::Var(ref cell, ref var) => { @@ -324,7 +338,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { is_exposed: bool, ) -> Vec where - Target: CompilationTarget<'a>, + Target: crate::targets::CompilationTarget<'a>, Iter: Iterator>, { let mut target = Vec::new(); @@ -343,7 +357,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { target.push(Target::to_structure(ct, terms.len(), cell.get())); for subterm in terms { - self.subterm_to_instr(subterm.as_ref(), term_loc, is_exposed, &mut target); + self.subterm_to_instr(subterm, term_loc, is_exposed, &mut target); } } TermRef::Cons(lvl, cell, head, tail) => { @@ -353,13 +367,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { self.subterm_to_instr(head, term_loc, is_exposed, &mut target); self.subterm_to_instr(tail, term_loc, is_exposed, &mut target); } - TermRef::Constant(lvl @ Level::Shallow, cell, Constant::String(ref string)) => { + TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => { self.marker.mark_non_var(lvl, term_loc, cell, &mut target); - target.push(Target::to_pstr(lvl, string.to_string(), cell.get(), false)); + target.push(Target::to_pstr(lvl, *string, cell.get(), false)); } - TermRef::Constant(lvl @ Level::Shallow, cell, constant) => { + TermRef::Literal(lvl @ Level::Shallow, cell, constant) => { self.marker.mark_non_var(lvl, term_loc, cell, &mut target); - target.push(Target::to_constant(lvl, constant.clone(), cell.get())); + target.push(Target::to_constant(lvl, *constant, cell.get())); } TermRef::PartialString(lvl, cell, string, tail) => { self.marker.mark_non_var(lvl, term_loc, cell, &mut target); @@ -418,6 +432,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { }; self.update_var_count(chunked_term.post_order_iter()); + vs.mark_vars_in_chunk(chunked_term.post_order_iter(), lt_arity, term_loc); } } @@ -476,7 +491,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { fn compile_inlined( &mut self, ct: &InlinedClauseType, - terms: &'a Vec>, + terms: &'a Vec, term_loc: GenContext, code: &mut Code, ) -> Result<(), CompilationError> { @@ -484,16 +499,16 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { &InlinedClauseType::CompareNumber(cmp, ..) => { self.marker.reset_arg(2); - let (mut lcode, at_1) = self.call_arith_eval(terms[0].as_ref(), 1)?; - let (mut rcode, at_2) = self.call_arith_eval(terms[1].as_ref(), 2)?; + let (mut lcode, at_1) = self.call_arith_eval(&terms[0], 1)?; + let (mut rcode, at_2) = self.call_arith_eval(&terms[1], 2)?; - let at_1 = if let &Term::Var(ref vr, ref name) = terms[0].as_ref() { + let at_1 = if let &Term::Var(ref vr, ref name) = &terms[0] { ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 1, term_loc, vr, code)) } else { at_1.unwrap_or(interm!(1)) }; - let at_2 = if let &Term::Var(ref vr, ref name) = terms[1].as_ref() { + let at_2 = if let &Term::Var(ref vr, ref name) = &terms[1] { ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code)) } else { at_2.unwrap_or(interm!(2)) @@ -504,10 +519,10 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(compare_number_instr!(cmp, at_1, at_2)); } - &InlinedClauseType::IsAtom(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Char(_)) - | &Term::Constant(_, Constant::EmptyList) - | &Term::Constant(_, Constant::Atom(..)) => { + &InlinedClauseType::IsAtom(..) => match &terms[0] { + &Term::Literal(_, Literal::Char(_)) + | &Term::Literal(_, Literal::Atom(atom!("[]"))) + | &Term::Literal(_, Literal::Atom(..)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -519,11 +534,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsAtomic(..) => match terms[0].as_ref() { - &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) => { + &InlinedClauseType::IsAtomic(..) => match &terms[0] { + &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) => { code.push(fail!()); } - &Term::Constant(..) => { + &Term::Literal(..) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -532,7 +547,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(is_atomic!(r)); } }, - &InlinedClauseType::IsCompound(..) => match terms[0].as_ref() { + &InlinedClauseType::IsCompound(..) => match &terms[0] { &Term::Clause(..) | &Term::Cons(..) => { code.push(succeed!()); } @@ -545,8 +560,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsRational(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Rational(_)) => { + &InlinedClauseType::IsRational(..) => match &terms[0] { + &Term::Literal(_, Literal::Rational(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -558,8 +573,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsFloat(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Float(_)) => { + &InlinedClauseType::IsFloat(..) => match &terms[0] { + &Term::Literal(_, Literal::Float(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -571,12 +586,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsNumber(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Float(_)) - | &Term::Constant(_, Constant::Rational(_)) - | &Term::Constant(_, Constant::Integer(_)) - | &Term::Constant(_, Constant::Fixnum(_)) - | &Term::Constant(_, Constant::Usize(_)) => { + &InlinedClauseType::IsNumber(..) => match &terms[0] { + &Term::Literal(_, Literal::Float(_)) + | &Term::Literal(_, Literal::Rational(_)) + | &Term::Literal(_, Literal::Integer(_)) + | &Term::Literal(_, Literal::Fixnum(_)) => { + // | &Term::Literal(_, Literal::Usize(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -588,7 +603,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsNonVar(..) => match terms[0].as_ref() { + &InlinedClauseType::IsNonVar(..) => match &terms[0] { &Term::AnonVar => { code.push(fail!()); } @@ -601,10 +616,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(succeed!()); } }, - &InlinedClauseType::IsInteger(..) => match terms[0].as_ref() { - &Term::Constant(_, Constant::Integer(_)) - | &Term::Constant(_, Constant::Fixnum(_)) - | &Term::Constant(_, Constant::Usize(_)) => { + &InlinedClauseType::IsInteger(..) => match &terms[0] { + &Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => { + // | &Term::Literal(_, Literal::Usize(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -616,8 +630,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.push(fail!()); } }, - &InlinedClauseType::IsVar(..) => match terms[0].as_ref() { - &Term::Constant(..) | &Term::Clause(..) | &Term::Cons(..) => { + &InlinedClauseType::IsVar(..) => match &terms[0] { + &Term::Literal(..) + | &Term::Clause(..) + | &Term::Cons(..) + | &Term::PartialString(..) => { code.push(fail!()); } &Term::AnonVar => { @@ -635,7 +652,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } fn call_arith_eval( - &self, + &mut self, term: &'a Term, target_int: usize, ) -> Result { @@ -645,17 +662,17 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { fn compile_is_call( &mut self, - terms: &'a Vec>, + terms: &'a Vec, code: &mut Code, term_loc: GenContext, use_default_call_policy: bool, ) -> Result<(), CompilationError> { - let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?; + let (mut acode, at) = self.call_arith_eval(&terms[1], 1)?; code.append(&mut acode); self.marker.reset_arg(2); - match terms[0].as_ref() { + match &terms[0] { &Term::Var(ref vr, ref name) => { let mut target = vec![]; @@ -666,31 +683,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code.extend(target.into_iter().map(Line::Query)); } } - &Term::Constant(_, ref c @ Constant::Integer(_)) - | &Term::Constant(_, ref c @ Constant::Fixnum(_)) => { - code.push(Line::Query(put_constant!( - Level::Shallow, - c.clone(), - temp_v!(1) - ))); + &Term::Literal(_, c @ Literal::Integer(_)) + | &Term::Literal(_, c @ Literal::Fixnum(_)) => { + let v = HeapCellValue::from(c); + code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1)))); self.marker.advance_arg(); } - &Term::Constant(_, ref c @ Constant::Float(_)) => { - code.push(Line::Query(put_constant!( - Level::Shallow, - c.clone(), - temp_v!(1) - ))); + &Term::Literal(_, c @ Literal::Float(_)) => { + let v = HeapCellValue::from(c); + code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1)))); self.marker.advance_arg(); } - &Term::Constant(_, ref c @ Constant::Rational(_)) => { - code.push(Line::Query(put_constant!( - Level::Shallow, - c.clone(), - temp_v!(1) - ))); + &Term::Literal(_, c @ Literal::Rational(_)) => { + let v = HeapCellValue::from(c); + code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1)))); self.marker.advance_arg(); } @@ -700,7 +708,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - let at = if let &Term::Var(ref vr, ref name) = terms[1].as_ref() { + let at = if let &Term::Var(ref vr, ref name) = &terms[1] { ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code)) } else { at.unwrap_or(interm!(1)) @@ -724,7 +732,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { &mut self, code: &mut Code, cell: &'a Cell, - var: Rc, + var: Rc, term_loc: GenContext, ) { let mut target = Vec::new(); @@ -837,9 +845,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - pub(crate) fn compile_rule<'b: 'a>( + pub(crate) fn compile_rule<'c: 'a>( &mut self, - rule: &'b Rule, + rule: &'c Rule, ) -> Result { let iter = ChunkedIterator::from_rule(rule); let conjunct_info = self.collect_var_data(iter); @@ -897,10 +905,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { UnsafeVarMarker::from_safe_vars(safe_vars) } - pub(crate) fn compile_fact<'b: 'a>(&mut self, term: &'b Term) -> Code { + pub(crate) fn compile_fact<'c: 'a>(&mut self, term: &'c Term) -> Code { self.update_var_count(post_order_iter(term)); let mut vs = VariableFixtures::new(); + vs.mark_vars_in_chunk(post_order_iter(term), term.arity(), GenContext::Head); vs.populate_restricting_sets(); @@ -908,7 +917,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { let mut code = Vec::new(); - if let &Term::Clause(_, _, ref args, _) = term { + if let &Term::Clause(_, _, ref args) = term { self.marker.reset_at_head(args); let iter = FactInstruction::iter(term); @@ -979,7 +988,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { break; } } - match **arg { + match arg { Term::AnonVar | Term::Var(..) => (), _ => { match optimal_index { @@ -1003,7 +1012,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { for (right_index, clause) in clauses.iter().enumerate() { // Can unwrap safely. if let Some(arg) = clause.args().unwrap().iter().nth(optimal_index) { - match **arg { + match arg { Term::Var(..) | Term::AnonVar => { if left_index < right_index { subseqs.push((left_index, right_index)); @@ -1025,17 +1034,13 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { subseqs } - fn compile_pred_subseq<'b: 'a, I: Indexer>( + fn compile_pred_subseq<'c: 'a, I: Indexer>( &mut self, - clauses: &'b [PredicateClause], + clauses: &'c [PredicateClause], optimal_index: usize, ) -> Result { let mut code = VecDeque::new(); - let mut code_offsets = CodeOffsets::new( - self.atom_tbl.clone(), - I::new(), - optimal_index + 1, - ); + let mut code_offsets = CodeOffsets::new(I::new(), optimal_index + 1); let mut skip_stub_try_me_else = false; let jmp_by_locs_len = self.jmp_by_locs.len(); @@ -1087,7 +1092,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { if let Some(arg) = arg { let index = code.len(); - code_offsets.index_term(arg, index, &mut clause_index_info); + code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl); } if !(clauses.len() == 1 && self.settings.is_extensible) { @@ -1122,9 +1127,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { Ok(Vec::from(code)) } - pub(crate) fn compile_predicate<'b: 'a>( + pub(crate) fn compile_predicate<'c: 'a>( &mut self, - clauses: &'b Vec, + clauses: &'c Vec, ) -> Result { let mut code = Code::new(); diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 7525a79a..2b67c56d 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -1,13 +1,13 @@ use indexmap::IndexMap; -use prolog_parser::ast::*; -use prolog_parser::temp_v; - use crate::allocator::*; use crate::fixtures::*; -use crate::forms::*; +use crate::forms::Level; use crate::machine::machine_indices::*; -use crate::targets::*; +use crate::parser::ast::*; +use crate::targets::CompilationTarget; + +use crate::temp_v; use std::cell::Cell; use std::collections::BTreeSet; @@ -15,23 +15,23 @@ use std::rc::Rc; #[derive(Debug)] pub(crate) struct DebrayAllocator { - bindings: IndexMap, VarData>, + bindings: IndexMap, VarData>, arg_c: usize, temp_lb: usize, arity: usize, // 0 if not at head. - contents: IndexMap>, + contents: IndexMap>, in_use: BTreeSet, } impl DebrayAllocator { - fn is_curr_arg_distinct_from(&self, var: &Var) -> bool { + fn is_curr_arg_distinct_from(&self, var: &String) -> bool { match self.contents.get(&self.arg_c) { Some(t_var) if **t_var != *var => true, _ => false, } } - fn occurs_shallowly_in_head(&self, var: &Var, r: usize) -> bool { + fn occurs_shallowly_in_head(&self, var: &String, r: usize) -> bool { match self.bindings.get(var).unwrap() { &VarData::Temp(_, _, ref tvd) => tvd.use_set.contains(&(GenContext::Head, r)), _ => false, @@ -44,7 +44,7 @@ impl DebrayAllocator { in_use_range || self.in_use.contains(&r) } - fn alloc_with_cr(&self, var: &Var) -> usize { + fn alloc_with_cr(&self, var: &String) -> usize { match self.bindings.get(var) { Some(&VarData::Temp(_, _, ref tvd)) => { for &(_, reg) in tvd.use_set.iter() { @@ -70,7 +70,7 @@ impl DebrayAllocator { } } - fn alloc_with_ca(&self, var: &Var) -> usize { + fn alloc_with_ca(&self, var: &String) -> usize { match self.bindings.get(var) { Some(&VarData::Temp(_, _, ref tvd)) => { for &(_, reg) in tvd.use_set.iter() { @@ -98,7 +98,7 @@ impl DebrayAllocator { } } - fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc, usize)> { + fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc, usize)> { // we want to allocate a register to the k^{th} parameter, par_k. // par_k may not be a temporary variable. let k = self.arg_c; @@ -149,7 +149,7 @@ impl DebrayAllocator { fn alloc_reg_to_var<'a, Target>( &mut self, - var: &Var, + var: &String, lvl: Level, term_loc: GenContext, target: &mut Vec, @@ -193,7 +193,7 @@ impl DebrayAllocator { final_index } - fn in_place(&self, var: &Var, term_loc: GenContext, r: RegType, k: usize) -> bool { + fn in_place(&self, var: &String, term_loc: GenContext, r: RegType, k: usize) -> bool { match term_loc { GenContext::Head if !r.is_perm() => r.reg_num() == k, _ => match self.bindings().get(var).unwrap() { @@ -272,7 +272,7 @@ impl<'a> Allocator<'a> for DebrayAllocator { fn mark_var( &mut self, - var: Rc, + var: Rc, lvl: Level, cell: &'a Cell, term_loc: GenContext, @@ -302,7 +302,7 @@ impl<'a> Allocator<'a> for DebrayAllocator { fn mark_reserved_var( &mut self, - var: Rc, + var: Rc, lvl: Level, cell: &'a Cell, term_loc: GenContext, @@ -382,12 +382,12 @@ impl<'a> Allocator<'a> for DebrayAllocator { self.bindings } - fn reset_at_head(&mut self, args: &Vec>) { + fn reset_at_head(&mut self, args: &Vec) { self.reset_arg(args.len()); self.arity = args.len(); for (idx, arg) in args.iter().enumerate() { - if let &Term::Var(_, ref var) = arg.as_ref() { + if let &Term::Var(_, ref var) = arg { let r = self.get(var.clone()); if !r.is_perm() && r.reg_num() == 0 { diff --git a/src/fixtures.rs b/src/fixtures.rs index 0ecdd9e8..d6a1eea9 100644 --- a/src/fixtures.rs +++ b/src/fixtures.rs @@ -1,4 +1,4 @@ -use prolog_parser::ast::*; +use crate::parser::ast::*; use crate::forms::*; use crate::instructions::*; @@ -84,8 +84,8 @@ type VariableFixture<'a> = (VarStatus, Vec<&'a Cell>); #[derive(Debug)] pub(crate) struct VariableFixtures<'a> { - perm_vars: IndexMap, VariableFixture<'a>>, - last_chunk_temp_vars: IndexSet>, + perm_vars: IndexMap, VariableFixture<'a>>, + last_chunk_temp_vars: IndexSet>, } impl<'a> VariableFixtures<'a> { @@ -96,11 +96,11 @@ impl<'a> VariableFixtures<'a> { } } - pub(crate) fn insert(&mut self, var: Rc, vs: VariableFixture<'a>) { + pub(crate) fn insert(&mut self, var: Rc, vs: VariableFixture<'a>) { self.perm_vars.insert(var, vs); } - pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc) { + pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc) { self.last_chunk_temp_vars.insert(var); } @@ -115,7 +115,7 @@ impl<'a> VariableFixtures<'a> { // Compute the conflict set of u. // 1. - let mut use_sets: IndexMap, OccurrenceSet> = IndexMap::new(); + let mut use_sets: IndexMap, OccurrenceSet> = IndexMap::new(); for (var, &mut (ref mut var_status, _)) in self.iter_mut() { if let &mut VarStatus::Temp(_, ref mut var_data) = var_status { @@ -153,11 +153,11 @@ impl<'a> VariableFixtures<'a> { } } - fn get_mut(&mut self, u: Rc) -> Option<&mut VariableFixture<'a>> { + fn get_mut(&mut self, u: Rc) -> Option<&mut VariableFixture<'a>> { self.perm_vars.get_mut(&u) } - fn iter_mut(&mut self) -> indexmap::map::IterMut, VariableFixture<'a>> { + fn iter_mut(&mut self) -> indexmap::map::IterMut, VariableFixture<'a>> { self.perm_vars.iter_mut() } @@ -218,11 +218,11 @@ impl<'a> VariableFixtures<'a> { } } - pub(crate) fn into_iter(self) -> indexmap::map::IntoIter, VariableFixture<'a>> { + pub(crate) fn into_iter(self) -> indexmap::map::IntoIter, VariableFixture<'a>> { self.perm_vars.into_iter() } - fn values(&self) -> indexmap::map::Values, VariableFixture<'a>> { + fn values(&self) -> indexmap::map::Values, VariableFixture<'a>> { self.perm_vars.values() } diff --git a/src/forms.rs b/src/forms.rs index 4f579c8c..4cda0237 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -1,33 +1,38 @@ -use prolog_parser::ast::*; -use prolog_parser::parser::OpDesc; -use prolog_parser::{clause_name, is_infix, is_postfix}; +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::parser::parser::CompositeOpDesc; +use crate::parser::rug::{Integer, Rational}; +use crate::{is_infix, is_postfix}; use crate::clause_types::*; +use crate::machine::heap::*; use crate::machine::loader::PredicateQueue; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; -use crate::rug::{Integer, Rational}; -use ordered_float::OrderedFloat; +use crate::types::*; use indexmap::{IndexMap, IndexSet}; +use ordered_float::OrderedFloat; use slice_deque::*; use std::cell::Cell; +use std::convert::TryFrom; use std::ops::AddAssign; use std::path::PathBuf; use std::rc::Rc; -pub(crate) type PredicateKey = (ClauseName, usize); // name, arity. +pub type PredicateKey = (Atom, usize); // name, arity. -pub(crate) type Predicate = Vec; +pub type Predicate = Vec; // vars of predicate, toplevel offset. Vec is always a vector // of vars (we get their adjoining cells this way). -pub(crate) type JumpStub = Vec; +pub type JumpStub = Vec; #[derive(Debug, Clone)] -pub(crate) enum TopLevel { +pub enum TopLevel { Fact(Term), // Term, line_num, col_num Predicate(Predicate), Query(Vec), @@ -35,7 +40,7 @@ pub(crate) enum TopLevel { } #[derive(Debug, Clone, Copy)] -pub(crate) enum AppendOrPrepend { +pub enum AppendOrPrepend { Append, Prepend, } @@ -51,7 +56,7 @@ impl AppendOrPrepend { } #[derive(Debug, Clone, Copy)] -pub(crate) enum Level { +pub enum Level { Deep, Root, Shallow, @@ -67,12 +72,12 @@ impl Level { } #[derive(Debug, Clone)] -pub(crate) enum QueryTerm { +pub enum QueryTerm { // register, clause type, subterms, use default call policy. - Clause(Cell, ClauseType, Vec>, bool), + Clause(Cell, ClauseType, Vec, bool), BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q. UnblockedCut(Cell), - GetLevelAndUnify(Cell, Rc), + GetLevelAndUnify(Cell, Rc), Jump(JumpStub), } @@ -95,25 +100,25 @@ impl QueryTerm { } #[derive(Debug, Clone)] -pub(crate) struct Rule { - pub(crate) head: (ClauseName, Vec>, QueryTerm), +pub struct Rule { + pub(crate) head: (Atom, Vec, QueryTerm), pub(crate) clauses: Vec, } #[derive(Clone, Debug, Hash)] -pub(crate) enum ListingSource { +pub enum ListingSource { DynamicallyGenerated, - File(ClauseName, PathBuf), // filename, path + File(Atom, PathBuf), // filename, path User, } impl ListingSource { - pub(crate) fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self { + pub(crate) fn from_file_and_path(filename: Atom, path_buf: PathBuf) -> Self { ListingSource::File(filename, path_buf) } } -pub(crate) trait ClauseInfo { +pub trait ClauseInfo { fn is_consistent(&self, clauses: &PredicateQueue) -> bool { match clauses.first() { Some(cl) => { @@ -123,14 +128,14 @@ pub(crate) trait ClauseInfo { } } - fn name(&self) -> Option; + fn name(&self) -> Option; fn arity(&self) -> usize; } impl ClauseInfo for PredicateKey { #[inline] - fn name(&self) -> Option { - Some(self.0.clone()) + fn name(&self) -> Option { + Some(self.0) } #[inline] @@ -140,28 +145,32 @@ impl ClauseInfo for PredicateKey { } impl ClauseInfo for Term { - fn name(&self) -> Option { + fn name(&self) -> Option { + //, atom_tbl: &AtomTable) -> Option { match self { - Term::Clause(_, ref name, ref terms, _) => { + Term::Clause(_, name, terms) => { + // let str_buf = StringBuffer::from(*name, atom_tbl); + match name.as_str() { + // str_buf.as_str() { ":-" => { match terms.len() { - 1 => None, // a declaration. - 2 => terms[0].name(), - _ => Some(clause_name!(":-")), + 1 => None, // a declaration. + 2 => terms[0].name(), //.map(|name| StringBuffer::from(name, atom_tbl)), + _ => Some(*name), } } - _ => Some(name.clone()), + _ => Some(*name), //str_buf), } } - Term::Constant(_, Constant::Atom(ref name, _)) => Some(name.clone()), + Term::Literal(_, Literal::Atom(name)) => Some(*name), //Some(StringBuffer::from(*name, atom_tbl)), _ => None, } } fn arity(&self) -> usize { match self { - Term::Clause(_, ref name, ref terms, _) => match name.as_str() { + Term::Clause(_, name, terms) => match name.as_str() { ":-" => match terms.len() { 1 => 0, 2 => terms[0].arity(), @@ -175,8 +184,8 @@ impl ClauseInfo for Term { } impl ClauseInfo for Rule { - fn name(&self) -> Option { - Some(self.head.0.clone()) + fn name(&self) -> Option { + Some(self.head.0) } fn arity(&self) -> usize { @@ -185,7 +194,7 @@ impl ClauseInfo for Rule { } impl ClauseInfo for PredicateClause { - fn name(&self) -> Option { + fn name(&self) -> Option { match self { &PredicateClause::Fact(ref term, ..) => term.name(), &PredicateClause::Rule(ref rule, ..) => rule.name(), @@ -200,23 +209,21 @@ impl ClauseInfo for PredicateClause { } } -// pub(crate) type CompiledResult = (Predicate, VecDeque); - #[derive(Debug, Clone)] -pub(crate) enum PredicateClause { +pub enum PredicateClause { Fact(Term), Rule(Rule), } impl PredicateClause { - // TODO: add this to `Term` in `prolog_parser` like `first_arg`. - pub(crate) fn args(&self) -> Option<&[Box]> { - match *self { - PredicateClause::Fact(ref term, ..) => match term { - Term::Clause(_, _, args, _) => Some(&args), + // TODO: add this to `Term` in `crate::parser` like `first_arg`. + pub(crate) fn args(&self) -> Option<&[Term]> { + match self { + PredicateClause::Fact(term, ..) => match term { + Term::Clause(_, _, args) => Some(&args), _ => None, }, - PredicateClause::Rule(ref rule, ..) => { + PredicateClause::Rule(rule, ..) => { if rule.head.1.is_empty() { None } else { @@ -228,36 +235,26 @@ impl PredicateClause { } #[derive(Debug, Clone)] -pub(crate) enum ModuleSource { - Library(ClauseName), - File(ClauseName), +pub enum ModuleSource { + Library(Atom), + File(Atom), } impl ModuleSource { pub(crate) fn as_functor_stub(&self) -> MachineStub { match self { - ModuleSource::Library(ref name) => { - functor!("library", [clause_name(name.clone())]) + ModuleSource::Library(name) => { + functor!(atom!("library"), [atom(name)]) } - ModuleSource::File(ref name) => { - functor!(clause_name(name.clone())) + ModuleSource::File(name) => { + functor!(name) } } } } -// pub(crate) type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator. - -/* -#[derive(Debug, Clone)] -pub(crate) enum MultiFileIndicator { - LocalScoped(ClauseName, usize), // name, arity - ModuleScoped(ScopedPredicateKey), -} -*/ - #[derive(Clone, Copy, Hash, Debug)] -pub(crate) enum MetaSpec { +pub enum MetaSpec { Minus, Plus, Either, @@ -265,71 +262,71 @@ pub(crate) enum MetaSpec { } #[derive(Debug, Clone)] -pub(crate) enum Declaration { - Dynamic(ClauseName, usize), - MetaPredicate(ClauseName, ClauseName, Vec), // module name, name, meta-specs +pub enum Declaration { + Dynamic(Atom, usize), + MetaPredicate(Atom, Atom, Vec), // module name, name, meta-specs Module(ModuleDecl), - NonCountedBacktracking(ClauseName, usize), // name, arity + NonCountedBacktracking(Atom, usize), // name, arity Op(OpDecl), UseModule(ModuleSource), UseQualifiedModule(ModuleSource, IndexSet), } -#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)] -pub(crate) struct OpDecl { - pub(crate) prec: usize, - pub(crate) spec: Specifier, - pub(crate) name: ClauseName, +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Ord, PartialOrd)] +pub struct OpDecl { + pub(crate) op_desc: OpDesc, + pub(crate) name: Atom, +} + +#[inline(always)] +pub(crate) fn fixity(spec: u32) -> Fixity { + match spec { + XFY | XFX | YFX => Fixity::In, + XF | YF => Fixity::Post, + FX | FY => Fixity::Pre, + _ => unreachable!(), + } } + impl OpDecl { #[inline] - pub(crate) fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self { - Self { prec, spec, name } + pub(crate) fn new(op_desc: OpDesc, name: Atom) -> Self { + Self { op_desc, name } } #[inline] pub(crate) fn remove(&mut self, op_dir: &mut OpDir) { - let prec = self.prec; - self.prec = 0; + let prec = self.op_desc.get_prec(); + self.op_desc.set(0, self.op_desc.get_spec()); self.insert_into_op_dir(op_dir); - self.prec = prec; - } - - #[inline] - pub(crate) fn fixity(&self) -> Fixity { - match self.spec { - XFY | XFX | YFX => Fixity::In, - XF | YF => Fixity::Post, - FX | FY => Fixity::Pre, - _ => unreachable!(), - } + self.op_desc.set(prec, self.op_desc.get_spec()); } - pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> { - let key = (self.name.clone(), self.fixity()); + pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option { + let key = (self.name, fixity(self.op_desc.get_spec() as u32)); - match op_dir.get(&key) { + match op_dir.get_mut(&key) { Some(cell) => { - return Some(cell.shared_op_desc().replace((self.prec, self.spec))); + let (old_prec, old_spec) = cell.get(); + cell.set(self.op_desc.get_prec(), self.op_desc.get_spec()); + return Some(OpDesc::build_with(old_prec, old_spec)); } None => {} } - op_dir - .insert(key, OpDirValue::new(self.spec, self.prec)) - .map(|op_dir_value| op_dir_value.shared_op_desc().get()) + op_dir.insert(key, self.op_desc) } pub(crate) fn submit( &self, - existing_desc: Option, + existing_desc: Option, op_dir: &mut OpDir, ) -> Result<(), SessionError> { - let (spec, name) = (self.spec, self.name.clone()); + let (spec, name) = (self.op_desc.get_spec(), self.name.clone()); - if is_infix!(spec) { + if is_infix!(spec as u32) { if let Some(desc) = existing_desc { if desc.post > 0 { return Err(SessionError::OpIsInfixAndPostFix(name)); @@ -337,7 +334,7 @@ impl OpDecl { } } - if is_postfix!(spec) { + if is_postfix!(spec as u32) { if let Some(desc) = existing_desc { if desc.inf > 0 { return Err(SessionError::OpIsInfixAndPostFix(name)); @@ -350,22 +347,51 @@ impl OpDecl { } } +#[derive(Debug)] +pub enum AtomOrString { + Atom(Atom), + String(String), +} + +impl AtomOrString { + #[inline] + pub fn as_str(&self) -> &str { + match self { + AtomOrString::Atom(atom) => atom.as_str(), + AtomOrString::String(string) => string.as_str(), + } + } + + #[inline] + pub fn to_string(self) -> String { + match self { + AtomOrString::Atom(atom) => { + atom.as_str().to_owned() + } + AtomOrString::String(string) => { + string + } + } + } +} + +//TODO: try to rid yourself and the earth of the next two functions. pub(crate) fn fetch_atom_op_spec( - name: ClauseName, - spec: Option, + name: Atom, + spec: Option, op_dir: &OpDir, -) -> Option { - fetch_op_spec_from_existing(name.clone(), 1, spec.clone(), op_dir) +) -> Option { + fetch_op_spec_from_existing(name, 1, spec, op_dir) .or_else(|| fetch_op_spec_from_existing(name, 2, spec, op_dir)) } pub(crate) fn fetch_op_spec_from_existing( - name: ClauseName, + name: Atom, arity: usize, - spec: Option, + op_desc: Option, op_dir: &OpDir, -) -> Option { - if let Some(ref op_desc) = &spec { +) -> Option { + if let Some(ref op_desc) = &op_desc { if op_desc.arity() != arity { /* it's possible to extend operator functors with * additional terms. When that happens, @@ -374,61 +400,53 @@ pub(crate) fn fetch_op_spec_from_existing( } } - spec.or_else(|| fetch_op_spec(name, arity, op_dir)) + op_desc.or_else(|| fetch_op_spec(name, arity, op_dir)) } -pub(crate) fn fetch_op_spec( - name: ClauseName, - arity: usize, - op_dir: &OpDir, -) -> Option { +pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option { match arity { - 2 => op_dir - .get(&(name, Fixity::In)) - .and_then(|OpDirValue(spec)| { - if spec.prec() > 0 { - Some(spec.clone()) - } else { - None - } - }), + 2 => op_dir.get(&(name, Fixity::In)).and_then(|op_desc| { + if op_desc.get_prec() > 0 { + Some(*op_desc) + } else { + None + } + }), 1 => { - if let Some(OpDirValue(spec)) = op_dir.get(&(name.clone(), Fixity::Pre)) { - if spec.prec() > 0 { - return Some(spec.clone()); + if let Some(op_desc) = op_dir.get(&(name.clone(), Fixity::Pre)) { + if op_desc.get_prec() > 0 { + return Some(*op_desc); } } - op_dir - .get(&(name.clone(), Fixity::Post)) - .and_then(|OpDirValue(spec)| { - if spec.prec() > 0 { - Some(spec.clone()) - } else { - None - } - }) + op_dir.get(&(name, Fixity::Post)).and_then(|op_desc| { + if op_desc.get_prec() > 0 { + Some(*op_desc) + } else { + None + } + }) } _ => None, } } -pub(crate) type ModuleDir = IndexMap; +pub(crate) type ModuleDir = IndexMap; #[derive(Debug, Clone, Eq, Hash, PartialEq)] -pub(crate) enum ModuleExport { +pub enum ModuleExport { OpDecl(OpDecl), PredicateKey(PredicateKey), } #[derive(Debug, Clone)] -pub(crate) struct ModuleDecl { - pub(crate) name: ClauseName, +pub struct ModuleDecl { + pub(crate) name: Atom, pub(crate) exports: Vec, } #[derive(Debug)] -pub(crate) struct Module { +pub struct Module { pub(crate) module_decl: ModuleDecl, pub(crate) code_dir: CodeDir, pub(crate) op_dir: OpDir, @@ -440,7 +458,10 @@ pub(crate) struct Module { // Module's and related types are defined in forms. impl Module { - pub(crate) fn new(module_decl: ModuleDecl, listing_src: ListingSource) -> Self { + pub(crate) fn new( + module_decl: ModuleDecl, + listing_src: ListingSource, + ) -> Self { Module { module_decl, code_dir: CodeDir::new(), @@ -465,61 +486,115 @@ impl Module { } } -#[derive(Debug, Clone)] -pub(crate) enum Number { +#[derive(Debug, Copy, Clone)] +pub enum Number { Float(OrderedFloat), - Integer(Rc), - Rational(Rc), - Fixnum(isize), + Integer(TypedArenaPtr), + Rational(TypedArenaPtr), + Fixnum(Fixnum), } -impl From for Number { +impl Default for Number { #[inline] - fn from(n: Integer) -> Self { - Number::Integer(Rc::new(n)) + fn default() -> Self { + Number::Fixnum(Fixnum::build_with(0)) } } -impl From for Number { +pub trait ArenaFrom { + fn arena_from(value: T, arena: &mut Arena) -> Self; +} + +impl ArenaFrom for Number { #[inline] - fn from(n: Rational) -> Self { - Number::Rational(Rc::new(n)) + fn arena_from(value: Integer, arena: &mut Arena) -> Number { + Number::Integer(arena_alloc!(value, arena)) } } -impl From for Number { +impl ArenaFrom for Number { #[inline] - fn from(n: isize) -> Self { - Number::Fixnum(n) + fn arena_from(value: Rational, arena: &mut Arena) -> Number { + Number::Rational(arena_alloc!(value, arena)) } } -impl Default for Number { - fn default() -> Self { - Number::Float(OrderedFloat(0f64)) +impl ArenaFrom for Number { + #[inline] + fn arena_from(value: usize, arena: &mut Arena) -> Number { + match i64::try_from(value) { + Ok(value) => Fixnum::build_with_checked(value) + .map(Number::Fixnum) + .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))), + Err(_) => Number::Integer(arena_alloc!(Integer::from(value), arena)), + } } } -impl Into for Number { +impl ArenaFrom for Number { #[inline] - fn into(self) -> Constant { - match self { - Number::Fixnum(n) => Constant::Fixnum(n), - Number::Integer(n) => Constant::Integer(n), - Number::Float(f) => Constant::Float(f), - Number::Rational(r) => Constant::Rational(r), + fn arena_from(value: u64, arena: &mut Arena) -> Number { + match i64::try_from(value) { + Ok(value) => Fixnum::build_with_checked(value) + .map(Number::Fixnum) + .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))), + Err(_) => Number::Integer(arena_alloc!(Integer::from(value), arena)), } } } -impl Into for Number { +impl ArenaFrom for Number { #[inline] - fn into(self) -> HeapCellValue { - match self { - Number::Fixnum(n) => HeapCellValue::Addr(Addr::Fixnum(n)), - Number::Integer(n) => HeapCellValue::Integer(n), - Number::Float(f) => HeapCellValue::Addr(Addr::Float(f)), - Number::Rational(r) => HeapCellValue::Rational(r), + fn arena_from(value: i64, arena: &mut Arena) -> Number { + Fixnum::build_with_checked(value) + .map(Number::Fixnum) + .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))) + } +} + +impl ArenaFrom for Number { + #[inline] + fn arena_from(value: isize, arena: &mut Arena) -> Number { + Fixnum::build_with_checked(value as i64) + .map(Number::Fixnum) + .unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))) + } +} + +impl ArenaFrom for Number { + #[inline] + fn arena_from(value: u32, _arena: &mut Arena) -> Number { + Number::Fixnum(Fixnum::build_with(value as i64)) + } +} + +impl ArenaFrom for Number { + #[inline] + fn arena_from(value: i32, _arena: &mut Arena) -> Number { + Number::Fixnum(Fixnum::build_with(value as i64)) + } +} + +impl ArenaFrom for Literal { + #[inline] + fn arena_from(value: Number, arena: &mut Arena) -> Literal { + match value { + Number::Fixnum(n) => Literal::Fixnum(n), + Number::Integer(n) => Literal::Integer(n), + Number::Float(f) => Literal::Float(arena_alloc!(f, arena)), + Number::Rational(r) => Literal::Rational(r), + } + } +} + +impl ArenaFrom for HeapCellValue { + #[inline] + fn arena_from(value: Number, arena: &mut Arena) -> HeapCellValue { + match value { + Number::Fixnum(n) => fixnum_as_cell!(n), + Number::Integer(n) => typed_arena_ptr_as_cell!(n), + Number::Float(n) => typed_arena_ptr_as_cell!(arena_alloc!(n, arena)), + Number::Rational(n) => typed_arena_ptr_as_cell!(n), } } } @@ -528,9 +603,9 @@ impl Number { #[inline] pub(crate) fn is_positive(&self) -> bool { match self { - &Number::Fixnum(n) => n > 0, + &Number::Fixnum(n) => n.get_num() > 0, &Number::Integer(ref n) => &**n > &0, - &Number::Float(OrderedFloat(f)) => f.is_sign_positive(), + &Number::Float(f) => f.is_sign_positive(), &Number::Rational(ref r) => &**r > &0, } } @@ -538,7 +613,7 @@ impl Number { #[inline] pub(crate) fn is_negative(&self) -> bool { match self { - &Number::Fixnum(n) => n < 0, + &Number::Fixnum(n) => n.get_num() < 0, &Number::Integer(ref n) => &**n < &0, &Number::Float(OrderedFloat(f)) => f.is_sign_negative(), &Number::Rational(ref r) => &**r < &0, @@ -548,36 +623,20 @@ impl Number { #[inline] pub(crate) fn is_zero(&self) -> bool { match self { - &Number::Fixnum(n) => n == 0, + &Number::Fixnum(n) => n.get_num() == 0, &Number::Integer(ref n) => &**n == &0, &Number::Float(f) => f == OrderedFloat(0f64), &Number::Rational(ref r) => &**r == &0, } } - - #[inline] - pub(crate) fn abs(self) -> Self { - match self { - Number::Fixnum(n) => { - if let Some(n) = n.checked_abs() { - Number::from(n) - } else { - Number::from(Integer::from(n).abs()) - } - } - Number::Integer(n) => Number::from(Integer::from(n.abs_ref())), - Number::Float(f) => Number::Float(OrderedFloat(f.abs())), - Number::Rational(r) => Number::from(Rational::from(r.abs_ref())), - } - } } #[derive(Debug, Clone)] pub(crate) enum OptArgIndexKey { - Constant(usize, usize, Constant, Vec), // index, IndexingCode location, opt arg, alternatives - List(usize, usize), // index, IndexingCode location + Literal(usize, usize, Literal, Vec), // index, IndexingCode location, opt arg, alternatives + List(usize, usize), // index, IndexingCode location None, - Structure(usize, usize, ClauseName, usize), // index, IndexingCode location, name, arity + Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity } impl OptArgIndexKey { @@ -589,7 +648,7 @@ impl OptArgIndexKey { #[inline] pub(crate) fn arg_num(&self) -> usize { match &self { - OptArgIndexKey::Constant(arg_num, ..) + OptArgIndexKey::Literal(arg_num, ..) | OptArgIndexKey::Structure(arg_num, ..) | OptArgIndexKey::List(arg_num, _) => { // these are always at least 1. @@ -607,7 +666,7 @@ impl OptArgIndexKey { #[inline] pub(crate) fn switch_on_term_loc(&self) -> Option { match &self { - OptArgIndexKey::Constant(_, loc, ..) + OptArgIndexKey::Literal(_, loc, ..) | OptArgIndexKey::Structure(_, loc, ..) | OptArgIndexKey::List(_, loc) => Some(*loc), OptArgIndexKey::None => None, @@ -617,7 +676,7 @@ impl OptArgIndexKey { #[inline] pub(crate) fn set_switch_on_term_loc(&mut self, value: usize) { match self { - OptArgIndexKey::Constant(_, ref mut loc, ..) + OptArgIndexKey::Literal(_, ref mut loc, ..) | OptArgIndexKey::Structure(_, ref mut loc, ..) | OptArgIndexKey::List(_, ref mut loc) => { *loc = value; @@ -631,7 +690,7 @@ impl AddAssign for OptArgIndexKey { #[inline] fn add_assign(&mut self, n: usize) { match self { - OptArgIndexKey::Constant(_, ref mut o, ..) + OptArgIndexKey::Literal(_, ref mut o, ..) | OptArgIndexKey::List(_, ref mut o) | OptArgIndexKey::Structure(_, ref mut o, ..) => { *o += n; @@ -700,6 +759,7 @@ pub(crate) struct LocalPredicateSkeleton { pub(crate) is_multifile: bool, pub(crate) clause_clause_locs: SliceDeque, pub(crate) clause_assert_margin: usize, + pub(crate) retracted_dynamic_clauses: Option>, // always None if non-dynamic. } impl LocalPredicateSkeleton { @@ -711,6 +771,7 @@ impl LocalPredicateSkeleton { is_multifile: false, clause_clause_locs: sdeq![], clause_assert_margin: 0, + retracted_dynamic_clauses: Some(vec![]), } } @@ -730,6 +791,20 @@ impl LocalPredicateSkeleton { self.clause_clause_locs.clear(); self.clause_assert_margin = 0; } + + #[inline] + pub(crate) fn add_retracted_dynamic_clause_info(&mut self, clause_info: ClauseIndexInfo) { + debug_assert_eq!(self.is_dynamic, true); + + if self.retracted_dynamic_clauses.is_none() { + self.retracted_dynamic_clauses = Some(vec![]); + } + + self.retracted_dynamic_clauses + .as_mut() + .unwrap() + .push(clause_info); + } } #[derive(Clone, Debug)] @@ -781,3 +856,12 @@ impl PredicateSkeleton { } } } + +#[derive(Debug, Clone, Copy)] +pub(crate) enum IndexingCodePtr { + External(usize), // the index points past the indexing instruction prelude. + DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction. + Fail, + Internal(usize), // the index points into the indexing instruction prelude. +} + diff --git a/src/heap_iter.rs b/src/heap_iter.rs index fd057ac3..b5c83a22 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -1,155 +1,274 @@ -use crate::machine::machine_indices::*; -use crate::machine::machine_state::*; +pub(crate) use crate::machine::gc::{IteratorUMP, StacklessPreOrderHeapIter}; +use crate::machine::heap::*; -use indexmap::IndexSet; +use crate::atom_table::*; +use crate::types::*; + +use modular_bitfield::prelude::*; -use std::cmp::Ordering; use std::ops::Deref; use std::vec::Vec; +#[inline] +fn forward_if_referent_marked(heap: &mut [HeapCellValue], h: usize) { + read_heap_cell!(heap[h], + (HeapCellValueTag::Str + | HeapCellValueTag::Lis + | HeapCellValueTag::AttrVar + | HeapCellValueTag::Var + | HeapCellValueTag::PStrLoc, vh) => { + if heap[vh].get_mark_bit() { + heap[h].set_forwarding_bit(true); + } + } + _ => {} + ) +} + +#[bitfield] +#[repr(u64)] +#[derive(Clone, Copy, Debug)] +pub struct IterStackLoc { + value: B63, + m: bool, +} + +impl IterStackLoc { + #[inline] + pub fn iterable_heap_loc(h: usize) -> Self { + IterStackLoc::new().with_m(false).with_value(h as u64) + } + + #[inline] + pub fn mark_heap_loc(h: usize) -> Self { + IterStackLoc::new().with_m(true).with_value(h as u64) + } +} + #[derive(Debug)] -pub(crate) struct HCPreOrderIterator<'a> { - pub(crate) machine_st: &'a MachineState, - pub(crate) state_stack: Vec, +pub struct StackfulPreOrderHeapIter<'a> { + pub heap: &'a mut Vec, + stack: Vec, + h: usize, +} + +impl<'a> Drop for StackfulPreOrderHeapIter<'a> { + fn drop(&mut self) { + while let Some(h) = self.stack.pop() { + let h = h.value() as usize; + + self.heap[h].set_forwarding_bit(false); + self.heap[h].set_mark_bit(false); + } + + self.heap.pop(); + } } -impl<'a> HCPreOrderIterator<'a> { - pub(crate) fn new(machine_st: &'a MachineState, a: Addr) -> Self { - HCPreOrderIterator { - machine_st, - state_stack: vec![a], +impl<'a> StackfulPreOrderHeapIter<'a> { + #[inline] + fn new(heap: &'a mut Vec, cell: HeapCellValue) -> Self { + let h = heap.len(); + heap.push(cell); + + Self { + heap, + h, + stack: vec![IterStackLoc::iterable_heap_loc(h)], } } #[inline] - pub(crate) fn machine_st(&self) -> &MachineState { - &self.machine_st + pub fn push_stack(&mut self, h: usize) { + self.stack.push(IterStackLoc::iterable_heap_loc(h)); } - fn follow_heap(&mut self, h: usize) -> Addr { - match &self.machine_st.heap[h] { - &HeapCellValue::NamedStr(arity, _, _) => { - for idx in (1..arity + 1).rev() { - self.state_stack.push(Addr::HeapCell(h + idx)); - } + #[inline] + pub fn stack_last(&self) -> Option { + for h in self.stack.iter().rev() { + let is_readable_marked = h.m(); + let h = h.value() as usize; + let cell = self.heap[h]; - Addr::Str(h) + if cell.get_forwarding_bit() == Some(true) { + return Some(h); + } else if cell.get_mark_bit() && !is_readable_marked { + continue; } - &HeapCellValue::Addr(a) => self.follow(a), - HeapCellValue::PartialString(..) => self.follow(Addr::PStrLocation(h, 0)), - HeapCellValue::Atom(..) - | HeapCellValue::DBRef(_) - | HeapCellValue::Integer(_) - | HeapCellValue::Rational(_) => Addr::Con(h), - HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(h), - HeapCellValue::Stream(_) => Addr::Stream(h), - HeapCellValue::TcpListener(_) => Addr::TcpListener(h), + + return Some(h); } + + None } - // called under the assumption that the location at r is about to - // be visited, and so any follow up states need to be added to - // state_stack. returns the dereferenced Addr from Ref. - fn follow(&mut self, addr: Addr) -> Addr { - let da = self.machine_st.store(self.machine_st.deref(addr)); + #[inline] + pub fn stack_is_empty(&self) -> bool { + self.stack.is_empty() + } - match da { - Addr::Lis(a) => { - self.state_stack.push(Addr::HeapCell(a + 1)); - self.state_stack.push(Addr::HeapCell(a)); + #[inline] + pub fn focus(&self) -> usize { + self.h + } - da - } - Addr::PStrLocation(h, n) => { - if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] - { - if let Some(c) = pstr.range_from(n..).next() { - if !pstr.at_end(n + c.len_utf8()) { - self.state_stack - .push(Addr::PStrLocation(h, n + c.len_utf8())); - } else if has_tail { - self.state_stack.push(Addr::HeapCell(h + 1)); - } else { - self.state_stack.push(Addr::EmptyList); - } + #[inline] + pub fn pop_stack(&mut self) -> Option { + while let Some(h) = self.stack.pop() { + let is_readable_marked = h.m(); + let h = h.value() as usize; + self.h = h; - self.state_stack.push(Addr::Char(c)); - } else if has_tail { - return self.follow(Addr::HeapCell(h + 1)); - } - } else { - unreachable!() - } + let cell = &mut self.heap[h]; - Addr::PStrLocation(h, n) - } - Addr::Str(s) => { - self.follow_heap(s) // record terms of structure. + if cell.get_forwarding_bit() == Some(true) { + cell.set_forwarding_bit(false); + } else if cell.get_mark_bit() && !is_readable_marked { + cell.set_mark_bit(false); + continue; } - Addr::Con(h) => { - if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.machine_st.heap[h] - { - if let Some(c) = pstr.range_from(0..).next() { - self.state_stack.push(Addr::PStrLocation(h, c.len_utf8())); - self.state_stack.push(Addr::Char(c)); - - Addr::PStrLocation(h, 0) - } else if has_tail { - self.follow(Addr::HeapCell(h + 1)) - } else { - Addr::EmptyList - } - } else { - Addr::Con(h) - } + + return Some(*cell); + } + + None + } + + fn push_if_unmarked(&mut self, h: usize) { + if !self.heap[h].get_mark_bit() { + self.heap[h].set_mark_bit(true); + self.stack.push(IterStackLoc::iterable_heap_loc(h)); + } + } + + fn follow(&mut self) -> Option { + while let Some(h) = self.stack.pop() { + let is_readable_marked = h.m(); + let h = h.value() as usize; + + self.h = h; + let cell = &mut self.heap[h]; + + if cell.get_forwarding_bit() == Some(true) { + let copy = *cell; + cell.set_forwarding_bit(false); + return Some(copy); + } else if cell.get_mark_bit() && !is_readable_marked { + cell.set_mark_bit(false); + continue; } - da => da, + + read_heap_cell!(*cell, + (HeapCellValueTag::Str, vh) => { + self.stack.push(IterStackLoc::iterable_heap_loc(vh)); + } + (HeapCellValueTag::Lis, vh) => { + self.push_if_unmarked(vh); + + self.stack.push(IterStackLoc::iterable_heap_loc(vh + 1)); + forward_if_referent_marked(&mut self.heap, vh + 1); + + self.stack.push(IterStackLoc::mark_heap_loc(vh)); + forward_if_referent_marked(&mut self.heap, vh); + + return Some(self.heap[h]); + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | HeapCellValueTag::Var, vh) => { + self.push_if_unmarked(h); + self.stack.push(IterStackLoc::iterable_heap_loc(vh)); + forward_if_referent_marked(&mut self.heap, vh); + } + (HeapCellValueTag::PStrOffset, offset) => { + self.push_if_unmarked(offset); + self.stack.push(IterStackLoc::iterable_heap_loc(h+1)); + + return Some(self.heap[h]); + } + (HeapCellValueTag::PStr) => { + self.push_if_unmarked(h); + + forward_if_referent_marked(&mut self.heap, h+1); + self.stack.push(IterStackLoc::iterable_heap_loc(h+1)); + + return Some(self.heap[h]); + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity > 0 { + self.push_if_unmarked(h); + } + + for h in (h + 1 .. h + arity + 1).rev() { + forward_if_referent_marked(&mut self.heap, h); + self.stack.push(IterStackLoc::iterable_heap_loc(h)); + } + + return Some(self.heap[h]); + } + // (HeapCellValueTag::StackVar) => { + // unreachable!() // TODO: here, crashing. + // } + _ => { + return Some(*cell); + } + ) } + + None } } -impl<'a> Iterator for HCPreOrderIterator<'a> { - type Item = Addr; +impl<'a> Iterator for StackfulPreOrderHeapIter<'a> { + type Item = HeapCellValue; + #[inline] fn next(&mut self) -> Option { - self.state_stack.pop().map(|a| self.follow(a)) + self.follow() } } -pub(crate) trait MutStackHCIterator<'b> -where - Self: Iterator, -{ - type MutStack; +#[inline(always)] +pub(crate) fn stackless_preorder_iter( + heap: &mut Vec, + cell: HeapCellValue, +) -> StacklessPreOrderHeapIter { + StacklessPreOrderHeapIter::new(heap, cell) +} - fn stack(&'b mut self) -> Self::MutStack; +#[inline(always)] +pub(crate) fn stackful_preorder_iter( + heap: &mut Vec, + cell: HeapCellValue, +) -> StackfulPreOrderHeapIter { + StackfulPreOrderHeapIter::new(heap, cell) } #[derive(Debug)] -pub(crate) struct HCPostOrderIterator<'a> { - base_iter: HCPreOrderIterator<'a>, - parent_stack: Vec<(usize, Addr)>, // number of children, parent node. +pub(crate) struct PostOrderIterator> { + base_iter: Iter, + base_iter_valid: bool, + parent_stack: Vec<(usize, HeapCellValue)>, // number of children, parent node. } -impl<'a> Deref for HCPostOrderIterator<'a> { - type Target = HCPreOrderIterator<'a>; +impl> Deref for PostOrderIterator { + type Target = Iter; fn deref(&self) -> &Self::Target { &self.base_iter } } -impl<'a> HCPostOrderIterator<'a> { - pub(crate) fn new(base_iter: HCPreOrderIterator<'a>) -> Self { - HCPostOrderIterator { +impl> PostOrderIterator { + pub(crate) fn new(base_iter: Iter) -> Self { + PostOrderIterator { base_iter, + base_iter_valid: true, parent_stack: vec![], } } } -impl<'a> Iterator for HCPostOrderIterator<'a> { - type Item = Addr; +impl> Iterator for PostOrderIterator { + type Item = HeapCellValue; fn next(&mut self) -> Option { loop { @@ -161,179 +280,2317 @@ impl<'a> Iterator for HCPostOrderIterator<'a> { self.parent_stack.push((child_count - 1, node)); } - if let Some(item) = self.base_iter.next() { - match self.base_iter.machine_st.heap.index_addr(&item).as_ref() { - &HeapCellValue::NamedStr(arity, ..) => { - self.parent_stack.push((arity, item)); - } - &HeapCellValue::Addr(Addr::Lis(a)) => { - self.parent_stack.push((2, Addr::Lis(a))); - } - &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => { - match &self.machine_st.heap[h] { - &HeapCellValue::PartialString(..) => { - // ref pstr, _) => { - /* - let c = pstr.range_from(n ..).next().unwrap(); - let next_n = n + c.len_utf8(); - - if !pstr.at_end(next_n) { - */ - // self.parent_stack.push((2, Addr::PStrLocation(h, next_n))); - // } - - self.parent_stack.push((2, Addr::PStrLocation(h, n))); - } - _ => { - unreachable!() - } + if self.base_iter_valid { + if let Some(item) = self.base_iter.next() { + read_heap_cell!(item, + (HeapCellValueTag::Atom, (_name, arity)) => { + self.parent_stack.push((arity, item)); } - } - _ => { - return Some(item); - } + (HeapCellValueTag::Lis) => { + self.parent_stack.push((2, item)); + } + (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + self.parent_stack.push((1, item)); + } + _ => { + return Some(item); + } + ); + + continue; + } else { + self.base_iter_valid = false; } - } else { + } + + if self.parent_stack.is_empty() { return None; } } } } -impl MachineState { - pub(crate) fn pre_order_iter<'a>(&'a self, a: Addr) -> HCPreOrderIterator<'a> { - HCPreOrderIterator::new(self, a) - } +pub(crate) type LeftistPostOrderHeapIter<'a> = PostOrderIterator>; - pub(crate) fn post_order_iter<'a>(&'a self, a: Addr) -> HCPostOrderIterator<'a> { - HCPostOrderIterator::new(HCPreOrderIterator::new(self, a)) - } +impl<'a> LeftistPostOrderHeapIter<'a> { + #[inline] + pub fn pop_stack(&mut self) { + if let Some((child_count, _)) = self.parent_stack.last() { + for _ in 0 .. *child_count { + self.base_iter.pop_stack(); + } - pub(crate) fn acyclic_pre_order_iter<'a>(&'a self, a: Addr) -> HCAcyclicIterator<'a> { - HCAcyclicIterator::new(HCPreOrderIterator::new(self, a)) + self.parent_stack.pop(); + } } - pub(crate) fn zipped_acyclic_pre_order_iter<'a>( - &'a self, - a1: Addr, - a2: Addr, - ) -> HCZippedAcyclicIterator<'a> { - HCZippedAcyclicIterator::new( - HCPreOrderIterator::new(self, a1), - HCPreOrderIterator::new(self, a2), - ) + #[inline] + pub fn parent_stack_len(&self) -> usize { + self.parent_stack.len() } } -impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCPreOrderIterator<'a> { - type MutStack = &'b mut Vec; - - fn stack(&'b mut self) -> Self::MutStack { - &mut self.state_stack - } +#[inline] +pub(crate) fn stackful_post_order_iter<'a>( + heap: &'a mut Heap, + cell: HeapCellValue, +) -> LeftistPostOrderHeapIter<'a> { + PostOrderIterator::new(StackfulPreOrderHeapIter::new(heap, cell)) } -#[derive(Debug)] -pub(crate) struct HCAcyclicIterator<'a> { - iter: HCPreOrderIterator<'a>, - seen: IndexSet, +pub(crate) type RightistPostOrderHeapIter<'a> = + PostOrderIterator>; + +#[inline] +pub(crate) fn stackless_post_order_iter<'a>( + heap: &'a mut Heap, + cell: HeapCellValue, +) -> RightistPostOrderHeapIter<'a> { + PostOrderIterator::new(stackless_preorder_iter(heap, cell)) } -impl<'a> HCAcyclicIterator<'a> { - pub(crate) fn new(iter: HCPreOrderIterator<'a>) -> Self { - HCAcyclicIterator { - iter, - seen: IndexSet::new(), +#[cfg(test)] +mod tests { + use super::*; + use crate::machine::mock_wam::*; + + #[test] + fn heap_stackless_iter_tests() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st + .heap + .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 2) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom, 0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom, 0) + ); + + assert_eq!(iter.next(), None); } - } -} -impl<'a> Deref for HCAcyclicIterator<'a> { - type Target = HCPreOrderIterator<'a>; + all_cells_unmarked(&wam.machine_st.heap); - fn deref(&self) -> &Self::Target { - &self.iter - } -} + wam.machine_st.heap.clear(); -impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCAcyclicIterator<'a> { - type MutStack = &'b mut Vec; + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); - fn stack(&'b mut self) -> Self::MutStack { - self.iter.stack() - } -} + for _ in 0..20 { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); -impl<'a> Iterator for HCAcyclicIterator<'a> { - type Item = Addr; + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 4) + ); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); - fn next(&mut self) -> Option { - while let Some(addr) = self.iter.stack().pop() { - if !self.seen.contains(&addr) { - self.iter.stack().push(addr.clone()); - self.seen.insert(addr); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); - break; - } + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); } - self.iter.next() - } -} + all_cells_unmarked(&wam.machine_st.heap); -#[derive(Debug)] -pub(crate) struct HCZippedAcyclicIterator<'a> { - i1: HCPreOrderIterator<'a>, - i2: HCPreOrderIterator<'a>, - seen: IndexSet<(Addr, Addr)>, - pub(crate) first_to_expire: Ordering, -} + wam.machine_st.heap.clear(); -impl<'b, 'a: 'b> MutStackHCIterator<'b> for HCZippedAcyclicIterator<'a> { - type MutStack = (&'b mut Vec, &'b mut Vec); + wam.machine_st.heap.push(str_loc_as_cell!(1)); - fn stack(&'b mut self) -> Self::MutStack { - (self.i1.stack(), self.i2.stack()) - } -} + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(1)) + ] + )); -impl<'a> HCZippedAcyclicIterator<'a> { - pub(crate) fn new(i1: HCPreOrderIterator<'a>, i2: HCPreOrderIterator<'a>) -> Self { - HCZippedAcyclicIterator { - i1, - i2, - seen: IndexSet::new(), - first_to_expire: Ordering::Equal, + for _ in 0..2 { //00000 { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 4) + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1)); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); } - } -} -impl<'a> Iterator for HCZippedAcyclicIterator<'a> { - type Item = (Addr, Addr); + all_cells_unmarked(&wam.machine_st.heap); - fn next(&mut self) -> Option { - while let (Some(a1), Some(a2)) = (self.i1.stack().pop(), self.i2.stack().pop()) { - if !self.seen.contains(&(a1.clone(), a2.clone())) { - self.i1.stack().push(a1.clone()); - self.i2.stack().push(a2.clone()); + wam.machine_st.heap.clear(); - self.seen.insert((a1, a2)); + { + wam.machine_st.heap.push(heap_loc_as_cell!(0)); - break; - } + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(0)); + assert_eq!(iter.next(), None); } - match (self.i1.next(), self.i2.next()) { - (Some(v1), Some(v2)) => Some((v1, v2)), - (Some(_), None) => { - self.first_to_expire = Ordering::Greater; - None - } - (None, Some(_)) => { - self.first_to_expire = Ordering::Less; - None - } - _ => None, + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + // term is: [a, b] + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.pop(); + + // now make the list cyclic. + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + // first a 'dangling' partial string, later modified to be a two-part complete string, + // then a three-part cyclic string involving an uncompacted list of chars. + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1), + ); + + assert_eq!(iter.next(), None); } + + assert_eq!(wam.machine_st.heap[0], pstr_cell); + assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1)); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string( + &mut wam.machine_st.heap, + "def", + &mut wam.machine_st.atom_tbl, + ); + + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(3), + ); + + assert_eq!(iter.next(), None); + } + + assert_eq!(wam.machine_st.heap[0], pstr_cell); + assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2)); + assert_eq!(wam.machine_st.heap[2], pstr_second_cell); + assert_eq!(wam.machine_st.heap[3], heap_loc_as_cell!(3)); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(4)); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + pstr_loc_as_cell!(4), + ); + + let pstr_offset_cell = pstr_offset_as_cell!(0); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + wam.machine_st.heap.truncate(4); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + let pstr_offset_cell = pstr_offset_as_cell!(0); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64))); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + + assert_eq!(iter.next(), None); + + assert_eq!(iter.heap[4], pstr_offset_as_cell!(0)); + assert_eq!(iter.heap[5], fixnum_as_cell!(Fixnum::build_with(1i64))); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.extend(functor); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + // drop the iterator before the iteration is complete to test + // that modified heap cells are restored to their + // pre-traversal state by the stackless iterator's Drop + // instance. + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(5)); + assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!()); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + // drop the iterator before the iteration is complete to test + // that modified heap cells are restored to their + // pre-traversal state by the stackless iterator's Drop + // instance. + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(5)); + assert_eq!(wam.machine_st.heap[4], empty_list_as_cell!()); + + wam.machine_st.heap[4] = list_loc_as_cell!(1); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), heap_loc_as_cell!(3)); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(3)); + + wam.machine_st.heap.clear(); + + // print L = [L|L]. + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + // this is what happens! this next line! We would like it not to happen though. + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(1)); + + wam.machine_st.heap.clear(); + + // term is [X,f(Y),Z]. + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2 + wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3 + wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4 + wam.machine_st.heap.push(heap_loc_as_cell!(8)); + wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6 + wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7 + wam.machine_st.heap.push(list_loc_as_cell!(9)); + wam.machine_st.heap.push(heap_loc_as_cell!(9)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. + wam.machine_st.heap.push(heap_loc_as_cell!(12)); + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(4) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(9) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(9) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + attr_var_as_cell!(11) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1) + ); + assert_eq!(iter.next(), None); + } + + // now populate the attributes list. the iteration must not change. + let clpz_atom = atom!("clpz"); + let p_atom = atom!("p"); + + wam.machine_st.heap.pop(); + + wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12 + wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13 + wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14 + wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15 + wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16 + wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17 + wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18 + wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19 + wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20 + wam.machine_st.heap.push(empty_list_as_cell!()); // 21 + wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22 + wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23 + + { + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(4) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(9) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(9) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + attr_var_as_cell!(11) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1) + ); + assert_eq!(iter.next(), None); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(13)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[13]), list_loc_as_cell!(14)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[14]), str_loc_as_cell!(16)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[15]), heap_loc_as_cell!(19)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[16]), atom_as_cell!(clpz_atom, 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[17]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[18]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[19]), list_loc_as_cell!(20)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[20]), str_loc_as_cell!(22)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[21]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[22]), atom_as_cell!(p_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[23]), heap_loc_as_cell!(23)); + + wam.machine_st.heap.clear(); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + fixnum_as_cell!(Fixnum::build_with(0)) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + fixnum_as_cell!(Fixnum::build_with(0)) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap.len(), 0); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(str_loc_as_cell!(1)); + + wam.machine_st.heap.push(atom_as_cell!(atom!("g"),2)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + str_loc_as_cell!(1), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("g"),2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("y")) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + str_loc_as_cell!(1) + ); + + assert!(iter.next().is_none()); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cell!(atom!("g"),2)); + wam.machine_st.heap.push(str_loc_as_cell!(0)); + wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + str_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("g"),2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("y")) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + str_loc_as_cell!(0) + ); + + assert!(iter.next().is_none()); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(str_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); + wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(list_loc_as_cell!(8)); + wam.machine_st.heap.push(str_loc_as_cell!(4)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(7), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(8) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("="), 2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("g"), 2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("y")) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("X")) + ); + + assert!(iter.next().is_none()); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], str_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(atom!("g"), 2)); + assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(0)); + assert_eq!(wam.machine_st.heap[3], atom_as_cell!(atom!("y"))); + assert_eq!(wam.machine_st.heap[4], atom_as_cell!(atom!("="), 2)); + assert_eq!(wam.machine_st.heap[5], atom_as_cell!(atom!("X"))); + assert_eq!(wam.machine_st.heap[6], heap_loc_as_cell!(0)); + assert_eq!(wam.machine_st.heap[7], list_loc_as_cell!(8)); + assert_eq!(wam.machine_st.heap[8], str_loc_as_cell!(4)); + assert_eq!(wam.machine_st.heap[9], empty_list_as_cell!()); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + + { + let mut iter = stackless_preorder_iter( + &mut wam.machine_st.heap, + str_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("f"), 2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1) + ); + + assert!(iter.next().is_none()); + } + + assert_eq!(wam.machine_st.heap[0], atom_as_cell!(atom!("f"), 2)); + assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[2], heap_loc_as_cell!(1)); + } + + #[test] + fn heap_stackful_iter_tests() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st.heap + .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 2) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + for _ in 0..20 { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 4) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + let mut var = heap_loc_as_cell!(0); + + // self-referencing variables are copied with their forwarding + // and marking bits set to true. it suffices to check only the + // forwarding bit to detect cycles of all kinds, including + // unbound/self-referencing variables. + + var.set_forwarding_bit(true); + var.set_mark_bit(true); + + assert_eq!(iter.next().unwrap(), var); + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + // mutually referencing variables. + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + // term is: [a, b] + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + + // now make the list cyclic. + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + // the cycle will be iterated twice before being detected. + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + // cut the iteration short to check that all cells are + // unmarked and unforwarded by the Drop instance of + // StackfulPreOrderHeapIter. + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom)); + assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0)); + + wam.machine_st.heap.clear(); + + // first a 'dangling' partial string, later modified to be a + // two-part complete string, then a three-part cyclic string + // involving an uncompacted list of chars. + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1), + ); + + assert_eq!(iter.next(), None); + } + + // here + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + { + let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(3), + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); + + { + let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + let pstr_offset_cell = pstr_offset_as_cell!(0); + + // pstr_offset_cell.set_forwarding_bit(true); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); + assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); + + assert_eq!(iter.next(), None); + } + + /* + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); + let string: String = iter.chars().collect(); + assert_eq!(string, "abc def"); + } + */ + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64))); + + { + let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + let pstr_offset_cell = pstr_offset_as_cell!(0); + + // pstr_offset_cell.set_forwarding_bit(true); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); + assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1i64))); + + let h = iter.focus(); + + assert_eq!(h, 5); + assert_eq!(unmark_cell_bits!(iter.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(iter.heap[5]), fixnum_as_cell!(Fixnum::build_with(1i64))); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.extend(functor); + + { + let mut iter = StackfulPreOrderHeapIter::new(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap[4] = list_loc_as_cell!(1); + + { + let mut iter = stackful_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + let mut link_back = list_loc_as_cell!(1); + link_back.set_forwarding_bit(true); + + assert_eq!(iter.next().unwrap(), link_back); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + + { + let mut iter = StackfulPreOrderHeapIter::new( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + let mut cyclic_link = list_loc_as_cell!(1); + cyclic_link.set_forwarding_bit(true); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!(iter.next().unwrap(), cyclic_link); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(pstr_as_cell!(atom!("a string"))); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackful_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_as_cell!(atom!("a string")) + ); + + assert_eq!( + iter.next().unwrap(), + empty_list_as_cell!() + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(str_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); + wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(list_loc_as_cell!(8)); + wam.machine_st.heap.push(str_loc_as_cell!(4)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackful_preorder_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(atom!("g"), 2) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + str_loc_as_cell!(1) + ); + + assert_eq!( + iter.next().unwrap(), + atom_as_cell!(atom!("y")) + ); + + assert!(iter.next().is_none()); + } + } + + #[test] + fn heap_stackful_post_order_iter() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st.heap + .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 2) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + for _ in 0..20 { // 0000 { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 4) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + let mut var = heap_loc_as_cell!(0); + + // self-referencing variables are copied with their forwarding + // and marking bits set to true. it suffices to check only the + // forwarding bit to detect cycles of all kinds, including + // unbound/self-referencing variables. + + var.set_forwarding_bit(true); + var.set_mark_bit(true); + + assert_eq!(iter.next().unwrap(), var); + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + // mutually referencing variables. + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + // term is: [a, b] + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + + // now make the list cyclic. + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + // the cycle will be iterated twice before being detected. + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + { + let mut iter = stackful_post_order_iter( + &mut wam.machine_st.heap, + heap_loc_as_cell!(0), + ); + + // cut the iteration short to check that all cells are + // unmarked and unforwarded by the Drop instance of + // StackfulPreOrderHeapIter. + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom)); + assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0)); + + wam.machine_st.heap.clear(); + + // first a 'dangling' partial string, later modified to be a + // two-part complete string, then a three-part cyclic string + // involving an uncompacted list of chars. + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1), + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(3), + ); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1i64))); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1i64))); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.extend(functor); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap[4] = list_loc_as_cell!(1); + + { + let mut iter = stackful_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + let mut link_back = list_loc_as_cell!(1); + link_back.set_forwarding_bit(true); + + assert_eq!(iter.next().unwrap(), link_back); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + wam.machine_st.heap.clear(); + } + + #[test] + fn heap_stackless_post_order_iter() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st.heap.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + { + let mut iter = stackless_post_order_iter( + &mut wam.machine_st.heap, + str_loc_as_cell!(0), + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 2) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + for _ in 0..20 { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 4) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + { + // mutually referencing variables. + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + // term is: [a, b] + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + + // now make the list cyclic. + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + // the cycle will be iterated twice before being detected. + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + // cut the iteration short to check that all cells are + // unmarked and unforwarded by the Drop instance of + // StacklessPreOrderHeapIter. + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(0) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + } + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], list_loc_as_cell!(3)); + assert_eq!(wam.machine_st.heap[3], atom_as_cell!(b_atom)); + assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(0)); + + wam.machine_st.heap.clear(); + + // first a 'dangling' partial string, later modified to be a + // two-part complete string, then a three-part cyclic string + // involving an uncompacted list of chars. + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1), + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string( + &mut wam.machine_st.heap, + "def", + &mut wam.machine_st.atom_tbl, + ); + + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(3), + ); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + let mut pstr_loc_cell = pstr_loc_as_cell!(0); + + pstr_loc_cell.set_forwarding_bit(true); + + // assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + //assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1))); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_as_cell!(0)); + + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); + assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + + assert_eq!(iter.next(), None); + } + + wam.machine_st.heap.clear(); + + let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.extend(functor); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + empty_list_as_cell!() + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap[4] = list_loc_as_cell!(1); + + { + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(b_atom) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(a_atom) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + atom_as_cell!(f_atom, 3) + ); + + assert_eq!(iter.next().unwrap(), list_loc_as_cell!(1)); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(3) + ); + + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + list_loc_as_cell!(1) + ); + + assert_eq!(iter.next(), None); + } + + all_cells_unmarked(&wam.machine_st.heap); } } diff --git a/src/heap_print.rs b/src/heap_print.rs index 09af815f..7a0c2c5d 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1,9 +1,11 @@ -use prolog_parser::ast::*; -use prolog_parser::{ - alpha_numeric_char, capital_letter_char, clause_name, cut_char, decimal_digit_char, - graphic_token_char, is_fx, is_infix, is_postfix, is_prefix, is_xf, is_xfx, is_xfy, is_yfx, - semicolon_char, sign_char, single_quote_char, small_letter_char, solo_char, - variable_indicator_char, +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::parser::rug::{Integer, Rational}; +use crate::{ + alpha_numeric_char, capital_letter_char, cut_char, decimal_digit_char, graphic_token_char, + is_fx, is_infix, is_postfix, is_prefix, is_xf, is_xfx, is_xfy, is_yfx, semicolon_char, + sign_char, single_quote_char, small_letter_char, solo_char, variable_indicator_char, }; use crate::clause_types::*; @@ -11,40 +13,41 @@ use crate::forms::*; use crate::heap_iter::*; use crate::machine::heap::*; use crate::machine::machine_indices::*; -use crate::machine::machine_state::*; +use crate::machine::partial_string::*; use crate::machine::streams::*; -use crate::rug::{Integer, Rational}; +use crate::types::*; + use ordered_float::OrderedFloat; use indexmap::{IndexMap, IndexSet}; use std::cell::Cell; use std::convert::TryFrom; -use std::iter::{once, FromIterator}; +use std::iter::once; use std::net::{IpAddr, TcpListener}; use std::ops::{Range, RangeFrom}; use std::rc::Rc; /* contains the location, name, precision and Specifier of the parent op. */ -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] pub(crate) enum DirectedOp { - Left(ClauseName, SharedOpDesc), - Right(ClauseName, SharedOpDesc), + Left(Atom, OpDesc), + Right(Atom, OpDesc), } impl DirectedOp { #[inline] - fn as_str(&self) -> &str { + fn as_atom(&self) -> Atom { match self { - &DirectedOp::Left(ref name, _) | &DirectedOp::Right(ref name, _) => name.as_str(), + &DirectedOp::Left(name, _) | &DirectedOp::Right(name, _) => name, } } #[inline] fn is_negative_sign(&self) -> bool { match self { - &DirectedOp::Left(ref name, ref cell) | &DirectedOp::Right(ref name, ref cell) => { - name.as_str() == "-" && is_prefix!(cell.assoc()) + &DirectedOp::Left(name, cell) | &DirectedOp::Right(name, cell) => { + name == atom!("-") && is_prefix!(cell.get_spec() as u32) } } } @@ -59,29 +62,33 @@ impl DirectedOp { } } -fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool { +fn needs_bracketing(child_desc: OpDesc, op: &DirectedOp) -> bool { match op { - &DirectedOp::Left(ref name, ref cell) => { + DirectedOp::Left(name, cell) => { let (priority, spec) = cell.get(); if name.as_str() == "-" { - let child_assoc = child_spec.assoc(); + let child_assoc = child_desc.get_spec(); if is_prefix!(spec) && (is_postfix!(child_assoc) || is_infix!(child_assoc)) { return true; } } let is_strict_right = is_yfx!(spec) || is_xfx!(spec) || is_fx!(spec); - child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_right) + child_desc.get_prec() > priority + || (child_desc.get_prec() == priority && is_strict_right) } - &DirectedOp::Right(_, ref cell) => { + DirectedOp::Right(_, cell) => { let (priority, spec) = cell.get(); let is_strict_left = is_xfx!(spec) || is_xfy!(spec) || is_xf!(spec); - if child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_left) { + if child_desc.get_prec() > priority + || (child_desc.get_prec() == priority && is_strict_left) + { true - } else if (is_postfix!(spec) || is_infix!(spec)) && !is_postfix!(child_spec.assoc()) { - !SharedOpDesc::ptr_eq(&cell, &child_spec) && child_spec.prec() == priority + } else if (is_postfix!(spec) || is_infix!(spec)) && !is_postfix!(child_desc.get_spec()) + { + *cell == child_desc && child_desc.get_prec() == priority } else { false } @@ -89,59 +96,67 @@ fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool { } } -impl<'a> HCPreOrderIterator<'a> { +impl<'a> StackfulPreOrderHeapIter<'a> { /* * descend into the subtree where the iterator is currently parked * and check that the leftmost leaf is a number, with every node * encountered on the way an infix or postfix operator, unblocked * by brackets. */ - fn leftmost_leaf_has_property

(&self, property_check: P) -> bool + fn leftmost_leaf_has_property

(&self, op_dir: &OpDir, property_check: P) -> bool where - P: Fn(Addr, &Heap) -> bool, + P: Fn(HeapCellValue) -> bool, { - let mut addr = match self.state_stack.last().cloned() { - Some(addr) => addr, + let mut h = match self.stack_last() { + Some(h) => h, None => return false, }; - let mut parent_spec = DirectedOp::Left(clause_name!("-"), SharedOpDesc::new(200, FY)); + let mut parent_spec = DirectedOp::Left(atom!("-"), OpDesc::build_with(200, FY as u8)); loop { - match self.machine_st.store(self.machine_st.deref(addr)) { - Addr::Str(s) => match &self.machine_st.heap[s] { - &HeapCellValue::NamedStr(_, ref name, Some(ref spec)) - if is_postfix!(spec.assoc()) || is_infix!(spec.assoc()) => - { - if needs_bracketing(spec, &parent_spec) { + // match self.machine_st.store(self.machine_st.deref(addr)) { + read_heap_cell!(self.heap[h], + (HeapCellValueTag::Str, s) => { + read_heap_cell!(self.heap[s], + (HeapCellValueTag::Atom, (name, _arity)) => { + if let Some(spec) = fetch_atom_op_spec(name, None, op_dir) { + if is_postfix!(spec.get_spec() as u32) || is_infix!(spec.get_spec() as u32) { + if needs_bracketing(spec, &parent_spec) { + return false; + } else { + h = s + 1; + parent_spec = DirectedOp::Right(name, spec); + continue; + } + } + } + return false; - } else { - addr = Addr::HeapCell(s + 1); - parent_spec = DirectedOp::Right(name.clone(), spec.clone()); } - } - _ => { - return false; - } - }, - addr => { - return property_check(addr, &self.machine_st.heap); + _ => { + return false; + } + ) } - } + _ => { + return property_check(self.heap[h]); + } + ) } } fn immediate_leaf_has_property

(&self, property_check: P) -> bool where - P: Fn(Addr, &Heap) -> bool, + P: Fn(HeapCellValue) -> bool, { - let addr = match self.state_stack.last().cloned() { - Some(addr) => addr, + let addr = match self.stack_last() { + Some(h) => self.heap[h], None => return false, }; - let addr = self.machine_st.store(self.machine_st.deref(addr)); - property_check(addr, &self.machine_st.heap) + // let addr = self.machine_st.store(self.machine_st.deref(addr)); + property_check(addr) } } @@ -168,20 +183,36 @@ fn char_to_string(is_quoted: bool, c: char) -> String { } } +#[derive(Clone, Copy, Debug)] +enum NumberFocus { + Unfocused(Number), + Denominator(TypedArenaPtr), + Numerator(TypedArenaPtr), +} + +impl NumberFocus { + fn is_positive(&self) -> bool { + match self { + NumberFocus::Unfocused(n) => n.is_positive(), + NumberFocus::Denominator(r) | NumberFocus::Numerator(r) => **r > 0, + } + } +} + #[derive(Debug, Clone)] enum TokenOrRedirect { - Atom(ClauseName), + Atom(Atom), BarAsOp, - Op(ClauseName, SharedOpDesc), + Op(Atom, OpDesc), NumberedVar(String), CompositeRedirect(usize, DirectedOp), FunctorRedirect(usize), - IpAddr(IpAddr), - Number(Number, Option), + #[allow(unused)] IpAddr(IpAddr), + NumberFocus(NumberFocus, Option), Open, Close, Comma, - RawPtr(*const u8), + RawPtr(*const ArenaHeader), Space, LeftCurly, RightCurly, @@ -190,7 +221,89 @@ enum TokenOrRedirect { HeadTailSeparator, } -pub(crate) trait HCValueOutputter { +pub(crate) fn requires_space(atom: &str, op: &str) -> bool { + match atom.chars().last() { + Some(ac) => op + .chars() + .next() + .map(|oc| { + if ac == '0' { + oc == '\'' || oc == '(' || alpha_numeric_char!(oc) + } else if alpha_numeric_char!(ac) { + oc == '(' || alpha_numeric_char!(oc) + } else if graphic_token_char!(ac) { + graphic_token_char!(oc) + } else if variable_indicator_char!(ac) { + alpha_numeric_char!(oc) + } else if capital_letter_char!(ac) { + alpha_numeric_char!(oc) + } else if sign_char!(ac) { + sign_char!(oc) || decimal_digit_char!(oc) + } else if single_quote_char!(ac) { + single_quote_char!(oc) + } else { + false + } + }) + .unwrap_or(false), + _ => false, + } +} + +fn non_quoted_graphic_token>(mut iter: Iter, c: char) -> bool { + if c == '/' { + return match iter.next() { + None => true, + Some('*') => false, // if we start with comment token, we must quote. + Some(c) => { + if graphic_token_char!(c) { + iter.all(|c| graphic_token_char!(c)) + } else { + false + } + } + }; + } else if c == '.' { + return match iter.next() { + None => false, + Some(c) => { + if graphic_token_char!(c) { + iter.all(|c| graphic_token_char!(c)) + } else { + false + } + } + }; + } else { + iter.all(|c| graphic_token_char!(c)) + } +} + +pub(super) fn non_quoted_token>(mut iter: Iter) -> bool { + if let Some(c) = iter.next() { + if small_letter_char!(c) { + iter.all(|c| alpha_numeric_char!(c)) + } else if graphic_token_char!(c) { + non_quoted_graphic_token(iter, c) + } else if semicolon_char!(c) { + iter.next().is_none() + } else if cut_char!(c) { + iter.next().is_none() + } else if c == '[' { + iter.next() == Some(']') && iter.next().is_none() + } else if c == '{' { + iter.next() == Some('}') && iter.next().is_none() + } else if solo_char!(c) { + !(c == '(' || c == ')' || c == '}' || c == ']' || c == ',' || c == '%' || c == '|') + } else { + false + } + } else { + false + } +} + +pub trait HCValueOutputter { type Output; fn new() -> Self; @@ -207,7 +320,7 @@ pub(crate) trait HCValueOutputter { } #[derive(Debug)] -pub(crate) struct PrinterOutputter { +pub struct PrinterOutputter { contents: String, } @@ -273,11 +386,15 @@ fn is_numbered_var(ct: &ClauseType, arity: usize) -> bool { } #[inline] -fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option) -> bool { +fn negated_op_needs_bracketing( + iter: &StackfulPreOrderHeapIter, + op_dir: &OpDir, + op: &Option, +) -> bool { if let Some(ref op) = op { op.is_negative_sign() - && iter.leftmost_leaf_has_property(|addr, heap| match Number::try_from((addr, heap)) { - Ok(Number::Fixnum(n)) => n > 0, + && iter.leftmost_leaf_has_property(op_dir, |addr| match Number::try_from(addr) { + Ok(Number::Fixnum(n)) => n.get_num() > 0, Ok(Number::Float(f)) => f > OrderedFloat(0f64), Ok(Number::Integer(n)) => &*n > &0, Ok(Number::Rational(n)) => &*n > &0, @@ -288,66 +405,103 @@ fn negated_op_needs_bracketing(iter: &HCPreOrderIterator, op: &Option Var { - static CHAR_CODES: [char; 26] = [ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', - 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - ]; +pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option { + fn numbervar(n: Integer) -> String { + static CHAR_CODES: [char; 26] = [ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + ]; - let i = n.mod_u(26) as usize; - let j = n.div_rem_floor(Integer::from(26)); - let j = <(Integer, Integer)>::from(j).0; + let i = n.mod_u(26) as usize; + let j = n.div_rem_floor(Integer::from(26)); + let j = <(Integer, Integer)>::from(j).0; - if j == 0 { - CHAR_CODES[i].to_string() - } else { - format!("{}{}", CHAR_CODES[i], j) + if j == 0 { + CHAR_CODES[i].to_string() + } else { + format!("{}{}", CHAR_CODES[i], j) + } } -} -impl MachineState { - pub(crate) fn numbervar(&self, offset: &Integer, addr: Addr) -> Option { - let addr = self.store(self.deref(addr)); - - match Number::try_from((addr, &self.heap)) { - Ok(Number::Fixnum(n)) => { - if n >= 0 { - Some(numbervar(Integer::from(offset + Integer::from(n)))) - } else { - None - } + match Number::try_from(addr) { + Ok(Number::Fixnum(n)) => { + if n.get_num() >= 0 { + Some(numbervar(offset + Integer::from(n.get_num()))) + } else { + None } - Ok(Number::Integer(n)) => { - if &*n >= &0 { - Some(numbervar(Integer::from(offset + &*n))) - } else { - None - } + } + Ok(Number::Integer(n)) => { + if &*n >= &0 { + Some(numbervar(Integer::from(offset + &*n))) + } else { + None } - _ => None, } + _ => None, } } -type ReverseHeapVarDict = IndexMap>; +macro_rules! push_char { + ($self:ident, $c:expr) => {{ + $self.outputter.push_char($c); + $self.last_item_idx = $self.outputter.len(); + }}; +} + +macro_rules! append_str { + ($self:ident, $s:expr) => {{ + $self.last_item_idx = $self.outputter.len(); + $self.outputter.append($s); + }}; +} + +macro_rules! print_char { + ($self:ident, $is_quoted:expr, $c:expr) => { + if non_quoted_token(once($c)) { + let result = char_to_string(false, $c); + + push_space_if_amb!($self, &result, { + append_str!($self, &result); + }); + } else { + let mut result = String::new(); + + if $self.quoted { + result.push('\''); + result += &char_to_string($is_quoted, $c); + result.push('\''); + } else { + result += &char_to_string($is_quoted, $c); + } + + push_space_if_amb!($self, &result, { + append_str!($self, result.as_str()); + }); + } + }; +} #[derive(Debug)] -pub(crate) struct HCPrinter<'a, Outputter> { +pub struct HCPrinter<'a, Outputter> { outputter: Outputter, - machine_st: &'a MachineState, + iter: StackfulPreOrderHeapIter<'a>, + arena: &'a mut Arena, op_dir: &'a OpDir, state_stack: Vec, toplevel_spec: Option, - heap_locs: ReverseHeapVarDict, + // heap_locs: ReverseHeapVarDict, + printed_vars: IndexSet, last_item_idx: usize, - cyclic_terms: IndexMap, - non_cyclic_terms: IndexSet, - pub(crate) var_names: IndexMap, - pub(crate) numbervars_offset: Integer, - pub(crate) numbervars: bool, - pub(crate) quoted: bool, - pub(crate) ignore_ops: bool, - pub(crate) max_depth: usize, + // cyclic_terms: IndexMap, + // non_cyclic_terms: IndexSet, + pub var_names: IndexMap>, + pub numbervars_offset: Integer, + pub numbervars: bool, + pub quoted: bool, + pub ignore_ops: bool, + pub print_strings_as_strs: bool, + pub max_depth: usize, } macro_rules! push_space_if_amb { @@ -361,117 +515,29 @@ macro_rules! push_space_if_amb { }; } -pub(crate) fn requires_space(atom: &str, op: &str) -> bool { - match atom.chars().last() { - Some(ac) => op - .chars() - .next() - .map(|oc| { - if ac == '0' { - oc == '\'' || oc == '(' || alpha_numeric_char!(oc) - } else if alpha_numeric_char!(ac) { - oc == '(' || alpha_numeric_char!(oc) - } else if graphic_token_char!(ac) { - graphic_token_char!(oc) - } else if variable_indicator_char!(ac) { - alpha_numeric_char!(oc) - } else if capital_letter_char!(ac) { - alpha_numeric_char!(oc) - } else if sign_char!(ac) { - sign_char!(oc) || decimal_digit_char!(oc) - } else if single_quote_char!(ac) { - single_quote_char!(oc) - } else { - false - } - }) - .unwrap_or(false), - _ => false, - } -} - -fn non_quoted_graphic_token>(mut iter: Iter, c: char) -> bool { - if c == '/' { - return match iter.next() { - None => true, - Some('*') => false, // if we start with comment token, we must quote. - Some(c) => { - if graphic_token_char!(c) { - iter.all(|c| graphic_token_char!(c)) - } else { - false - } - } - }; - } else if c == '.' { - return match iter.next() { - None => false, - Some(c) => { - if graphic_token_char!(c) { - iter.all(|c| graphic_token_char!(c)) - } else { - false - } - } - }; - } else { - iter.all(|c| graphic_token_char!(c)) - } -} - -pub(super) fn non_quoted_token>(mut iter: Iter) -> bool { - if let Some(c) = iter.next() { - if small_letter_char!(c) { - iter.all(|c| alpha_numeric_char!(c)) - } else if graphic_token_char!(c) { - non_quoted_graphic_token(iter, c) - } else if semicolon_char!(c) { - iter.next().is_none() - } else if cut_char!(c) { - iter.next().is_none() - } else if c == '[' { - iter.next() == Some(']') && iter.next().is_none() - } else if c == '{' { - iter.next() == Some('}') && iter.next().is_none() - } else if solo_char!(c) { - !(c == '(' || c == ')' || c == '}' || c == ']' || c == ',' || c == '%' || c == '|') - } else { - false - } - } else { - false - } -} - -#[inline] -fn functor_location(addr: &Addr) -> Option { - Some(match addr { - &Addr::Lis(l) => l, - &Addr::Str(s) => s, - &Addr::PStrLocation(h, _) => h, - _ => { - return None; - } - }) -} - impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { - pub(crate) fn new(machine_st: &'a MachineState, op_dir: &'a OpDir, output: Outputter) -> Self { + pub fn new( + heap: &'a mut Heap, + arena: &'a mut Arena, + op_dir: &'a OpDir, + output: Outputter, + cell: HeapCellValue, + ) -> Self { HCPrinter { outputter: output, - machine_st, + iter: stackful_preorder_iter(heap, cell), + arena, op_dir, state_stack: vec![], - heap_locs: ReverseHeapVarDict::new(), toplevel_spec: None, + printed_vars: IndexSet::new(), last_item_idx: 0, numbervars: false, numbervars_offset: Integer::from(0), quoted: false, ignore_ops: false, - cyclic_terms: IndexMap::new(), - non_cyclic_terms: IndexSet::new(), var_names: IndexMap::new(), + print_strings_as_strs: false, max_depth: 0, } } @@ -482,87 +548,82 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { requires_space(tail, atom) } - fn enqueue_op( - &mut self, - iter: &mut HCPreOrderIterator, - mut max_depth: usize, - ct: ClauseType, - spec: SharedOpDesc, - ) { - if is_postfix!(spec.assoc()) { + fn enqueue_op(&mut self, mut max_depth: usize, ct: ClauseType, spec: OpDesc) { + let name = ct.name(); + + if is_postfix!(spec.get_spec()) { if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); + self.iter.pop_stack(); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); return; } - let right_directed_op = DirectedOp::Right(ct.name(), spec.clone()); + let right_directed_op = DirectedOp::Right(name, spec); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, right_directed_op, )); - } else if is_prefix!(spec.assoc()) { - match ct.name().as_str() { - "-" | "\\" => { - self.format_prefix_op_with_space(iter, max_depth, ct.name(), spec); + } else if is_prefix!(spec.get_spec()) { + match name { + atom!("-") | atom!("\\") => { + self.format_prefix_op_with_space(max_depth, name, spec); return; } _ => {} }; if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); + self.iter.pop_stack(); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); return; } - let left_directed_op = DirectedOp::Left(ct.name(), spec.clone()); + let left_directed_op = DirectedOp::Left(name, spec); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, left_directed_op, )); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); + + self.state_stack.push(TokenOrRedirect::Op(name, spec)); } else { - match ct.name().as_str() { + match name.as_str() { "|" => { - self.format_bar_separator_op(iter, max_depth, ct.name(), spec); + self.format_bar_separator_op(max_depth, name, spec); return; } _ => {} }; + let ellipsis_atom = atom!("..."); + if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); - iter.stack().pop(); + self.iter.pop_stack(); + self.iter.pop_stack(); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom)); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); + self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom)); return; } - let left_directed_op = DirectedOp::Left(ct.name(), spec.clone()); - let right_directed_op = DirectedOp::Right(ct.name(), spec.clone()); + let left_directed_op = DirectedOp::Left(name, spec); + let right_directed_op = DirectedOp::Right(name, spec); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, left_directed_op, )); - self.state_stack.push(TokenOrRedirect::Op(ct.name(), spec)); + self.state_stack.push(TokenOrRedirect::Op(name, spec)); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, right_directed_op, @@ -570,21 +631,14 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - fn format_struct( - &mut self, - iter: &mut HCPreOrderIterator, - mut max_depth: usize, - arity: usize, - name: ClauseName, - ) -> bool { + fn format_struct(&mut self, mut max_depth: usize, arity: usize, name: Atom) -> bool { if self.check_max_depth(&mut max_depth) { for _ in 0..arity { - iter.stack().pop(); + self.iter.pop_stack(); } self.state_stack.push(TokenOrRedirect::Close); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Atom(name)); @@ -608,25 +662,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { true } - fn format_prefix_op_with_space( - &mut self, - iter: &mut HCPreOrderIterator, - mut max_depth: usize, - name: ClauseName, - spec: SharedOpDesc, - ) { + fn format_prefix_op_with_space(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) { if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); + self.iter.pop_stack(); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::Space); self.state_stack.push(TokenOrRedirect::Atom(name)); return; } - let op = DirectedOp::Left(name.clone(), spec); + let op = DirectedOp::Left(name, spec); self.state_stack .push(TokenOrRedirect::CompositeRedirect(max_depth, op)); @@ -634,46 +681,43 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::Atom(name)); } - fn format_bar_separator_op( - &mut self, - iter: &mut HCPreOrderIterator, - mut max_depth: usize, - name: ClauseName, - spec: SharedOpDesc, - ) { + fn format_bar_separator_op(&mut self, mut max_depth: usize, name: Atom, spec: OpDesc) { if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); + self.iter.pop_stack(); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + let ellipsis_atom = atom!("..."); + + self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom)); self.state_stack.push(TokenOrRedirect::BarAsOp); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom)); return; } - let left_directed_op = DirectedOp::Left(name.clone(), spec.clone()); - let right_directed_op = DirectedOp::Right(name.clone(), spec.clone()); + let left_directed_op = DirectedOp::Left(name, spec); + let right_directed_op = DirectedOp::Right(name, spec); self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, left_directed_op, )); + self.state_stack.push(TokenOrRedirect::BarAsOp); + self.state_stack.push(TokenOrRedirect::CompositeRedirect( max_depth, right_directed_op, )); } - fn format_curly_braces(&mut self, iter: &mut HCPreOrderIterator, mut max_depth: usize) -> bool { + fn format_curly_braces(&mut self, mut max_depth: usize) -> bool { if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); + self.iter.pop_stack(); + + let ellipsis_atom = atom!("..."); self.state_stack.push(TokenOrRedirect::RightCurly); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::Atom(ellipsis_atom)); self.state_stack.push(TokenOrRedirect::LeftCurly); return false; @@ -687,12 +731,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { true } - fn format_numbered_vars(&mut self, iter: &mut HCPreOrderIterator) -> bool { - let addr = iter.stack().last().cloned().unwrap(); + fn format_numbered_vars(&mut self) -> bool { + let h = self.iter.stack_last().unwrap(); // 7.10.4 - if let Some(var) = iter.machine_st().numbervar(&self.numbervars_offset, addr) { - iter.stack().pop(); + if let Some(var) = numbervar(&self.numbervars_offset, self.iter.heap[h]) { + self.iter.pop_stack(); self.state_stack.push(TokenOrRedirect::NumberedVar(var)); return true; } @@ -702,198 +746,134 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { fn format_clause( &mut self, - iter: &mut HCPreOrderIterator, max_depth: usize, arity: usize, ct: ClauseType, + op_desc: Option, ) -> bool { if self.numbervars && is_numbered_var(&ct, arity) { - if self.format_numbered_vars(iter) { + if self.format_numbered_vars() { return true; } } - if let Some(spec) = ct.spec() { - if "." == ct.name().as_str() && is_infix!(spec.assoc()) { + let dot_atom = atom!("."); + let name = ct.name(); + + if let Some(spec) = op_desc { + if dot_atom == name && is_infix!(spec.get_spec()) { if !self.ignore_ops { - self.push_list(iter, max_depth); + self.push_list(max_depth); return true; } } - if !self.ignore_ops && spec.prec() > 0 { - self.enqueue_op(iter, max_depth, ct, spec); + if !self.ignore_ops && spec.get_prec() > 0 { + self.enqueue_op(max_depth, ct, spec); return true; } } - return match (ct.name().as_str(), arity) { - ("{}", 1) if !self.ignore_ops => self.format_curly_braces(iter, max_depth), - _ => self.format_struct(iter, max_depth, arity, ct.name()), + return match (name.as_str(), arity) { + ("{}", 1) if !self.ignore_ops => self.format_curly_braces(max_depth), + _ => self.format_struct(max_depth, arity, name), }; } - #[inline] - fn push_char(&mut self, c: char) { - self.outputter.push_char(c); - self.last_item_idx = self.outputter.len(); - } - - #[inline] - fn append_str(&mut self, s: &str) { - self.last_item_idx = self.outputter.len(); - self.outputter.append(s); - } + fn offset_as_string(&mut self, h: usize) -> Option { + let addr = self.iter.heap[h]; - fn offset_as_string(&mut self, iter: &mut HCPreOrderIterator, addr: Addr) -> Option { if let Some(var) = self.var_names.get(&addr) { - if addr.as_var().is_some() { - return Some(format!("{}", var)); - } else { - iter.stack().push(addr); - return None; - } + read_heap_cell!(addr, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + return Some(format!("{}", var.as_str())); + } + _ => { + self.iter.push_stack(h); + return None; + } + ); } - match addr { - Addr::Lis(h) | Addr::Str(h) => Some(format!("{}", h)), - _ => { - if let Some(r) = addr.as_var() { - match r { - Ref::StackCell(fr, sc) => Some(format!("_s_{}_{}", fr, sc)), - Ref::HeapCell(h) | Ref::AttrVar(h) => Some(format!("_{}", h)), - } - } else { - None - } + read_heap_cell!(addr, + (HeapCellValueTag::Lis | HeapCellValueTag::Str, h) => { + Some(format!("{}", h)) } - } - } - - fn record_children_as_non_cyclic(&mut self, addr: &Addr) { - match addr { - &Addr::Lis(l) => { - let c1 = self - .machine_st - .store(self.machine_st.deref(Addr::HeapCell(l))); - let c2 = self - .machine_st - .store(self.machine_st.deref(Addr::HeapCell(l + 1))); - - if let Some(c) = functor_location(&c1) { - self.non_cyclic_terms.insert(c); - } - - if let Some(c) = functor_location(&c2) { - self.non_cyclic_terms.insert(c); - } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { + Some(format!("_{}", h)) } - &Addr::Str(s) => { - let arity = match &self.machine_st.heap[s] { - HeapCellValue::NamedStr(arity, ..) => arity, - _ => { - unreachable!() - } - }; - - for i in 1..arity + 1 { - let c = self - .machine_st - .store(self.machine_st.deref(Addr::HeapCell(s + i))); - - if let Some(c) = functor_location(&c) { - self.non_cyclic_terms.insert(c); - } - } + (HeapCellValueTag::StackVar, h) => { + Some(format!("_s_{}", h)) } - &Addr::PStrLocation(h, _) => { - let tail = self.machine_st.heap[h + 1].as_addr(h + 1); - let tail = self.machine_st.store(self.machine_st.deref(tail)); - - if let Some(c) = functor_location(&tail) { - self.non_cyclic_terms.insert(c); - } + _ => { + None } - _ => {} - } + ) } - fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option { - iter.stack().last().cloned().and_then(|addr| { - let addr = self.machine_st.store(self.machine_st.deref(addr)); + fn check_for_seen(&mut self) -> Option { + if let Some(addr) = self.iter.next() { + let is_cyclic = addr.is_forwarded(); - if let Some(var) = self.var_names.get(&addr) { - self.heap_locs.insert(addr.clone(), Rc::new(var.clone())); - } + let addr = heap_bound_store( + self.iter.heap, + heap_bound_deref(self.iter.heap, addr), + ); + + let addr = unmark_cell_bits!(addr); - match self.heap_locs.get(&addr).cloned() { - Some(var) if addr.is_ref() => { - iter.stack().pop(); + match self.var_names.get(&addr).cloned() { + Some(var) if addr.is_var() => { + // If addr is an unbound variable and maps to + // a name via heap_locs, append the name to + // the current output, and return None. None + // short-circuits handle_heap_term. + // self.iter.pop_stack(); - push_space_if_amb!(self, &var, { - self.append_str(&var); + let var_str = var.as_str(); + + push_space_if_amb!(self, var_str, { + append_str!(self, var_str); }); - return None; + None } var_opt => { - let offset = match functor_location(&addr) { - Some(offset) => offset, - None => { - return iter.next(); - } - }; - - if !self.non_cyclic_terms.contains(&offset) { - if let Some(reps) = self.cyclic_terms.get(&addr).cloned() { - if reps > 0 { - self.cyclic_terms.insert(addr, reps - 1); - } else { - match var_opt { - Some(var) => { - push_space_if_amb!(self, &var, { - self.append_str(&var); - }); - - iter.stack().pop(); - } - None => { - push_space_if_amb!(self, "...", { - self.append_str("..."); - }); - - iter.stack().pop(); - self.cyclic_terms.insert(addr, 2); - } - } - - return None; + if is_cyclic && addr.is_compound() { + // self-referential variables are marked "cyclic". + match var_opt { + Some(var) => { + // If the term is bound to a named variable, + // print the variable's name to output. + push_space_if_amb!(self, &var, { + append_str!(self, &var); + }); } - } else if self.machine_st.is_cyclic_term(addr.clone()) { - if var_opt.is_some() { - self.cyclic_terms.insert(addr, 0); - } else { - self.cyclic_terms.insert(addr, 2); + None => { + // otherwise, contract it to an ellipsis. + push_space_if_amb!(self, "...", { + append_str!(self, "..."); + }); } - } else { - self.record_children_as_non_cyclic(&addr); - self.non_cyclic_terms.insert(offset); } - } else { - self.record_children_as_non_cyclic(&addr); + + return None; } - iter.next() + Some(addr) } } - }) + } else { + while let Some(_) = self.iter.pop_stack() {} + None + } } - fn print_atom(&mut self, atom: &ClauseName) { + fn print_atom(&mut self, atom: Atom) { let result = self.print_op_addendum(atom.as_str()); push_space_if_amb!(self, result.as_str(), { - self.append_str(&result); + append_str!(self, &result); }); } @@ -929,23 +909,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }; push_space_if_amb!(self, &result, { - self.append_str(&result); + append_str!(self, &result); }); } #[inline] fn print_ip_addr(&mut self, ip: IpAddr) { - self.push_char('\''); - self.append_str(&format!("{}", ip)); - self.push_char('\''); + push_char!(self, '\''); + append_str!(self, &format!("{}", ip)); + push_char!(self, '\''); } #[inline] - fn print_raw_ptr(&mut self, ptr: *const u8) { - self.append_str(&format!("0x{:x}", ptr as usize)); + fn print_raw_ptr(&mut self, ptr: *const ArenaHeader) { + append_str!(self, &format!("0x{:x}", ptr as *const u8 as usize)); } - fn print_number(&mut self, n: Number, op: &Option) { + fn print_number(&mut self, n: NumberFocus, op: &Option) { let add_brackets = if let Some(op) = op { op.is_negative_sign() && n.is_positive() } else { @@ -953,86 +933,106 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }; if add_brackets { - self.push_char('('); + push_char!(self, '('); } match n { - Number::Float(fl) => { - if &fl == &OrderedFloat(0f64) { - push_space_if_amb!(self, "0.0", { - self.append_str("0.0"); - }); - } else { - let OrderedFloat(fl) = fl; - let output_str = format!("{0:<20?}", fl); + NumberFocus::Unfocused(n) => match n { + Number::Float(fl) => { + if &fl == &OrderedFloat(0f64) { + push_space_if_amb!(self, "0.0", { + append_str!(self, "0.0"); + }); + } else { + let OrderedFloat(fl) = fl; + let output_str = format!("{0:<20?}", fl); + + push_space_if_amb!(self, &output_str, { + append_str!(self, &output_str.trim()); + }); + } + } + Number::Rational(r) => { + self.print_rational(r, add_brackets); + return; + } + n => { + let output_str = format!("{}", n); push_space_if_amb!(self, &output_str, { - self.append_str(&output_str.trim()); + append_str!(self, &output_str); }); } + }, + NumberFocus::Denominator(r) => { + let output_str = format!("{}", r.denom()); + + push_space_if_amb!(self, &output_str, { + append_str!(self, &output_str); + }); } - Number::Rational(r) => { - self.print_rational(&r, add_brackets); - return; - } - n => { - let output_str = format!("{}", n); + NumberFocus::Numerator(r) => { + let output_str = format!("{}", r.numer()); push_space_if_amb!(self, &output_str, { - self.append_str(&output_str); + append_str!(self, &output_str); }); } } if add_brackets { - self.push_char(')'); + push_char!(self, ')'); } } - fn print_rational(&mut self, r: &Rational, add_brackets: bool) { - match self.op_dir.get(&(clause_name!("rdiv"), Fixity::In)) { - Some(OpDirValue(ref spec)) => { + fn print_rational(&mut self, r: TypedArenaPtr, add_brackets: bool) { + match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) { + Some(op_desc) => { if add_brackets { self.state_stack.push(TokenOrRedirect::Close); } - let rdiv_ct = clause_name!("rdiv"); + let rdiv_ct = atom!("rdiv"); - let left_directed_op = if spec.prec() > 0 { - Some(DirectedOp::Left(rdiv_ct.clone(), spec.clone())) + let left_directed_op = if op_desc.get_prec() > 0 { + Some(DirectedOp::Left(rdiv_ct, *op_desc)) } else { None }; - let right_directed_op = if spec.prec() > 0 { - Some(DirectedOp::Right(rdiv_ct.clone(), spec.clone())) + let right_directed_op = if op_desc.get_prec() > 0 { + Some(DirectedOp::Right(rdiv_ct, *op_desc)) } else { None }; - if spec.prec() > 0 { - self.state_stack.push(TokenOrRedirect::Number( - Number::from(r.denom()), + if op_desc.get_prec() > 0 { + self.state_stack.push(TokenOrRedirect::NumberFocus( + NumberFocus::Denominator(r), left_directed_op, )); self.state_stack - .push(TokenOrRedirect::Op(rdiv_ct, spec.clone())); + .push(TokenOrRedirect::Op(rdiv_ct, *op_desc)); - self.state_stack.push(TokenOrRedirect::Number( - Number::from(r.numer()), + self.state_stack.push(TokenOrRedirect::NumberFocus( + NumberFocus::Numerator(r), right_directed_op, )); } else { self.state_stack.push(TokenOrRedirect::Close); - self.state_stack - .push(TokenOrRedirect::Number(Number::from(r.denom()), None)); + self.state_stack.push(TokenOrRedirect::NumberFocus( + NumberFocus::Denominator(r), + None, + )); self.state_stack.push(TokenOrRedirect::Comma); - self.state_stack - .push(TokenOrRedirect::Number(Number::from(r.numer()), None)); + self.state_stack.push(TokenOrRedirect::NumberFocus( + NumberFocus::Numerator(r), + None, + )); self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Atom(rdiv_ct)); @@ -1046,157 +1046,164 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - fn print_char(&mut self, is_quoted: bool, c: char) { - if non_quoted_token(once(c)) { - let c = char_to_string(false, c); + // returns true if max_depth limit is reached and ellipsis is printed. + fn print_string_as_functor(&mut self, focus: usize, max_depth: usize) -> bool { + let iter = HeapPStrIter::new(self.iter.heap, focus); - push_space_if_amb!(self, &c, { - self.append_str(c.as_str()); - }); - } else { - let mut result = String::new(); + for (char_count, c) in iter.chars().enumerate() { + append_str!(self, "'.'"); + push_char!(self, '('); - if self.quoted { - result.push('\''); - result += &char_to_string(is_quoted, c); - result.push('\''); - } else { - result += &char_to_string(is_quoted, c); - } + print_char!(self, self.quoted, c); + push_char!(self, ','); - push_space_if_amb!(self, &result, { - self.append_str(result.as_str()); - }); + self.state_stack.push(TokenOrRedirect::Close); + + if max_depth >= char_count + 1 { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + return true; + } } + + false } - fn print_proper_string(&mut self, buf: String, max_depth: usize) { - self.push_char('"'); + fn print_proper_string(&mut self, focus: usize, max_depth: usize) { + push_char!(self, '"'); - let buf = if max_depth == 0 { - String::from_iter(buf.chars().map(|c| char_to_string(self.quoted, c))) + let iter = HeapPStrIter::new(self.iter.heap, focus); + + if max_depth == 0 { + for c in iter.chars() { + for c in char_to_string(self.quoted, c).chars() { + push_char!(self, c); + } + } } else { let mut char_count = 0; - let mut buf = String::from_iter(buf.chars().take(max_depth).map(|c| { + + for c in iter.chars().take(max_depth) { char_count += 1; - char_to_string(self.quoted, c) - })); + + for c in char_to_string(self.quoted, c).chars() { + push_char!(self, c); + } + } if char_count == max_depth { - buf += " ..."; + append_str!(self, " ..."); } + } - buf - }; + push_char!(self, '"'); + } - self.append_str(&buf); - self.push_char('"'); + fn remove_list_children(&mut self, h: usize) { + match self.iter.heap[h].get_tag() { + HeapCellValueTag::Lis => { + self.iter.pop_stack(); + self.iter.pop_stack(); + } + HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset => { + self.iter.pop_stack(); + } + HeapCellValueTag::CStr => { + } + _ => { + unreachable!(); + } + } } - fn print_list_like(&mut self, iter: &mut HCPreOrderIterator, addr: Addr, mut max_depth: usize) { - if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); - iter.stack().pop(); + fn print_list_like(&mut self, mut max_depth: usize) { + let focus = self.iter.focus(); + let mut heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); - return; + if heap_pstr_iter.next().is_some() { + while let Some(_) = heap_pstr_iter.next() {} + } else { + return self.push_list(max_depth); } - let mut heap_pstr_iter = self.machine_st.heap_pstr_iter(addr); + let end_h = heap_pstr_iter.focus(); + let end_cell = self.iter.heap[end_h]; - let buf = heap_pstr_iter.to_string(); + self.remove_list_children(focus); - if buf.is_empty() { - self.push_list(iter, max_depth); + if self.check_max_depth(&mut max_depth) { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); return; } - iter.stack().pop(); - iter.stack().pop(); - - let end_addr = heap_pstr_iter.focus(); - let at_cdr = self.at_cdr(","); - if !at_cdr && Addr::EmptyList == end_addr { - if !self.ignore_ops { - self.print_proper_string(buf, max_depth); - return; - } + if !at_cdr && !self.ignore_ops && end_cell.is_string_terminator(&self.iter.heap) { + return self.print_proper_string(focus, max_depth); } - let buf_len = buf.len(); - - let buf_iter: Box> = if self.max_depth == 0 { - Box::new(buf.chars()) - } else { - Box::new(buf.chars().take(max_depth)) - }; - - let mut byte_len = 0; - if self.ignore_ops { - let mut char_count = 0; - - for c in buf_iter { - self.append_str("'.'"); - self.push_char('('); - - self.print_char(self.quoted, c); - self.push_char(','); - - char_count += 1; - byte_len += c.len_utf8(); - } - - for _ in 0..char_count { - self.state_stack.push(TokenOrRedirect::Close); - } + if !self.print_string_as_functor(end_h, max_depth) { + if end_cell.get_tag() == HeapCellValueTag::CStr { + append_str!(self, "[]"); + } else { + if self.outputter.ends_with(",") { + self.outputter.truncate(self.outputter.len() - ','.len_utf8()); + } - if self.max_depth > 0 && buf_len > byte_len { - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); - } else { - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth)); - iter.stack().push(end_addr); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.iter.push_stack(end_h); + } } } else { let switch = if !at_cdr { - self.push_char('['); + push_char!(self, '['); true } else { false }; - for c in buf_iter { - self.print_char(self.quoted, c); - self.push_char(','); + let heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus); + + let mut iter = heap_pstr_iter.chars(); + let mut char_count = 0; + + while let Some(c) = iter.next() { + print_char!(self, self.quoted, c); + push_char!(self, ','); + + char_count += 1; - byte_len += c.len_utf8(); + if max_depth > 0 && max_depth <= char_count { + break; + } } - self.state_stack - .push(TokenOrRedirect::CloseList(Rc::new(Cell::new((switch, 0))))); + self.state_stack.push(TokenOrRedirect::CloseList(Rc::new(Cell::new((switch, 0))))); - if self.max_depth > 0 && buf_len > byte_len { - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + if self.max_depth > 0 && iter.next().is_some() { + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); } else { - self.outputter - .truncate(self.outputter.len() - ','.len_utf8()); - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth)); + if iter.cycle_detected() { + self.iter.heap[end_h].set_forwarding_bit(true); + } - iter.stack().push(end_addr); + if end_cell.get_tag() == HeapCellValueTag::CStr { + self.state_stack.push(TokenOrRedirect::Atom(atom!("[]"))); + } else { + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.iter.push_stack(end_h); + } } self.state_stack.push(TokenOrRedirect::HeadTailSeparator); + + if self.outputter.ends_with(",") { + self.outputter.truncate(self.outputter.len() - ','.len_utf8()); + } } } - fn check_max_depth(&mut self, max_depth: &mut usize) -> bool { + fn check_max_depth(&self, max_depth: &mut usize) -> bool { if self.max_depth > 0 && *max_depth == 0 { return true; } @@ -1208,17 +1215,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { false } - fn push_list(&mut self, iter: &mut HCPreOrderIterator, mut max_depth: usize) { + fn push_list(&mut self, mut max_depth: usize) { if self.check_max_depth(&mut max_depth) { - iter.stack().pop(); - iter.stack().pop(); + self.iter.pop_stack(); + self.iter.pop_stack(); let cell = Rc::new(Cell::new((true, 0))); - self.state_stack - .push(TokenOrRedirect::CloseList(cell.clone())); - self.state_stack - .push(TokenOrRedirect::Atom(clause_name!("..."))); + self.state_stack.push(TokenOrRedirect::CloseList(cell.clone())); + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::OpenList(cell)); return; @@ -1226,26 +1231,22 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let cell = Rc::new(Cell::new((true, max_depth))); - self.state_stack - .push(TokenOrRedirect::CloseList(cell.clone())); + self.state_stack.push(TokenOrRedirect::CloseList(cell.clone())); - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); // bar - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::OpenList(cell)); } fn handle_op_as_struct( &mut self, - name: ClauseName, + name: Atom, arity: usize, - iter: &mut HCPreOrderIterator, op: &Option, is_functor_redirect: bool, - spec: SharedOpDesc, + op_desc: OpDesc, negated_operand: bool, max_depth: usize, ) { @@ -1253,20 +1254,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { negated_operand || if let Some(ref op) = op { if self.numbervars && arity == 1 && name.as_str() == "$VAR" { - !iter.immediate_leaf_has_property(|addr, heap| { - match heap.index_addr(&addr).as_ref() { - &HeapCellValue::Integer(ref n) => &**n >= &0, - &HeapCellValue::Addr(Addr::Fixnum(n)) => n >= 0, - &HeapCellValue::Addr(Addr::Float(f)) => f >= OrderedFloat(0f64), - &HeapCellValue::Rational(ref r) => &**r >= &0, + !self.iter.immediate_leaf_has_property(|addr| { + match Number::try_from(addr) { + Ok(Number::Integer(n)) => &*n >= &0, + Ok(Number::Fixnum(n)) => n.get_num() >= 0, + Ok(Number::Float(f)) => f >= OrderedFloat(0f64), + Ok(Number::Rational(r)) => &*r >= &0, _ => false, } - }) && needs_bracketing(&spec, op) + }) && needs_bracketing(op_desc, op) } else { - needs_bracketing(&spec, op) + needs_bracketing(op_desc, op) } } else { - is_functor_redirect && spec.prec() >= 1000 + is_functor_redirect && op_desc.get_prec() >= 1000 } } else { false @@ -1276,44 +1277,46 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::Close); } - let ct = ClauseType::from(name.clone(), arity, Some(spec)); + let ct = ClauseType::from(name, arity); - if self.format_clause(iter, max_depth, arity, ct) { - if add_brackets { - self.state_stack.push(TokenOrRedirect::Open); + if self.format_clause(max_depth, arity, ct, Some(op_desc)) && add_brackets { + self.state_stack.push(TokenOrRedirect::Open); - if let Some(ref op) = &op { - if op.is_left() && requires_space(op.as_str(), "(") { - self.state_stack.push(TokenOrRedirect::Space); - } + if let Some(ref op) = &op { + if op.is_left() && requires_space(op.as_atom().as_str(), "(") { + self.state_stack.push(TokenOrRedirect::Space); } } } } - fn print_tcp_listener( - &mut self, - iter: &mut HCPreOrderIterator, - tcp_listener: &TcpListener, - max_depth: usize, - ) { + #[allow(dead_code)] + fn print_tcp_listener(&mut self, tcp_listener: &TcpListener, max_depth: usize) { let (ip, port) = if let Some(addr) = tcp_listener.local_addr().ok() { - (addr.ip(), Number::from(addr.port() as isize)) + ( + addr.ip(), + Number::arena_from(addr.port() as usize, self.arena), + ) } else { - let disconnected_atom = clause_name!("$disconnected_tcp_listener"); + let disconnected_atom = atom!("$disconnected_tcp_listener"); self.state_stack .push(TokenOrRedirect::Atom(disconnected_atom)); return; }; - if self.format_struct(iter, max_depth, 1, clause_name!("$tcp_listener")) { + let tcp_listener_atom = atom!("$tcp_listener"); + + if self.format_struct(max_depth, 1, tcp_listener_atom) { let atom = self.state_stack.pop().unwrap(); self.state_stack.pop(); self.state_stack.pop(); - self.state_stack.push(TokenOrRedirect::Number(port, None)); + self.state_stack.push(TokenOrRedirect::NumberFocus( + NumberFocus::Unfocused(port), + None, + )); self.state_stack.push(TokenOrRedirect::Comma); self.state_stack.push(TokenOrRedirect::IpAddr(ip)); @@ -1322,13 +1325,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - fn print_stream(&mut self, iter: &mut HCPreOrderIterator, stream: &Stream, max_depth: usize) { - if let Some(alias) = &stream.options().alias { + fn print_stream(&mut self, stream: Stream, max_depth: usize) { + if let Some(alias) = stream.options().get_alias() { self.print_atom(alias); } else { - if self.format_struct(iter, max_depth, 1, clause_name!("$stream")) { - let atom = if stream.is_stdout() || stream.is_stdin() || stream.is_stderr() { - TokenOrRedirect::Atom(clause_name!("user")) + let stream_atom = atom!("$stream"); + + if self.format_struct(max_depth, 1, stream_atom) { + let atom = if stream.is_stdout() || stream.is_stdin() { + TokenOrRedirect::Atom(atom!("user")) } else { TokenOrRedirect::RawPtr(stream.as_ptr()) }; @@ -1347,121 +1352,144 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { fn handle_heap_term( &mut self, - iter: &mut HCPreOrderIterator, op: Option, is_functor_redirect: bool, max_depth: usize, ) { - let negated_operand = negated_op_needs_bracketing(iter, &op); + let negated_operand = negated_op_needs_bracketing(&self.iter, self.op_dir, &op); - let addr = match self.check_for_seen(iter) { + let addr = match self.check_for_seen() { Some(addr) => addr, None => return, }; - match self.machine_st.heap.index_addr(&addr).as_ref() { - &HeapCellValue::NamedStr(arity, ref name, ref spec) => { - let spec = - fetch_op_spec_from_existing(name.clone(), arity, spec.clone(), self.op_dir); - - if let Some(spec) = spec { - self.handle_op_as_struct( - name.clone(), - arity, - iter, - &op, - is_functor_redirect, - spec.clone(), - negated_operand, - max_depth, - ); - } else { - push_space_if_amb!(self, name.as_str(), { - let ct = ClauseType::from(name.clone(), arity, spec); - self.format_clause(iter, max_depth, arity, ct); - }); - } - } - &HeapCellValue::Atom(ref atom, ref spec) => { - if let Some(_) = fetch_atom_op_spec(atom.clone(), spec.clone(), self.op_dir) { + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") { + if !self.at_cdr("") { + append_str!(self, "[]"); + } + } else if arity > 0 { + if let Some(spec) = fetch_op_spec(name, arity, self.op_dir) { + self.handle_op_as_struct( + name, + arity, + &op, + is_functor_redirect, + spec, + negated_operand, + max_depth, + ); + } else { + push_space_if_amb!(self, name.as_str(), { + let ct = ClauseType::from(name, arity); + self.format_clause(max_depth, arity, ct, None); + }); + } + } else if fetch_op_spec(name, arity, self.op_dir).is_some() { let mut result = String::new(); if let Some(ref op) = op { - if self.outputter.ends_with(&format!(" {}", op.as_str())) { + if self.outputter.ends_with(&format!(" {}", op.as_atom().as_str())) { result.push(' '); } result.push('('); } - result += &self.print_op_addendum(atom.as_str()); + result += &self.print_op_addendum(name.as_str()); if op.is_some() { result.push(')'); } push_space_if_amb!(self, &result, { - self.append_str(&result); + append_str!(self, &result); }); } else { - push_space_if_amb!(self, atom.as_str(), { - self.print_atom(&atom); + push_space_if_amb!(self, name.as_str(), { + self.print_atom(name); }); } } - &HeapCellValue::Addr(Addr::Char(c)) => { - self.print_char(self.quoted, c); - } - &HeapCellValue::Addr(Addr::CutPoint(b)) => { - self.append_str(&format!("{}", b)); - } - &HeapCellValue::Addr(Addr::EmptyList) => { - if !self.at_cdr("") { - self.append_str("[]"); + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.iter.heap[s]) + .get_name_and_arity(); + + if let Some(spec) = fetch_op_spec(name, arity, self.op_dir) { + self.handle_op_as_struct( + name, + arity, + &op, + is_functor_redirect, + spec, + negated_operand, + max_depth, + ); + } else { + push_space_if_amb!(self, name.as_str(), { + let ct = ClauseType::from(name, arity); + self.format_clause(max_depth, arity, ct, None); + }); } } - &HeapCellValue::Addr(Addr::Float(n)) => { - self.print_number(Number::Float(n), &op); + (HeapCellValueTag::Fixnum, n) => { + append_str!(self, &format!("{}", n.get_num())); } - &HeapCellValue::Addr(Addr::Fixnum(n)) => { - self.print_number(Number::Fixnum(n), &op); + (HeapCellValueTag::F64, f) => { + self.print_number(NumberFocus::Unfocused(Number::Float(**f)), &op); } - &HeapCellValue::Addr(Addr::Usize(u)) => { - self.append_str(&format!("{}", u)); + (HeapCellValueTag::PStrOffset) => { + self.print_list_like(max_depth); } - &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => { - self.print_list_like(iter, Addr::PStrLocation(h, n), max_depth); + (HeapCellValueTag::PStr | HeapCellValueTag::CStr) => { + self.print_list_like(max_depth); } - &HeapCellValue::Addr(Addr::Lis(l)) => { + (HeapCellValueTag::Lis) => { if self.ignore_ops { - self.format_struct(iter, max_depth, 2, clause_name!(".")); + let period_atom = atom!("."); + self.format_struct(max_depth, 2, period_atom); } else { - self.print_list_like(iter, Addr::Lis(l), max_depth); + self.print_list_like(max_depth); } } - &HeapCellValue::Addr(addr) => { - if let Some(offset_str) = self.offset_as_string(iter, addr) { + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let h = self.iter.focus(); + + if let Some(offset_str) = self.offset_as_string(h) { push_space_if_amb!(self, &offset_str, { - self.append_str(offset_str.as_str()); + append_str!(self, offset_str.as_str()); }) } } - &HeapCellValue::Integer(ref n) => { - self.print_number(Number::Integer(n.clone()), &op); - } - &HeapCellValue::Rational(ref n) => { - self.print_number(Number::Rational(n.clone()), &op); - } - &HeapCellValue::Stream(ref stream) => { - self.print_stream(iter, stream, max_depth); + (HeapCellValueTag::Char, c) => { + print_char!(self, self.quoted, c); } - &HeapCellValue::TcpListener(ref tcp_listener) => { - self.print_tcp_listener(iter, tcp_listener, max_depth); + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::F64, f) => { + self.print_number(NumberFocus::Unfocused(Number::Float(*f)), &op); + } + (ArenaHeaderTag::Integer, n) => { + self.print_number(NumberFocus::Unfocused(Number::Integer(n)), &op); + } + (ArenaHeaderTag::Rational, r) => { + self.print_number(NumberFocus::Unfocused(Number::Rational(r)), &op); + } + (ArenaHeaderTag::Stream, stream) => { + self.print_stream(stream, max_depth); + } + (ArenaHeaderTag::OssifiedOpDir, _op_dir) => { + append_str!(self, "$ossified_op_dir"); + } + _ => { + } + ); } _ => { unreachable!() } - } + ); } fn at_cdr(&mut self, tr: &str) -> bool { @@ -1469,7 +1497,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if self.outputter.ends_with("|") { self.outputter.truncate(len - "|".len()); - self.append_str(tr); + append_str!(self, tr); true } else { @@ -1477,29 +1505,27 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } - pub(crate) fn print(mut self, addr: Addr) -> Outputter { - let mut iter = self.machine_st.pre_order_iter(addr); - + pub fn print(mut self) -> Outputter { loop { if let Some(loc_data) = self.state_stack.pop() { match loc_data { - TokenOrRedirect::Atom(atom) => self.print_atom(&atom), - TokenOrRedirect::BarAsOp => self.append_str(" | "), + TokenOrRedirect::Atom(atom) => self.print_atom(atom), + TokenOrRedirect::BarAsOp => append_str!(self, " | "), TokenOrRedirect::Op(atom, _) => self.print_op(atom.as_str()), - TokenOrRedirect::NumberedVar(num_var) => self.append_str(num_var.as_str()), + TokenOrRedirect::NumberedVar(num_var) => append_str!(self, &num_var), TokenOrRedirect::CompositeRedirect(max_depth, op) => { - self.handle_heap_term(&mut iter, Some(op), false, max_depth) + self.handle_heap_term(Some(op), false, max_depth) } TokenOrRedirect::FunctorRedirect(max_depth) => { - self.handle_heap_term(&mut iter, None, true, max_depth) + self.handle_heap_term(None, true, max_depth) } - TokenOrRedirect::Close => self.push_char(')'), + TokenOrRedirect::Close => push_char!(self, ')'), TokenOrRedirect::IpAddr(ip) => self.print_ip_addr(ip), TokenOrRedirect::RawPtr(ptr) => self.print_raw_ptr(ptr), - TokenOrRedirect::Open => self.push_char('('), + TokenOrRedirect::Open => push_char!(self, '('), TokenOrRedirect::OpenList(delimit) => { if !self.at_cdr(",") { - self.push_char('['); + push_char!(self, '['); } else { let (_, max_depth) = delimit.get(); delimit.set((false, max_depth)); @@ -1507,19 +1533,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } TokenOrRedirect::CloseList(delimit) => { if delimit.get().0 { - self.push_char(']'); + push_char!(self, ']'); } } - TokenOrRedirect::HeadTailSeparator => self.append_str("|"), - TokenOrRedirect::Number(n, op) => self.print_number(n, &op), - TokenOrRedirect::Comma => self.append_str(","), - TokenOrRedirect::Space => self.push_char(' '), - TokenOrRedirect::LeftCurly => self.push_char('{'), - TokenOrRedirect::RightCurly => self.push_char('}'), + TokenOrRedirect::HeadTailSeparator => append_str!(self, "|"), + TokenOrRedirect::NumberFocus(n, op) => self.print_number(n, &op), + TokenOrRedirect::Comma => append_str!(self, ","), + TokenOrRedirect::Space => push_char!(self, ' '), + TokenOrRedirect::LeftCurly => push_char!(self, '{'), + TokenOrRedirect::RightCurly => push_char!(self, '}'), } - } else if !iter.stack().is_empty() { + } else if !self.iter.stack_is_empty() { let spec = self.toplevel_spec.take(); - self.handle_heap_term(&mut iter, spec, false, self.max_depth); + self.handle_heap_term(spec, false, self.max_depth); } else { break; } @@ -1528,3 +1554,273 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.outputter } } + +#[cfg(test)] +mod tests { + use super::*; + + use crate::machine::mock_wam::*; + + #[test] + fn term_printing_tests() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + let c_atom = atom!("c"); + + wam.machine_st.heap.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + let output = printer.print(); + + assert_eq!(output.result(), "f(a,b)"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + let output = printer.print(); + + assert_eq!(output.result(), "f(a,b,a,...)"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + // print L = [L|L]. + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + let output = printer.print(); + + assert_eq!(output.result(), "[...|...]"); + + let mut printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + printer + .var_names + .insert(list_loc_as_cell!(1), Rc::new("L".to_string())); + + let output = printer.print(); + + assert_eq!(output.result(), "[L|L]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(str_loc_as_cell!(5)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.extend(functor); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0), + ); + + let output = printer.print(); + + assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap[4] = list_loc_as_cell!(1); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0), + ); + + let output = printer.print(); + + assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|...]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + { + let mut printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + printer + .var_names + .insert(list_loc_as_cell!(1), Rc::new("L".to_string())); + + let output = printer.print(); + + assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|L]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + // issue #382 + wam.machine_st.heap.clear(); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + + for idx in 0..3000 { + wam.machine_st.heap.push(heap_loc_as_cell!(2 * idx + 1)); + wam.machine_st.heap.push(list_loc_as_cell!(2 * idx + 2 + 1)); + } + + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0) + ); + + printer.max_depth = 5; + + let output = printer.print(); + + assert_eq!(output.result(), "[_1,_3,_5,_7,_9,...]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + put_partial_string(&mut wam.machine_st.heap, "abc", &mut wam.machine_st.atom_tbl); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + pstr_loc_as_cell!(0) + ); + + let output = printer.print(); + + assert_eq!(output.result(), "[a,b,c|_1]"); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.pop(); + + wam.machine_st.heap.push(list_loc_as_cell!(2)); + + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(4)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(6)); + wam.machine_st.heap.push(atom_as_cell!(c_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let printer = HCPrinter::new( + &mut wam.machine_st.heap, + &mut wam.machine_st.arena, + &wam.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(0), + ); + + let output = printer.print(); + + assert_eq!(output.result(), "\"abcabc\""); + } + + all_cells_unmarked(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + assert_eq!( + &wam.parse_and_print_term("=(X,[a,b,c|X]).").unwrap(), + "=(X,[a,b,c|X])" + ); + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!( + &wam.parse_and_print_term("[a,b,\"a\",[a,b,c]].").unwrap(), + "[a,b,\"a\",\"abc\"]" + ); + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!( + &wam.parse_and_print_term("[\"abc\",e,f,[g,e,h,Y,v|[X,Y]]].") + .unwrap(), + "[\"abc\",e,f,[g,e,h,Y,v,X,Y]]" + ); + + all_cells_unmarked(&wam.machine_st.heap); + + assert_eq!(&wam.parse_and_print_term("f((a,b)).").unwrap(), "f((a,b))"); + } +} diff --git a/src/indexing.rs b/src/indexing.rs index a71ab01f..6d63ff79 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1,33 +1,20 @@ -use prolog_parser::ast::*; -use prolog_parser::clause_name; -use prolog_parser::tabled_rc::*; +use crate::atom_table::*; +use crate::parser::ast::*; use crate::forms::*; use crate::instructions::*; -use crate::rug::Integer; use indexmap::IndexMap; - use slice_deque::{sdeq, SliceDeque}; -use std::convert::TryFrom; use std::hash::Hash; use std::iter::once; use std::mem; -use std::rc::Rc; - -#[derive(Debug, Clone, Copy)] -pub(crate) enum IndexingCodePtr { - External(usize), // the index points past the indexing instruction prelude. - DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction. - Fail, - Internal(usize), // the index points into the indexing instruction prelude. -} #[derive(Debug, Clone, Copy)] enum OptArgIndexKeyType { Structure, - Constant, + Literal, // List, } @@ -35,7 +22,7 @@ impl OptArgIndexKey { #[inline] fn has_key_type(&self, key_type: OptArgIndexKeyType) -> bool { match (self, key_type) { - (OptArgIndexKey::Constant(..), OptArgIndexKeyType::Constant) + (OptArgIndexKey::Literal(..), OptArgIndexKeyType::Literal) | (OptArgIndexKey::Structure(..), OptArgIndexKeyType::Structure) // | (OptArgIndexKey::List(..), OptArgIndexKeyType::List) => true, @@ -45,11 +32,12 @@ impl OptArgIndexKey { } #[inline] -fn search_skeleton_for_first_key_type( - skeleton: &[ClauseIndexInfo], +fn search_skeleton_for_first_key_type<'a>( + skeleton: &'a [ClauseIndexInfo], + retracted_dynamic_clauses: &'a Option>, key_type: OptArgIndexKeyType, append_or_prepend: AppendOrPrepend, -) -> Option<&OptArgIndexKey> { +) -> Option<&'a OptArgIndexKey> { if append_or_prepend.is_append() { for clause_index_info in skeleton.iter().rev() { if clause_index_info.opt_arg_index_key.has_key_type(key_type) { @@ -64,11 +52,20 @@ fn search_skeleton_for_first_key_type( } } + if let Some(retracted_clauses) = retracted_dynamic_clauses { + for clause_index_info in retracted_clauses.iter().rev() { + if clause_index_info.opt_arg_index_key.has_key_type(key_type) { + return Some(&clause_index_info.opt_arg_index_key); + } + } + } + None } struct IndexingCodeMergingPtr<'a> { skeleton: &'a mut [ClauseIndexInfo], + retracted_dynamic_clauses: &'a Option>, indexing_code: &'a mut Vec, offset: usize, append_or_prepend: AppendOrPrepend, @@ -79,22 +76,22 @@ impl<'a> IndexingCodeMergingPtr<'a> { #[inline] fn new( skeleton: &'a mut [ClauseIndexInfo], + retracted_dynamic_clauses: &'a Option>, indexing_code: &'a mut Vec, append_or_prepend: AppendOrPrepend, ) -> Self { let is_dynamic = match &indexing_code[0] { - IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => { - match v { - IndexingCodePtr::External(_) => false, - IndexingCodePtr::DynamicExternal(_) => true, - _ => unreachable!() - } - } - _ => unreachable!() + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v { + IndexingCodePtr::External(_) => false, + IndexingCodePtr::DynamicExternal(_) => true, + _ => unreachable!(), + }, + _ => unreachable!(), }; Self { skeleton, + retracted_dynamic_clauses, indexing_code, offset: 0, append_or_prepend, @@ -105,15 +102,16 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn internalize_constant(&mut self, constant_ptr: IndexingCodePtr) { let constant_key = search_skeleton_for_first_key_type( self.skeleton, - OptArgIndexKeyType::Constant, + self.retracted_dynamic_clauses, + OptArgIndexKeyType::Literal, self.append_or_prepend, ); let mut constants = IndexMap::new(); match constant_key { - Some(OptArgIndexKey::Constant(_, _, ref constant, _)) => { - constants.insert(constant.clone(), constant_ptr); + Some(OptArgIndexKey::Literal(_, _, constant, _)) => { + constants.insert(*constant, constant_ptr); } _ => { if let IndexingCodePtr::DynamicExternal(_) = constant_ptr { @@ -145,7 +143,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn add_static_indexed_choice_for_constant( &mut self, external: usize, - constant: Constant, + constant: Literal, index: usize, ) { let third_level_index = if self.append_or_prepend.is_append() { @@ -179,7 +177,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn add_dynamic_indexed_choice_for_constant( &mut self, external: usize, - constant: Constant, + constant: Literal, index: usize, ) { let third_level_index = if self.append_or_prepend.is_append() { @@ -232,8 +230,8 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn index_overlapping_constant( &mut self, - orig_constant: &Constant, - overlapping_constant: Constant, + orig_constant: Literal, + overlapping_constant: Literal, index: usize, ) { loop { @@ -252,7 +250,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { } IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => { let mut constants = IndexMap::new(); - constants.insert(orig_constant.clone(), *c); + constants.insert(orig_constant, *c); *c = IndexingCodePtr::Internal(indexing_code_len); @@ -282,10 +280,18 @@ impl<'a> IndexingCodeMergingPtr<'a> { ); } Some(IndexingCodePtr::DynamicExternal(o)) => { - self.add_dynamic_indexed_choice_for_constant(o, overlapping_constant, index); + self.add_dynamic_indexed_choice_for_constant( + o, + overlapping_constant, + index, + ); } Some(IndexingCodePtr::External(o)) => { - self.add_static_indexed_choice_for_constant(o, overlapping_constant, index); + self.add_static_indexed_choice_for_constant( + o, + overlapping_constant, + index, + ); } Some(IndexingCodePtr::Internal(o)) => { self.offset += o; @@ -307,7 +313,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { } } - fn index_constant(&mut self, constant: Constant, index: usize) { + fn index_constant(&mut self, constant: Literal, index: usize) { loop { let indexing_code_len = self.indexing_code.len(); @@ -338,10 +344,16 @@ impl<'a> IndexingCodeMergingPtr<'a> { IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => { match constants.get(&constant).cloned() { None | Some(IndexingCodePtr::Fail) if self.is_dynamic => { - constants.insert(constant, IndexingCodePtr::DynamicExternal(index)); + constants.insert( + constant, + IndexingCodePtr::DynamicExternal(index), + ); } None | Some(IndexingCodePtr::Fail) => { - constants.insert(constant, IndexingCodePtr::External(index)); + constants.insert( + constant, + IndexingCodePtr::External(index), + ); } Some(IndexingCodePtr::DynamicExternal(o)) => { self.add_dynamic_indexed_choice_for_constant(o, constant, index); @@ -372,6 +384,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { fn internalize_structure(&mut self, structure_ptr: IndexingCodePtr) { let structure_key = search_skeleton_for_first_key_type( self.skeleton, + self.retracted_dynamic_clauses, OptArgIndexKeyType::Structure, self.append_or_prepend, ); @@ -379,8 +392,8 @@ impl<'a> IndexingCodeMergingPtr<'a> { let mut structures = IndexMap::new(); match structure_key { - Some(OptArgIndexKey::Structure(_, _, ref name, ref arity)) => { - structures.insert((name.clone(), *arity), structure_ptr); + Some(OptArgIndexKey::Structure(_, _, name, arity)) => { + structures.insert((*name, *arity), structure_ptr); } _ => { if let IndexingCodePtr::DynamicExternal(_) = structure_ptr { @@ -428,8 +441,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { }; let indexing_code_len = self.indexing_code.len(); - self.indexing_code - .push(IndexingLine::IndexedChoice(third_level_index)); + self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index)); match &mut self.indexing_code[self.offset] { IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => { @@ -599,6 +611,7 @@ impl<'a> IndexingCodeMergingPtr<'a> { pub(crate) fn merge_clause_index( target_indexing_code: &mut Vec, skeleton: &mut [ClauseIndexInfo], // the clause to be merged is the last element in the skeleton. + retracted_clauses: &Option>, new_clause_loc: usize, // the absolute location of the new clause in the code vector. append_or_prepend: AppendOrPrepend, ) { @@ -609,27 +622,28 @@ pub(crate) fn merge_clause_index( let mut merging_ptr = IndexingCodeMergingPtr::new( skeleton, + retracted_clauses, target_indexing_code, append_or_prepend, ); match &opt_arg_index_key { - OptArgIndexKey::Constant(_, index_loc, ref constant, ref overlapping_constants) => { + OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => { let offset = new_clause_loc - index_loc + 1; - merging_ptr.index_constant(constant.clone(), offset); + merging_ptr.index_constant(*constant, offset); for overlapping_constant in overlapping_constants { merging_ptr.offset = 0; merging_ptr.index_overlapping_constant( - constant, - overlapping_constant.clone(), + *constant, + *overlapping_constant, offset, ); } } - OptArgIndexKey::Structure(_, index_loc, ref name, ref arity) => { - merging_ptr.index_structure((name.clone(), *arity), new_clause_loc - index_loc + 1); + OptArgIndexKey::Structure(_, index_loc, name, arity) => { + merging_ptr.index_structure((*name, *arity), new_clause_loc - index_loc + 1); } OptArgIndexKey::List(_, index_loc) => { merging_ptr.index_list(new_clause_loc - index_loc + 1); @@ -650,13 +664,13 @@ pub(crate) fn merge_clause_index( } pub(crate) fn remove_constant_indices( - constant: &Constant, - overlapping_constants: &[Constant], + constant: Literal, + overlapping_constants: &[Literal], indexing_code: &mut Vec, offset: usize, ) { let mut index = 0; - let iter = once(constant).chain(overlapping_constants.iter()); + let iter = once(&constant).chain(overlapping_constants.iter()); match &mut indexing_code[index] { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => { @@ -688,11 +702,13 @@ pub(crate) fn remove_constant_indices( )) => { constants_index = index; - match constants.get(constant).cloned() { - Some(IndexingCodePtr::DynamicExternal(_)) | - Some(IndexingCodePtr::External(_)) | - Some(IndexingCodePtr::Fail) => { - constants.remove(constant); + let constant = *constant; + + match constants.get(&constant).cloned() { + Some(IndexingCodePtr::DynamicExternal(_)) + | Some(IndexingCodePtr::External(_)) + | Some(IndexingCodePtr::Fail) => { + constants.remove(&constant); break; } Some(IndexingCodePtr::Internal(o)) => { @@ -704,13 +720,14 @@ pub(crate) fn remove_constant_indices( } } IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { - StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); + StaticCodeIndices::remove_instruction_with_offset( + indexed_choice_instrs, + offset, + ); if indexed_choice_instrs.len() == 1 { if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { - let ext = IndexingCodePtr::External( - indexed_choice_instr.offset() - ); + let ext = IndexingCodePtr::External(indexed_choice_instr.offset()); match &mut indexing_code[constants_index] { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( @@ -724,7 +741,7 @@ pub(crate) fn remove_constant_indices( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( ref mut constants, )) => { - constants.insert(constant.clone(), ext); + constants.insert(*constant, ext); } _ => { unreachable!() @@ -736,7 +753,10 @@ pub(crate) fn remove_constant_indices( break; } IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => { - DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset); + DynamicCodeIndices::remove_instruction_with_offset( + indexed_choice_instrs, + offset, + ); if indexed_choice_instrs.len() == 1 { if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() { @@ -754,7 +774,7 @@ pub(crate) fn remove_constant_indices( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( ref mut constants, )) => { - constants.insert(constant.clone(), ext); + constants.insert(*constant, ext); } _ => { unreachable!() @@ -790,7 +810,7 @@ pub(crate) fn remove_constant_indices( } pub(crate) fn remove_structure_index( - name: &ClauseName, + name: Atom, arity: usize, indexing_code: &mut Vec, offset: usize, @@ -825,7 +845,8 @@ pub(crate) fn remove_structure_index( structures_index = index; match structures.get(&(name.clone(), arity)).cloned() { - Some(IndexingCodePtr::DynamicExternal(_)) | Some(IndexingCodePtr::External(_)) => { + Some(IndexingCodePtr::DynamicExternal(_)) + | Some(IndexingCodePtr::External(_)) => { structures.remove(&(name.clone(), arity)); break; } @@ -1012,27 +1033,14 @@ pub(crate) fn remove_index( clause_loc: usize, ) { match opt_arg_index_key { - OptArgIndexKey::Constant(_, _, ref constant, ref overlapping_constants) => { - remove_constant_indices( - constant, - overlapping_constants, - indexing_code, - clause_loc, - ); - } - OptArgIndexKey::Structure(_, _, ref name, ref arity) => { - remove_structure_index( - name, - *arity, - indexing_code, - clause_loc, - ); + OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => { + remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc); + } + OptArgIndexKey::Structure(_, _, name, arity) => { + remove_structure_index(*name, *arity, indexing_code, clause_loc); } OptArgIndexKey::List(..) => { - remove_list_index( - indexing_code, - clause_loc, - ); + remove_list_index(indexing_code, clause_loc); } OptArgIndexKey::None => { unreachable!() @@ -1076,49 +1084,52 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) { }); } -pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledData) -> Vec { +pub(crate) fn constant_key_alternatives( + constant: Literal, + atom_tbl: &mut AtomTable, + // arena: &mut Arena, +) -> Vec { let mut constants = vec![]; match constant { - Constant::Atom(ref name, ref op) => { - if name.is_char() { - let c = name.as_str().chars().next().unwrap(); - constants.push(Constant::Char(c)); - } - - if op.is_some() { - constants.push(Constant::Atom(name.clone(), None)); + Literal::Atom(ref name) => { + if let Some(c) = name.as_char() { + constants.push(Literal::Char(c)); } } - Constant::Char(c) => { - let atom = clause_name!(c.to_string(), atom_tbl); - constants.push(Constant::Atom(atom, None)); + Literal::Char(c) => { + let atom = atom_tbl.build_with(&c.to_string()); + constants.push(Literal::Atom(atom)); } - Constant::Fixnum(ref n) => { - constants.push(Constant::Integer(Rc::new(Integer::from(*n)))); + /* + Literal::Fixnum(ref n) => { + constants.push(Literal::Integer(arena_alloc!(n, arena))); //Rc::new(Integer::from(*n)))); + /* if *n >= 0 { if let Ok(n) = usize::try_from(*n) { - constants.push(Constant::Usize(n)); + constants.push(Literal::Usize(n)); } } + */ } - Constant::Integer(ref n) => { + */ + Literal::Integer(ref n) => { if let Some(n) = n.to_isize() { - constants.push(Constant::Fixnum(n)); - } - - if let Some(n) = n.to_usize() { - constants.push(Constant::Usize(n)); + Fixnum::build_with_checked(n as i64).map(|n| { + constants.push(Literal::Fixnum(n)); + }).unwrap(); } } - Constant::Usize(n) => { - constants.push(Constant::Integer(Rc::new(Integer::from(*n)))); + /* + Literal::Usize(n) => { + constants.push(Literal::Integer(Rc::new(Integer::from(*n)))); if let Ok(n) = isize::try_from(*n) { - constants.push(Constant::Fixnum(n)); + constants.push(Literal::Fixnum(n)); } } + */ _ => {} } @@ -1127,16 +1138,16 @@ pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledDat #[derive(Debug)] pub(crate) struct StaticCodeIndices { - constants: IndexMap>, + constants: IndexMap>, lists: SliceDeque, - structures: IndexMap<(ClauseName, usize), SliceDeque>, + structures: IndexMap<(Atom, usize), SliceDeque>, } #[derive(Debug)] pub(crate) struct DynamicCodeIndices { - constants: IndexMap>, + constants: IndexMap>, lists: SliceDeque, - structures: IndexMap<(ClauseName, usize), SliceDeque>, + structures: IndexMap<(Atom, usize), SliceDeque>, } pub(crate) trait Indexer { @@ -1144,9 +1155,9 @@ pub(crate) trait Indexer { fn new() -> Self; - fn constants(&mut self) -> &mut IndexMap>; + fn constants(&mut self) -> &mut IndexMap>; fn lists(&mut self) -> &mut SliceDeque; - fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque>; + fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque>; fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex; @@ -1166,10 +1177,7 @@ pub(crate) trait Indexer { prelude: &mut SliceDeque, ) -> IndexingCodePtr; - fn remove_instruction_with_offset( - code: &mut SliceDeque, - offset: usize, - ); + fn remove_instruction_with_offset(code: &mut SliceDeque, offset: usize); fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr; } @@ -1187,7 +1195,7 @@ impl Indexer for StaticCodeIndices { } #[inline] - fn constants(&mut self) -> &mut IndexMap> { + fn constants(&mut self) -> &mut IndexMap> { &mut self.constants } @@ -1197,7 +1205,7 @@ impl Indexer for StaticCodeIndices { } #[inline] - fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque> { + fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque> { &mut self.structures } @@ -1271,7 +1279,10 @@ impl Indexer for StaticCodeIndices { } #[inline] - fn remove_instruction_with_offset(code: &mut SliceDeque, offset: usize) { + fn remove_instruction_with_offset( + code: &mut SliceDeque, + offset: usize, + ) { for (index, line) in code.iter().enumerate() { if offset == line.offset() { code.remove(index); @@ -1300,7 +1311,7 @@ impl Indexer for DynamicCodeIndices { } #[inline] - fn constants(&mut self) -> &mut IndexMap> { + fn constants(&mut self) -> &mut IndexMap> { &mut self.constants } @@ -1310,7 +1321,7 @@ impl Indexer for DynamicCodeIndices { } #[inline] - fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque> { + fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque> { &mut self.structures } @@ -1395,19 +1406,13 @@ impl Indexer for DynamicCodeIndices { #[derive(Debug)] pub(crate) struct CodeOffsets { - atom_tbl: TabledData, indices: I, optimal_index: usize, } impl CodeOffsets { - pub(crate) fn new( - atom_tbl: TabledData, - indices: I, - optimal_index: usize, - ) -> Self { + pub(crate) fn new(indices: I, optimal_index: usize) -> Self { CodeOffsets { - atom_tbl, indices, optimal_index, } @@ -1419,15 +1424,24 @@ impl CodeOffsets { self.indices.lists().push_back(index); } - fn index_constant(&mut self, constant: &Constant, index: usize) -> Vec { - let overlapping_constants = constant_key_alternatives(constant, self.atom_tbl.clone()); - let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]); + fn index_constant( + &mut self, + atom_tbl: &mut AtomTable, + constant: Literal, + index: usize, + ) -> Vec { + let overlapping_constants = constant_key_alternatives(constant, atom_tbl); + let code = self.indices.constants().entry(constant).or_insert(sdeq![]); let is_initial_index = code.is_empty(); code.push_back(I::compute_index(is_initial_index, index)); for constant in &overlapping_constants { - let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]); + let code = self + .indices + .constants() + .entry(*constant) + .or_insert(sdeq![]); let is_initial_index = code.is_empty(); let index = I::compute_index(is_initial_index, index); @@ -1438,8 +1452,9 @@ impl CodeOffsets { overlapping_constants } - fn index_structure(&mut self, name: &ClauseName, arity: usize, index: usize) -> usize { - let code = self.indices + fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize { + let code = self + .indices .structures() .entry((name.clone(), arity)) .or_insert(sdeq![]); @@ -1456,28 +1471,25 @@ impl CodeOffsets { optimal_arg: &Term, index: usize, clause_index_info: &mut ClauseIndexInfo, + atom_tbl: &mut AtomTable, ) { match optimal_arg { - &Term::Clause(_, ref name, ref terms, _) => { + &Term::Clause(_, name, ref terms) => { clause_index_info.opt_arg_index_key = OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len()); self.index_structure(name, terms.len(), index); } - &Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => { + &Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => { clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); self.index_list(index); } - &Term::Constant(_, ref constant) => { - let overlapping_constants = self.index_constant(constant, index); - - clause_index_info.opt_arg_index_key = OptArgIndexKey::Constant( - self.optimal_index, - 0, - constant.clone(), - overlapping_constants, - ); + &Term::Literal(_, constant) => { + let overlapping_constants = self.index_constant(atom_tbl, constant, index); + + clause_index_info.opt_arg_index_key = + OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants); } _ => {} } diff --git a/src/instructions.rs b/src/instructions.rs index 90cbeeab..76c9c76c 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -1,46 +1,42 @@ -use prolog_parser::ast::*; -use prolog_parser::clause_name; +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; use crate::clause_types::*; use crate::forms::*; -use crate::indexing::IndexingCodePtr; +use crate::types::*; use crate::machine::heap::*; use crate::machine::machine_errors::MachineStub; -use crate::machine::machine_indices::*; -use crate::rug::Integer; use indexmap::IndexMap; - use slice_deque::SliceDeque; -use std::rc::Rc; - fn reg_type_into_functor(r: RegType) -> MachineStub { match r { - RegType::Temp(r) => functor!("x", [integer(r)]), - RegType::Perm(r) => functor!("y", [integer(r)]), + RegType::Temp(r) => functor!(atom!("x"), [fixnum(r)]), + RegType::Perm(r) => functor!(atom!("y"), [fixnum(r)]), } } impl Level { fn into_functor(self) -> MachineStub { match self { - Level::Root => functor!("level", [atom("root")]), - Level::Shallow => functor!("level", [atom("shallow")]), - Level::Deep => functor!("level", [atom("deep")]), + Level::Root => functor!(atom!("level"), [atom(atom!("root"))]), + Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]), + Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]), } } } impl ArithmeticTerm { - fn into_functor(&self) -> MachineStub { + fn into_functor(&self, arena: &mut Arena) -> MachineStub { match self { &ArithmeticTerm::Reg(r) => reg_type_into_functor(r), &ArithmeticTerm::Interm(i) => { - functor!("intermediate", [integer(i)]) + functor!(atom!("intermediate"), [fixnum(i)]) } - &ArithmeticTerm::Number(ref n) => { - vec![n.clone().into()] + &ArithmeticTerm::Number(n) => { + vec![HeapCellValue::from((n, arena))] } } } @@ -87,33 +83,30 @@ impl ChoiceInstruction { match (death, next_or_fail) { (Death::Infinity, NextOrFail::Next(i)) => { functor!( - "dynamic_else", - [integer(birth), atom("inf"), integer(i)] + atom!("dynamic_else"), + [fixnum(birth), atom(atom!("inf")), fixnum(i)] ) } (Death::Infinity, NextOrFail::Fail(i)) => { - let next_functor = functor!("fail", [integer(i)]); + let next_functor = functor!(atom!("fail"), [fixnum(i)]); functor!( - "dynamic_else", - [integer(birth), atom("inf"), aux(h, 0)], + atom!("dynamic_else"), + [fixnum(birth), atom(atom!("inf")), str(h, 0)], [next_functor] ) } (Death::Finite(d), NextOrFail::Fail(i)) => { - let next_functor = functor!("fail", [integer(i)]); + let next_functor = functor!(atom!("fail"), [fixnum(i)]); functor!( - "dynamic_else", - [integer(birth), integer(d), aux(h, 0)], + atom!("dynamic_else"), + [fixnum(birth), fixnum(d), str(h, 0)], [next_functor] ) } (Death::Finite(d), NextOrFail::Next(i)) => { - functor!( - "dynamic_else", - [integer(birth), integer(d), integer(i)] - ) + functor!(atom!("dynamic_else"), [fixnum(birth), fixnum(d), fixnum(i)]) } } } @@ -121,50 +114,50 @@ impl ChoiceInstruction { match (death, next_or_fail) { (Death::Infinity, NextOrFail::Next(i)) => { functor!( - "dynamic_internal_else", - [integer(birth), atom("inf"), integer(i)] + atom!("dynamic_internal_else"), + [fixnum(birth), atom(atom!("inf")), fixnum(i)] ) } (Death::Infinity, NextOrFail::Fail(i)) => { - let next_functor = functor!("fail", [integer(i)]); + let next_functor = functor!(atom!("fail"), [fixnum(i)]); functor!( - "dynamic_internal_else", - [integer(birth), atom("inf"), aux(h, 0)], + atom!("dynamic_internal_else"), + [fixnum(birth), atom(atom!("inf")), str(h, 0)], [next_functor] ) } (Death::Finite(d), NextOrFail::Fail(i)) => { - let next_functor = functor!("fail", [integer(i)]); + let next_functor = functor!(atom!("fail"), [fixnum(i)]); functor!( - "dynamic_internal_else", - [integer(birth), integer(d), aux(h, 0)], + atom!("dynamic_internal_else"), + [fixnum(birth), fixnum(d), str(h, 0)], [next_functor] ) } (Death::Finite(d), NextOrFail::Next(i)) => { functor!( - "dynamic_internal_else", - [integer(birth), integer(d), integer(i)] + atom!("dynamic_internal_else"), + [fixnum(birth), fixnum(d), fixnum(i)] ) } } } &ChoiceInstruction::TryMeElse(offset) => { - functor!("try_me_else", [integer(offset)]) + functor!(atom!("try_me_else"), [fixnum(offset)]) } &ChoiceInstruction::RetryMeElse(offset) => { - functor!("retry_me_else", [integer(offset)]) + functor!(atom!("retry_me_else"), [fixnum(offset)]) } &ChoiceInstruction::TrustMe(offset) => { - functor!("trust_me", [integer(offset)]) + functor!(atom!("trust_me"), [fixnum(offset)]) } &ChoiceInstruction::DefaultRetryMeElse(offset) => { - functor!("default_retry_me_else", [integer(offset)]) + functor!(atom!("default_retry_me_else"), [fixnum(offset)]) } &ChoiceInstruction::DefaultTrustMe(offset) => { - functor!("default_trust_me", [integer(offset)]) + functor!(atom!("default_trust_me"), [fixnum(offset)]) } } } @@ -183,18 +176,18 @@ impl CutInstruction { match self { &CutInstruction::Cut(r) => { let rt_stub = reg_type_into_functor(r); - functor!("cut", [aux(h, 0)], [rt_stub]) + functor!(atom!("cut"), [str(h, 0)], [rt_stub]) } &CutInstruction::GetLevel(r) => { let rt_stub = reg_type_into_functor(r); - functor!("get_level", [aux(h, 0)], [rt_stub]) + functor!(atom!("get_level"), [str(h, 0)], [rt_stub]) } &CutInstruction::GetLevelAndUnify(r) => { let rt_stub = reg_type_into_functor(r); - functor!("get_level_and_unify", [aux(h, 0)], [rt_stub]) + functor!(atom!("get_level_and_unify"), [str(h, 0)], [rt_stub]) } &CutInstruction::NeckCut => { - functor!("neck_cut") + functor!(atom!("neck_cut")) } } } @@ -219,13 +212,13 @@ impl IndexedChoiceInstruction { pub(crate) fn to_functor(&self) -> MachineStub { match self { &IndexedChoiceInstruction::Try(offset) => { - functor!("try", [integer(offset)]) + functor!(atom!("try"), [fixnum(offset)]) } &IndexedChoiceInstruction::Trust(offset) => { - functor!("trust", [integer(offset)]) + functor!(atom!("trust"), [fixnum(offset)]) } &IndexedChoiceInstruction::Retry(offset) => { - functor!("retry", [integer(offset)]) + functor!(atom!("retry"), [fixnum(offset)]) } } } @@ -276,9 +269,16 @@ impl Line { } } - pub(crate) fn enqueue_functors(&self, mut h: usize, functors: &mut Vec) { + pub(crate) fn enqueue_functors( + &self, + mut h: usize, + arena: &mut Arena, + functors: &mut Vec, + ) { match self { - &Line::Arithmetic(ref arith_instr) => functors.push(arith_instr.to_functor(h)), + &Line::Arithmetic(ref arith_instr) => { + functors.push(arith_instr.to_functor(h, arena)) + } &Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor(h)), &Line::Control(ref control_instr) => functors.push(control_instr.to_functor()), &Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)), @@ -300,7 +300,11 @@ impl Line { } IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => { for indexed_choice_instr in indexed_choice_instrs { - let section = functor!("dynamic", [integer(*indexed_choice_instr)]); + let section = functor!( + atom!("dynamic"), + [fixnum(*indexed_choice_instr)] + ); + h += section.len(); functors.push(section); } @@ -312,7 +316,7 @@ impl Line { functors.push(indexed_choice_instr.to_functor()) } &Line::DynamicIndexedChoice(ref indexed_choice_instr) => { - functors.push(functor!("dynamic", [integer(*indexed_choice_instr)])); + functors.push(functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)])); } &Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)), } @@ -336,7 +340,7 @@ pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec> { } #[derive(Debug, Clone)] -pub(crate) enum ArithmeticInstruction { +pub enum ArithmeticInstruction { Add(ArithmeticTerm, ArithmeticTerm, usize), Sub(ArithmeticTerm, ArithmeticTerm, usize), Mul(ArithmeticTerm, ArithmeticTerm, usize), @@ -380,132 +384,175 @@ pub(crate) enum ArithmeticInstruction { fn arith_instr_unary_functor( h: usize, - name: &'static str, + name: Atom, + arena: &mut Arena, at: &ArithmeticTerm, t: usize, ) -> MachineStub { - let at_stub = at.into_functor(); - - functor!(name, [aux(h, 0), integer(t)], [at_stub]) + let at_stub = at.into_functor(arena); + functor!(name, [str(h, 0), fixnum(t)], [at_stub]) } fn arith_instr_bin_functor( h: usize, - name: &'static str, + name: Atom, + arena: &mut Arena, at_1: &ArithmeticTerm, at_2: &ArithmeticTerm, t: usize, ) -> MachineStub { - let at_1_stub = at_1.into_functor(); - let at_2_stub = at_2.into_functor(); + let at_1_stub = at_1.into_functor(arena); + let at_2_stub = at_2.into_functor(arena); functor!( name, - [aux(h, 0), aux(h, 1), integer(t)], + [str(h, 0), str(h, 1), fixnum(t)], [at_1_stub, at_2_stub] ) } impl ArithmeticInstruction { - pub(crate) fn to_functor(&self, h: usize) -> MachineStub { + pub(crate) fn to_functor( + &self, + h: usize, + arena: &mut Arena, + ) -> MachineStub { match self { &ArithmeticInstruction::Add(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "add", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("add"), arena, at_1, at_2, t) } &ArithmeticInstruction::Sub(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "sub", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("sub"), arena, at_1, at_2, t) } &ArithmeticInstruction::Mul(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "mul", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("mul"), arena, at_1, at_2, t) } &ArithmeticInstruction::IntPow(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "int_pow", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("int_pow"), arena, at_1, at_2, t) } &ArithmeticInstruction::Pow(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "pow", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("pow"), arena, at_1, at_2, t) } &ArithmeticInstruction::IDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "idiv", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("idiv"), arena, at_1, at_2, t) } &ArithmeticInstruction::Max(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "max", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("max"), arena, at_1, at_2, t) } &ArithmeticInstruction::Min(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "min", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("min"), arena, at_1, at_2, t) } &ArithmeticInstruction::IntFloorDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "int_floor_div", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("int_floor_div"), arena, at_1, at_2, t) } &ArithmeticInstruction::RDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "rdiv", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("rdiv"), arena, at_1, at_2, t) } &ArithmeticInstruction::Div(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "div", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("div"), arena, at_1, at_2, t) } &ArithmeticInstruction::Shl(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "shl", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("shl"), arena, at_1, at_2, t) } &ArithmeticInstruction::Shr(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "shr", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("shr"), arena, at_1, at_2, t) } &ArithmeticInstruction::Xor(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "xor", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("xor"), arena, at_1, at_2, t) } &ArithmeticInstruction::And(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "and", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("and"), arena, at_1, at_2, t) } &ArithmeticInstruction::Or(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "or", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("or"), arena, at_1, at_2, t) } &ArithmeticInstruction::Mod(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "mod", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("mod"), arena, at_1, at_2, t) } &ArithmeticInstruction::Rem(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "rem", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t) } &ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "rem", at_1, at_2, t) + arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t) } &ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, "gcd", at_1, at_2, t) - } - &ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t), - &ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t), - &ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t), - &ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t), - &ArithmeticInstruction::Log(ref at, t) => arith_instr_unary_functor(h, "log", at, t), - &ArithmeticInstruction::Exp(ref at, t) => arith_instr_unary_functor(h, "exp", at, t), - &ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t), - &ArithmeticInstruction::ASin(ref at, t) => arith_instr_unary_functor(h, "asin", at, t), - &ArithmeticInstruction::ATan(ref at, t) => arith_instr_unary_functor(h, "atan", at, t), - &ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t), - &ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", at, t), + arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t) + } + &ArithmeticInstruction::Sign(ref at, t) => { + arith_instr_unary_functor(h, atom!("sign"), arena, at, t) + } + &ArithmeticInstruction::Cos(ref at, t) => { + arith_instr_unary_functor(h, atom!("cos"), arena, at, t) + } + &ArithmeticInstruction::Sin(ref at, t) => { + arith_instr_unary_functor(h, atom!("sin"), arena, at, t) + } + &ArithmeticInstruction::Tan(ref at, t) => { + arith_instr_unary_functor(h, atom!("tan"), arena, at, t) + } + &ArithmeticInstruction::Log(ref at, t) => { + arith_instr_unary_functor(h, atom!("log"), arena, at, t) + } + &ArithmeticInstruction::Exp(ref at, t) => { + arith_instr_unary_functor(h, atom!("exp"), arena, at, t) + } + &ArithmeticInstruction::ACos(ref at, t) => { + arith_instr_unary_functor(h, atom!("acos"), arena, at, t) + } + &ArithmeticInstruction::ASin(ref at, t) => { + arith_instr_unary_functor(h, atom!("asin"), arena, at, t) + } + &ArithmeticInstruction::ATan(ref at, t) => { + arith_instr_unary_functor(h, atom!("atan"), arena, at, t) + } + &ArithmeticInstruction::Sqrt(ref at, t) => { + arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t) + } + &ArithmeticInstruction::Abs(ref at, t) => { + arith_instr_unary_functor(h, atom!("abs"), arena, at, t) + } &ArithmeticInstruction::Float(ref at, t) => { - arith_instr_unary_functor(h, "float", at, t) + arith_instr_unary_functor(h, atom!("float"), arena, at, t) } &ArithmeticInstruction::Truncate(ref at, t) => { - arith_instr_unary_functor(h, "truncate", at, t) + arith_instr_unary_functor(h, atom!("truncate"), arena, at, t) } &ArithmeticInstruction::Round(ref at, t) => { - arith_instr_unary_functor(h, "round", at, t) + arith_instr_unary_functor(h, atom!("round"), arena, at, t) } &ArithmeticInstruction::Ceiling(ref at, t) => { - arith_instr_unary_functor(h, "ceiling", at, t) + arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t) } &ArithmeticInstruction::Floor(ref at, t) => { - arith_instr_unary_functor(h, "floor", at, t) - } - &ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t), - &ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(h, "+", at, t), - &ArithmeticInstruction::BitwiseComplement(ref at, t) => { - arith_instr_unary_functor(h, "\\", at, t) - } + arith_instr_unary_functor(h, atom!("floor"), arena, at, t) + } + &ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor( + h, + atom!("-"), + arena, + at, + t, + ), + &ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor( + h, + atom!("+"), + arena, + at, + t, + ), + &ArithmeticInstruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor( + h, + atom!("\\"), + arena, + at, + t, + ), } } } #[derive(Debug)] -pub(crate) enum ControlInstruction { +pub enum ControlInstruction { Allocate(usize), // num_frames. // name, arity, perm_vars after threshold, last call, use default call policy. CallClause(ClauseType, usize, usize, bool, bool), @@ -529,25 +576,25 @@ impl ControlInstruction { pub(crate) fn to_functor(&self) -> MachineStub { match self { &ControlInstruction::Allocate(num_frames) => { - functor!("allocate", [integer(num_frames)]) + functor!(atom!("allocate"), [fixnum(num_frames)]) } &ControlInstruction::CallClause(ref ct, arity, _, false, _) => { - functor!("call", [clause_name(ct.name()), integer(arity)]) + functor!(atom!("call"), [atom(ct.name()), fixnum(arity)]) } &ControlInstruction::CallClause(ref ct, arity, _, true, _) => { - functor!("execute", [clause_name(ct.name()), integer(arity)]) + functor!(atom!("execute"), [atom(ct.name()), fixnum(arity)]) } &ControlInstruction::Deallocate => { - functor!("deallocate") + functor!(atom!("deallocate")) } &ControlInstruction::JmpBy(_, offset, ..) => { - functor!("jmp_by", [integer(offset)]) + functor!(atom!("jmp_by"), [fixnum(offset)]) } &ControlInstruction::RevJmpBy(offset) => { - functor!("rev_jmp_by", [integer(offset)]) + functor!(atom!("rev_jmp_by"), [fixnum(offset)]) } &ControlInstruction::Proceed => { - functor!("proceed") + functor!(atom!("proceed")) } } } @@ -564,8 +611,22 @@ pub(crate) enum IndexingInstruction { IndexingCodePtr, IndexingCodePtr, ), - SwitchOnConstant(IndexMap), - SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>), + SwitchOnConstant(IndexMap), + SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>), +} + +impl IndexingCodePtr { + #[allow(dead_code)] + pub(crate) fn to_functor(self) -> MachineStub { + match self { + IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]), + IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]), + IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]), + IndexingCodePtr::Fail => { + vec![atom_as_cell!(atom!("fail"))] + }, + } + } } impl IndexingInstruction { @@ -573,9 +634,9 @@ impl IndexingInstruction { match self { &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => { functor!( - "switch_on_term", + atom!("switch_on_term"), [ - integer(arg), + fixnum(arg), indexing_code_ptr(h, vars), indexing_code_ptr(h, constants), indexing_code_ptr(h, lists), @@ -591,26 +652,23 @@ impl IndexingInstruction { for (c, ptr) in constants.iter() { let key_value_pair = functor!( - ":", - SharedOpDesc::new(600, XFY), - [constant(c), indexing_code_ptr(h + 3, *ptr)] + atom!(":"), + [literal(*c), indexing_code_ptr(h + 3, *ptr)] ); - key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1))); - key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3))); - key_value_list_stub.push(HeapCellValue::Addr(Addr::HeapCell( - h + 3 + key_value_pair.len(), - ))); + key_value_list_stub.push(list_loc_as_cell!(h + 1)); + key_value_list_stub.push(str_loc_as_cell!(h + 3)); + key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len())); h += key_value_pair.len() + 3; key_value_list_stub.extend(key_value_pair.into_iter()); } - key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList)); + key_value_list_stub.push(empty_list_as_cell!()); functor!( - "switch_on_constant", - [aux(orig_h, 0)], + atom!("switch_on_constant"), + [str(orig_h, 0)], [key_value_list_stub] ) } @@ -622,33 +680,29 @@ impl IndexingInstruction { for ((name, arity), ptr) in structures.iter() { let predicate_indicator_stub = functor!( - "/", - SharedOpDesc::new(400, YFX), - [clause_name(name.clone()), integer(*arity)] + atom!("/"), + [atom(name), fixnum(*arity)] ); let key_value_pair = functor!( - ":", - SharedOpDesc::new(600, XFY), - [aux(h + 3, 0), indexing_code_ptr(h + 3, *ptr)], + atom!(":"), + [str(h + 3, 0), indexing_code_ptr(h + 3, *ptr)], [predicate_indicator_stub] ); - key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1))); - key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3))); - key_value_list_stub.push(HeapCellValue::Addr(Addr::HeapCell( - h + 3 + key_value_pair.len(), - ))); + key_value_list_stub.push(list_loc_as_cell!(h + 1)); + key_value_list_stub.push(str_loc_as_cell!(h + 3)); + key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len())); h += key_value_pair.len() + 3; key_value_list_stub.extend(key_value_pair.into_iter()); } - key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList)); + key_value_list_stub.push(empty_list_as_cell!()); functor!( - "switch_on_structure", - [aux(orig_h, 0)], + atom!("switch_on_structure"), + [str(orig_h, 0)], [key_value_list_stub] ) } @@ -657,14 +711,14 @@ impl IndexingInstruction { } #[derive(Debug, Clone)] -pub(crate) enum FactInstruction { - GetConstant(Level, Constant, RegType), +pub enum FactInstruction { + GetConstant(Level, HeapCellValue, RegType), GetList(Level, RegType), - GetPartialString(Level, String, RegType, bool), + GetPartialString(Level, Atom, RegType, bool), GetStructure(ClauseType, usize, RegType), GetValue(RegType, usize), GetVariable(RegType, usize), - UnifyConstant(Constant), + UnifyConstant(HeapCellValue), UnifyLocalValue(RegType), UnifyVariable(RegType), UnifyValue(RegType), @@ -674,13 +728,13 @@ pub(crate) enum FactInstruction { impl FactInstruction { pub(crate) fn to_functor(&self, h: usize) -> MachineStub { match self { - &FactInstruction::GetConstant(lvl, ref c, r) => { + &FactInstruction::GetConstant(lvl, c, r) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); functor!( - "get_constant", - [aux(h, 0), constant(h, c), aux(h, 1)], + atom!("get_constant"), + [str(h, 0), cell(c), str(h, 1)], [lvl_stub, rt_stub] ) } @@ -688,15 +742,24 @@ impl FactInstruction { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!("get_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub]) + functor!( + atom!("get_list"), + [str(h, 0), str(h, 1)], + [lvl_stub, rt_stub] + ) } - &FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => { + &FactInstruction::GetPartialString(lvl, s, r, has_tail) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); functor!( - "get_partial_string", - [aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)], + atom!("get_partial_string"), + [ + str(h, 0), + string(h, s), + str(h, 1), + boolean(has_tail) + ], [lvl_stub, rt_stub] ) } @@ -704,41 +767,41 @@ impl FactInstruction { let rt_stub = reg_type_into_functor(r); functor!( - "get_structure", - [clause_name(ct.name()), integer(arity), aux(h, 0)], + atom!("get_structure"), + [atom(ct.name()), fixnum(arity), str(h, 0)], [rt_stub] ) } &FactInstruction::GetValue(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!("get_value", [aux(h, 0), integer(arg)], [rt_stub]) + functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub]) } &FactInstruction::GetVariable(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub]) + functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) } - &FactInstruction::UnifyConstant(ref c) => { - functor!("unify_constant", [constant(h, c)], []) + &FactInstruction::UnifyConstant(c) => { + functor!(atom!("unify_constant"), [cell(c)]) } &FactInstruction::UnifyLocalValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!("unify_local_value", [aux(h, 0)], [rt_stub]) + functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub]) } &FactInstruction::UnifyVariable(r) => { let rt_stub = reg_type_into_functor(r); - functor!("unify_variable", [aux(h, 0)], [rt_stub]) + functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub]) } &FactInstruction::UnifyValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!("unify_value", [aux(h, 0)], [rt_stub]) + functor!(atom!("unify_value"), [str(h, 0)], [rt_stub]) } &FactInstruction::UnifyVoid(vars) => { - functor!("unify_void", [integer(vars)]) + functor!(atom!("unify_void"), [fixnum(vars)]) } } } @@ -747,14 +810,14 @@ impl FactInstruction { #[derive(Debug, Clone)] pub(crate) enum QueryInstruction { GetVariable(RegType, usize), - PutConstant(Level, Constant, RegType), + PutConstant(Level, HeapCellValue, RegType), PutList(Level, RegType), - PutPartialString(Level, String, RegType, bool), + PutPartialString(Level, Atom, RegType, bool), PutStructure(ClauseType, usize, RegType), PutUnsafeValue(usize, usize), PutValue(RegType, usize), PutVariable(RegType, usize), - SetConstant(Constant), + SetConstant(HeapCellValue), SetLocalValue(RegType), SetVariable(RegType), SetValue(RegType), @@ -765,15 +828,15 @@ impl QueryInstruction { pub(crate) fn to_functor(&self, h: usize) -> MachineStub { match self { &QueryInstruction::PutUnsafeValue(norm, arg) => { - functor!("put_unsafe_value", [integer(norm), integer(arg)]) + functor!(atom!("put_unsafe_value"), [fixnum(norm), fixnum(arg)]) } - &QueryInstruction::PutConstant(lvl, ref c, r) => { + &QueryInstruction::PutConstant(lvl, c, r) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); functor!( - "put_constant", - [aux(h, 0), constant(h, c), aux(h, 1)], + atom!("put_constant"), + [str(h, 0), cell(c), str(h, 1)], [lvl_stub, rt_stub] ) } @@ -781,15 +844,24 @@ impl QueryInstruction { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); - functor!("put_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub]) + functor!( + atom!("put_list"), + [str(h, 0), str(h, 1)], + [lvl_stub, rt_stub] + ) } - &QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => { + &QueryInstruction::PutPartialString(lvl, s, r, has_tail) => { let lvl_stub = lvl.into_functor(); let rt_stub = reg_type_into_functor(r); functor!( - "put_partial_string", - [aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)], + atom!("put_partial_string"), + [ + str(h, 0), + string(h, s), + str(h, 1), + boolean(has_tail) + ], [lvl_stub, rt_stub] ) } @@ -797,46 +869,46 @@ impl QueryInstruction { let rt_stub = reg_type_into_functor(r); functor!( - "put_structure", - [clause_name(ct.name()), integer(arity), aux(h, 0)], + atom!("put_structure"), + [atom(ct.name()), fixnum(arity), str(h, 0)], [rt_stub] ) } &QueryInstruction::PutValue(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!("put_value", [aux(h, 0), integer(arg)], [rt_stub]) + functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub]) } &QueryInstruction::GetVariable(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub]) + functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) } &QueryInstruction::PutVariable(r, arg) => { let rt_stub = reg_type_into_functor(r); - functor!("put_variable", [aux(h, 0), integer(arg)], [rt_stub]) + functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) } - &QueryInstruction::SetConstant(ref c) => { - functor!("set_constant", [constant(h, c)], []) + &QueryInstruction::SetConstant(c) => { + functor!(atom!("set_constant"), [cell(c)], []) } &QueryInstruction::SetLocalValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!("set_local_value", [aux(h, 0)], [rt_stub]) + functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub]) } &QueryInstruction::SetVariable(r) => { let rt_stub = reg_type_into_functor(r); - functor!("set_variable", [aux(h, 0)], [rt_stub]) + functor!(atom!("set_variable"), [str(h, 0)], [rt_stub]) } &QueryInstruction::SetValue(r) => { let rt_stub = reg_type_into_functor(r); - functor!("set_value", [aux(h, 0)], [rt_stub]) + functor!(atom!("set_value"), [str(h, 0)], [rt_stub]) } &QueryInstruction::SetVoid(vars) => { - functor!("set_void", [integer(vars)]) + functor!(atom!("set_void"), [fixnum(vars)]) } } } diff --git a/src/iterators.rs b/src/iterators.rs index a83c5796..3c6e955c 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -1,5 +1,5 @@ -use prolog_parser::ast::*; -use prolog_parser::rc_atom; +use crate::atom_table::*; +use crate::parser::ast::*; use crate::clause_types::*; use crate::forms::*; @@ -16,10 +16,10 @@ use std::vec::Vec; pub(crate) enum TermRef<'a> { AnonVar(Level), Cons(Level, &'a Cell, &'a Term, &'a Term), - Constant(Level, &'a Cell, &'a Constant), - Clause(Level, &'a Cell, ClauseType, &'a Vec>), - PartialString(Level, &'a Cell, String, Option<&'a Term>), - Var(Level, &'a Cell, Rc), + Literal(Level, &'a Cell, &'a Literal), + Clause(Level, &'a Cell, ClauseType, &'a Vec), + PartialString(Level, &'a Cell, Atom, &'a Option>), + Var(Level, &'a Cell, Rc), } impl<'a> TermRef<'a> { @@ -27,7 +27,7 @@ impl<'a> TermRef<'a> { match self { TermRef::AnonVar(lvl) | TermRef::Cons(lvl, ..) - | TermRef::Constant(lvl, ..) + | TermRef::Literal(lvl, ..) | TermRef::Var(lvl, ..) | TermRef::Clause(lvl, ..) => lvl, TermRef::PartialString(lvl, ..) => lvl, @@ -38,82 +38,31 @@ impl<'a> TermRef<'a> { #[derive(Debug)] pub(crate) enum TermIterState<'a> { AnonVar(Level), - Constant(Level, &'a Cell, &'a Constant), - Clause( - Level, - usize, - &'a Cell, - ClauseType, - &'a Vec>, - ), + Literal(Level, &'a Cell, &'a Literal), + Clause(Level, usize, &'a Cell, ClauseType, &'a Vec), InitialCons(Level, &'a Cell, &'a Term, &'a Term), FinalCons(Level, &'a Cell, &'a Term, &'a Term), - PartialString(Level, &'a Cell, String, Option<&'a Term>), - Var(Level, &'a Cell, Rc), -} - -fn is_partial_string<'a>(head: &'a Term, mut tail: &'a Term) -> Option<(String, Option<&'a Term>)> { - let mut string = match head { - &Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => { - atom.as_str().chars().next().unwrap().to_string() - } - &Term::Constant(_, Constant::Char(c)) => c.to_string(), - _ => { - return None; - } - }; - - while let Term::Cons(_, ref head, ref succ) = tail { - match head.as_ref() { - &Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => { - string.push(atom.as_str().chars().next().unwrap()); - } - &Term::Constant(_, Constant::Char(c)) => { - string.push(c); - } - _ => { - return None; - } - }; - - tail = succ.as_ref(); - } - - match tail { - Term::AnonVar | Term::Var(..) => { - return Some((string, Some(tail))); - } - Term::Constant(_, Constant::EmptyList) => { - return Some((string, None)); - } - Term::Constant(_, Constant::String(tail)) => { - string += &tail; - return Some((string, None)); - } - _ => { - return None; - } - } + InitialPartialString(Level, &'a Cell, Atom, &'a Option>), + FinalPartialString(Level, &'a Cell, Atom, &'a Option>), + Var(Level, &'a Cell, Rc), } impl<'a> TermIterState<'a> { pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> { match term { - &Term::AnonVar => TermIterState::AnonVar(lvl), - &Term::Clause(ref cell, ref name, ref subterms, ref spec) => { - let ct = if let Some(spec) = spec { - ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default()) - } else { - ClauseType::Named(name.clone(), subterms.len(), CodeIndex::default()) - }; - + Term::AnonVar => TermIterState::AnonVar(lvl), + Term::Clause(cell, name, subterms) => { + let ct = ClauseType::Named(name.clone(), subterms.len(), CodeIndex::default()); TermIterState::Clause(lvl, 0, cell, ct, subterms) } - &Term::Cons(ref cell, ref head, ref tail) => { + Term::Cons(cell, head, tail) => { TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref()) } - &Term::Constant(ref cell, ref constant) => TermIterState::Constant(lvl, cell, constant), - &Term::Var(ref cell, ref var) => TermIterState::Var(lvl, cell, var.clone()), + Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant), + Term::PartialString(cell, string_buf, tail) => { + TermIterState::InitialPartialString(lvl, cell, *string_buf, tail) + } + Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()), } } } @@ -129,11 +78,11 @@ impl<'a> QueryIterator<'a> { .push(TermIterState::subterm_to_state(lvl, term)); } - fn from_rule_head_clause(terms: &'a Vec>) -> Self { + fn from_rule_head_clause(terms: &'a Vec) -> Self { let state_stack = terms .iter() .rev() - .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref())) + .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt)) .collect(); QueryIterator { state_stack } @@ -141,29 +90,19 @@ impl<'a> QueryIterator<'a> { fn from_term(term: &'a Term) -> Self { let state = match term { - &Term::AnonVar => { + Term::AnonVar | Term::Cons(..) | Term::Literal(..) | Term::PartialString(..) => { return QueryIterator { state_stack: vec![], } } - &Term::Clause(ref r, ref name, ref terms, ref fixity) => TermIterState::Clause( + Term::Clause(r, name, terms) => TermIterState::Clause( Level::Root, 0, r, - ClauseType::from(name.clone(), terms.len(), fixity.clone()), + ClauseType::from(*name, terms.len()), terms, ), - &Term::Cons(..) => { - return QueryIterator { - state_stack: vec![], - } - } - &Term::Constant(_, _) => { - return QueryIterator { - state_stack: vec![], - } - } - &Term::Var(ref cell, ref var) => TermIterState::Var(Level::Root, cell, (*var).clone()), + Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()), }; QueryIterator { @@ -186,7 +125,7 @@ impl<'a> QueryIterator<'a> { } } &QueryTerm::UnblockedCut(ref cell) => { - let state = TermIterState::Var(Level::Root, cell, rc_atom!("!")); + let state = TermIterState::Var(Level::Root, cell, Rc::new("!".to_string())); QueryIterator { state_stack: vec![state], } @@ -226,9 +165,9 @@ impl<'a> Iterator for QueryIterator<'a> { if child_num == child_terms.len() { match ct { ClauseType::CallN => { - self.push_subterm(Level::Shallow, child_terms[0].as_ref()) + self.push_subterm(Level::Shallow, &child_terms[0]); } - ClauseType::Named(..) | ClauseType::Op(..) => { + ClauseType::Named(..) => { return match lvl { Level::Root => None, lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)), @@ -247,33 +186,30 @@ impl<'a> Iterator for QueryIterator<'a> { child_terms, )); - self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref()); + self.push_subterm(lvl.child_level(), &child_terms[child_num]); } } TermIterState::InitialCons(lvl, cell, head, tail) => { - if let Some((string, tail)) = is_partial_string(head, tail) { - self.state_stack - .push(TermIterState::PartialString(lvl, cell, string, tail)); + self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail)); - if let Some(tail) = tail { - self.push_subterm(lvl.child_level(), tail); - } - } else { - self.state_stack - .push(TermIterState::FinalCons(lvl, cell, head, tail)); + self.push_subterm(lvl.child_level(), tail); + self.push_subterm(lvl.child_level(), head); + } + TermIterState::InitialPartialString(lvl, cell, string, tail) => { + self.state_stack.push(TermIterState::FinalPartialString(lvl, cell, string, tail)); + if let Some(tail) = tail { self.push_subterm(lvl.child_level(), tail); - self.push_subterm(lvl.child_level(), head); } } - TermIterState::PartialString(lvl, cell, string, tail) => { + TermIterState::FinalPartialString(lvl, cell, string, tail) => { return Some(TermRef::PartialString(lvl, cell, string, tail)); } TermIterState::FinalCons(lvl, cell, head, tail) => { return Some(TermRef::Cons(lvl, cell, head, tail)); } - TermIterState::Constant(lvl, cell, constant) => { - return Some(TermRef::Constant(lvl, cell, constant)); + TermIterState::Literal(lvl, cell, constant) => { + return Some(TermRef::Literal(lvl, cell, constant)); } TermIterState::Var(lvl, cell, var) => { return Some(TermRef::Var(lvl, cell, var)); @@ -297,10 +233,10 @@ impl<'a> FactIterator<'a> { .push_back(TermIterState::subterm_to_state(lvl, term)); } - pub(crate) fn from_rule_head_clause(terms: &'a Vec>) -> Self { + pub(crate) fn from_rule_head_clause(terms: &'a Vec) -> Self { let state_queue = terms .iter() - .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref())) + .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt)) .collect(); FactIterator { @@ -311,23 +247,31 @@ impl<'a> FactIterator<'a> { fn new(term: &'a Term, iterable_root: bool) -> Self { let states = match term { - &Term::AnonVar => { + Term::AnonVar => { vec![TermIterState::AnonVar(Level::Root)] } - &Term::Clause(ref cell, ref name, ref terms, ref fixity) => { - let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone()); + Term::Clause(cell, name, terms) => { + let ct = ClauseType::from(*name, terms.len()); vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)] } - &Term::Cons(ref cell, ref head, ref tail) => vec![TermIterState::InitialCons( + Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons( Level::Root, cell, head.as_ref(), tail.as_ref(), )], - &Term::Constant(ref cell, ref constant) => { - vec![TermIterState::Constant(Level::Root, cell, constant)] + Term::PartialString(cell, string_buf, tail_opt) => { + vec![TermIterState::InitialPartialString( + Level::Root, + cell, + *string_buf, + tail_opt, + )] } - &Term::Var(ref cell, ref var) => { + Term::Literal(cell, constant) => { + vec![TermIterState::Literal(Level::Root, cell, constant)] + } + Term::Var(cell, var) => { vec![TermIterState::Var(Level::Root, cell, var.clone())] } }; @@ -359,21 +303,20 @@ impl<'a> Iterator for FactIterator<'a> { }; } TermIterState::InitialCons(lvl, cell, head, tail) => { - if let Some((string, tail)) = is_partial_string(head, tail) { - if let Some(tail) = tail { - self.push_subterm(Level::Deep, tail); - } + self.push_subterm(Level::Deep, head); + self.push_subterm(Level::Deep, tail); - return Some(TermRef::PartialString(lvl, cell, string, tail)); - } else { - self.push_subterm(Level::Deep, head); + return Some(TermRef::Cons(lvl, cell, head, tail)); + } + TermIterState::InitialPartialString(lvl, cell, string_buf, tail_opt) => { + if let Some(tail) = tail_opt { self.push_subterm(Level::Deep, tail); - - return Some(TermRef::Cons(lvl, cell, head, tail)); } + + return Some(TermRef::PartialString(lvl, cell, string_buf, tail_opt)); } - TermIterState::Constant(lvl, cell, constant) => { - return Some(TermRef::Constant(lvl, cell, constant)) + TermIterState::Literal(lvl, cell, constant) => { + return Some(TermRef::Literal(lvl, cell, constant)) } TermIterState::Var(lvl, cell, var) => { return Some(TermRef::Var(lvl, cell, var)); @@ -386,17 +329,17 @@ impl<'a> Iterator for FactIterator<'a> { } } -pub(crate) fn post_order_iter(term: &Term) -> QueryIterator { +pub(crate) fn post_order_iter<'a>(term: &'a Term) -> QueryIterator<'a> { QueryIterator::from_term(term) } -pub(crate) fn breadth_first_iter(term: &Term, iterable_root: bool) -> FactIterator { +pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: bool) -> FactIterator<'a> { FactIterator::new(term, iterable_root) } #[derive(Debug)] pub(crate) enum ChunkedTerm<'a> { - HeadClause(ClauseName, &'a Vec>), + HeadClause(Atom, &'a Vec), BodyTerm(&'a QueryTerm), } @@ -407,7 +350,7 @@ pub(crate) fn query_term_post_order_iter<'a>(query_term: &'a QueryTerm) -> Query impl<'a> ChunkedTerm<'a> { pub(crate) fn post_order_iter(&self) -> QueryIterator<'a> { match self { - &ChunkedTerm::BodyTerm(ref qt) => QueryIterator::new(qt), + &ChunkedTerm::BodyTerm(qt) => QueryIterator::new(qt), &ChunkedTerm::HeadClause(_, terms) => QueryIterator::from_rule_head_clause(terms), } } @@ -517,7 +460,7 @@ impl<'a> ChunkedIterator<'a> { while let Some(term) = item { match term { ChunkedTerm::HeadClause(_, terms) => { - if contains_cut_var(terms.iter().map(|t| t.as_ref())) { + if contains_cut_var(terms.iter()) { self.cut_var_in_head = true; } @@ -547,7 +490,10 @@ impl<'a> ChunkedIterator<'a> { arity = 1; break; } - ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => result.push(term), + ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => { + self.deep_cut_encountered = true; + result.push(term); + } ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), ..)) => { result.push(term) } diff --git a/src/lib.rs b/src/lib.rs index 1fd4a4fb..458ad485 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,25 +1,29 @@ -#[cfg(feature = "num-rug-adapter")] -use num_rug_adapter as rug; -#[cfg(feature = "rug")] -use rug; +#[macro_use] +extern crate static_assertions; #[macro_use] -mod macros; +pub mod macros; +#[macro_use] +pub mod atom_table; +#[macro_use] +pub mod arena; +#[macro_use] +pub mod parser; mod allocator; mod arithmetic; mod clause_types; -mod codegen; +pub mod codegen; mod debray_allocator; mod fixtures; mod forms; mod heap_iter; -mod heap_print; +pub mod heap_print; mod indexing; mod instructions; mod iterators; pub mod machine; +mod raw_block; pub mod read; mod targets; -mod write; - -use machine::*; +pub mod types; +pub mod write; diff --git a/src/lib/atts.pl b/src/lib/atts.pl index 5906466b..a9369426 100644 --- a/src/lib/atts.pl +++ b/src/lib/atts.pl @@ -24,30 +24,42 @@ '$absent_from_list'(Ls, Attr). '$absent_from_list'(X, Attr) :- - ( var(X) -> true - ; X = [L|Ls], L \= Attr -> '$absent_from_list'(Ls, Attr) + ( var(X) -> + true + ; X = [L|Ls], + L \= Attr -> + '$absent_from_list'(Ls, Attr) ). '$get_attr'(V, Attr) :- - '$get_attr_list'(V, Ls), nonvar(Ls), '$get_from_list'(Ls, V, Attr). + '$get_attr_list'(V, Ls), + nonvar(Ls), + '$get_from_list'(Ls, V, Attr). '$get_from_list'([L|Ls], V, Attr) :- nonvar(L), - ( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr) - ; L = Attr, '$enqueue_attr_var'(V) + ( L \= Attr -> + nonvar(Ls), + '$get_from_list'(Ls, V, Attr) + ; L = Attr, + '$enqueue_attr_var'(V) ). '$put_attr'(V, Attr) :- - '$get_attr_list'(V, Ls), '$add_to_list'(Ls, V, Attr). + '$get_attr_list'(V, Ls), + '$add_to_list'(Ls, V, Attr). '$add_to_list'(Ls, V, Attr) :- - ( var(Ls) -> - Ls = [Attr | _], '$enqueue_attr_var'(V) - ; Ls = [_ | Ls0], '$add_to_list'(Ls0, V, Attr) + ( var(Ls) -> + Ls = [Attr | _], + '$enqueue_attr_var'(V) + ; Ls = [_ | Ls0], + '$add_to_list'(Ls0, V, Attr) ). '$del_attr'(Ls0, _, _) :- - var(Ls0), !. + var(Ls0), + !. '$del_attr'(Ls0, V, Attr) :- Ls0 = [Att | Ls1], nonvar(Att), @@ -134,22 +146,22 @@ put_attr(Name, Arity, Module) --> [(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity), - functor(AttrForm, Head, Arity), - '$get_attr_list'(V, Ls), - atts:'$del_attr'(Ls, V, Module:AttrForm), - atts:'$put_attr'(V, Module:Attr)), + functor(AttrForm, Head, Arity), + '$get_attr_list'(V, Ls), + atts:'$del_attr'(Ls, V, Module:AttrForm), + atts:'$put_attr'(V, Module:Attr)), (put_atts(V, Attr) :- !, functor(Attr, Head, Arity), - functor(AttrForm, Head, Arity), - '$get_attr_list'(V, Ls), - atts:'$del_attr'(Ls, V, Module:AttrForm), - atts:'$put_attr'(V, Module:Attr)), + functor(AttrForm, Head, Arity), + '$get_attr_list'(V, Ls), + atts:'$del_attr'(Ls, V, Module:AttrForm), + atts:'$put_attr'(V, Module:Attr)), (put_atts(V, -Attr) :- !, functor(Attr, _, _), - '$get_attr_list'(V, Ls), - atts:'$del_attr'(Ls, V, Module:Attr))]. + '$get_attr_list'(V, Ls), + atts:'$del_attr'(Ls, V, Module:Attr))]. get_attr(Name, Arity, Module) --> { functor(Attr, Name, Arity) }, diff --git a/src/lib/between.pl b/src/lib/between.pl index 5a0d5bab..b162e023 100644 --- a/src/lib/between.pl +++ b/src/lib/between.pl @@ -12,10 +12,22 @@ between(Lower, Upper, X) :- ( nonvar(X) -> Lower =< X, X =< Upper - ; compare(Ord, Lower, Upper), - between_(Ord, Lower, Upper, X) + ; % compare(Ord, Lower, Upper), + % between_(Ord, Lower, Upper, X) + Lower =< Upper, + between_(Lower, Upper, X) ). +between_(Lower, Lower, Lower) :- !. +between_(Lower, Upper, Lower1) :- + ( Lower < Upper, + ( Lower1 = Lower + ; Lower0 is Lower + 1, + between_(Lower0, Upper, Lower1) + ) + ). + +/* between_(<, Lower0, Upper, X) :- ( X = Lower0 ; Lower1 is Lower0 + 1, @@ -23,6 +35,7 @@ between_(<, Lower0, Upper, X) :- between_(Ord, Lower1, Upper, X) ). between_(=, Upper, Upper, Upper). +*/ enumerate_nats(I, I). enumerate_nats(I0, N) :- diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 00a26238..0c9d33f9 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -347,11 +347,11 @@ call_or_cut_interp((G1 -> G2), B) :- :- non_counted_backtracking univ_errors/3. univ_errors(Term, List, N) :- '$skip_max_list'(N, -1, List, R), - ( var(R) -> - ( var(Term), - throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a) - ; true - ) + ( var(R) -> + ( var(Term), + throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a) + ; true + ) ; R \== [] -> throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b) ; List = [H|T] -> @@ -388,9 +388,10 @@ univ_worker(Term, List, _) :- !, '$call_with_default_policy'(List = [Term]). univ_worker(Term, [Name|Args], N) :- - var(Term), !, + var(Term), + !, '$call_with_default_policy'(Arity is N-1), - '$call_with_default_policy'(functor(Term, Name, Arity)), + '$call_with_default_policy'(functor(Term, Name, Arity)), % Term = {var}, Name = nonvar, Arity = 0. '$call_with_default_policy'(get_args(Args, Term, 1, Arity)). univ_worker(Term, List, _) :- '$call_with_default_policy'(functor(Term, Name, Arity)), @@ -679,9 +680,9 @@ set_difference([], _, []) :- !. set_difference(Xs, [], Xs). group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :- - iso_ext:variant(V1, V2), + V1 = V2, % \+ \+ (V1 = V2), % (2) % iso_ext:variant(V1, V2), % (1) !, - V1 = V2, + % V1 = V2, % (3) group_by_variant(Pairs, V2-S2, Solutions, Pairs0). group_by_variant(Pairs, _, [], Pairs). @@ -1075,17 +1076,16 @@ abolish(Pred) :- ; throw(error(type_error(predicate_indicator, Pred), abolish/1)) ). -'$iterate_db_refs'(Ref, Name/Arity) :- - '$lookup_db_ref'(Ref, Name, Arity). -'$iterate_db_refs'(Ref, Name/Arity) :- - '$get_next_db_ref'(Ref, NextRef), - '$iterate_db_refs'(NextRef, Name/Arity). - +'$iterate_db_refs'(Name, Arity, Name/Arity). % :- +% '$lookup_db_ref'(Ref, Name, Arity). +'$iterate_db_refs'(RName, RArity, Name/Arity) :- + '$get_next_db_ref'(RName, RArity, RRName, RRArity), + '$iterate_db_refs'(RRName, RRArity, Name/Arity). current_predicate(Pred) :- ( var(Pred) -> - '$get_next_db_ref'(Ref, _), - '$iterate_db_refs'(Ref, Pred) + '$get_next_db_ref'(RN, RA, _, _), + '$iterate_db_refs'(RN, RA, Pred) ; Pred \= _/_ -> throw(error(type_error(predicate_indicator, Pred), current_predicate/1)) ; Pred = Name/Arity, @@ -1094,15 +1094,14 @@ current_predicate(Pred) :- ; integer(Arity), Arity < 0 ) -> throw(error(type_error(predicate_indicator, Pred), current_predicate/1)) - ; '$get_next_db_ref'(Ref, _), - '$iterate_db_refs'(Ref, Pred) + ; '$get_next_db_ref'(RN, RA, _, _), + '$iterate_db_refs'(RN, RA, Pred) ). -'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :- - '$lookup_op_db_ref'(Ref, Priority, Spec, Op). -'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :- - '$get_next_op_db_ref'(Ref, NextRef), - '$iterate_op_db_refs'(NextRef, Priority, Spec, Op). +'$iterate_op_db_refs'(RPriority, RSpec, ROp, _, RPriority, RSpec, ROp). +'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) :- + '$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, RRPriority, RRSpec, RROp), + '$iterate_op_db_refs'(RRPriority, RRSpec, RROp, OssifiedOpDir, Priority, Spec, Op). can_be_op_priority(Priority) :- var(Priority). can_be_op_priority(Priority) :- op_priority(Priority). @@ -1114,8 +1113,8 @@ current_op(Priority, Spec, Op) :- ( can_be_op_priority(Priority), can_be_op_specifier(Spec), error:can_be(atom, Op) -> - '$get_next_op_db_ref'(Ref, _), - '$iterate_op_db_refs'(Ref, Priority, Spec, Op) + '$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, _, _, Op), + '$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) ). list_of_op_atoms(Var) :- diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index 378d495a..f48af1d2 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -14,7 +14,7 @@ partial_string_tail/2, setup_call_cleanup/3, call_nth/2, - variant/2, +% variant/2, copy_term_nat/2]). :- use_module(library(error), [can_be/2, @@ -22,6 +22,7 @@ instantiation_error/1, type_error/3]). +:- use_module(library(lists), [maplist/3]). :- meta_predicate(call_cleanup(0, 0)). @@ -160,14 +161,12 @@ call_with_inference_limit(_, _, R, Bb, B) :- '$erase_ball', '$call_with_default_policy'(handle_ile(B, Ball, R)). -variant(X, Y) :- '$variant'(X, Y). - partial_string(String, L, L0) :- ( String == [] -> L = L0 ; catch(atom_chars(Atom, String), - error(E, _), - throw(error(E, partial_string/3))), + error(E, _), + throw(error(E, partial_string/3))), '$create_partial_string'(Atom, L, L0) ). diff --git a/src/lib/lists.pl b/src/lib/lists.pl index 20631588..a64c3ad3 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -3,7 +3,7 @@ maplist/3, maplist/4, maplist/5, maplist/6, maplist/7, maplist/8, maplist/9, same_length/2, nth0/3, sum_list/2, transpose/2, list_to_set/2, list_max/2, - list_min/2, permutation/2]). + list_min/2, permutation/2]). /* Author: Mark Thom, Jan Wielemaker, and Richard O'Keefe Copyright (c) 2018-2021, Mark Thom diff --git a/src/lib/serialization/abnf.pl b/src/lib/serialization/abnf.pl index d5c1c31b..037e7aa0 100644 --- a/src/lib/serialization/abnf.pl +++ b/src/lib/serialization/abnf.pl @@ -9,26 +9,26 @@ syntaxes. The DCGs are presented in the order they appear in the RFC. While some DCGs below use `char_type/2`, the most common ones are defined manually in order to take advantage of Prolog's first-argument indexing. - + BSD 3-Clause License - + Copyright (c) 2021, Aram Panasenco All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE diff --git a/src/lib/serialization/json.pl b/src/lib/serialization/json.pl index e1bebe11..dac27882 100644 --- a/src/lib/serialization/json.pl +++ b/src/lib/serialization/json.pl @@ -1,29 +1,29 @@ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Written Apr 2021 by Aram Panasenco (panasenco@ucla.edu) Part of Scryer Prolog. - + `json_chars//1` can be used with [`phrase_from_file/2`](src/lib/pio.pl) or [`phrase/2`](src/lib/dcgs.pl) to parse and generate [JSON](https://www.json.org/json-en.html). - + BSD 3-Clause License - + Copyright (c) 2021, Aram Panasenco All rights reserved. - + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - + * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -44,7 +44,7 @@ :- use_module(library(dif)). :- use_module(library(lists)). -/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html +/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html as closely as possible. Note that the names in the McKeeman form conflict with the pictures on the site. */ json_chars(Internal) --> json_element(Internal). diff --git a/src/lib/uuid.pl b/src/lib/uuid.pl index affa3b68..3f89db4b 100644 --- a/src/lib/uuid.pl +++ b/src/lib/uuid.pl @@ -4,9 +4,9 @@ This library provides reasoning about UUID (only version 4 right now). There are three predicates: * uuidv4/1, to generate a new UUIDv4 - * uuidv4_string/1, to generate a new UUIDv4 in string hex representation + * uuidv4_string/1, to generate a new UUIDv4 in string hex representation * uuid_string/2, to converte between UUID list of bytes and UUID hex representation - + Examples: ?- uuidv4(X). X = [42,147,248,242,117,196,79,2,129,159|...]. @@ -30,7 +30,7 @@ :- use_module(library(dcgs)). :- use_module(library(lists)). -/* +/* An UUID is made of 16 bytes, composed of 5 sections: time_low - 4 time_mid - 2 diff --git a/src/loader.pl b/src/loader.pl index 531730cc..722d413a 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -1,4 +1,3 @@ - :- module(loader, [consult/1, expand_goal/3, expand_term/2, @@ -508,7 +507,8 @@ open_file(Path, Stream) :- ; catch(open(Path, read, Stream), error(existence_error(source_sink, _), _), ( atom_concat(Path, '.pl', ExtendedPath), - open(ExtendedPath, read, Stream) ) + open(ExtendedPath, read, Stream) + ) ) ). diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 4e3f832a..85b6cbc3 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1,37 +1,98 @@ use divrem::*; -use prolog_parser::ast::*; -use prolog_parser::clause_name; - +use crate::arena::*; use crate::arithmetic::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::forms::*; +use crate::heap_iter::*; use crate::machine::machine_errors::*; -use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -use crate::rug::{Integer, Rational}; +use crate::parser::ast::*; +use crate::parser::rug::{Integer, Rational}; +use crate::types::*; + +use crate::fixnum; + use ordered_float::*; use std::cmp; use std::convert::TryFrom; use std::f64; use std::mem; -use std::rc::Rc; #[macro_export] macro_rules! try_numeric_result { - ($s: ident, $e: expr, $caller: expr) => { + ($e: expr, $stub_gen: expr) => { match $e { Ok(val) => Ok(val), - Err(e) => { - let caller_copy = $caller.iter().map(|v| v.context_free_clone()).collect(); + Err(e) => Err(Box::new(move |machine_st: &mut MachineState| { + let stub = $stub_gen(); + let evaluation_error = machine_st.evaluation_error(e); + + machine_st.error_form(evaluation_error, stub) + }) as Box MachineStub>), + } + }; +} - Err($s.error_form(MachineError::evaluation_error(e), caller_copy)) +macro_rules! drop_iter_on_err { + ($self:expr, $iter: expr, $result: expr) => { + match $result { + Ok(val) => val, + Err(stub_gen) => { + std::mem::drop($iter); + return Err(stub_gen($self)); } } }; } +fn zero_divisor_eval_error( + stub_gen: impl Fn() -> FunctorStub + 'static, +) -> MachineStubGen { + Box::new(move |machine_st| { + let eval_error = machine_st.evaluation_error(EvalError::ZeroDivisor); + let stub = stub_gen(); + + machine_st.error_form(eval_error, stub) + }) +} + +fn undefined_eval_error( + stub_gen: impl Fn() -> FunctorStub + 'static, +) -> MachineStubGen { + Box::new(move |machine_st| { + let eval_error = machine_st.evaluation_error(EvalError::Undefined); + let stub = stub_gen(); + + machine_st.error_form(eval_error, stub) + }) +} + +fn numerical_type_error( + valid_type: ValidType, + n: Number, + stub_gen: impl Fn() -> FunctorStub + 'static, +) -> MachineStubGen { + Box::new(move |machine_st| { + let type_error = machine_st.type_error(valid_type, n); + let stub = stub_gen(); + + machine_st.error_form(type_error, stub) + }) +} + +pub(crate) fn sign(n: Number) -> Number { + if n.is_positive() { + Number::Fixnum(Fixnum::build_with(1)) + } else if n.is_negative() { + Number::Fixnum(Fixnum::build_with(-1)) + } else { + Number::Fixnum(Fixnum::build_with(0)) + } +} + fn isize_gcd(n1: isize, n2: isize) -> Option { if n1 == 0 { return n2.checked_abs().map(|n| n as isize); @@ -80,935 +141,1290 @@ fn isize_gcd(n1: isize, n2: isize) -> Option { Some(n1 << shift as isize) } -impl MachineState { - pub(crate) fn get_number(&mut self, at: &ArithmeticTerm) -> Result { - match at { - &ArithmeticTerm::Reg(r) => self.arith_eval_by_metacall(r), - &ArithmeticTerm::Interm(i) => { - Ok(mem::replace(&mut self.interms[i - 1], Number::Fixnum(0))) - } - &ArithmeticTerm::Number(ref n) => Ok(n.clone()), +pub(crate) fn add(lhs: Number, rhs: Number, arena: &mut Arena) -> Result { + match (lhs, rhs) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok( + if let Some(result) = n1.get_num().checked_add(n2.get_num()) { + fixnum!(Number, result, arena) + } else { + Number::arena_from( + Integer::from(n1.get_num()) + Integer::from(n2.get_num()), + arena, + ) + }, + ), + (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => { + Ok(Number::arena_from( + Integer::from(n1.get_num()) + &*n2, + arena, + )) + } + (Number::Fixnum(n1), Number::Rational(n2)) | (Number::Rational(n2), Number::Fixnum(n1)) => { + Ok(Number::arena_from( + Rational::from(n1.get_num()) + &*n2, + arena, + )) + } + (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => { + Ok(Number::Float(add_f(float_fn_to_f(n1.get_num())?, n2)?)) + } + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(&*n1) + &*n2, arena)) // add_i + } + (Number::Integer(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { + Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?)) + } + (Number::Integer(n1), Number::Rational(n2)) + | (Number::Rational(n2), Number::Integer(n1)) => { + Ok(Number::arena_from(Rational::from(&*n1) + &*n2, arena)) + } + (Number::Rational(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { + Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?)) + } + (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { + Ok(Number::Float(add_f(f1, f2)?)) + } + (Number::Rational(r1), Number::Rational(r2)) => { + Ok(Number::arena_from(Rational::from(&*r1) + &*r2, arena)) } } +} - pub(super) fn rational_from_number(&self, n: Number) -> Result, MachineError> { - match n { - Number::Fixnum(n) => Ok(Rc::new(Rational::from(n))), - Number::Rational(r) => Ok(r), - Number::Float(OrderedFloat(f)) => match Rational::from_f64(f) { - Some(r) => Ok(Rc::new(r)), - None => Err(MachineError::instantiation_error()), - }, - Number::Integer(n) => Ok(Rc::new(Rational::from(&*n))), +pub(crate) fn neg(n: Number, arena: &mut Arena) -> Number { + match n { + Number::Fixnum(n) => { + if let Some(n) = n.get_num().checked_neg() { + fixnum!(Number, n, arena) + } else { + Number::arena_from(-Integer::from(n.get_num()), arena) + } } + Number::Integer(n) => Number::arena_from(-Integer::from(&*n), arena), + Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)), + Number::Rational(r) => Number::arena_from(-Rational::from(&*r), arena), } +} - pub(crate) fn get_rational( - &mut self, - at: &ArithmeticTerm, - caller: MachineStub, - ) -> Result<(Rc, MachineStub), MachineStub> { - let n = self.get_number(at)?; - - match self.rational_from_number(n) { - Ok(r) => Ok((r, caller)), - Err(e) => Err(self.error_form(e, caller)), - } - } - - pub(crate) fn arith_eval_by_metacall(&self, r: RegType) -> Result { - let caller = MachineError::functor_stub(clause_name!("is"), 2); - let mut interms: Vec = Vec::with_capacity(64); - - for addr in self.post_order_iter(self[r]) { - match self.heap.index_addr(&addr).as_ref() { - &HeapCellValue::NamedStr(2, ref name, _) => { - let a2 = interms.pop().unwrap(); - let a1 = interms.pop().unwrap(); - - match name.as_str() { - "+" => interms.push(try_numeric_result!(self, a1 + a2, caller)?), - "-" => interms.push(try_numeric_result!(self, a1 - a2, caller)?), - "*" => interms.push(try_numeric_result!(self, a1 * a2, caller)?), - "/" => interms.push(self.div(a1, a2)?), - "**" => interms.push(self.pow(a1, a2, "is")?), - "^" => interms.push(self.int_pow(a1, a2)?), - "max" => interms.push(self.max(a1, a2)?), - "min" => interms.push(self.min(a1, a2)?), - "rdiv" => { - let r1 = self.rational_from_number(a1); - let r2 = - r1.and_then(|r1| self.rational_from_number(a2).map(|r2| (r1, r2))); - - match r2 { - Ok((r1, r2)) => { - let result = Number::Rational(Rc::new(self.rdiv(r1, r2)?)); - interms.push(result); - } - Err(e) => { - return Err(self.error_form(e, caller)); - } - } - } - "//" => interms.push(self.idiv(a1, a2)?), - "div" => interms.push(self.int_floor_div(a1, a2)?), - ">>" => interms.push(self.shr(a1, a2)?), - "<<" => interms.push(self.shl(a1, a2)?), - "/\\" => interms.push(self.and(a1, a2)?), - "\\/" => interms.push(self.or(a1, a2)?), - "xor" => interms.push(self.xor(a1, a2)?), - "mod" => interms.push(self.modulus(a1, a2)?), - "rem" => interms.push(self.remainder(a1, a2)?), - "atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))), - "gcd" => interms.push(self.gcd(a1, a2)?), - _ => { - let evaluable_stub = MachineError::functor_stub(name.clone(), 2); - - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Evaluable, - evaluable_stub, - ), - caller, - )); - } - } - } - &HeapCellValue::NamedStr(1, ref name, _) => { - let a1 = interms.pop().unwrap(); - - match name.as_str() { - "-" => interms.push(-a1), - "+" => interms.push(a1), - "cos" => interms.push(Number::Float(OrderedFloat(self.cos(a1)?))), - "sin" => interms.push(Number::Float(OrderedFloat(self.sin(a1)?))), - "tan" => interms.push(Number::Float(OrderedFloat(self.tan(a1)?))), - "sqrt" => interms.push(Number::Float(OrderedFloat(self.sqrt(a1)?))), - "log" => interms.push(Number::Float(OrderedFloat(self.log(a1)?))), - "exp" => interms.push(Number::Float(OrderedFloat(self.exp(a1)?))), - "acos" => interms.push(Number::Float(OrderedFloat(self.acos(a1)?))), - "asin" => interms.push(Number::Float(OrderedFloat(self.asin(a1)?))), - "atan" => interms.push(Number::Float(OrderedFloat(self.atan(a1)?))), - "abs" => interms.push(a1.abs()), - "float" => interms.push(Number::Float(OrderedFloat(self.float(a1)?))), - "truncate" => interms.push(self.truncate(a1)), - "round" => interms.push(self.round(a1)?), - "ceiling" => interms.push(self.ceiling(a1)), - "floor" => interms.push(self.floor(a1)), - "\\" => interms.push(self.bitwise_complement(a1)?), - "sign" => interms.push(self.sign(a1)), - _ => { - let evaluable_stub = MachineError::functor_stub(name.clone(), 1); - - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Evaluable, - evaluable_stub, - ), - caller, - )); - } - } - } - &HeapCellValue::Addr(Addr::Fixnum(n)) => { - interms.push(Number::Fixnum(n)); - } - &HeapCellValue::Addr(Addr::Float(n)) => interms.push(Number::Float(n)), - &HeapCellValue::Integer(ref n) => interms.push(Number::Integer(n.clone())), - &HeapCellValue::Addr(Addr::Usize(n)) => { - interms.push(Number::Integer(Rc::new(Integer::from(n)))); - } - &HeapCellValue::Rational(ref n) => interms.push(Number::Rational(n.clone())), - &HeapCellValue::Atom(ref name, _) if name.as_str() == "pi" => { - interms.push(Number::Float(OrderedFloat(f64::consts::PI))) - } - &HeapCellValue::Atom(ref name, _) if name.as_str() == "e" => { - interms.push(Number::Float(OrderedFloat(f64::consts::E))) - } - &HeapCellValue::Atom(ref name, _) if name.as_str() == "epsilon" => { - interms.push(Number::Float(OrderedFloat(f64::EPSILON))) - } - &HeapCellValue::NamedStr(arity, ref name, _) => { - let evaluable_stub = MachineError::functor_stub(name.clone(), arity); - - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Evaluable, - evaluable_stub, - ), - caller, - )); - } - &HeapCellValue::Atom(ref name, _) => { - let evaluable_stub = MachineError::functor_stub(name.clone(), 0); - - return Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Evaluable, - evaluable_stub, - ), - caller, - )); - } - &HeapCellValue::Addr(addr) if addr.is_ref() => { - return Err(self.error_form(MachineError::instantiation_error(), caller)); - } - val => { - return Err(self.type_error( - ValidType::Number, - val.context_free_clone(), - clause_name!("is"), - 2, - )); - } +pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number { + match n { + Number::Fixnum(n) => { + if let Some(n) = n.get_num().checked_abs() { + fixnum!(Number, n, arena) + } else { + Number::arena_from(Integer::from(n.get_num()).abs(), arena) } } - - Ok(interms.pop().unwrap()) + Number::Integer(n) => Number::arena_from(Integer::from(n.abs_ref()), arena), + Number::Float(f) => Number::Float(f.abs()), + Number::Rational(r) => Number::arena_from(Rational::from(r.abs_ref()), arena), } +} + +#[inline] +pub(crate) fn sub(lhs: Number, rhs: Number, arena: &mut Arena) -> Result { + let neg_result = neg(rhs, arena); + add(lhs, neg_result, arena) +} - pub(crate) fn rdiv(&self, r1: Rc, r2: Rc) -> Result { - if &*r2 == &0 { - let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); - Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Rational::from(&*r1 / &*r2)) +pub(crate) fn mul(lhs: Number, rhs: Number, arena: &mut Arena) -> Result { + match (lhs, rhs) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok( + if let Some(result) = n1.get_num().checked_mul(n2.get_num()) { + fixnum!(Number, result, arena) + } else { + Number::arena_from( + Integer::from(n1.get_num()) * Integer::from(n2.get_num()), + arena, + ) + }, + ), + (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => { + Ok(Number::arena_from( + Integer::from(n1.get_num()) * &*n2, + arena, + )) + } + (Number::Fixnum(n1), Number::Rational(n2)) | (Number::Rational(n2), Number::Fixnum(n1)) => { + Ok(Number::arena_from( + Rational::from(n1.get_num()) * &*n2, + arena, + )) + } + (Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => { + Ok(Number::Float(mul_f(float_fn_to_f(n1.get_num())?, n2)?)) + } + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(&*n1) * &*n2, arena)) // mul_i + } + (Number::Integer(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => { + Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?)) + } + (Number::Integer(n1), Number::Rational(n2)) + | (Number::Rational(n2), Number::Integer(n1)) => { + Ok(Number::arena_from(Rational::from(&*n1) * &*n2, arena)) + } + (Number::Rational(n1), Number::Float(OrderedFloat(n2))) + | (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => { + Ok(Number::Float(mul_f(float_r_to_f(&n1)?, n2)?)) + } + (Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => { + Ok(Number::Float(mul_f(f1, f2)?)) + } + (Number::Rational(r1), Number::Rational(r2)) => { + Ok(Number::arena_from(Rational::from(&*r1) * &*r2, arena)) } } +} - pub(crate) fn int_floor_div(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(div)"), 2); - let modulus = self.modulus(n1.clone(), n2.clone())?; +pub(crate) fn div(n1: Number, n2: Number) -> Result { + let stub_gen = || functor_stub(atom!("/"), 2); - self.idiv(try_numeric_result!(self, n1 - modulus, stub)?, n2) + if n2.is_zero() { + Err(zero_divisor_eval_error(stub_gen)) + } else { + try_numeric_result!(n1 / n2, stub_gen) } +} - pub(crate) fn idiv(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if n2 == 0 { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); +pub(crate) fn float_pow(n1: Number, n2: Number) -> Result { + let f1 = result_f(&n1, rnd_f); + let f2 = result_f(&n2, rnd_f); - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - if let Some(result) = n1.checked_div(n2) { - Ok(Number::from(result)) - } else { - let n1 = Integer::from(n1); - let n2 = Integer::from(n2); + let stub_gen = || { + let pow_atom = atom!("**"); + functor_stub(pow_atom, 2) + }; + + let f1 = try_numeric_result!(f1, stub_gen)?; + let f2 = try_numeric_result!(f2, stub_gen)?; - Ok(Number::from(n1 / n2)) + let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f); + + Ok(Number::Float(OrderedFloat(try_numeric_result!( + result, stub_gen + )?))) +} + +pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result { + if n1.is_zero() && n2.is_negative() { + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; + + return Err(undefined_eval_error(stub_gen)); + } + + let stub_gen = || { + let caret_atom = atom!("^"); + functor_stub(caret_atom, 2) + }; + + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n1_i = n1.get_num(); + let n2_i = n2.get_num(); + + if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && n2_i < 0 { + let n = Number::Fixnum(n1); + Err(numerical_type_error(ValidType::Float, n, stub_gen)) + } else { + if let Ok(n2_u) = u32::try_from(n2_i) { + if let Some(result) = n1_i.checked_pow(n2_u) { + return Ok(Number::arena_from(result, arena)); } } - } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if &*n2 == &0 { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from(Integer::from(n1) / &*n2)) - } - } - (Number::Integer(n2), Number::Fixnum(n1)) => { - if n1 == 0 { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); + let n1 = Integer::from(n1_i); + let n2 = Integer::from(n2_i); - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from(&*n2 / Integer::from(n1))) - } + Ok(Number::arena_from(binary_pow(n1, &n2), arena)) } - (Number::Integer(n1), Number::Integer(n2)) => { - if &*n2 == &0 { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from( - <(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0, - )) - } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1_i = n1.get_num(); + + if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && &*n2 < &0 { + let n = Number::Fixnum(n1); + Err(numerical_type_error(ValidType::Float, n, stub_gen)) + } else { + let n1 = Integer::from(n1_i); + Ok(Number::arena_from(binary_pow(n1, &*n2), arena)) } - (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )) + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + let n2_i = n2.get_num(); + + if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && n2_i < 0 { + let n = Number::Integer(n1); + Err(numerical_type_error(ValidType::Float, n, stub_gen)) + } else { + let n2 = Integer::from(n2_i); + Ok(Number::arena_from(binary_pow((*n1).clone(), &n2), arena)) } - (n1, _) => { - let stub = MachineError::functor_stub(clause_name!("(//)"), 2); - - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )) + } + (Number::Integer(n1), Number::Integer(n2)) => { + if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && &*n2 < &0 { + let n = Number::Integer(n1); + Err(numerical_type_error(ValidType::Float, n, stub_gen)) + } else { + Ok(Number::arena_from(binary_pow((*n1).clone(), &*n2), arena)) } } - } + (n1, Number::Integer(n2)) => { + let f1 = float(n1)?; + let f2 = float(Number::Integer(n2))?; - pub(crate) fn div(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(/)"), 2); - - if n2.is_zero() { - Err(self.error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - try_numeric_result!(self, n1 / n2, stub) + unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) + .map(|f| Number::Float(OrderedFloat(f))) } - } + (n1, n2) => { + let f2 = float(n2)?; - pub(crate) fn atan2(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("is"), 2); + if n1.is_negative() && f2 != f2.floor() { + return Err(undefined_eval_error(stub_gen)); + } - if n1.is_zero() && n2.is_zero() { - Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)) - } else { - let f1 = self.float(n1)?; - let f2 = self.float(n2)?; + let f1 = float(n1)?; - self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2)) + unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) + .map(|f| Number::Float(OrderedFloat(f))) } } +} - pub(crate) fn int_pow(&self, n1: Number, n2: Number) -> Result { - if n1.is_zero() && n2.is_negative() { - let stub = MachineError::functor_stub(clause_name!("is"), 2); - return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); - } +pub(crate) fn pow(n1: Number, n2: Number, culprit: Atom) -> Result { + if n2.is_negative() && n1.is_zero() { + let stub_gen = move || functor_stub(culprit, 2); - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if !(n1 == 1 || n1 == 0 || n1 == -1) && n2 < 0 { - let n = Number::from(n1); - let stub = MachineError::functor_stub(clause_name!("^"), 2); + return Err(undefined_eval_error(stub_gen)); + } - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Float, n), - stub, - )) - } else { - if let Ok(n2) = u32::try_from(n2) { - if let Some(result) = n1.checked_pow(n2) { - return Ok(Number::from(result)); - } - } + float_pow(n1, n2) +} - let n1 = Integer::from(n1); - let n2 = Integer::from(n2); +#[inline] +pub(crate) fn float(n: Number) -> Result { + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; - Ok(Number::from(binary_pow(n1, &n2))) - } - } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if !(n1 == 1 || n1 == 0 || n1 == -1) && &*n2 < &0 { - let n = Number::from(n1); - let stub = MachineError::functor_stub(clause_name!("^"), 2); + try_numeric_result!(result_f(&n, rnd_f), stub_gen) +} - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Float, n), - stub, - )) - } else { - let n1 = Integer::from(n1); - Ok(Number::from(binary_pow(n1, n2.as_ref()))) - } - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && n2 < 0 { - let n = Number::Integer(n1); - let stub = MachineError::functor_stub(clause_name!("^"), 2); +#[inline] +pub(crate) fn unary_float_fn_template( + n1: Number, + f: FloatFn, +) -> Result +where + FloatFn: Fn(f64) -> f64, +{ + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Float, n), - stub, - )) - } else { - let n2 = Integer::from(n2); - Ok(Number::from(binary_pow(n1.as_ref().clone(), &n2))) - } - } - (Number::Integer(n1), Number::Integer(n2)) => { - if !(&*n1 == &1 || &*n1 == &0 || &*n1 == &-1) && &*n2 < &0 { - let n = Number::Integer(n1); - let stub = MachineError::functor_stub(clause_name!("^"), 2); + let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?; + let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f); - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Float, n), - stub, - )) - } else { - Ok(Number::from(binary_pow(n1.as_ref().clone(), n2.as_ref()))) - } - } - (n1, Number::Integer(n2)) => { - let f1 = self.float(n1)?; - let f2 = self.float(Number::Integer(n2))?; + try_numeric_result!(f1, stub_gen) +} - self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) - .map(|f| Number::Float(OrderedFloat(f))) +pub(crate) fn max(n1: Number, n2: Number) -> Result { + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n1.get_num() > n2.get_num() { + Ok(Number::Fixnum(n1)) + } else { + Ok(Number::Fixnum(n2)) + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 > &n1.get_num() { + Ok(Number::Integer(n2)) + } else { + Ok(Number::Fixnum(n1)) } - (n1, n2) => { - let f2 = self.float(n2)?; + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + if &*n1 > &n2.get_num() { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Fixnum(n2)) + } + } + (Number::Integer(n1), Number::Integer(n2)) => { + if n1 > n2 { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Integer(n2)) + } + } + (n1, n2) => { + let stub_gen = || { + let max_atom = atom!("max"); + functor_stub(max_atom, 2) + }; - if n1.is_negative() && f2 != f2.floor() { - let stub = MachineError::functor_stub(clause_name!("is"), 2); - return Err( - self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub) - ); - } + let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?; + let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?; - let f1 = self.float(n1)?; - self.unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.powf(f2)) - .map(|f| Number::Float(OrderedFloat(f))) - } + Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2)))) } } +} - pub(crate) fn gcd(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if let Some(result) = isize_gcd(n1, n2) { - Ok(Number::Fixnum(result)) - } else { - Ok(Number::from(Integer::from(n1).gcd(&Integer::from(n2)))) - } +pub(crate) fn min(n1: Number, n2: Number) -> Result { + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n1.get_num() < n2.get_num() { + Ok(Number::Fixnum(n1)) + } else { + Ok(Number::Fixnum(n2)) } - (Number::Fixnum(n1), Number::Integer(n2)) - | (Number::Integer(n2), Number::Fixnum(n1)) => { - let n1 = Integer::from(n1); - Ok(Number::from(Integer::from(n2.gcd_ref(&n1)))) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 < &n1.get_num() { + Ok(Number::Integer(n2)) + } else { + Ok(Number::Fixnum(n1)) } - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(n1.gcd_ref(&n2)))) + } + (Number::Integer(n1), Number::Fixnum(n2)) => { + if &*n1 < &n2.get_num() { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Fixnum(n2)) } - (Number::Float(f), _) | (_, Number::Float(f)) => { - let n = Number::Float(f); - let stub = MachineError::functor_stub(clause_name!("gcd"), 2); - - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n), - stub, - )) + } + (Number::Integer(n1), Number::Integer(n2)) => { + if n1 < n2 { + Ok(Number::Integer(n1)) + } else { + Ok(Number::Integer(n2)) } - (Number::Rational(r), _) | (_, Number::Rational(r)) => { - let n = Number::Rational(r); - let stub = MachineError::functor_stub(clause_name!("gcd"), 2); + } + (n1, n2) => { + let stub_gen = || { + let min_atom = atom!("min"); + functor_stub(min_atom, 2) + }; - Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n), - stub, - )) - } + let f1 = try_numeric_result!(result_f(&n1, rnd_f), stub_gen)?; + let f2 = try_numeric_result!(result_f(&n2, rnd_f), stub_gen)?; + + Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2)))) } } +} - pub(crate) fn float_pow(&self, n1: Number, n2: Number) -> Result { - let f1 = result_f(&n1, rnd_f); - let f2 = result_f(&n2, rnd_f); - - let stub = MachineError::functor_stub(clause_name!("(**)"), 2); +pub fn rational_from_number( + n: Number, + stub_gen: impl Fn() -> FunctorStub + 'static, + arena: &mut Arena, +) -> Result, MachineStubGen> { + match n { + Number::Fixnum(n) => Ok(arena_alloc!(Rational::from(n.get_num()), arena)), + Number::Rational(r) => Ok(r), + Number::Float(OrderedFloat(f)) => match Rational::from_f64(f) { + Some(r) => Ok(arena_alloc!(r, arena)), + None => Err(Box::new(move |machine_st| { + let instantiation_error = machine_st.instantiation_error(); + let stub = stub_gen(); + + machine_st.error_form(instantiation_error, stub) + })), + }, + Number::Integer(n) => Ok(arena_alloc!(Rational::from(&*n), arena)), + } +} - let f1 = try_numeric_result!(self, f1, stub)?; - let f2 = try_numeric_result!(self, f2, stub)?; +pub(crate) fn rdiv( + r1: TypedArenaPtr, + r2: TypedArenaPtr, +) -> Result { + if &*r2 == &0 { + let stub_gen = || { + let rdiv_atom = atom!("rdiv"); + functor_stub(rdiv_atom, 2) + }; + + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Rational::from(&*r1 / &*r2)) + } +} - let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f); +pub(crate) fn idiv(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let idiv_atom = atom!("//"); + functor_stub(idiv_atom, 2) + }; - Ok(Number::Float(OrderedFloat(try_numeric_result!( - self, result, stub - )?))) - } + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + if n2.get_num() == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + if let Some(result) = n1.get_num().checked_div(n2.get_num()) { + Ok(Number::arena_from(result, arena)) + } else { + let n1 = Integer::from(n1.get_num()); + let n2 = Integer::from(n2.get_num()); - pub(crate) fn pow( - &self, - n1: Number, - n2: Number, - culprit: &'static str, - ) -> Result { - if n2.is_negative() && n1.is_zero() { - let stub = MachineError::functor_stub(clause_name!(culprit), 2); - return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); + Ok(Number::arena_from(n1 / n2, arena)) + } + } } - - self.float_pow(n1, n2) + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Number::arena_from(Integer::from(n1) / &*n2, arena)) + } + } + (Number::Integer(n2), Number::Fixnum(n1)) => { + if n1.get_num() == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Number::arena_from(&*n2 / Integer::from(n1), arena)) + } + } + (Number::Integer(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Number::arena_from( + <(Integer, Integer)>::from(n1.div_rem_ref(&*n2)).0, + arena, + )) + } + } + (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) + } + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - #[inline] - pub(crate) fn unary_float_fn_template( - &self, - n1: Number, - f: FloatFn, - ) -> Result - where - FloatFn: Fn(f64) -> f64, - { - let stub = MachineError::functor_stub(clause_name!("is"), 2); +pub(crate) fn int_floor_div( + n1: Number, + n2: Number, + arena: &mut Arena, +) -> Result { + let stub_gen = || { + let div_atom = atom!("div"); + functor_stub(div_atom, 2) + }; - let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?; - let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f); + let modulus = modulus(n1, n2, arena)?; + let n1 = try_numeric_result!(sub(n1, modulus, arena), stub_gen)?; - try_numeric_result!(self, f1, stub) - } + idiv(n1, n2, arena) +} - #[inline] - pub(crate) fn sin(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.sin()) - } +pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let shr_atom = atom!(">>"); + functor_stub(shr_atom, 2) + }; - #[inline] - pub(crate) fn cos(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.cos()) - } + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n1_i = n1.get_num(); + let n2_i = n2.get_num(); - #[inline] - pub(crate) fn tan(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.tan()) - } + let n1 = Integer::from(n1_i); - #[inline] - pub(crate) fn log(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.log(f64::consts::E)) - } + if let Ok(n2) = u32::try_from(n2_i) { + return Ok(Number::arena_from(n1 >> n2, arena)); + } else { + return Ok(Number::arena_from(n1 >> u32::max_value(), arena)); + } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1.get_num()); - #[inline] - pub(crate) fn exp(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.exp()) + match n2.to_u32() { + Some(n2) => Ok(Number::arena_from(n1 >> n2, arena)), + _ => Ok(Number::arena_from(n1 >> u32::max_value(), arena)), + } + } + (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2.get_num()) { + Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)), + _ => Ok(Number::arena_from( + Integer::from(&*n1 >> u32::max_value()), + arena, + )), + }, + (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { + Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)), + _ => Ok(Number::arena_from( + Integer::from(&*n1 >> u32::max_value()), + arena, + )), + }, + (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), + (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - #[inline] - pub(crate) fn asin(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.asin()) - } +pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let shl_atom = atom!(">>"); + functor_stub(shl_atom, 2) + }; - #[inline] - pub(crate) fn acos(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.acos()) - } + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n1_i = n1.get_num(); + let n2_i = n2.get_num(); - #[inline] - pub(crate) fn atan(&self, n1: Number) -> Result { - self.unary_float_fn_template(n1, |f| f.atan()) - } + let n1 = Integer::from(n1_i); - #[inline] - pub(crate) fn sqrt(&self, n1: Number) -> Result { - if n1.is_negative() { - let stub = MachineError::functor_stub(clause_name!("is"), 2); - return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub)); + if let Ok(n2) = u32::try_from(n2_i) { + return Ok(Number::arena_from(n1 << n2, arena)); + } else { + return Ok(Number::arena_from(n1 << u32::max_value(), arena)); + } } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1.get_num()); - self.unary_float_fn_template(n1, |f| f.sqrt()) + match n2.to_u32() { + Some(n2) => Ok(Number::arena_from(n1 << n2, arena)), + _ => Ok(Number::arena_from(n1 << u32::max_value(), arena)), + } + } + (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2.get_num()) { + Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)), + _ => Ok(Number::arena_from( + Integer::from(&*n1 << u32::max_value()), + arena, + )), + }, + (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { + Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)), + _ => Ok(Number::arena_from( + Integer::from(&*n1 << u32::max_value()), + arena, + )), + }, + (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), + (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - #[inline] - pub(crate) fn float(&self, n: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("is"), 2); - try_numeric_result!(self, result_f(&n, rnd_f), stub) - } +pub(crate) fn and(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let and_atom = atom!("/\\"); + functor_stub(and_atom, 2) + }; - #[inline] - pub(crate) fn floor(&self, n1: Number) -> Number { - rnd_i(&n1).to_owned() + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(Number::arena_from(n1.get_num() & n2.get_num(), arena)) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from(n1 & &*n2, arena)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from( + &*n1 & Integer::from(n2.get_num()), + arena, + )), + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(&*n1 & &*n2), arena)) + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) + } + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - #[inline] - pub(crate) fn ceiling(&self, n1: Number) -> Number { - -self.floor(-n1) - } +pub(crate) fn or(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let or_atom = atom!("\\/"); + functor_stub(or_atom, 2) + }; - #[inline] - pub(crate) fn truncate(&self, n: Number) -> Number { - if n.is_negative() { - -self.floor(n.abs()) - } else { - self.floor(n) + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(Number::arena_from(n1.get_num() | n2.get_num(), arena)) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from(n1 | &*n2, arena)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from( + &*n1 | Integer::from(n2.get_num()), + arena, + )), + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(&*n1 | &*n2), arena)) + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) } + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - pub(crate) fn round(&self, n: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("is"), 2); - - let result = n + Number::Float(OrderedFloat(0.5f64)); - let result = try_numeric_result!(self, result, stub)?; +pub(crate) fn xor(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let xor_atom = atom!("xor"); + functor_stub(xor_atom, 2) + }; - Ok(self.floor(result)) + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + Ok(Number::arena_from(n1.get_num() ^ n2.get_num(), arena)) + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from(n1 ^ &*n2, arena)) + } + (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from( + &*n1 ^ Integer::from(n2.get_num()), + arena, + )), + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(&*n1 ^ &*n2), arena)) + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) + } + _ => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)), } +} - pub(crate) fn shr(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(>>)"), 2); +pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let mod_atom = atom!("mod"); + functor_stub(mod_atom, 2) + }; - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - let n1 = Integer::from(n1); + match (x, y) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n2_i = n2.get_num(); - if let Ok(n2) = u32::try_from(n2) { - return Ok(Number::from(n1 >> n2)); - } else { - return Ok(Number::from(n1 >> u32::max_value())); - } + if n2_i == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n1_i = n1.get_num(); + Ok(Number::arena_from(n1_i.rem_floor(n2_i), arena)) } - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - - match n2.to_u32() { - Some(n2) => Ok(Number::from(n1 >> n2)), - _ => Ok(Number::from(n1 >> u32::max_value())), - } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from( + <(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1, + arena, + )) } - (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2) { - Ok(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))), - _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))), - }, - (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { - Some(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))), - _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))), - }, - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), } + (Number::Integer(n1), Number::Fixnum(n2)) => { + let n2_i = n2.get_num(); + + if n2_i == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n2 = Integer::from(n2_i); + Ok(Number::arena_from( + <(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1, + arena, + )) + } + } + (Number::Integer(x), Number::Integer(y)) => { + if &*y == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Number::arena_from( + <(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1, + arena, + )) + } + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) + } + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - pub(crate) fn shl(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(<<)"), 2); +pub(crate) fn remainder(x: Number, y: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let rem_atom = atom!("rem"); + functor_stub(rem_atom, 2) + }; - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - let n1 = Integer::from(n1); + match (x, y) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n2_i = n2.get_num(); - if let Ok(n2) = u32::try_from(n2) { - return Ok(Number::from(n1 << n2)); - } else { - return Ok(Number::from(n1 << u32::max_value())); - } + if n2_i == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n1_i = n1.get_num(); + Ok(Number::arena_from(n1_i % n2_i, arena)) } - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - - match n2.to_u32() { - Some(n2) => Ok(Number::from(n1 << n2)), - _ => Ok(Number::from(n1 << u32::max_value())), - } + } + (Number::Fixnum(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from(n1 % &*n2, arena)) } - (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2) { - Ok(n2) => Ok(Number::from(Integer::from(&*n1 << n2))), - _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))), - }, - (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() { - Some(n2) => Ok(Number::from(Integer::from(&*n1 << n2))), - _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))), - }, - (Number::Integer(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), } + (Number::Integer(n1), Number::Fixnum(n2)) => { + let n2_i = n2.get_num(); + + if n2_i == 0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + let n2 = Integer::from(n2_i); + Ok(Number::arena_from(&*n1 % n2, arena)) + } + } + (Number::Integer(n1), Number::Integer(n2)) => { + if &*n2 == &0 { + Err(zero_divisor_eval_error(stub_gen)) + } else { + Ok(Number::arena_from(Integer::from(&*n1 % &*n2), arena)) + } + } + (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => { + Err(numerical_type_error(ValidType::Integer, n2, stub_gen)) + } + (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)), } +} - pub(crate) fn bitwise_complement(&self, n1: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(\\)"), 2); +pub(crate) fn gcd(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let gcd_atom = atom!("gcd"); + functor_stub(gcd_atom, 2) + }; - match n1 { - Number::Fixnum(n) => Ok(Number::Fixnum(!n)), - Number::Integer(n1) => Ok(Number::from(Integer::from(!&*n1))), - _ => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), + match (n1, n2) { + (Number::Fixnum(n1), Number::Fixnum(n2)) => { + let n1_i = n1.get_num() as isize; + let n2_i = n2.get_num() as isize; + + if let Some(result) = isize_gcd(n1_i, n2_i) { + Ok(Number::arena_from(result, arena)) + } else { + Ok(Number::arena_from( + Integer::from(n1_i).gcd(&Integer::from(n2_i)), + arena, + )) + } + } + (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => { + let n1 = Integer::from(n1.get_num()); + Ok(Number::arena_from(Integer::from(n2.gcd_ref(&n1)), arena)) + } + (Number::Integer(n1), Number::Integer(n2)) => { + Ok(Number::arena_from(Integer::from(n1.gcd_ref(&n2)), arena)) + } + (Number::Float(f), _) | (_, Number::Float(f)) => { + let n = Number::Float(f); + Err(numerical_type_error(ValidType::Integer, n, stub_gen)) + } + (Number::Rational(r), _) | (_, Number::Rational(r)) => { + let n = Number::Rational(r); + Err(numerical_type_error(ValidType::Integer, n, stub_gen)) } } +} - pub(crate) fn xor(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(xor)"), 2); +pub(crate) fn atan2(n1: Number, n2: Number) -> Result { + if n1.is_zero() && n2.is_zero() { + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 ^ n2)), - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - Ok(Number::from(n1 ^ &*n2)) - } - (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 ^ Integer::from(n2))), - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(&*n1 ^ &*n2))) - } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), - } + Err(undefined_eval_error(stub_gen)) + } else { + let f1 = float(n1)?; + let f2 = float(n2)?; + + unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2)) } +} - pub(crate) fn and(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(/\\)"), 2); +#[inline] +pub(crate) fn sin(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.sin()) +} - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 & n2)), - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - Ok(Number::from(n1 & &*n2)) - } - (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 & Integer::from(n2))), - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(&*n1 & &*n2))) - } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), - } +#[inline] +pub(crate) fn cos(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.cos()) +} + +#[inline] +pub(crate) fn tan(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.tan()) +} + +#[inline] +pub(crate) fn log(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.log(f64::consts::E)) +} + +#[inline] +pub(crate) fn exp(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.exp()) +} + +#[inline] +pub(crate) fn asin(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.asin()) +} + +#[inline] +pub(crate) fn acos(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.acos()) +} + +#[inline] +pub(crate) fn atan(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.atan()) +} + +#[inline] +pub(crate) fn sqrt(n1: Number) -> Result { + if n1.is_negative() { + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; + + return Err(undefined_eval_error(stub_gen)); } - pub(crate) fn or(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(\\/)"), 2); + unary_float_fn_template(n1, |f| f.sqrt()) +} - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 | n2)), - (Number::Fixnum(n1), Number::Integer(n2)) => { - let n1 = Integer::from(n1); - Ok(Number::from(n1 | &*n2)) - } - (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 | Integer::from(n2))), - (Number::Integer(n1), Number::Integer(n2)) => { - Ok(Number::from(Integer::from(&*n1 | &*n2))) - } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), +#[inline] +pub(crate) fn floor(n1: Number, arena: &mut Arena) -> Number { + rnd_i(&n1, arena) +} + +#[inline] +pub(crate) fn ceiling(n1: Number, arena: &mut Arena) -> Number { + let n1 = neg(n1, arena); + let n1 = floor(n1, arena); + + neg(n1, arena) +} + +#[inline] +pub(crate) fn truncate(n: Number, arena: &mut Arena) -> Number { + if n.is_negative() { + let n = abs(n, arena); + let n = floor(n, arena); + + neg(n, arena) + } else { + floor(n, arena) + } +} + +pub(crate) fn round(n: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let is_atom = atom!("is"); + functor_stub(is_atom, 2) + }; + + let result = add(n, Number::Float(OrderedFloat(0.5f64)), arena); + let result = try_numeric_result!(result, stub_gen)?; + + Ok(floor(result, arena)) +} + +pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result { + match n1 { + Number::Fixnum(n) => Ok(Number::Fixnum(Fixnum::build_with(!n.get_num()))), + Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)), + _ => { + let stub_gen = || { + let bitwise_atom = atom!("\\"); + functor_stub(bitwise_atom, 2) + }; + + Err(numerical_type_error(ValidType::Integer, n1, stub_gen)) } } +} - pub(crate) fn modulus(&self, x: Number, y: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(mod)"), 2); +impl MachineState { + #[inline] + pub fn get_number(&mut self, at: &ArithmeticTerm) -> Result { + match at { + &ArithmeticTerm::Reg(r) => { + let value = self.store(self.deref(self[r])); - match (x, y) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if n2 == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from(n1.rem_floor(n2))) + match Number::try_from(value) { + Ok(n) => Ok(n), + Err(_) => self.arith_eval_by_metacall(value), } } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if &*n2 == &0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - let n1 = Integer::from(n1); - Ok(Number::from( - <(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1, - )) - } - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - if n2 == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - let n2 = Integer::from(n2); - Ok(Number::from( - <(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1, - )) - } - } - (Number::Integer(x), Number::Integer(y)) => { - if &*y == &0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from( - <(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1, - )) - } + &ArithmeticTerm::Interm(i) => { + Ok(mem::replace(&mut self.interms[i - 1], Number::Fixnum(Fixnum::build_with(0)))) } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), + &ArithmeticTerm::Number(n) => Ok(n), } } - pub(crate) fn remainder(&self, n1: Number, n2: Number) -> Result { - let stub = MachineError::functor_stub(clause_name!("(rem)"), 2); + pub fn get_rational( + &mut self, + at: &ArithmeticTerm, + caller: impl Fn() -> FunctorStub + 'static, + ) -> Result, MachineStub> { + let n = self.get_number(at)?; - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if n2 == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from(n1 % n2)) - } - } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if &*n2 == &0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - let n1 = Integer::from(n1); - Ok(Number::from(n1 % &*n2)) - } - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - if n2 == 0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - let n2 = Integer::from(n2); - Ok(Number::from(&*n1 % n2)) - } - } - (Number::Integer(n1), Number::Integer(n2)) => { - if &*n2 == &0 { - Err(self - .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub)) - } else { - Ok(Number::from(Integer::from(&*n1 % &*n2))) - } - } - (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n2), - stub, - )), - (n1, _) => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, n1), - stub, - )), + match rational_from_number(n, caller, &mut self.arena) { + Ok(r) => Ok(r), + Err(e_gen) => Err(e_gen(self)) } } - pub(crate) fn max(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if n1 > n2 { - Ok(Number::Fixnum(n1)) - } else { - Ok(Number::Fixnum(n2)) - } + pub(crate) fn arith_eval_by_metacall(&mut self, value: HeapCellValue) -> Result { + let stub_gen = || functor_stub(atom!("is"), 2); + let mut iter = stackless_post_order_iter(&mut self.heap, value); + + while let Some(value) = iter.next() { + if value.is_forwarded() { + let (name, arity) = read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + (name, arity) + } + (HeapCellValueTag::Lis | HeapCellValueTag::PStr) => { + (atom!("."), 2) + } + _ => { + unreachable!() + } + ); + + std::mem::drop(iter); + + let evaluable_error = self.evaluable_error(name, arity); + let stub = stub_gen(); + + return Err(self.error_form(evaluable_error, stub)); } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if &*n2 > &n1 { - Ok(Number::Integer(n2)) - } else { - Ok(Number::Fixnum(n1)) - } - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - if &*n1 > &n2 { - Ok(Number::Integer(n1)) - } else { - Ok(Number::Fixnum(n2)) - } - } - (Number::Integer(n1), Number::Integer(n2)) => { - if n1 > n2 { - Ok(Number::Integer(n1)) - } else { - Ok(Number::Integer(n2)) - } - } - (n1, n2) => { - let stub = MachineError::functor_stub(clause_name!("max"), 2); - let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?; - let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?; + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 2 { + let a1 = self.interms.pop().unwrap(); + let a2 = self.interms.pop().unwrap(); + + match name { + atom!("+") => self.interms.push(drop_iter_on_err!( + self, + iter, + try_numeric_result!(add(a1, a2, &mut self.arena), stub_gen) + )), + atom!("-") => self.interms.push(drop_iter_on_err!( + self, + iter, + try_numeric_result!(sub(a1, a2, &mut self.arena), stub_gen) + )), + atom!("*") => self.interms.push(drop_iter_on_err!( + self, + iter, + try_numeric_result!(mul(a1, a2, &mut self.arena), stub_gen) + )), + atom!("/") => self.interms.push( + drop_iter_on_err!(self, iter, div(a1, a2)) + ), + atom!("**") => self.interms.push( + drop_iter_on_err!(self, iter, pow(a1, a2, atom!("is"))) + ), + atom!("^") => self.interms.push( + drop_iter_on_err!(self, iter, int_pow(a1, a2, &mut self.arena)) + ), + atom!("max") => self.interms.push( + drop_iter_on_err!(self, iter, max(a1, a2)) + ), + atom!("min") => self.interms.push( + drop_iter_on_err!(self, iter, min(a1, a2)) + ), + atom!("rdiv") => { + let r1 = drop_iter_on_err!( + self, + iter, + rational_from_number(a1, stub_gen, &mut self.arena) + ); + + let r2 = drop_iter_on_err!( + self, + iter, + rational_from_number(a2, stub_gen, &mut self.arena) + ); + + let result = arena_alloc!( + drop_iter_on_err!(self, iter, rdiv(r1, r2)), + self.arena + ); + + self.interms.push(Number::Rational(result)); + } + atom!("//") => self.interms.push( + drop_iter_on_err!(self, iter, idiv(a1, a2, &mut self.arena)) + ), + atom!("div") => self.interms.push( + drop_iter_on_err!(self, iter, int_floor_div(a1, a2, &mut self.arena)) + ), + atom!(">>") => self.interms.push( + drop_iter_on_err!(self, iter, shr(a1, a2, &mut self.arena)) + ), + atom!("<<") => self.interms.push( + drop_iter_on_err!(self, iter, shl(a1, a2, &mut self.arena)) + ), + atom!("/\\") => self.interms.push( + drop_iter_on_err!(self, iter, and(a1, a2, &mut self.arena)) + ), + atom!("\\/") => self.interms.push( + drop_iter_on_err!(self, iter, or(a1, a2, &mut self.arena)) + ), + atom!("xor") => self.interms.push( + drop_iter_on_err!(self, iter, xor(a1, a2, &mut self.arena)) + ), + atom!("mod") => self.interms.push( + drop_iter_on_err!(self, iter, modulus(a1, a2, &mut self.arena)) + ), + atom!("rem") => self.interms.push( + drop_iter_on_err!(self, iter, remainder(a1, a2, &mut self.arena)) + ), + atom!("atan2") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, atan2(a1, a2)) + ))), + atom!("gcd") => self.interms.push( + drop_iter_on_err!(self, iter, gcd(a1, a2, &mut self.arena)) + ), + _ => { + let evaluable_stub = functor_stub(name, 2); + let stub = stub_gen(); + + std::mem::drop(iter); + + let type_error = self.type_error(ValidType::Evaluable, evaluable_stub); + return Err(self.error_form(type_error, stub)); + } + } - Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2)))) - } - } - } + continue; + } else if arity == 1 { + let a1 = self.interms.pop().unwrap(); + + match name { + atom!("-") => self.interms.push(neg(a1, &mut self.arena)), + atom!("+") => self.interms.push(a1), + atom!("cos") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, cos(a1)) + ))), + atom!("sin") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, sin(a1)) + ))), + atom!("tan") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, tan(a1)) + ))), + atom!("sqrt") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, sqrt(a1)) + ))), + atom!("log") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, log(a1)) + ))), + atom!("exp") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, exp(a1)) + ))), + atom!("acos") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, acos(a1)) + ))), + atom!("asin") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, asin(a1)) + ))), + atom!("atan") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, atan(a1)) + ))), + atom!("abs") => self.interms.push(abs(a1, &mut self.arena)), + atom!("float") => self.interms.push(Number::Float(OrderedFloat( + drop_iter_on_err!(self, iter, float(a1)) + ))), + atom!("truncate") => self.interms.push(truncate(a1, &mut self.arena)), + atom!("round") => self.interms.push(drop_iter_on_err!(self, iter, round(a1, &mut self.arena))), + atom!("ceiling") => self.interms.push(ceiling(a1, &mut self.arena)), + atom!("floor") => self.interms.push(floor(a1, &mut self.arena)), + atom!("\\") => self.interms.push( + drop_iter_on_err!(self, iter, bitwise_complement(a1, &mut self.arena)) + ), + atom!("sign") => self.interms.push(sign(a1)), + _ => { + let evaluable_stub = functor_stub(name, 1); + std::mem::drop(iter); + + let type_error = self.type_error( + ValidType::Evaluable, + evaluable_stub, + ); - pub(crate) fn min(&self, n1: Number, n2: Number) -> Result { - match (n1, n2) { - (Number::Fixnum(n1), Number::Fixnum(n2)) => { - if n1 < n2 { - Ok(Number::Fixnum(n1)) - } else { - Ok(Number::Fixnum(n2)) + let stub = stub_gen(); + return Err(self.error_form(type_error, stub)); + } + } + + continue; + } else if arity == 0 { + match name { + atom!("pi") => { + self.interms.push(Number::Float(OrderedFloat(f64::consts::PI))); + continue; + } + atom!("e") => { + self.interms.push(Number::Float(OrderedFloat(f64::consts::E))); + continue; + } + atom!("epsilon") => { + self.interms.push(Number::Float(OrderedFloat(f64::EPSILON))); + continue; + } + _ => { + } + } + } + + std::mem::drop(iter); + + let evaluable_error = self.evaluable_error(name, arity); + let stub = stub_gen(); + + return Err(self.error_form(evaluable_error, stub)); } - } - (Number::Fixnum(n1), Number::Integer(n2)) => { - if &*n2 < &n1 { - Ok(Number::Integer(n2)) - } else { - Ok(Number::Fixnum(n1)) + (HeapCellValueTag::Fixnum, n) => { + self.interms.push(Number::Fixnum(n)); } - } - (Number::Integer(n1), Number::Fixnum(n2)) => { - if &*n1 < &n2 { - Ok(Number::Integer(n1)) - } else { - Ok(Number::Fixnum(n2)) + (HeapCellValueTag::F64, fl) => { + self.interms.push(Number::Float(**fl)); } - } - (Number::Integer(n1), Number::Integer(n2)) => { - if n1 < n2 { - Ok(Number::Integer(n1)) - } else { - Ok(Number::Integer(n2)) + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Integer, n) => { + self.interms.push(Number::Integer(n)); + } + (ArenaHeaderTag::Rational, r) => { + self.interms.push(Number::Rational(r)); + } + _ => { + std::mem::drop(iter); + + let type_error = self.type_error(ValidType::Evaluable, value); + let stub = stub_gen(); + + return Err(self.error_form(type_error, stub)); + } + ) } - } - (n1, n2) => { - let stub = MachineError::functor_stub(clause_name!("max"), 2); + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar) => { + std::mem::drop(iter); - let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?; - let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?; + let instantiation_error = self.instantiation_error(); + let stub = stub_gen(); - Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2)))) - } + return Err(self.error_form(instantiation_error, stub)); + } + _ => { + std::mem::drop(iter); + + let type_error = self.type_error(ValidType::Evaluable, value); + let stub = stub_gen(); + + return Err(self.error_form(type_error, stub)); + } + ) } + + Ok(self.interms.pop().unwrap()) } +} - pub(crate) fn sign(&self, n: Number) -> Number { - if n.is_positive() { - Number::from(1) - } else if n.is_negative() { - Number::from(-1) - } else { - Number::from(0) - } +#[cfg(test)] +mod tests { + use super::*; + use crate::machine::mock_wam::*; + + #[test] + fn arith_eval_by_metacall_tests() { + let mut wam = MachineState::new(); + let mut op_dir = default_op_dir(); + + op_dir.insert( + (atom!("+"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("-"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("-"), Fixity::Pre), + OpDesc::build_with(200, FY as u8), + ); + op_dir.insert( + (atom!("*"), Fixity::In), + OpDesc::build_with(400, YFX as u8), + ); + op_dir.insert( + (atom!("/"), Fixity::In), + OpDesc::build_with(400, YFX as u8), + ); + + let term_write_result = + parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap(); + + assert_eq!( + wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)), + Ok(Number::Fixnum(Fixnum::build_with(8))), + ); + + wam.heap.clear(); + + let term_write_result = + parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap(); + + assert_eq!( + wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)), + Ok(Number::Fixnum(Fixnum::build_with(19))), + ); + + wam.heap.clear(); + + let term_write_result = + parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap(); + + assert_eq!( + wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)), + Ok(Number::Fixnum(Fixnum::build_with(-1))) + ); } } diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index f39a2ac8..34cdd12e 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -1,13 +1,15 @@ use crate::heap_iter::*; use crate::machine::*; -use prolog_parser::temp_v; +use crate::parser::ast::*; +use crate::temp_v; +use crate::types::*; use indexmap::IndexSet; use std::cmp::Ordering; use std::vec::IntoIter; -pub(super) type Bindings = Vec<(usize, Addr)>; +pub(super) type Bindings = Vec<(usize, HeapCellValue)>; #[derive(Debug)] pub(super) struct AttrVarInitializer { @@ -37,7 +39,7 @@ impl AttrVarInitializer { } impl MachineState { - pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) { + pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: HeapCellValue) { if self.attr_var_init.bindings.is_empty() { self.attr_var_init.instigating_p = self.p.local(); @@ -53,28 +55,24 @@ impl MachineState { self.attr_var_init.bindings.push((h, addr)); } - fn populate_var_and_value_lists(&mut self) -> (Addr, Addr) { + fn populate_var_and_value_lists(&mut self) -> (HeapCellValue, HeapCellValue) { let iter = self .attr_var_init .bindings .iter() - .map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h))); + .map(|(ref h, _)| attr_var_as_cell!(*h)); - let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); + let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter)); - let iter = self - .attr_var_init - .bindings - .drain(0..) - .map(|(_, addr)| HeapCellValue::Addr(addr)); + let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v); - let value_list_addr = Addr::HeapCell(self.heap.to_list(iter)); + let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter)); (var_list_addr, value_list_addr) } fn verify_attributes(&mut self) { for (h, _) in &self.attr_var_init.bindings { - self.heap[*h] = HeapCellValue::Addr(Addr::AttrVar(*h)); + self.heap[*h] = attr_var_as_cell!(*h); } let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists(); @@ -83,19 +81,26 @@ impl MachineState { self[temp_v!(2)] = value_list_addr; } - pub(super) fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter { + pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter { let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..] .iter() - .filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) { - Addr::AttrVar(h) => Some(Addr::AttrVar(h)), - _ => None, + .filter_map(|h| { + read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))), //Addr::HeapCell(*h))) { + (HeapCellValueTag::AttrVar, h) => { + Some(attr_var_as_cell!(h)) + } + _ => { + None + } + ) }) .collect(); - attr_vars - .sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2).unwrap_or(Ordering::Less)); + attr_vars.sort_unstable_by(|a1, a2| { + compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less) + }); - self.term_dedup(&mut attr_vars); + attr_vars.dedup(); attr_vars.into_iter() } @@ -109,8 +114,10 @@ impl MachineState { self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)]; } - self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = Addr::CutPoint(self.b0); - self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = Addr::Usize(self.num_of_args); + self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.b0 as i64)); + self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = + fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64)); self.verify_attributes(); @@ -119,33 +126,51 @@ impl MachineState { self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); } - pub(super) fn attr_vars_of_term(&self, addr: Addr) -> Vec { + pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec { let mut seen_set = IndexSet::new(); let mut seen_vars = vec![]; - let mut iter = self.acyclic_pre_order_iter(addr); - - while let Some(addr) = iter.next() { - if let HeapCellValue::Addr(Addr::AttrVar(h)) = self.heap.index_addr(&addr).as_ref() { - if seen_set.contains(h) { - continue; - } - - seen_vars.push(addr); - seen_set.insert(*h); - - let mut l = h + 1; - let mut list_elements = vec![]; - - while let Addr::Lis(elem) = self.store(self.deref(Addr::HeapCell(l))) { - list_elements.push(self.heap[elem].as_addr(elem)); - l = elem + 1; + let mut iter = stackful_preorder_iter(&mut self.heap, cell); + + while let Some(value) = iter.next() { + read_heap_cell!(value, + (HeapCellValueTag::AttrVar, h) => { + if seen_set.contains(&h) { + continue; + } + + seen_vars.push(value); + seen_set.insert(h); + + let mut l = h + 1; + // let mut list_elements = vec![]; + // let iter_stack_len = iter.stack_len(); + + loop { + read_heap_cell!(iter.heap[l], + (HeapCellValueTag::Lis) => { + iter.push_stack(l); + // l = elem + 1; + break; + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { + if h == l { + break; + } else { + l = h; + } + } + _ => { + break; + } + ) + } + + // iter.stack_slice_from(iter_stack_len ..).reverse(); } - - for element in list_elements.into_iter().rev() { - iter.stack().push(element); + _ => { } - } + ); } seen_vars diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs index bb21462e..54db570f 100644 --- a/src/machine/code_repo.rs +++ b/src/machine/code_repo.rs @@ -3,7 +3,7 @@ use crate::instructions::*; use crate::machine::machine_indices::*; #[derive(Debug)] -pub(crate) struct CodeRepo { +pub struct CodeRepo { pub(super) code: Code, } diff --git a/src/machine/compile.rs b/src/machine/compile.rs index ef99df34..72ec57c4 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1,18 +1,22 @@ -use prolog_parser::clause_name; - +use crate::atom_table::*; use crate::codegen::*; use crate::debray_allocator::*; -use crate::indexing::{merge_clause_index, remove_index, IndexingCodePtr}; +use crate::forms::*; +use crate::indexing::{merge_clause_index, remove_index}; +use crate::instructions::*; use crate::machine::load_state::*; use crate::machine::loader::*; +use crate::machine::machine_errors::*; use crate::machine::preprocessor::*; use crate::machine::term_stream::*; use crate::machine::*; +use crate::parser::ast::*; use slice_deque::{sdeq, SliceDeque}; use std::cell::Cell; use std::collections::VecDeque; +use std::mem; use std::ops::Range; struct StandaloneCompileResult { @@ -25,17 +29,21 @@ pub(super) fn bootstrapping_compile( wam: &mut Machine, listing_src: ListingSource, ) -> Result<(), SessionError> { - let stream = &mut parsing_stream(stream)?; - let term_stream = BootstrappingTermStream::from_prolog_stream( + let (wam_prelude, machine_st) = wam.prelude_view_and_machine_st(); + + let term_stream = BootstrappingTermStream::from_char_reader( stream, - wam.machine_st.atom_tbl.clone(), - wam.machine_st.flags, + machine_st, listing_src, ); - let loader = Loader::new(term_stream, wam); - loader.load()?; + let payload = BootstrappingLoadState( + LoadStatePayload::new(wam_prelude.code_repo.code.len(), term_stream) + ); + let loader: Loader<'_, BootstrappingLoadState> = Loader { payload, wam_prelude }; + + loader.load()?; Ok(()) } @@ -57,7 +65,7 @@ pub(super) fn compile_appendix( mut queue: VecDeque, jmp_by_locs: Vec, non_counted_bt: bool, - atom_tbl: TabledData, + atom_tbl: &mut AtomTable, ) -> Result<(), CompilationError> { let mut jmp_by_locs = VecDeque::from(jmp_by_locs); @@ -80,7 +88,7 @@ pub(super) fn compile_appendix( non_counted_bt, }; - let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); + let mut cg = CodeGenerator::::new(atom_tbl, settings); let tl = queue.pop_front().unwrap(); let decl_code = compile_relation(&mut cg, &tl)?; @@ -164,6 +172,7 @@ fn merge_indices( target_index_loc: usize, index_range: Range, skeleton: &mut [ClauseIndexInfo], + retracted_dynamic_clauses: &Option>, retraction_info: &mut RetractionInfo, ) { for clause_index in index_range { @@ -183,6 +192,7 @@ fn merge_indices( merge_clause_index( target_indexing_line, &mut skeleton[0..clause_index + 1], + retracted_dynamic_clauses, clause_loc, AppendOrPrepend::Append, ); @@ -422,13 +432,24 @@ fn delete_from_skeleton( skeleton.core.clause_assert_margin -= 1; } - retraction_info.push_record(RetractionRecord::RemovedSkeletonClause( - compilation_target, - key, - target_pos, - clause_index_info, - clause_clause_loc, - )); + if skeleton.core.is_dynamic { + skeleton.core.add_retracted_dynamic_clause_info(clause_index_info); + + retraction_info.push_record(RetractionRecord::RemovedDynamicSkeletonClause( + compilation_target, + key, + target_pos, + clause_clause_loc, + )); + } else { + retraction_info.push_record(RetractionRecord::RemovedSkeletonClause( + compilation_target, + key, + target_pos, + clause_index_info, + clause_clause_loc, + )); + } clause_clause_loc } @@ -617,7 +638,6 @@ fn internalize_choice_instr_at( } Line::Choice(ChoiceInstruction::TryMeElse(0)) => { retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, 0)); - code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0)); } Line::Choice(ChoiceInstruction::TryMeElse(o)) => { @@ -804,8 +824,8 @@ fn finalize_retract( retraction_info: &mut RetractionInfo, ) -> usize { let clause_clause_loc = delete_from_skeleton( - compilation_target.clone(), - key.clone(), + compilation_target, + key, skeleton, target_pos, retraction_info, @@ -920,7 +940,7 @@ fn prepend_compiled_clause( retraction_info.push_record(RetractionRecord::SkeletonClauseStartReplaced( compilation_target, - key.clone(), + key, 1, skeleton.clauses[1].clause_start, )); @@ -999,6 +1019,7 @@ fn prepend_compiled_clause( merge_clause_index( target_indexing_line, &mut skeleton.clauses, + &skeleton.core.retracted_dynamic_clauses, clause_loc + 2, // == skeleton.clauses[0].clause_start AppendOrPrepend::Prepend, ); @@ -1202,6 +1223,7 @@ fn append_compiled_clause( merge_clause_index( target_indexing_line, &mut skeleton.clauses[lower_bound..], + &skeleton.core.retracted_dynamic_clauses, clause_loc, AppendOrPrepend::Append, ); @@ -1322,21 +1344,20 @@ fn print_overwrite_warning( _ => {} } - println!("Warning: overwriting {}/{}", key.0, key.1); + println!("Warning: overwriting {}/{}", key.0.as_str(), key.1); } -impl<'a> LoadState<'a> { - pub(super) fn listing_src_file_name(&self) -> Option { - if let Some(load_context) = self.wam.load_contexts.last() { +impl<'a, LS: LoadState<'a>> Loader<'a, LS> { + pub(super) fn listing_src_file_name(&mut self) -> Option { + if let Some(load_context) = self.wam_prelude.load_contexts.last() { if !load_context.path.is_file() { return None; } if let Some(path_str) = load_context.path.to_str() { if !path_str.is_empty() { - return Some(clause_name!( - path_str.to_string(), - self.wam.machine_st.atom_tbl + return Some(LS::machine_st(&mut self.payload).atom_tbl.build_with( + path_str )); } } @@ -1349,14 +1370,13 @@ impl<'a> LoadState<'a> { &mut self, term: Term, settings: CodeGenSettings, - atom_tbl: TabledData, ) -> Result { - let mut preprocessor = Preprocessor::new(); - let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); + let mut preprocessor = Preprocessor::new(LS::machine_st(&mut self.payload).flags); let clause = self.try_term_to_tl(term, &mut preprocessor)?; let queue = preprocessor.parse_queue(self)?; + let mut cg = CodeGenerator::::new(&mut LS::machine_st(&mut self.payload).atom_tbl, settings); let mut clause_code = cg.compile_predicate(&vec![clause])?; compile_appendix( @@ -1364,7 +1384,7 @@ impl<'a> LoadState<'a> { queue, cg.jmp_by_locs, settings.non_counted_bt, - atom_tbl, + cg.atom_tbl, )?; Ok(StandaloneCompileResult { @@ -1376,26 +1396,28 @@ impl<'a> LoadState<'a> { fn compile( &mut self, key: PredicateKey, - predicates: &mut PredicateQueue, + mut predicates: PredicateQueue, settings: CodeGenSettings, ) -> Result { - let code_index = - self.get_or_insert_code_index(key.clone(), predicates.compilation_target.clone()); + let code_index = self.get_or_insert_code_index(key, predicates.compilation_target); - let code_len = self.wam.code_repo.code.len(); + let code_len = self.wam_prelude.code_repo.code.len(); let mut code_ptr = code_len; - let mut cg = - CodeGenerator::::new(self.wam.machine_st.atom_tbl.clone(), settings); - let mut clauses = vec![]; - let mut preprocessor = Preprocessor::new(); + let mut preprocessor = Preprocessor::new(LS::machine_st(&mut self.payload).flags); for term in predicates.predicates.drain(0..) { clauses.push(self.try_term_to_tl(term, &mut preprocessor)?); } let queue = preprocessor.parse_queue(self)?; + + let mut cg = CodeGenerator::::new( + &mut LS::machine_st(&mut self.payload).atom_tbl, + settings, + ); + let mut code = cg.compile_predicate(&clauses)?; compile_appendix( @@ -1403,7 +1425,7 @@ impl<'a> LoadState<'a> { queue, cg.jmp_by_locs, settings.non_counted_bt, - self.wam.machine_st.atom_tbl.clone(), + cg.atom_tbl, )?; if settings.is_extensible { @@ -1424,34 +1446,38 @@ impl<'a> LoadState<'a> { } match self - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&predicates.compilation_target, &key) { Some(skeleton) => { - self.retraction_info - .push_record(RetractionRecord::SkeletonClauseTruncateBack( - predicates.compilation_target.clone(), - key.clone(), - skeleton.clauses.len(), - )); + let skeleton_clause_len = skeleton.clauses.len(); skeleton.clauses.extend(cg.skeleton.clauses.into_iter()); skeleton .core .clause_clause_locs .extend_from_slice(&clause_clause_locs[0..]); + + self.payload.retraction_info + .push_record(RetractionRecord::SkeletonClauseTruncateBack( + predicates.compilation_target, + key, + skeleton_clause_len, + )); } None => { cg.skeleton - .core - .clause_clause_locs - .extend_from_slice(&clause_clause_locs[0..]); + .core + .clause_clause_locs + .extend_from_slice(&clause_clause_locs[0..]); + + let skeleton = cg.skeleton; self.add_extensible_predicate( - key.clone(), - cg.skeleton, - predicates.compilation_target.clone(), + key, + skeleton, + predicates.compilation_target, ); } }; @@ -1477,14 +1503,14 @@ impl<'a> LoadState<'a> { }; set_code_index( - &mut self.retraction_info, + &mut self.payload.retraction_info, &predicates.compilation_target, key, &code_index, index_ptr, ); - self.wam.code_repo.code.extend(code.into_iter()); + self.wam_prelude.code_repo.code.extend(code.into_iter()); Ok(code_index) } @@ -1494,18 +1520,22 @@ impl<'a> LoadState<'a> { key: &PredicateKey, clause_clause_locs: SliceDeque, ) { - match self.wam.indices.get_local_predicate_skeleton_mut( - self.compilation_target.clone(), - compilation_target.clone(), - self.listing_src_file_name(), - key.clone(), + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + self.payload.compilation_target, + *compilation_target, + listing_src_file_name, + *key, ) { Some(skeleton) => { - self.retraction_info.push_record( + let payload_compilation_target = self.payload.compilation_target; + + self.payload.retraction_info.push_record( RetractionRecord::SkeletonLocalClauseTruncateBack( - self.compilation_target.clone(), - compilation_target.clone(), - key.clone(), + payload_compilation_target, + *compilation_target, + *key, skeleton.clause_clause_locs.len(), ), ); @@ -1519,8 +1549,8 @@ impl<'a> LoadState<'a> { skeleton.clause_clause_locs = clause_clause_locs; self.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + *compilation_target, + *key, skeleton, ); } @@ -1533,18 +1563,22 @@ impl<'a> LoadState<'a> { key: &PredicateKey, code_len: usize, ) { - match self.wam.indices.get_local_predicate_skeleton_mut( - self.compilation_target.clone(), - compilation_target.clone(), - self.listing_src_file_name(), - key.clone(), + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + self.payload.compilation_target, + *compilation_target, + listing_src_file_name, + *key, ) { Some(skeleton) => { - self.retraction_info.push_record( + let payload_compilation_target = self.payload.compilation_target; + + self.payload.retraction_info.push_record( RetractionRecord::SkeletonLocalClauseClausePopFront( - self.compilation_target.clone(), - compilation_target.clone(), - key.clone(), + payload_compilation_target, + *compilation_target, + *key, ), ); @@ -1555,8 +1589,8 @@ impl<'a> LoadState<'a> { skeleton.clause_clause_locs.push_front(code_len); self.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + *compilation_target, + *key, skeleton, ); } @@ -1569,18 +1603,22 @@ impl<'a> LoadState<'a> { key: &PredicateKey, code_len: usize, ) { - match self.wam.indices.get_local_predicate_skeleton_mut( - self.compilation_target.clone(), - compilation_target.clone(), - self.listing_src_file_name(), - key.clone(), + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + self.payload.compilation_target, + *compilation_target, + listing_src_file_name, + *key, ) { Some(skeleton) => { - self.retraction_info.push_record( + let payload_compilation_target = self.payload.compilation_target; + + self.payload.retraction_info.push_record( RetractionRecord::SkeletonLocalClauseClausePopBack( - self.compilation_target.clone(), - compilation_target.clone(), - key.clone(), + payload_compilation_target, + *compilation_target, + *key, ), ); @@ -1591,8 +1629,8 @@ impl<'a> LoadState<'a> { skeleton.clause_clause_locs.push_back(code_len); self.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + *compilation_target, + *key, skeleton, ); } @@ -1608,13 +1646,13 @@ impl<'a> LoadState<'a> { append_or_prepend: AppendOrPrepend, ) -> Result { let settings = match self - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&compilation_target, &key) { Some(skeleton) if !skeleton.clauses.is_empty() => CodeGenSettings { global_clock_tick: if skeleton.core.is_dynamic { - Some(self.wam.machine_st.global_clock) + Some(LS::machine_st(&mut self.payload).global_clock) } else { None }, @@ -1625,7 +1663,7 @@ impl<'a> LoadState<'a> { let settings = CodeGenSettings { global_clock_tick: if let Some(skeleton) = skeleton_opt { if skeleton.core.is_dynamic { - Some(self.wam.machine_st.global_clock) + Some(LS::machine_st(&mut self.payload).global_clock) } else { None } @@ -1639,21 +1677,19 @@ impl<'a> LoadState<'a> { let mut predicate_queue = predicate_queue![clause]; predicate_queue.compilation_target = compilation_target; - return self.compile(key, &mut predicate_queue, settings); + return self.compile(key, predicate_queue, settings); } }; - let atom_tbl = self.wam.machine_st.atom_tbl.clone(); - let StandaloneCompileResult { clause_code, mut standalone_skeleton, - } = self.compile_standalone_clause(clause, settings, atom_tbl)?; + } = self.compile_standalone_clause(clause, settings)?; - let code_len = self.wam.code_repo.code.len(); + let code_len = self.wam_prelude.code_repo.code.len(); let skeleton = match self - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&compilation_target, &key) { @@ -1668,28 +1704,30 @@ impl<'a> LoadState<'a> { skeleton.core.clause_clause_locs.push_back(code_len); - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::SkeletonClausePopBack( - compilation_target.clone(), - key.clone(), + compilation_target, + key, )); + let global_clock = LS::machine_st(&mut self.payload).global_clock; + let result = append_compiled_clause( - &mut self.wam.code_repo.code, + &mut self.wam_prelude.code_repo.code, clause_code, skeleton, - &mut self.retraction_info, - self.wam.machine_st.global_clock, + &mut self.payload.retraction_info, + global_clock, ); self.push_back_to_local_predicate_skeleton(&compilation_target, &key, code_len); let code_index = - self.get_or_insert_code_index(key.clone(), compilation_target.clone()); + self.get_or_insert_code_index(key, compilation_target); if let Some(new_code_ptr) = result { set_code_index( - &mut self.retraction_info, + &mut self.payload.retraction_info, &compilation_target, key, &code_index, @@ -1706,29 +1744,31 @@ impl<'a> LoadState<'a> { skeleton.core.clause_clause_locs.push_front(code_len); skeleton.core.clause_assert_margin += 1; - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::SkeletonClausePopFront( - compilation_target.clone(), - key.clone(), + compilation_target, + key, )); + let global_clock = LS::machine_st(&mut self.payload).global_clock; + let new_code_ptr = prepend_compiled_clause( - &mut self.wam.code_repo.code, - compilation_target.clone(), - key.clone(), + &mut self.wam_prelude.code_repo.code, + compilation_target, + key, clause_code, skeleton, - &mut self.retraction_info, - self.wam.machine_st.global_clock, + &mut self.payload.retraction_info, + global_clock, ); self.push_front_to_local_predicate_skeleton(&compilation_target, &key, code_len); let code_index = - self.get_or_insert_code_index(key.clone(), compilation_target.clone()); + self.get_or_insert_code_index(key, compilation_target); set_code_index( - &mut self.retraction_info, + &mut self.payload.retraction_info, &compilation_target, key, &code_index, @@ -1742,9 +1782,9 @@ impl<'a> LoadState<'a> { pub(super) fn retract_dynamic_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize { let skeleton = match self - .wam + .wam_prelude .indices - .get_predicate_skeleton_mut(&self.compilation_target, &key) + .get_predicate_skeleton_mut(&self.payload.compilation_target, &key) { Some(skeleton) => skeleton, None => { @@ -1757,38 +1797,38 @@ impl<'a> LoadState<'a> { .switch_on_term_loc() { Some(index_loc) => find_inner_choice_instr( - &self.wam.code_repo.code, + &self.wam_prelude.code_repo.code, skeleton.clauses[target_pos].clause_start, index_loc, ), None => skeleton.clauses[target_pos].clause_start, }; - match &mut self.wam.code_repo.code[clause_loc] { + match &mut self.wam_prelude.code_repo.code[clause_loc] { Line::Choice(ChoiceInstruction::DynamicElse(_, ref mut d, _)) | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, ref mut d, _)) => { - *d = Death::Finite(self.wam.machine_st.global_clock); + *d = Death::Finite(LS::machine_st(&mut self.payload).global_clock); } _ => unreachable!(), } delete_from_skeleton( - self.compilation_target.clone(), + self.payload.compilation_target, key, skeleton, target_pos, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) } pub(super) fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize { - let code_index = - self.get_or_insert_code_index(key.clone(), self.compilation_target.clone()); + let payload_compilation_target = self.payload.compilation_target; + let code_index = self.get_or_insert_code_index(key, payload_compilation_target); let skeleton = match self - .wam + .wam_prelude .indices - .get_predicate_skeleton_mut(&self.compilation_target, &key) + .get_predicate_skeleton_mut(&payload_compilation_target, &key) { Some(skeleton) => skeleton, None => { @@ -1796,7 +1836,7 @@ impl<'a> LoadState<'a> { } }; - let code = &mut self.wam.code_repo.code; + let code = &mut self.wam_prelude.code_repo.code; let lower_bound = lower_bound_of_target_clause(skeleton, target_pos); let lower_bound_is_unindexed = !skeleton.clauses[lower_bound].opt_arg_index_key.is_some(); @@ -1818,13 +1858,13 @@ impl<'a> LoadState<'a> { code, &skeleton.clauses[target_pos].opt_arg_index_key, inner_clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); match derelictize_try_me_else( code, inner_clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) { Some(offset) => { let instr_loc = find_inner_choice_instr( @@ -1836,20 +1876,20 @@ impl<'a> LoadState<'a> { let clause_loc = blunt_leading_choice_instr( code, instr_loc, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); set_switch_var_offset( code, index_loc, clause_loc - index_loc, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); - self.retraction_info.push_record( + self.payload.retraction_info.push_record( RetractionRecord::SkeletonClauseStartReplaced( - self.compilation_target.clone(), - key.clone(), + payload_compilation_target, + key, target_pos + 1, skeleton.clauses[target_pos + 1].clause_start, ), @@ -1866,12 +1906,12 @@ impl<'a> LoadState<'a> { return finalize_retract( key, - self.compilation_target.clone(), + payload_compilation_target, skeleton, code_index, target_pos, index_ptr_opt, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); } None => { @@ -1883,24 +1923,24 @@ impl<'a> LoadState<'a> { code, preceding_choice_instr_loc, skeleton.clauses[target_pos].clause_start - 2, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) } else { remove_leading_unindexed_clause( code, skeleton.clauses[target_pos].clause_start - 2, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) }; return finalize_retract( key, - self.compilation_target.clone(), + payload_compilation_target, skeleton, code_index, target_pos, index_ptr_opt, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); } } @@ -1938,7 +1978,7 @@ impl<'a> LoadState<'a> { match target_indexing_line { Line::IndexingCode(indexing_code) => { - self.retraction_info.push_record( + self.payload.retraction_info.push_record( RetractionRecord::ReplacedIndexingLine( target_indexing_loc, indexing_code, @@ -1953,7 +1993,7 @@ impl<'a> LoadState<'a> { skeleton, lower_bound, target_pos + 1, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); merge_indices( @@ -1961,14 +2001,15 @@ impl<'a> LoadState<'a> { later_indexing_loc, 0..target_pos - lower_bound, &mut skeleton.clauses[lower_bound..], - &mut self.retraction_info, + &skeleton.core.retracted_dynamic_clauses, + &mut self.payload.retraction_info, ); set_switch_var_offset( code, later_indexing_loc, lower_bound_clause_start - later_indexing_loc, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); } _ => { @@ -1977,7 +2018,7 @@ impl<'a> LoadState<'a> { skeleton, lower_bound, target_pos + 1, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); merge_indices( @@ -1985,14 +2026,15 @@ impl<'a> LoadState<'a> { target_indexing_loc, target_pos + 1 - lower_bound..skeleton.clauses.len() - lower_bound, &mut skeleton.clauses[lower_bound..], - &mut self.retraction_info, + &skeleton.core.retracted_dynamic_clauses, + &mut self.payload.retraction_info, ); set_switch_var_offset_to_choice_instr( code, target_indexing_loc, lower_bound_clause_start - target_indexing_loc, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); } }; @@ -2005,7 +2047,7 @@ impl<'a> LoadState<'a> { code, &skeleton.clauses[target_pos].opt_arg_index_key, skeleton.clauses[target_pos].clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); match skeleton.clauses[target_pos] @@ -2023,7 +2065,7 @@ impl<'a> LoadState<'a> { code, preceding_choice_instr_loc, skeleton.clauses[target_pos].clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); match &mut code[preceding_choice_instr_loc] { @@ -2032,7 +2074,7 @@ impl<'a> LoadState<'a> { code, index_loc, preceding_choice_instr_loc + 1 - index_loc, - &mut self.retraction_info, + &mut self.payload.retraction_info, ); } _ => {} @@ -2052,7 +2094,7 @@ impl<'a> LoadState<'a> { code, preceding_choice_instr_loc, skeleton.clauses[target_pos].clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) } } @@ -2060,7 +2102,7 @@ impl<'a> LoadState<'a> { remove_leading_unindexed_clause( code, skeleton.clauses[target_pos].clause_start, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) } } @@ -2068,17 +2110,17 @@ impl<'a> LoadState<'a> { finalize_retract( key, - self.compilation_target.clone(), + payload_compilation_target, skeleton, code_index, target_pos, index_ptr_opt, - &mut self.retraction_info, + &mut self.payload.retraction_info, ) } } -impl<'a, TS: TermStream> Loader<'a, TS> { +impl<'a, LS: LoadState<'a>> Loader<'a, LS> { pub(super) fn compile_clause_clauses>( &mut self, key: PredicateKey, @@ -2089,24 +2131,23 @@ impl<'a, TS: TermStream> Loader<'a, TS> { let clause_predicates = clause_clauses.map(|(head, body)| { Term::Clause( Cell::default(), - clause_name!("$clause"), - vec![Box::new(head), Box::new(body)], - None, + atom!("$clause"), + vec![head, body], ) }); let clause_clause_compilation_target = match compilation_target { - CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), - _ => compilation_target.clone(), + CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), + _ => compilation_target, }; let mut num_clause_predicates = 0; for clause_term in clause_predicates { - self.load_state.incremental_compile_clause( - (clause_name!("$clause"), 2), + self.incremental_compile_clause( + (atom!("$clause"), 2), clause_term, - clause_clause_compilation_target.clone(), + clause_clause_compilation_target, false, // non_counted_bt is false. append_or_prepend, )?; @@ -2115,8 +2156,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } let locs_vec: Vec<_> = match self - .load_state - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&compilation_target, &key) { @@ -2136,9 +2176,9 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } }; - match self.load_state.wam.indices.get_predicate_skeleton_mut( + match self.wam_prelude.indices.get_predicate_skeleton_mut( &clause_clause_compilation_target, - &(clause_name!("$clause"), 2), + &(atom!("$clause"), 2), ) { Some(skeleton) if append_or_prepend.is_append() => { for _ in 0..num_clause_predicates { @@ -2168,6 +2208,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> { let key = self + .payload .predicates .first() .and_then(|cl| { @@ -2176,23 +2217,24 @@ impl<'a, TS: TermStream> Loader<'a, TS> { }) .ok_or(SessionError::NamelessEntry)?; + let listing_src_file_name = self.listing_src_file_name(); + let payload_compilation_target = self.payload.compilation_target; + let mut predicate_info = self - .load_state - .wam + .wam_prelude .indices - .get_predicate_skeleton(&self.predicates.compilation_target, &key) + .get_predicate_skeleton(&self.payload.predicates.compilation_target, &key) .map(|skeleton| skeleton.predicate_info()) .unwrap_or_default(); let local_predicate_info = self - .load_state - .wam + .wam_prelude .indices .get_local_predicate_skeleton( - self.load_state.compilation_target.clone(), - self.predicates.compilation_target.clone(), - self.load_state.listing_src_file_name(), - key.clone(), + payload_compilation_target, + self.payload.predicates.compilation_target, + listing_src_file_name, + key, ) .map(|skeleton| skeleton.predicate_info()) .unwrap_or_default(); @@ -2202,54 +2244,55 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } let do_incremental_compile = - if self.load_state.compilation_target == self.predicates.compilation_target { + if payload_compilation_target == self.payload.predicates.compilation_target { predicate_info.compile_incrementally() } else { local_predicate_info.is_multifile && predicate_info.compile_incrementally() }; - let predicates_len = self.predicates.len(); - let non_counted_bt = self.non_counted_bt_preds.contains(&key); + let predicates_len = self.payload.predicates.len(); + let non_counted_bt = self.payload.non_counted_bt_preds.contains(&key); if do_incremental_compile { - for term in self.predicates.predicates.drain(0..) { - self.load_state.incremental_compile_clause( - key.clone(), + let predicates = self.payload.predicates.take(); + + for term in predicates.predicates { + self.incremental_compile_clause( + key, term, - self.predicates.compilation_target.clone(), + payload_compilation_target, non_counted_bt, AppendOrPrepend::Append, )?; } } else { - if self.load_state.compilation_target != self.predicates.compilation_target { + if payload_compilation_target != self.payload.predicates.compilation_target { if !local_predicate_info.is_extensible { if predicate_info.is_multifile { println!( "Warning: overwriting multifile predicate {}:{}/{} because \ it was not locally declared multifile.", - self.predicates.compilation_target, key.0, key.1 + self.payload.predicates.compilation_target, key.0.as_str(), key.1 ); } if let Some(skeleton) = self - .load_state - .wam + .wam_prelude .indices - .remove_predicate_skeleton(&self.predicates.compilation_target, &key) + .remove_predicate_skeleton(&self.payload.predicates.compilation_target, &key) { if predicate_info.is_dynamic { let clause_clause_compilation_target = - match &self.predicates.compilation_target { + match self.payload.predicates.compilation_target { CompilationTarget::User => { - CompilationTarget::Module(clause_name!("builtins")) + CompilationTarget::Module(atom!("builtins")) } - module => module.clone(), + module => module, }; - self.load_state.retract_local_clauses_by_locs( + self.retract_local_clauses_by_locs( clause_clause_compilation_target, - (clause_name!("$clause"), 2), + (atom!("$clause"), 2), (0..skeleton.clauses.len()).map(Some).collect(), false, // the builtin M:'$clause'/2 is never dynamic. ); @@ -2257,10 +2300,10 @@ impl<'a, TS: TermStream> Loader<'a, TS> { predicate_info.is_dynamic = false; } - self.load_state.retraction_info.push_record( + self.payload.retraction_info.push_record( RetractionRecord::RemovedSkeleton( - self.predicates.compilation_target.clone(), - key.clone(), + payload_compilation_target, + key, skeleton, ), ); @@ -2270,7 +2313,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { let settings = CodeGenSettings { global_clock_tick: if predicate_info.is_dynamic { - Some(self.load_state.wam.machine_st.global_clock) + Some(LS::machine_st(&mut self.payload).global_clock) } else { None }, @@ -2278,20 +2321,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> { non_counted_bt, }; - let code_index = - self.load_state - .compile(key.clone(), &mut self.predicates, settings)?; + let predicates = self.payload.predicates.take(); + let code_index = self.compile(key, predicates, settings)?; - if let Some(filename) = self.load_state.listing_src_file_name() { - match self.load_state.wam.indices.modules.get_mut(&filename) { + if let Some(filename) = self.listing_src_file_name() { + match self.wam_prelude.indices.modules.get_mut(&filename) { Some(ref mut module) => { let index_ptr = code_index.get(); - let code_index = module.code_dir.entry(key.clone()).or_insert(code_index); + let code_index = module.code_dir.entry(key).or_insert(code_index); set_code_index( - &mut self.load_state.retraction_info, + &mut self.payload.retraction_info, &CompilationTarget::Module(filename), - key.clone(), + key, &code_index, index_ptr, ); @@ -2302,13 +2344,14 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } if predicate_info.is_dynamic { - self.load_state.wam.machine_st.global_clock += 1; + LS::machine_st(&mut self.payload).global_clock += 1; - let clauses_vec: Vec<_> = self.clause_clauses.drain(0..predicates_len).collect(); + let clauses_vec: Vec<_> = self.payload + .clause_clauses.drain(0..predicates_len).collect(); self.compile_clause_clauses( key, - self.predicates.compilation_target.clone(), + payload_compilation_target, clauses_vec.into_iter(), AppendOrPrepend::Append, )?; diff --git a/src/machine/copier.rs b/src/machine/copier.rs index fdd52c96..bab1d110 100644 --- a/src/machine/copier.rs +++ b/src/machine/copier.rs @@ -1,5 +1,6 @@ -use crate::machine::machine_indices::*; +use crate::atom_table::*; use crate::machine::stack::*; +use crate::types::*; use std::mem; use std::ops::IndexMut; @@ -7,20 +8,24 @@ use std::ops::IndexMut; type Trail = Vec<(Ref, HeapCellValue)>; #[derive(Debug, Clone, Copy)] -pub(crate) enum AttrVarPolicy { +pub enum AttrVarPolicy { DeepCopy, StripAttributes, } -pub(crate) trait CopierTarget: IndexMut { - fn deref(&self, val: Addr) -> Addr; - fn push(&mut self, val: HeapCellValue); +pub trait CopierTarget: IndexMut { + fn store(&self, value: HeapCellValue) -> HeapCellValue; + fn deref(&self, value: HeapCellValue) -> HeapCellValue; + fn push(&mut self, value: HeapCellValue); fn stack(&mut self) -> &mut Stack; - fn store(&self, val: Addr) -> Addr; fn threshold(&self) -> usize; } -pub(crate) fn copy_term(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) { +pub(crate) fn copy_term( + target: T, + addr: HeapCellValue, + attr_var_policy: AttrVarPolicy, +) { let mut copy_term_state = CopyTermState::new(target, attr_var_policy); copy_term_state.copy_term_impl(addr); } @@ -47,50 +52,51 @@ impl CopyTermState { #[inline] fn value_at_scan(&mut self) -> &mut HeapCellValue { - let scan = self.scan; - &mut self.target[scan] + &mut self.target[self.scan] } fn trail_list_cell(&mut self, addr: usize, threshold: usize) { - let trail_item = mem::replace( - &mut self.target[addr], - HeapCellValue::Addr(Addr::Lis(threshold)), - ); - - self.trail.push((Ref::HeapCell(addr), trail_item)); + let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold)); + self.trail.push((Ref::heap_cell(addr), trail_item)); } fn copy_list(&mut self, addr: usize) { for offset in 0..2 { - if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) { - if h >= self.old_h { - *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h)); - self.scan += 1; + read_heap_cell!(self.target[addr + offset], + (HeapCellValueTag::Lis, h) => { + if h >= self.old_h { + *self.value_at_scan() = list_loc_as_cell!(h); + self.scan += 1; - return; + return; + } } - } + _ => { + } + ) } let threshold = self.target.threshold(); - *self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold)); + *self.value_at_scan() = list_loc_as_cell!(threshold); for i in 0..2 { - let hcv = self.target[addr + i].context_free_clone(); + let hcv = self.target[addr + i]; self.target.push(hcv); } let cdr = self .target - .store(self.target.deref(Addr::HeapCell(addr + 1))); + .store(self.target.deref(heap_loc_as_cell!(addr + 1))); - if !cdr.is_ref() { + if !cdr.is_var() { self.trail_list_cell(addr + 1, threshold); } else { - let car = self.target.store(self.target.deref(Addr::HeapCell(addr))); + let car = self + .target + .store(self.target.deref(heap_loc_as_cell!(addr))); - if !car.is_ref() { + if !car.is_var() { self.trail_list_cell(addr, threshold); } } @@ -98,187 +104,208 @@ impl CopyTermState { self.scan += 1; } - fn copy_partial_string(&mut self, addr: usize, n: usize) { - if let &HeapCellValue::Addr(Addr::PStrLocation(h, _)) = &self.target[addr] { - if h >= self.old_h { - *self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, n)); - self.scan += 1; + fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) { + read_heap_cell!(self.target[pstr_loc], + (HeapCellValueTag::PStrLoc, h) => { + if h >= self.old_h { + *self.value_at_scan() = match scan_tag { + HeapCellValueTag::PStrLoc => { + pstr_loc_as_cell!(h) + } + tag => { + debug_assert!(tag == HeapCellValueTag::PStrOffset); + pstr_offset_as_cell!(h) + } + }; - return; + self.scan += 1; + return; + } } - } + _ => {} + ); let threshold = self.target.threshold(); - *self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(threshold, n)); - + *self.value_at_scan() = pstr_loc_as_cell!(threshold); self.scan += 1; - let (pstr, has_tail) = match &self.target[addr] { - &HeapCellValue::PartialString(ref pstr, has_tail) => { - (pstr.clone_from_offset(0), has_tail) - } - _ => { - unreachable!() - } - }; - - self.target - .push(HeapCellValue::PartialString(pstr, has_tail)); - - let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, n)); - - let trail_item = mem::replace(&mut self.target[addr], replacement); + self.target.push(self.target[pstr_loc]); - self.trail.push((Ref::HeapCell(addr), trail_item)); + let replacement = pstr_loc_as_cell!(threshold); + let trail_item = mem::replace(&mut self.target[pstr_loc], replacement); - if has_tail { - let tail_addr = self.target[addr + 1].as_addr(addr + 1); - self.target.push(HeapCellValue::Addr(tail_addr)); - } + self.trail.push((Ref::heap_cell(pstr_loc), trail_item)); + self.target.push(self.target[pstr_loc + 1]); } - fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) { - match addr { - Addr::HeapCell(h) => { - self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier)); - self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier)); + fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) { + read_heap_cell!(addr, + (HeapCellValueTag::Var, h) => { + self.target[frontier] = heap_loc_as_cell!(frontier); + self.target[h] = heap_loc_as_cell!(frontier); - self.trail - .push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h)))); + self.trail.push((Ref::heap_cell(h), heap_loc_as_cell!(h))); } - Addr::StackCell(fr, sc) => { - self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier)); - self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier); - - self.trail.push(( - Ref::StackCell(fr, sc), - HeapCellValue::Addr(Addr::StackCell(fr, sc)), - )); + (HeapCellValueTag::StackVar, s) => { + self.target[frontier] = heap_loc_as_cell!(frontier); + self.target.stack()[s] = heap_loc_as_cell!(frontier); + + self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s))); } - Addr::AttrVar(h) => { + (HeapCellValueTag::AttrVar, h) => { let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy { self.target.threshold() } else { frontier }; - self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold)); - self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold)); + self.target[frontier] = heap_loc_as_cell!(threshold); + self.target[h] = heap_loc_as_cell!(threshold); - self.trail - .push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h)))); + self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h))); if let AttrVarPolicy::DeepCopy = self.attr_var_policy { self.target - .push(HeapCellValue::Addr(Addr::AttrVar(threshold))); + .push(attr_var_as_cell!(threshold)); - let list_val = self.target[h + 1].context_free_clone(); + let list_val = self.target[h + 1]; self.target.push(list_val); } } _ => { unreachable!() } + ); + } + + fn copy_var(&mut self, addr: HeapCellValue) { + let rd = self.target.deref(addr); + let ra = self.target.store(rd); + + read_heap_cell!(ra, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h >= self.old_h { + *self.value_at_scan() = rd; + self.scan += 1; + + return; + } + } + _ => {} + ); + + if addr == ra { + self.reinstantiate_var(addr, self.scan); + self.scan += 1; + } else { + *self.value_at_scan() = ra; + // self.copy_compound(rd, ra); } } - fn copy_var(&mut self, addr: Addr) { - let rd = self.target.store(self.target.deref(addr)); + /* + fn copy_compound(&mut self, rd: HeapCellValue, ra: HeapCellValue) { + let h = rd.get_value(); + let trail_item = self.target[h]; + let threshold = self.target.threshold(); + + self.trail.push((Ref::heap_cell(h), trail_item)); + self.target[self.scan].set_value(threshold); + + read_heap_cell!(ra, + (HeapCellValueTag::Atom, (_name, arity)) => { + self.target.push(ra); + + for i in 0..arity { + self.target.push(self.target[h + 1 + i]); + } + + self.target[h] = str_loc_as_cell!(self.scan + 1); + } + (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + self.target.push(ra); + self.target.push(self.target[h + 1]); - match rd { - Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => { - *self.value_at_scan() = HeapCellValue::Addr(rd); - self.scan += 1; + self.target[h] = pstr_loc_as_cell!(self.scan + 1); } - _ if addr == rd => { - self.reinstantiate_var(addr, self.scan); - self.scan += 1; + (HeapCellValueTag::CStr, cstr_atom) => { + self.target[h] = atom_as_cstr_cell!(cstr_atom); + } + (HeapCellValueTag::Str, s) => { + self.copy_structure(s); + return; } _ => { - *self.value_at_scan() = HeapCellValue::Addr(rd); + *self.value_at_scan() = rd; + self.trail.pop(); + return; } - } + ); + + self.scan += 1; } + */ fn copy_structure(&mut self, addr: usize) { - match self.target[addr].context_free_clone() { - HeapCellValue::NamedStr(arity, name, fixity) => { + read_heap_cell!(self.target[addr], + (HeapCellValueTag::Atom, (name, arity)) => { let threshold = self.target.threshold(); - *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold)); + *self.value_at_scan() = str_loc_as_cell!(threshold); let trail_item = mem::replace( &mut self.target[addr], - HeapCellValue::Addr(Addr::Str(threshold)), + str_loc_as_cell!(threshold), ); - self.trail.push((Ref::HeapCell(addr), trail_item)); - - self.target - .push(HeapCellValue::NamedStr(arity, name, fixity)); + self.trail.push((Ref::heap_cell(addr), trail_item)); + self.target.push(atom_as_cell!(name, arity)); for i in 0..arity { - let hcv = self.target[addr + 1 + i].context_free_clone(); + let hcv = self.target[addr + 1 + i]; self.target.push(hcv); } } - HeapCellValue::Addr(Addr::Str(addr)) => { - *self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr)) + (HeapCellValueTag::Str, h) => { + *self.value_at_scan() = str_loc_as_cell!(h); } _ => { unreachable!() } - } + ); self.scan += 1; } - fn copy_term_impl(&mut self, addr: Addr) { + fn copy_term_impl(&mut self, addr: HeapCellValue) { self.scan = self.target.threshold(); - self.target.push(HeapCellValue::Addr(addr)); + self.target.push(addr); while self.scan < self.target.threshold() { - match self.value_at_scan() { - &mut HeapCellValue::Addr(addr) => match addr { - Addr::Con(h) => { - let addr = self.target[h].as_addr(h); - - if addr == Addr::Con(h) { - *self.value_at_scan() = self.target[h].context_free_clone(); - } else { - *self.value_at_scan() = HeapCellValue::Addr(addr); - } - } - Addr::Lis(h) => { - if h >= self.old_h { - self.scan += 1; - } else { - self.copy_list(h); - } - } - addr @ Addr::AttrVar(_) - | addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) => { - self.copy_var(addr); - } - Addr::Str(addr) => { - self.copy_structure(addr); - } - Addr::PStrLocation(addr, n) => { - self.copy_partial_string(addr, n); - } - Addr::Stream(h) => { - *self.value_at_scan() = self.target[h].context_free_clone(); - } - _ => { + let addr = *self.value_at_scan(); + + read_heap_cell!(addr, + (HeapCellValueTag::Lis, h) => { + if h >= self.old_h { self.scan += 1; + } else { + self.copy_list(h); } - }, + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => { + self.copy_var(addr); + } + (HeapCellValueTag::Str, h) => { + self.copy_structure(h); + } + (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => { + self.copy_partial_string(addr.get_tag(), pstr_loc); + } _ => { self.scan += 1; } - } + ); } self.unwind_trail(); @@ -286,12 +313,117 @@ impl CopyTermState { fn unwind_trail(&mut self) { for (r, value) in self.trail.drain(0..) { - match r { - Ref::AttrVar(h) | Ref::HeapCell(h) => self.target[h] = value, - Ref::StackCell(fr, sc) => { - self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0) - } + let index = r.get_value() as usize; + + match r.get_tag() { + RefTag::AttrVar | RefTag::HeapCell => self.target[index] = value, + RefTag::StackCell => self.target.stack()[index] = value, } } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::machine::mock_wam::*; + + #[test] + fn copier_tests() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st.heap + .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom)); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy); + } + + // check that the original heap state is still intact. + assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom)); + + assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(4)); + assert_eq!(wam.machine_st.heap[4], atom_as_cell!(f_atom, 2)); + assert_eq!(wam.machine_st.heap[5], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[6], atom_as_cell!(b_atom)); + + wam.machine_st.heap.clear(); + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64))); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy); + } + + print_heap_terms(wam.machine_st.heap[6..].iter(), 6); + + assert_eq!(wam.machine_st.heap[0], pstr_cell); + assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2)); + assert_eq!(wam.machine_st.heap[2], pstr_second_cell); + assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(4)); + assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0)); + assert_eq!(wam.machine_st.heap[5], fixnum_as_cell!(Fixnum::build_with(0i64))); + + assert_eq!(wam.machine_st.heap[7], pstr_cell); + assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(9)); + assert_eq!(wam.machine_st.heap[9], pstr_second_cell); + assert_eq!(wam.machine_st.heap[10], pstr_loc_as_cell!(11)); + assert_eq!(wam.machine_st.heap[11], pstr_offset_as_cell!(7)); + assert_eq!(wam.machine_st.heap[12], fixnum_as_cell!(Fixnum::build_with(0i64))); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + { + let wam = TermCopyingMockWAM { wam: &mut wam }; + copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy); + } + + assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4)); + assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom)); + assert_eq!(wam.machine_st.heap[3], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[4], str_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[5], str_loc_as_cell!(6)); + assert_eq!(wam.machine_st.heap[6], atom_as_cell!(f_atom, 4)); + assert_eq!(wam.machine_st.heap[7], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[8], atom_as_cell!(b_atom)); + assert_eq!(wam.machine_st.heap[9], atom_as_cell!(a_atom)); + assert_eq!(wam.machine_st.heap[10], str_loc_as_cell!(6)); + } +} diff --git a/src/machine/gc.rs b/src/machine/gc.rs new file mode 100644 index 00000000..1b7f83fe --- /dev/null +++ b/src/machine/gc.rs @@ -0,0 +1,1101 @@ +use crate::atom_table::*; +use crate::machine::heap::*; +use crate::types::*; + +use core::marker::PhantomData; + +// TODO: rename to 'unmark_if_iter', 'mark_if_gc' +pub(crate) trait UnmarkPolicy { + fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool; + fn mark(heap: &mut [HeapCellValue], current: usize); + fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option + where + Self: Sized; +} + +pub(crate) struct IteratorUMP; + +impl UnmarkPolicy for IteratorUMP { + #[inline(always)] + fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool { + heap[current].set_mark_bit(false); + false + } + + #[inline(always)] + fn mark(_heap: &mut [HeapCellValue], _current: usize) {} + + #[inline(always)] + fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option { + iter.forward_var() + } +} + +struct MarkerUMP {} + +impl UnmarkPolicy for MarkerUMP { + #[inline(always)] + fn unmark(_heap: &mut [HeapCellValue], _current: usize) -> bool { true } + + #[inline(always)] + fn mark(heap: &mut [HeapCellValue], current: usize) { + heap[current].set_mark_bit(true); + } + + #[inline(always)] + fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option { + if iter.heap[iter.current + 1].get_mark_bit() { + return iter.forward_var(); + } + + let temp = iter.heap[iter.current].get_value(); + + iter.heap[iter.current].set_value(iter.next); + iter.current += 1; + + iter.next = iter.heap[iter.current].get_value(); + + iter.heap[iter.current].set_value(temp); + iter.heap[iter.current].set_mark_bit(true); + + None + } +} + +#[derive(Debug)] +pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> { + pub(crate) heap: &'a mut Vec, + orig_heap_len: usize, + start: usize, + current: usize, + next: usize, + _marker: PhantomData, +} + +impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> { + fn drop(&mut self) { + if self.current == self.start { + self.heap.truncate(self.orig_heap_len); + return; + } + + while !self.backward() {} + + self.heap.truncate(self.orig_heap_len); + } +} + +impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { + pub(crate) fn new(heap: &'a mut Vec, cell: HeapCellValue) -> Self { + let orig_heap_len = heap.len(); + let start = orig_heap_len + 1; + + heap.push(cell); + heap.push(heap_loc_as_cell!(orig_heap_len)); + + heap[start].set_mark_bit(true); + let next = heap[start].get_value(); + + Self { + heap, + orig_heap_len, + start, + current: start, + next, + _marker: PhantomData, + } + } + + fn backward_and_return(&mut self) -> Option { + let current = self.current; + + if self.backward() { + self.heap[self.current].set_forwarding_bit(true); + self.heap[self.current].set_mark_bit(true); + } + + Some(self.heap[current]) + } + + fn forward_var(&mut self) -> Option { + if self.heap[self.next].get_mark_bit() { + return self.backward_and_return(); + } + + self.heap[self.current].set_forwarding_bit(true); + + if self.heap[self.next].get_forwarding_bit() == Some(true) { + return self.backward_and_return(); + } + + let temp = self.heap[self.next].get_value(); + + self.heap[self.next].set_value(self.current); + self.current = self.next; + self.next = temp; + + None + } + + fn forward(&mut self) -> Option { + loop { + if self.heap[self.current].get_forwarding_bit() != Some(true) { + match self.heap[self.current].get_tag() { + HeapCellValueTag::AttrVar => { + if let Some(cell) = UMP::forward_attr_var(self) { return Some(cell); } + } + HeapCellValueTag::Var => { + if let Some(cell) = self.forward_var() { return Some(cell); } + } + HeapCellValueTag::Str => { + if self.heap[self.next + 1].get_mark_bit() { + return self.backward_and_return(); + } + + let h = self.next; + let cell = self.heap[h]; + + self.heap[h].set_forwarding_bit(true); + self.heap[self.current].set_forwarding_bit(true); + + let arity = cell_as_atom_cell!(self.heap[h]).get_arity(); + + for cell in &mut self.heap[h + 1 .. h + arity + 1] { + cell.set_mark_bit(true); + } + + let last_cell_loc = h + arity; + + self.next = self.heap[last_cell_loc].get_value(); + self.heap[last_cell_loc].set_value(self.current); + self.current = last_cell_loc; + + return Some(cell); + } + HeapCellValueTag::Lis => { + if self.heap[self.next + 1].get_mark_bit() { + return self.backward_and_return(); + } + + self.heap[self.current].set_forwarding_bit(true); + self.heap[self.next+1].set_mark_bit(true); + + let last_cell_loc = self.next + 1; + + self.next = self.heap[last_cell_loc].get_value(); + self.heap[last_cell_loc].set_value(self.current); + self.current = last_cell_loc; + + return Some(list_loc_as_cell!(last_cell_loc - 1)); + } + HeapCellValueTag::PStrLoc => { + let h = self.next; + let cell = self.heap[h]; + + self.heap[self.current].set_forwarding_bit(true); + + if self.heap[h+1].get_mark_bit() { + return self.backward_and_return(); + } + + if self.heap[h].get_tag() == HeapCellValueTag::PStr { + self.heap[h+1].set_mark_bit(true); + + self.next = self.heap[h+1].get_value(); + self.heap[h+1].set_value(self.current); + self.heap[h].set_forwarding_bit(true); + + self.current = h+1; + } else { + debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset); + + self.next = self.heap[h].get_value(); + self.heap[h].set_value(self.current); + self.current = h; + + if self.heap[h].get_forwarding_bit() == Some(true) { + continue; + } + } + + return Some(cell); + } + HeapCellValueTag::PStrOffset => { + let h = self.next; + + UMP::mark(self.heap, self.current+1); + + if self.heap[h].get_tag() == HeapCellValueTag::PStr { + if self.heap[h+1].get_mark_bit() { + return self.backward_and_return(); + } + + self.heap[h+1].set_mark_bit(true); + self.heap[self.current].set_forwarding_bit(true); + + self.next = self.heap[h+1].get_value(); + self.heap[h+1].set_value(self.current); + self.current = h+1; + } else { + debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr); + + self.next = self.heap[h].get_value(); + self.heap[h].set_value(self.current); + self.current = h; + } + } + HeapCellValueTag::StackVar => { + let cell = self.heap[self.current]; + self.heap[self.current].set_forwarding_bit(true); + return Some(cell); + } + _ => { + if self.heap[self.current].get_mark_bit() { + let current = self.current; + + if self.backward() { + return None; + } + + return Some(self.heap[current]); + } + + return self.backward_and_return(); + } + } + } else { + if self.backward() { + return None; + } + } + } + } + + fn backward(&mut self) -> bool { + while !self.heap[self.current].get_mark_bit() { + let temp = self.heap[self.current].get_value(); + + UMP::mark(self.heap, self.current); + + self.heap[self.current].set_forwarding_bit(false); + self.heap[self.current].set_value(self.next); + + self.next = self.current; + self.current = temp; + } + + self.heap[self.current].set_forwarding_bit(false); + + let unmark_is_no_op = UMP::unmark(self.heap, self.current); + + if self.current == self.start { + return true; + } + + if unmark_is_no_op { // if true, the marker is running. + let cell = self.heap[self.current]; + + // a cyclic root must be handled specially when marking. + if self.next >= self.orig_heap_len && cell.is_ref() { + debug_assert!(cell.get_tag() != HeapCellValueTag::PStrOffset); + + self.heap[self.current].set_mark_bit(false); + let prev_current = self.heap[self.current].get_value(); + + if !self.heap[prev_current].is_forwarded() { + return self.backward(); + } + } + } + + self.current -= 1; + + let temp = self.heap[self.current+1].get_value(); + + self.heap[self.current+1].set_value(self.next); + self.next = self.heap[self.current].get_value(); + self.heap[self.current].set_value(temp); + + false + } +} + +impl<'a, UMP: UnmarkPolicy> Iterator for StacklessPreOrderHeapIter<'a, UMP> { + type Item = HeapCellValue; + + #[inline] + fn next(&mut self) -> Option { + self.forward() + } +} + +pub fn mark_cells(heap: &mut Heap, cell: HeapCellValue) { + let mut iter = StacklessPreOrderHeapIter::::new(heap, cell); + while let Some(_) = iter.forward() {} +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::machine::mock_wam::*; + + #[test] + fn heap_marking_tests() { + let mut wam = MockWAM::new(); + + let f_atom = atom!("f"); + let a_atom = atom!("a"); + let b_atom = atom!("b"); + + wam.machine_st + .heap + .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + + mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom)); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(0)) + ] + )); + + mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(0)); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + // make the structure doubly cyclic. + wam.machine_st.heap[2] = str_loc_as_cell!(0); + + mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(str_loc_as_cell!(1)); + + wam.machine_st.heap.extend(functor!( + f_atom, + [ + atom(a_atom), + atom(b_atom), + atom(a_atom), + cell(str_loc_as_cell!(1)) + ] + )); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), str_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(f_atom, 4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), str_loc_as_cell!(1)); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(0)); + + wam.machine_st.heap.clear(); + + // term is: [a, b] + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(atom_as_cell!(b_atom)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), empty_list_as_cell!()); + + wam.machine_st.heap.pop(); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + // now make the list cyclic. + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), heap_loc_as_cell!(0)); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + // make the list doubly cyclic. + wam.machine_st.heap[3] = heap_loc_as_cell!(0); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + // term is: [a, ] + let stream = Stream::from_static_string("test", &mut wam.machine_st.arena); + let stream_cell = + HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons)); + + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(a_atom)); + wam.machine_st.heap.push(list_loc_as_cell!(3)); + wam.machine_st.heap.push(stream_cell); + wam.machine_st.heap.push(empty_list_as_cell!()); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), stream_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), empty_list_as_cell!()); + + wam.machine_st.heap.clear(); + + // now a cycle of variables. + + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(0)); + + wam.machine_st.heap.clear(); + + // first a 'dangling' partial string, later modified to be a + // two-part complete string, then a three-part cyclic string + // involving an uncompacted list of chars. + + let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + + wam.machine_st.heap.pop(); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl); + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(3)); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(4)); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(4)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(3)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(2)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(1)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), fixnum_as_cell!(Fixnum::build_with(2))); + + wam.machine_st.heap.truncate(4); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff"))); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + + wam.machine_st.heap[3] = pstr_loc_as_cell!(5); + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(5)); + + assert!(wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(wam.machine_st.heap[3].get_mark_bit()); + assert!(!wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(wam.machine_st.heap[6].get_mark_bit()); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_loc_as_cell!(5)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), fixnum_as_cell!(Fixnum::build_with(2))); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff"))); + wam.machine_st.heap.push(pstr_cell); + wam.machine_st.heap.push(pstr_loc_as_cell!(4)); + wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff"))); + wam.machine_st.heap.push(pstr_second_cell); + wam.machine_st.heap.push(pstr_loc_as_cell!(7)); + wam.machine_st.heap.push(atom_as_cell!(atom!("irrelevant stuff"))); + wam.machine_st.heap.push(pstr_offset_as_cell!(1)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(7)); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); + assert!(wam.machine_st.heap[8].get_mark_bit()); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(5)); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); + assert!(wam.machine_st.heap[8].get_mark_bit()); + + for cell in &wam.machine_st.heap { + assert!(cell.get_forwarding_bit() != Some(true)); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(4)); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); + assert!(wam.machine_st.heap[8].get_mark_bit()); + + for cell in &wam.machine_st.heap { + assert!(cell.get_forwarding_bit() != Some(true)); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(2)); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); + assert!(wam.machine_st.heap[8].get_mark_bit()); + + for cell in &wam.machine_st.heap { + assert!(cell.get_forwarding_bit() != Some(true)); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + mark_cells(&mut wam.machine_st.heap, pstr_loc_as_cell!(1)); + + assert!(!wam.machine_st.heap[0].get_mark_bit()); + assert!(wam.machine_st.heap[1].get_mark_bit()); + assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[3].get_mark_bit()); + assert!(wam.machine_st.heap[4].get_mark_bit()); + assert!(wam.machine_st.heap[5].get_mark_bit()); + assert!(!wam.machine_st.heap[6].get_mark_bit()); + assert!(wam.machine_st.heap[7].get_mark_bit()); + assert!(wam.machine_st.heap[8].get_mark_bit()); + + for cell in &wam.machine_st.heap { + assert!(cell.get_forwarding_bit() != Some(true)); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(7)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(atom!("irrelevant stuff"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), pstr_offset_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), fixnum_as_cell!(Fixnum::build_with(2))); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + wam.machine_st.heap.clear(); + + // embedded cyclic partial string. + + wam.machine_st.heap.push(pstr_cell); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(3))); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(4)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), fixnum_as_cell!(Fixnum::build_with(3))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), list_loc_as_cell!(5)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), empty_list_as_cell!()); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(pstr_cell); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(3))); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.heap.push(heap_loc_as_cell!(4)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(4)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), pstr_offset_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), fixnum_as_cell!(Fixnum::build_with(3))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), list_loc_as_cell!(5)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), pstr_loc_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), heap_loc_as_cell!(4)); + + wam.machine_st.heap.clear(); + + // a chain of variables, ending in a self-referential variable. + + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), heap_loc_as_cell!(3)); + + wam.machine_st.heap.clear(); + + // print L = [L|L]. + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(list_loc_as_cell!(1)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), list_loc_as_cell!(1)); + + wam.machine_st.heap.clear(); + + // term is [X,f(Y),Z]. + // Z is an attributed variable, but has a variable attributes list. + wam.machine_st.heap.push(list_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2 + wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3 + wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4 + wam.machine_st.heap.push(heap_loc_as_cell!(8)); + wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6 + wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7 + wam.machine_st.heap.push(list_loc_as_cell!(9)); + wam.machine_st.heap.push(heap_loc_as_cell!(9)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. + wam.machine_st.heap.push(heap_loc_as_cell!(12)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(12)); + + // now populate the attributes list. + let clpz_atom = atom!("clpz"); + let p_atom = atom!("p"); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + cell.set_forwarding_bit(false); + } + + wam.machine_st.heap.pop(); + + wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12 + wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13 + wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14 + wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15 + wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16 + wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17 + wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18 + wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19 + wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20 + wam.machine_st.heap.push(empty_list_as_cell!()); // 21 + wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22 + wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23 + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(13)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[13]), list_loc_as_cell!(14)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[14]), str_loc_as_cell!(16)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[15]), heap_loc_as_cell!(19)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[16]), atom_as_cell!(clpz_atom, 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[17]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[18]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[19]), list_loc_as_cell!(20)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[20]), str_loc_as_cell!(22)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[21]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[22]), atom_as_cell!(p_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[23]), heap_loc_as_cell!(23)); + + for cell in &mut wam.machine_st.heap { + cell.set_mark_bit(false); + cell.set_forwarding_bit(false); + } + + // push some unrelated nonsense cells to the heap and check that they + // are unmarked after the marker has finished at 0. + wam.machine_st.heap.push(heap_loc_as_cell!(5)); + wam.machine_st.heap.push(heap_loc_as_cell!(5)); + wam.machine_st.heap.push(list_loc_as_cell!(5)); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&mut wam.machine_st.heap[0..24]); + + for cell in &wam.machine_st.heap[24..] { + assert_eq!(cell.get_mark_bit(), false); + } + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), list_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(3)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), list_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), str_loc_as_cell!(6)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), heap_loc_as_cell!(8)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), atom_as_cell!(f_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), heap_loc_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), list_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), heap_loc_as_cell!(9)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[10]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[11]), attr_var_as_cell!(11)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[12]), heap_loc_as_cell!(13)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[13]), list_loc_as_cell!(14)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[14]), str_loc_as_cell!(16)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[15]), heap_loc_as_cell!(19)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[16]), atom_as_cell!(clpz_atom, 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[17]), atom_as_cell!(a_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[18]), atom_as_cell!(b_atom)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[19]), list_loc_as_cell!(20)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[20]), str_loc_as_cell!(22)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[21]), empty_list_as_cell!()); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[22]), atom_as_cell!(p_atom, 1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[23]), heap_loc_as_cell!(23)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[24]), heap_loc_as_cell!(5)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[25]), heap_loc_as_cell!(5)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[26]), list_loc_as_cell!(5)); + + wam.machine_st.heap.clear(); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap.len(), 1); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(str_loc_as_cell!(1)); + wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); + wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); + wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push(list_loc_as_cell!(8)); + wam.machine_st.heap.push(str_loc_as_cell!(4)); + wam.machine_st.heap.push(empty_list_as_cell!()); + + mark_cells(&mut wam.machine_st.heap, heap_loc_as_cell!(7)); + + assert_eq!(wam.machine_st.heap.len(), 10); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), str_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(atom!("g"), 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(atom!("y"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), atom_as_cell!(atom!("="), 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[5]), atom_as_cell!(atom!("X"))); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[6]), heap_loc_as_cell!(0)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[7]), list_loc_as_cell!(8)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[8]), str_loc_as_cell!(4)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[9]), empty_list_as_cell!()); + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + wam.machine_st.heap.push(heap_loc_as_cell!(1)); + + mark_cells(&mut wam.machine_st.heap, str_loc_as_cell!(0)); + + all_cells_marked_and_unforwarded(&wam.machine_st.heap); + + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(atom!("f"), 2)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), heap_loc_as_cell!(1)); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[2]), heap_loc_as_cell!(1)); + } +} diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 067bfa93..462aacbc 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -1,140 +1,282 @@ -use core::marker::PhantomData; - -use prolog_parser::ast::Constant; - +use crate::arena::*; +use crate::atom_table::*; +use crate::forms::*; use crate::machine::machine_indices::*; use crate::machine::partial_string::*; -use crate::machine::raw_block::*; +use crate::parser::ast::*; +use crate::types::*; + +use ordered_float::OrderedFloat; +use rug::{Integer, Rational}; use std::convert::TryFrom; -use std::mem; -use std::ops::{Index, IndexMut}; -use std::ptr; -#[derive(Debug)] -pub(crate) struct StandardHeapTraits {} +pub(crate) type Heap = Vec; -impl RawBlockTraits for StandardHeapTraits { +impl From for HeapCellValue { #[inline] - fn init_size() -> usize { - 256 * mem::size_of::() + fn from(literal: Literal) -> Self { + match literal { + Literal::Atom(name) => atom_as_cell!(name), + Literal::Char(c) => char_as_cell!(c), + Literal::Fixnum(n) => fixnum_as_cell!(n), + Literal::Integer(bigint_ptr) => { + typed_arena_ptr_as_cell!(bigint_ptr) + } + Literal::Rational(bigint_ptr) => { + typed_arena_ptr_as_cell!(bigint_ptr) + } + Literal::Float(f) => HeapCellValue::from(f), + Literal::String(s) => { + if s == atom!("") { + empty_list_as_cell!() + } else { + string_as_cstr_cell!(s) + } + } + } } +} - #[inline] - fn align() -> usize { - mem::align_of::() +impl TryFrom for Literal { + type Error = (); + + fn try_from(value: HeapCellValue) -> Result { + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + Ok(Literal::Atom(name)) + } else { + Err(()) + } + } + (HeapCellValueTag::Char, c) => { + Ok(Literal::Char(c)) + } + (HeapCellValueTag::Fixnum, n) => { + Ok(Literal::Fixnum(n)) + } + (HeapCellValueTag::F64, f) => { + Ok(Literal::Float(f)) + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Integer, n) => { + Ok(Literal::Integer(n)) + } + (ArenaHeaderTag::Rational, n) => { + Ok(Literal::Rational(n)) + } + _ => { + Err(()) + } + ) + } + (HeapCellValueTag::CStr, cstr_atom) => { + Ok(Literal::String(cstr_atom)) + } + _ => { + Err(()) + } + ) } } -#[derive(Debug)] -pub(crate) struct HeapTemplate { - buf: RawBlock, - _marker: PhantomData, -} +// sometimes we need to dereference variables that are found only in +// the heap without access to the full WAM (e.g., while detecting +// cycles in terms), and which therefore may only point other cells in +// the heap (thanks to the design of the WAM). +pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue { + loop { + let new_value = read_heap_cell!(value, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + heap[h] + } + _ => { + value + } + ); -pub(crate) type Heap = HeapTemplate; + if new_value != value && new_value.is_var() { + value = new_value; + continue; + } -impl Drop for HeapTemplate { - fn drop(&mut self) { - self.clear(); - self.buf.deallocate(); + return value; } } -#[derive(Debug)] -pub(crate) struct HeapIntoIter { - offset: usize, - buf: RawBlock, +pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue { + read_heap_cell!(value, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + heap[h] + } + _ => { + value + } + ) } -impl Drop for HeapIntoIter { - fn drop(&mut self) { - let mut heap = HeapTemplate { - buf: self.buf.take(), - _marker: PhantomData, - }; - - heap.truncate(self.offset / mem::size_of::()); - heap.buf.deallocate(); +#[allow(dead_code)] +pub fn print_heap_terms<'a, I: Iterator>(heap: I, h: usize) { + for (index, term) in heap.enumerate() { + println!("{} : {:?}", h + index, term); } } -impl Iterator for HeapIntoIter { - type Item = HeapCellValue; - - fn next(&mut self) -> Option { - let ptr = self.buf.base as usize + self.offset; - self.offset += mem::size_of::(); - - if ptr < self.buf.top as usize { - unsafe { Some(ptr::read(ptr as *const HeapCellValue)) } - } else { - None +#[inline] +pub(crate) fn put_complete_string( + heap: &mut Heap, + s: &str, + atom_tbl: &mut AtomTable, +) -> HeapCellValue { + match allocate_pstr(heap, s, atom_tbl) { + Some(h) => { + heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr. + + if heap.len() == h + 1 { + let pstr_atom = cell_as_atom!(heap[h]); + heap[h] = atom_as_cstr_cell!(pstr_atom); + heap_loc_as_cell!(h) + } else { + heap.push(empty_list_as_cell!()); + pstr_loc_as_cell!(h) + } + } + None => { + empty_list_as_cell!() } } } -#[derive(Debug)] -pub(crate) struct HeapIter<'a, T: RawBlockTraits> { - offset: usize, - buf: &'a RawBlock, -} - -impl<'a, T: RawBlockTraits> HeapIter<'a, T> { - pub(crate) fn new(buf: &'a RawBlock, offset: usize) -> Self { - HeapIter { buf, offset } +#[inline] +pub(crate) fn put_partial_string( + heap: &mut Heap, + s: &str, + atom_tbl: &mut AtomTable, +) -> HeapCellValue { + match allocate_pstr(heap, s, atom_tbl) { + Some(h) => { + pstr_loc_as_cell!(h) + } + None => { + empty_list_as_cell!() + } } } -impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> { - type Item = &'a HeapCellValue; +#[inline] +pub(crate) fn allocate_pstr( + heap: &mut Heap, + mut src: &str, + atom_tbl: &mut AtomTable, +) -> Option { + let orig_h = heap.len(); + + loop { + if src == "" { + return if orig_h == heap.len() { + None + } else { + let tail_h = heap.len() - 1; + heap[tail_h] = heap_loc_as_cell!(tail_h); + + Some(orig_h) + }; + } + + let h = heap.len(); + + let (pstr, rest_src) = match PartialString::new(src, atom_tbl) { + Some(tuple) => tuple, + None => { + if src.len() > '\u{0}'.len_utf8() { + src = &src['\u{0}'.len_utf8()..]; + continue; + } else if orig_h == h { + return None; + } else { + heap[h - 1] = heap_loc_as_cell!(h - 1); + return Some(orig_h); + } + } + }; - fn next(&mut self) -> Option { - let ptr = self.buf.base as usize + self.offset; - self.offset += mem::size_of::(); + heap.push(string_as_pstr_cell!(pstr)); - if ptr < self.buf.top as usize { - unsafe { Some(&*(ptr as *const _)) } + if rest_src != "" { + heap.push(pstr_loc_as_cell!(h + 2)); + src = rest_src; } else { - None + heap.push(heap_loc_as_cell!(h + 1)); + return Some(orig_h); } } } -#[allow(dead_code)] -pub(crate) fn print_heap_terms<'a, I: Iterator>(heap: I, h: usize) { - for (index, term) in heap.enumerate() { - println!("{} : {}", h + index, term); +pub fn filtered_iter_to_heap_list>( + heap: &mut Heap, + values: impl Iterator, + filter_fn: impl Fn(&Heap, HeapCellValue) -> bool, +) -> usize { + let head_addr = heap.len(); + let mut h = head_addr; + + for value in values { + let value = value.into(); + + if filter_fn(heap, value) { + heap.push(list_loc_as_cell!(h + 1)); + heap.push(value); + + h += 2; + } } -} -#[derive(Debug)] -pub(crate) struct HeapIterMut<'a, T: RawBlockTraits> { - offset: usize, - buf: &'a mut RawBlock, + heap.push(empty_list_as_cell!()); + + head_addr } -impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> { - pub(crate) fn new(buf: &'a mut RawBlock, offset: usize) -> Self { - HeapIterMut { buf, offset } - } +#[inline(always)] +pub fn iter_to_heap_list(heap: &mut Heap, values: Iter) -> usize +where + Iter: Iterator, + SrcT: Into, +{ + filtered_iter_to_heap_list(heap, values, |_, _| true) } -impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> { - type Item = &'a mut HeapCellValue; +pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option { + let extract_integer = |s: usize| -> Option { + match Number::try_from(heap[s]) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), + Ok(Number::Integer(n)) => n.to_usize(), + _ => None, + } + }; - fn next(&mut self) -> Option { - let ptr = self.buf.base as usize + self.offset; - self.offset += mem::size_of::(); + read_heap_cell!(addr, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); - if ptr < self.buf.top as usize { - unsafe { Some(&mut *(ptr as *mut _)) } - } else { + if name == atom!("dir_entry") && arity == 1 { + extract_integer(s+1).map(LocalCodePtr::DirEntry) + } else { + panic!( + "to_local_code_ptr crashed with p.i. {}/{}", + name.as_str(), + arity, + ); + } + } + _ => { None } - } + ) } +/* impl HeapTemplate { #[inline] pub(crate) fn new() -> Self { @@ -144,67 +286,40 @@ impl HeapTemplate { } } - #[inline] - pub(crate) fn clone(&self, h: usize) -> HeapCellValue { - match &self[h] { - &HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr), - &HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()), - &HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()), - &HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()), - &HeapCellValue::LoadStatePayload(_) => HeapCellValue::Addr(Addr::LoadStatePayload(h)), - &HeapCellValue::NamedStr(arity, ref name, ref op) => { - HeapCellValue::NamedStr(arity, name.clone(), op.clone()) - } - &HeapCellValue::PartialString(..) => HeapCellValue::Addr(Addr::PStrLocation(h, 0)), - &HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()), - &HeapCellValue::Stream(_) => HeapCellValue::Addr(Addr::Stream(h)), - &HeapCellValue::TcpListener(_) => HeapCellValue::Addr(Addr::TcpListener(h)), - } - } - - #[inline] - pub(crate) fn put_complete_string(&mut self, s: &str) -> Addr { - if s.is_empty() { - return Addr::EmptyList; - } - - let addr = self.allocate_pstr(s); - self.pop(); - - let h = self.h(); - - match &mut self[h - 1] { - &mut HeapCellValue::PartialString(_, ref mut has_tail) => { - *has_tail = false; - } - _ => { - unreachable!() - } - } - - addr - } - - #[inline] - pub(crate) fn put_constant(&mut self, c: Constant) -> Addr { - match c { - Constant::Atom(name, op) => Addr::Con(self.push(HeapCellValue::Atom(name, op))), - Constant::Char(c) => Addr::Char(c), - Constant::EmptyList => Addr::EmptyList, - Constant::Fixnum(n) => Addr::Fixnum(n), - Constant::Integer(n) => Addr::Con(self.push(HeapCellValue::Integer(n))), - Constant::Rational(r) => Addr::Con(self.push(HeapCellValue::Rational(r))), - Constant::Float(f) => Addr::Float(f), - Constant::String(s) => { - if s.is_empty() { - Addr::EmptyList - } else { - self.put_complete_string(&s) + /* + // TODO: move this to the WAM, then remove the temporary (and by + // then, unnecessary and impossible) "arena" argument. OR, remove + // this thing totally! if we can. by that I mean, just convert a + // little to a HeapCellValue. don't bother writing to the + // heap at all. Each of these data is either already inlinable in a + // HeapCellValue or a pointer to an GC'ed location in memory. + #[inline] + pub(crate) fn put_literal(&mut self, literal: Literal) -> HeapCellValue { + match literal { + Literal::Atom(name) => atom_as_cell!(name), + Literal::Char(c) => char_as_cell!(c), + Literal::EmptyList => empty_list_as_cell!(), + Literal::Fixnum(n) => fixnum_as_cell!(n), + Literal::Integer(bigint_ptr) => { + let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr)); + self[h] + } + Literal::Rational(bigint_ptr) => { + let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr)); + self[h] } + Literal::Float(f) => typed_arena_ptr_as_cell!(f), + Literal::String(s) => { + if s.as_str().is_empty() { + empty_list_as_cell!() + } else { + // TODO: how do we know where the tail is located?? well, there is no tail. separate tag? + untyped_arena_ptr_as_cell!(s) // self.put_complete_string(arena, &s) + } + } // Literal::Usize(n) => Addr::Usize(n), } - Constant::Usize(n) => Addr::Usize(n), } - } + */ #[inline] pub(crate) fn is_empty(&self) -> bool { @@ -225,14 +340,14 @@ impl HeapTemplate { let h = self.h(); unsafe { - let new_top = self.buf.new_block(mem::size_of::()); - ptr::write(self.buf.top as *mut _, val); - self.buf.top = new_top; + let new_ptr = self.buf.alloc(mem::size_of::()); + ptr::write(new_ptr as *mut _, val); } h } + /* #[inline] pub(crate) fn atom_at(&self, h: usize) -> bool { if let HeapCellValue::Atom(..) = &self[h] { @@ -265,76 +380,17 @@ impl HeapTemplate { val @ HeapCellValue::TcpListener(..) => Addr::TcpListener(self.push(val)), } } - - #[inline] - pub(crate) fn allocate_pstr(&mut self, src: &str) -> Addr { - self.write_pstr(src).unwrap_or_else(|| Addr::EmptyList) - } - - #[inline] - fn write_pstr(&mut self, mut src: &str) -> Option { - let orig_h = self.h(); - - loop { - if src == "" { - return if orig_h == self.h() { - None - } else { - let tail_h = self.h() - 1; - self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h)); - - Some(Addr::PStrLocation(orig_h, 0)) - }; - } - - let h = self.h(); - - let (pstr, rest_src) = match PartialString::new(src) { - Some(tuple) => tuple, - None => { - if src.len() > '\u{0}'.len_utf8() { - src = &src['\u{0}'.len_utf8()..]; - continue; - } else if orig_h == h { - return None; - } else { - self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1)); - return Some(Addr::PStrLocation(orig_h, 0)); - } - } - }; - - self.push(HeapCellValue::PartialString(pstr, true)); - - if rest_src != "" { - self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0))); - src = rest_src; - } else { - self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1))); - return Some(Addr::PStrLocation(orig_h, 0)); - } - } - } + */ #[inline] pub(crate) fn truncate(&mut self, h: usize) { - let new_top = h * mem::size_of::() + self.buf.base as usize; - let mut h = new_top; - - unsafe { - while h as *const _ < self.buf.top { - let val = h as *mut HeapCellValue; - ptr::drop_in_place(val); - h += mem::size_of::(); - } - } - - self.buf.top = new_top as *const _; + let new_ptr = self.buf.top as usize - h * mem::size_of::(); + self.buf.ptr = new_ptr as *mut _; } #[inline] pub(crate) fn h(&self) -> usize { - (self.buf.top as usize - self.buf.base as usize) / mem::size_of::() + (self.buf.top as usize - self.buf.ptr as usize) / mem::size_of::() } pub(crate) fn append(&mut self, vals: Vec) { @@ -350,84 +406,7 @@ impl HeapTemplate { } } - pub(crate) fn to_list(&mut self, values: Iter) -> usize - where - Iter: Iterator, - SrcT: Into, - { - let head_addr = self.h(); - let mut h = head_addr; - - for value in values.map(|v| v.into()) { - self.push(HeapCellValue::Addr(Addr::Lis(h + 1))); - self.push(value); - - h += 2; - } - - self.push(HeapCellValue::Addr(Addr::EmptyList)); - - head_addr - } - - /* Create an iterator starting from the passed offset. */ - pub(crate) fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> { - HeapIter::new(&self.buf, offset * mem::size_of::()) - } - - pub(crate) fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> { - HeapIterMut::new(&mut self.buf, offset * mem::size_of::()) - } - - pub(crate) fn into_iter(mut self) -> HeapIntoIter { - HeapIntoIter { - buf: self.buf.take(), - offset: 0, - } - } - - pub(crate) fn extend>(&mut self, iter: Iter) { - for hcv in iter { - self.push(hcv); - } - } - - pub(crate) fn to_local_code_ptr(&self, addr: &Addr) -> Option { - let extract_integer = |s: usize| -> Option { - match &self[s] { - &HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(), - &HeapCellValue::Integer(ref n) => n.to_usize(), - _ => None, - } - }; - - match addr { - Addr::Str(s) => { - match &self[*s] { - HeapCellValue::NamedStr(arity, ref name, _) => { - match (name.as_str(), *arity) { - ("dir_entry", 1) => extract_integer(s + 1).map(LocalCodePtr::DirEntry), - /* - ("top_level", 2) => { - if let Some(chunk_num) = extract_integer(s+1) { - if let Some(p) = extract_integer(s+2) { - return Some(LocalCodePtr::TopLevel(chunk_num, p)); - } - } - - None - } - */ - _ => None, - } - } - _ => unreachable!(), - } - } - _ => None, - } - } - + /* TODO: get rid of this!! #[inline] pub(crate) fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> { match addr { @@ -437,6 +416,20 @@ impl HeapTemplate { addr => RefOrOwned::Owned(HeapCellValue::Addr(*addr)), } } + */ +} + +impl Index for HeapTemplate { + type Output = HeapCellValue; + + #[inline] + fn index(&self, index: u64) -> &Self::Output { + unsafe { + let ptr = + self.buf.top as usize - (index as usize + 1) * mem::size_of::(); + &*(ptr as *const HeapCellValue) + } + } } impl Index for HeapTemplate { @@ -445,7 +438,7 @@ impl Index for HeapTemplate { #[inline] fn index(&self, index: usize) -> &Self::Output { unsafe { - let ptr = self.buf.base as usize + index * mem::size_of::(); + let ptr = self.buf.top as usize - (index + 1) * mem::size_of::(); &*(ptr as *const HeapCellValue) } } @@ -455,8 +448,9 @@ impl IndexMut for HeapTemplate { #[inline] fn index_mut(&mut self, index: usize) -> &mut Self::Output { unsafe { - let ptr = self.buf.base as usize + index * mem::size_of::(); + let ptr = self.buf.top as usize - (index + 1) * mem::size_of::(); &mut *(ptr as *mut HeapCellValue) } } } +*/ diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index d0a0d126..2b8c0fb5 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -1,26 +1,21 @@ +use crate::clause_types::*; +use crate::forms::*; +use crate::machine::loader::*; +use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::preprocessor::*; use crate::machine::term_stream::*; use crate::machine::*; - -use prolog_parser::clause_name; +use crate::parser::ast::*; use indexmap::IndexSet; use ref_thread_local::RefThreadLocal; use slice_deque::{sdeq, SliceDeque}; -type ModuleOpExports = Vec<(OpDecl, Option<(usize, Specifier)>)>; - -/* - * We will want to borrow these fields from Loader separately, without - * restricting access to other fields by borrowing them mutably. - */ -pub(super) struct LoadState<'a> { - pub(super) compilation_target: CompilationTarget, - pub(super) module_op_exports: ModuleOpExports, - pub(super) retraction_info: RetractionInfo, - pub(super) wam: &'a mut Machine, -} +use std::fs::File; +use std::mem; + +pub(super) type ModuleOpExports = Vec<(OpDecl, Option)>; pub(super) fn set_code_index( retraction_info: &mut RetractionInfo, @@ -42,10 +37,10 @@ pub(super) fn set_code_index( CompilationTarget::Module(ref module_name) => { if IndexPtr::Undefined == code_index.get() { code_index.set(code_ptr); - RetractionRecord::AddedModulePredicate(module_name.clone(), key) + RetractionRecord::AddedModulePredicate(*module_name, key) } else { let replaced = code_index.replace(code_ptr); - RetractionRecord::ReplacedModulePredicate(module_name.clone(), key, replaced) + RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced) } } }; @@ -69,18 +64,17 @@ fn add_op_decl_as_module_export( */ match op_decl.insert_into_op_dir(wam_op_dir) { - Some((prec, spec)) => { + Some(op_desc) => { retraction_info.push_record(RetractionRecord::ReplacedUserOp( - op_decl.clone(), - prec, - spec, + *op_decl, + op_desc, )); - module_op_exports.push((op_decl.clone(), Some((prec, spec)))); + module_op_exports.push((*op_decl, Some(op_desc))); } None => { - retraction_info.push_record(RetractionRecord::AddedUserOp(op_decl.clone())); - module_op_exports.push((op_decl.clone(), None)); + retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl)); + module_op_exports.push((*op_decl, None)); } } @@ -94,31 +88,29 @@ pub(super) fn add_op_decl( op_decl: &OpDecl, ) { match op_decl.insert_into_op_dir(op_dir) { - Some((prec, spec)) => match &compilation_target { + Some(op_desc) => match &compilation_target { CompilationTarget::User => { retraction_info.push_record(RetractionRecord::ReplacedUserOp( - op_decl.clone(), - prec, - spec, + *op_decl, + op_desc, )); } CompilationTarget::Module(ref module_name) => { retraction_info.push_record(RetractionRecord::ReplacedModuleOp( - module_name.clone(), - op_decl.clone(), - prec, - spec, + *module_name, + *op_decl, + op_desc, )); } }, None => match &compilation_target { CompilationTarget::User => { - retraction_info.push_record(RetractionRecord::AddedUserOp(op_decl.clone())); + retraction_info.push_record(RetractionRecord::AddedUserOp(*op_decl)); } CompilationTarget::Module(ref module_name) => { retraction_info.push_record(RetractionRecord::AddedModuleOp( - module_name.clone(), - op_decl.clone(), + *module_name, + *op_decl, )); } }, @@ -135,16 +127,16 @@ pub(super) fn import_module_exports( ) -> Result<(), SessionError> { for export in imported_module.module_decl.exports.iter() { match export { - ModuleExport::PredicateKey((ref name, arity)) => { - let key = (name.clone(), *arity); + ModuleExport::PredicateKey((name, arity)) => { + let key = (*name, *arity); if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { - meta_predicates.insert(key.clone(), meta_specs.clone()); + meta_predicates.insert(key, meta_specs.clone()); } if let Some(src_code_index) = imported_module.code_dir.get(&key) { let target_code_index = code_dir - .entry(key.clone()) + .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .clone(); @@ -157,8 +149,8 @@ pub(super) fn import_module_exports( ); } else { return Err(SessionError::ModuleDoesNotContainExport( - imported_module.module_decl.name.clone(), - (name.clone(), *arity), + imported_module.module_decl.name, + key, )); } } @@ -183,8 +175,8 @@ fn import_module_exports_into_module( ) -> Result<(), SessionError> { for export in imported_module.module_decl.exports.iter() { match export { - ModuleExport::PredicateKey((ref name, arity)) => { - let key = (name.clone(), *arity); + ModuleExport::PredicateKey((name, arity)) => { + let key = (*name, *arity); if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { meta_predicates.insert(key.clone(), meta_specs.clone()); @@ -192,7 +184,7 @@ fn import_module_exports_into_module( if let Some(src_code_index) = imported_module.code_dir.get(&key) { let target_code_index = code_dir - .entry(key.clone()) + .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .clone(); @@ -206,7 +198,7 @@ fn import_module_exports_into_module( } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name.clone(), - (name.clone(), *arity), + (*name, *arity), )); } } @@ -241,8 +233,8 @@ fn import_qualified_module_exports( } match export { - ModuleExport::PredicateKey((ref name, arity)) => { - let key = (name.clone(), *arity); + ModuleExport::PredicateKey((name, arity)) => { + let key = (*name, *arity); if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { meta_predicates.insert(key.clone(), meta_specs.clone()); @@ -264,7 +256,7 @@ fn import_qualified_module_exports( } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name.clone(), - (name.clone(), *arity), + (*name, *arity), )); } } @@ -294,16 +286,16 @@ fn import_qualified_module_exports_into_module( } match export { - ModuleExport::PredicateKey((ref name, arity)) => { - let key = (name.clone(), *arity); + ModuleExport::PredicateKey((name, arity)) => { + let key = (*name, *arity); if let Some(meta_specs) = imported_module.meta_predicates.get(&key) { - meta_predicates.insert(key.clone(), meta_specs.clone()); + meta_predicates.insert(key, meta_specs.clone()); } if let Some(src_code_index) = imported_module.code_dir.get(&key) { let target_code_index = code_dir - .entry(key.clone()) + .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .clone(); @@ -317,7 +309,7 @@ fn import_qualified_module_exports_into_module( } else { return Err(SessionError::ModuleDoesNotContainExport( imported_module.module_decl.name.clone(), - (name.clone(), *arity), + (*name, *arity), )); } } @@ -337,15 +329,15 @@ fn import_qualified_module_exports_into_module( Ok(()) } -impl<'a> LoadState<'a> { - pub(super) fn retract_local_clauses( +impl<'a, LS: LoadState<'a>> Loader<'a, LS> { + pub(super) fn retract_local_clauses_impl( &mut self, compilation_target: CompilationTarget, key: PredicateKey, clause_locs: &SliceDeque, ) { let result_opt = self - .wam + .wam_prelude .indices .get_predicate_skeleton(&compilation_target, &key) .map(|skeleton| { @@ -377,15 +369,18 @@ impl<'a> LoadState<'a> { mut clause_target_poses: Vec>, is_dynamic: bool, ) { - let old_compilation_target = mem::replace(&mut self.compilation_target, compilation_target); + let old_compilation_target = mem::replace( + &mut self.payload.compilation_target, + compilation_target, + ); while let Some(target_pos_opt) = clause_target_poses.pop() { match target_pos_opt { Some(target_pos) if is_dynamic => { - self.retract_dynamic_clause(key.clone(), target_pos); + self.retract_dynamic_clause(key, target_pos); } Some(target_pos) => { - self.retract_clause(key.clone(), target_pos); + self.retract_clause(key, target_pos); } None => { // Here because the clause was been removed @@ -395,7 +390,7 @@ impl<'a> LoadState<'a> { } } - self.compilation_target = old_compilation_target; + self.payload.compilation_target = old_compilation_target; } pub(super) fn retract_local_clause_clauses( @@ -403,20 +398,23 @@ impl<'a> LoadState<'a> { clause_clause_compilation_target: CompilationTarget, clause_locs: &SliceDeque, ) { - let key = (clause_name!("$clause"), 2); - - match self.wam.indices.get_local_predicate_skeleton_mut( - self.compilation_target.clone(), - clause_clause_compilation_target.clone(), - self.listing_src_file_name(), - key.clone(), + let key = (atom!("$clause"), 2); + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + self.payload.compilation_target, + clause_clause_compilation_target, + listing_src_file_name, + key, ) { Some(skeleton) => { - self.retraction_info.push_record( + let payload_compilation_target = self.payload.compilation_target; + + self.payload.retraction_info.push_record( RetractionRecord::RemovedLocalSkeletonClauseLocations( - self.compilation_target.clone(), - clause_clause_compilation_target.clone(), - key.clone(), + payload_compilation_target, + clause_clause_compilation_target, + key, mem::replace(&mut skeleton.clause_clause_locs, sdeq![]), ), ); @@ -430,7 +428,7 @@ impl<'a> LoadState<'a> { } }; - self.retract_local_clauses(clause_clause_compilation_target, key, &clause_locs); + self.retract_local_clauses_impl(clause_clause_compilation_target, key, &clause_locs); } pub(super) fn try_term_to_tl( @@ -450,19 +448,18 @@ impl<'a> LoadState<'a> { #[inline] pub(super) fn remove_module_op_exports(&mut self) { - for (mut op_decl, record) in self.module_op_exports.drain(0..) { - op_decl.remove(&mut self.wam.indices.op_dir); + for (mut op_decl, record) in self.payload.module_op_exports.drain(0..) { + op_decl.remove(&mut self.wam_prelude.indices.op_dir); - if let Some((prec, spec)) = record { - op_decl.prec = prec; - op_decl.spec = spec; - op_decl.insert_into_op_dir(&mut self.wam.indices.op_dir); + if let Some(op_desc) = record { + op_decl.op_desc = op_desc; + op_decl.insert_into_op_dir(&mut self.wam_prelude.indices.op_dir); } } } - pub(super) fn remove_replaced_in_situ_module(&mut self, module_name: ClauseName) { - let removed_module = match self.wam.indices.modules.remove(&module_name) { + pub(super) fn remove_replaced_in_situ_module(&mut self, module_name: Atom) { + let removed_module = match self.wam_prelude.indices.modules.remove(&module_name) { Some(module) => module, None => return, }; @@ -479,7 +476,7 @@ impl<'a> LoadState<'a> { if code_index.get() != IndexPtr::Undefined { let old_index_ptr = code_index.replace(IndexPtr::Undefined); - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::ReplacedModulePredicate( module_name.clone(), key.clone(), @@ -488,11 +485,11 @@ impl<'a> LoadState<'a> { } } - self.wam.indices.modules.insert(module_name, removed_module); + self.wam_prelude.indices.modules.insert(module_name, removed_module); } - pub(super) fn remove_module_exports(&mut self, module_name: ClauseName) { - let removed_module = match self.wam.indices.modules.remove(&module_name) { + pub(super) fn remove_module_exports(&mut self, module_name: Atom) { + let removed_module = match self.wam_prelude.indices.modules.remove(&module_name) { Some(module) => module, None => return, }; @@ -503,7 +500,7 @@ impl<'a> LoadState<'a> { op_dir: &mut OpDir, retraction_info: &mut RetractionInfo, predicate_retractor: impl Fn(PredicateKey, IndexPtr) -> RetractionRecord, - op_retractor: impl Fn(OpDecl, usize, Specifier) -> RetractionRecord, + op_retractor: impl Fn(OpDecl, OpDesc) -> RetractionRecord, ) { for export in removed_module.module_decl.exports.iter() { match export { @@ -513,55 +510,51 @@ impl<'a> LoadState<'a> { if module_code_index.get() == target_code_index.get() => { let old_index_ptr = target_code_index.replace(IndexPtr::Undefined); - - retraction_info - .push_record(predicate_retractor(key.clone(), old_index_ptr)); + retraction_info.push_record(predicate_retractor(*key, old_index_ptr)); } _ => {} } } ModuleExport::OpDecl(op_decl) => { let op_dir_value_opt = - op_dir.remove(&(op_decl.name.clone(), op_decl.fixity())); - - if let Some(op_dir_value) = op_dir_value_opt { - let (prec, spec) = op_dir_value.shared_op_desc().get(); + op_dir.remove(&(op_decl.name, fixity(op_decl.op_desc.get_spec() as u32))); - retraction_info.push_record(op_retractor(op_decl.clone(), prec, spec)); + if let Some(op_desc) = op_dir_value_opt { + retraction_info.push_record(op_retractor(*op_decl, op_desc)); } } } } } - match &self.compilation_target { + match self.payload.compilation_target { CompilationTarget::User => { remove_module_exports( &removed_module, - &mut self.wam.indices.code_dir, - &mut self.wam.indices.op_dir, - &mut self.retraction_info, + &mut self.wam_prelude.indices.code_dir, + &mut self.wam_prelude.indices.op_dir, + &mut self.payload.retraction_info, RetractionRecord::ReplacedUserPredicate, RetractionRecord::ReplacedUserOp, ); } - CompilationTarget::Module(ref target_module_name) - if target_module_name.as_str() != module_name.as_str() => + CompilationTarget::Module(target_module_name) + if target_module_name != module_name => { let predicate_retractor = |key, index_ptr| { - RetractionRecord::ReplacedModulePredicate(module_name.clone(), key, index_ptr) + RetractionRecord::ReplacedModulePredicate(module_name, key, index_ptr) }; - let op_retractor = |op_decl, prec, spec| { - RetractionRecord::ReplacedModuleOp(module_name.clone(), op_decl, prec, spec) + let op_retractor = |op_decl, op_desc| { + RetractionRecord::ReplacedModuleOp(module_name, op_decl, op_desc) }; - if let Some(module) = self.wam.indices.modules.get_mut(target_module_name) { + if let Some(module) = self.wam_prelude.indices.modules.get_mut(&target_module_name) { remove_module_exports( &removed_module, &mut module.code_dir, &mut module.op_dir, - &mut self.retraction_info, + &mut self.payload.retraction_info, predicate_retractor, op_retractor, ); @@ -572,24 +565,24 @@ impl<'a> LoadState<'a> { CompilationTarget::Module(_) => {} }; - self.wam.indices.modules.insert(module_name, removed_module); + self.wam_prelude.indices.modules.insert(module_name, removed_module); } fn get_or_insert_local_code_index( &mut self, - module_name: ClauseName, + module_name: Atom, key: PredicateKey, ) -> CodeIndex { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => module .code_dir .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)) .clone(), None => { - self.add_dynamically_generated_module(&module_name); + self.add_dynamically_generated_module(module_name); - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => module .code_dir .entry(key) @@ -610,7 +603,7 @@ impl<'a> LoadState<'a> { ) -> CodeIndex { match compilation_target { CompilationTarget::User => self - .wam + .wam_prelude .indices .code_dir .entry(key) @@ -624,12 +617,12 @@ impl<'a> LoadState<'a> { pub(super) fn get_or_insert_qualified_code_index( &mut self, - module_name: ClauseName, + module_name: Atom, key: PredicateKey, ) -> CodeIndex { - if module_name.as_str() == "user" { + if module_name == atom!("user") { return self - .wam + .wam_prelude .indices .code_dir .entry(key) @@ -649,18 +642,18 @@ impl<'a> LoadState<'a> { ) { match compilation_target { CompilationTarget::User => { - self.wam + self.wam_prelude .indices .extensible_predicates - .insert(key.clone(), skeleton); + .insert(key, skeleton); let record = RetractionRecord::AddedExtensiblePredicate(CompilationTarget::User, key); - self.retraction_info.push_record(record); + self.payload.retraction_info.push_record(record); } CompilationTarget::Module(module_name) => { - if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) { module.extensible_predicates.insert(key.clone(), skeleton); let record = RetractionRecord::AddedExtensiblePredicate( @@ -668,7 +661,7 @@ impl<'a> LoadState<'a> { key, ); - self.retraction_info.push_record(record); + self.payload.retraction_info.push_record(record); } else { unreachable!() } @@ -685,21 +678,21 @@ impl<'a> LoadState<'a> { ) { let src_compilation_target = match self.listing_src_file_name() { Some(filename) => CompilationTarget::Module(filename), - None => self.compilation_target.clone(), + None => self.payload.compilation_target, }; match src_compilation_target { CompilationTarget::User => { - self.wam + self.wam_prelude .indices .local_extensible_predicates - .insert((local_compilation_target.clone(), key.clone()), skeleton); + .insert((local_compilation_target, key), skeleton); } CompilationTarget::Module(module_name) => { - if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) { module .local_extensible_predicates - .insert((local_compilation_target.clone(), key.clone()), skeleton); + .insert((local_compilation_target, key), skeleton); } else { unreachable!() } @@ -708,10 +701,13 @@ impl<'a> LoadState<'a> { } pub(super) fn add_op_decl(&mut self, op_decl: &OpDecl) { - match &self.compilation_target { + let listing_src_file_name = self.listing_src_file_name(); + let payload_compilation_target = self.payload.compilation_target; + + match payload_compilation_target { CompilationTarget::User => { - if let Some(filename) = self.listing_src_file_name() { - match self.wam.indices.modules.get_mut(&filename) { + if let Some(filename) = listing_src_file_name { + match self.wam_prelude.indices.modules.get_mut(&filename) { Some(ref mut module) => { op_decl.insert_into_op_dir(&mut module.op_dir); } @@ -720,21 +716,23 @@ impl<'a> LoadState<'a> { } add_op_decl( - &mut self.retraction_info, - &self.compilation_target, - &mut self.wam.indices.op_dir, + &mut self.payload.retraction_info, + &payload_compilation_target, + &mut self.wam_prelude.indices.op_dir, op_decl, ); } CompilationTarget::Module(ref module_name) => { - match self.wam.indices.modules.get_mut(module_name) { + match self.wam_prelude.indices.modules.get_mut(module_name) { Some(ref mut module) => { + let payload: &mut LoadStatePayload<_> = &mut self.payload; + add_op_decl_as_module_export( &mut module.op_dir, - &self.compilation_target, - &mut self.retraction_info, - &mut self.wam.indices.op_dir, - &mut self.module_op_exports, + &payload.compilation_target, + &mut payload.retraction_info, + &mut self.wam_prelude.indices.op_dir, + &mut payload.module_op_exports, op_decl, ); } @@ -746,28 +744,17 @@ impl<'a> LoadState<'a> { } } - pub(super) fn get_clause_type( - &mut self, - name: ClauseName, - arity: usize, - fixity: Option, - ) -> ClauseType { - match ClauseType::from(name, arity, fixity) { + pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType { + match ClauseType::from(name, arity) { ClauseType::Named(name, arity, _) => { - let idx = self.get_or_insert_code_index( - (name.clone(), arity), - self.compilation_target.clone(), - ); + let payload_compilation_target = self.payload.compilation_target; - ClauseType::Named(name, arity, idx) - } - ClauseType::Op(name, fixity, _) => { let idx = self.get_or_insert_code_index( - (name.clone(), arity), - self.compilation_target.clone(), + (name, arity), + payload_compilation_target, ); - ClauseType::Op(name, fixity, idx) + ClauseType::Named(name, arity, idx) } ct => ct, } @@ -775,92 +762,85 @@ impl<'a> LoadState<'a> { pub(super) fn get_qualified_clause_type( &mut self, - module_name: ClauseName, - name: ClauseName, + module_name: Atom, + name: Atom, arity: usize, - fixity: Option, ) -> ClauseType { - match ClauseType::from(name, arity, fixity) { + match ClauseType::from(name, arity) { ClauseType::Named(name, arity, _) => { - let key = (name.clone(), arity); + let key = (name, arity); let idx = self.get_or_insert_qualified_code_index(module_name, key); ClauseType::Named(name, arity, idx) } - ClauseType::Op(name, fixity, _) => { - let key = (name.clone(), arity); - let idx = self.get_or_insert_qualified_code_index(module_name, key); - - ClauseType::Op(name, fixity, idx) - } ct => ct, } } pub(super) fn add_meta_predicate_record( &mut self, - module_name: ClauseName, - name: ClauseName, + module_name: Atom, + name: Atom, meta_specs: Vec, ) { let arity = meta_specs.len(); let key = (name, arity); - match module_name.as_str() { - "user" => { + match module_name { + atom!("user") => { match self - .wam + .wam_prelude .indices .meta_predicates - .insert(key.clone(), meta_specs) + .insert(key, meta_specs) { Some(old_meta_specs) => { - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::ReplacedMetaPredicate( - module_name.clone(), + module_name, key.0, old_meta_specs, )); } None => { - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::AddedMetaPredicate( - module_name.clone(), + module_name, key, )); } } } _ => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { match module.meta_predicates.insert(key.clone(), meta_specs) { Some(old_meta_specs) => { - self.retraction_info.push_record( + self.payload.retraction_info.push_record( RetractionRecord::ReplacedMetaPredicate( - module_name.clone(), + module_name, key.0, old_meta_specs, ), ); } None => { - self.retraction_info.push_record( - RetractionRecord::AddedMetaPredicate(module_name.clone(), key), + self.payload.retraction_info.push_record( + RetractionRecord::AddedMetaPredicate(module_name, key), ); } } } None => { - self.add_dynamically_generated_module(&module_name); + self.add_dynamically_generated_module(module_name); - if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) { module.meta_predicates.insert(key.clone(), meta_specs); } else { unreachable!() } - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::AddedMetaPredicate( module_name.clone(), key, @@ -871,7 +851,7 @@ impl<'a> LoadState<'a> { } } - pub(super) fn add_dynamically_generated_module(&mut self, module_name: &ClauseName) { + pub(super) fn add_dynamically_generated_module(&mut self, module_name: Atom) { let module_decl = ModuleDecl { name: module_name.clone(), exports: vec![], @@ -887,28 +867,28 @@ impl<'a> LoadState<'a> { &mut module.meta_predicates, ); - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::AddedModule(module_name.clone())); - self.wam.indices.modules.insert(module_name.clone(), module); + self.wam_prelude.indices.modules.insert(module_name.clone(), module); } fn import_builtins_in_module( &mut self, - module_name: ClauseName, + module_name: Atom, code_dir: &mut CodeDir, op_dir: &mut OpDir, meta_predicates: &mut MetaPredicateDir, ) { - if let Some(builtins) = self.wam.indices.modules.get(&clause_name!("builtins")) { + if let Some(builtins) = self.wam_prelude.indices.modules.get(&atom!("builtins")) { let module_compilation_target = CompilationTarget::Module(module_name); - if CompilationTarget::Module(clause_name!("builtins")) == self.compilation_target { + if CompilationTarget::Module(atom!("builtins")) == self.payload.compilation_target { return; } import_module_exports( - &mut self.retraction_info, + &mut self.payload.retraction_info, &module_compilation_target, builtins, code_dir, @@ -929,7 +909,7 @@ impl<'a> LoadState<'a> { self.remove_module_exports(module_name.clone()); self.remove_replaced_in_situ_module(module_name.clone()); - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(module) => { let old_module_decl = mem::replace(&mut module.module_decl, module_decl.clone()); @@ -939,14 +919,14 @@ impl<'a> LoadState<'a> { ); for ((compilation_target, key), skeleton) in local_extensible_predicates.iter() { - self.retract_local_clauses( - compilation_target.clone(), - key.clone(), + self.retract_local_clauses_impl( + *compilation_target, + *key, &skeleton.clause_clause_locs, ); let is_dynamic = self - .wam + .wam_prelude .indices .get_predicate_skeleton(compilation_target, key) .map(|skeleton| skeleton.core.is_dynamic) @@ -955,7 +935,7 @@ impl<'a> LoadState<'a> { if is_dynamic { let clause_clause_compilation_target = match compilation_target { CompilationTarget::User => { - CompilationTarget::Module(clause_name!("builtins")) + CompilationTarget::Module(atom!("builtins")) } module => module.clone(), }; @@ -967,7 +947,7 @@ impl<'a> LoadState<'a> { } } - self.retraction_info + self.payload.retraction_info .push_record(RetractionRecord::ReplacedModule( old_module_decl, listing_src.clone(), @@ -980,15 +960,16 @@ impl<'a> LoadState<'a> { pub(crate) fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) { self.reset_in_situ_module(module_decl.clone(), &listing_src); - let module_name = module_decl.name.clone(); + let module_name = module_decl.name; - let mut module = match self.wam.indices.modules.remove(&module_name) { + let mut module = match self.wam_prelude.indices.modules.remove(&module_name) { Some(mut module) => { module.listing_src = listing_src; module } None => { - self.retraction_info + self.payload + .retraction_info .push_record(RetractionRecord::AddedModule(module_name.clone())); Module::new(module_decl, listing_src) @@ -996,7 +977,7 @@ impl<'a> LoadState<'a> { }; self.import_builtins_in_module( - module_name.clone(), + module_name, &mut module.code_dir, &mut module.op_dir, &mut module.meta_predicates, @@ -1004,62 +985,68 @@ impl<'a> LoadState<'a> { for export in &module.module_decl.exports { if let ModuleExport::OpDecl(ref op_decl) = export { + let payload: &mut LoadStatePayload<_> = &mut self.payload; + add_op_decl_as_module_export( &mut module.op_dir, - &self.compilation_target, // this is a Module. - &mut self.retraction_info, - &mut self.wam.indices.op_dir, - &mut self.module_op_exports, + &payload.compilation_target, // this is a Module. + &mut payload.retraction_info, + &mut self.wam_prelude.indices.op_dir, + &mut payload.module_op_exports, op_decl, ); } } - if let Some(load_context) = self.wam.load_contexts.last_mut() { - load_context.module = module_name.clone(); + if let Some(load_context) = self.wam_prelude.load_contexts.last_mut() { + load_context.module = module_name; } - self.wam.indices.modules.insert(module_name, module); + self.wam_prelude.indices.modules.insert(module_name, module); } - pub(super) fn import_module(&mut self, module_name: ClauseName) -> Result<(), SessionError> { - if let Some(module) = self.wam.indices.modules.remove(&module_name) { - match &self.compilation_target { + pub(super) fn import_module(&mut self, module_name: Atom) -> Result<(), SessionError> { + if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) { + let payload_compilation_target = self.payload.compilation_target; + + match &payload_compilation_target { CompilationTarget::User => { import_module_exports( - &mut self.retraction_info, - &self.compilation_target, + &mut self.payload.retraction_info, + &payload_compilation_target, &module, - &mut self.wam.indices.code_dir, - &mut self.wam.indices.op_dir, - &mut self.wam.indices.meta_predicates, + &mut self.wam_prelude.indices.code_dir, + &mut self.wam_prelude.indices.op_dir, + &mut self.wam_prelude.indices.meta_predicates, )?; } CompilationTarget::Module(ref defining_module_name) => { - match self.wam.indices.modules.get_mut(defining_module_name) { + match self.wam_prelude.indices.modules.get_mut(defining_module_name) { Some(ref mut target_module) => { + let payload: &mut LoadStatePayload<_> = &mut self.payload; + import_module_exports_into_module( - &mut self.retraction_info, - &self.compilation_target, + &mut payload.retraction_info, + &payload_compilation_target, &module, &mut target_module.code_dir, &mut target_module.op_dir, &mut target_module.meta_predicates, - &mut self.wam.indices.op_dir, - &mut self.module_op_exports, + &mut self.wam_prelude.indices.op_dir, + &mut payload.module_op_exports, )?; } None => { // we find ourselves here because we're trying to import // a module into itself as it is being defined. - self.wam.indices.modules.insert(module_name.clone(), module); + self.wam_prelude.indices.modules.insert(module_name, module); return Err(SessionError::ModuleCannotImportSelf(module_name)); } } } } - self.wam.indices.modules.insert(module_name, module); + self.wam_prelude.indices.modules.insert(module_name, module); Ok(()) } else { Err(SessionError::ExistenceError(ExistenceError::Module( @@ -1070,53 +1057,55 @@ impl<'a> LoadState<'a> { pub(super) fn import_qualified_module( &mut self, - module_name: ClauseName, + module_name: Atom, exports: IndexSet, ) -> Result<(), SessionError> { - if let Some(module) = self.wam.indices.modules.remove(&module_name) { - match &self.compilation_target { + if let Some(module) = self.wam_prelude.indices.modules.remove(&module_name) { + let payload_compilation_target = self.payload.compilation_target; + + match &payload_compilation_target { CompilationTarget::User => { import_qualified_module_exports( - &mut self.retraction_info, - &self.compilation_target, + &mut self.payload.retraction_info, + &payload_compilation_target, &module, &exports, - &mut self.wam.indices.code_dir, - &mut self.wam.indices.op_dir, - &mut self.wam.indices.meta_predicates, + &mut self.wam_prelude.indices.code_dir, + &mut self.wam_prelude.indices.op_dir, + &mut self.wam_prelude.indices.meta_predicates, )?; } CompilationTarget::Module(ref defining_module_name) => { - match self.wam.indices.modules.get_mut(defining_module_name) { + match self.wam_prelude.indices.modules.get_mut(defining_module_name) { Some(ref mut target_module) => { + let payload: &mut LoadStatePayload<_> = &mut self.payload; + import_qualified_module_exports_into_module( - &mut self.retraction_info, - &self.compilation_target, + &mut payload.retraction_info, + &payload_compilation_target, &module, &exports, &mut target_module.code_dir, &mut target_module.op_dir, &mut target_module.meta_predicates, - &mut self.wam.indices.op_dir, - &mut self.module_op_exports, + &mut self.wam_prelude.indices.op_dir, + &mut payload.module_op_exports, )?; } None => { // we find ourselves here because we're trying to import // a module into itself as it is being defined. - self.wam.indices.modules.insert(module_name.clone(), module); + self.wam_prelude.indices.modules.insert(module_name, module); return Err(SessionError::ModuleCannotImportSelf(module_name)); } } } } - self.wam.indices.modules.insert(module_name, module); + self.wam_prelude.indices.modules.insert(module_name, module); Ok(()) } else { - Err(SessionError::ExistenceError(ExistenceError::Module( - module_name, - ))) + Err(SessionError::ExistenceError(ExistenceError::Module(module_name))) } } @@ -1125,23 +1114,30 @@ impl<'a> LoadState<'a> { ModuleSource::File(filename) => { let mut path_buf = PathBuf::from(filename.as_str()); path_buf.set_extension("pl"); + let file = File::open(&path_buf)?; ( - Stream::from_file_as_input(filename.clone(), file), + Stream::from_file_as_input(filename, file, &mut LS::machine_st(&mut self.payload).arena), ListingSource::File(filename, path_buf), ) } ModuleSource::Library(library) => match LIBRARIES.borrow().get(library.as_str()) { Some(code) => { - if let Some(ref module) = self.wam.indices.modules.get(&library) { + if let Some(ref module) = self.wam_prelude.indices.modules.get(&library) { if let ListingSource::DynamicallyGenerated = &module.listing_src { - (Stream::from(*code), ListingSource::User) + ( + Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena), + ListingSource::User, + ) } else { return self.import_module(library); } } else { - (Stream::from(*code), ListingSource::User) + ( + Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena), + ListingSource::User, + ) } } None => { @@ -1151,16 +1147,23 @@ impl<'a> LoadState<'a> { }; let compilation_target = { - let stream = &mut parsing_stream(stream)?; - - let ts = BootstrappingTermStream::from_prolog_stream( + let term_stream = BootstrappingTermStream::from_char_reader( stream, - self.wam.machine_st.atom_tbl.clone(), - self.wam.machine_st.flags, + LS::machine_st(&mut self.payload), listing_src, ); - let subloader = Loader::new(ts, self.wam); + let subloader: Loader<'_, BootstrappingLoadState> = Loader { + payload: BootstrappingLoadState( + LoadStatePayload::new(self.wam_prelude.code_repo.code.len(), term_stream) + ), + wam_prelude: MachinePreludeView { + indices: self.wam_prelude.indices, + code_repo: self.wam_prelude.code_repo, + load_contexts: self.wam_prelude.load_contexts, + } + }; + subloader.load()? }; @@ -1185,16 +1188,19 @@ impl<'a> LoadState<'a> { let file = File::open(&path_buf)?; ( - Stream::from_file_as_input(filename.clone(), file), + Stream::from_file_as_input(filename, file, &mut LS::machine_st(&mut self.payload).arena), ListingSource::File(filename, path_buf), ) } ModuleSource::Library(library) => match LIBRARIES.borrow().get(library.as_str()) { Some(code) => { - if self.wam.indices.modules.contains_key(&library) { + if self.wam_prelude.indices.modules.contains_key(&library) { return self.import_qualified_module(library, exports); } else { - (Stream::from(*code), ListingSource::User) + ( + Stream::from_static_string(*code, &mut LS::machine_st(&mut self.payload).arena), + ListingSource::User, + ) } } None => { @@ -1204,16 +1210,23 @@ impl<'a> LoadState<'a> { }; let compilation_target = { - let stream = &mut parsing_stream(stream)?; - - let ts = BootstrappingTermStream::from_prolog_stream( + let term_stream = BootstrappingTermStream::from_char_reader( stream, - self.wam.machine_st.atom_tbl.clone(), - self.wam.machine_st.flags, + LS::machine_st(&mut self.payload), listing_src, ); - let subloader = Loader::new(ts, self.wam); + let subloader: Loader<'_, BootstrappingLoadState> = Loader { + payload: BootstrappingLoadState( + LoadStatePayload::new(self.wam_prelude.code_repo.code.len(), term_stream), + ), + wam_prelude: MachinePreludeView { + indices: self.wam_prelude.indices, + code_repo: self.wam_prelude.code_repo, + load_contexts: self.wam_prelude.load_contexts, + } + }; + subloader.load()? }; @@ -1227,21 +1240,4 @@ impl<'a> LoadState<'a> { } } } - - #[inline] - pub(super) fn composite_op_dir(&self) -> CompositeOpDir { - match &self.compilation_target { - CompilationTarget::User => CompositeOpDir::new(&self.wam.indices.op_dir, None), - CompilationTarget::Module(ref module_name) => { - match self.wam.indices.modules.get(module_name) { - Some(ref module) => { - CompositeOpDir::new(&self.wam.indices.op_dir, Some(&module.op_dir)) - } - None => { - unreachable!() - } - } - } - } - } } diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 6f48b1d9..b2f43e54 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1,18 +1,26 @@ -use prolog_parser::ast::*; -use prolog_parser::{clause_name, temp_v}; - +use crate::arena::*; +use crate::atom_table::*; +use crate::clause_types::*; use crate::forms::*; +use crate::heap_iter::*; use crate::indexing::*; +use crate::instructions::*; use crate::machine::load_state::*; +use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::preprocessor::*; +use crate::machine::term_stream::*; use crate::machine::*; +use crate::parser::ast::*; +use crate::types::*; use indexmap::IndexSet; use slice_deque::{sdeq, SliceDeque}; use std::cell::Cell; use std::convert::TryFrom; +use std::mem; +use std::ops::{Deref, DerefMut}; use std::rc::Rc; /* @@ -44,19 +52,19 @@ use std::rc::Rc; #[derive(Debug)] pub(crate) enum RetractionRecord { - AddedMetaPredicate(ClauseName, PredicateKey), - ReplacedMetaPredicate(ClauseName, ClauseName, Vec), - AddedModule(ClauseName), + AddedMetaPredicate(Atom, PredicateKey), + ReplacedMetaPredicate(Atom, Atom, Vec), + AddedModule(Atom), ReplacedModule(ModuleDecl, ListingSource, LocalExtensiblePredicates), - AddedModuleOp(ClauseName, OpDecl), - ReplacedModuleOp(ClauseName, OpDecl, usize, Specifier), - AddedModulePredicate(ClauseName, PredicateKey), - ReplacedModulePredicate(ClauseName, PredicateKey, IndexPtr), + AddedModuleOp(Atom, OpDecl), + ReplacedModuleOp(Atom, OpDecl, OpDesc), + AddedModulePredicate(Atom, PredicateKey), + ReplacedModulePredicate(Atom, PredicateKey, IndexPtr), AddedDiscontiguousPredicate(CompilationTarget, PredicateKey), AddedDynamicPredicate(CompilationTarget, PredicateKey), AddedMultifilePredicate(CompilationTarget, PredicateKey), AddedUserOp(OpDecl), - ReplacedUserOp(OpDecl, usize, Specifier), + ReplacedUserOp(OpDecl, OpDesc), AddedExtensiblePredicate(CompilationTarget, PredicateKey), AddedUserPredicate(PredicateKey), ReplacedUserPredicate(PredicateKey, IndexPtr), @@ -75,6 +83,7 @@ pub(crate) enum RetractionRecord { SkeletonLocalClauseTruncateBack(CompilationTarget, CompilationTarget, PredicateKey, usize), SkeletonClauseTruncateBack(CompilationTarget, PredicateKey, usize), SkeletonClauseStartReplaced(CompilationTarget, PredicateKey, usize, usize), + RemovedDynamicSkeletonClause(CompilationTarget, PredicateKey, usize, usize), RemovedSkeletonClause( CompilationTarget, PredicateKey, @@ -113,7 +122,7 @@ impl RetractionInfo { pub(super) fn new(orig_code_extent: usize) -> Self { Self { orig_code_extent, - records: vec![], //BTreeMap::new(), + records: vec![], } } @@ -134,16 +143,397 @@ impl RetractionInfo { } } -impl<'a> Drop for LoadState<'a> { +impl<'a, LS: LoadState<'a>> Drop for Loader<'a, LS> { fn drop(&mut self) { - while let Some(record) = self.retraction_info.records.pop() { + if LS::should_drop_load_state(self) { + LS::reset_machine(self); + } + } +} + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub enum CompilationTarget { + Module(Atom), + User, +} + +impl Default for CompilationTarget { + #[inline] + fn default() -> Self { + CompilationTarget::User + } +} + +impl CompilationTarget { + #[inline] + pub(crate) fn module_name(&self) -> Atom { + match self { + CompilationTarget::User => { + atom!("user") + } + CompilationTarget::Module(module_name) => *module_name, + } + } +} + +pub struct PredicateQueue { + pub(super) predicates: Vec, + pub(super) compilation_target: CompilationTarget, +} + +impl PredicateQueue { + #[inline] + pub(super) fn push(&mut self, clause: Term) { + self.predicates.push(clause); + } + + #[inline] + pub(crate) fn first(&self) -> Option<&Term> { + self.predicates.first() + } + + #[inline] + pub(crate) fn is_empty(&self) -> bool { + self.predicates.is_empty() + } + + #[inline] + pub(super) fn take(&mut self) -> Self { + Self { + predicates: mem::replace(&mut self.predicates, vec![]), + compilation_target: self.compilation_target.clone(), + } + } + + #[inline] + pub(super) fn len(&self) -> usize { + self.predicates.len() + } +} + +#[macro_export] +macro_rules! predicate_queue { + [$($v:expr),*] => ( + PredicateQueue { + predicates: vec![$($v,)*], + compilation_target: CompilationTarget::default(), + } + ) +} + +pub type LiveLoadState = LoadStatePayload; + +pub struct BootstrappingLoadState<'a>( + pub LoadStatePayload> +); + +impl<'a> Deref for BootstrappingLoadState<'a> { + type Target = LoadStatePayload>; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a> DerefMut for BootstrappingLoadState<'a> { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +pub trait LoadState<'a>: Sized { + type Evacuable; + type TS: TermStream; + type LoaderFieldType: DerefMut>; + + fn new(machine_st: &'a mut MachineState, payload: LoadStatePayload) -> Self::LoaderFieldType; + fn evacuate(loader: Loader<'a, Self>) -> Result; + fn should_drop_load_state(loader: &Loader<'a, Self>) -> bool; + fn reset_machine(loader: &mut Loader<'a, Self>); + fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState; +} + +pub struct LiveLoadAndMachineState<'a> { + load_state: TypedArenaPtr, + machine_st: &'a mut MachineState, +} + +impl<'a> Deref for LiveLoadAndMachineState<'a> { + type Target = LiveLoadState; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.load_state + } +} + +impl<'a> DerefMut for LiveLoadAndMachineState<'a> { + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.load_state + } +} + +impl<'a> LoadState<'a> for LiveLoadAndMachineState<'a> { + type TS = LiveTermStream; + type LoaderFieldType = LiveLoadAndMachineState<'a>; + type Evacuable = TypedArenaPtr; + + #[inline(always)] + fn new(machine_st: &'a mut MachineState, payload: LoadStatePayload) -> Self::LoaderFieldType { + let load_state = arena_alloc!(payload, &mut machine_st.arena); + LiveLoadAndMachineState { load_state, machine_st } + } + + #[inline(always)] + fn evacuate(mut loader: Loader<'a, Self>) -> Result { + loader.payload.load_state.set_tag(ArenaHeaderTag::InactiveLoadState); + Ok(loader.payload.load_state) + } + + #[inline(always)] + fn should_drop_load_state(loader: &Loader<'a, Self>) -> bool { + loader.payload.load_state.get_tag() == ArenaHeaderTag::LiveLoadState + } + + #[inline(always)] + fn reset_machine(loader: &mut Loader<'a, Self>) { + if loader.payload.load_state.get_tag() != ArenaHeaderTag::Dropped { + loader.payload.load_state.set_tag(ArenaHeaderTag::Dropped); + loader.reset_machine(); + } + } + + #[inline(always)] + fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState { + loader.machine_st + } +} + +impl<'a> LoadState<'a> for BootstrappingLoadState<'a> { + type TS = BootstrappingTermStream<'a>; + type LoaderFieldType = BootstrappingLoadState<'a>; + type Evacuable = CompilationTarget; + + #[inline(always)] + fn new(_: &'a mut MachineState, payload: LoadStatePayload) -> Self::LoaderFieldType { + BootstrappingLoadState(payload) + } + + fn evacuate(mut loader: Loader<'a, Self>) -> Result { + if !loader.payload.predicates.is_empty() { + loader.compile_and_submit()?; + } + + let repo_len = loader.wam_prelude.code_repo.code.len(); + + loader + .payload + .retraction_info + .reset(repo_len); + + loader.remove_module_op_exports(); + + Ok(loader.payload.compilation_target) + } + + #[inline(always)] + fn should_drop_load_state(_loader: &Loader<'a, Self>) -> bool { + true + } + + #[inline(always)] + fn reset_machine(loader: &mut Loader<'a, Self>) { + loader.reset_machine(); + } + + #[inline(always)] + fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState { + &mut loader.term_stream.parser.lexer.machine_st + } +} + +pub struct Loader<'a, LS: LoadState<'a>> { + pub(super) payload: LS::LoaderFieldType, + pub(super) wam_prelude: MachinePreludeView<'a>, +} + +impl<'a, LS: LoadState<'a>> Loader<'a, LS> { + #[inline] + pub(super) fn new(wam: &'a mut Machine, term_stream: >::TS) -> Self { + let payload = LoadStatePayload::new(wam.code_repo.code.len(), term_stream); + let (wam_prelude, machine_st) = wam.prelude_view_and_machine_st(); + + Self { + payload: LS::new(machine_st, payload), + wam_prelude, + } + } + + pub(crate) fn load(mut self) -> Result { + while let Some(decl) = self.dequeue_terms()? { + self.load_decl(decl)?; + } + + LS::evacuate(self) + } + + /* + #[inline(always)] + pub(crate) fn load_state(&mut self) -> &mut LoadStatePayload<>::TS> { + self.payload.as_mut() + } + */ + + fn dequeue_terms(&mut self) -> Result, SessionError> { + while !self.payload.term_stream.eof()? { + let load_state = &mut self.payload; + let compilation_target = &load_state.compilation_target; + let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target); + + let term = load_state.term_stream.next(&composite_op_dir)?; + + // if is_consistent is false, self.predicates is not empty. + if !term.is_consistent(&load_state.predicates) { + self.compile_and_submit()?; + } + + let term = match term { + Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => { + return Ok(Some(setup_declaration(self, terms)?)); + } + term => term, + }; + + self.payload.predicates.push(term); + } + + Ok(None) + } + + pub(super) fn load_decl(&mut self, decl: Declaration) -> Result<(), SessionError> { + match decl { + Declaration::Dynamic(name, arity) => { + let compilation_target = self.payload.compilation_target; + self.add_dynamic_predicate(compilation_target, name, arity)?; + } + Declaration::MetaPredicate(module_name, name, meta_specs) => { + self.add_meta_predicate_record(module_name, name, meta_specs); + } + Declaration::Module(module_decl) => { + self.payload.compilation_target = CompilationTarget::Module(module_decl.name); + self.payload.predicates.compilation_target = self.payload.compilation_target; + + let listing_src = self.payload.term_stream.listing_src().clone(); + self.add_module(module_decl, listing_src); + } + Declaration::NonCountedBacktracking(name, arity) => { + self.payload.non_counted_bt_preds.insert((name, arity)); + } + Declaration::Op(op_decl) => { + self.add_op_decl(&op_decl); + } + Declaration::UseModule(module_src) => { + self.use_module(module_src)?; + } + Declaration::UseQualifiedModule(module_src, exports) => { + self.use_qualified_module(module_src, exports)?; + } + } + + Ok(()) + } + + pub(super) fn read_term_from_heap(&mut self, heap_term_loc: RegType) -> Result { + let machine_st = LS::machine_st(&mut self.payload); + let term_addr = machine_st[heap_term_loc]; + + /* + if let Ok(lit) = Literal::try_from(term_addr) { + return Ok(Term::Literal(Cell::default(), lit)); + } else if machine_st.is_cyclic_term(term_addr) { + return Err(SessionError::from(CompilationError::CannotParseCyclicTerm)); + } + */ + + let mut term_stack = vec![]; + let mut iter = stackful_post_order_iter(&mut machine_st.heap, term_addr); + + while let Some(addr) = iter.next() { + read_heap_cell!(addr, + (HeapCellValueTag::Lis) => { + let tail = term_stack.pop().unwrap(); + let head = term_stack.pop().unwrap(); + + term_stack.push(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => { + let offset_string = format!("_{}", h); + term_stack.push(Term::Var(Cell::default(), Rc::new(offset_string))); + } + (HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum | + HeapCellValueTag::Char | HeapCellValueTag::F64) => { + let addr = unmark_cell_bits!(addr); + term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap())); + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name))); + } else { + let subterms = term_stack + .drain(term_stack.len() - arity ..) + .collect(); + + term_stack.push(Term::Clause(Cell::default(), name, subterms)); + } + } + (HeapCellValueTag::PStr, string) => { + let tail = term_stack.pop().unwrap(); + + if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail { + term_stack.push(Term::PartialString( + Cell::default(), + string, + None, + )); + } else { + term_stack.push(Term::PartialString( + Cell::default(), + string, + Some(Box::new(tail)), + )); + } + } + (HeapCellValueTag::PStrOffset, h) => { + let string = cell_as_atom_cell!(iter.heap[h]).get_name(); + let tail = term_stack.pop().unwrap(); + + term_stack.push(Term::PartialString( + Cell::default(), + string, + Some(Box::new(tail)), + )); + } + _ => { + } + ); + } + + debug_assert!(term_stack.len() == 1); + Ok(term_stack.pop().unwrap()) + } + + fn reset_machine(&mut self) { + while let Some(record) = self.payload.retraction_info.records.pop() { match record { RetractionRecord::AddedMetaPredicate(target_module_name, key) => { - match target_module_name.as_str() { - "user" => { - self.wam.indices.meta_predicates.remove(&key); + match target_module_name { + atom!("user") => { + self.wam_prelude.indices.meta_predicates.remove(&key); } - _ => match self.wam.indices.modules.get_mut(&target_module_name) { + _ => match self.wam_prelude.indices.modules.get_mut(&target_module_name) { Some(ref mut module) => { module.meta_predicates.remove(&key); } @@ -154,14 +544,14 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::ReplacedMetaPredicate(target_module_name, name, meta_specs) => { - match target_module_name.as_str() { - "user" => { - self.wam + match target_module_name { + atom!("user") => { + self.wam_prelude .indices .meta_predicates .insert((name, meta_specs.len()), meta_specs); } - _ => match self.wam.indices.modules.get_mut(&target_module_name) { + _ => match self.wam_prelude.indices.modules.get_mut(&target_module_name) { Some(ref mut module) => { module .meta_predicates @@ -174,13 +564,13 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::AddedModule(module_name) => { - self.wam.indices.modules.remove(&module_name); + self.wam_prelude.indices.modules.remove(&module_name); } RetractionRecord::ReplacedModule( module_decl, listing_src, local_extensible_predicates, - ) => match self.wam.indices.modules.get_mut(&module_decl.name) { + ) => match self.wam_prelude.indices.modules.get_mut(&module_decl.name) { Some(ref mut module) => { module.module_decl = module_decl; module.listing_src = listing_src; @@ -193,7 +583,7 @@ impl<'a> Drop for LoadState<'a> { RetractionRecord::AddedDiscontiguousPredicate(compilation_target, key) => { match compilation_target { CompilationTarget::User => { - self.wam + self.wam_prelude .indices .extensible_predicates .get_mut(&key) @@ -202,7 +592,7 @@ impl<'a> Drop for LoadState<'a> { }); } CompilationTarget::Module(module_name) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { module.extensible_predicates.get_mut(&key).map(|skeleton| { skeleton.core.is_discontiguous = false; @@ -216,7 +606,7 @@ impl<'a> Drop for LoadState<'a> { RetractionRecord::AddedDynamicPredicate(compilation_target, key) => { match compilation_target { CompilationTarget::User => { - self.wam + self.wam_prelude .indices .extensible_predicates .get_mut(&key) @@ -225,10 +615,11 @@ impl<'a> Drop for LoadState<'a> { }); } CompilationTarget::Module(module_name) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { module.extensible_predicates.get_mut(&key).map(|skeleton| { skeleton.core.is_dynamic = false; + skeleton.core.retracted_dynamic_clauses = None; }); } None => {} @@ -239,7 +630,7 @@ impl<'a> Drop for LoadState<'a> { RetractionRecord::AddedMultifilePredicate(compilation_target, key) => { match compilation_target { CompilationTarget::User => { - self.wam + self.wam_prelude .indices .extensible_predicates .get_mut(&key) @@ -248,7 +639,7 @@ impl<'a> Drop for LoadState<'a> { }); } CompilationTarget::Module(module_name) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { module.extensible_predicates.get_mut(&key).map(|skeleton| { skeleton.core.is_multifile = false; @@ -260,25 +651,24 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::AddedModuleOp(module_name, mut op_decl) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { op_decl.remove(&mut module.op_dir); } None => {} } } - RetractionRecord::ReplacedModuleOp(module_name, mut op_decl, prec, spec) => { - match self.wam.indices.modules.get_mut(&module_name) { + RetractionRecord::ReplacedModuleOp(module_name, mut op_decl, op_desc) => { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { - op_decl.prec = prec; - op_decl.spec = spec; + op_decl.op_desc = op_desc; op_decl.insert_into_op_dir(&mut module.op_dir); } None => {} } } RetractionRecord::AddedModulePredicate(module_name, key) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { module.code_dir.remove(&key); } @@ -286,7 +676,7 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::ReplacedModulePredicate(module_name, key, old_code_idx) => { - match self.wam.indices.modules.get_mut(&module_name) { + match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(ref mut module) => { module .code_dir @@ -297,23 +687,22 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::AddedExtensiblePredicate(compilation_target, key) => { - self.wam + self.wam_prelude .indices .remove_predicate_skeleton(&compilation_target, &key); } RetractionRecord::AddedUserOp(mut op_decl) => { - op_decl.remove(&mut self.wam.indices.op_dir); + op_decl.remove(&mut self.wam_prelude.indices.op_dir); } - RetractionRecord::ReplacedUserOp(mut op_decl, prec, spec) => { - op_decl.prec = prec; - op_decl.spec = spec; - op_decl.insert_into_op_dir(&mut self.wam.indices.op_dir); + RetractionRecord::ReplacedUserOp(mut op_decl, op_desc) => { + op_decl.op_desc = op_desc; + op_decl.insert_into_op_dir(&mut self.wam_prelude.indices.op_dir); } RetractionRecord::AddedUserPredicate(key) => { - self.wam.indices.code_dir.remove(&key); + self.wam_prelude.indices.code_dir.remove(&key); } RetractionRecord::ReplacedUserPredicate(key, old_code_idx) => { - self.wam + self.wam_prelude .indices .code_dir .get_mut(&key) @@ -322,7 +711,7 @@ impl<'a> Drop for LoadState<'a> { RetractionRecord::AddedIndex(index_key, clause_loc) => { // WAS: inner_index_locs) => { if let Some(index_loc) = index_key.switch_on_term_loc() { - let indexing_code = match &mut self.wam.code_repo.code[index_loc] { + let indexing_code = match &mut self.wam_prelude.code_repo.code[index_loc] { Line::IndexingCode(indexing_code) => indexing_code, _ => { unreachable!() @@ -330,14 +719,14 @@ impl<'a> Drop for LoadState<'a> { }; match index_key { - OptArgIndexKey::Constant( + OptArgIndexKey::Literal( _, index_loc, constant, overlapping_constants, ) => { remove_constant_indices( - &constant, + constant, &overlapping_constants, indexing_code, clause_loc - index_loc, // WAS: &inner_index_locs, @@ -345,7 +734,7 @@ impl<'a> Drop for LoadState<'a> { } OptArgIndexKey::Structure(_, index_loc, name, arity) => { remove_structure_index( - &name, + name, arity, indexing_code, clause_loc - index_loc, // WAS: &inner_index_locs, @@ -369,7 +758,7 @@ impl<'a> Drop for LoadState<'a> { // write the retraction logic of this arm. } RetractionRecord::ReplacedChoiceOffset(instr_loc, offset) => { - match &mut self.wam.code_repo.code[instr_loc] { + match self.wam_prelude.code_repo.code[instr_loc] { Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) | Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) | Line::Choice(ChoiceInstruction::DefaultRetryMeElse(ref mut o)) => { @@ -381,7 +770,7 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::AppendedTrustMe(instr_loc, offset, is_default) => { - match &mut self.wam.code_repo.code[instr_loc] { + match self.wam_prelude.code_repo.code[instr_loc] { Line::Choice(ref mut choice_instr) => { *choice_instr = if is_default { ChoiceInstruction::DefaultTrustMe(offset) @@ -395,7 +784,7 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::ReplacedSwitchOnTermVarIndex(index_loc, old_v) => { - match &mut self.wam.code_repo.code[index_loc] { + match self.wam_prelude.code_repo.code[index_loc] { Line::IndexingCode(ref mut indexing_code) => match &mut indexing_code[0] { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( _, @@ -410,20 +799,20 @@ impl<'a> Drop for LoadState<'a> { } } RetractionRecord::ModifiedTryMeElse(instr_loc, o) => { - self.wam.code_repo.code[instr_loc] = + self.wam_prelude.code_repo.code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(o)); } RetractionRecord::ModifiedRetryMeElse(instr_loc, o) => { - self.wam.code_repo.code[instr_loc] = + self.wam_prelude.code_repo.code[instr_loc] = Line::Choice(ChoiceInstruction::RetryMeElse(o)); } RetractionRecord::ModifiedRevJmpBy(instr_loc, o) => { - self.wam.code_repo.code[instr_loc] = + self.wam_prelude.code_repo.code[instr_loc] = Line::Control(ControlInstruction::RevJmpBy(o)); } RetractionRecord::SkeletonClausePopBack(compilation_target, key) => { match self - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&compilation_target, &key) { @@ -436,7 +825,7 @@ impl<'a> Drop for LoadState<'a> { } RetractionRecord::SkeletonClausePopFront(compilation_target, key) => { match self - .wam + .wam_prelude .indices .get_predicate_skeleton_mut(&compilation_target, &key) { @@ -453,10 +842,12 @@ impl<'a> Drop for LoadState<'a> { local_compilation_target, key, ) => { - match self.wam.indices.get_local_predicate_skeleton_mut( + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( src_compilation_target, local_compilation_target, - self.listing_src_file_name(), + listing_src_file_name, key, ) { Some(skeleton) => { @@ -470,10 +861,12 @@ impl<'a> Drop for LoadState<'a> { local_compilation_target, key, ) => { - match self.wam.indices.get_local_predicate_skeleton_mut( + let listing_src_file_name = self.listing_src_file_name(); + + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( src_compilation_target, local_compilation_target, - self.listing_src_file_name(), + listing_src_file_name, key, ) { Some(skeleton) => { @@ -488,401 +881,175 @@ impl<'a> Drop for LoadState<'a> { key, len, ) => { - match self.wam.indices.get_local_predicate_skeleton_mut( - src_compilation_target, - local_compilation_target, - self.listing_src_file_name(), - key, - ) { - Some(skeleton) => { - skeleton.clause_clause_locs.truncate_back(len); - } - None => {} - } - } - RetractionRecord::SkeletonClauseTruncateBack(compilation_target, key, len) => { - match self - .wam - .indices - .get_predicate_skeleton_mut(&compilation_target, &key) - { - Some(skeleton) => { - skeleton.clauses.truncate_back(len); - skeleton.core.clause_clause_locs.truncate_back(len); - } - None => {} - } - } - RetractionRecord::SkeletonClauseStartReplaced( - compilation_target, - key, - target_pos, - clause_start, - ) => { - match self - .wam - .indices - .get_predicate_skeleton_mut(&compilation_target, &key) - { - Some(skeleton) => { - skeleton.clauses[target_pos].clause_start = clause_start; - } - None => {} - } - } - RetractionRecord::RemovedSkeletonClause( - compilation_target, - key, - target_pos, - clause_index_info, - clause_clause_loc, - ) => { - match self - .wam - .indices - .get_predicate_skeleton_mut(&compilation_target, &key) - { - Some(skeleton) => { - skeleton - .core - .clause_clause_locs - .insert(target_pos, clause_clause_loc); - skeleton.clauses.insert(target_pos, clause_index_info); - } - None => {} - } - } - RetractionRecord::ReplacedIndexingLine(index_loc, indexing_code) => { - self.wam.code_repo.code[index_loc] = Line::IndexingCode(indexing_code); - } - RetractionRecord::RemovedLocalSkeletonClauseLocations( - compilation_target, - local_compilation_target, - key, - clause_locs, - ) => { - match self.wam.indices.get_local_predicate_skeleton_mut( - compilation_target, - local_compilation_target, - self.listing_src_file_name(), - key, - ) { - Some(skeleton) => skeleton.clause_clause_locs = clause_locs, - None => {} - } - } - RetractionRecord::RemovedSkeleton(compilation_target, key, skeleton) => { - match compilation_target { - CompilationTarget::User => { - self.wam.indices.extensible_predicates.insert(key, skeleton); - } - CompilationTarget::Module(module_name) => { - if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { - module.extensible_predicates.insert(key, skeleton); - } - } - } - } - RetractionRecord::ReplacedDynamicElseOffset(instr_loc, next) => { - match &mut self.wam.code_repo.code[instr_loc] { - Line::Choice(ChoiceInstruction::DynamicElse( - _, - _, - NextOrFail::Next(ref mut o), - )) - | Line::Choice(ChoiceInstruction::DynamicInternalElse( - _, - _, - NextOrFail::Next(ref mut o), - )) => { - *o = next; - } - _ => {} - } - } - RetractionRecord::AppendedNextOrFail(instr_loc, fail) => { - match &mut self.wam.code_repo.code[instr_loc] { - Line::Choice(ChoiceInstruction::DynamicElse( - _, - _, - ref mut next_or_fail, - )) - | Line::Choice(ChoiceInstruction::DynamicInternalElse( - _, - _, - ref mut next_or_fail, - )) => { - *next_or_fail = fail; - } - _ => {} - } - } - } - } - - // TODO: necessary? unnecessary? - // self.wam.code_repo.code.truncate(self.retraction_info.orig_code_extent); - } -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub(crate) enum CompilationTarget { - Module(ClauseName), - User, -} - -impl Default for CompilationTarget { - #[inline] - fn default() -> Self { - CompilationTarget::User - } -} - -impl CompilationTarget { - #[inline] - pub(super) fn take(&mut self) -> CompilationTarget { - mem::replace(self, CompilationTarget::User) - } + let listing_src_file_name = self.listing_src_file_name(); - #[inline] - pub(crate) fn module_name(&self) -> ClauseName { - match self { - CompilationTarget::User => { - clause_name!("user") - } - CompilationTarget::Module(ref module_name) => module_name.clone(), - } - } -} - -pub(crate) struct PredicateQueue { - pub(super) predicates: Vec, - pub(super) compilation_target: CompilationTarget, -} - -impl PredicateQueue { - #[inline] - pub(super) fn push(&mut self, clause: Term) { - self.predicates.push(clause); - } - - #[inline] - pub(crate) fn first(&self) -> Option<&Term> { - self.predicates.first() - } - - #[inline] - pub(crate) fn is_empty(&self) -> bool { - self.predicates.is_empty() - } - - #[inline] - pub(super) fn take(&mut self) -> Self { - Self { - predicates: mem::replace(&mut self.predicates, vec![]), - compilation_target: self.compilation_target.take(), - } - } - - #[inline] - pub(super) fn len(&self) -> usize { - self.predicates.len() - } -} - -macro_rules! predicate_queue { - [$($v:expr),*] => ( - PredicateQueue { - predicates: vec![$($v,)*], - compilation_target: CompilationTarget::default(), - } - ) -} - -pub(crate) struct Loader<'a, TermStream> { - pub(super) load_state: LoadState<'a>, - pub(super) predicates: PredicateQueue, - pub(super) clause_clauses: Vec<(Term, Term)>, - pub(super) term_stream: TermStream, - pub(super) non_counted_bt_preds: IndexSet, -} - -impl<'a, TS: TermStream> Loader<'a, TS> { - #[inline] - pub(super) fn new(term_stream: TS, wam: &'a mut Machine) -> Self { - let load_state = LoadState { - compilation_target: CompilationTarget::User, - module_op_exports: vec![], - retraction_info: RetractionInfo::new(wam.code_repo.code.len()), - wam, - }; - - Self { - load_state, - term_stream, - non_counted_bt_preds: IndexSet::new(), - predicates: predicate_queue![], - clause_clauses: vec![], - } - } - - pub(crate) fn load(mut self) -> Result { - while let Some(decl) = self.dequeue_terms()? { - self.load_decl(decl)?; - } - - TS::evacuate(self) - } - - fn dequeue_terms(&mut self) -> Result, SessionError> { - while !self.term_stream.eof()? { - let term = self.term_stream.next(&self.load_state.composite_op_dir())?; - - // if is_consistent is false, self.predicates is not empty. - if !term.is_consistent(&self.predicates) { - self.compile_and_submit()?; - } - - let term = match term { - Term::Clause(_, name, terms, _) if name.as_str() == ":-" && terms.len() == 1 => { - return Ok(Some(setup_declaration(&self.load_state, terms)?)); - } - term => term, - }; - - self.predicates.push(term); - } - - Ok(None) - } - - pub(super) fn load_decl(&mut self, decl: Declaration) -> Result<(), SessionError> { - match decl { - Declaration::Dynamic(name, arity) => { - let compilation_target = self.load_state.compilation_target.clone(); - self.add_dynamic_predicate(compilation_target, name, arity)?; - } - Declaration::MetaPredicate(module_name, name, meta_specs) => { - self.load_state - .add_meta_predicate_record(module_name, name, meta_specs); - } - Declaration::Module(module_decl) => { - self.load_state.compilation_target = - CompilationTarget::Module(module_decl.name.clone()); - - self.predicates.compilation_target = self.load_state.compilation_target.clone(); - - self.load_state - .add_module(module_decl, self.term_stream.listing_src().clone()); - } - Declaration::NonCountedBacktracking(name, arity) => { - self.non_counted_bt_preds.insert((name, arity)); - } - Declaration::Op(op_decl) => { - self.load_state.add_op_decl(&op_decl); - } - Declaration::UseModule(module_src) => { - self.load_state.use_module(module_src)?; - } - Declaration::UseQualifiedModule(module_src, exports) => { - self.load_state.use_qualified_module(module_src, exports)?; - } - } - - Ok(()) - } - - pub(super) fn read_term_from_heap(&self, heap_term_loc: RegType) -> Result { - let machine_st = &self.load_state.wam.machine_st; - let term_addr = machine_st[heap_term_loc]; - - if machine_st.is_cyclic_term(term_addr) { - return Err(SessionError::from(CompilationError::CannotParseCyclicTerm)); - } - - let mut term_stack = vec![]; - - for addr in machine_st.post_order_iter(term_addr) { - match machine_st.heap.index_addr(&addr).as_ref() { - HeapCellValue::Addr(Addr::Lis(_)) | HeapCellValue::Addr(Addr::PStrLocation(..)) => { - let tail = term_stack.pop().unwrap(); - let head = term_stack.pop().unwrap(); - - term_stack.push(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + src_compilation_target, + local_compilation_target, + listing_src_file_name, + key, + ) { + Some(skeleton) => { + skeleton.clause_clause_locs.truncate_back(len); + } + None => {} + } } - HeapCellValue::Addr(addr) => { - if let Some(r) = addr.as_var() { - let offset_string = match r { - Ref::HeapCell(h) | Ref::AttrVar(h) => format!("_{}", h), - Ref::StackCell(fr, sc) => format!("_s_{}_{}", fr, sc), - }; + RetractionRecord::SkeletonClauseTruncateBack(compilation_target, key, len) => { + match self + .wam_prelude + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton.clauses.truncate_back(len); + skeleton.core.clause_clause_locs.truncate_back(len); + } + None => {} + } + } + RetractionRecord::SkeletonClauseStartReplaced( + compilation_target, + key, + target_pos, + clause_start, + ) => { + match self + .wam_prelude + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton.clauses[target_pos].clause_start = clause_start; + } + None => {} + } + } + RetractionRecord::RemovedDynamicSkeletonClause( + compilation_target, + key, + target_pos, + clause_clause_loc, + ) => { + match self + .wam_prelude + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + if let Some(removed_clauses) = &mut skeleton.core.retracted_dynamic_clauses { + let clause_index_info = removed_clauses.pop().unwrap(); - term_stack.push(Term::Var(Cell::default(), Rc::new(offset_string))); - } else { - match addr.as_constant_index(machine_st) { - Some(constant) => { - term_stack.push(Term::Constant(Cell::default(), constant)); - } - None => { - return Err(SessionError::from(CompilationError::UnreadableTerm)); + skeleton + .core + .clause_clause_locs + .insert(target_pos, clause_clause_loc); + + skeleton.clauses.insert(target_pos, clause_index_info); } } + None => {} } } - HeapCellValue::Atom(ref name, ref shared_op_desc) => { - term_stack.push(Term::Constant( - Cell::default(), - Constant::Atom(name.clone(), shared_op_desc.clone()), - )); + RetractionRecord::RemovedSkeletonClause( + compilation_target, + key, + target_pos, + clause_index_info, + clause_clause_loc, + ) => { + match self + .wam_prelude + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + { + Some(skeleton) => { + skeleton + .core + .clause_clause_locs + .insert(target_pos, clause_clause_loc); + skeleton.clauses.insert(target_pos, clause_index_info); + } + None => {} + } } - HeapCellValue::Integer(ref integer) => { - term_stack.push(Term::Constant( - Cell::default(), - Constant::Integer(integer.clone()), - )); + RetractionRecord::ReplacedIndexingLine(index_loc, indexing_code) => { + self.wam_prelude.code_repo.code[index_loc] = Line::IndexingCode(indexing_code); } - HeapCellValue::NamedStr(arity, ref name, ref shared_op_desc) => { - let subterms = term_stack - .drain(term_stack.len() - arity..) - .map(Box::new) - .collect(); + RetractionRecord::RemovedLocalSkeletonClauseLocations( + compilation_target, + local_compilation_target, + key, + clause_locs, + ) => { + let listing_src_file_name = self.listing_src_file_name(); - term_stack.push(Term::Clause( - Cell::default(), - name.clone(), - subterms, - shared_op_desc.clone(), - )); + match self.wam_prelude.indices.get_local_predicate_skeleton_mut( + compilation_target, + local_compilation_target, + listing_src_file_name, + key, + ) { + Some(skeleton) => skeleton.clause_clause_locs = clause_locs, + None => {} + } } - HeapCellValue::PartialString(..) => { - let string = machine_st.heap_pstr_iter(addr).to_string(); - term_stack.push(Term::Constant( - Cell::default(), - Constant::String(Rc::new(string)), - )); + RetractionRecord::RemovedSkeleton(compilation_target, key, skeleton) => { + match compilation_target { + CompilationTarget::User => { + self.wam_prelude.indices.extensible_predicates.insert(key, skeleton); + } + CompilationTarget::Module(module_name) => { + if let Some(module) = self.wam_prelude.indices.modules.get_mut(&module_name) { + module.extensible_predicates.insert(key, skeleton); + } + } + } } - HeapCellValue::Rational(ref rational) => { - term_stack.push(Term::Constant( - Cell::default(), - Constant::Rational(rational.clone()), - )); + RetractionRecord::ReplacedDynamicElseOffset(instr_loc, next) => { + match self.wam_prelude.code_repo.code[instr_loc] { + Line::Choice(ChoiceInstruction::DynamicElse( + _, + _, + NextOrFail::Next(ref mut o), + )) + | Line::Choice(ChoiceInstruction::DynamicInternalElse( + _, + _, + NextOrFail::Next(ref mut o), + )) => { + *o = next; + } + _ => {} + } } - _ => { - return Err(SessionError::from(CompilationError::UnreadableTerm)); + RetractionRecord::AppendedNextOrFail(instr_loc, fail) => { + match self.wam_prelude.code_repo.code[instr_loc] { + Line::Choice(ChoiceInstruction::DynamicElse( + _, + _, + ref mut next_or_fail, + )) + | Line::Choice(ChoiceInstruction::DynamicInternalElse( + _, + _, + ref mut next_or_fail, + )) => { + *next_or_fail = fail; + } + _ => {} + } } } } - - debug_assert!(term_stack.len() == 1); - Ok(term_stack.pop().unwrap()) } fn extract_module_export_list_from_heap( - &self, + &mut self, r: RegType, ) -> Result, SessionError> { let export_list = self.read_term_from_heap(r)?; - let atom_tbl = self.load_state.wam.machine_st.atom_tbl.clone(); + let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl; let export_list = setup_module_export_list(export_list, atom_tbl)?; Ok(export_list.into_iter().collect()) @@ -890,19 +1057,16 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> { match term { - Term::Clause(_, turnstile, mut terms, _) - if turnstile.as_str() == ":-" && terms.len() == 2 => + Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 => { - let body = *terms.pop().unwrap(); - let head = *terms.pop().unwrap(); + let body = terms.pop().unwrap(); + let head = terms.pop().unwrap(); - self.clause_clauses.push((head, body)); + self.payload.clause_clauses.push((head, body)); } - head @ Term::Constant(_, Constant::Atom(..)) | head @ Term::Clause(..) => { - let body = - Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None)); - - self.clause_clauses.push((head, body)); + head @ Term::Literal(_, Literal::Atom(..)) | head @ Term::Clause(..) => { + let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true"))); + self.payload.clause_clauses.push((head, body)); } _ => { return Err(CompilationError::InadmissibleFact); @@ -915,7 +1079,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_extensible_predicate_declaration( &mut self, compilation_target: CompilationTarget, - name: ClauseName, + name: Atom, arity: usize, flag_accessor: impl Fn(&mut LocalPredicateSkeleton) -> &mut bool, retraction_fn: impl Fn(CompilationTarget, PredicateKey) -> RetractionRecord, @@ -926,8 +1090,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { match &compilation_target { CompilationTarget::User => { match self - .load_state - .wam + .wam_prelude .indices .extensible_predicates .get_mut(&key) @@ -936,19 +1099,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> { if !*flag_accessor(&mut skeleton.core) { *flag_accessor(&mut skeleton.core) = true; - self.load_state.retraction_info.push_record(retraction_fn( - compilation_target.clone(), - key.clone(), + self.payload.retraction_info.push_record(retraction_fn( + compilation_target, + key, )); } } None => { - if self.load_state.compilation_target == compilation_target { + if self.payload.compilation_target == compilation_target { let mut skeleton = PredicateSkeleton::new(); *flag_accessor(&mut skeleton.core) = true; - self.load_state.add_extensible_predicate( - key.clone(), + self.add_extensible_predicate( + key, skeleton, CompilationTarget::User, ); @@ -959,27 +1122,27 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } } CompilationTarget::Module(ref module_name) => { - match self.load_state.wam.indices.modules.get_mut(module_name) { + match self.wam_prelude.indices.modules.get_mut(module_name) { Some(ref mut module) => match module.extensible_predicates.get_mut(&key) { Some(ref mut skeleton) => { if !*flag_accessor(&mut skeleton.core) { *flag_accessor(&mut skeleton.core) = true; - self.load_state.retraction_info.push_record(retraction_fn( - compilation_target.clone(), - key.clone(), + self.payload.retraction_info.push_record(retraction_fn( + compilation_target, + key, )); } } None => { - if self.load_state.compilation_target == compilation_target { + if self.payload.compilation_target == compilation_target { let mut skeleton = PredicateSkeleton::new(); *flag_accessor(&mut skeleton.core) = true; - self.load_state.add_extensible_predicate( - key.clone(), + self.add_extensible_predicate( + key, skeleton, - compilation_target.clone(), + compilation_target, ); } else { throw_permission_error = true; @@ -987,16 +1150,15 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } }, None => { - self.load_state - .add_dynamically_generated_module(module_name); + self.add_dynamically_generated_module(*module_name); let mut skeleton = PredicateSkeleton::new(); *flag_accessor(&mut skeleton.core) = true; - self.load_state.add_extensible_predicate( - key.clone(), + self.add_extensible_predicate( + key, skeleton, - compilation_target.clone(), + compilation_target, ); } } @@ -1004,17 +1166,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } if !throw_permission_error { - match self.load_state.compilation_target.clone() { + let listing_src_file_name = self.listing_src_file_name(); + let payload_compilation_target = self.payload.compilation_target; + + match payload_compilation_target { CompilationTarget::User => { match self - .load_state - .wam + .wam_prelude .indices .get_local_predicate_skeleton_mut( - self.load_state.compilation_target.clone(), - compilation_target.clone(), - self.load_state.listing_src_file_name(), - key.clone(), + payload_compilation_target, + compilation_target, + listing_src_file_name, + key, ) { Some(skeleton) => { if !*flag_accessor(skeleton) { @@ -1025,19 +1189,19 @@ impl<'a, TS: TermStream> Loader<'a, TS> { let mut skeleton = LocalPredicateSkeleton::new(); *flag_accessor(&mut skeleton) = true; - self.load_state.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + self.add_local_extensible_predicate( + compilation_target, + key, skeleton, ); } } } CompilationTarget::Module(ref module_name) => { - match self.load_state.wam.indices.modules.get_mut(module_name) { + match self.wam_prelude.indices.modules.get_mut(module_name) { Some(module) => match module .local_extensible_predicates - .get_mut(&(compilation_target.clone(), key.clone())) + .get_mut(&(compilation_target, key)) { Some(skeleton) => { if !*flag_accessor(skeleton) { @@ -1048,23 +1212,22 @@ impl<'a, TS: TermStream> Loader<'a, TS> { let mut skeleton = LocalPredicateSkeleton::new(); *flag_accessor(&mut skeleton) = true; - self.load_state.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + self.add_local_extensible_predicate( + compilation_target, + key, skeleton, ); } }, None => { - self.load_state - .add_dynamically_generated_module(module_name); + self.add_dynamically_generated_module(*module_name); let mut skeleton = LocalPredicateSkeleton::new(); *flag_accessor(&mut skeleton) = true; - self.load_state.add_local_extensible_predicate( - compilation_target.clone(), - key.clone(), + self.add_local_extensible_predicate( + compilation_target, + key, skeleton, ); } @@ -1072,7 +1235,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } } - self.fail_on_undefined(&compilation_target, key); + self.fail_on_undefined(compilation_target, key); Ok(()) } else { @@ -1083,20 +1246,18 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } } - fn fail_on_undefined(&mut self, compilation_target: &CompilationTarget, key: PredicateKey) { + fn fail_on_undefined(&mut self, compilation_target: CompilationTarget, key: PredicateKey) { /* * DynamicUndefined isn't only applied to dynamic predicates * but to multifile and discontiguous predicates as well. */ - let code_index = self - .load_state - .get_or_insert_code_index(key.clone(), compilation_target.clone()); + let code_index = self.get_or_insert_code_index(key, compilation_target); if let IndexPtr::Undefined = code_index.get() { set_code_index( - &mut self.load_state.retraction_info, - compilation_target, + &mut self.payload.retraction_info, + &compilation_target, key, &code_index, IndexPtr::DynamicUndefined, @@ -1107,7 +1268,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_discontiguous_predicate( &mut self, compilation_target: CompilationTarget, - name: ClauseName, + name: Atom, arity: usize, ) -> Result<(), SessionError> { self.add_extensible_predicate_declaration( @@ -1122,12 +1283,12 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_dynamic_predicate( &mut self, compilation_target: CompilationTarget, - name: ClauseName, + name: Atom, arity: usize, ) -> Result<(), SessionError> { self.add_extensible_predicate_declaration( - compilation_target.clone(), - name.clone(), + compilation_target, + name, arity, |skeleton| &mut skeleton.is_dynamic, RetractionRecord::AddedDynamicPredicate, @@ -1137,7 +1298,7 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_multifile_predicate( &mut self, compilation_target: CompilationTarget, - name: ClauseName, + name: Atom, arity: usize, ) -> Result<(), SessionError> { self.add_extensible_predicate_declaration( @@ -1152,13 +1313,13 @@ impl<'a, TS: TermStream> Loader<'a, TS> { fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> { if let Some(predicate_name) = ClauseInfo::name(term) { let arity = ClauseInfo::arity(term); + let predicates_compilation_target = self.payload.predicates.compilation_target; let is_dynamic = self - .load_state - .wam + .wam_prelude .indices .get_predicate_skeleton( - &self.predicates.compilation_target, + &predicates_compilation_target, &(predicate_name, arity), ) .map(|skeleton| skeleton.core.is_dynamic) @@ -1173,15 +1334,18 @@ impl<'a, TS: TermStream> Loader<'a, TS> { } pub(super) fn retract_local_clauses(&mut self, key: &PredicateKey, is_dynamic: bool) { + let payload_compilation_target = self.payload.compilation_target; + let predicates_compilation_target = self.payload.predicates.compilation_target; + let listing_src_file_name = self.listing_src_file_name(); + let clause_locs = match self - .load_state - .wam + .wam_prelude .indices .get_local_predicate_skeleton_mut( - self.load_state.compilation_target.clone(), - self.predicates.compilation_target.clone(), - self.load_state.listing_src_file_name(), - key.clone(), + payload_compilation_target, + predicates_compilation_target, + listing_src_file_name, + *key, ) { Some(skeleton) if !skeleton.clause_clause_locs.is_empty() => { mem::replace(&mut skeleton.clause_clause_locs, sdeq![]) @@ -1189,29 +1353,47 @@ impl<'a, TS: TermStream> Loader<'a, TS> { _ => return, }; - self.load_state.retraction_info.push_record( + self.payload.retraction_info.push_record( RetractionRecord::RemovedLocalSkeletonClauseLocations( - self.load_state.compilation_target.clone(), - self.predicates.compilation_target.clone(), - key.clone(), + payload_compilation_target, + predicates_compilation_target, + *key, clause_locs.clone(), ), ); - self.load_state.retract_local_clauses( - self.predicates.compilation_target.clone(), - key.clone(), + self.retract_local_clauses_impl( + predicates_compilation_target, + *key, &clause_locs, ); if is_dynamic { - let clause_clause_compilation_target = match &self.predicates.compilation_target { - CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), - module_name => module_name.clone(), + let clause_clause_compilation_target = match predicates_compilation_target { + CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), + module_name => module_name, }; - self.load_state - .retract_local_clause_clauses(clause_clause_compilation_target, &clause_locs); + self.retract_local_clause_clauses(clause_clause_compilation_target, &clause_locs); + } + } +} + +impl<'a> MachinePreludeView<'a> { + #[inline] + pub(super) fn composite_op_dir(&self, compilation_target: &CompilationTarget) -> CompositeOpDir { + match compilation_target { + CompilationTarget::User => CompositeOpDir::new(&self.indices.op_dir, None), + CompilationTarget::Module(ref module_name) => { + match self.indices.modules.get(module_name) { + Some(ref module) => { + CompositeOpDir::new(&self.indices.op_dir, Some(&module.op_dir)) + } + None => { + unreachable!() + } + } + } } } } @@ -1220,50 +1402,40 @@ impl Machine { pub(crate) fn use_module(&mut self) { let subevacuable_addr = self .machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(2)])); - - let module_src = ModuleSource::Library(match subevacuable_addr { - Addr::LoadStatePayload(payload) => match &self.machine_st.heap[payload] { - HeapCellValue::LoadStatePayload(payload) => match &payload.compilation_target { - CompilationTarget::Module(ref module_name) => module_name.clone(), - CompilationTarget::User => { - return; - } - }, - _ => { - unreachable!() + .store(self.machine_st.deref(self.machine_st.registers[2])); + + let module_src = ModuleSource::Library({ + let payload = cell_as_load_state_payload!(subevacuable_addr); + + match payload.compilation_target { + CompilationTarget::Module(module_name) => module_name, + CompilationTarget::User => { + return; } - }, - _ => { - unreachable!() } }); - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let use_module = || { let export_list = loader.extract_module_export_list_from_heap(temp_v!(3))?; if export_list.is_empty() { - loader.load_state.use_module(module_src)?; + loader.use_module(module_src)?; } else { - loader - .load_state - .use_qualified_module(module_src, export_list)?; + loader.use_qualified_module(module_src, export_list)?; } - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = use_module(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn load_compiled_library(&mut self) { - let library = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let library = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); if let Some(module) = self.indices.modules.get(&library) { @@ -1272,38 +1444,33 @@ impl Machine { return; } - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); let import_module = || { let export_list = loader.extract_module_export_list_from_heap(temp_v!(2))?; if export_list.is_empty() { - loader.load_state.import_module(library)?; + loader.import_module(library)?; } else { - loader - .load_state - .import_qualified_module(library, export_list)?; + loader.import_qualified_module(library, export_list)?; } - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = import_module(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } else { self.machine_st.fail = true; } } pub(crate) fn declare_module(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); - // let export_list = self.machine_st.extract_module_export_list(temp_v!(2)); - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); let declare_module = || { // let export_list = export_list?; @@ -1315,11 +1482,11 @@ impl Machine { }; loader.load_decl(Declaration::Module(module_decl))?; - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = declare_module(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } #[inline] @@ -1351,145 +1518,135 @@ impl Machine { fn add_extensible_predicate_declaration( &mut self, - decl_adder: impl Fn( - &mut Loader, + decl_adder: impl for<'a> Fn( + &mut Loader<'a, LiveLoadAndMachineState<'a>>, CompilationTarget, - ClauseName, + Atom, usize, ) -> Result<(), SessionError>, ) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; - let predicate_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(2)])) + let predicate_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) ); let arity = self .machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(3)])); + .store(self.machine_st.deref(self.machine_st.registers[3])); - let arity = match Number::try_from((arity, &self.machine_st.heap)) { + let arity = match Number::try_from(arity) { Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => Ok(n.to_usize().unwrap()), - Ok(Number::Fixnum(n)) if n >= 0 && n <= MAX_ARITY as isize => { - Ok(usize::try_from(n).unwrap()) + Ok(Number::Fixnum(n)) if n.get_num() >= 0 && n.get_num() <= MAX_ARITY as i64 => { + Ok(usize::try_from(n.get_num()).unwrap()) } _ => Err(SessionError::from(CompilationError::InvalidRuleHead)), }; - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(4)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(4)); - let add_predicate_decl = || { + let add_predicate_decl = move || { decl_adder(&mut loader, compilation_target, predicate_name, arity?)?; - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = add_predicate_decl(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn add_term_expansion_clause(&mut self) { - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let add_clause = || { let term = loader.read_term_from_heap(temp_v!(1))?; - loader.load_state.incremental_compile_clause( - (clause_name!("term_expansion"), 2), + loader.incremental_compile_clause( + (atom!("term_expansion"), 2), term, CompilationTarget::User, false, AppendOrPrepend::Append, )?; - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = add_clause(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn add_goal_expansion_clause(&mut self) { - let target_module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let target_module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); - let compilation_target = match target_module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match target_module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(target_module_name), }; let add_clause = || { let term = loader.read_term_from_heap(temp_v!(2))?; - loader.load_state.incremental_compile_clause( - (clause_name!("goal_expansion"), 2), + loader.incremental_compile_clause( + (atom!("goal_expansion"), 2), term, compilation_target, false, // backtracking inferences are counted by call_with_inference_limit. AppendOrPrepend::Append, )?; - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = add_clause(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn add_in_situ_filename_module(&mut self) { - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let add_in_situ_filename_module = || { - if let Some(filename) = loader.load_state.listing_src_file_name() { + if let Some(filename) = loader.listing_src_file_name() { let module_decl = ModuleDecl { name: filename, exports: vec![], }; - let module_name = module_decl.name.clone(); + let module_name = module_decl.name; if !loader - .load_state - .wam + .wam_prelude .indices .modules .contains_key(&module_decl.name) { let module = Module::new_in_situ(module_decl); loader - .load_state - .wam + .wam_prelude .indices .modules .insert(module_name, module); } else { - loader.load_state.reset_in_situ_module( + loader.reset_in_situ_module( module_decl.clone(), &ListingSource::DynamicallyGenerated, ); - match loader.load_state.wam.indices.modules.get_mut(&module_name) { + match loader.wam_prelude.indices.modules.get_mut(&module_name) { Some(module) => { for (key, value) in module.op_dir.drain(0..) { - let (prec, spec) = value.shared_op_desc().get(); - let mut op_decl = OpDecl::new(prec, spec, key.0); - - op_decl.remove(&mut loader.load_state.wam.indices.op_dir); + let mut op_decl = OpDecl::new(value, key.0); + op_decl.remove(&mut loader.wam_prelude.indices.op_dir); } } None => {} @@ -1497,83 +1654,78 @@ impl Machine { } } - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = add_in_situ_filename_module(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } - pub(crate) fn loader_from_heap_evacuable( - &mut self, + pub(crate) fn loader_from_heap_evacuable<'a>( + &'a mut self, r: RegType, - ) -> (Loader, usize) { - let (load_state_payload, evacuable_h) = match self - .machine_st - .store(self.machine_st.deref(self.machine_st[r])) - { - Addr::LoadStatePayload(h) => ( - mem::replace( - &mut self.machine_st.heap[h], - HeapCellValue::Addr(Addr::EmptyList), - ), - h, - ), - _ => { - unreachable!() - } - }; + ) -> Loader<'a, LiveLoadAndMachineState<'a>> { + let mut load_state = cell_as_load_state_payload!( + self.machine_st.store(self.machine_st.deref(self.machine_st[r])) + ); - match load_state_payload { - HeapCellValue::LoadStatePayload(payload) => { - (Loader::from_load_state_payload(self, payload), evacuable_h) - } - _ => { - unreachable!() - } + load_state.set_tag(ArenaHeaderTag::LiveLoadState); + + let (wam_prelude, machine_st) = self.prelude_view_and_machine_st(); + + Loader { + payload: LiveLoadAndMachineState { load_state, machine_st }, + wam_prelude, } } #[inline] pub(crate) fn push_load_state_payload(&mut self) { - let payload = Box::new(LoadStatePayload::new(self)); - let addr = Addr::LoadStatePayload( - self.machine_st - .heap - .push(HeapCellValue::LoadStatePayload(payload)), + let payload = arena_alloc!( + LoadStatePayload::new( + self.code_repo.code.len(), + LiveTermStream::new(ListingSource::User), + ), + &mut self.machine_st.arena ); - self.machine_st - .bind(self.machine_st[temp_v!(1)].as_var().unwrap(), addr); + let var = self.machine_st.deref( + self.machine_st.registers[1] + ); + + self.machine_st.bind( + var.as_var().unwrap(), + typed_arena_ptr_as_cell!(payload), + ); } #[inline] pub(crate) fn pop_load_state_payload(&mut self) { - let load_state_payload = match self - .machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) - { - Addr::LoadStatePayload(h) => mem::replace( - &mut self.machine_st.heap[h], - HeapCellValue::Addr(Addr::EmptyList), - ), - _ => { - unreachable!() - } - }; + let load_state_payload = self.machine_st.store( + self.machine_st.deref(self.machine_st.registers[1]) + ); - match load_state_payload { - HeapCellValue::LoadStatePayload(payload) => { - Loader::from_load_state_payload(self, payload); - } - _ => { - // unlike in loader_from_heap_evacuable, - // pop_load_state_payload is allowed to fail to find a - // LoadStatePayload in the heap, as a Rust-side - // top-level command may have failed to write the - // load state payload back to the heap. + // unlike in loader_from_heap_evacuable, + // pop_load_state_payload is allowed to fail to find a + // LoadStatePayload in the heap, as a Rust-side + // top-level command may have failed to write the + // load state payload back to the heap. + + read_heap_cell!(load_state_payload, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::LiveLoadState, payload) => { + unsafe { + std::ptr::drop_in_place( + payload.as_ptr() as *mut LiveLoadState, + ); + } + } + _ => {} + ); } - } + _ => {} + ); } #[inline] @@ -1585,94 +1737,79 @@ impl Machine { let stream = try_or_fail!( self.machine_st, self.machine_st.get_stream_or_alias( - self.machine_st[temp_v!(1)], + self.machine_st.registers[1], &self.indices.stream_aliases, - "$push_load_context", + atom!("$push_load_context"), 2, ) ); - let path = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(2)])) + let path = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) ); - self.load_contexts - .push(LoadContext::new(path.as_str(), stream)); + self.load_contexts.push(LoadContext::new(path.as_str(), stream)); } pub(crate) fn restore_load_state_payload( &mut self, - result: Result, - evacuable_h: usize, + result: Result, SessionError>, ) { match result { - Ok(payload) => { - self.machine_st.heap[evacuable_h] = - HeapCellValue::LoadStatePayload(Box::new(payload)); + Ok(_payload) => { } Err(e) => { - self.throw_session_error(e, (clause_name!("load"), 1)); + self.throw_session_error(e, (atom!("load"), 1)); } } } pub(crate) fn scoped_clause_to_evacuable(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); - let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + let loader = self.loader_from_heap_evacuable(temp_v!(3)); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; let result = loader.read_and_enqueue_term(temp_v!(2), compilation_target); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn clause_to_evacuable(&mut self) { - let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); - let compilation_target = loader.load_state.compilation_target.clone(); + let loader = self.loader_from_heap_evacuable(temp_v!(2)); + let compilation_target = loader.payload.compilation_target; let result = loader.read_and_enqueue_term(temp_v!(1), compilation_target); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn conclude_load(&mut self) { - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let compile_final_terms = || { - if !loader.predicates.is_empty() { + if !loader.payload.predicates.is_empty() { loader.compile_and_submit()?; } - loader.load_state.remove_module_op_exports(); - LiveTermStream::evacuate(loader) + loader.remove_module_op_exports(); + LiveLoadAndMachineState::evacuate(loader) }; let result = compile_final_terms(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn load_context_source(&mut self) { if let Some(load_context) = self.load_contexts.last() { let path_str = load_context.path.to_str().unwrap(); - let path_atom = clause_name!(path_str.to_string(), self.machine_st.atom_tbl); - - let path_addr = Addr::Con( - self.machine_st - .heap - .push(HeapCellValue::Atom(path_atom, None)), - ); + let path_atom = self.machine_st.atom_tbl.build_with(path_str); - self.machine_st - .unify(path_addr, self.machine_st[temp_v!(1)]); + self.machine_st.unify_atom(path_atom, self.machine_st.registers[1]); } else { self.machine_st.fail = true; } @@ -1683,17 +1820,9 @@ impl Machine { match load_context.path.file_name() { Some(file_name) if load_context.path.is_file() => { let file_name_str = file_name.to_str().unwrap(); - let file_name_atom = - clause_name!(file_name_str.to_string(), self.machine_st.atom_tbl); - - let file_name_addr = Addr::Con( - self.machine_st - .heap - .push(HeapCellValue::Atom(file_name_atom, None)), - ); + let file_name_atom = self.machine_st.atom_tbl.build_with(file_name_str); - self.machine_st - .unify(file_name_addr, self.machine_st[temp_v!(1)]); + self.machine_st.unify_atom(file_name_atom, self.machine_st.registers[1]); return; } _ => { @@ -1709,18 +1838,9 @@ impl Machine { if let Some(load_context) = self.load_contexts.last() { if let Some(directory) = load_context.path.parent() { let directory_str = directory.to_str().unwrap(); + let directory_atom = self.machine_st.atom_tbl.build_with(directory_str); - let directory_atom = - clause_name!(directory_str.to_string(), self.machine_st.atom_tbl); - - let directory_addr = Addr::Con( - self.machine_st - .heap - .push(HeapCellValue::Atom(directory_atom, None)), - ); - - self.machine_st - .unify(directory_addr, self.machine_st[temp_v!(1)]); + self.machine_st.unify_atom(directory_atom, self.machine_st.registers[1]); return; } } @@ -1730,14 +1850,7 @@ impl Machine { pub(crate) fn load_context_module(&mut self) { if let Some(load_context) = self.load_contexts.last() { - let module_name_addr = Addr::Con( - self.machine_st - .heap - .push(HeapCellValue::Atom(load_context.module.clone(), None)), - ); - - self.machine_st - .unify(module_name_addr, self.machine_st[temp_v!(1)]); + self.machine_st.unify_atom(load_context.module, self.machine_st.registers[1]); } else { self.machine_st.fail = true; } @@ -1745,63 +1858,57 @@ impl Machine { pub(crate) fn load_context_stream(&mut self) { if let Some(load_context) = self.load_contexts.last() { - let stream_addr = Addr::Stream( - self.machine_st - .heap - .push(HeapCellValue::Stream(load_context.stream.clone())), + self.machine_st.unify_constant( + UntypedArenaPtr::from(load_context.stream.as_ptr()), + self.machine_st.registers[1], ); - - self.machine_st - .unify(stream_addr, self.machine_st[temp_v!(1)]); } else { self.machine_st.fail = true; } } - pub(crate) fn compile_assert(&mut self, append_or_prepend: AppendOrPrepend) { + pub(crate) fn compile_assert<'a>(&'a mut self, append_or_prepend: AppendOrPrepend) { let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(3)], self.machine_st[temp_v!(4)]); - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(5)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[5])) ); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; - let compile_assert = || { - let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); + let mut compile_assert = || { + let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = + Loader::new(self, LiveTermStream::new(ListingSource::User)); - loader.load_state.compilation_target = compilation_target.clone(); + loader.payload.compilation_target = compilation_target; let head = loader.read_term_from_heap(temp_v!(1))?; let body = loader.read_term_from_heap(temp_v!(2))?; let asserted_clause = Term::Clause( Cell::default(), - clause_name!(":-"), - vec![Box::new(head.clone()), Box::new(body.clone())], - fetch_op_spec(clause_name!(":-"), 2, &loader.load_state.wam.indices.op_dir), + atom!(":-"), + vec![head.clone(), body.clone()], ); // if a new predicate was just created, make it dynamic. - loader.add_dynamic_predicate(compilation_target.clone(), key.0.clone(), key.1)?; + loader.add_dynamic_predicate(compilation_target, key.0, key.1)?; - loader.load_state.incremental_compile_clause( - key.clone(), + loader.incremental_compile_clause( + key, asserted_clause, - compilation_target.clone(), + compilation_target, false, append_or_prepend, )?; // the global clock is incremented after each assertion. - loader.load_state.wam.machine_st.global_clock += 1; + LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; loader.compile_clause_clauses( key, @@ -1810,15 +1917,15 @@ impl Machine { append_or_prepend, )?; - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; match compile_assert() { Ok(_) => {} Err(e) => { let error_pi = match append_or_prepend { - AppendOrPrepend::Append => (clause_name!("assertz"), 1), - AppendOrPrepend::Prepend => (clause_name!("asserta"), 1), + AppendOrPrepend::Append => (atom!("assertz"), 1), + AppendOrPrepend::Prepend => (atom!("asserta"), 1), }; self.throw_session_error(e, error_pi); @@ -1827,43 +1934,41 @@ impl Machine { } pub(crate) fn abolish_clause(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; - let abolish_clause = || { - let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); - loader.load_state.compilation_target = compilation_target; + let mut abolish_clause = || { + let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> + = Loader::new(self, LiveTermStream::new(ListingSource::User)); + + loader.payload.compilation_target = compilation_target; - let clause_clause_compilation_target = match &loader.load_state.compilation_target { - CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), - module => module.clone(), + let clause_clause_compilation_target = match compilation_target { + CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), + module => module, }; let mut clause_clause_target_poses: Vec<_> = loader - .load_state - .wam + .wam_prelude .indices - .get_predicate_skeleton(&loader.load_state.compilation_target, &key) + .get_predicate_skeleton(&compilation_target, &key) .map(|skeleton| { loader - .load_state - .wam + .wam_prelude .indices .get_predicate_skeleton( &clause_clause_compilation_target, - &(clause_name!("$clause"), 2), + &(atom!("$clause"), 2), ) .map(|clause_clause_skeleton| { skeleton @@ -1882,33 +1987,29 @@ impl Machine { .unwrap(); loader - .load_state - .wam + .wam_prelude .indices - .get_predicate_skeleton_mut(&loader.load_state.compilation_target, &key) + .get_predicate_skeleton_mut(&compilation_target, &key) .map(|skeleton| skeleton.reset()); let code_index = loader - .load_state - .get_or_insert_code_index(key, loader.load_state.compilation_target.clone()); + .get_or_insert_code_index(key, compilation_target); code_index.set(IndexPtr::DynamicUndefined); - loader.load_state.compilation_target = clause_clause_compilation_target; + loader.payload.compilation_target = clause_clause_compilation_target; while let Some(target_pos) = clause_clause_target_poses.pop() { - loader - .load_state - .retract_clause((clause_name!("$clause"), 2), target_pos); + loader.retract_clause((atom!("$clause"), 2), target_pos); } - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; match abolish_clause() { Ok(_) => {} Err(e) => { - self.throw_session_error(e, (clause_name!("abolish"), 1)); + self.throw_session_error(e, (atom!("abolish"), 1)); } } } @@ -1922,40 +2023,40 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st[temp_v!(3)])); - let target_pos = match Number::try_from((target_pos, &self.machine_st.heap)) { + let target_pos = match Number::try_from(target_pos) { Ok(Number::Integer(n)) => n.to_usize().unwrap(), - Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), _ => unreachable!(), }; - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(4)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4])) ); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; - let clause_clause_compilation_target = match &compilation_target { - CompilationTarget::User => CompilationTarget::Module(clause_name!("builtins")), - _ => compilation_target.clone(), + let clause_clause_compilation_target = match compilation_target { + CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), + _ => compilation_target, }; - let retract_clause = || { - let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); - loader.load_state.compilation_target = compilation_target; + let mut retract_clause = || { + let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = + Loader::new(self, LiveTermStream::new(ListingSource::User)); + + loader.payload.compilation_target = compilation_target; - let clause_clause_loc = loader.load_state.retract_dynamic_clause(key, target_pos); + let clause_clause_loc = loader.retract_dynamic_clause(key, target_pos); // the global clock is incremented after each retraction. - loader.load_state.wam.machine_st.global_clock += 1; + LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; - let target_pos = match loader.load_state.wam.indices.get_predicate_skeleton( + let target_pos = match loader.wam_prelude.indices.get_predicate_skeleton( &clause_clause_compilation_target, - &(clause_name!("$clause"), 2), + &(atom!("$clause"), 2), ) { Some(skeleton) => skeleton .target_pos_of_clause_clause_loc(clause_clause_loc) @@ -1965,79 +2066,74 @@ impl Machine { } }; - loader.load_state.compilation_target = clause_clause_compilation_target; - loader - .load_state - .retract_clause((clause_name!("$clause"), 2), target_pos); + loader.payload.compilation_target = clause_clause_compilation_target; + loader.retract_clause((atom!("$clause"), 2), target_pos); - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; match retract_clause() { Ok(_) => {} Err(e) => { - self.throw_session_error(e, (clause_name!("retract"), 1)); + self.throw_session_error(e, (atom!("retract"), 1)); } } } pub(crate) fn is_consistent_with_term_queue(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; - let (loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(4)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(4)); - loader.load_state.wam.machine_st.fail = (!loader.predicates.is_empty() - && loader.predicates.compilation_target != compilation_target) - || !key.is_consistent(&loader.predicates); + LiveLoadAndMachineState::machine_st(&mut loader.payload).fail = + (!loader.payload.predicates.is_empty() + && loader.payload.predicates.compilation_target != compilation_target) + || !key.is_consistent(&loader.payload.predicates); - let result = LiveTermStream::evacuate(loader); - self.restore_load_state_payload(result, evacuable_h); + let result = LiveLoadAndMachineState::evacuate(loader); + self.restore_load_state_payload(result); } pub(crate) fn flush_term_queue(&mut self) { - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let flush_term_queue = || { - if !loader.predicates.is_empty() { + if !loader.payload.predicates.is_empty() { loader.compile_and_submit()?; } - LiveTermStream::evacuate(loader) + LiveLoadAndMachineState::evacuate(loader) }; let result = flush_term_queue(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn remove_module_exports(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); + let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let remove_module_exports = || { - loader.load_state.remove_module_exports(module_name); - LiveTermStream::evacuate(loader) + loader.remove_module_exports(module_name); + LiveLoadAndMachineState::evacuate(loader) }; let result = remove_module_exports(); - self.restore_load_state_payload(result, evacuable_h); + self.restore_load_state_payload(result); } pub(crate) fn add_non_counted_backtracking(&mut self) { @@ -2045,26 +2141,24 @@ impl Machine { .machine_st .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]); - let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); - loader.non_counted_bt_preds.insert(key); + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); + loader.payload.non_counted_bt_preds.insert(key); - let result = LiveTermStream::evacuate(loader); - self.restore_load_state_payload(result, evacuable_h); + let result = LiveLoadAndMachineState::evacuate(loader); + self.restore_load_state_payload(result); } pub(crate) fn meta_predicate_property(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let (predicate_name, arity) = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; @@ -2073,30 +2167,23 @@ impl Machine { .get_meta_predicate_spec(predicate_name, arity, &compilation_target) { Some(meta_specs) => { - let list_loc = self - .machine_st - .heap - .to_list(meta_specs.iter().map(|meta_spec| match meta_spec { - MetaSpec::Minus => HeapCellValue::Atom(clause_name!("+"), None), - MetaSpec::Plus => HeapCellValue::Atom(clause_name!("-"), None), - MetaSpec::Either => HeapCellValue::Atom(clause_name!("?"), None), + let list_loc = iter_to_heap_list( + &mut self.machine_st.heap, + meta_specs.iter().map(|meta_spec| match meta_spec { + MetaSpec::Minus => atom_as_cell!(atom!("+")), + MetaSpec::Plus => atom_as_cell!(atom!("-")), + MetaSpec::Either => atom_as_cell!(atom!("?")), MetaSpec::RequiresExpansionWithArgument(ref arg_num) => { - HeapCellValue::Addr(Addr::Usize(*arg_num)) + fixnum_as_cell!(Fixnum::build_with(*arg_num as i64)) } })); - let heap_loc = self.machine_st.heap.push(HeapCellValue::NamedStr( - 1, - clause_name!("meta_predicate"), - None, - )); + let heap_loc = self.machine_st.heap.len(); - self.machine_st - .heap - .push(HeapCellValue::Addr(Addr::HeapCell(list_loc))); + self.machine_st.heap.push(atom_as_cell!(atom!("meta_predicate"), 1)); + self.machine_st.heap.push(heap_loc_as_cell!(list_loc)); - self.machine_st - .unify(Addr::HeapCell(heap_loc), self.machine_st[temp_v!(4)]); + unify!(self.machine_st, str_loc_as_cell!(heap_loc), self.machine_st.registers[4]); } None => { self.machine_st.fail = true; @@ -2105,18 +2192,16 @@ impl Machine { } pub(crate) fn dynamic_property(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; @@ -2134,18 +2219,16 @@ impl Machine { } pub(crate) fn multifile_property(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; @@ -2163,18 +2246,16 @@ impl Machine { } pub(crate) fn discontiguous_property(&mut self) { - let module_name = atom_from!( - self.machine_st, - self.machine_st - .store(self.machine_st.deref(self.machine_st[temp_v!(1)])) + let module_name = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); - let compilation_target = match module_name.as_str() { - "user" => CompilationTarget::User, + let compilation_target = match module_name { + atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; @@ -2194,24 +2275,15 @@ impl Machine { pub(crate) fn builtin_property(&mut self) { let key = self .machine_st - .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]); + .read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]); - match ClauseType::from(key.0, key.1, None) { + match ClauseType::from(key.0, key.1) { ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN => { return; } - ClauseType::Named(ref name, arity, _) => { - if let Some(module) = self.indices.modules.get(&(clause_name!("builtins"))) { - self.machine_st.fail = !module.code_dir.contains_key(&(name.clone(), arity)); - - return; - } - } - ClauseType::Op(ref name, ref op_desc, _) => { - if let Some(module) = self.indices.modules.get(&(clause_name!("builtins"))) { - self.machine_st.fail = !module - .code_dir - .contains_key(&(name.clone(), op_desc.arity())); + ClauseType::Named(name, arity, _) => { + if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) { + self.machine_st.fail = !module.code_dir.contains_key(&(name, arity)); return; } @@ -2223,63 +2295,24 @@ impl Machine { } } -impl<'a> Loader<'a, LiveTermStream> { - pub(super) fn to_load_state_payload(mut self) -> LoadStatePayload { - LoadStatePayload { - term_stream: mem::replace( - &mut self.term_stream, - LiveTermStream::new(ListingSource::User), - ), - non_counted_bt_preds: mem::replace(&mut self.non_counted_bt_preds, IndexSet::new()), - compilation_target: self.load_state.compilation_target.take(), - retraction_info: mem::replace( - &mut self.load_state.retraction_info, - RetractionInfo::new(self.load_state.wam.code_repo.code.len()), - ), - predicates: self.predicates.take(), - clause_clauses: mem::replace(&mut self.clause_clauses, vec![]), - module_op_exports: mem::replace(&mut self.load_state.module_op_exports, vec![]), - } - } - - pub(super) fn from_load_state_payload( - wam: &'a mut Machine, - mut payload: Box, - ) -> Self { - Loader { - term_stream: mem::replace( - &mut payload.term_stream, - LiveTermStream::new(ListingSource::User), - ), - non_counted_bt_preds: mem::replace(&mut payload.non_counted_bt_preds, IndexSet::new()), - clause_clauses: mem::replace(&mut payload.clause_clauses, vec![]), - predicates: payload.predicates.take(), - load_state: LoadState { - compilation_target: payload.compilation_target.take(), - module_op_exports: mem::replace(&mut payload.module_op_exports, vec![]), - retraction_info: mem::replace(&mut payload.retraction_info, RetractionInfo::new(0)), - wam, - }, - } - } - +impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> { fn read_and_enqueue_term( mut self, term_reg: RegType, compilation_target: CompilationTarget, - ) -> Result { - if self.predicates.compilation_target != compilation_target { - if !self.predicates.is_empty() { + ) -> Result>, SessionError> { + if self.payload.predicates.compilation_target != compilation_target { + if !self.payload.predicates.is_empty() { self.compile_and_submit()?; } - self.predicates.compilation_target = compilation_target; + self.payload.predicates.compilation_target = compilation_target; } let term = self.read_term_from_heap(term_reg)?; self.add_clause_clause_if_dynamic(&term)?; - self.term_stream.term_queue.push_back(term); + self.payload.term_stream.term_queue.push_back(term); self.load() } diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index fbfb1bcf..d62e5b5b 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -1,17 +1,14 @@ -use prolog_parser::ast::*; -use prolog_parser::{clause_name, temp_v}; +use crate::atom_table::*; +use crate::parser::ast::*; -use crate::forms::{ModuleSource, Number}; //, PredicateKey}; +use crate::forms::*; use crate::machine::heap::*; use crate::machine::loader::CompilationTarget; -use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -use crate::machine::PredicateKey; -use crate::rug::Integer; +use crate::types::*; -use std::rc::Rc; - -pub(crate) type MachineStub = Vec; +pub type MachineStub = Vec; +pub type MachineStubGen = Box MachineStub>; #[derive(Debug, Clone, Copy)] enum ErrorProvenance { @@ -26,13 +23,64 @@ pub(crate) struct MachineError { from: ErrorProvenance, } +// from 7.12.2 b) of 13211-1:1995 +#[derive(Debug, Clone, Copy)] +pub(crate) enum ValidType { + Atom, + Atomic, + // Boolean, + Byte, + Callable, + Character, + Compound, + Evaluable, + Float, + InByte, + InCharacter, + Integer, + List, + #[allow(unused)] Number, + Pair, + // PredicateIndicator, + // Variable + TcpListener, +} + +impl ValidType { + pub(crate) fn as_atom(self) -> Atom { + match self { + ValidType::Atom => atom!("atom"), + ValidType::Atomic => atom!("atomic"), + // ValidType::Boolean => atom!("boolean"), + ValidType::Byte => atom!("byte"), + ValidType::Callable => atom!("callable"), + ValidType::Character => atom!("character"), + ValidType::Compound => atom!("compound"), + ValidType::Evaluable => atom!("evaluable"), + ValidType::Float => atom!("float"), + ValidType::InByte => atom!("in_byte"), + ValidType::InCharacter => atom!("in_character"), + ValidType::Integer => atom!("integer"), + ValidType::List => atom!("list"), + ValidType::Number => atom!("number"), + ValidType::Pair => atom!("pair"), + // ValidType::PredicateIndicator => atom!("predicate_indicator"), + // ValidType::Variable => atom!("variable") + ValidType::TcpListener => atom!("tcp_listener"), + } + } +} + pub(crate) trait TypeError { - fn type_error(self, h: usize, valid_type: ValidType) -> MachineError; + fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError; } -impl TypeError for Addr { - fn type_error(self, _: usize, valid_type: ValidType) -> MachineError { - let stub = functor!("type_error", [atom(valid_type.as_str()), addr(self)]); +impl TypeError for HeapCellValue { + fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { + let stub = functor!( + atom!("type_error"), + [atom(valid_type.as_atom()), cell(self)] + ); MachineError { stub, @@ -42,21 +90,29 @@ impl TypeError for Addr { } } -impl TypeError for HeapCellValue { - fn type_error(self, _: usize, valid_type: ValidType) -> MachineError { - let stub = functor!("type_error", [atom(valid_type.as_str()), value(self)]); +impl TypeError for MachineStub { + fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { + let stub = functor!( + atom!("type_error"), + [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)], + [self] + ); MachineError { stub, location: None, - from: ErrorProvenance::Received, + from: ErrorProvenance::Constructed, } } } -impl TypeError for MachineStub { - fn type_error(self, h: usize, valid_type: ValidType) -> MachineError { - let stub = functor!("type_error", [atom(valid_type.as_str()), aux(h, 0)], [self]); +impl TypeError for FunctorStub { + fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { + let stub = functor!( + atom!("type_error"), + [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)], + [self] + ); MachineError { stub, @@ -67,8 +123,14 @@ impl TypeError for MachineStub { } impl TypeError for Number { - fn type_error(self, _h: usize, valid_type: ValidType) -> MachineError { - let stub = functor!("type_error", [atom(valid_type.as_str()), number(self)]); + fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError { + let stub = functor!( + atom!("type_error"), + [ + atom(valid_type.as_atom()), + number(&mut machine_st.arena, self) + ] + ); MachineError { stub, @@ -79,14 +141,24 @@ impl TypeError for Number { } pub(crate) trait PermissionError { - fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError; -} - -impl PermissionError for Addr { - fn permission_error(self, _: usize, index_str: &'static str, perm: Permission) -> MachineError { + fn permission_error( + self, + machine_st: &mut MachineState, + index_atom: Atom, + perm: Permission, + ) -> MachineError; +} + +impl PermissionError for HeapCellValue { + fn permission_error( + self, + _machine_st: &mut MachineState, + index_atom: Atom, + perm: Permission, + ) -> MachineError { let stub = functor!( - "permission_error", - [atom(perm.as_str()), atom(index_str), addr(self)] + atom!("permission_error"), + [atom(perm.as_atom()), atom(index_atom), cell(self)] ); MachineError { @@ -98,10 +170,19 @@ impl PermissionError for Addr { } impl PermissionError for MachineStub { - fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError { + fn permission_error( + self, + machine_st: &mut MachineState, + index_atom: Atom, + perm: Permission, + ) -> MachineError { let stub = functor!( - "permission_error", - [atom(perm.as_str()), atom(index_str), aux(h, 0)], + atom!("permission_error"), + [ + atom(perm.as_atom()), + atom(index_atom), + str(machine_st.heap.len(), 0) + ], [self] ); @@ -114,12 +195,12 @@ impl PermissionError for MachineStub { } pub(super) trait DomainError { - fn domain_error(self, error: DomainErrorType) -> MachineError; + fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError; } -impl DomainError for Addr { - fn domain_error(self, error: DomainErrorType) -> MachineError { - let stub = functor!("domain_error", [atom(error.as_str()), addr(self)]); +impl DomainError for HeapCellValue { + fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError { + let stub = functor!(atom!("domain_error"), [atom(error.as_atom()), cell(self)]); MachineError { stub, @@ -130,8 +211,11 @@ impl DomainError for Addr { } impl DomainError for Number { - fn domain_error(self, error: DomainErrorType) -> MachineError { - let stub = functor!("domain_error", [atom(error.as_str()), number(self)]); + fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError { + let stub = functor!( + atom!("domain_error"), + [atom(error.as_atom()), number(&mut machine_st.arena, self)] + ); MachineError { stub, @@ -141,18 +225,19 @@ impl DomainError for Number { } } -impl MachineError { - pub(super) fn functor_stub(name: ClauseName, arity: usize) -> MachineStub { - functor!( - "/", - SharedOpDesc::new(400, YFX), - [clause_name(name), integer(arity)] - ) - } +pub(super) type FunctorStub = [HeapCellValue; 3]; +#[inline(always)] +pub(super) fn functor_stub(name: Atom, arity: usize) -> FunctorStub { + [atom_as_cell!(atom!("/"), 2), + atom_as_cell!(name), + fixnum_as_cell!(Fixnum::build_with(arity as i64))] +} + +impl MachineState { #[inline] - pub(super) fn interrupt_error() -> Self { - let stub = functor!("$interrupt_thrown"); + pub(super) fn interrupt_error(&mut self) -> MachineError { + let stub = functor!(atom!("$interrupt_thrown")); MachineError { stub, @@ -161,8 +246,8 @@ impl MachineError { } } - pub(super) fn evaluation_error(eval_error: EvalError) -> Self { - let stub = functor!("evaluation_error", [atom(eval_error.as_str())]); + pub(super) fn evaluation_error(&mut self, eval_error: EvalError) -> MachineError { + let stub = functor!(atom!("evaluation_error"), [atom(eval_error.as_atom())]); MachineError { stub, @@ -171,30 +256,26 @@ impl MachineError { } } - pub(super) fn type_error(h: usize, valid_type: ValidType, culprit: T) -> Self { - culprit.type_error(h, valid_type) + pub(super) fn type_error( + &mut self, + valid_type: ValidType, + culprit: T, + ) -> MachineError { + culprit.type_error(self, valid_type) } pub(super) fn module_resolution_error( - h: usize, - mod_name: ClauseName, - name: ClauseName, + &mut self, + mod_name: Atom, + name: Atom, arity: usize, - ) -> Self { - let res_stub = functor!( - ":", - SharedOpDesc::new(600, XFY), - [clause_name(mod_name), clause_name(name)] - ); + ) -> MachineError { + let h = self.heap.len(); - let ind_stub = functor!( - "/", - SharedOpDesc::new(400, YFX), - [aux(h + 2, 0), integer(arity)], - [res_stub] - ); + let res_stub = functor!(atom!(":"), [atom(mod_name), atom(name)]); + let ind_stub = functor!(atom!("/"), [str(h + 2, 0), fixnum(arity)], [res_stub]); - let stub = functor!("evaluation_error", [aux(h, 0)], [ind_stub]); + let stub = functor!(atom!("evaluation_error"), [str(h, 0)], [ind_stub]); MachineError { stub, @@ -203,10 +284,13 @@ impl MachineError { } } - pub(super) fn existence_error(h: usize, err: ExistenceError) -> Self { + pub(super) fn existence_error(&mut self, err: ExistenceError) -> MachineError { match err { ExistenceError::Module(name) => { - let stub = functor!("existence_error", [atom("source_sink"), clause_name(name)]); + let stub = functor!( + atom!("existence_error"), + [atom(atom!("source_sink")), atom(name)] + ); MachineError { stub, @@ -215,13 +299,13 @@ impl MachineError { } } ExistenceError::Procedure(name, arity) => { - let culprit = functor!( - "/", - SharedOpDesc::new(400, YFX), - [clause_name(name), integer(arity)] - ); + let culprit = functor!(atom!("/"), [atom(name), fixnum(arity)]); - let stub = functor!("existence_error", [atom("procedure"), aux(h, 0)], [culprit]); + let stub = functor!( + atom!("existence_error"), + [atom(atom!("procedure")), str(self.heap.len(), 0)], + [culprit] + ); MachineError { stub, @@ -233,8 +317,8 @@ impl MachineError { let source_stub = source.as_functor_stub(); let stub = functor!( - "existence_error", - [atom("source_sink"), aux(h, 0)], + atom!("existence_error"), + [atom(atom!("source_sink")), str(self.heap.len(), 0)], [source_stub] ); @@ -245,7 +329,10 @@ impl MachineError { } } ExistenceError::SourceSink(culprit) => { - let stub = functor!("existence_error", [atom("source_sink"), addr(culprit)]); + let stub = functor!( + atom!("existence_error"), + [atom(atom!("source_sink")), cell(culprit)] + ); MachineError { stub, @@ -254,7 +341,10 @@ impl MachineError { } } ExistenceError::Stream(culprit) => { - let stub = functor!("existence_error", [atom("stream"), addr(culprit)]); + let stub = functor!( + atom!("existence_error"), + [atom(atom!("stream")), cell(culprit)] + ); MachineError { stub, @@ -266,36 +356,41 @@ impl MachineError { } pub(super) fn permission_error( - h: usize, + &mut self, err: Permission, - index_str: &'static str, + index_atom: Atom, culprit: T, - ) -> Self { - culprit.permission_error(h, index_str, err) + ) -> MachineError { + culprit.permission_error(self, index_atom, err) } - fn arithmetic_error(h: usize, err: ArithmeticError) -> Self { + pub(super) fn evaluable_error(&mut self, name: Atom, arity: usize) -> MachineError { + let evaluable_stub = functor_stub(name, arity); + evaluable_stub.type_error(self, ValidType::Evaluable) + } + + fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError { match err { - ArithmeticError::UninstantiatedVar => Self::instantiation_error(), - ArithmeticError::NonEvaluableFunctor(name, arity) => { - let culprit = functor!( - "/", - SharedOpDesc::new(400, YFX), - [constant(h, &name), integer(arity)] - ); + ArithmeticError::UninstantiatedVar => self.instantiation_error(), + ArithmeticError::NonEvaluableFunctor(literal, arity) => { + let culprit = functor!(atom!("/"), [literal(literal), fixnum(arity)]); - Self::type_error(h, ValidType::Evaluable, culprit) + self.type_error(ValidType::Evaluable, culprit) } } } #[inline] - pub(super) fn domain_error(error: DomainErrorType, culprit: T) -> Self { - culprit.domain_error(error) + pub(super) fn domain_error( + &mut self, + error: DomainErrorType, + culprit: T, + ) -> MachineError { + culprit.domain_error(self, error) } - pub(super) fn instantiation_error() -> Self { - let stub = functor!("instantiation_error"); + pub(super) fn instantiation_error(&mut self) -> MachineError { + let stub = functor!(atom!("instantiation_error")); MachineError { stub, @@ -304,81 +399,91 @@ impl MachineError { } } - pub(super) fn session_error(h: usize, err: SessionError) -> Self { + pub(super) fn session_error(&mut self, err: SessionError) -> MachineError { match err { // SessionError::CannotOverwriteBuiltIn(pred_str) | /* SessionError::CannotOverwriteImport(pred_str) => { Self::permission_error( + atom_tbl, h, Permission::Modify, - "private_procedure", - functor!(clause_name(pred_str)), + atom!("private_procedure"), + functor!(atom(pred_str)), ) } */ - SessionError::ExistenceError(err) => Self::existence_error(h, err), + SessionError::ExistenceError(err) => self.existence_error(err), // SessionError::InvalidFileName(filename) => { // Self::existence_error(h, ExistenceError::Module(filename)) // } - SessionError::ModuleDoesNotContainExport(..) => Self::permission_error( - h, - Permission::Access, - "private_procedure", - functor!("module_does_not_contain_claimed_export"), - ), - SessionError::ModuleCannotImportSelf(module_name) => Self::permission_error( - h, - Permission::Modify, - "module", - functor!("module_cannot_import_self", [clause_name(module_name)]), - ), - SessionError::NamelessEntry => Self::permission_error( - h, - Permission::Create, - "static_procedure", - functor!("nameless_procedure"), - ), + SessionError::ModuleDoesNotContainExport(..) => { + let error_atom = atom!("module_does_not_contain_claimed_export"); + + self.permission_error( + Permission::Access, + atom!("private_procedure"), + functor!(error_atom), + ) + } + SessionError::ModuleCannotImportSelf(module_name) => { + let error_atom = atom!("module_cannot_import_self"); + + self.permission_error( + Permission::Modify, + atom!("module"), + functor!(error_atom, [atom(module_name)]), + ) + } + SessionError::NamelessEntry => { + let error_atom = atom!("nameless_procedure"); + self.permission_error(Permission::Create, atom!("static_procedure"), functor!(error_atom)) + } SessionError::OpIsInfixAndPostFix(op) => { - Self::permission_error(h, Permission::Create, "operator", functor!(clause_name(op))) + self.permission_error(Permission::Create, atom!("operator"), functor!(op)) } - SessionError::CompilationError(err) => Self::syntax_error(h, err), + SessionError::CompilationError(err) => self.syntax_error(err), SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => { - let functor_stub = Self::functor_stub(key.0, key.1); + let functor_stub = functor_stub(key.0, key.1); + let stub = functor!( - ":", - SharedOpDesc::new(600, XFY), - [clause_name(compilation_target.module_name()), aux(h + 4, 0)], + atom!(":"), + [ + atom(compilation_target.module_name()), + str(self.heap.len() + 4, 0) + ], [functor_stub] ); - Self::permission_error( - h, + self.permission_error( Permission::Modify, - "not_declared_multifile_or_discontiguous", + atom!("not_declared_multifile_or_discontiguous"), stub, ) } - SessionError::QueryCannotBeDefinedAsFact => Self::permission_error( - h, - Permission::Create, - "static_procedure", - functor!("query_cannot_be_defined_as_fact"), - ), + SessionError::QueryCannotBeDefinedAsFact => { + let error_atom = atom!("query_cannot_be_defined_as_fact"); + + self.permission_error( + Permission::Create, + atom!("static_procedure"), + functor!(error_atom), + ) + } } } - pub(super) fn syntax_error>(h: usize, err: E) -> Self { + pub(super) fn syntax_error>(&mut self, err: E) -> MachineError { let err = err.into(); if let CompilationError::Arithmetic(err) = err { - return Self::arithmetic_error(h, err); + return self.arithmetic_error(err); } let location = err.line_and_col_num(); - let stub = err.as_functor(h); + let stub = err.as_functor(); - let stub = functor!("syntax_error", [aux(h, 0)], [stub]); + let stub = functor!(atom!("syntax_error"), [str(self.heap.len(), 0)], [stub]); MachineError { stub, @@ -387,8 +492,8 @@ impl MachineError { } } - pub(super) fn representation_error(flag: RepFlag) -> Self { - let stub = functor!("representation_error", [atom(flag.as_str())]); + pub(super) fn representation_error(&mut self, flag: RepFlag) -> MachineError { + let stub = functor!(atom!("representation_error"), [atom(flag.as_atom())]); MachineError { stub, @@ -397,13 +502,53 @@ impl MachineError { } } + pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub { + let location = err.location; + let err_len = err.len(); + + let h = self.heap.len(); + + let mut stub = vec![ + atom_as_cell!(atom!("error"), 2), + str_loc_as_cell!(h + 3), + str_loc_as_cell!(h + 3 + err_len), + ]; + + stub.extend(err.into_iter(3)); + + if let Some((line_num, _)) = location { + stub.push(atom_as_cell!(atom!(":"), 2)); + stub.push(str_loc_as_cell!(h + 6 + err_len)); + stub.push(integer_as_cell!(Number::arena_from( + line_num, + &mut self.arena + ))); + } + + stub.extend(src.iter()); + stub + } + + pub(super) fn throw_exception(&mut self, err: MachineStub) { + let h = self.heap.len(); + + self.ball.boundary = 0; + self.ball.stub.truncate(0); + + self.heap.extend(err.into_iter()); + + self.registers[1] = str_loc_as_cell!(h); + + self.set_ball(); + self.unwind_stack(); + } +} + +impl MachineError { fn into_iter(self, offset: usize) -> Box> { match self.from { ErrorProvenance::Constructed => { - Box::new(self.stub.into_iter().map(move |hcv| match hcv { - HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr + offset), - hcv => hcv, - })) + Box::new(self.stub.into_iter().map(move |hcv| hcv + offset)) } ErrorProvenance::Received => Box::new(self.stub.into_iter()), } @@ -415,7 +560,7 @@ impl MachineError { } #[derive(Debug)] -pub(crate) enum CompilationError { +pub enum CompilationError { Arithmetic(ArithmeticError), ParserError(ParserError), // BadPendingByte, @@ -433,7 +578,7 @@ pub(crate) enum CompilationError { InvalidModuleExport, InvalidRuleHead, InvalidUseModuleDecl, - InvalidModuleResolution(ClauseName), + InvalidModuleResolution(Atom), UnreadableTerm, } @@ -459,34 +604,60 @@ impl CompilationError { } } - pub(crate) fn as_functor(&self, _h: usize) -> MachineStub { + pub(crate) fn as_functor(&self) -> MachineStub { match self { - &CompilationError::Arithmetic(..) => functor!("arithmetic_error"), + &CompilationError::Arithmetic(..) => { + functor!(atom!("arithmetic_error")) + } // &CompilationError::BadPendingByte => - // functor!("bad_pending_byte"), - &CompilationError::CannotParseCyclicTerm => functor!("cannot_parse_cyclic_term"), + // functor!(atom_from_ss!("bad_pending_byte"), atom_tbl), + &CompilationError::CannotParseCyclicTerm => { + functor!(atom!("cannot_parse_cyclic_term")) + } // &CompilationError::ExpandedTermsListNotAList => - // functor!("expanded_terms_list_is_not_a_list"), - &CompilationError::ExpectedRel => functor!("expected_relation"), + // functor!(atom_tbl.build_with_static_str("expanded_terms_list_is_not_a_list")), + &CompilationError::ExpectedRel => { + functor!(atom!("expected_relation")) + } // &CompilationError::ExpectedTopLevelTerm => - // functor!("expected_atom_or_cons_or_clause"), - &CompilationError::InadmissibleFact => functor!("inadmissible_fact"), - &CompilationError::InadmissibleQueryTerm => functor!("inadmissible_query_term"), - &CompilationError::InconsistentEntry => functor!("inconsistent_entry"), + // functor!(atom_from_ss!("expected_atom_or_cons_or_clause"), atom_tbl), + &CompilationError::InadmissibleFact => { + functor!(atom!("inadmissible_fact")) + } + &CompilationError::InadmissibleQueryTerm => { + functor!(atom!("inadmissible_query_term")) + } + &CompilationError::InconsistentEntry => { + functor!(atom!("inconsistent_entry")) + } // &CompilationError::InvalidDoubleQuotesDecl => - // functor!("invalid_double_quotes_declaration"), + // functor!(atom_from_ss!("invalid_double_quotes_declaration"), atom_tbl), // &CompilationError::InvalidHook => - // functor!("invalid_hook"), - &CompilationError::InvalidMetaPredicateDecl => functor!("invalid_meta_predicate_decl"), - &CompilationError::InvalidModuleDecl => functor!("invalid_module_declaration"), - &CompilationError::InvalidModuleExport => functor!("invalid_module_export"), + // functor!(atom_from_ss!("invalid_hook"), atom_tbl), + &CompilationError::InvalidMetaPredicateDecl => { + functor!(atom!("invalid_meta_predicate_decl")) + } + &CompilationError::InvalidModuleDecl => { + functor!(atom!("invalid_module_declaration")) + } + &CompilationError::InvalidModuleExport => { + functor!(atom!("invalid_module_export")) + } &CompilationError::InvalidModuleResolution(ref module_name) => { - functor!("no_such_module", [clause_name(module_name.clone())]) + functor!(atom!("no_such_module"), [atom(module_name)]) + } + &CompilationError::InvalidRuleHead => { + functor!(atom!("invalid_head_of_rule")) + } + &CompilationError::InvalidUseModuleDecl => { + functor!(atom!("invalid_use_module_declaration")) + } + &CompilationError::ParserError(ref err) => { + functor!(err.as_atom()) + } + &CompilationError::UnreadableTerm => { + functor!(atom!("unreadable_term")) } - &CompilationError::InvalidRuleHead => functor!("invalid_head_of_rule"), - &CompilationError::InvalidUseModuleDecl => functor!("invalid_use_module_declaration"), - &CompilationError::ParserError(ref err) => functor!(err.as_str()), - &CompilationError::UnreadableTerm => functor!("unreadable_term"), } } } @@ -504,63 +675,15 @@ pub(crate) enum Permission { impl Permission { #[inline] - pub(crate) fn as_str(self) -> &'static str { - match self { - Permission::Access => "access", - Permission::Create => "create", - Permission::InputStream => "input", - Permission::Modify => "modify", - Permission::Open => "open", - Permission::OutputStream => "output", - Permission::Reposition => "reposition", - } - } -} - -// from 7.12.2 b) of 13211-1:1995 -#[derive(Debug, Clone, Copy)] -pub(crate) enum ValidType { - Atom, - Atomic, - // Boolean, - Byte, - Callable, - Character, - Compound, - Evaluable, - Float, - InByte, - InCharacter, - Integer, - List, - Number, - Pair, - // PredicateIndicator, - // Variable - TcpListener, -} - -impl ValidType { - pub(crate) fn as_str(self) -> &'static str { + pub(crate) fn as_atom(self) -> Atom { match self { - ValidType::Atom => "atom", - ValidType::Atomic => "atomic", - // ValidType::Boolean => "boolean", - ValidType::Byte => "byte", - ValidType::Callable => "callable", - ValidType::Character => "character", - ValidType::Compound => "compound", - ValidType::Evaluable => "evaluable", - ValidType::Float => "float", - ValidType::InByte => "in_byte", - ValidType::InCharacter => "in_character", - ValidType::Integer => "integer", - ValidType::List => "list", - ValidType::Number => "number", - ValidType::Pair => "pair", - // ValidType::PredicateIndicator => "predicate_indicator", - // ValidType::Variable => "variable" - ValidType::TcpListener => "tcp_listener", + Permission::Access => atom!("access"), + Permission::Create => atom!("create"), + Permission::InputStream => atom!("input"), + Permission::Modify => atom!("modify"), + Permission::Open => atom!("open"), + Permission::OutputStream => atom!("output"), + Permission::Reposition => atom!("reposition"), } } } @@ -576,14 +699,14 @@ pub(crate) enum DomainErrorType { } impl DomainErrorType { - pub(crate) fn as_str(self) -> &'static str { + pub(crate) fn as_atom(self) -> Atom { match self { - DomainErrorType::IOMode => "io_mode", - DomainErrorType::NotLessThanZero => "not_less_than_zero", - DomainErrorType::Order => "order", - DomainErrorType::SourceSink => "source_sink", - DomainErrorType::Stream => "stream", - DomainErrorType::StreamOrAlias => "stream_or_alias", + DomainErrorType::IOMode => atom!("io_mode"), + DomainErrorType::NotLessThanZero => atom!("not_less_than_zero"), + DomainErrorType::Order => atom!("order"), + DomainErrorType::SourceSink => atom!("source_sink"), + DomainErrorType::Stream => atom!("stream"), + DomainErrorType::StreamOrAlias => atom!("stream_or_alias"), } } } @@ -601,22 +724,22 @@ pub(crate) enum RepFlag { } impl RepFlag { - pub(crate) fn as_str(self) -> &'static str { + pub(crate) fn as_atom(self) -> Atom { match self { - RepFlag::Character => "character", - RepFlag::CharacterCode => "character_code", - RepFlag::InCharacterCode => "in_character_code", - RepFlag::MaxArity => "max_arity", - RepFlag::Term => "term", - // RepFlag::MaxInteger => "max_integer", - // RepFlag::MinInteger => "min_integer" + RepFlag::Character => atom!("character"), + RepFlag::CharacterCode => atom!("character_code"), + RepFlag::InCharacterCode => atom!("in_character_code"), + RepFlag::MaxArity => atom!("max_arity"), + RepFlag::Term => atom!("term"), + // RepFlag::MaxInteger => atom!("max_integer"), + // RepFlag::MinInteger => atom!("min_integer") } } } // from 7.12.2 g) of 13211-1:1995 #[derive(Debug, Clone, Copy)] -pub(crate) enum EvalError { +pub enum EvalError { FloatOverflow, Undefined, // Underflow, @@ -624,93 +747,108 @@ pub(crate) enum EvalError { } impl EvalError { - pub(crate) fn as_str(self) -> &'static str { + pub(crate) fn as_atom(self) -> Atom { match self { - EvalError::FloatOverflow => "float_overflow", - EvalError::Undefined => "undefined", - // EvalError::FloatUnderflow => "underflow", - EvalError::ZeroDivisor => "zero_divisor", + EvalError::FloatOverflow => atom!("float_overflow"), + EvalError::Undefined => atom!("undefined"), + // EvalError::FloatUnderflow => atom!("underflow"), + EvalError::ZeroDivisor => atom!("zero_divisor"), } } } // used by '$skip_max_list'. -#[derive(Debug, Clone, Copy)] -pub(super) enum CycleSearchResult { +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CycleSearchResult { EmptyList, NotList, PartialList(usize, Ref), // the list length (up to max), and an offset into the heap. ProperList(usize), // the list length. - PStrLocation(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string. - UntouchedList(usize), // the address of an uniterated Addr::Lis(address). + PStrLocation(usize, usize), // list length (up to max), the heap address of the PStrOffset + UntouchedList(usize), // the address of an uniterated Addr::Lis(address). + UntouchedCStr(Atom, usize), } impl MachineState { // see 8.4.3 of Draft Technical Corrigendum 2. - pub(super) fn check_sort_errors(&self) -> CallResult { - let stub = MachineError::functor_stub(clause_name!("sort"), 2); - let list = self.store(self.deref(self[temp_v!(1)].clone())); - let sorted = self.store(self.deref(self[temp_v!(2)].clone())); + pub(super) fn check_sort_errors(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("sort"), 2); - match self.detect_cycles(list.clone()) { + let list = self.registers[1]; + let sorted = self.registers[2]; + + match self.detect_cycles(list) { CycleSearchResult::PartialList(..) => { - return Err(self.error_form(MachineError::instantiation_error(), stub)) + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())) } CycleSearchResult::NotList => { - return Err( - self.error_form(MachineError::type_error(0, ValidType::List, list), stub) - ) + let err = self.type_error(ValidType::List, list); + return Err(self.error_form(err, stub_gen())); } _ => {} }; - match self.detect_cycles(sorted.clone()) { - CycleSearchResult::NotList if !sorted.is_ref() => { - Err(self.error_form(MachineError::type_error(0, ValidType::List, sorted), stub)) + match self.detect_cycles(sorted) { + CycleSearchResult::NotList if !sorted.is_var() => { + let err = self.type_error(ValidType::List, sorted); + Err(self.error_form(err, stub_gen())) } _ => Ok(()), } } - fn check_for_list_pairs(&self, list: Addr) -> CallResult { - let stub = MachineError::functor_stub(clause_name!("keysort"), 2); + fn check_for_list_pairs(&mut self, mut list: HeapCellValue) -> CallResult { + let stub_gen = || functor_stub(atom!("keysort"), 2); - match self.detect_cycles(list.clone()) { - CycleSearchResult::NotList if !list.is_ref() => { - Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub)) + match self.detect_cycles(list) { + CycleSearchResult::NotList if !list.is_var() => { + let err = self.type_error(ValidType::List, list); + Err(self.error_form(err, stub_gen())) } _ => { - let mut addr = list; - - while let Addr::Lis(l) = self.store(self.deref(addr)) { - let mut new_l = l; - - loop { - match self.heap.clone(new_l) { - HeapCellValue::Addr(Addr::Str(l)) => { - new_l = l; - } - HeapCellValue::NamedStr(2, ref name, Some(_)) - if name.as_str() == "-" => - { - break; - } - HeapCellValue::Addr(Addr::HeapCell(_)) => { - break; + loop { + read_heap_cell!(self.store(self.deref(list)), + (HeapCellValueTag::Lis, l) => { + let mut new_l = l; + + loop { + read_heap_cell!(self.heap[new_l], + (HeapCellValueTag::Str, s) => { + new_l = s; + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("-") && arity == 2 { + break; + } else { + let err = self.type_error( + ValidType::Pair, + list_loc_as_cell!(l), + ); + + return Err(self.error_form(err, stub_gen())); + } + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar) => { + break; + } + _ => { + let err = self.type_error( + ValidType::Pair, + list_loc_as_cell!(l), + ); + + return Err(self.error_form(err, stub_gen())); + } + ); } - HeapCellValue::Addr(Addr::StackCell(..)) => { - break; - } - _ => { - return Err(self.error_form( - MachineError::type_error(0, ValidType::Pair, Addr::HeapCell(l)), - stub, - )) - } - }; - } - addr = Addr::HeapCell(l + 1); + list = heap_loc_as_cell!(l+1); + } + _ => { + break; + } + ); } Ok(()) @@ -719,112 +857,48 @@ impl MachineState { } // see 8.4.4 of Draft Technical Corrigendum 2. - pub(super) fn check_keysort_errors(&self) -> CallResult { - let stub = MachineError::functor_stub(clause_name!("keysort"), 2); + pub(super) fn check_keysort_errors(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("keysort"), 2); - let pairs = self.store(self.deref(self[temp_v!(1)].clone())); - let sorted = self.store(self.deref(self[temp_v!(2)].clone())); + let pairs = self.store(self.deref(self[temp_v!(1)])); + let sorted = self.store(self.deref(self[temp_v!(2)])); - match self.detect_cycles(pairs.clone()) { + match self.detect_cycles(pairs) { CycleSearchResult::PartialList(..) => { - Err(self.error_form(MachineError::instantiation_error(), stub)) + let err = self.instantiation_error(); + Err(self.error_form(err, stub_gen())) } CycleSearchResult::NotList => { - Err(self.error_form(MachineError::type_error(0, ValidType::List, pairs), stub)) + let err = self.type_error(ValidType::List, pairs); + Err(self.error_form(err, stub_gen())) } _ => Ok(()), }?; self.check_for_list_pairs(sorted) } - - #[inline] - pub(crate) fn type_error( - &self, - valid_type: ValidType, - culprit: T, - caller: ClauseName, - arity: usize, - ) -> MachineStub { - let stub = MachineError::functor_stub(caller, arity); - let err = MachineError::type_error(self.heap.h(), valid_type, culprit); - - return self.error_form(err, stub); - } - - #[inline] - pub(crate) fn representation_error( - &self, - rep_flag: RepFlag, - caller: ClauseName, - arity: usize, - ) -> MachineStub { - let stub = MachineError::functor_stub(caller, arity); - let err = MachineError::representation_error(rep_flag); - - return self.error_form(err, stub); - } - - pub(super) fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub { - let location = err.location; - let err_len = err.len(); - - let h = self.heap.h(); - let mut stub = vec![ - HeapCellValue::NamedStr(2, clause_name!("error"), None), - HeapCellValue::Addr(Addr::HeapCell(h + 3)), - HeapCellValue::Addr(Addr::HeapCell(h + 3 + err_len)), - ]; - - stub.extend(err.into_iter(3)); - - if let Some((line_num, _)) = location { - let colon_op_desc = Some(SharedOpDesc::new(600, XFY)); - - stub.push(HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc)); - stub.push(HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len))); - stub.push(HeapCellValue::Integer(Rc::new(Integer::from(line_num)))); - } - - stub.extend(src.into_iter()); - stub - } - - pub(super) fn throw_exception(&mut self, err: MachineStub) { - let h = self.heap.h(); - - self.ball.boundary = 0; - self.ball.stub.truncate(0); - - self.heap.append(err); - - self.registers[1] = Addr::HeapCell(h); - - self.set_ball(); - self.unwind_stack(); - } } #[derive(Debug)] -pub(crate) enum ExistenceError { - Module(ClauseName), +pub enum ExistenceError { + Module(Atom), ModuleSource(ModuleSource), - Procedure(ClauseName, usize), - SourceSink(Addr), - Stream(Addr), + Procedure(Atom, usize), + SourceSink(HeapCellValue), + Stream(HeapCellValue), } #[derive(Debug)] -pub(crate) enum SessionError { +pub enum SessionError { CompilationError(CompilationError), - // CannotOverwriteBuiltIn(ClauseName), - // CannotOverwriteImport(ClauseName), + // CannotOverwriteBuiltIn(Atom), + // CannotOverwriteImport(Atom), ExistenceError(ExistenceError), - // InvalidFileName(ClauseName), - ModuleDoesNotContainExport(ClauseName, PredicateKey), - ModuleCannotImportSelf(ClauseName), + // InvalidFileName(Atom), + ModuleDoesNotContainExport(Atom, PredicateKey), + ModuleCannotImportSelf(Atom), NamelessEntry, - OpIsInfixAndPostFix(ClauseName), + OpIsInfixAndPostFix(Atom), PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey), QueryCannotBeDefinedAsFact, } diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index e66a8713..6d5be8c1 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -1,53 +1,43 @@ -use prolog_parser::ast::*; -use prolog_parser::clause_name; +use crate::parser::ast::*; +use crate::arena::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::fixtures::*; use crate::forms::*; use crate::instructions::*; + use crate::machine::code_repo::CodeRepo; use crate::machine::heap::*; +use crate::machine::loader::*; +use crate::machine::machine_errors::MachineStub; use crate::machine::machine_state::*; -use crate::machine::partial_string::*; -use crate::machine::raw_block::RawBlockTraits; use crate::machine::streams::Stream; -use crate::machine::term_stream::LoadStatePayload; -use crate::machine::CompilationTarget; -use crate::rug::{Integer, Rational}; -use ordered_float::OrderedFloat; use indexmap::IndexMap; use std::cell::Cell; use std::cmp::Ordering; -use std::collections::{BTreeMap, BTreeSet}; -use std::convert::TryFrom; +use std::collections::BTreeSet; use std::fmt; -// use std::mem; -use std::net::TcpListener; use std::ops::{Add, AddAssign, Deref, Sub, SubAssign}; use std::rc::Rc; +use crate::types::*; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct OrderedOpDirKey(pub(crate) ClauseName, pub(crate) Fixity); +pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity); -pub(crate) type OssifiedOpDir = BTreeMap; +pub(crate) type OssifiedOpDir = IndexMap<(Atom, Fixity), (usize, Specifier)>; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) enum DBRef { - NamedPred(ClauseName, usize, Option), - Op( - usize, - Specifier, - ClauseName, - Rc, - SharedOpDesc, - ), +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DBRef { + NamedPred(Atom, usize), + Op(Atom, Fixity, TypedArenaPtr), } // 7.2 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) enum TermOrderCategory { +pub enum TermOrderCategory { Variable, FloatingPoint, Integer, @@ -55,43 +45,95 @@ pub(crate) enum TermOrderCategory { Compound, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) enum Addr { - AttrVar(usize), - Char(char), - Con(usize), - CutPoint(usize), - EmptyList, - Fixnum(isize), - Float(OrderedFloat), - Lis(usize), - LoadStatePayload(usize), - HeapCell(usize), - PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes. - StackCell(usize, usize), - Str(usize), - Stream(usize), - TcpListener(usize), - Usize(usize), -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd)] -pub(crate) enum Ref { - AttrVar(usize), - HeapCell(usize), - StackCell(usize, usize), -} - -impl Ref { - pub(crate) fn as_addr(self) -> Addr { - match self { - Ref::AttrVar(h) => Addr::AttrVar(h), - Ref::HeapCell(h) => Addr::HeapCell(h), - Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc), - } +// the position-dependent heap template: + +/* + read_heap_cell!( + (HeapCellValueTag::AttrVar, n) => { + } + (HeapCellValueTag::Lis, n) => { + } + (HeapCellValueTag::Var, n) => { + } + (HeapCellValueTag::Str, n) => { + } + (HeapCellValueTag::PStrOffset, n) => { + } + _ => { + } + ) +*/ + +impl PartialEq for HeapCellValue { + fn eq(&self, r: &Ref) -> bool { + self.as_var() == Some(*r) } } +impl PartialOrd for HeapCellValue { + fn partial_cmp(&self, r: &Ref) -> Option { + read_heap_cell!(*self, + (HeapCellValueTag::StackVar, s1) => { + match r.get_tag() { + RefTag::StackCell => { + let s2 = r.get_value() as usize; + s1.partial_cmp(&s2) + } + _ => Some(Ordering::Greater), + } + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h1) => { + match r.get_tag() { + RefTag::StackCell => Some(Ordering::Less), + _ => { + let h2 = r.get_value() as usize; + h1.partial_cmp(&h2) + } + } + } + _ => { + None + } + ) + } +} +/* +impl HeapCellValue { + #[inline] + pub fn as_constant_index(self, machine_st: &MachineState) -> Option { + read_heap_cell!(self, + (HeapCellValueTag::Char, c) => Some(Literal::Char(c)), + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + Some(Literal::Atom(name)) + } else { + None + } + } + (HeapCellValueTag::Fixnum, n) => { + Some(Literal::Fixnum(n)) + } + (HeapCellValueTag::F64, f) => { + Some(Literal::Float(f)) + } + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Integer, n) => { + Some(Literal::Integer(n)) + } + (ArenaHeaderTag::Rational, r) => { + Some(Literal::Rational(r)) + } + _ => { + None + } + ) + } + ) + } +} +*/ +/* impl Ord for Ref { fn cmp(&self, other: &Ref) -> Ordering { match (self, other) { @@ -114,31 +156,6 @@ impl PartialEq for Addr { } } -// for use crate::in MachineState::bind. -impl PartialOrd for Addr { - fn partial_cmp(&self, r: &Ref) -> Option { - match self { - &Addr::StackCell(fr, sc) => match *r { - Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater), - Ref::StackCell(fr1, sc1) => { - if fr1 < fr || (fr1 == fr && sc1 < sc) { - Some(Ordering::Greater) - } else if fr1 == fr && sc1 == sc { - Some(Ordering::Equal) - } else { - Some(Ordering::Less) - } - } - }, - &Addr::HeapCell(h) | &Addr::AttrVar(h) => match r { - Ref::StackCell(..) => Some(Ordering::Less), - Ref::AttrVar(h1) | Ref::HeapCell(h1) => h.partial_cmp(h1), - }, - _ => None, - } - } -} - impl Addr { #[inline] pub(crate) fn is_heap_bound(&self) -> bool { @@ -171,57 +188,6 @@ impl Addr { } } - pub(super) fn order_category(&self, heap: &Heap) -> Option { - match Number::try_from((*self, heap)) { - Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => { - Some(TermOrderCategory::Integer) - } - Ok(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint), - _ => match self { - Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => { - Some(TermOrderCategory::Variable) - } - Addr::Float(_) => Some(TermOrderCategory::FloatingPoint), - &Addr::Con(h) => match &heap[h] { - HeapCellValue::Atom(..) => Some(TermOrderCategory::Atom), - HeapCellValue::DBRef(_) => None, - _ => { - unreachable!() - } - }, - Addr::Char(_) | Addr::EmptyList => Some(TermOrderCategory::Atom), - Addr::Fixnum(_) | Addr::Usize(_) => Some(TermOrderCategory::Integer), - Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => { - Some(TermOrderCategory::Compound) - } - Addr::CutPoint(_) - | Addr::LoadStatePayload(_) - | Addr::Stream(_) - | Addr::TcpListener(_) => None, - }, - } - } - - pub(crate) fn as_constant_index(&self, machine_st: &MachineState) -> Option { - match self { - &Addr::Char(c) => Some(Constant::Char(c)), - &Addr::Con(h) => match &machine_st.heap[h] { - &HeapCellValue::Atom(ref name, _) if name.is_char() => { - Some(Constant::Char(name.as_str().chars().next().unwrap())) - } - &HeapCellValue::Atom(ref name, _) => Some(Constant::Atom(name.clone(), None)), - &HeapCellValue::Integer(ref n) => Some(Constant::Integer(n.clone())), - &HeapCellValue::Rational(ref n) => Some(Constant::Rational(n.clone())), - _ => None, - }, - &Addr::EmptyList => Some(Constant::EmptyList), - &Addr::Fixnum(n) => Some(Constant::Fixnum(n)), - &Addr::Float(f) => Some(Constant::Float(f)), - &Addr::Usize(n) => Some(Constant::Usize(n)), - _ => None, - } - } - pub(crate) fn is_protected(&self, e: usize) -> bool { match self { &Addr::StackCell(addr, _) if addr >= e => false, @@ -230,61 +196,6 @@ impl Addr { } } -impl Add for Addr { - type Output = Addr; - - fn add(self, rhs: usize) -> Self::Output { - match self { - Addr::Stream(h) => Addr::Stream(h + rhs), - Addr::Con(h) => Addr::Con(h + rhs), - Addr::Lis(a) => Addr::Lis(a + rhs), - Addr::AttrVar(h) => Addr::AttrVar(h + rhs), - Addr::HeapCell(h) => Addr::HeapCell(h + rhs), - Addr::Str(s) => Addr::Str(s + rhs), - Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n), - _ => self, - } - } -} - -impl Sub for Addr { - type Output = Addr; - - fn sub(self, rhs: i64) -> Self::Output { - if rhs < 0 { - match self { - Addr::Stream(h) => Addr::Stream(h + rhs.abs() as usize), - Addr::Con(h) => Addr::Con(h + rhs.abs() as usize), - Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize), - Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize), - Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize), - Addr::Str(s) => Addr::Str(s + rhs.abs() as usize), - Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n), - _ => self, - } - } else { - self.sub(rhs as usize) - } - } -} - -impl Sub for Addr { - type Output = Addr; - - fn sub(self, rhs: usize) -> Self::Output { - match self { - Addr::Stream(h) => Addr::Stream(h - rhs), - Addr::Con(h) => Addr::Con(h - rhs), - Addr::Lis(a) => Addr::Lis(a - rhs), - Addr::AttrVar(h) => Addr::AttrVar(h - rhs), - Addr::HeapCell(h) => Addr::HeapCell(h - rhs), - Addr::Str(s) => Addr::Str(s - rhs), - Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n), - _ => self, - } - } -} - impl SubAssign for Addr { fn sub_assign(&mut self, rhs: usize) { *self = self.clone() - rhs; @@ -305,72 +216,9 @@ impl From for TrailRef { TrailRef::Ref(r) } } - -#[derive(Debug)] -pub(crate) enum HeapCellValue { - Addr(Addr), - Atom(ClauseName, Option), - DBRef(DBRef), - Integer(Rc), - LoadStatePayload(Box), - NamedStr(usize, ClauseName, Option), // arity, name, precedence/Specifier if it has one. - Rational(Rc), - PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant. - Stream(Stream), - TcpListener(TcpListener), -} - -impl HeapCellValue { - #[inline] - pub(crate) fn as_addr(&self, focus: usize) -> Addr { - match self { - HeapCellValue::Addr(ref a) => *a, - HeapCellValue::Atom(..) - | HeapCellValue::DBRef(..) - | HeapCellValue::Integer(..) - | HeapCellValue::Rational(..) => Addr::Con(focus), - HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(focus), - HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus), - HeapCellValue::PartialString(..) => Addr::PStrLocation(focus, 0), - HeapCellValue::Stream(_) => Addr::Stream(focus), - HeapCellValue::TcpListener(_) => Addr::TcpListener(focus), - } - } - - #[inline] - pub(crate) fn context_free_clone(&self) -> HeapCellValue { - match self { - &HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr), - &HeapCellValue::Atom(ref name, ref op) => HeapCellValue::Atom(name.clone(), op.clone()), - &HeapCellValue::DBRef(ref db_ref) => HeapCellValue::DBRef(db_ref.clone()), - &HeapCellValue::Integer(ref n) => HeapCellValue::Integer(n.clone()), - &HeapCellValue::LoadStatePayload(_) => { - HeapCellValue::Atom(clause_name!("$live_term_stream"), None) - } - &HeapCellValue::NamedStr(arity, ref name, ref op) => { - HeapCellValue::NamedStr(arity, name.clone(), op.clone()) - } - &HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()), - &HeapCellValue::PartialString(ref pstr, has_tail) => { - HeapCellValue::PartialString(pstr.clone(), has_tail) - } - &HeapCellValue::Stream(ref stream) => HeapCellValue::Stream(stream.clone()), - &HeapCellValue::TcpListener(_) => { - HeapCellValue::Atom(clause_name!("$tcp_listener"), None) - } - } - } -} - -impl From for HeapCellValue { - #[inline] - fn from(value: Addr) -> HeapCellValue { - HeapCellValue::Addr(value) - } -} - +*/ #[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub(crate) enum IndexPtr { +pub enum IndexPtr { DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. DynamicIndex(usize), Index(usize), @@ -378,7 +226,7 @@ pub(crate) enum IndexPtr { } #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] -pub(crate) struct CodeIndex(pub(crate) Rc>); +pub struct CodeIndex(pub(crate) Rc>); impl Deref for CodeIndex { type Target = Cell; @@ -419,7 +267,7 @@ impl Default for CodeIndex { } #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] -pub(crate) enum REPLCodePtr { +pub enum REPLCodePtr { AddDiscontiguousPredicate, AddDynamicPredicate, AddMultifilePredicate, @@ -456,12 +304,11 @@ pub(crate) enum REPLCodePtr { AddNonCountedBacktracking, } -#[derive(Debug, Clone, PartialEq)] -pub(crate) enum CodePtr { +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum CodePtr { BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call. CallN(usize, LocalCodePtr, bool), // arity, local, last call. Local(LocalCodePtr), - // DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer. REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer. VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir. } @@ -488,7 +335,7 @@ impl CodePtr { } #[derive(Copy, Clone, Debug, PartialEq)] -pub(crate) enum LocalCodePtr { +pub enum LocalCodePtr { DirEntry(usize), // offset Halt, IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset @@ -496,7 +343,7 @@ pub(crate) enum LocalCodePtr { } impl LocalCodePtr { - pub(crate) fn assign_if_local(&mut self, cp: CodePtr) { + pub fn assign_if_local(&mut self, cp: CodePtr) { match cp { CodePtr::Local(local) => *self = local, _ => {} @@ -504,7 +351,7 @@ impl LocalCodePtr { } #[inline] - pub(crate) fn abs_loc(&self) -> usize { + pub fn abs_loc(&self) -> usize { match self { LocalCodePtr::DirEntry(ref p) => *p, LocalCodePtr::IndexingBuf(ref p, ..) => *p, @@ -528,33 +375,21 @@ impl LocalCodePtr { false } - pub(crate) fn as_functor(&self, heap: &mut HeapTemplate) -> Addr { - let addr = Addr::HeapCell(heap.h()); - + pub(crate) fn as_functor(&self) -> MachineStub { match self { LocalCodePtr::DirEntry(p) => { - heap.append(functor!("dir_entry", [integer(*p)])); + functor!(atom!("dir_entry"), [fixnum(*p)]) } LocalCodePtr::Halt => { - heap.append(functor!("halt")); + functor!(atom!("halt")) } - /* - LocalCodePtr::TopLevel(chunk_num, offset) => { - heap.append(functor!( - "top_level", - [integer(*chunk_num), integer(*offset)] - )); - } - */ LocalCodePtr::IndexingBuf(p, o, i) => { - heap.append(functor!( - "indexed_buf", - [integer(*p), integer(*o), integer(*i)] - )); + functor!( + atom!("indexed_buf"), + [fixnum(*p), fixnum(*o), fixnum(*i)] + ) } } - - addr } } @@ -614,9 +449,8 @@ impl AddAssign for LocalCodePtr { #[inline] fn add_assign(&mut self, rhs: usize) { match self { - &mut LocalCodePtr::DirEntry(ref mut p) /* | - &mut LocalCodePtr::TopLevel(_, ref mut p) */ => *p += rhs, - &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs, + &mut LocalCodePtr::DirEntry(ref mut i) + | &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs, &mut LocalCodePtr::Halt => unreachable!(), } } @@ -627,11 +461,7 @@ impl Add for CodePtr { fn add(self, rhs: usize) -> Self::Output { match self { - p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => { - // | - // p @ CodePtr::DynamicTransaction(..) => { - p - } + p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => p, CodePtr::Local(local) => CodePtr::Local(local + rhs), CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => { CodePtr::Local(local + rhs) @@ -660,12 +490,12 @@ impl SubAssign for CodePtr { } } -pub(crate) type HeapVarDict = IndexMap, Addr>; -pub(crate) type AllocVarDict = IndexMap, VarData>; +pub(crate) type HeapVarDict = IndexMap, HeapCellValue>; +pub(crate) type AllocVarDict = IndexMap, VarData>; -pub(crate) type GlobalVarDir = IndexMap)>; +pub(crate) type GlobalVarDir = IndexMap)>; -pub(crate) type StreamAliasDir = IndexMap; +pub(crate) type StreamAliasDir = IndexMap; pub(crate) type StreamDir = BTreeSet; pub(crate) type MetaPredicateDir = IndexMap>; @@ -676,7 +506,7 @@ pub(crate) type LocalExtensiblePredicates = IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>; #[derive(Debug)] -pub(crate) struct IndexStore { +pub struct IndexStore { pub(super) code_dir: CodeDir, pub(super) extensible_predicates: ExtensiblePredicates, pub(super) local_extensible_predicates: LocalExtensiblePredicates, @@ -688,31 +518,21 @@ pub(crate) struct IndexStore { pub(super) stream_aliases: StreamAliasDir, } -impl Default for IndexStore { - #[inline] - fn default() -> Self { - index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new()) - } -} - impl IndexStore { pub(crate) fn get_predicate_skeleton_mut( &mut self, compilation_target: &CompilationTarget, key: &PredicateKey, ) -> Option<&mut PredicateSkeleton> { - match (key.0.as_str(), key.1) { - // ("term_expansion", 2) => self.extensible_predicates.get_mut(key), - _ => match compilation_target { - CompilationTarget::User => self.extensible_predicates.get_mut(key), - CompilationTarget::Module(ref module_name) => { - if let Some(module) = self.modules.get_mut(module_name) { - module.extensible_predicates.get_mut(key) - } else { - None - } + match compilation_target { + CompilationTarget::User => self.extensible_predicates.get_mut(key), + CompilationTarget::Module(ref module_name) => { + if let Some(module) = self.modules.get_mut(module_name) { + module.extensible_predicates.get_mut(key) + } else { + None } - }, + } } } @@ -737,7 +557,7 @@ impl IndexStore { &mut self, mut src_compilation_target: CompilationTarget, local_compilation_target: CompilationTarget, - listing_src_file_name: Option, + listing_src_file_name: Option, key: PredicateKey, ) -> Option<&mut LocalPredicateSkeleton> { if let Some(filename) = listing_src_file_name { @@ -748,8 +568,8 @@ impl IndexStore { CompilationTarget::User => self .local_extensible_predicates .get_mut(&(local_compilation_target, key)), - CompilationTarget::Module(ref module_name) => { - if let Some(module) = self.modules.get_mut(module_name) { + CompilationTarget::Module(module_name) => { + if let Some(module) = self.modules.get_mut(&module_name) { module .local_extensible_predicates .get_mut(&(local_compilation_target, key)) @@ -764,7 +584,7 @@ impl IndexStore { &self, mut src_compilation_target: CompilationTarget, local_compilation_target: CompilationTarget, - listing_src_file_name: Option, + listing_src_file_name: Option, key: PredicateKey, ) -> Option<&LocalPredicateSkeleton> { if let Some(filename) = listing_src_file_name { @@ -775,8 +595,8 @@ impl IndexStore { CompilationTarget::User => self .local_extensible_predicates .get(&(local_compilation_target, key)), - CompilationTarget::Module(ref module_name) => { - if let Some(module) = self.modules.get(module_name) { + CompilationTarget::Module(module_name) => { + if let Some(module) = self.modules.get(&module_name) { module .local_extensible_predicates .get(&(local_compilation_target, key)) @@ -806,35 +626,30 @@ impl IndexStore { pub(crate) fn get_predicate_code_index( &self, - name: ClauseName, + name: Atom, arity: usize, - module: ClauseName, - op_spec: Option, + module: Atom, ) -> Option { - if module.as_str() == "user" { - match ClauseType::from(name, arity, op_spec) { + if module == atom!("user") { + match ClauseType::from(name, arity) { ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(), - ClauseType::Op(name, spec, ..) => self.code_dir.get(&(name, spec.arity())).cloned(), _ => None, } } else { - self.modules.get(&module).and_then(|module| { - match ClauseType::from(name, arity, op_spec) { + self.modules + .get(&module) + .and_then(|module| match ClauseType::from(name, arity) { ClauseType::Named(name, arity, _) => { module.code_dir.get(&(name, arity)).cloned() } - ClauseType::Op(name, spec, ..) => { - module.code_dir.get(&(name, spec.arity())).cloned() - } _ => None, - } - }) + }) } } pub(crate) fn get_meta_predicate_spec( &self, - name: ClauseName, + name: Atom, arity: usize, compilation_target: &CompilationTarget, ) -> Option<&Vec> { @@ -850,9 +665,13 @@ impl IndexStore { } } - pub(crate) fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool { - match module_name.as_str() { - "user" => self + pub(crate) fn is_dynamic_predicate( + &self, + module_name: Atom, + key: PredicateKey, + ) -> bool { + match module_name { + atom!("user") => self .extensible_predicates .get(&key) .map(|skeleton| skeleton.core.is_dynamic) @@ -870,19 +689,19 @@ impl IndexStore { #[inline] pub(super) fn new() -> Self { - IndexStore::default() + index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new()) } pub(super) fn get_cleaner_sites(&self) -> (usize, usize) { - let r_w_h = clause_name!("run_cleaners_with_handling"); - let r_wo_h = clause_name!("run_cleaners_without_handling"); - let iso_ext = clause_name!("iso_ext"); + let r_w_h = atom!("run_cleaners_with_handling"); + let r_wo_h = atom!("run_cleaners_without_handling"); + let iso_ext = atom!("iso_ext"); let r_w_h = self - .get_predicate_code_index(r_w_h, 0, iso_ext.clone(), None) + .get_predicate_code_index(r_w_h, 0, iso_ext) .and_then(|item| item.local()); let r_wo_h = self - .get_predicate_code_index(r_wo_h, 1, iso_ext, None) + .get_predicate_code_index(r_wo_h, 1, iso_ext) .and_then(|item| item.local()); if let Some(r_w_h) = r_w_h { @@ -895,7 +714,7 @@ impl IndexStore { } } -pub(crate) type CodeDir = BTreeMap; +pub(crate) type CodeDir = IndexMap; pub(crate) enum RefOrOwned<'a, T: 'a> { Borrowed(&'a T), @@ -918,14 +737,4 @@ impl<'a, T> RefOrOwned<'a, T> { &RefOrOwned::Owned(ref r) => r, } } - - pub(crate) fn to_owned(self) -> T - where - T: Clone, - { - match self { - RefOrOwned::Borrowed(item) => item.clone(), - RefOrOwned::Owned(item) => item, - } - } } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 9e845f04..8d39edcd 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -1,19 +1,22 @@ -use prolog_parser::ast::*; -use prolog_parser::tabled_rc::*; -use prolog_parser::{clause_name, temp_v}; +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::temp_v; use crate::clause_types::*; use crate::forms::*; +use crate::heap_iter::*; use crate::heap_print::*; use crate::machine::attributed_variables::*; use crate::machine::copier::*; use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; -use crate::machine::partial_string::HeapPStrIter; use crate::machine::stack::*; use crate::machine::streams::*; -use crate::rug::Integer; +use crate::types::*; + +use crate::parser::rug::Integer; use downcast::{ downcast, downcast_methods, downcast_methods_core, downcast_methods_std, impl_downcast, Any, @@ -28,203 +31,7 @@ use std::mem; use std::ops::{Index, IndexMut}; use std::rc::Rc; -#[derive(Debug)] -pub(crate) struct Ball { - pub(super) boundary: usize, - pub(super) stub: Heap, -} - -impl Ball { - pub(super) fn new() -> Self { - Ball { - boundary: 0, - stub: Heap::new(), - } - } - - pub(super) fn reset(&mut self) { - self.boundary = 0; - self.stub.clear(); - } - - pub(super) fn copy_and_align(&self, h: usize) -> Heap { - let diff = self.boundary as i64 - h as i64; - let mut stub = Heap::new(); - - for heap_value in self.stub.iter_from(0) { - stub.push(match heap_value { - &HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff), - heap_value => heap_value.context_free_clone(), - }); - } - - stub - } -} - -#[derive(Debug)] -pub(super) struct CopyTerm<'a> { - state: &'a mut MachineState, -} - -impl<'a> CopyTerm<'a> { - pub(super) fn new(state: &'a mut MachineState) -> Self { - CopyTerm { state: state } - } -} - -impl<'a> Index for CopyTerm<'a> { - type Output = HeapCellValue; - - fn index(&self, index: usize) -> &Self::Output { - &self.state.heap[index] - } -} - -impl<'a> IndexMut for CopyTerm<'a> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.state.heap[index] - } -} - -// the ordinary, heap term copier, used by duplicate_term. -impl<'a> CopierTarget for CopyTerm<'a> { - fn threshold(&self) -> usize { - self.state.heap.h() - } - - fn push(&mut self, hcv: HeapCellValue) { - self.state.heap.push(hcv); - } - - fn store(&self, a: Addr) -> Addr { - self.state.store(a) - } - - fn deref(&self, a: Addr) -> Addr { - self.state.deref(a) - } - - fn stack(&mut self) -> &mut Stack { - &mut self.state.stack - } -} - -#[derive(Debug)] -pub(super) struct CopyBallTerm<'a> { - stack: &'a mut Stack, - heap: &'a mut Heap, - heap_boundary: usize, - stub: &'a mut Heap, -} - -impl<'a> CopyBallTerm<'a> { - pub(super) fn new(stack: &'a mut Stack, heap: &'a mut Heap, stub: &'a mut Heap) -> Self { - let hb = heap.h(); - - CopyBallTerm { - stack, - heap, - heap_boundary: hb, - stub, - } - } -} - -impl<'a> Index for CopyBallTerm<'a> { - type Output = HeapCellValue; - - fn index(&self, index: usize) -> &Self::Output { - if index < self.heap_boundary { - &self.heap[index] - } else { - let index = index - self.heap_boundary; - &self.stub[index] - } - } -} - -impl<'a> IndexMut for CopyBallTerm<'a> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - if index < self.heap_boundary { - &mut self.heap[index] - } else { - let index = index - self.heap_boundary; - &mut self.stub[index] - } - } -} - -// the ordinary, heap term copier, used by duplicate_term. -impl<'a> CopierTarget for CopyBallTerm<'a> { - fn threshold(&self) -> usize { - self.heap_boundary + self.stub.h() - } - - fn push(&mut self, value: HeapCellValue) { - self.stub.push(value); - } - - fn store(&self, addr: Addr) -> Addr { - match addr { - Addr::HeapCell(h) | Addr::AttrVar(h) if h < self.heap_boundary => { - self.heap[h].as_addr(h) - } - Addr::HeapCell(h) | Addr::AttrVar(h) => { - let index = h - self.heap_boundary; - self.stub[index].as_addr(h) - } - Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc], - addr => addr, - } - } - - fn deref(&self, mut addr: Addr) -> Addr { - loop { - let value = self.store(addr); - - if value.is_ref() && value != addr { - addr = value; - continue; - } - - return addr; - } - } - - fn stack(&mut self) -> &mut Stack { - self.stack - } -} - -impl Index for MachineState { - type Output = Addr; - - fn index(&self, reg: RegType) -> &Self::Output { - match reg { - RegType::Temp(temp) => &self.registers[temp], - RegType::Perm(perm) => { - let e = self.e; - &self.stack.index_and_frame(e)[perm] - } - } - } -} - -impl IndexMut for MachineState { - fn index_mut(&mut self, reg: RegType) -> &mut Self::Output { - match reg { - RegType::Temp(temp) => &mut self.registers[temp], - RegType::Perm(perm) => { - let e = self.e; - - &mut self.stack.index_and_frame_mut(e)[perm] - } - } - } -} - -pub(crate) type Registers = Vec; +pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1]; #[derive(Debug, Clone, Copy)] pub(super) enum MachineMode { @@ -239,29 +46,6 @@ pub(super) enum HeapPtr { PStrLocation(usize, usize), } -impl HeapPtr { - #[inline] - pub(super) fn read(&self, heap: &Heap) -> Addr { - match self { - &HeapPtr::HeapCell(h) => Addr::HeapCell(h), - &HeapPtr::PStrChar(h, n) => { - if let &HeapCellValue::PartialString(ref pstr, has_tail) = &heap[h] { - if let Some(c) = pstr.range_from(n..).next() { - Addr::Char(c) - } else if has_tail { - Addr::HeapCell(h + 1) - } else { - Addr::EmptyList - } - } else { - unreachable!() - } - } - &HeapPtr::PStrLocation(h, n) => Addr::PStrLocation(h, n), - } - } -} - impl Default for HeapPtr { fn default() -> Self { HeapPtr::HeapCell(0) @@ -274,9 +58,10 @@ pub enum FirstOrNext { Next, } -// #[derive(Debug)] -pub(crate) struct MachineState { - pub(crate) atom_tbl: TabledData, +pub struct MachineState { + pub atom_tbl: AtomTable, + pub arena: Arena, + pub(super) pdl: Vec, pub(super) s: HeapPtr, pub(super) p: CodePtr, pub(super) b: usize, @@ -286,11 +71,11 @@ pub(crate) struct MachineState { pub(super) cp: LocalCodePtr, pub(super) attr_var_init: AttrVarInitializer, pub(super) fail: bool, - pub(crate) heap: Heap, + pub heap: Heap, pub(super) mode: MachineMode, pub(crate) stack: Stack, pub(super) registers: Registers, - pub(super) trail: Vec, + pub(super) trail: Vec, pub(super) tr: usize, pub(super) hb: usize, pub(super) block: usize, // an offset into the OR stack. @@ -302,14 +87,15 @@ pub(crate) struct MachineState { pub(crate) cc: usize, pub(crate) global_clock: usize, pub(crate) dynamic_mode: FirstOrNext, - pub(crate) unify_fn: fn(&mut MachineState, Addr, Addr), - pub(crate) bind_fn: fn(&mut MachineState, Ref, Addr), + pub(crate) unify_fn: fn(&mut MachineState), + pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue), } impl fmt::Debug for MachineState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MachineState") .field("atom_tbl", &self.atom_tbl) + .field("arena", &self.arena) .field("s", &self.s) .field("p", &self.p) .field("b", &self.b) @@ -361,403 +147,73 @@ impl fmt::Debug for MachineState { } } -impl MachineState { - pub(crate) fn read_term(&mut self, mut stream: Stream, indices: &mut IndexStore) -> CallResult { - fn push_var_eq_functors<'a>( - heap: &mut Heap, - iter: impl Iterator, &'a Addr)>, - op_dir: &OpDir, - atom_tbl: TabledData, - ) -> Vec { - let mut list_of_var_eqs = vec![]; +impl Index for MachineState { + type Output = HeapCellValue; - for (var, binding) in iter { - let var_atom = clause_name!(var.to_string(), atom_tbl); + #[inline(always)] + fn index(&self, reg: RegType) -> &Self::Output { + match reg { + RegType::Temp(temp) => &self.registers[temp], + RegType::Perm(perm) => { + let e = self.e; + &self.stack[stack_loc!(AndFrame, e, perm)] + } + } + } +} - let h = heap.h(); - let spec = fetch_atom_op_spec(clause_name!("="), None, op_dir); +impl IndexMut for MachineState { + #[inline(always)] + fn index_mut(&mut self, reg: RegType) -> &mut Self::Output { + match reg { + RegType::Temp(temp) => &mut self.registers[temp], + RegType::Perm(perm) => { + let e = self.e; + &mut self.stack[stack_loc!(AndFrame, e, perm)] + } + } + } +} - heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec)); - heap.push(HeapCellValue::Atom(var_atom, None)); - heap.push(HeapCellValue::Addr(*binding)); +pub type CallResult = Result<(), Vec>; - list_of_var_eqs.push(Addr::Str(h)); - } +pub trait CutPolicy: Any + fmt::Debug { + // returns true iff we fail or cut redirected the MachineState's p itself + fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool; +} - list_of_var_eqs - } +downcast!(dyn CutPolicy); - self.check_stream_properties( - &mut stream, - StreamType::Text, - Some(self[temp_v!(2)]), - clause_name!("read_term"), - 3, - )?; +pub trait CallPolicy: Any + fmt::Debug { + fn retry_me_else( + &mut self, + machine_st: &mut MachineState, + offset: usize, + global_variables: &mut GlobalVarDir, + ) -> CallResult { + let b = machine_st.b; + let n = machine_st + .stack + .index_or_frame(b) + .prelude + .univ_prelude + .num_cells; - if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { - return return_from_clause!(self.last_call, self); - } else if self.fail { - return Ok(()); - } + for i in 1..n + 1 { + machine_st.registers[i] = machine_st.stack[stack_loc!(OrFrame, b, i - 1)]; } - let mut orig_stream = stream.clone(); - - loop { - match self.read(stream.clone(), self.atom_tbl.clone(), &indices.op_dir) { - Ok(term_write_result) => { - let term = self[temp_v!(2)]; - (self.unify_fn)(self, Addr::HeapCell(term_write_result.heap_loc), term); + machine_st.num_of_args = n; + machine_st.e = machine_st.stack.index_or_frame(b).prelude.e; + machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp; - if self.fail { - return Ok(()); - } + machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + offset; - let mut singleton_var_set: IndexMap = IndexMap::new(); + let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; + let curr_tr = machine_st.tr; - for addr in self.acyclic_pre_order_iter(term) { - if let Some(var) = addr.as_var() { - if !singleton_var_set.contains_key(&var) { - singleton_var_set.insert(var, true); - } else { - singleton_var_set.insert(var, false); - } - } - } - - let singleton_var_list = push_var_eq_functors( - &mut self.heap, - term_write_result.var_dict.iter().filter(|(_, binding)| { - if let Some(r) = binding.as_var() { - *singleton_var_set.get(&r).unwrap_or(&false) - } else { - false - } - }), - &indices.op_dir, - self.atom_tbl.clone(), - ); - - let mut var_list = Vec::with_capacity(singleton_var_set.len()); - - for (var_name, addr) in term_write_result.var_dict { - if let Some(var) = addr.as_var() { - let idx = singleton_var_set.get_index_of(&var).unwrap(); - var_list.push((var_name, addr, idx)); - } - } - - var_list.sort_by(|(_,_,idx_1),(_,_,idx_2)| idx_1.cmp(idx_2)); - - let list_of_var_eqs = push_var_eq_functors( - &mut self.heap, - var_list.iter().map(|(var_name, var,_)| (var_name,var)), - &indices.op_dir, - self.atom_tbl.clone(), - ); - - let singleton_addr = self[temp_v!(3)]; - let singletons_offset = Addr::HeapCell(self.heap.to_list( - singleton_var_list.into_iter() - )); - - (self.unify_fn)(self, singletons_offset, singleton_addr); - - if self.fail { - return Ok(()); - } - - let vars_addr = self[temp_v!(4)]; - let vars_offset = Addr::HeapCell(self.heap.to_list( - var_list.into_iter().map(|(_,var,_)| var) - )); - - (self.unify_fn)(self, vars_offset, vars_addr); - - if self.fail { - return Ok(()); - } - - let var_names_addr = self[temp_v!(5)]; - let var_names_offset = - Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter())); - - return Ok((self.unify_fn)(self, var_names_offset, var_names_addr)); - } - Err(err) => { - if let ParserError::UnexpectedEOF = err { - self.eof_action( - self[temp_v!(2)], - &mut orig_stream, - clause_name!("read_term"), - 3, - )?; - - if orig_stream.options().eof_action == EOFAction::Reset { - if self.fail == false { - continue; - } - } - - return Ok(()); - } - - let stub = MachineError::functor_stub(clause_name!("read_term"), 3); - let err = MachineError::syntax_error(self.heap.h(), err); - - return Err(self.error_form(err, stub)); - } - } - } - } - - pub(crate) fn write_term<'a>( - &'a self, - op_dir: &'a OpDir, - ) -> Result>, MachineStub> { - let ignore_ops = self.store(self.deref(self[temp_v!(3)])); - let numbervars = self.store(self.deref(self[temp_v!(4)])); - let quoted = self.store(self.deref(self[temp_v!(5)])); - let max_depth = self.store(self.deref(self[temp_v!(7)])); - - let mut printer = HCPrinter::new(&self, op_dir, PrinterOutputter::new()); - - if let &Addr::Con(h) = &ignore_ops { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - printer.ignore_ops = name.as_str() == "true"; - } else { - unreachable!() - } - } - - if let &Addr::Con(h) = &numbervars { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - printer.numbervars = name.as_str() == "true"; - } else { - unreachable!() - } - } - - if let &Addr::Con(h) = "ed { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - printer.quoted = name.as_str() == "true"; - } else { - unreachable!() - } - } - - match Number::try_from((max_depth, &self.heap)) { - Ok(Number::Fixnum(n)) => { - if let Ok(n) = usize::try_from(n) { - printer.max_depth = n; - } else { - return Ok(None); - } - } - Ok(Number::Integer(n)) => { - if let Some(n) = n.to_usize() { - printer.max_depth = n; - } else { - return Ok(None); - } - } - _ => { - unreachable!(); - } - } - - let stub = MachineError::functor_stub(clause_name!("write_term"), 2); - - match self.try_from_list(temp_v!(6), stub) { - Ok(addrs) => { - let mut var_names: IndexMap = IndexMap::new(); - - for addr in addrs { - match addr { - Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(2, ref name, _) if name.as_str() == "=" => { - let atom = self.heap[s + 1].as_addr(s + 1); - let var = self.heap[s + 2].as_addr(s + 2); - - let atom = match self.store(self.deref(atom)) { - Addr::Con(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.to_string() - } else { - unreachable!() - } - } - Addr::Char(c) => c.to_string(), - _ => unreachable!(), - }; - - let var = self.store(self.deref(var)); - - if var_names.contains_key(&var) { - continue; - } - - var_names.insert(var, atom); - } - _ => {} - }, - _ => {} - } - } - - printer.var_names = var_names; - } - Err(err) => { - return Err(err); - } - } - - Ok(Some(printer)) - } - - pub(super) fn throw_undefined_error(&mut self, name: ClauseName, arity: usize) -> MachineStub { - let stub = MachineError::functor_stub(name.clone(), arity); - let h = self.heap.h(); - let key = ExistenceError::Procedure(name, arity); - - self.error_form(MachineError::existence_error(h, key), stub) - } - - #[inline] - pub(crate) fn heap_pstr_iter<'a>(&'a self, focus: Addr) -> HeapPStrIter<'a> { - HeapPStrIter::new(self, focus) - } - - pub(super) fn try_char_list(&self, addrs: Vec) -> Result { - let mut chars = String::new(); - let mut iter = addrs.iter(); - - while let Some(addr) = iter.next() { - let addr = self.store(self.deref(*addr)); - - match addr { - Addr::Char(c) => { - chars.push(c); - continue; - } - Addr::Con(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - if name.is_char() { - chars += name.as_str(); - continue; - } - } - } - _ => {} - }; - - let h = self.heap.h(); - - return Err(MachineError::type_error(h, ValidType::Character, addr)); - } - - Ok(chars) - } - - pub(super) fn read_predicate_key(&self, name: Addr, arity: Addr) -> (ClauseName, usize) { - let predicate_name = atom_from!(self, self.store(self.deref(name))); - let arity = self.store(self.deref(arity)); - - let arity = match Number::try_from((arity, &self.heap)) { - Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => n.to_usize().unwrap(), - Ok(Number::Fixnum(n)) if n >= 0 && n <= MAX_ARITY as isize => { - usize::try_from(n).unwrap() - } - _ => unreachable!(), - }; - - (predicate_name, arity) - } - - pub(super) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) { - self.cp.assign_if_local(self.p.clone() + 1); - self.num_of_args = arity; - self.b0 = self.b; - self.p = CodePtr::Local(p); - } - - pub(super) fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) { - self.num_of_args = arity; - self.b0 = self.b; - self.p = CodePtr::Local(p); - } - - pub(super) fn module_lookup( - &mut self, - indices: &IndexStore, - call_policy: &mut Box, - key: PredicateKey, - module_name: ClauseName, - _last_call: bool, - stream_aliases: &StreamAliasDir, - ) -> CallResult { - if module_name.as_str() == "user" { - return call_policy.call_clause_type( - self, - key, - &indices.code_dir, - &indices.op_dir, - stream_aliases, - ); - } else if let Some(module) = indices.modules.get(&module_name) { - return call_policy.call_clause_type( - self, - key, - &module.code_dir, - &module.op_dir, - stream_aliases, - ); - } - - let (name, arity) = key; - - let h = self.heap.h(); - let stub = MachineError::functor_stub(name.clone(), arity); - let err = MachineError::module_resolution_error(h, module_name, name, arity); - - return Err(self.error_form(err, stub)); - } -} - -pub(crate) type CallResult = Result<(), Vec>; - -pub(crate) trait CallPolicy: Any + fmt::Debug { - fn retry_me_else( - &mut self, - machine_st: &mut MachineState, - offset: usize, - global_variables: &mut GlobalVarDir, - ) -> CallResult { - let b = machine_st.b; - let n = machine_st - .stack - .index_or_frame(b) - .prelude - .univ_prelude - .num_cells; - - for i in 1..n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; - } - - machine_st.num_of_args = n; - machine_st.e = machine_st.stack.index_or_frame(b).prelude.e; - machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp; - - machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + offset; - - let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; - let curr_tr = machine_st.tr; - - machine_st.unwind_trail(old_tr, curr_tr, global_variables); - machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; + machine_st.unwind_trail(old_tr, curr_tr, global_variables); + machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; machine_st.trail.truncate(machine_st.tr); machine_st @@ -765,8 +221,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .truncate(machine_st.stack.index_or_frame(b).prelude.h); machine_st.attr_var_init.reset(); - - machine_st.hb = machine_st.heap.h(); + machine_st.hb = machine_st.heap.len(); machine_st.p += 1; Ok(()) @@ -808,8 +263,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .truncate(machine_st.stack.index_or_frame(b).prelude.h); machine_st.attr_var_init.reset(); - - machine_st.hb = machine_st.heap.h(); + machine_st.hb = machine_st.heap.len(); machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); Ok(()) @@ -830,7 +284,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .num_cells; for i in 1..n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; + machine_st.registers[i] = machine_st.stack[stack_loc!(OrFrame, b, i - 1)]; } machine_st.num_of_args = n; @@ -849,11 +303,10 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .truncate(machine_st.stack.index_or_frame(b).prelude.h); machine_st.attr_var_init.reset(); - machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.stack.truncate(b); - machine_st.hb = machine_st.heap.h(); + machine_st.hb = machine_st.heap.len(); machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); Ok(()) @@ -873,7 +326,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .num_cells; for i in 1..n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; + machine_st.registers[i] = machine_st.stack[stack_loc!(OrFrame, b, i - 1)]; } machine_st.num_of_args = n; @@ -892,11 +345,10 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { .truncate(machine_st.stack.index_or_frame(b).prelude.h); machine_st.attr_var_init.reset(); - machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.stack.truncate(b); - machine_st.hb = machine_st.heap.h(); + machine_st.hb = machine_st.heap.len(); machine_st.p += 1; Ok(()) @@ -905,7 +357,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { fn context_call( &mut self, machine_st: &mut MachineState, - name: ClauseName, + name: Atom, arity: usize, idx: &CodeIndex, ) -> CallResult { @@ -919,7 +371,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { fn try_call( &mut self, machine_st: &mut MachineState, - name: ClauseName, + name: Atom, arity: usize, idx: &CodeIndex, ) -> CallResult { @@ -946,7 +398,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { fn try_execute( &mut self, machine_st: &mut MachineState, - name: ClauseName, + name: Atom, arity: usize, idx: &CodeIndex, ) -> CallResult { @@ -980,7 +432,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { ) -> CallResult { match ct { &BuiltInClauseType::AcyclicTerm => { - let addr = machine_st[temp_v!(1)]; + let addr = machine_st.registers[1]; machine_st.fail = machine_st.is_cyclic_term(addr); return_from_clause!(machine_st.last_call, machine_st) } @@ -989,57 +441,47 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Compare => { - let a1 = machine_st.store(machine_st.deref(machine_st[temp_v!(1)])); - let a2 = machine_st[temp_v!(2)]; - let a3 = machine_st[temp_v!(3)]; - - match a1 { - Addr::Con(h) if machine_st.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &machine_st.heap[h] { - match atom.as_str() { - ">" | "<" | "=" => {} - _ => { - let stub = - MachineError::functor_stub(clause_name!("compare"), 3); - - let err = - MachineError::domain_error(DomainErrorType::Order, a1); - return Err(machine_st.error_form(err, stub)); - } + let stub_gen = || functor_stub(atom!("compare"), 3); + + let a1 = machine_st.store(machine_st.deref(machine_st.registers[1])); + let a2 = machine_st.registers[2]; + let a3 = machine_st.registers[3]; + + read_heap_cell!(a1, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(machine_st.heap[s]) + .get_name_and_arity(); + + match name { + atom!(">") | atom!("<") | atom!("=") if arity == 2 => { + } + _ => { + let err = machine_st.domain_error(DomainErrorType::Order, a1); + return Err(machine_st.error_form(err, stub_gen())); } - } else { - unreachable!() } } - addr if !addr.is_ref() => { - let h = machine_st.heap.h(); - let stub = MachineError::functor_stub(clause_name!("compare"), 3); - let err = MachineError::type_error(h, ValidType::Atom, a1); - return Err(machine_st.error_form(err, stub)); + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { } - _ => {} - } + _ => { + let err = machine_st.type_error(ValidType::Atom, a1); + return Err(machine_st.error_form(err, stub_gen())); + } + ); - let atom = match machine_st.compare_term_test(&a2, &a3) { + let atom = match compare_term_test!(machine_st, a2, a3) { Some(Ordering::Greater) => { - let spec = fetch_atom_op_spec(clause_name!(">"), None, op_dir); - HeapCellValue::Atom(clause_name!(">"), spec) + atom!(">") } Some(Ordering::Equal) => { - let spec = fetch_atom_op_spec(clause_name!("="), None, op_dir); - HeapCellValue::Atom(clause_name!("="), spec) + atom!("=") } None | Some(Ordering::Less) => { - let spec = fetch_atom_op_spec(clause_name!("<"), None, op_dir); - HeapCellValue::Atom(clause_name!("<"), spec) + atom!("<") } }; - let h = machine_st.heap.h(); - - machine_st.heap.push(atom); - (machine_st.unify_fn)(machine_st, a1, Addr::Con(h)); - + machine_st.unify_atom(atom, a1); return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::CompareTerm(qt) => { @@ -1050,31 +492,24 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let stream = machine_st.get_stream_or_alias( machine_st[temp_v!(1)], stream_aliases, - "read", + atom!("read"), 2, )?; - match machine_st.read(stream, machine_st.atom_tbl.clone(), op_dir) { + match machine_st.read(stream, op_dir) { Ok(offset) => { - let addr = machine_st[temp_v!(2)]; - (machine_st.unify_fn)(machine_st, addr, Addr::HeapCell(offset.heap_loc)); + let value = machine_st.registers[2]; + unify_fn!(machine_st, value, heap_loc_as_cell!(offset.heap_loc)); } Err(ParserError::UnexpectedEOF) => { - let addr = machine_st[temp_v!(2)]; - let eof = clause_name!("end_of_file".to_string(), machine_st.atom_tbl); - - let atom = machine_st.heap.to_unifiable(HeapCellValue::Atom(eof, None)); - - (machine_st.unify_fn)(machine_st, addr, atom); + let value = machine_st.registers[2]; + machine_st.unify_atom(atom!("end_of_file"), value); } Err(e) => { - let h = machine_st.heap.h(); - let stub = MachineError::functor_stub(clause_name!("read"), 2); - - let err = MachineError::syntax_error(h, e); - let err = machine_st.error_form(err, stub); + let stub = functor_stub(atom!("read"), 2); + let err = machine_st.syntax_error(e); - return Err(err); + return Err(machine_st.error_form(err, stub)); } }; @@ -1085,8 +520,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Eq => { - let a1 = machine_st[temp_v!(1)]; - let a2 = machine_st[temp_v!(2)]; + let a1 = machine_st.registers[1]; + let a2 = machine_st.registers[2]; machine_st.fail = machine_st.eq_test(a1, a2); return_from_clause!(machine_st.last_call, machine_st) @@ -1096,146 +531,757 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Functor => { - machine_st.try_functor(op_dir)?; + machine_st.try_functor()?; return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::NotEq => { - let a1 = machine_st[temp_v!(1)]; - let a2 = machine_st[temp_v!(2)]; + let a1 = machine_st.registers[1]; + let a2 = machine_st.registers[2]; + + machine_st.fail = + if let Some(Ordering::Equal) = compare_term_test!(machine_st, a1, a2) { + true + } else { + false + }; + + return_from_clause!(machine_st.last_call, machine_st) + } + &BuiltInClauseType::Sort => { + machine_st.check_sort_errors()?; + + let stub_gen = || functor_stub(atom!("sort"), 2); + let mut list = machine_st.try_from_list(machine_st.registers[1], stub_gen)?; + + list.sort_unstable_by(|v1, v2| { + compare_term_test!(machine_st, *v1, *v2).unwrap_or(Ordering::Less) + }); + + list.dedup_by(|v1, v2| { + compare_term_test!(machine_st, *v1, *v2) == Some(Ordering::Equal) + }); + + let heap_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut machine_st.heap, list.into_iter()) + ); + + let r2 = machine_st.registers[2]; + unify_fn!(machine_st, r2, heap_addr); + + return_from_clause!(machine_st.last_call, machine_st) + } + &BuiltInClauseType::KeySort => { + machine_st.check_keysort_errors()?; + + let stub_gen = || functor_stub(atom!("keysort"), 2); + let list = machine_st.try_from_list(machine_st.registers[1], stub_gen)?; + + let mut key_pairs = Vec::with_capacity(list.len()); + + for val in list { + let key = machine_st.project_onto_key(val)?; + key_pairs.push((key, val)); + } + + key_pairs.sort_by(|a1, a2| { + compare_term_test!(machine_st, a1.0, a2.0).unwrap_or(Ordering::Less) + }); + + let key_pairs = key_pairs.into_iter().map(|kp| kp.1); + let heap_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut machine_st.heap, key_pairs) + ); + + let r2 = machine_st.registers[2]; + unify_fn!(machine_st, r2, heap_addr); + + return_from_clause!(machine_st.last_call, machine_st) + } + &BuiltInClauseType::Is(r, ref at) => { + let n1 = machine_st[r]; + let n2 = machine_st.get_number(at)?; + + match n2 { + Number::Fixnum(n) => machine_st.unify_fixnum(n, n1), + Number::Float(n) => { + // TODO: argghh.. deal with it. + let n = arena_alloc!(n, &mut machine_st.arena); + machine_st.unify_f64(n, n1) + } + Number::Integer(n) => machine_st.unify_big_int(n, n1), + Number::Rational(n) => machine_st.unify_rational(n, n1), + } + + return_from_clause!(machine_st.last_call, machine_st) + } + } + } + + fn call_clause_type( + &mut self, + machine_st: &mut MachineState, + key: PredicateKey, + code_dir: &CodeDir, + op_dir: &OpDir, + stream_aliases: &StreamAliasDir, + ) -> CallResult { + let (name, arity) = key; + + match ClauseType::from(name, arity) { + ClauseType::BuiltIn(built_in) => { + machine_st.setup_built_in_call(built_in); + self.call_builtin(machine_st, &built_in, code_dir, op_dir, stream_aliases)?; + } + ClauseType::CallN => { + machine_st.handle_internal_call_n(arity); + + if machine_st.fail { + return Ok(()); + } + + machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call); + } + ClauseType::Inlined(inlined) => { + machine_st.execute_inlined(&inlined); + + if machine_st.last_call { + machine_st.p = CodePtr::Local(machine_st.cp); + } + } + ClauseType::Named(..) => { + if let Some(idx) = code_dir.get(&(name, arity)) { + self.context_call(machine_st, name, arity, idx)?; + } else { + return Err(machine_st.throw_undefined_error(name, arity)); + } + } + ClauseType::System(_) => { + let (name, arity) = key; + let name = functor!(name); + + let stub = functor_stub(atom!("call"), arity + 1); + let err = machine_st.type_error(ValidType::Callable, name); + + return Err(machine_st.error_form(err, stub)); + } + } + + Ok(()) + } + + fn call_n( + &mut self, + machine_st: &mut MachineState, + arity: usize, + code_dir: &CodeDir, + op_dir: &OpDir, + stream_aliases: &StreamAliasDir, + ) -> CallResult { + if let Some(key) = machine_st.setup_call_n(arity) { + self.call_clause_type(machine_st, key, code_dir, op_dir, stream_aliases)?; + } + + Ok(()) + } +} + +#[inline(always)] +pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) { + read_heap_cell!(heap[index], + (HeapCellValueTag::PStr | HeapCellValueTag::CStr) => { + (index, Fixnum::build_with(0)) + } + (HeapCellValueTag::PStrOffset, h) => { + (h, cell_as_fixnum!(heap[index+1])) + } + _ => { + unreachable!() + } + ) +} + +#[derive(Debug)] +pub struct Ball { + pub(super) boundary: usize, + pub(super) stub: Heap, +} + +impl Ball { + pub(super) fn new() -> Self { + Ball { + boundary: 0, + stub: Heap::new(), + } + } + + pub(super) fn reset(&mut self) { + self.boundary = 0; + self.stub.clear(); + } + + pub(super) fn copy_and_align(&self, h: usize) -> Heap { + let diff = self.boundary as i64 - h as i64; + + self.stub.iter().cloned().map(|heap_value| { + heap_value - diff + }).collect() + } +} + +#[derive(Debug)] +pub(super) struct CopyTerm<'a> { + state: &'a mut MachineState, +} + +impl<'a> CopyTerm<'a> { + pub(super) fn new(state: &'a mut MachineState) -> Self { + CopyTerm { state } + } +} + +impl<'a> Index for CopyTerm<'a> { + type Output = HeapCellValue; + + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + &self.state.heap[index] + } +} + +impl<'a> IndexMut for CopyTerm<'a> { + #[inline(always)] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.state.heap[index] + } +} + +// the ordinary, heap term copier, used by duplicate_term. +impl<'a> CopierTarget for CopyTerm<'a> { + #[inline(always)] + fn threshold(&self) -> usize { + self.state.heap.len() + } + + #[inline(always)] + fn push(&mut self, hcv: HeapCellValue) { + self.state.heap.push(hcv); + } + + #[inline(always)] + fn store(&self, value: HeapCellValue) -> HeapCellValue { + self.state.store(value) + } + + #[inline(always)] + fn deref(&self, value: HeapCellValue) -> HeapCellValue { + self.state.deref(value) + } + + #[inline(always)] + fn stack(&mut self) -> &mut Stack { + &mut self.state.stack + } +} + +#[derive(Debug)] +pub(super) struct CopyBallTerm<'a> { + stack: &'a mut Stack, + heap: &'a mut Heap, + heap_boundary: usize, + stub: &'a mut Heap, +} + +impl<'a> CopyBallTerm<'a> { + pub(super) fn new(stack: &'a mut Stack, heap: &'a mut Heap, stub: &'a mut Heap) -> Self { + let hb = heap.len(); + + CopyBallTerm { + stack, + heap, + heap_boundary: hb, + stub, + } + } +} + +impl<'a> Index for CopyBallTerm<'a> { + type Output = HeapCellValue; + + fn index(&self, index: usize) -> &Self::Output { + if index < self.heap_boundary { + &self.heap[index] + } else { + let index = index - self.heap_boundary; + &self.stub[index] + } + } +} + +impl<'a> IndexMut for CopyBallTerm<'a> { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + if index < self.heap_boundary { + &mut self.heap[index] + } else { + let index = index - self.heap_boundary; + &mut self.stub[index] + } + } +} + +// the ordinary, heap term copier, used by duplicate_term. +impl<'a> CopierTarget for CopyBallTerm<'a> { + fn threshold(&self) -> usize { + self.heap_boundary + self.stub.len() + } + + fn push(&mut self, value: HeapCellValue) { + self.stub.push(value); + } + + fn store(&self, value: HeapCellValue) -> HeapCellValue { + read_heap_cell!(value, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => { + if h < self.heap_boundary { + self.heap[h] + } else { + let index = h - self.heap_boundary; + self.stub[index] + } + } + (HeapCellValueTag::StackVar, s) => { + self.stack[s] + } + _ => { + value + } + ) + } + + fn deref(&self, mut addr: HeapCellValue) -> HeapCellValue { + loop { + let value = self.store(addr); + + if value.is_var() && value != addr { + addr = value; + continue; + } + + return addr; + } + } + + fn stack(&mut self) -> &mut Stack { + self.stack + } +} + +impl MachineState { + #[allow(dead_code)] + pub(super) fn try_char_list(&mut self, addrs: Vec) -> Result { + let mut chars = String::new(); + + for addr in addrs { + let addr = self.store(self.deref(addr)); + + read_heap_cell!(addr, + (HeapCellValueTag::Char, c) => { + chars.push(c); + continue; + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + if let Some(c) = name.as_char() { + chars.push(c); + continue; + } + } + } + _ => { + } + ); + + return Err(self.type_error(ValidType::Character, addr)); + } + + Ok(chars) + } + + pub(super) fn throw_undefined_error(&mut self, name: Atom, arity: usize) -> MachineStub { + let stub = functor_stub(name, arity); + let err = self.existence_error(ExistenceError::Procedure(name, arity)); + + self.error_form(err, stub) + } + + pub(super) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) { + self.cp.assign_if_local(self.p + 1); + self.num_of_args = arity; + self.b0 = self.b; + self.p = CodePtr::Local(p); + } + + pub(super) fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) { + self.num_of_args = arity; + self.b0 = self.b; + self.p = CodePtr::Local(p); + } + + pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult { + fn push_var_eq_functors<'a>( + heap: &mut Heap, + iter: impl Iterator, &'a HeapCellValue)>, + atom_tbl: &mut AtomTable, + ) -> Vec { + let mut list_of_var_eqs = vec![]; + + for (var, binding) in iter { + let var_atom = atom_tbl.build_with(&var); + let h = heap.len(); + + heap.push(atom_as_cell!(atom!("="), 2)); + heap.push(atom_as_cell!(var_atom)); + heap.push(*binding); + + list_of_var_eqs.push(str_loc_as_cell!(h)); + } + + list_of_var_eqs + } + + self.check_stream_properties( + stream, + StreamType::Text, + Some(self.registers[2]), + atom!("read_term"), + 3, + )?; + + if stream.past_end_of_stream() { + if EOFAction::Reset != stream.options().eof_action() { + return return_from_clause!(self.last_call, self); + } else if self.fail { + return Ok(()); + } + } + + loop { + match self.read(stream, &indices.op_dir) { + Ok(term_write_result) => { + let term = self.registers[2]; + unify_fn!(self, heap_loc_as_cell!(term_write_result.heap_loc), term); + let term = self.store(self.deref(term)); + + if self.fail { + return Ok(()); + } + + let mut singleton_var_set: IndexMap = IndexMap::new(); + let mut var_list = vec![]; + + let list_of_var_eqs = push_var_eq_functors( + &mut self.heap, + term_write_result.var_dict.iter(), + &mut self.atom_tbl, + ); + + for addr in stackful_preorder_iter(&mut self.heap, term) { + let addr = unmark_cell_bits!(addr); + + if let Some(var) = addr.as_var() { + if !singleton_var_set.contains_key(&var) { + singleton_var_set.insert(var, true); + var_list.push(addr); + } else { + singleton_var_set.insert(var, false); + } + } + } + + let singleton_var_list = push_var_eq_functors( + &mut self.heap, + term_write_result.var_dict.iter().filter(|(_, binding)| { + if let Some(r) = binding.as_var() { + *singleton_var_set.get(&r).unwrap_or(&false) + } else { + false + } + }), + &mut self.atom_tbl, + ); + + let singleton_addr = self.registers[3]; + let singletons_offset = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, singleton_var_list.into_iter()) + ); + + unify_fn!(self, singletons_offset, singleton_addr); + + if self.fail { + return Ok(()); + } + + let vars_addr = self.registers[4]; + let vars_offset = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, var_list.into_iter()) + ); + + unify_fn!(self, vars_offset, vars_addr); + + if self.fail { + return Ok(()); + } + + let var_names_addr = self.registers[5]; + let var_names_offset = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, list_of_var_eqs.into_iter()) + ); + + return Ok(unify_fn!(self, var_names_offset, var_names_addr)); + } + Err(err) => { + if let ParserError::UnexpectedEOF = err { + self.eof_action( + self.registers[2], + stream, + atom!("read_term"), + 3, + )?; + + if stream.options().eof_action() == EOFAction::Reset { + if self.fail == false { + continue; + } + } + + return Ok(()); + } - machine_st.fail = - if let Some(Ordering::Equal) = machine_st.compare_term_test(&a1, &a2) { - true - } else { - false - }; + let stub = functor_stub(atom!("read_term"), 3); + let err = self.syntax_error(err); - return_from_clause!(machine_st.last_call, machine_st) + return Err(self.error_form(err, stub)); + } } - &BuiltInClauseType::Sort => { - machine_st.check_sort_errors()?; + } + } - let stub = MachineError::functor_stub(clause_name!("sort"), 2); - let mut list = machine_st.try_from_list(temp_v!(1), stub)?; + pub(crate) fn write_term<'a>( + &'a mut self, + op_dir: &'a OpDir, + ) -> Result>, MachineStub> { + let ignore_ops = self.store(self.deref(self.registers[3])); + let numbervars = self.store(self.deref(self.registers[4])); + let quoted = self.store(self.deref(self.registers[5])); + let max_depth = self.store(self.deref(self.registers[7])); - list.sort_unstable_by(|a1, a2| { - machine_st - .compare_term_test(a1, a2) - .unwrap_or(Ordering::Less) - }); + let term_to_be_printed = self.store(self.deref(self.registers[2])); + let stub_gen = || functor_stub(atom!("write_term"), 2); - machine_st.term_dedup(&mut list); + let printer = match self.try_from_list(self.registers[6], stub_gen) { + Ok(addrs) => { + let mut var_names: IndexMap> = IndexMap::new(); - let heap_addr = Addr::HeapCell(machine_st.heap.to_list(list.into_iter())); + for addr in addrs { + read_heap_cell!(addr, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); - let r2 = machine_st[temp_v!(2)]; - (machine_st.unify_fn)(machine_st, r2, heap_addr); + if name == atom!("=") && arity == 2 { + let atom = self.store(self.deref(self.heap[s+1])); + let var = self.store(self.deref(self.heap[s+2])); - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::KeySort => { - machine_st.check_keysort_errors()?; + if var_names.contains_key(&var) { + continue; + } - let stub = MachineError::functor_stub(clause_name!("keysort"), 2); - let list = machine_st.try_from_list(temp_v!(1), stub)?; - let mut key_pairs = Vec::new(); + var_names.insert(var, Rc::new(cell_as_atom!(atom).as_str().to_owned())); + } + } + _ => { + } + ); + } - for val in list { - let key = machine_st.project_onto_key(val.clone())?; - key_pairs.push((key, val.clone())); + let mut printer = HCPrinter::new( + &mut self.heap, + &mut self.arena, + op_dir, + PrinterOutputter::new(), + term_to_be_printed, + ); + + if let HeapCellValueTag::Atom = ignore_ops.get_tag() { + let name = cell_as_atom!(ignore_ops); + printer.ignore_ops = name == atom!("true"); + } else { + unreachable!(); } - key_pairs.sort_by(|a1, a2| { - machine_st - .compare_term_test(&a1.0, &a2.0) - .unwrap_or(Ordering::Less) - }); + if let HeapCellValueTag::Atom = numbervars.get_tag() { + let name = cell_as_atom!(numbervars); + printer.numbervars = name == atom!("true"); + } else { + unreachable!(); + } - let key_pairs = key_pairs.into_iter().map(|kp| kp.1); - let heap_addr = Addr::HeapCell(machine_st.heap.to_list(key_pairs)); + if let HeapCellValueTag::Atom = quoted.get_tag() { + let name = cell_as_atom!(quoted); + printer.quoted = name == atom!("true"); + } else { + unreachable!(); + } - let r2 = machine_st[temp_v!(2)]; - (machine_st.unify_fn)(machine_st, r2, heap_addr); + match Number::try_from(max_depth) { + Ok(Number::Fixnum(n)) => { + if let Ok(n) = usize::try_from(n.get_num()) { + printer.max_depth = n; + } else { + self.fail = true; + return Ok(None); + } + } + Ok(Number::Integer(n)) => { + if let Some(n) = n.to_usize() { + printer.max_depth = n; + } else { + self.fail = true; + return Ok(None); + } + } + _ => { + unreachable!(); + } + } - return_from_clause!(machine_st.last_call, machine_st) + printer.var_names = var_names; + + printer } - &BuiltInClauseType::Is(r, ref at) => { - let a1 = machine_st[r]; - let n2 = machine_st.get_number(at)?; + Err(err) => { + return Err(err); + } + }; - let n2 = machine_st.heap.put_constant(n2.into()); - (machine_st.unify_fn)(machine_st, a1, n2); + Ok(Some(printer)) + } - return_from_clause!(machine_st.last_call, machine_st) - } - } + pub(super) fn read_predicate_key(&self, name: HeapCellValue, arity: HeapCellValue) -> (Atom, usize) { + let name = cell_as_atom!(self.store(self.deref(name))); + let arity = cell_as_fixnum!(self.store(self.deref(arity))); + + (name, usize::try_from(arity.get_num()).unwrap()) } - fn call_clause_type( + pub(super) fn module_lookup( &mut self, - machine_st: &mut MachineState, + indices: &IndexStore, + call_policy: &mut Box, key: PredicateKey, - code_dir: &CodeDir, - op_dir: &OpDir, + module_name: Atom, + _last_call: bool, stream_aliases: &StreamAliasDir, ) -> CallResult { + if module_name == atom!("user") { + return call_policy.call_clause_type( + self, + key, + &indices.code_dir, + &indices.op_dir, + stream_aliases, + ); + } else if let Some(module) = indices.modules.get(&module_name) { + return call_policy.call_clause_type( + self, + key, + &module.code_dir, + &module.op_dir, + stream_aliases, + ); + } + let (name, arity) = key; - match ClauseType::from(name.clone(), arity, None) { - ClauseType::BuiltIn(built_in) => { - machine_st.setup_built_in_call(built_in.clone()); - self.call_builtin(machine_st, &built_in, code_dir, op_dir, stream_aliases)?; - } - ClauseType::CallN => { - machine_st.handle_internal_call_n(arity); + let stub = functor_stub(name, arity); + let err = self.module_resolution_error(module_name, name, arity); - if machine_st.fail { - return Ok(()); - } + return Err(self.error_form(err, stub)); + } +} - machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call); - } - ClauseType::Inlined(inlined) => { - machine_st.execute_inlined(&inlined); +#[derive(Debug)] +pub(crate) struct CWILCallPolicy { + pub(crate) prev_policy: Box, + count: Integer, + limits: Vec<(Integer, usize)>, + inference_limit_exceeded: bool, +} - if machine_st.last_call { - machine_st.p = CodePtr::Local(machine_st.cp); - } - } - ClauseType::Op(..) | ClauseType::Named(..) => { - if let Some(idx) = code_dir.get(&(name.clone(), arity)) { - self.context_call(machine_st, name, arity, idx)?; - } else { - return Err(machine_st.throw_undefined_error(name, arity)); - } - } - ClauseType::System(_) => { - let name = functor!(clause_name(name)); - let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); +impl CWILCallPolicy { + pub(crate) fn new_in_place(policy: &mut Box) { + let mut prev_policy: Box = Box::new(DefaultCallPolicy {}); + mem::swap(&mut prev_policy, policy); + + let new_policy = CWILCallPolicy { + prev_policy, + count: Integer::from(0), + limits: vec![], + inference_limit_exceeded: false, + }; + + *policy = Box::new(new_policy); + } + + fn increment(&mut self, machine_st: &MachineState) -> CallResult { + if self.inference_limit_exceeded || machine_st.ball.stub.len() > 0 { + return Ok(()); + } + + if let Some(&(ref limit, bp)) = self.limits.last() { + if self.count == *limit { + self.inference_limit_exceeded = true; - return Err(machine_st.error_form( - MachineError::type_error(machine_st.heap.h(), ValidType::Callable, name), - stub, - )); + return Err( + functor!(atom!("inference_limit_exceeded"), [fixnum(bp)]) + ); + } else { + self.count += 1; } } Ok(()) } - fn call_n( - &mut self, - machine_st: &mut MachineState, - arity: usize, - code_dir: &CodeDir, - op_dir: &OpDir, - stream_aliases: &StreamAliasDir, - ) -> CallResult { - if let Some(key) = machine_st.setup_call_n(arity) { - self.call_clause_type(machine_st, key, code_dir, op_dir, stream_aliases)?; + pub(crate) fn add_limit(&mut self, limit: usize, b: usize) -> &Integer { + let mut limit = Integer::from(limit); + limit += &self.count; + + match self.limits.last() { + Some((ref inner_limit, _)) if *inner_limit <= limit => {} + _ => self.limits.push((limit, b)), + }; + + &self.count + } + + pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { + if let Some((_, bp)) = self.limits.last() { + if bp == &b { + self.limits.pop(); + } } - Ok(()) + &self.count + } + + pub(crate) fn is_empty(&self) -> bool { + self.limits.is_empty() + } + + pub(crate) fn into_inner(&mut self) -> Box { + let mut new_inner: Box = Box::new(DefaultCallPolicy {}); + mem::swap(&mut self.prev_policy, &mut new_inner); + new_inner } } @@ -1243,12 +1289,11 @@ impl CallPolicy for CWILCallPolicy { fn context_call( &mut self, machine_st: &mut MachineState, - name: ClauseName, + name: Atom, arity: usize, idx: &CodeIndex, ) -> CallResult { - self.prev_policy - .context_call(machine_st, name, arity, idx)?; //, indices)?; + self.prev_policy.context_call(machine_st, name, arity, idx)?; self.increment(machine_st) } @@ -1258,8 +1303,7 @@ impl CallPolicy for CWILCallPolicy { offset: usize, global_variables: &mut GlobalVarDir, ) -> CallResult { - self.prev_policy - .retry_me_else(machine_st, offset, global_variables)?; + self.prev_policy.retry_me_else(machine_st, offset, global_variables)?; self.increment(machine_st) } @@ -1269,8 +1313,7 @@ impl CallPolicy for CWILCallPolicy { offset: usize, global_variables: &mut GlobalVarDir, ) -> CallResult { - self.prev_policy - .retry(machine_st, offset, global_variables)?; + self.prev_policy.retry(machine_st, offset, global_variables)?; self.increment(machine_st) } @@ -1289,8 +1332,7 @@ impl CallPolicy for CWILCallPolicy { offset: usize, global_variables: &mut GlobalVarDir, ) -> CallResult { - self.prev_policy - .trust(machine_st, offset, global_variables)?; + self.prev_policy.trust(machine_st, offset, global_variables)?; self.increment(machine_st) } @@ -1302,9 +1344,7 @@ impl CallPolicy for CWILCallPolicy { op_dir: &OpDir, stream_aliases: &StreamAliasDir, ) -> CallResult { - self.prev_policy - .call_builtin(machine_st, ct, code_dir, op_dir, stream_aliases)?; - + self.prev_policy.call_builtin(machine_st, ct, code_dir, op_dir, stream_aliases)?; self.increment(machine_st) } @@ -1316,9 +1356,7 @@ impl CallPolicy for CWILCallPolicy { op_dir: &OpDir, stream_aliases: &StreamAliasDir, ) -> CallResult { - self.prev_policy - .call_n(machine_st, arity, code_dir, op_dir, stream_aliases)?; - + self.prev_policy.call_n(machine_st, arity, code_dir, op_dir, stream_aliases)?; self.increment(machine_st) } } @@ -1330,94 +1368,13 @@ pub(crate) struct DefaultCallPolicy {} impl CallPolicy for DefaultCallPolicy {} -#[derive(Debug)] -pub(crate) struct CWILCallPolicy { - pub(crate) prev_policy: Box, - count: Integer, - limits: Vec<(Integer, usize)>, - inference_limit_exceeded: bool, -} - -impl CWILCallPolicy { - pub(crate) fn new_in_place(policy: &mut Box) { - let mut prev_policy: Box = Box::new(DefaultCallPolicy {}); - mem::swap(&mut prev_policy, policy); - - let new_policy = CWILCallPolicy { - prev_policy, - count: Integer::from(0), - limits: vec![], - inference_limit_exceeded: false, - }; - - *policy = Box::new(new_policy); - } - - fn increment(&mut self, machine_st: &MachineState) -> CallResult { - if self.inference_limit_exceeded || machine_st.ball.stub.h() > 0 { - return Ok(()); - } - - if let Some(&(ref limit, bp)) = self.limits.last() { - if self.count == *limit { - self.inference_limit_exceeded = true; - - return Err(functor!( - "inference_limit_exceeded", - [addr(Addr::Usize(bp))] - )); - } else { - self.count += 1; - } - } - - Ok(()) - } - - pub(crate) fn add_limit(&mut self, mut limit: Integer, b: usize) -> &Integer { - limit += &self.count; - - match self.limits.last().cloned() { - Some((ref inner_limit, _)) if *inner_limit <= limit => {} - _ => self.limits.push((limit, b)), - }; - - &self.count - } - - pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { - if let Some((_, bp)) = self.limits.last().cloned() { - if bp == b { - self.limits.pop(); - } - } - - &self.count - } - - pub(crate) fn is_empty(&self) -> bool { - self.limits.is_empty() - } - - pub(crate) fn into_inner(&mut self) -> Box { - let mut new_inner: Box = Box::new(DefaultCallPolicy {}); - mem::swap(&mut self.prev_policy, &mut new_inner); - new_inner - } -} - -pub(crate) trait CutPolicy: Any + fmt::Debug { - // returns true iff we fail or cut redirected the MachineState's p itself - fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool; -} - -downcast!(dyn CutPolicy); - -fn cut_body(machine_st: &mut MachineState, addr: &Addr) -> bool { +fn cut_body(machine_st: &mut MachineState, addr: HeapCellValue) -> bool { let b = machine_st.b; - match addr { - &Addr::CutPoint(b0) | &Addr::Usize(b0) => { + read_heap_cell!(addr, + (HeapCellValueTag::Fixnum, b0) => { + let b0 = b0.get_num() as usize; + if b > b0 { machine_st.b = b0; } @@ -1426,7 +1383,7 @@ fn cut_body(machine_st: &mut MachineState, addr: &Addr) -> bool { machine_st.fail = true; return true; } - }; + ); false } @@ -1436,20 +1393,20 @@ pub(crate) struct DefaultCutPolicy {} pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) { let addr = machine_st.store(machine_st.deref(machine_st[r])); - cut_body(machine_st, &addr); + cut_body(machine_st, addr); } impl CutPolicy for DefaultCutPolicy { fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool { let addr = machine_st[r]; - cut_body(machine_st, &addr) + cut_body(machine_st, addr) } } #[derive(Debug)] pub(crate) struct SCCCutPolicy { // locations of cleaners, cut points, the previous block - cont_pts: Vec<(Addr, usize, usize)>, + cont_pts: Vec<(HeapCellValue, usize, usize)>, r_c_w_h: usize, r_c_wo_h: usize, } @@ -1467,21 +1424,21 @@ impl SCCCutPolicy { self.cont_pts.is_empty() } - pub(crate) fn push_cont_pt(&mut self, addr: Addr, b: usize, prev_b: usize) { + pub(crate) fn push_cont_pt(&mut self, addr: HeapCellValue, b: usize, prev_b: usize) { self.cont_pts.push((addr, b, prev_b)); } - pub(crate) fn pop_cont_pt(&mut self) -> Option<(Addr, usize, usize)> { + pub(crate) fn pop_cont_pt(&mut self) -> Option<(HeapCellValue, usize, usize)> { self.cont_pts.pop() } fn run_cleaners(&self, machine_st: &mut MachineState) -> bool { if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() { if machine_st.b < b_cutoff { - let (idx, arity) = if machine_st.block < prev_block { + let (idx, arity) = if machine_st.block > prev_block { (dir_entry!(self.r_c_w_h), 0) } else { - machine_st[temp_v!(1)] = Addr::Usize(b_cutoff); + machine_st.registers[1] = fixnum_as_cell!(Fixnum::build_with(b_cutoff as i64)); (dir_entry!(self.r_c_wo_h), 1) }; @@ -1503,8 +1460,10 @@ impl CutPolicy for SCCCutPolicy { fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool { let b = machine_st.b; - match machine_st[r] { - Addr::Usize(b0) | Addr::CutPoint(b0) => { + read_heap_cell!(machine_st[r], + (HeapCellValueTag::Fixnum, b0) => { + let b0 = b0.get_num() as usize; + if b > b0 { machine_st.b = b0; } @@ -1513,8 +1472,9 @@ impl CutPolicy for SCCCutPolicy { machine_st.fail = true; return true; } - } + ); self.run_cleaners(machine_st) } } + diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index c4929d2d..8f4dc44d 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1,12 +1,12 @@ -use prolog_parser::ast::*; -use prolog_parser::tabled_rc::*; -use prolog_parser::{clause_name, perm_v, temp_v}; +use crate::arena::*; +use crate::atom_table::*; +use crate::types::*; use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; -use crate::indexing::*; use crate::instructions::*; +use crate::machine::arithmetic_ops::*; use crate::machine::attributed_variables::*; use crate::machine::code_repo::CodeRepo; use crate::machine::copier::*; @@ -18,19 +18,24 @@ use crate::machine::partial_string::*; use crate::machine::stack::*; use crate::machine::streams::*; use crate::machine::INTERRUPT; -use crate::rug::Integer; +use crate::parser::ast::*; +use crate::parser::rug::{Integer, Rational}; + +use crate::try_numeric_result; + use ordered_float::*; -use indexmap::{IndexMap, IndexSet}; +use indexmap::IndexSet; use std::cmp::Ordering; use std::convert::TryFrom; -use std::rc::Rc; impl MachineState { pub(crate) fn new() -> Self { MachineState { - atom_tbl: TabledData::new(Rc::new("".to_owned())), + arena: Arena::new(), + atom_tbl: AtomTable::new(), + pdl: Vec::with_capacity(1024), s: HeapPtr::default(), p: CodePtr::default(), b: 0, @@ -40,10 +45,10 @@ impl MachineState { cp: LocalCodePtr::default(), attr_var_init: AttrVarInitializer::new(0), fail: false, - heap: Heap::new(), + heap: Heap::with_capacity(256 * 256), mode: MachineMode::Write, stack: Stack::new(), - registers: vec![Addr::HeapCell(0); MAX_ARITY + 1], // self.registers[0] is never used. + registers: [heap_loc_as_cell!(0); MAX_ARITY + 1], // self.registers[0] is never used. trail: vec![], tr: 0, hb: 0, @@ -62,36 +67,25 @@ impl MachineState { } #[inline] - pub(crate) fn machine_flags(&self) -> MachineFlags { - self.flags - } - - pub(crate) fn store(&self, addr: Addr) -> Addr { - match addr { - Addr::AttrVar(h) | Addr::HeapCell(h) => self.heap[h].as_addr(h), - Addr::StackCell(fr, sc) => self.stack.index_and_frame(fr)[sc], - Addr::PStrLocation(h, n) => { - if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.heap[h] { - if !pstr.at_end(n) { - Addr::PStrLocation(h, n) - } else if has_tail { - Addr::HeapCell(h + 1) - } else { - Addr::EmptyList - } - } else { - unreachable!() - } + pub(crate) fn store(&self, value: HeapCellValue) -> HeapCellValue { + read_heap_cell!(value, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + self.heap[h] } - addr => addr, - } + (HeapCellValueTag::StackVar, s) => { + self.stack[s] + } + _ => { + value + } + ) } - pub(crate) fn deref(&self, mut addr: Addr) -> Addr { + pub fn deref(&self, mut addr: HeapCellValue) -> HeapCellValue { loop { let value = self.store(addr); - if value.is_ref() && value != addr { + if value.is_var() && value != addr { addr = value; continue; } @@ -100,589 +94,1713 @@ impl MachineState { } } - fn bind_attr_var(&mut self, h: usize, addr: Addr) { - match addr.as_var() { - Some(Ref::HeapCell(hc)) => { - self.heap[hc] = HeapCellValue::Addr(Addr::AttrVar(h)); - self.trail(TrailRef::Ref(Ref::HeapCell(hc))); + pub fn trail(&mut self, r: TrailRef) { + match r { + TrailRef::Ref(r) => { + let h = r.get_value() as usize; + + match r.get_tag() { + RefTag::HeapCell => { + if h < self.hb { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedHeapVar, + h as u64, + )); + + self.tr += 1; + } + } + RefTag::StackCell => { + if h < self.b { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedStackVar, + h as u64, + )); + + self.tr += 1; + } + } + RefTag::AttrVar => { + if h < self.hb { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedAttrVar, + h as u64, + )); + + self.tr += 1; + } + } + } } - Some(Ref::StackCell(fr, sc)) => { - self.stack.index_and_frame_mut(fr)[sc] = Addr::AttrVar(h); - self.trail(TrailRef::Ref(Ref::StackCell(fr, sc))); + TrailRef::AttrVarHeapLink(h) => { + if h < self.hb { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedAttrVarHeapLink, + h as u64, + )); + + self.tr += 1; + } } - _ => { - self.push_attr_var_binding(h, addr); - self.heap[h] = HeapCellValue::Addr(addr); - self.trail(TrailRef::Ref(Ref::AttrVar(h))); + TrailRef::AttrVarListLink(h, l) => { + if h < self.hb { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedAttrVarListLink, + h as u64, + )); + + self.trail.push(TrailEntry::from_bytes( + list_loc_as_cell!(l).into_bytes() + )); + + self.tr += 2; + } + } + TrailRef::BlackboardEntry(key_atom) => { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedBlackboardEntry, + key_atom.index as u64, + )); + + self.tr += 1; + } + TrailRef::BlackboardOffset(key_atom, value_cell) => { + self.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedBlackboardOffset, + key_atom.index as u64, + )); + + self.trail.push(TrailEntry::from_bytes( + value_cell.into_bytes(), + )); + + self.tr += 2; } } } - pub(super) fn bind(&mut self, r1: Ref, a2: Addr) { - let t1 = self.store(r1.as_addr()); + pub fn allocate(&mut self, num_cells: usize) { + let e = self.stack.allocate_and_frame(num_cells); + let and_frame = self.stack.index_and_frame_mut(e); + + and_frame.prelude.e = self.e; + and_frame.prelude.cp = self.cp; + + self.e = e; + self.p += 1; + } + + pub fn bind(&mut self, r1: Ref, a2: HeapCellValue) { + let t1 = self.store(r1.as_heap_cell_value()); let t2 = self.store(a2); - if t1.is_ref() && (!t2.is_ref() || a2 < r1) { - match r1 { - Ref::StackCell(fr, sc) => { - self.stack.index_and_frame_mut(fr)[sc] = t2; + if t1.is_var() && (!t2.is_var() || a2 < r1) { + match r1.get_tag() { + RefTag::StackCell => { + self.stack[r1.get_value() as usize] = t2; } - Ref::HeapCell(h) => { - self.heap[h] = HeapCellValue::Addr(t2); - } - Ref::AttrVar(h) => { - return self.bind_attr_var(h, t2); + RefTag::HeapCell => { + self.heap[r1.get_value() as usize] = t2; } + RefTag::AttrVar => { + self.bind_attr_var(r1.get_value() as usize, t2); + } }; - self.trail(TrailRef::from(r1)); + self.trail(TrailRef::Ref(r1)); } else { - match a2.as_var() { - Some(Ref::StackCell(fr, sc)) => { - self.stack.index_and_frame_mut(fr)[sc] = t1; - self.trail(TrailRef::Ref(Ref::StackCell(fr, sc))); + read_heap_cell!(a2, + (HeapCellValueTag::StackVar, s) => { + self.stack[s] = t1; + self.trail(TrailRef::Ref(Ref::stack_cell(s))); } - Some(Ref::HeapCell(h)) => { - self.heap[h] = HeapCellValue::Addr(t1); - self.trail(TrailRef::Ref(Ref::HeapCell(h))); + (HeapCellValueTag::Var, h) => { + self.heap[h] = t1; + self.trail(TrailRef::Ref(Ref::heap_cell(h))); } - Some(Ref::AttrVar(h)) => { + (HeapCellValueTag::AttrVar, h) => { self.bind_attr_var(h, t1); } - None => {} - } - } - } - - #[inline] - pub(super) fn bind_with_occurs_check_with_error_wrapper(&mut self, r: Ref, addr: Addr) { - if self.bind_with_occurs_check(r, addr) { - let err = self.representation_error( - RepFlag::Term, - clause_name!("unify_with_occurs_check"), - 2, + _ => { + unreachable!(); + } ); - - self.throw_exception(err); } } - #[inline] - pub(super) fn bind_with_occurs_check_wrapper(&mut self, r: Ref, addr: Addr) { - self.bind_with_occurs_check(r, addr); + pub fn bind_attr_var(&mut self, h: usize, addr: HeapCellValue) { + read_heap_cell!(addr, + (HeapCellValueTag::Var, hc) => { + self.heap[hc] = attr_var_as_cell!(h); + self.trail(TrailRef::Ref(Ref::heap_cell(hc))); + } + (HeapCellValueTag::StackVar, hc) => { + self.stack[hc] = attr_var_as_cell!(h); + self.trail(TrailRef::Ref(Ref::stack_cell(hc))); + } + _ => { + self.push_attr_var_binding(h, addr); + self.heap[h] = addr; + self.trail(TrailRef::Ref(Ref::attr_var(h))); + } + ) } - #[inline] - pub(super) fn bind_with_occurs_check(&mut self, r: Ref, addr: Addr) -> bool { - if let Ref::StackCell(..) = r { - // local variable optimization -- r cannot occur in the - // data structure bound to addr, so don't bother - // traversing it. - self.bind(r, addr); - return false; - } + fn unify_structure(&mut self, s1: usize, value: HeapCellValue) { + // s1 is the value of a STR cell. + let (n1, a1) = cell_as_atom_cell!(self.heap[s1]).get_name_and_arity(); - let mut occurs_triggered = false; + read_heap_cell!(value, + (HeapCellValueTag::Str, s2) => { + let (n2, a2) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); - for addr in self.acyclic_pre_order_iter(addr) { - if let Some(inner_r) = addr.as_var() { - if r == inner_r { - occurs_triggered = true; - break; + if n1 == n2 && a1 == a2 { + for idx in 0..a1 { + self.pdl.push(heap_loc_as_cell!(s2+1+idx)); + self.pdl.push(heap_loc_as_cell!(s1+1+idx)); + } + } else { + self.fail = true; } } - } - - self.fail = occurs_triggered; - self.bind(r, addr); - - return occurs_triggered; + (HeapCellValueTag::Lis, l2) => { + if a1 == 2 && n1 == atom!(".") { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(l2+1+idx)); + self.pdl.push(heap_loc_as_cell!(s1+1+idx)); + } + } else { + self.fail = true; + } + } + (HeapCellValueTag::Atom, (n2, a2)) => { + if !(a1 == 0 && a2 == 0 && n1 == n2) { + self.fail = true; + } + } + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), str_loc_as_cell!(s1)); + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), str_loc_as_cell!(s1)); + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), str_loc_as_cell!(s1)); + } + _ => { + self.fail = true; + } + ) } - pub(super) fn unify_with_occurs_check_with_error(&mut self, a1: Addr, a2: Addr) { - let mut throw_error = false; - self.unify_with_occurs_check_loop(a1, a2, || throw_error = true); + fn unify_list(&mut self, l1: usize, d2: HeapCellValue) { + read_heap_cell!(d2, + (HeapCellValueTag::Lis, l2) => { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(l2 + idx)); + self.pdl.push(heap_loc_as_cell!(l1 + idx)); + } + } + (HeapCellValueTag::Str, s2) => { + let (n2, a2) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); - if throw_error { - let err = self.representation_error( - RepFlag::Term, - clause_name!("unify_with_occurs_check"), - 2, - ); + if a2 == 2 && n2 == atom!(".") { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(s2+1+idx)); + self.pdl.push(heap_loc_as_cell!(l1+idx)); + } + } else { + self.fail = true; + } + } + (HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => { + self.unify_partial_string(list_loc_as_cell!(l1), d2) + } + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), list_loc_as_cell!(l1)); + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), list_loc_as_cell!(l1)); + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), list_loc_as_cell!(l1)); + } + _ => { + self.fail = true; + } + ) + } - self.throw_exception(err); + pub fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) { + if let Some(r) = value.as_var() { + self.bind(r, atom_as_cstr_cell!(atom)); + return; } - } - pub(super) fn unify_with_occurs_check(&mut self, a1: Addr, a2: Addr) { - self.unify_with_occurs_check_loop(a1, a2, || {}) + read_heap_cell!(value, + (HeapCellValueTag::CStr, cstr_atom) => { + self.fail = atom != cstr_atom; + } + _ => { + self.fail = true; + } + ); } - pub(super) fn unify_with_occurs_check_loop( - &mut self, - a1: Addr, - a2: Addr, - mut occurs_trigger: impl FnMut(), - ) { - let mut pdl = vec![a1, a2]; - let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new(); + // d1's tag is LIS, STR or PSTRLOC. + pub fn unify_partial_string(&mut self, d1: HeapCellValue, d2: HeapCellValue) { + if let Some(r) = d2.as_var() { + self.bind(r, d1); + return; + } - self.fail = false; + let s1 = self.heap.len(); - while !(pdl.is_empty() || self.fail) { - let d1 = self.deref(pdl.pop().unwrap()); - let d2 = self.deref(pdl.pop().unwrap()); + self.heap.push(d1); + self.heap.push(d2); - if d1 != d2 { - let d1 = self.store(d1); - let d2 = self.store(d2); + let mut pstr_iter1 = HeapPStrIter::new(&self.heap, s1); + let mut pstr_iter2 = HeapPStrIter::new(&self.heap, s1 + 1); - if tabu_list.contains(&(d1, d2)) { - continue; - } else { - tabu_list.insert((d1, d2)); + match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { + PStrCmpResult::Ordered(Ordering::Equal) => {} + PStrCmpResult::Ordered(Ordering::Less) => { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter2.focus); + } + PStrCmpResult::Ordered(Ordering::Greater) => { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter1.focus); + } + continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | + continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { + if continuable.is_second_iter() { + std::mem::swap(&mut pstr_iter1, &mut pstr_iter2); } - match (d1, d2) { - (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => { - if self.bind_with_occurs_check(Ref::AttrVar(h), addr) { - occurs_trigger(); - } - } - (Addr::HeapCell(h), addr) | (addr, Addr::HeapCell(h)) => { - if self.bind_with_occurs_check(Ref::HeapCell(h), addr) { - occurs_trigger(); - } - } - (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => { - if self.bind_with_occurs_check(Ref::StackCell(fr, sc), addr) { - occurs_trigger(); - } - } - (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => { - if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] { - if f2.as_str() == "." && n2 == 2 { - pdl.push(Addr::HeapCell(a1)); - pdl.push(Addr::HeapCell(a2 + 1)); + let mut chars_iter = PStrCharsIter { + iter: pstr_iter1, + item: Some(iteratee), + }; - pdl.push(Addr::HeapCell(a1 + 1)); - pdl.push(Addr::HeapCell(a2 + 2)); + let mut focus = pstr_iter2.focus; - continue; - } - } + 'outer: loop { + while let Some(c) = chars_iter.peek() { + read_heap_cell!(focus, + (HeapCellValueTag::Lis, l) => { + let val = pstr_iter2.heap[l]; - self.fail = true; - } - (Addr::PStrLocation(h, n), Addr::Lis(l)) - | (Addr::Lis(l), Addr::PStrLocation(h, n)) => { - if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] { - if let Some(c) = pstr.range_from(n..).next() { - pdl.push(Addr::PStrLocation(h, n + c.len_utf8())); - pdl.push(Addr::HeapCell(l + 1)); + self.pdl.push(val); + self.pdl.push(char_as_cell!(c)); - pdl.push(Addr::Char(c)); - pdl.push(Addr::HeapCell(l)); - } else { - unreachable!() + focus = pstr_iter2.heap[l+1]; } - } else { - unreachable!() - } - } - (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => { - if let &HeapCellValue::PartialString(ref pstr1, has_tail_1) = &self.heap[h1] - { - if let &HeapCellValue::PartialString(ref pstr2, has_tail_2) = - &self.heap[h2] - { - let pstr1_s = pstr1.as_str_from(n1); - let pstr2_s = pstr2.as_str_from(n2); - - let m_len = if pstr1_s.starts_with(pstr2_s) { - pstr2_s.len() - } else if pstr2_s.starts_with(pstr1_s) { - pstr1_s.len() - } else { - self.fail = true; - return; - }; + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s]) + .get_name_and_arity(); - if pstr1.at_end(n1 + m_len) { - if has_tail_1 { - pdl.push(Addr::HeapCell(h1 + 1)); - } else { - pdl.push(Addr::EmptyList); - } + if name == atom!(".") && arity == 2 { + self.pdl.push(pstr_iter2.heap[s+1]); + self.pdl.push(char_as_cell!(c)); - if pstr2.at_end(n2 + m_len) { - if has_tail_2 { - pdl.push(Addr::HeapCell(h2 + 1)); - } else { - pdl.push(Addr::EmptyList); - } - } else { - pdl.push(Addr::PStrLocation(h2, n2 + m_len)); - } + focus = pstr_iter2.heap[s+2]; } else { - pdl.push(Addr::PStrLocation(h1, n1 + m_len)); - - if pstr2.at_end(n2 + m_len) { - if has_tail_2 { - pdl.push(Addr::HeapCell(h2 + 1)); - } else { - pdl.push(Addr::EmptyList); - } - } else { - pdl.push(Addr::PStrLocation(h2, n2 + m_len)); - } + self.fail = true; + break 'outer; } - } else { - unreachable!() } - } else { - unreachable!() - } - } - (Addr::Lis(a1), Addr::Lis(a2)) => { - pdl.push(Addr::HeapCell(a1)); - pdl.push(Addr::HeapCell(a2)); - - pdl.push(Addr::HeapCell(a1 + 1)); - pdl.push(Addr::HeapCell(a2 + 1)); - } - (Addr::Str(a1), Addr::Str(a2)) => { - let r1 = &self.heap[a1]; - let r2 = &self.heap[a2]; - - if let &HeapCellValue::NamedStr(n1, ref f1, _) = r1 { - if let &HeapCellValue::NamedStr(n2, ref f2, _) = r2 { - if n1 == n2 && *f1 == *f2 { - for i in 1..n1 + 1 { - pdl.push(Addr::HeapCell(a1 + i)); - pdl.push(Addr::HeapCell(a2 + i)); + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + match chars_iter.item.unwrap() { + PStrIteratee::Char(focus, _) => { + self.pdl.push(self.heap[focus]); + self.pdl.push(heap_loc_as_cell!(h)); } + PStrIteratee::PStrSegment(focus, _, n) => { + read_heap_cell!(self.heap[focus], + (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => { + if focus < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } + + if n == 0 { + let target_cell = match self.heap[focus].get_tag() { + HeapCellValueTag::CStr => { + atom_as_cstr_cell!(pstr_atom) + } + HeapCellValueTag::PStr => { + pstr_loc_as_cell!(focus) + } + _ => { + unreachable!() + } + }; + + self.pdl.push(target_cell); + self.pdl.push(heap_loc_as_cell!(h)); + } else { + let h_len = self.heap.len(); + + self.heap.push(pstr_offset_as_cell!(focus)); + self.heap.push(fixnum_as_cell!( + Fixnum::build_with(n as i64) + )); + + self.pdl.push(pstr_loc_as_cell!(h_len)); + self.pdl.push(heap_loc_as_cell!(h)); + } + + return; + } + (HeapCellValueTag::PStrOffset, pstr_loc) => { + let n0 = cell_as_fixnum!(self.heap[focus+1]) + .get_num() as usize; + + if pstr_loc < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } + + if n == n0 { + self.pdl.push(pstr_loc_as_cell!(focus)); + self.pdl.push(heap_loc_as_cell!(h)); + } else { + let h_len = self.heap.len(); + + self.heap.push(pstr_offset_as_cell!(pstr_loc)); + self.heap.push(fixnum_as_cell!( + Fixnum::build_with(n as i64) + )); + + self.pdl.push(pstr_loc_as_cell!(h_len)); + self.pdl.push(heap_loc_as_cell!(h)); + } + + return; + } + _ => { + } + ); - continue; - } - } - } + if focus < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } - self.fail = true; - } - (Addr::Con(c1), Addr::Con(c2)) => match (&self.heap[c1], &self.heap[c2]) { - (&HeapCellValue::Atom(ref n1, _), &HeapCellValue::Atom(ref n2, _)) - if n1.as_str() == n2.as_str() => {} - ( - &HeapCellValue::DBRef(ref db_ref_1), - &HeapCellValue::DBRef(ref db_ref_2), - ) if db_ref_1 == db_ref_2 => {} - (v1, v2) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 == n2 { - continue; + self.pdl.push(self.heap[focus]); + self.pdl.push(heap_loc_as_cell!(h)); + + return; } } - } - self.fail = true; - } - }, - (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => { - match &self.heap[h] { - &HeapCellValue::Atom(ref name, _) if name.is_char() => { - if name.as_str().chars().next() != Some(c) { - self.fail = true; - return; - } + break 'outer; } _ => { self.fail = true; - return; - } - } - } - (Addr::Stream(s1), Addr::Stream(s2)) => { - if s1 != s2 { - self.fail = true; - } - } - (v, Addr::Con(h)) | (Addr::Con(h), v) => { - if let Ok(n1) = Number::try_from(&self.heap[h]) { - if let Ok(v) = Number::try_from(&HeapCellValue::Addr(v)) { - if n1 == v { - continue; - } - } - } - - self.fail = true; - } - (a1, a2) => { - if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(a1)) { - if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(a2)) { - if n1 == n2 { - continue; - } + break 'outer; } - } + ); - if a1 != a2 { - self.fail = true; - } + chars_iter.next(); } - }; - } - } - } - - pub(super) fn unify(&mut self, a1: Addr, a2: Addr) { - let mut pdl = vec![a1, a2]; - let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new(); + chars_iter.iter.next(); - self.fail = false; + self.pdl.push(chars_iter.iter.focus); + self.pdl.push(focus); - while !(pdl.is_empty() || self.fail) { - let d1 = self.deref(pdl.pop().unwrap()); - let d2 = self.deref(pdl.pop().unwrap()); + break; + } + } + PStrCmpResult::Unordered => { + self.pdl.push(pstr_iter1.focus); + self.pdl.push(pstr_iter2.focus); + } + } - if d1 != d2 { - let d1 = self.store(d1); - let d2 = self.store(d2); + self.heap.pop(); + self.heap.pop(); + } - if tabu_list.contains(&(d1, d2)) { - continue; + pub fn unify_atom(&mut self, atom: Atom, value: HeapCellValue) { + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + self.fail = !(arity == 0 && name == atom); + } + (HeapCellValueTag::Char, c1) => { + if let Some(c2) = atom.as_char() { + self.fail = c1 != c2; } else { - tabu_list.insert((d1, d2)); + self.fail = true; } + } + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), atom_as_cell!(atom)); + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), atom_as_cell!(atom)); + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), atom_as_cell!(atom)); + } + _ => { + self.fail = true; + } + ); + } - match (d1, d2) { - (Addr::AttrVar(h), addr) | (addr, Addr::AttrVar(h)) => { - self.bind(Ref::AttrVar(h), addr); - } - (Addr::HeapCell(h), addr) | (addr, Addr::HeapCell(h)) => { - self.bind(Ref::HeapCell(h), addr); - } - (Addr::StackCell(fr, sc), addr) | (addr, Addr::StackCell(fr, sc)) => { - self.bind(Ref::StackCell(fr, sc), addr); - } - (Addr::Lis(a1), Addr::Str(a2)) | (Addr::Str(a2), Addr::Lis(a1)) => { - if let &HeapCellValue::NamedStr(n2, ref f2, _) = &self.heap[a2] { - if f2.as_str() == "." && n2 == 2 { - pdl.push(Addr::HeapCell(a1)); - pdl.push(Addr::HeapCell(a2 + 1)); - - pdl.push(Addr::HeapCell(a1 + 1)); - pdl.push(Addr::HeapCell(a2 + 2)); + pub fn unify_char(&mut self, c: char, value: HeapCellValue) { + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, arity)) => { + if let Some(c2) = name.as_char() { + self.fail = !(c == c2 && arity == 0); + } else { + self.fail = true; + } + } + (HeapCellValueTag::Char, c2) => { + if c != c2 { + self.fail = true; + } + } + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), char_as_cell!(c)); + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), char_as_cell!(c)); + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), char_as_cell!(c)); + } + _ => { + self.fail = true; + } + ); + } - continue; - } - } + pub fn unify_fixnum(&mut self, n1: Fixnum, value: HeapCellValue) { + if let Some(r) = value.as_var() { + self.bind(r, fixnum_as_cell!(n1)); + return; + } - self.fail = true; + match Number::try_from(value) { + Ok(n2) => match n2 { + Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {} + Number::Integer(n2) if n1.get_num() == *n2 => {} + Number::Rational(n2) if n1.get_num() == *n2 => {} + _ => { + self.fail = true; + } + }, + Err(_) => { + self.fail = true; + } + } + } + + pub fn unify_big_int(&mut self, n1: TypedArenaPtr, value: HeapCellValue) { + if let Some(r) = value.as_var() { + self.bind(r, typed_arena_ptr_as_cell!(n1)); + return; + } + + match Number::try_from(value) { + Ok(n2) => match n2 { + Number::Fixnum(n2) if *n1 == n2.get_num() => {} + Number::Integer(n2) if *n1 == *n2 => {} + Number::Rational(n2) if *n1 == *n2 => {} + _ => { + self.fail = true; + } + }, + Err(_) => { + self.fail = true; + } + } + } + + pub fn unify_rational(&mut self, n1: TypedArenaPtr, value: HeapCellValue) { + if let Some(r) = value.as_var() { + self.bind(r, typed_arena_ptr_as_cell!(n1)); + return; + } + + match Number::try_from(value) { + Ok(n2) => match n2 { + Number::Fixnum(n2) if *n1 == n2.get_num() => {} + Number::Integer(n2) if *n1 == *n2 => {} + Number::Rational(n2) if *n1 == *n2 => {} + _ => { + self.fail = true; + } + }, + Err(_) => { + self.fail = true; + } + } + } + + pub fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) { + if let Some(r) = value.as_var() { + self.bind(r, typed_arena_ptr_as_cell!(f1)); + return; + } + + read_heap_cell!(value, + (HeapCellValueTag::F64, f2) => { + if *f1 != *f2 { + self.fail = true; + } + } + _ => { + self.fail = true; + } + ); + } + + pub fn unify_constant(&mut self, ptr: UntypedArenaPtr, value: HeapCellValue) { + if let Some(ptr2) = value.to_untyped_arena_ptr() { + if ptr.get_ptr() == ptr2.get_ptr() { + return; + } + } + + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Integer, int_ptr) => { + self.unify_big_int(int_ptr, value); + } + (ArenaHeaderTag::Rational, rat_ptr) => { + self.unify_rational(rat_ptr, value); + } + _ => { + if let Some(r) = value.as_var() { + self.bind(r, untyped_arena_ptr_as_cell!(ptr)); + } else { + self.fail = true; + } + } + ); + } + + pub fn unify(&mut self) { + let mut tabu_list: IndexSet<(usize, usize)> = IndexSet::new(); + // self.fail = false; + + while !(self.pdl.is_empty() || self.fail) { + let s1 = self.pdl.pop().unwrap(); + let s1 = self.deref(s1); + + let s2 = self.pdl.pop().unwrap(); + let s2 = self.deref(s2); + + if s1 != s2 { + let d1 = self.store(s1); + let d2 = self.store(s2); + + read_heap_cell!(d1, + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), d2); + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), d2); + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), d2); + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert!(arity == 0); + self.unify_atom(name, d2); + } + (HeapCellValueTag::Str, s1) => { + if d2.is_constant() { + self.fail = true; + break; + } + + let s2 = s2.get_value() as usize; + + if tabu_list.contains(&(s1, s2)) { + continue; + } + + self.unify_structure(s1, d2); + + if !self.fail { + tabu_list.insert((s1, s2)); + } + } + (HeapCellValueTag::Lis, l1) => { + if d2.is_ref() { + let l2 = s2.get_value(); + + if tabu_list.contains(&(l1, l2)) { + continue; + } + + tabu_list.insert((l1, l2)); + } + + self.unify_list(l1, d2); + } + (HeapCellValueTag::PStrLoc, pstr1_loc) => { + read_heap_cell!(d2, + (HeapCellValueTag::PStrLoc | + HeapCellValueTag::Lis | + HeapCellValueTag::Str, + pstr2_loc) => { + if tabu_list.contains(&(pstr1_loc, pstr2_loc)) { + continue; + } + } + (HeapCellValueTag::CStr | + HeapCellValueTag::AttrVar | + HeapCellValueTag::Var | + HeapCellValueTag::StackVar) => { + } + _ => { + self.fail = true; + break; + } + ); + + self.unify_partial_string(d1, d2); + + if !self.fail && !d2.is_constant() { + tabu_list.insert((pstr1_loc, d2.get_value())); + } + } + (HeapCellValueTag::CStr) => { + read_heap_cell!(d2, + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), d1); + continue; + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), d1); + continue; + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), d1); + continue; + } + (HeapCellValueTag::Str | + HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc) => { + } + (HeapCellValueTag::CStr) => { + self.fail = d1 != d2; + continue; + } + _ => { + self.fail = true; + return; + } + ); + + self.unify_partial_string(d2, d1); + } + (HeapCellValueTag::F64, f1) => { + self.unify_f64(f1, d2); + } + (HeapCellValueTag::Fixnum, n1) => { + self.unify_fixnum(n1, d2); + } + (HeapCellValueTag::Char, c1) => { + self.unify_char(c1, d2); + } + (HeapCellValueTag::Cons, ptr_1) => { + self.unify_constant(ptr_1, d2); + } + _ => { + unreachable!(); + } + ); + } + } + } + + pub(super) fn set_ball(&mut self) { + self.ball.reset(); + + let addr = self.registers[1]; + self.ball.boundary = self.heap.len(); + + copy_term( + CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.ball.stub), + addr, + AttrVarPolicy::DeepCopy, + ); + } + + pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { + let old_h = self.heap.len(); + + let a1 = self.registers[1]; + let a2 = self.registers[2]; + + copy_term(CopyTerm::new(self), a1, attr_var_policy); + + unify_fn!(self, heap_loc_as_cell!(old_h), a2); + } + + pub(super) fn unwind_stack(&mut self) { + self.b = self.block; + self.fail = true; + } + + #[inline] + pub fn bind_with_occurs_check(&mut self, r: Ref, value: HeapCellValue) -> bool { + if let RefTag::StackCell = r.get_tag() { + // local variable optimization -- r cannot occur in the + // heap structure bound to value, so don't bother + // traversing value. + self.bind(r, value); + return false; + } + + let mut occurs_triggered = false; + + if !value.is_constant() { + for addr in stackful_preorder_iter(&mut self.heap, value) { + if let Some(inner_r) = addr.as_var() { + if r == inner_r { + occurs_triggered = true; + break; + } + } + } + } + + if occurs_triggered { + self.fail = true; + } else { + self.bind(r, value); + } + + return occurs_triggered; + } + + #[inline] + pub(super) fn bind_with_occurs_check_wrapper(&mut self, r: Ref, value: HeapCellValue) { + self.bind_with_occurs_check(r, value); + } + + #[inline] + pub(super) fn bind_with_occurs_check_with_error_wrapper( + &mut self, + r: Ref, + value: HeapCellValue, + ) { + if self.bind_with_occurs_check(r, value) { + let err = self.representation_error(RepFlag::Term); + let stub = functor_stub(atom!("unify_with_occurs_check"), 2); + let err = self.error_form(err, stub); + + self.throw_exception(err); + } + } + + pub(super) fn unify_with_occurs_check_with_error(&mut self) { + let mut throw_error = false; + self.unify_with_occurs_check_loop(|| throw_error = true); + + if throw_error { + let err = self.representation_error(RepFlag::Term); + let stub = functor_stub(atom!("unify_with_occurs_check"), 2); + let err = self.error_form(err, stub); + + self.throw_exception(err); + } + } + + pub(super) fn unify_with_occurs_check(&mut self) { + self.unify_with_occurs_check_loop(|| {}) + } + + fn unify_structure_with_occurs_check( + &mut self, + s1: usize, + value: HeapCellValue, + mut occurs_trigger: impl FnMut(), + ) { + // s1 is the value of a STR cell. + let (n1, a1) = cell_as_atom_cell!(self.heap[s1]).get_name_and_arity(); + + read_heap_cell!(value, + (HeapCellValueTag::Str, s2) => { + let (n2, a2) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); + + if n1 == n2 && a1 == a2 { + for idx in 0..a1 { + self.pdl.push(heap_loc_as_cell!(s2+1+idx)); + self.pdl.push(heap_loc_as_cell!(s1+1+idx)); + } + } else { + self.fail = true; + } + } + (HeapCellValueTag::Lis, l2) => { + if a1 == 2 && n1 == atom!(".") { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(l2+idx)); + self.pdl.push(heap_loc_as_cell!(s1+1+idx)); + } + } else { + self.fail = true; + } + } + (HeapCellValueTag::Atom, (n2, a2)) => { + if !(a1 == 0 && a2 == 0 && n1 == n2) { + self.fail = true; + } + } + (HeapCellValueTag::AttrVar, h) => { + if self.bind_with_occurs_check(Ref::attr_var(h), str_loc_as_cell!(s1)) { + occurs_trigger(); + } + } + (HeapCellValueTag::Var, h) => { + if self.bind_with_occurs_check(Ref::heap_cell(h), str_loc_as_cell!(s1)) { + occurs_trigger(); + } + } + (HeapCellValueTag::StackVar, s) => { + if self.bind_with_occurs_check(Ref::stack_cell(s), str_loc_as_cell!(s1)) { + occurs_trigger(); + } + } + _ => { + self.fail = true; + } + ) + } + + // the return value of unify_partial_string_with_occurs_check is + // interpreted as follows: + // + // Some(None) -- the strings are equal, nothing to unify + // Some(Some(f2,f1)) -- prefixes equal, try to unify focus values f2, f1 + // None -- prefixes not equal, unification fails + // + // d1's tag is assumed to be one of LIS, STR or PSTRLOC. + pub fn unify_partial_string_with_occurs_check( + &mut self, + d1: HeapCellValue, + d2: HeapCellValue, + mut occurs_trigger: impl FnMut(), + ) { + if let Some(r) = d2.as_var() { + if self.bind_with_occurs_check(r, d1) { + occurs_trigger(); + } + + return; + } + + let s1 = self.heap.len(); + + self.heap.push(d1); + self.heap.push(d2); + + let mut pstr_iter1 = HeapPStrIter::new(&self.heap, s1); + let mut pstr_iter2 = HeapPStrIter::new(&self.heap, s1 + 1); + + match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { + PStrCmpResult::Ordered(Ordering::Equal) => {} + PStrCmpResult::Ordered(Ordering::Less) => { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter2.focus); + } + PStrCmpResult::Ordered(Ordering::Greater) => { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter1.focus); + } + continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | + continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { + if continuable.is_second_iter() { + std::mem::swap(&mut pstr_iter1, &mut pstr_iter2); + } + + let mut chars_iter = PStrCharsIter { + iter: pstr_iter1, + item: Some(iteratee), + }; + + let mut focus = pstr_iter2.focus; + + 'outer: loop { + while let Some(c) = chars_iter.peek() { + read_heap_cell!(focus, + (HeapCellValueTag::Lis, l) => { + let val = pstr_iter2.heap[l]; + + self.pdl.push(val); + self.pdl.push(char_as_cell!(c)); + + focus = pstr_iter2.heap[l+1]; + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s]) + .get_name_and_arity(); + + if name == atom!(".") && arity == 2 { + self.pdl.push(pstr_iter2.heap[s+1]); + self.pdl.push(char_as_cell!(c)); + + focus = pstr_iter2.heap[s+2]; + } else { + self.fail = true; + break 'outer; + } + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + match chars_iter.item.unwrap() { + PStrIteratee::Char(focus, _) => { + self.pdl.push(self.heap[focus]); + self.pdl.push(heap_loc_as_cell!(h)); + } + PStrIteratee::PStrSegment(focus, _, n) => { + read_heap_cell!(self.heap[focus], + (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => { + if focus < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } + + if n == 0 { + let target_cell = match self.heap[focus].get_tag() { + HeapCellValueTag::CStr => { + atom_as_cstr_cell!(pstr_atom) + } + HeapCellValueTag::PStr => { + pstr_loc_as_cell!(focus) + } + _ => { + unreachable!() + } + }; + + self.pdl.push(target_cell); + self.pdl.push(heap_loc_as_cell!(h)); + } else { + let h_len = self.heap.len(); + + self.heap.push(pstr_offset_as_cell!(focus)); + self.heap.push(fixnum_as_cell!( + Fixnum::build_with(n as i64) + )); + + self.pdl.push(pstr_loc_as_cell!(h_len)); + self.pdl.push(heap_loc_as_cell!(h)); + } + + return; + } + (HeapCellValueTag::PStrOffset, pstr_loc) => { + let n0 = cell_as_fixnum!(self.heap[focus+1]) + .get_num() as usize; + + if pstr_loc < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } + + if n == n0 { + self.pdl.push(pstr_loc_as_cell!(focus)); + self.pdl.push(heap_loc_as_cell!(h)); + } else { + let h_len = self.heap.len(); + + self.heap.push(pstr_offset_as_cell!(pstr_loc)); + self.heap.push(fixnum_as_cell!( + Fixnum::build_with(n as i64) + )); + + self.pdl.push(pstr_loc_as_cell!(h_len)); + self.pdl.push(heap_loc_as_cell!(h)); + } + + return; + } + _ => { + } + ); + + if focus < self.heap.len() - 2 { + self.heap.pop(); + self.heap.pop(); + } + + self.pdl.push(self.heap[focus]); + self.pdl.push(heap_loc_as_cell!(h)); + + return; + } + } + + break 'outer; + } + _ => { + self.fail = true; + break 'outer; + } + ); + + chars_iter.next(); + } + + chars_iter.iter.next(); + + self.pdl.push(chars_iter.iter.focus); + self.pdl.push(focus); + + break; + } + } + PStrCmpResult::Unordered => { + self.pdl.push(pstr_iter1.focus); + self.pdl.push(pstr_iter2.focus); + } + } + + self.heap.pop(); + self.heap.pop(); + } + + fn unify_list_with_occurs_trigger( + &mut self, + l1: usize, + d2: HeapCellValue, + mut occurs_trigger: impl FnMut(), + ) { + read_heap_cell!(d2, + (HeapCellValueTag::Lis, l2) => { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(l2+idx)); + self.pdl.push(heap_loc_as_cell!(l1+idx)); + } + } + (HeapCellValueTag::Str, s2) => { + let (n2, a2) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); + + if a2 == 2 && n2 == atom!(".") { + for idx in 0..2 { + self.pdl.push(heap_loc_as_cell!(s2+1+idx)); + self.pdl.push(heap_loc_as_cell!(l1+idx)); } - (Addr::PStrLocation(h, n), Addr::Lis(l)) - | (Addr::Lis(l), Addr::PStrLocation(h, n)) => { - if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] { - if let Some(c) = pstr.range_from(n..).next() { - pdl.push(Addr::PStrLocation(h, n + c.len_utf8())); - pdl.push(Addr::HeapCell(l + 1)); + } else { + self.fail = true; + } + } + (HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => { + self.unify_partial_string_with_occurs_check( + list_loc_as_cell!(l1), + d2, + &mut occurs_trigger, + ) + } + (HeapCellValueTag::AttrVar, h) => { + if self.bind_with_occurs_check(Ref::attr_var(h), list_loc_as_cell!(l1)) { + occurs_trigger(); + } + } + (HeapCellValueTag::Var, h) => { + if self.bind_with_occurs_check(Ref::heap_cell(h), list_loc_as_cell!(l1)) { + occurs_trigger(); + } + } + (HeapCellValueTag::StackVar, s) => { + if self.bind_with_occurs_check(Ref::stack_cell(s), list_loc_as_cell!(l1)) { + occurs_trigger(); + } + } + _ => { + self.fail = true; + } + ) + } - pdl.push(Addr::Char(c)); - pdl.push(Addr::HeapCell(l)); - } else { - unreachable!() + pub(super) fn unify_with_occurs_check_loop(&mut self, mut occurs_trigger: impl FnMut()) { + let mut tabu_list: IndexSet<(usize, usize)> = IndexSet::new(); + + // self.fail = false; + + while !(self.pdl.is_empty() || self.fail) { + let s1 = self.pdl.pop().unwrap(); + let s1 = self.deref(s1); + + let s2 = self.pdl.pop().unwrap(); + let s2 = self.deref(s2); + + if s1 != s2 { + let d1 = self.store(s1); + let d2 = self.store(s2); + + read_heap_cell!(d1, + (HeapCellValueTag::AttrVar, h) => { + if self.bind_with_occurs_check(Ref::attr_var(h), d2) { + occurs_trigger(); + } + } + (HeapCellValueTag::Var, h) => { + if self.bind_with_occurs_check(Ref::heap_cell(h), d2) { + occurs_trigger(); + } + } + (HeapCellValueTag::StackVar, s) => { + if self.bind_with_occurs_check(Ref::stack_cell(s), d2) { + occurs_trigger(); + } + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert!(arity == 0); + self.unify_atom(name, d2); + } + (HeapCellValueTag::Str, s1) => { + if d2.is_constant() { + self.fail = true; + break; + } + + let s2 = s2.get_value() as usize; + + if tabu_list.contains(&(s1, s2)) { + continue; + } + + self.unify_structure_with_occurs_check(s1, d2, &mut occurs_trigger); + + if !self.fail { + tabu_list.insert((s1, s2)); + } + } + (HeapCellValueTag::Lis, l1) => { + if d2.is_ref() { + let l2 = s2.get_value() as usize; + + if tabu_list.contains(&(l1, l2)) { + continue; + } + + tabu_list.insert((l1, l2)); + } + + self.unify_list_with_occurs_trigger(l1, d2, &mut occurs_trigger); + } + (HeapCellValueTag::PStrLoc, pstr1_loc) => { + read_heap_cell!(d2, + (HeapCellValueTag::PStrLoc | + HeapCellValueTag::Lis | + HeapCellValueTag::Str, + pstr2_loc) => { + if tabu_list.contains(&(pstr1_loc, pstr2_loc)) { + continue; + } + } + (HeapCellValueTag::CStr | + HeapCellValueTag::AttrVar | + HeapCellValueTag::Var | + HeapCellValueTag::StackVar) => { + } + _ => { + self.fail = true; + break; + } + ); + + self.unify_partial_string_with_occurs_check( + d1, + d2, + &mut occurs_trigger, + ); + + if !self.fail && !d2.is_constant() { + tabu_list.insert((pstr1_loc, d2.get_value())); + } + } + (HeapCellValueTag::CStr) => { + read_heap_cell!(d2, + (HeapCellValueTag::AttrVar, h) => { + self.bind(Ref::attr_var(h), d1); + continue; + } + (HeapCellValueTag::Var, h) => { + self.bind(Ref::heap_cell(h), d1); + continue; + } + (HeapCellValueTag::StackVar, s) => { + self.bind(Ref::stack_cell(s), d1); + continue; + } + (HeapCellValueTag::Str | + HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc) => { + } + _ => { + self.fail = true; + return; } + ); + + self.unify_partial_string(d2, d1); + } + (HeapCellValueTag::F64, f1) => { + self.unify_f64(f1, d2); + } + (HeapCellValueTag::Fixnum, n1) => { + self.unify_fixnum(n1, d2); + } + (HeapCellValueTag::Char, c1) => { + self.unify_char(c1, d2); + } + (HeapCellValueTag::Cons, ptr_1) => { + self.unify_constant(ptr_1, d2); + } + _ => { + unreachable!(); + } + ); + } + } + } + + fn read_s(&mut self) -> HeapCellValue { + match &self.s { + &HeapPtr::HeapCell(h) => self.deref(self.heap[h]), + &HeapPtr::PStrChar(h, n) => { + read_heap_cell!(self.heap[h], + (HeapCellValueTag::PStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + + if let Some(c) = pstr.as_str_from(n).chars().next() { + char_as_cell!(c) + } else { // if has_tail { + self.deref(self.heap[h+1]) // heap_loc_as_cell!(h+1) + } + // } else { + // empty_list_as_cell!() + // } + } + (HeapCellValueTag::CStr, cstr_atom) => { + let pstr = PartialString::from(cstr_atom); + + if let Some(c) = pstr.as_str_from(n).chars().next() { + char_as_cell!(c) + } else { // if has_tail { + empty_list_as_cell!() + } + } + _ => { + unreachable!() + } + ) + } + &HeapPtr::PStrLocation(h, n) => { + read_heap_cell!(self.heap[h], + (HeapCellValueTag::PStr, pstr_atom) => { + if n < pstr_atom.len() { + let h_len = self.heap.len(); + + self.heap.push(pstr_offset_as_cell!(h)); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(n as i64))); + + pstr_loc_as_cell!(h_len) } else { - unreachable!() + self.deref(self.heap[h+1]) } } - (Addr::PStrLocation(h1, n1), Addr::PStrLocation(h2, n2)) => { - if let &HeapCellValue::PartialString(ref pstr1, has_tail_1) = &self.heap[h1] - { - if let &HeapCellValue::PartialString(ref pstr2, has_tail_2) = - &self.heap[h2] - { - let pstr1_s = pstr1.as_str_from(n1); - let pstr2_s = pstr2.as_str_from(n2); + (HeapCellValueTag::CStr, cstr_atom) => { + if n < cstr_atom.len() { + let h_len = self.heap.len(); - let m_len = if pstr1_s.starts_with(pstr2_s) { - pstr2_s.len() - } else if pstr2_s.starts_with(pstr1_s) { - pstr1_s.len() - } else { - self.fail = true; - return; - }; + self.heap.push(pstr_offset_as_cell!(h)); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(n as i64))); - if pstr1.at_end(n1 + m_len) { - if has_tail_1 { - pdl.push(Addr::HeapCell(h1 + 1)); - } else { - pdl.push(Addr::EmptyList); - } + pstr_loc_as_cell!(h_len) + } else { + empty_list_as_cell!() + } + } + _ => { + unreachable!() + } + ) + } + } + } + + pub fn compare_term_test(&mut self) -> Option { + let mut tabu_list = IndexSet::new(); + + while !self.pdl.is_empty() { + let s1 = self.pdl.pop().unwrap(); + let s1 = self.deref(s1); + + let s2 = self.pdl.pop().unwrap(); + let s2 = self.deref(s2); + + if s1 == s2 { + continue; + } + + let v1 = self.store(s1); + let v2 = self.store(s2); + + let order_cat_v1 = v1.order_category(); + let order_cat_v2 = v2.order_category(); + + if order_cat_v1 != order_cat_v2 { + self.pdl.clear(); + return Some(order_cat_v1.cmp(&order_cat_v2)); + } - if pstr2.at_end(n2 + m_len) { - if has_tail_2 { - pdl.push(Addr::HeapCell(h2 + 1)); - } else { - pdl.push(Addr::EmptyList); + match order_cat_v1 { + Some(TermOrderCategory::Variable) => { + let v1 = v1.as_var().unwrap(); + let v2 = v2.as_var().unwrap(); + + if v1 != v2 { + self.pdl.clear(); + return Some(v1.cmp(&v2)); + } + } + Some(TermOrderCategory::FloatingPoint) => { + let v1 = cell_as_f64_ptr!(v1); + let v2 = cell_as_f64_ptr!(v2); + + if v1 != v2 { + self.pdl.clear(); + return Some(v1.cmp(&v2)); + } + } + Some(TermOrderCategory::Integer) => { + let v1 = Number::try_from(v1).unwrap(); + let v2 = Number::try_from(v2).unwrap(); + + if v1 != v2 { + self.pdl.clear(); + return Some(v1.cmp(&v2)); + } + } + Some(TermOrderCategory::Atom) => { + read_heap_cell!(v1, + (HeapCellValueTag::Atom, (n1, _a1)) => { + read_heap_cell!(v2, + (HeapCellValueTag::Atom, (n2, _a2)) => { + if n1 != n2 { + self.pdl.clear(); + return Some(n1.cmp(&n2)); + } + } + (HeapCellValueTag::Char, c2) => { + if let Some(c1) = n1.as_char() { + if c1 != c2 { + self.pdl.clear(); + return Some(c1.cmp(&c2)); } } else { - pdl.push(Addr::PStrLocation(h2, n2 + m_len)); + self.pdl.clear(); + return Some(Ordering::Greater); } - } else { - pdl.push(Addr::PStrLocation(h1, n1 + m_len)); - - if pstr2.at_end(n2 + m_len) { - if has_tail_2 { - pdl.push(Addr::HeapCell(h2 + 1)); - } else { - pdl.push(Addr::EmptyList); + } + _ => { + unreachable!(); + } + ) + } + (HeapCellValueTag::Char, c1) => { + read_heap_cell!(v2, + (HeapCellValueTag::Atom, (n2, _a2)) => { + if let Some(c2) = n2.as_char() { + if c1 != c2 { + self.pdl.clear(); + return Some(c1.cmp(&c2)); } } else { - pdl.push(Addr::PStrLocation(h2, n2 + m_len)); + self.pdl.clear(); + return Some(Ordering::Less); } } - } + (HeapCellValueTag::Char, c2) => { + if c1 != c2 { + self.pdl.clear(); + return Some(c1.cmp(&c2)); + } + } + _ => { + unreachable!() + } + ) } - } - (Addr::Lis(a1), Addr::Lis(a2)) => { - pdl.push(Addr::HeapCell(a1)); - pdl.push(Addr::HeapCell(a2)); + _ => { + unreachable!() + } + ) + } + Some(TermOrderCategory::Compound) => { + fn stalled_pstr_iter_handler( + string_iter: HeapPStrIter, + stalled_iter: HeapPStrIter, + pdl: &mut Vec, + ) -> Option { + let l = read_heap_cell!(stalled_iter.focus, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(stalled_iter.heap[s]) + .get_name_and_arity(); + + if !(name == atom!(".") && arity == 2) { + pdl.clear(); + return Some((atom!("."),2).cmp(&(name,arity))); + } + + s+1 + } + (HeapCellValueTag::Lis, l) => { + l + } + _ => { + unreachable!() + } + ); + + let c2 = stalled_iter.heap[l]; + let c1 = string_iter.chars().next().unwrap(); - pdl.push(Addr::HeapCell(a1 + 1)); - pdl.push(Addr::HeapCell(a2 + 1)); + pdl.push(c2); + pdl.push(char_as_cell!(c1)); + + None } - (Addr::Str(a1), Addr::Str(a2)) => { - let r1 = &self.heap[a1]; - let r2 = &self.heap[a2]; - if let &HeapCellValue::NamedStr(n1, ref f1, _) = r1 { - if let &HeapCellValue::NamedStr(n2, ref f2, _) = r2 { - if n1 == n2 && *f1 == *f2 { - for i in 1..n1 + 1 { - pdl.push(Addr::HeapCell(a1 + i)); - pdl.push(Addr::HeapCell(a2 + i)); - } + fn pstr_comparator( + heap: &[HeapCellValue], + pdl: &mut Vec, + s1: usize, + s2: usize, + ) -> Option { + let mut iter1 = HeapPStrIter::new(heap, s1); + let mut iter2 = HeapPStrIter::new(heap, s2); - continue; + match compare_pstr_prefixes(&mut iter1, &mut iter2) { + PStrCmpResult::Ordered(ordering) => Some(ordering), + _ => { + if iter1.num_steps() == 0 && iter2.num_steps() == 0 { + return match iter2.focus.get_tag() { + HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc => { + let result = stalled_pstr_iter_handler(iter2, iter1, pdl); + + if let Some(ordering) = result { + Some(ordering.reverse()) + } else { + let pdl_len = pdl.len(); + pdl.swap(pdl_len - 2, pdl_len - 1); + result + } + } + _ => { + stalled_pstr_iter_handler(iter1, iter2, pdl) + } + }; } + + pdl.push(iter2.focus); + pdl.push(iter1.focus); + + None } } - - self.fail = true; } - (Addr::Con(c1), Addr::Con(c2)) => match (&self.heap[c1], &self.heap[c2]) { - (&HeapCellValue::Atom(ref n1, _), &HeapCellValue::Atom(ref n2, _)) - if n1.as_str() == n2.as_str() => {} - ( - &HeapCellValue::DBRef(ref db_ref_1), - &HeapCellValue::DBRef(ref db_ref_2), - ) if db_ref_1 == db_ref_2 => {} - (v1, v2) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 == n2 { + + read_heap_cell!(v1, + (HeapCellValueTag::Lis, l1) => { + read_heap_cell!(v2, + (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { + let h = self.heap.len(); + + self.heap.push(v1); + self.heap.push(v2); + + if let Some(ordering) = pstr_comparator( + &self.heap, &mut self.pdl, h, h+1 + ) { + if ordering != Ordering::Equal { + self.heap.pop(); + self.heap.pop(); + + self.pdl.clear(); + + return Some(ordering); + } + } + + self.heap.pop(); + self.heap.pop(); + } + (HeapCellValueTag::Lis, l2) => { + if tabu_list.contains(&(l1, l2)) { continue; } + + tabu_list.insert((l1, l2)); + + self.pdl.push(self.heap[l2 + 1]); + self.pdl.push(self.heap[l1 + 1]); + + self.pdl.push(self.heap[l2]); + self.pdl.push(self.heap[l1]); } - } + (HeapCellValueTag::Str, s2) => { + if tabu_list.contains(&(l1, s2)) { + continue; + } - self.fail = true; - } - }, - (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => { - match &self.heap[h] { - &HeapCellValue::Atom(ref name, _) if name.is_char() => { - if name.as_str().chars().next() != Some(c) { - self.fail = true; - return; + let (name, arity) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); + + match (atom!("."), 2).cmp(&(name, arity)) { + Ordering::Equal => { + tabu_list.insert((l1, s2)); + + self.pdl.push(self.heap[s2 + 2]); + self.pdl.push(self.heap[l1 + 1]); + + self.pdl.push(self.heap[s2 + 1]); + self.pdl.push(self.heap[l1]); + } + ordering => { + self.pdl.clear(); + return Some(ordering); + } + } } - } - _ => { - self.fail = true; - return; - } - } - } - (Addr::Stream(s1), Addr::Stream(s2)) => { - if s1 != s2 { - self.fail = true; + _ => { + unreachable!(); + } + ) } - } - (v, Addr::Con(h)) | (Addr::Con(h), v) => { - if let Ok(n1) = Number::try_from(&self.heap[h]) { - if let Ok(v) = Number::try_from(&HeapCellValue::Addr(v)) { - if n1 == v { - continue; + (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { + let h = self.heap.len(); + + self.heap.push(v1); + self.heap.push(v2); + + if let Some(ordering) = pstr_comparator( + &self.heap, &mut self.pdl, h, h+1, + ) { + if ordering != Ordering::Equal { + self.heap.pop(); + self.heap.pop(); + + self.pdl.clear(); + + return Some(ordering); } } + + self.heap.pop(); + self.heap.pop(); } + (HeapCellValueTag::Str, s1) => { + read_heap_cell!(v2, + (HeapCellValueTag::Str, s2) => { + if tabu_list.contains(&(s1, s2)) { + continue; + } - self.fail = true; - } - (a1, a2) => { - if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(a1)) { - if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(a2)) { - if n1 == n2 { - continue; + let (n1, a1) = cell_as_atom_cell!(self.heap[s1]) + .get_name_and_arity(); + + let (n2, a2) = cell_as_atom_cell!(self.heap[s2]) + .get_name_and_arity(); + + match (n1,a1).cmp(&(n2,a2)) { + Ordering::Equal => { + tabu_list.insert((s1, s2)); + + for idx in (1 .. a1+1).rev() { + self.pdl.push(self.heap[s2+idx]); + self.pdl.push(self.heap[s1+idx]); + } + } + ordering => { + self.pdl.clear(); + return Some(ordering); + } + } + } + (HeapCellValueTag::Lis, l2) => { + if tabu_list.contains(&(s1, l2)) { + continue; + } + + tabu_list.insert((s1, l2)); + + let (n1, a1) = cell_as_atom_cell!(self.heap[s1]) + .get_name_and_arity(); + + match (n1,a1).cmp(&(atom!("."), 2)) { + Ordering::Equal => { + self.pdl.push(self.heap[l2]); + self.pdl.push(self.heap[s1+1]); + + self.pdl.push(self.heap[l2+1]); + self.pdl.push(self.heap[s1+2]); + } + ordering => { + self.pdl.clear(); + return Some(ordering); + } + } + } + (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { + let h = self.heap.len(); + + self.heap.push(v1); + self.heap.push(v2); + + if let Some(ordering) = pstr_comparator( + &self.heap, &mut self.pdl, h, h+1, + ) { + if ordering != Ordering::Equal { + self.heap.pop(); + self.heap.pop(); + + self.pdl.clear(); + + return Some(ordering); + } + } + + self.heap.pop(); + self.heap.pop(); + } + _ => { + unreachable!() } - } + ) } - - if a1 != a2 { - self.fail = true; + _ => { + unreachable!() } - } - }; - } - } - } - - pub(super) fn trail(&mut self, r: TrailRef) { - match r { - TrailRef::Ref(Ref::HeapCell(h)) => { - if h < self.hb { - self.trail.push(TrailRef::Ref(Ref::HeapCell(h))); - self.tr += 1; - } - } - TrailRef::Ref(Ref::AttrVar(h)) => { - if h < self.hb { - self.trail.push(TrailRef::Ref(Ref::AttrVar(h))); - self.tr += 1; - } - } - TrailRef::AttrVarHeapLink(h) => { - if h < self.hb { - self.trail.push(TrailRef::AttrVarHeapLink(h)); - self.tr += 1; - } - } - TrailRef::AttrVarListLink(h, l) => { - if h < self.hb { - self.trail.push(TrailRef::AttrVarListLink(h, l)); - self.tr += 1; + ); } - } - TrailRef::Ref(Ref::StackCell(b, sc)) => { - if b < self.b { - self.trail.push(TrailRef::Ref(Ref::StackCell(b, sc))); - self.tr += 1; + None => { + if v1 != v2 { + self.pdl.clear(); + return None; + } } } - TrailRef::BlackboardOffset(key_h, value_h) => { - self.trail.push(TrailRef::BlackboardOffset(key_h, value_h)); - self.tr += 1; - } - TrailRef::BlackboardEntry(key_h) => { - self.trail.push(TrailRef::BlackboardEntry(key_h)); - self.tr += 1; - } } + + Some(Ordering::Equal) } fn increment_s_ptr(&mut self, rhs: usize) { @@ -691,16 +1809,20 @@ impl MachineState { *h += rhs; } &mut HeapPtr::PStrChar(h, ref mut n) | &mut HeapPtr::PStrLocation(h, ref mut n) => { - match &self.heap[h] { - &HeapCellValue::PartialString(ref pstr, _) => { - for c in pstr.range_from(*n..).take(rhs) { + read_heap_cell!(self.heap[h], + (HeapCellValueTag::PStr | HeapCellValueTag::CStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + + for c in pstr.as_str_from(*n).chars().take(rhs) { *n += c.len_utf8(); } self.s = HeapPtr::PStrLocation(h, *n); } - _ => {} - } + _ => { + unreachable!() + } + ) } } } @@ -715,425 +1837,409 @@ impl MachineState { // additions, now that deleted attributes can be undeleted by // backtracking. for i in (a1..a2).rev() { - match self.trail[i] { - TrailRef::Ref(Ref::HeapCell(h)) => { - self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h)) + let h = self.trail[i].get_value() as usize; + + match self.trail[i].get_tag() { + TrailEntryTag::TrailedHeapVar => { + self.heap[h] = heap_loc_as_cell!(h); } - TrailRef::Ref(Ref::AttrVar(h)) => { - self.heap[h] = HeapCellValue::Addr(Addr::AttrVar(h)) + TrailEntryTag::TrailedStackVar => { + self.stack[h] = stack_loc_as_cell!(h); } - TrailRef::Ref(Ref::StackCell(fr, sc)) => { - self.stack.index_and_frame_mut(fr)[sc] = Addr::StackCell(fr, sc) + TrailEntryTag::TrailedAttrVar => { + self.heap[h] = attr_var_as_cell!(h); } - TrailRef::AttrVarHeapLink(h) => { - self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h)); + TrailEntryTag::TrailedAttrVarHeapLink => { + self.heap[h] = heap_loc_as_cell!(h); } - TrailRef::AttrVarListLink(h, l) => { - self.heap[h] = HeapCellValue::Addr(Addr::Lis(l)); + TrailEntryTag::TrailedAttrVarListLink => { + let l = self.trail[i + 1].get_value(); + self.heap[h] = list_loc_as_cell!(l); } - TrailRef::BlackboardOffset(key_h, value_h) => { - let key = atom_from!( - self, - self.store(self.deref(self.heap[key_h].as_addr(key_h))) - ); - - let value_addr = self.heap[value_h].as_addr(value_h); + TrailEntryTag::TrailedBlackboardEntry => { + let key = Atom::from(h); match global_variables.get_mut(&key) { - Some((_, ref mut loc)) => *loc = Some(value_addr), + Some((_, ref mut loc)) => *loc = None, None => unreachable!(), } } - TrailRef::BlackboardEntry(key_h) => { - let key = atom_from!( - self, - self.store(self.deref(self.heap[key_h].as_addr(key_h))) - ); + TrailEntryTag::TrailedBlackboardOffset => { + let key = Atom::from(h); + let value_cell = HeapCellValue::from(u64::from(self.trail[i + 1])); match global_variables.get_mut(&key) { - Some((_, ref mut loc)) => *loc = None, + Some((_, ref mut loc)) => *loc = Some(value_cell), None => unreachable!(), } } + TrailEntryTag::TrailedAttachedValue => { + } } } } - pub(super) fn match_partial_string(&mut self, addr: Addr, string: &String, has_tail: bool) { - let mut heap_pstr_iter = self.heap_pstr_iter(addr); + pub fn match_partial_string(&mut self, value: HeapCellValue, string: Atom, has_tail: bool) { + let h = self.heap.len(); + self.heap.push(value); - match compare_pstr_to_string(&mut heap_pstr_iter, string) { - Some(prefix_len) if prefix_len == string.len() => { - let focus = heap_pstr_iter.focus(); + let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h); + let s = string.as_str(); + + match heap_pstr_iter.compare_pstr_to_string(s) { + Some(PStrPrefixCmpResult { focus, offset, prefix_len }) if prefix_len == s.len() => { + let focus_addr = self.heap[focus]; - match focus { - Addr::PStrLocation(h, n) => { + read_heap_cell!(focus_addr, + (HeapCellValueTag::PStr | HeapCellValueTag::CStr, pstr_atom) => { if has_tail { - self.s = HeapPtr::PStrLocation(h, n); + self.s = HeapPtr::PStrLocation(focus, offset); self.mode = MachineMode::Read; + } else if offset == pstr_atom.len() { + let focus_addr = heap_pstr_iter.focus; + unify!(self, focus_addr, empty_list_as_cell!()); } else { self.fail = true; } } - addr => { + (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, h) => { if has_tail { - let h = self.heap.h(); + let (h, _) = pstr_loc_and_offset(&self.heap, h); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self.bind(Ref::HeapCell(h), addr); + self.s = HeapPtr::PStrLocation(h, offset); + self.mode = MachineMode::Read; + } else { + let end_cell = heap_pstr_iter.focus; + self.fail = end_cell != empty_list_as_cell!(); + } + } + _ => { + let focus = heap_pstr_iter.focus(); - self.s = HeapPtr::HeapCell(h); + if has_tail { + self.s = HeapPtr::HeapCell(focus); self.mode = MachineMode::Read; } else { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::EmptyList); - } else { - self.fail = addr != Addr::EmptyList; - } + let focus = heap_pstr_iter.focus; + unify!(self, focus, empty_list_as_cell!()); } } - } + ); } - Some(prefix_len) => match heap_pstr_iter.focus() { - addr if addr.is_ref() => { - let h = self.heap.h(); - - let pstr_addr = if has_tail { - self.s = HeapPtr::HeapCell(h + 1); - self.mode = MachineMode::Read; - - self.heap.allocate_pstr(&string[prefix_len..]) - } else { - self.heap.put_complete_string(&string[prefix_len..]) - }; + Some(PStrPrefixCmpResult { prefix_len, .. }) => { + // TODO: this is woefully insufficient! you need to + // match the remaining portion of string if offset < + // pstr.len(). + let focus = heap_pstr_iter.focus(); + let tail_addr = self.heap[focus]; - self.bind(addr.as_var().unwrap(), pstr_addr); - } - Addr::Lis(l) => { - let h = self.heap.h(); + let h = self.heap.len(); - let pstr_addr = if has_tail { - self.s = HeapPtr::HeapCell(h + 1); - self.mode = MachineMode::Read; + let target_cell = if has_tail { + self.s = HeapPtr::HeapCell(h + 1); + self.mode = MachineMode::Read; - self.heap.allocate_pstr(&string[prefix_len..]) - } else { - self.heap.put_complete_string(&string[prefix_len..]) - }; + put_partial_string( + &mut self.heap, + &string.as_str()[prefix_len ..], + &mut self.atom_tbl, + ) + } else { + put_complete_string( + &mut self.heap, + &string.as_str()[prefix_len ..], + &mut self.atom_tbl, + ) + }; - (self.unify_fn)(self, Addr::Lis(l), pstr_addr); - } - _ => { - self.fail = true; - } - }, + unify!(self, tail_addr, target_cell); + } None => { self.fail = true; } } } - pub(super) fn write_constant_to_var(&mut self, addr: Addr, c: &Constant) { - match self.store(self.deref(addr)) { - Addr::Con(c1) => { - match &self.heap[c1] { - HeapCellValue::Atom(ref n1, _) => { - self.fail = match c { - Constant::Atom(ref n2, _) => n1 != n2, - Constant::Char(c) if n1.is_char() => { - Some(*c) != n1.as_str().chars().next() - } - _ => true, - }; - } - HeapCellValue::Integer(ref n1) => { - self.fail = match c { - Constant::Fixnum(n2) => n1.to_isize() != Some(*n2), - Constant::Integer(ref n2) => n1 != n2, - Constant::Usize(n2) => n1.to_usize() != Some(*n2), - _ => true, - }; - } - HeapCellValue::Rational(ref r1) => { - self.fail = if let Constant::Rational(ref r2) = c { - r1 != r2 - } else { - true - } - } - HeapCellValue::PartialString(..) => { - if let Constant::String(ref s2) = c { - self.match_partial_string(Addr::PStrLocation(c1, 0), &s2, false); - } else { - self.fail = true; - } - } - _ => { - unreachable!() - } - }; - } - Addr::Char(ch) => { - self.fail = match c { - Constant::Atom(ref n2, _) if n2.is_char() => { - Some(ch) != n2.as_str().chars().next() - } - Constant::Char(c) => *c != ch, - _ => true, - }; - } - Addr::EmptyList => { - if let Constant::EmptyList = c { + pub(super) fn write_literal_to_var(&mut self, deref_v: HeapCellValue, lit: HeapCellValue) { + let store_v = self.store(deref_v); + + read_heap_cell!(lit, + (HeapCellValueTag::Atom, (atom, arity)) => { + if arity == 0 { + self.unify_atom(atom, store_v); } else { self.fail = true; } } - Addr::Lis(l) => { - let addr = self.heap.put_constant(c.clone()); - self.unify(Addr::Lis(l), addr); - } - Addr::PStrLocation(h, n) => { - if let Constant::String(ref s2) = c { - self.match_partial_string(Addr::PStrLocation(h, n), &s2, false) - } else { - self.fail = true; - }; - } - Addr::Stream(_) => { - self.fail = true; + (HeapCellValueTag::Char, c) => { + self.unify_char(c, store_v); + } + (HeapCellValueTag::Fixnum, n) => { + self.unify_fixnum(n, store_v); + } + (HeapCellValueTag::F64, f64_ptr) => { + self.unify_f64(f64_ptr, store_v); + } + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Integer, n) => { + self.unify_big_int(n, store_v); + } + (ArenaHeaderTag::Rational, r) => { + self.unify_rational(r, store_v); + } + _ => { + self.fail = true; + } + ) } - addr => { - let c = self.heap.put_constant(c.clone()); - - if let Some(r) = addr.as_var() { - self.bind(r, c); - } else { - self.unify(addr, c); + (HeapCellValueTag::CStr, cstr_atom) => { + match store_v.get_tag() { + HeapCellValueTag::PStrLoc + | HeapCellValueTag::Lis + | HeapCellValueTag::Str => { + self.match_partial_string(store_v, cstr_atom, false); + } + _ => { + self.fail = true; + } } } - }; + _ => { + unreachable!() + } + ) } - pub(super) fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { - let stub = MachineError::functor_stub(clause_name!("is"), 2); + pub fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { + let stub_gen = || functor_stub(atom!("is"), 2); match instr { &ArithmeticInstruction::Add(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 + n2, stub)); + self.interms[t - 1] = try_or_fail_gen!( + self, + try_numeric_result!(add(n1, n2, &mut self.arena), stub_gen) + ); self.p += 1; } &ArithmeticInstruction::Sub(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 - n2, stub)); + self.interms[t - 1] = try_or_fail_gen!( + self, + try_numeric_result!(sub(n1, n2, &mut self.arena), stub_gen) + ); self.p += 1; } &ArithmeticInstruction::Mul(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, try_numeric_result!(self, n1 * n2, stub)); + self.interms[t - 1] = try_or_fail_gen!( + self, + try_numeric_result!(mul(n1, n2, &mut self.arena), stub_gen) + ); self.p += 1; } &ArithmeticInstruction::Max(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.max(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, max(n1, n2)); self.p += 1; } &ArithmeticInstruction::Min(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.min(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, min(n1, n2)); self.p += 1; } &ArithmeticInstruction::IntPow(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, int_pow(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.gcd(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, gcd(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Pow(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.pow(n1, n2, "(**)")); + self.interms[t - 1] = try_or_fail_gen!(self, pow(n1, n2, atom!("**"))); self.p += 1; } &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => { - let stub = MachineError::functor_stub(clause_name!("(rdiv)"), 2); + let stub_gen = || functor_stub(atom!("(rdiv)"), 2); - let (r1, stub) = try_or_fail!(self, self.get_rational(a1, stub)); - let (r2, _) = try_or_fail!(self, self.get_rational(a2, stub)); + let r1 = try_or_fail!(self, self.get_rational(a1, stub_gen)); + let r2 = try_or_fail!(self, self.get_rational(a2, stub_gen)); - self.interms[t - 1] = - Number::Rational(Rc::new(try_or_fail!(self, self.rdiv(r1, r2)))); + self.interms[t - 1] = Number::Rational(arena_alloc!( + try_or_fail_gen!(self, rdiv(r1, r2)), + self.arena + )); self.p += 1; } &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.int_floor_div(n1, n2)); + self.interms[t - 1] = + try_or_fail_gen!(self, int_floor_div(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.idiv(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, idiv(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Abs(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = n1.abs(); + self.interms[t - 1] = abs(n1, &mut self.arena); self.p += 1; } &ArithmeticInstruction::Sign(ref a1, t) => { let n = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = self.sign(n); + self.interms[t - 1] = sign(n); self.p += 1; } &ArithmeticInstruction::Neg(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = -n1; + self.interms[t - 1] = neg(n1, &mut self.arena); self.p += 1; } &ArithmeticInstruction::BitwiseComplement(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = try_or_fail!(self, self.bitwise_complement(n1)); + self.interms[t - 1] = + try_or_fail_gen!(self, bitwise_complement(n1, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Div(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.div(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, div(n1, n2)); self.p += 1; } &ArithmeticInstruction::Shr(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.shr(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, shr(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Shl(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.shl(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, shl(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Xor(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.xor(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, xor(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::And(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.and(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, and(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Or(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.or(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, or(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Mod(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.modulus(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, modulus(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Rem(ref a1, ref a2, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); let n2 = try_or_fail!(self, self.get_number(a2)); - self.interms[t - 1] = try_or_fail!(self, self.remainder(n1, n2)); + self.interms[t - 1] = try_or_fail_gen!(self, remainder(n1, n2, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Cos(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.cos(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, cos(n1)))); self.p += 1; } &ArithmeticInstruction::Sin(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.sin(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, sin(n1)))); self.p += 1; } &ArithmeticInstruction::Tan(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.tan(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, tan(n1)))); self.p += 1; } &ArithmeticInstruction::Sqrt(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.sqrt(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, sqrt(n1)))); self.p += 1; } &ArithmeticInstruction::Log(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.log(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, log(n1)))); self.p += 1; } &ArithmeticInstruction::Exp(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail!(self, self.exp(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, exp(n1)))); self.p += 1; } &ArithmeticInstruction::ACos(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.acos(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, acos(n1)))); self.p += 1; } &ArithmeticInstruction::ASin(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.asin(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, asin(n1)))); self.p += 1; } &ArithmeticInstruction::ATan(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.atan(n1)))); + self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, atan(n1)))); self.p += 1; } &ArithmeticInstruction::ATan2(ref a1, ref a2, t) => { @@ -1141,38 +2247,38 @@ impl MachineState { let n2 = try_or_fail!(self, self.get_number(a2)); self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.atan2(n1, n2)))); + Number::Float(OrderedFloat(try_or_fail_gen!(self, atan2(n1, n2)))); self.p += 1; } &ArithmeticInstruction::Float(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail!(self, self.float(n1)))); + Number::Float(OrderedFloat(try_or_fail_gen!(self, float(n1)))); self.p += 1; } &ArithmeticInstruction::Truncate(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = self.truncate(n1); + self.interms[t - 1] = truncate(n1, &mut self.arena); self.p += 1; } &ArithmeticInstruction::Round(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = try_or_fail!(self, self.round(n1)); + self.interms[t - 1] = try_or_fail_gen!(self, round(n1, &mut self.arena)); self.p += 1; } &ArithmeticInstruction::Ceiling(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = self.ceiling(n1); + self.interms[t - 1] = ceiling(n1, &mut self.arena); self.p += 1; } &ArithmeticInstruction::Floor(ref a1, t) => { let n1 = try_or_fail!(self, self.get_number(a1)); - self.interms[t - 1] = self.floor(n1); + self.interms[t - 1] = floor(n1, &mut self.arena); self.p += 1; } &ArithmeticInstruction::Plus(ref a1, t) => { @@ -1184,74 +2290,99 @@ impl MachineState { }; } - pub(super) fn execute_fact_instr(&mut self, instr: &FactInstruction) { + pub fn execute_fact_instr(&mut self, instr: &FactInstruction) { match instr { - &FactInstruction::GetConstant(_, ref c, reg) => { - let addr = self[reg]; - self.write_constant_to_var(addr, c); + &FactInstruction::GetConstant(_, c, reg) => { + let value = self.deref(self[reg]); + self.write_literal_to_var(value, c); } &FactInstruction::GetList(_, reg) => { - let addr = self.store(self.deref(self[reg])); + let deref_v = self.deref(self[reg]); + let store_v = self.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::PStrLoc, h) => { + let (h, n) = pstr_loc_and_offset(&self.heap, h); - match addr { - Addr::PStrLocation(h, n) => { - self.s = HeapPtr::PStrChar(h, n); + self.s = HeapPtr::PStrChar(h, n.get_num() as usize); self.mode = MachineMode::Read; } - addr @ Addr::AttrVar(_) - | addr @ Addr::StackCell(..) - | addr @ Addr::HeapCell(_) => { - let h = self.heap.h(); + (HeapCellValueTag::CStr) => { + let h = self.heap.len(); + self.heap.push(store_v); - self.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1))); - self.bind(addr.as_var().unwrap(), Addr::HeapCell(h)); - - self.mode = MachineMode::Write; + self.s = HeapPtr::PStrChar(h, 0); + self.mode = MachineMode::Read; } - Addr::Lis(a) => { - self.s = HeapPtr::HeapCell(a); + (HeapCellValueTag::Lis, l) => { + self.s = HeapPtr::HeapCell(l); self.mode = MachineMode::Read; } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + let h = self.heap.len(); + + self.heap.push(list_loc_as_cell!(h+1)); + self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); + + self.mode = MachineMode::Write; + } _ => { self.fail = true; } - }; + ); } - &FactInstruction::GetPartialString(_, ref string, reg, has_tail) => { - let addr = self.store(self.deref(self[reg])); - self.match_partial_string(addr, string, has_tail); + &FactInstruction::GetPartialString(_, string, reg, has_tail) => { + let deref_v = self.deref(self[reg]); + let store_v = self.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::Str | HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar | + HeapCellValueTag::StackVar | HeapCellValueTag::Var | + HeapCellValueTag::CStr) => { + self.match_partial_string(store_v, string, has_tail); + } + _ => { + self.fail = true; + } + ); } &FactInstruction::GetStructure(ref ct, arity, reg) => { - let addr = self.deref(self[reg]); - - match self.store(addr) { - Addr::Str(a) => { - let result = &self.heap[a]; - - if let &HeapCellValue::NamedStr(narity, ref s, _) = result { - if narity == arity && ct.name() == *s { - self.s = HeapPtr::HeapCell(a + 1); - self.mode = MachineMode::Read; - } else { - self.fail = true; + let deref_v = self.deref(self[reg]); + let store_v = self.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::Str, a) => { + let result = self.heap[a]; + + read_heap_cell!(result, + (HeapCellValueTag::Atom, (name, narity)) => { + if narity == arity && ct.name() == name { + self.s = HeapPtr::HeapCell(a + 1); + self.mode = MachineMode::Read; + } else { + self.fail = true; + } } - } + _ => { + unreachable!(); + } + ); } - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => { - let h = self.heap.h(); + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + let h = self.heap.len(); - self.heap.push(HeapCellValue::Addr(Addr::Str(h + 1))); - self.heap - .push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec())); + self.heap.push(str_loc_as_cell!(h+1)); + self.heap.push(atom_as_cell!(ct.name(), arity)); - self.bind(addr.as_var().unwrap(), Addr::HeapCell(h)); + self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); self.mode = MachineMode::Write; } _ => { self.fail = true; } - }; + ); } &FactInstruction::GetVariable(norm, arg) => { self[norm] = self.registers[arg]; @@ -1260,36 +2391,32 @@ impl MachineState { let norm_addr = self[norm]; let reg_addr = self.registers[arg]; - (self.unify_fn)(self, norm_addr, reg_addr); + unify_fn!(self, norm_addr, reg_addr); } - &FactInstruction::UnifyConstant(ref c) => { + &FactInstruction::UnifyConstant(v) => { match self.mode { MachineMode::Read => { - let addr = self.s.read(&self.heap); + let addr = self.read_s(); - self.write_constant_to_var(addr, c); + self.write_literal_to_var(addr, v); self.increment_s_ptr(1); } MachineMode::Write => { - let addr = self.heap.put_constant(c.clone()); - - if !addr.is_heap_bound() { - self.heap.push(HeapCellValue::Addr(addr)); - } + self.heap.push(v); } }; } &FactInstruction::UnifyVariable(reg) => { match self.mode { MachineMode::Read => { - self[reg] = self.s.read(&self.heap); + self[reg] = self.read_s(); self.increment_s_ptr(1); } MachineMode::Write => { - let h = self.heap.h(); + let h = self.heap.len(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self[reg] = Addr::HeapCell(h); + self.heap.push(heap_loc_as_cell!(h)); + self[reg] = heap_loc_as_cell!(h); } }; } @@ -1297,25 +2424,30 @@ impl MachineState { match self.mode { MachineMode::Read => { let reg_addr = self[reg]; + let value = self.read_s(); - (self.unify_fn)(self, reg_addr, self.s.read(&self.heap)); + unify_fn!(self, reg_addr, value); self.increment_s_ptr(1); } MachineMode::Write => { - let addr = self.store(self.deref(self[reg])); - let h = self.heap.h(); + let value = self.store(self.deref(self[reg])); + let h = self.heap.len(); - if let Addr::HeapCell(hc) = addr { - let val = self.heap.clone(hc); + read_heap_cell!(value, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => { + let value = self.heap[hc]; - self.heap.push(val); - self.increment_s_ptr(1); + self.heap.push(value); + self.increment_s_ptr(1); - return; - } + return; + } + _ => { + } + ); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - (self.bind_fn)(self, Ref::HeapCell(h), addr); + self.heap.push(heap_loc_as_cell!(h)); + (self.bind_fn)(self, Ref::heap_cell(h), value); } }; } @@ -1323,16 +2455,17 @@ impl MachineState { match self.mode { MachineMode::Read => { let reg_addr = self[reg]; + let value = self.read_s(); - (self.unify_fn)(self, reg_addr, self.s.read(&self.heap)); + unify_fn!(self, reg_addr, value); self.increment_s_ptr(1); } MachineMode::Write => { - let h = self.heap.h(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); let addr = self.store(self[reg]); - (self.bind_fn)(self, Ref::HeapCell(h), addr); + (self.bind_fn)(self, Ref::heap_cell(h), addr); // the former code of this match arm was: @@ -1352,10 +2485,10 @@ impl MachineState { self.increment_s_ptr(n); } MachineMode::Write => { - let h = self.heap.h(); + let h = self.heap.len(); for i in h..h + n { - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(i))); + self.heap.push(heap_loc_as_cell!(i)); } } }; @@ -1408,22 +2541,45 @@ impl MachineState { loop { match &indexing_lines[index] { &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => { - let offset = match addr { - Addr::LoadStatePayload(_) | Addr::Stream(_) | Addr::TcpListener(_) => { - IndexingCodePtr::Fail + let offset = read_heap_cell!(addr, + (HeapCellValueTag::Var + | HeapCellValueTag::StackVar + | HeapCellValueTag::AttrVar) => { + v } - Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => v, - Addr::PStrLocation(..) => l, - Addr::Char(_) - | Addr::Con(_) - | Addr::CutPoint(_) - | Addr::EmptyList - | Addr::Fixnum(_) - | Addr::Float(_) - | Addr::Usize(_) => c, - Addr::Lis(_) => l, - Addr::Str(_) => s, - }; + (HeapCellValueTag::PStrLoc + | HeapCellValueTag::Lis + | HeapCellValueTag::CStr) => { + l + } + (HeapCellValueTag::Fixnum + | HeapCellValueTag::Char + | HeapCellValueTag::F64) => { + c + } + (HeapCellValueTag::Atom, (_name, arity)) => { + // if arity == 0 { c } else { s } + debug_assert!(arity == 0); + c + } + (HeapCellValueTag::Str) => { + s + } + (HeapCellValueTag::Cons, ptr) => { + match ptr.get_tag() { + ArenaHeaderTag::Rational | ArenaHeaderTag::Integer | + ArenaHeaderTag::F64 => { + c + } + _ => { + IndexingCodePtr::Fail + } + } + } + _ => { + unreachable!(); + } + ); match offset { IndexingCodePtr::Fail => { @@ -1451,15 +2607,47 @@ impl MachineState { IndexingCodePtr::Internal(o) => { index += o; } - }; + } } &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => { - let offset = match addr.as_constant_index(&self) { - Some(c) => match hm.get(&c) { - Some(offset) => *offset, - _ => IndexingCodePtr::Fail, - }, - None => IndexingCodePtr::Fail, + let lit = read_heap_cell!(addr, + (HeapCellValueTag::Char, c) => { + Literal::Char(c) + } + (HeapCellValueTag::Fixnum, n) => { + Literal::Fixnum(n) + } + (HeapCellValueTag::F64, f) => { + Literal::Float(f) + } + (HeapCellValueTag::Atom, (atom, arity)) => { + debug_assert_eq!(arity, 0); + Literal::Atom(atom) + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Rational, r) => { + Literal::Rational(r) + } + (ArenaHeaderTag::F64, f) => { + Literal::Float(F64Ptr(f)) + } + (ArenaHeaderTag::Integer, n) => { + Literal::Integer(n) + } + _ => { + unreachable!() + } + ) + } + _ => { + unreachable!() + } + ); + + let offset = match hm.get(&lit) { + Some(offset) => *offset, + _ => IndexingCodePtr::Fail, }; match offset { @@ -1488,22 +2676,28 @@ impl MachineState { IndexingCodePtr::Internal(o) => { index += o; } - }; + } } &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => { - let offset = match addr { - Addr::Str(s) => { - if let &HeapCellValue::NamedStr(arity, ref name, _) = &self.heap[s] { - match hm.get(&(name.clone(), arity)) { - Some(offset) => *offset, - _ => IndexingCodePtr::Fail, - } - } else { - IndexingCodePtr::Fail + let offset = read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, arity)) => { + match hm.get(&(name, arity)) { + Some(offset) => *offset, + None => IndexingCodePtr::Fail, } } - _ => IndexingCodePtr::Fail, - }; + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + + match hm.get(&(name, arity)) { + Some(offset) => *offset, + None => IndexingCodePtr::Fail, + } + } + _ => { + IndexingCodePtr::Fail + } + ); match offset { IndexingCodePtr::Fail => { @@ -1559,47 +2753,50 @@ impl MachineState { &QueryInstruction::GetVariable(norm, arg) => { self[norm] = self.registers[arg]; } - &QueryInstruction::PutConstant(_, ref c, reg) => { - self[reg] = self.heap.put_constant(c.clone()); + &QueryInstruction::PutConstant(_, c, reg) => { + self[reg] = c; } &QueryInstruction::PutList(_, reg) => { - self[reg] = Addr::Lis(self.heap.h()); + self[reg] = list_loc_as_cell!(self.heap.len()); } - &QueryInstruction::PutPartialString(_, ref string, reg, has_tail) => { + &QueryInstruction::PutPartialString(_, string, reg, has_tail) => { let pstr_addr = if has_tail { - if !string.is_empty() { - let pstr_addr = self.heap.allocate_pstr(&string); - self.heap.pop(); // the tail will be added by the next instruction. - pstr_addr + if string != atom!("") { + let h = self.heap.len(); + self.heap.push(string_as_pstr_cell!(string)); + + // the tail will be pushed by the next + // instruction, so don't push one here. + + pstr_loc_as_cell!(h) } else { - Addr::EmptyList + empty_list_as_cell!() } } else { - self.heap.put_complete_string(&string) + string_as_cstr_cell!(string) }; self[reg] = pstr_addr; } &QueryInstruction::PutStructure(ref ct, arity, reg) => { - let h = self.heap.h(); + let h = self.heap.len(); - self.heap - .push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec())); - self[reg] = Addr::Str(h); + self.heap.push(atom_as_cell!(ct.name(), arity)); + self[reg] = str_loc_as_cell!(h); } &QueryInstruction::PutUnsafeValue(n, arg) => { - let e = self.e; - let addr = self.store(self.deref(Addr::StackCell(e, n))); + let s = stack_loc!(AndFrame, self.e, n); + let addr = self.store(self.deref(stack_loc_as_cell!(s))); - if addr.is_protected(e) { + if addr.is_protected(self.e) { self.registers[arg] = addr; } else { - let h = self.heap.h(); + let h = self.heap.len(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - (self.bind_fn)(self, Ref::HeapCell(h), addr); + self.heap.push(heap_loc_as_cell!(h)); + (self.bind_fn)(self, Ref::heap_cell(h), addr); - self.registers[arg] = self.heap[h].as_addr(h); + self.registers[arg] = heap_loc_as_cell!(h); } } &QueryInstruction::PutValue(norm, arg) => { @@ -1608,71 +2805,52 @@ impl MachineState { &QueryInstruction::PutVariable(norm, arg) => { match norm { RegType::Perm(n) => { - let e = self.e; - - self[norm] = Addr::StackCell(e, n); + self[norm] = stack_loc_as_cell!(AndFrame, self.e, n); self.registers[arg] = self[norm]; } RegType::Temp(_) => { - let h = self.heap.h(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); - self[norm] = Addr::HeapCell(h); - self.registers[arg] = Addr::HeapCell(h); + self[norm] = heap_loc_as_cell!(h); + self.registers[arg] = heap_loc_as_cell!(h); } }; } - &QueryInstruction::SetConstant(ref c) => { - let addr = self.heap.put_constant(c.clone()); - - if !addr.is_heap_bound() { - self.heap.push(HeapCellValue::Addr(addr)); - } + &QueryInstruction::SetConstant(c) => { + self.heap.push(c); } &QueryInstruction::SetLocalValue(reg) => { let addr = self.deref(self[reg]); - let h = self.heap.h(); + let h = self.heap.len(); - if addr < Ref::HeapCell(h) { - self.heap.push(HeapCellValue::Addr(addr)); + if addr < Ref::heap_cell(h) { + self.heap.push(addr); return; } - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - (self.bind_fn)(self, Ref::HeapCell(h), addr); + self.heap.push(heap_loc_as_cell!(h)); + (self.bind_fn)(self, Ref::heap_cell(h), addr); } &QueryInstruction::SetVariable(reg) => { - let h = self.heap.h(); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self[reg] = Addr::HeapCell(h); + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); + self[reg] = heap_loc_as_cell!(h); } &QueryInstruction::SetValue(reg) => { let heap_val = self.store(self[reg]); - self.heap.push(HeapCellValue::Addr(heap_val)); + self.heap.push(heap_val); } &QueryInstruction::SetVoid(n) => { - let h = self.heap.h(); + let h = self.heap.len(); for i in h..h + n { - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(i))); + self.heap.push(heap_loc_as_cell!(i)); } } } } - pub(super) fn set_ball(&mut self) { - self.ball.reset(); - - let addr = self[temp_v!(1)]; - self.ball.boundary = self.heap.h(); - - copy_term( - CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.ball.stub), - addr, - AttrVarPolicy::DeepCopy, - ); - } - pub(super) fn handle_internal_call_n(&mut self, arity: usize) { let arity = arity + 1; let pred = self.registers[1]; @@ -1692,238 +2870,183 @@ impl MachineState { pub(super) fn setup_call_n(&mut self, arity: usize) -> Option { let addr = self.store(self.deref(self.registers[arity])); - let (name, narity) = match addr { - Addr::Str(a) => { - let result = self.heap.clone(a); - - if let HeapCellValue::NamedStr(narity, name, _) = result { - let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); + let (name, narity) = read_heap_cell!(addr, + (HeapCellValueTag::Str, s) => { + let (name, narity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); - if narity + arity > MAX_ARITY { - let representation_error = self.error_form( - MachineError::representation_error(RepFlag::MaxArity), - stub, - ); + if narity + arity > MAX_ARITY { + let stub = functor_stub(atom!("call"), arity + 1); + let err = self.representation_error(RepFlag::MaxArity); + let representation_error = self.error_form(err, stub); - self.throw_exception(representation_error); - return None; - } + self.throw_exception(representation_error); + return None; + } - for i in (1..arity).rev() { - self.registers[i + narity] = self.registers[i]; - } + for i in (1..arity).rev() { + self.registers[i + narity] = self.registers[i]; + } - for i in 1..narity + 1 { - self.registers[i] = self.heap[a + i].as_addr(a + i); - } + for i in 1..narity + 1 { + self.registers[i] = self.heap[s + i]; + } - (name, narity) + (name, narity) + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + (name, 0) } else { self.fail = true; return None; } } - Addr::Char(c) => (clause_name!(c.to_string(), self.atom_tbl), 0), - Addr::Con(h) => match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => (name.clone(), 0), - _ => { - self.fail = true; - return None; - } - }, - Addr::HeapCell(_) | Addr::StackCell(_, _) => { - let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); - let instantiation_error = - self.error_form(MachineError::instantiation_error(), stub); + (HeapCellValueTag::Char, c) => { + (self.atom_tbl.build_with(&c.to_string()), 0) + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, _h) => { + let stub = functor_stub(atom!("call"), arity + 1); + let err = self.instantiation_error(); + let instantiation_error = self.error_form(err, stub); self.throw_exception(instantiation_error); return None; } - addr => { - let stub = MachineError::functor_stub(clause_name!("call"), arity + 1); - let type_error = self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Callable, addr), - stub, - ); + _ => { + let stub = functor_stub(atom!("call"), arity + 1); + let err = self.type_error(ValidType::Callable, addr); + let type_error = self.error_form(err, stub); self.throw_exception(type_error); - return None; - } - }; - - Some((name, arity + narity - 1)) - } - - pub(super) fn unwind_stack(&mut self) { - self.b = self.block; - self.fail = true; - } - - pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool { - let mut seen = IndexSet::new(); - let mut fail = false; - let mut iter = self.pre_order_iter(addr); - let mut parent_stack = vec![]; - - let is_composite = |addr: Addr| match addr { - Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => true, - _ => false, - }; + return None; + } + ); - 'outer: loop { - if let Some(addr) = iter.stack().last().cloned() { - let addr = self.store(self.deref(addr)); + Some((name, arity + narity - 1)) + } - if is_composite(addr) { - if !seen.contains(&addr) { - seen.insert(addr); - } else { - // when we again encounter a seen composite - // term, check that it precedes itself as a - // parent in the post-order traversal. in the - // future, when value cells have mark bits, - // use them to designate parenthood instead of - // this linear search. - - for (_, prec_addr) in parent_stack.iter().rev().cloned() { - if prec_addr == addr { - fail = true; - break 'outer; - } - } - } + #[inline] + pub fn is_cyclic_term(&mut self, addr: HeapCellValue) -> bool { + if addr.is_constant() { + return false; + } - let arity = match addr { - Addr::Str(h) => match &self.heap[h] { - &HeapCellValue::NamedStr(arity, ..) => arity, - _ => unreachable!(), - }, - _ => 2, - }; + let mut iter = stackful_preorder_iter(&mut self.heap, addr); - parent_stack.push((arity, addr)); - } - } + while let Some(value) = iter.next() { + if value.is_forwarded() { + let value = heap_bound_store(iter.heap, heap_bound_deref(iter.heap, value)); - if iter.next().is_none() { - break; - } else { - while let Some((rem_children, addr)) = parent_stack.pop() { - if rem_children > 0 { - parent_stack.push((rem_children - 1, addr)); - break; - } + if value.is_compound() { + return true; } } } - fail + false } // arg(+N, +Term, ?Arg) - pub(super) fn try_arg(&mut self) -> CallResult { - let stub = MachineError::functor_stub(clause_name!("arg"), 3); - let n = self.store(self.deref(self[temp_v!(1)])); + pub fn try_arg(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("arg"), 3); + let n = self.registers[1]; //self.store(self.deref(self.registers[1])); // TODO: necessary? - match n { - Addr::HeapCell(_) | Addr::StackCell(..) => { + read_heap_cell!(n, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { // 8.5.2.3 a) - return Err(self.error_form(MachineError::instantiation_error(), stub)); + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); } - addr => { - let n = match Number::try_from((addr, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n), - Ok(Number::Integer(n)) => Integer::from(n.as_ref()), + _ => { + let n = match Number::try_from(n) { + Ok(Number::Fixnum(n)) => Number::Fixnum(n), + Ok(Number::Integer(n)) => Number::Integer(n), _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, addr), - stub, - )); + let err = self.type_error(ValidType::Integer, n); + return Err(self.error_form(err, stub_gen())); } }; if n < 0 { // 8.5.2.3 e) - let n = Number::from(n); - let dom_err = MachineError::domain_error(DomainErrorType::NotLessThanZero, n); - - return Err(self.error_form(dom_err, stub)); + let err = self.domain_error(DomainErrorType::NotLessThanZero, n); + return Err(self.error_form(err, stub_gen())); } - let n = match n.to_usize() { - Some(n) => n, - None => { + let n = match n { + Number::Fixnum(n) => n.get_num() as usize, + Number::Integer(n) => n.to_usize().unwrap(), + _ => { self.fail = true; return Ok(()); } }; - let term = self.store(self.deref(self[temp_v!(2)])); + let term = self.deref(self.registers[2]); - match term { - Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(_) => { - // 8.5.2.3 b) - return Err(self.error_form(MachineError::instantiation_error(), stub)); + read_heap_cell!(self.store(term), + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); } - Addr::Str(o) => match self.heap.clone(o) { - HeapCellValue::NamedStr(arity, _, _) if 1 <= n && n <= arity => { - let a3 = self[temp_v!(3)]; - let h_a = Addr::HeapCell(o + n); + (HeapCellValueTag::Str, o) => { + let arity = cell_as_atom_cell!(self.heap[o]).get_arity(); - (self.unify_fn)(self, a3, h_a); - } - _ => { + if 1 <= n && n <= arity { + let a3 = self.registers[3]; + unify_fn!(self, a3, heap_loc_as_cell!(o + n)); + } else { self.fail = true; } - }, - Addr::Lis(l) => { + } + (HeapCellValueTag::Lis, l) => { if n == 1 || n == 2 { - let a3 = self[temp_v!(3)]; - let h_a = Addr::HeapCell(l + n - 1); - - (self.unify_fn)(self, a3, h_a); + let a3 = self.registers[3]; + unify_fn!(self, a3, heap_loc_as_cell!(l + n - 1)); } else { self.fail = true; } } - Addr::PStrLocation(h, offset) => { + (HeapCellValueTag::PStrLoc, pstr_loc) => { if n == 1 || n == 2 { - let a3 = self[temp_v!(3)]; - let h_a = - if let HeapCellValue::PartialString(ref pstr, _) = &self.heap[h] { - if let Some(c) = pstr.range_from(offset..).next() { - if n == 1 { - Addr::Char(c) - } else { - Addr::PStrLocation(h, offset + c.len_utf8()) - } - } else { - unreachable!() - } + let a3 = self.registers[3]; + let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc); + + let pstr = cell_as_string!(self.heap[h]); + let offset = offset.get_num() as usize; + + if let Some(c) = pstr.as_str_from(offset).chars().next() { + if n == 1 { + self.unify_char(c, a3); } else { - unreachable!() - }; + let offset = (offset + c.len_utf8()) as i64; + let h_len = self.heap.len(); - (self.unify_fn)(self, a3, h_a); + self.heap.push(pstr_offset_as_cell!(h_len)); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); + + unify_fn!(self, pstr_loc_as_cell!(h_len), a3); + } + } else { + unreachable!() + } } else { self.fail = true; } } _ => { // 8.5.2.3 d) - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Compound, term), - stub, - )); + let err = self.type_error(ValidType::Compound, term); + return Err(self.error_form(err, stub_gen())); } - } + ) } - } + ); Ok(()) } - fn compare_numbers(&mut self, cmp: CompareNumberQT, n1: Number, n2: Number) { + pub fn compare_numbers(&mut self, cmp: CompareNumberQT, n1: Number, n2: Number) { let ordering = n1.cmp(&n2); self.fail = match cmp { @@ -1939,403 +3062,52 @@ impl MachineState { self.p += 1; } - pub(super) fn compare_term(&mut self, qt: CompareTermQT) { - let a1 = self[temp_v!(1)]; - let a2 = self[temp_v!(2)]; + pub fn compare_term(&mut self, qt: CompareTermQT) { + let a1 = self.registers[1]; + let a2 = self.registers[2]; - match self.compare_term_test(&a1, &a2) { + match compare_term_test!(self, a1, a2) { Some(Ordering::Greater) => match qt { - CompareTermQT::GreaterThan | CompareTermQT::GreaterThanOrEqual => return, + CompareTermQT::GreaterThan | CompareTermQT::GreaterThanOrEqual => {} _ => self.fail = true, }, Some(Ordering::Equal) => match qt { - CompareTermQT::GreaterThanOrEqual | CompareTermQT::LessThanOrEqual => return, + CompareTermQT::GreaterThanOrEqual | CompareTermQT::LessThanOrEqual => {} _ => self.fail = true, }, Some(Ordering::Less) => match qt { - CompareTermQT::LessThan | CompareTermQT::LessThanOrEqual => return, + CompareTermQT::LessThan | CompareTermQT::LessThanOrEqual => {} _ => self.fail = true, }, None => { self.fail = true; } - }; + } } - // returns true on failure. - pub(super) fn eq_test(&self, a1: Addr, a2: Addr) -> bool { - let mut iter = self.zipped_acyclic_pre_order_iter(a1, a2); - - while let Some((v1, v2)) = iter.next() { - match (v1, v2) { - (Addr::Str(s1), Addr::Str(s2)) => { - if let HeapCellValue::NamedStr(ar1, n1, _) = &self.heap[s1] { - if let HeapCellValue::NamedStr(ar2, n2, _) = &self.heap[s2] { - if ar1 != ar2 || n1 != n2 { - return true; - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (Addr::PStrLocation(..), Addr::Lis(_)) | (Addr::Lis(_), Addr::PStrLocation(..)) => { - continue; - } - (pstr1 @ Addr::PStrLocation(..), pstr2 @ Addr::PStrLocation(..)) => { - let mut i1 = self.heap_pstr_iter(pstr1); - let mut i2 = self.heap_pstr_iter(pstr2); - - let ordering = compare_pstr_prefixes(&mut i1, &mut i2); - - if let Some(ordering) = ordering { - if ordering != Ordering::Equal { - return true; - } - } - - let (lstack, rstack) = iter.stack(); - - lstack.pop(); - lstack.pop(); - - rstack.pop(); - rstack.pop(); - - lstack.push(i1.focus()); - rstack.push(i2.focus()); - } - (Addr::Lis(_), Addr::Lis(_)) => { - continue; - } - (Addr::Con(h1), Addr::Con(h2)) => match (&self.heap[h1], &self.heap[h2]) { - ( - &HeapCellValue::Atom(ref n1, ref spec_1), - &HeapCellValue::Atom(ref n2, ref spec_2), - ) => { - if n1 != n2 || spec_1 != spec_2 { - return true; - } - } - (&HeapCellValue::DBRef(ref db_ref_1), &HeapCellValue::DBRef(ref db_ref_2)) => { - if db_ref_1 != db_ref_2 { - return true; - } - } - (v1, v2) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 == n2 { - continue; - } - } - } - - return true; - } - }, - (Addr::Con(h), Addr::Char(c)) | (Addr::Char(c), Addr::Con(h)) => { - match &self.heap[h] { - &HeapCellValue::Atom(ref name, _) if name.is_char() => { - if name.as_str().chars().next() != Some(c) { - return true; - } - } - _ => { - return true; - } - } - } - (a1, a2) => { - if let Ok(n1) = Number::try_from((a1, &self.heap)) { - if let Ok(n2) = Number::try_from((a2, &self.heap)) { - if n1 != n2 { - return true; - } else { - continue; - } - } - } - - if a1 != a2 { - return true; - } - } - } + // returns true on failure, false on success. + pub fn eq_test(&mut self, h1: HeapCellValue, h2: HeapCellValue) -> bool { + if h1 == h2 { + return false; } - // did the two iterators expire at the same step? - iter.first_to_expire != Ordering::Equal + compare_term_test!(self, h1, h2) + .map(|o| o != Ordering::Equal) + .unwrap_or(true) } - pub(super) fn compare_term_test(&self, a1: &Addr, a2: &Addr) -> Option { - let mut iter = self.zipped_acyclic_pre_order_iter(*a1, *a2); - - while let Some((v1, v2)) = iter.next() { - let order_cat_v1 = v1.order_category(&self.heap); - let order_cat_v2 = v2.order_category(&self.heap); - - if order_cat_v1 != order_cat_v2 { - return Some(order_cat_v1.cmp(&order_cat_v2)); + pub fn reset_block(&mut self, addr: HeapCellValue) { + read_heap_cell!(self.store(addr), + (HeapCellValueTag::Fixnum, n) => { + self.block = n.get_num() as usize; } - - match order_cat_v1 { - Some(TermOrderCategory::Variable) => { - let v1 = v1.as_var().unwrap(); - let v2 = v2.as_var().unwrap(); - - if v1 != v2 { - return Some(v1.cmp(&v2)); - } - } - Some(TermOrderCategory::FloatingPoint) => { - if let Addr::Float(f1) = v1 { - if let Addr::Float(f2) = v2 { - return Some(f1.cmp(&f2)); - } else { - unreachable!() - } - } else { - unreachable!() - } - } - Some(TermOrderCategory::Integer) => match (v1, v2) { - (Addr::Con(h1), Addr::Con(h2)) => { - if let Ok(n1) = Number::try_from(&self.heap[h1]) { - if let Ok(n2) = Number::try_from(&self.heap[h2]) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (Addr::Con(h1), v2) => { - if let Ok(n1) = Number::try_from(&self.heap[h1]) { - if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (v1, Addr::Con(h2)) => { - if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) { - if let Ok(n2) = Number::try_from(&self.heap[h2]) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (v1, v2) => { - if let Ok(n1) = Number::try_from(&HeapCellValue::Addr(v1)) { - if let Ok(n2) = Number::try_from(&HeapCellValue::Addr(v2)) { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - }, - Some(TermOrderCategory::Atom) => match (v1, v2) { - (Addr::Con(h1), Addr::Con(h2)) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { - if let HeapCellValue::Atom(ref n2, _) = &self.heap[h2] { - if n1 != n2 { - return Some(n1.cmp(&n2)); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (Addr::Con(h1), Addr::Char(c)) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { - if n1.is_char() { - if n1.as_str().chars().next() != Some(c) { - return Some(n1.as_str().chars().next().cmp(&Some(c))); - } - } else { - return Some(Ordering::Greater); - } - } else { - unreachable!() - } - } - (Addr::Char(c), Addr::Con(h1)) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h1] { - if n1.is_char() { - if n1.as_str().chars().next() != Some(c) { - return Some(Some(c).cmp(&n1.as_str().chars().next())); - } - } else { - return Some(Ordering::Less); - } - } else { - unreachable!() - } - } - (Addr::EmptyList, Addr::Con(h)) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { - if "[]" != n1.as_str() { - return Some("[]".cmp(n1.as_str())); - } - } else { - unreachable!() - } - } - (Addr::Con(h), Addr::EmptyList) => { - if let HeapCellValue::Atom(ref n1, _) = &self.heap[h] { - if "[]" != n1.as_str() { - return Some(n1.as_str().cmp("[]")); - } - } else { - unreachable!() - } - } - (Addr::Char(c1), Addr::Char(c2)) => { - if c1 != c2 { - return Some(c1.cmp(&c2)); - } - } - (Addr::Char(c), Addr::EmptyList) => { - return if c == '[' { - Some(Ordering::Less) - } else { - Some(c.cmp(&'[')) - }; - } - (Addr::EmptyList, Addr::Char(c)) => { - return if c == '[' { - Some(Ordering::Greater) - } else { - Some('['.cmp(&c)) - }; - } - (Addr::EmptyList, Addr::EmptyList) => {} - _ => { - return None; - } - }, - Some(TermOrderCategory::Compound) => match (v1, v2) { - (Addr::Lis(_), Addr::Lis(_)) => {} - (pstr1 @ Addr::PStrLocation(..), pstr2 @ Addr::PStrLocation(..)) => { - let mut i1 = self.heap_pstr_iter(pstr1); - let mut i2 = self.heap_pstr_iter(pstr2); - - let ordering = compare_pstr_prefixes(&mut i1, &mut i2); - - if let Some(ordering) = ordering { - if ordering != Ordering::Equal { - return Some(ordering); - } - } else { - let (lstack, rstack) = iter.stack(); - - lstack.pop(); - lstack.pop(); - - rstack.pop(); - rstack.pop(); - - lstack.push(i1.focus()); - rstack.push(i2.focus()); - } - } - (Addr::Str(h1), Addr::Str(h2)) => { - if let HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[h1] { - if let HeapCellValue::NamedStr(a2, ref n2, _) = &self.heap[h2] { - if a1 != a2 || n1.as_str() != n2.as_str() { - return Some( - a1.cmp(&a2).then_with(|| n1.as_str().cmp(n2.as_str())), - ); - } - } else { - unreachable!() - } - } else { - unreachable!() - } - } - (Addr::Lis(_), Addr::PStrLocation(..)) - | (Addr::PStrLocation(..), Addr::Lis(_)) => {} - (Addr::Lis(_), Addr::Str(s)) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp("."))); - } - } else { - unreachable!() - } - } - (Addr::Str(s), Addr::Lis(_)) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str()))); - } - } else { - unreachable!() - } - } - (Addr::PStrLocation(..), Addr::Str(s)) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(a1.cmp(&2).then_with(|| n1.as_str().cmp("."))); - } - } else { - unreachable!() - } - } - (Addr::Str(s), Addr::PStrLocation(..)) => { - if let &HeapCellValue::NamedStr(a1, ref n1, _) = &self.heap[s] { - if a1 != 2 || n1.as_str() != "." { - return Some(2.cmp(&a1).then_with(|| ".".cmp(n1.as_str()))); - } - } else { - unreachable!() - } - } - _ => { - return None; - } - }, - None => { - return None; - } + _ => { + self.fail = true; } - } - - Some(iter.first_to_expire) - } - - pub(super) fn reset_block(&mut self, addr: Addr) { - match self.store(addr) { - Addr::Usize(b) => self.block = b, - _ => self.fail = true, - }; + ) } - pub(super) fn execute_inlined(&mut self, inlined: &InlinedClauseType) { + pub fn execute_inlined(&mut self, inlined: &InlinedClauseType) { match inlined { &InlinedClauseType::CompareNumber(cmp, ref at_1, ref at_2) => { let n1 = try_or_fail!(self, self.get_number(at_1)); @@ -2346,36 +3118,46 @@ impl MachineState { &InlinedClauseType::IsAtom(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::Con(h) => { - if let HeapCellValue::Atom(..) = &self.heap[h] { + read_heap_cell!(d, + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + self.p += 1; + } else { + self.fail = true; + } + } + (HeapCellValueTag::Char) => { + self.p += 1; + } + _ => { + self.fail = true; + } + ); + } + &InlinedClauseType::IsAtomic(r1) => { + let d = self.store(self.deref(self[r1])); + + read_heap_cell!(d, + (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + HeapCellValueTag::Cons) => { + self.p += 1; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { self.p += 1; } else { self.fail = true; } } - Addr::Char(_) => self.p += 1, - Addr::EmptyList => self.p += 1, - _ => self.fail = true, - }; - } - &InlinedClauseType::IsAtomic(r1) => { - let d = self.store(self.deref(self[r1])); - - match d { - Addr::Char(_) - | Addr::Con(_) - | Addr::EmptyList - | Addr::Fixnum(_) - | Addr::Float(_) - | Addr::Usize(_) => self.p += 1, - _ => self.fail = true, - }; + _ => { + self.fail = true; + } + ); } &InlinedClauseType::IsInteger(r1) => { let d = self.store(self.deref(self[r1])); - match Number::try_from((d, &self.heap)) { + match Number::try_from(d) { Ok(Number::Fixnum(_)) => { self.p += 1; } @@ -2397,22 +3179,39 @@ impl MachineState { &InlinedClauseType::IsCompound(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => self.p += 1, - _ => self.fail = true, - }; + read_heap_cell!(d, + (HeapCellValueTag::Str | HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { + self.p += 1; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity > 0 { + self.p += 1; + } else { + self.fail = true; + } + } + _ => { + self.fail = true; + } + ); } &InlinedClauseType::IsFloat(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::Float(_) => self.p += 1, - _ => self.fail = true, - }; + match Number::try_from(d) { + Ok(Number::Float(_)) => { + self.p += 1; + } + _ => { + self.fail = true; + } + } } - &InlinedClauseType::IsNumber(r1) => match self.store(self.deref(self[r1])) { - Addr::Float(_) => self.p += 1, - d => match Number::try_from((d, &self.heap)) { + &InlinedClauseType::IsNumber(r1) => { + let d = self.store(self.deref(self[r1])); + + match Number::try_from(d) { Ok(Number::Fixnum(_)) => { self.p += 1; } @@ -2429,156 +3228,134 @@ impl MachineState { _ => { self.fail = true; } - }, - }, + } + } &InlinedClauseType::IsRational(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::Con(h) => { - if let HeapCellValue::Rational(_) = &self.heap[h] { - self.p += 1; - } else { - self.fail = true; - } + read_heap_cell!(d, + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Rational, _r) => { + self.p += 1; + } + _ => { + self.fail = true; + } + ); } _ => { self.fail = true; } - }; + ); } &InlinedClauseType::IsNonVar(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { + match d.get_tag() { + HeapCellValueTag::AttrVar + | HeapCellValueTag::Var + | HeapCellValueTag::StackVar => { self.fail = true; } _ => { self.p += 1; } - }; + } } &InlinedClauseType::IsVar(r1) => { let d = self.store(self.deref(self[r1])); - match d { - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(_, _) => { + match d.get_tag() { + HeapCellValueTag::AttrVar + | HeapCellValueTag::Var + | HeapCellValueTag::StackVar => { self.p += 1; } _ => { self.fail = true; } - }; + } } } } - fn try_functor_compound_case( - &mut self, - name: ClauseName, - arity: usize, - spec: Option, - ) { - let name = self.heap.to_unifiable(HeapCellValue::Atom(name, spec)); - self.try_functor_unify_components(name, arity); + #[inline(always)] + fn try_functor_compound_case(&mut self, name: Atom, arity: usize) { + self.try_functor_unify_components(atom_as_cell!(name), arity); } - fn try_functor_unify_components(&mut self, name: Addr, arity: usize) { - let a2 = self[temp_v!(2)]; - let a3 = self[temp_v!(3)]; - - (self.unify_fn)(self, a2, name); + fn try_functor_unify_components(&mut self, name: HeapCellValue, arity: usize) { + let a2 = self.deref(self.registers[2]); + self.write_literal_to_var(a2, name); if !self.fail { - (self.unify_fn)(self, a3, Addr::Usize(arity)); + let a3 = self.store(self.deref(self.registers[3])); + self.unify_fixnum(Fixnum::build_with(arity as i64), a3); } } - fn try_functor_fabricate_struct( - &mut self, - name: ClauseName, - arity: usize, - spec: Option, - op_dir: &OpDir, - r: Ref, - ) { - let spec = spec.and_then(|spec| { - if spec.arity() != arity { - fetch_op_spec(name.clone(), arity, op_dir) - } else { - Some(spec) - } - }); + fn try_functor_fabricate_struct(&mut self, name: Atom, arity: usize, r: Ref) { + let h = self.heap.len(); + + let f_a = if name == atom!(".") && arity == 2 { + self.heap.push(heap_loc_as_cell!(h)); + self.heap.push(heap_loc_as_cell!(h+1)); - let f_a = if name.as_str() == "." && arity == 2 { - Addr::Lis(self.heap.h()) + list_loc_as_cell!(h) } else { - self.heap - .to_unifiable(HeapCellValue::NamedStr(arity, name, spec)) - }; + self.heap.push(atom_as_cell!(name, arity)); - let h = self.heap.h(); + for i in 0..arity { + self.heap.push(heap_loc_as_cell!(h + i + 1)); + } - for i in 0..arity { - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + i))); - } + str_loc_as_cell!(h) + }; (self.bind_fn)(self, r, f_a); } - pub(super) fn try_functor(&mut self, op_dir: &OpDir) -> CallResult { - let stub = MachineError::functor_stub(clause_name!("functor"), 3); - let a1 = self.store(self.deref(self[temp_v!(1)])); + pub fn try_functor(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("functor"), 3); + let a1 = self.store(self.deref(self.registers[1])); - match a1 { - Addr::Stream(_) => { - self.fail = true; + read_heap_cell!(a1, + (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum | + HeapCellValueTag::F64) => { + self.try_functor_unify_components(a1, 0); } - Addr::Char(_) - | Addr::Con(_) - | Addr::Fixnum(_) - | Addr::Float(_) - | Addr::EmptyList - | Addr::Usize(_) => { + (HeapCellValueTag::Atom, (_name, arity)) => { + debug_assert_eq!(arity, 0); self.try_functor_unify_components(a1, 0); } - Addr::Str(o) => match self.heap.clone(o) { - HeapCellValue::NamedStr(arity, name, spec) => { - let spec = fetch_op_spec_from_existing(name.clone(), arity, spec, &op_dir); - - self.try_functor_compound_case(name, arity, spec) - } - _ => { - self.fail = true; - } - }, - Addr::Lis(_) | Addr::PStrLocation(..) => { - let spec = fetch_op_spec_from_existing(clause_name!("."), 2, None, &op_dir); - - self.try_functor_compound_case(clause_name!("."), 2, spec) + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + self.try_functor_compound_case(name, arity); + } + (HeapCellValueTag::Lis | HeapCellValueTag::PStrOffset) => { + self.try_functor_compound_case(atom!("."), 2); } - Addr::AttrVar(..) | Addr::HeapCell(_) | Addr::StackCell(..) => { - let name = self.store(self.deref(self[temp_v!(2)])); - let arity = self.store(self.deref(self[temp_v!(3)])); + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let deref_name = self.deref(self.registers[2]); + let store_name = self.store(deref_name); - if name.is_ref() || arity.is_ref() { + let arity = self.store(self.deref(self.registers[3])); + + if store_name.is_var() || arity.is_var() { // 8.5.1.3 a) & 8.5.1.3 b) - return Err(self.error_form(MachineError::instantiation_error(), stub)); - } - - let arity = match Number::try_from((arity, &self.heap)) { - Ok(Number::Fixnum(n)) => Some(n), - Ok(Number::Integer(n)) => n.to_isize(), - Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().to_isize(), - _ => match arity { - arity => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, arity), - stub, - )); - } - }, + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); + } + + let arity = match Number::try_from(arity) { + Ok(Number::Fixnum(n)) => Some(n.get_num()), + Ok(Number::Integer(n)) => n.to_i64(), + Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().to_i64(), + _ => { + let err = self.type_error(ValidType::Integer, arity); + return Err(self.error_form(err, stub_gen())); + } }; let arity = match arity { @@ -2589,449 +3366,276 @@ impl MachineState { } }; - if arity > MAX_ARITY as isize { + if arity > MAX_ARITY as i64 { // 8.5.1.3 f) - let rep_err = MachineError::representation_error(RepFlag::MaxArity); - return Err(self.error_form(rep_err, stub)); + let err = self.representation_error(RepFlag::MaxArity); + return Err(self.error_form(err, stub_gen())); } else if arity < 0 { // 8.5.1.3 g) - let arity = Number::Integer(Rc::new(Integer::from(arity))); - let dom_err = - MachineError::domain_error(DomainErrorType::NotLessThanZero, arity); - - return Err(self.error_form(dom_err, stub)); - } - - match name { - Addr::Char(_) - | Addr::Con(_) - | Addr::Fixnum(_) - | Addr::Float(_) - | Addr::EmptyList - | Addr::PStrLocation(..) - | Addr::Usize(_) - if arity == 0 => - { - (self.unify_fn)(self, a1, name); - } - Addr::Con(h) => { - if let HeapCellValue::Atom(name, spec) = self.heap.clone(h) { - self.try_functor_fabricate_struct( - name, - arity as usize, - spec, - &op_dir, - a1.as_var().unwrap(), - ); - } else { - // 8.5.1.3 e) - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Atom, name), - stub, - )); - } + let arity = Number::Fixnum(Fixnum::build_with(arity)); + let err = self.domain_error(DomainErrorType::NotLessThanZero, arity); + + return Err(self.error_form(err, stub_gen())); + } + + read_heap_cell!(store_name, + (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum | + HeapCellValueTag::F64) if arity == 0 => { + self.bind(a1.as_var().unwrap(), deref_name); + } + (HeapCellValueTag::Atom, (name, atom_arity)) => { + debug_assert_eq!(atom_arity, 0); + self.try_functor_fabricate_struct( + name, + arity as usize, + a1.as_var().unwrap(), + ); } - Addr::Char(c) => { + (HeapCellValueTag::Char, c) => { + let c = self.atom_tbl.build_with(&c.to_string()); + self.try_functor_fabricate_struct( - clause_name!(c.to_string(), self.atom_tbl), + c, arity as usize, - None, - &op_dir, a1.as_var().unwrap(), ); } _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Atomic, name), - stub, - )); + let err = self.type_error(ValidType::Atomic, store_name); + return Err(self.error_form(err, stub_gen())); } // 8.5.1.3 c) - } + ); } _ => { self.fail = true; } - } + ); Ok(()) } - pub(super) fn term_dedup(&self, list: &mut Vec) { - let mut result = vec![]; - - for a2 in list.iter() { - if let Some(a1) = result.last() { - if self.compare_term_test(&a1, &a2) == Some(Ordering::Equal) { - continue; + pub fn try_from_list( + &mut self, + value: HeapCellValue, + stub_gen: impl Fn() -> FunctorStub, + ) -> Result, MachineStub> { + let deref_v = self.deref(value); + let store_v = self.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::Lis, l) => { + self.try_from_inner_list(vec![], l, stub_gen, store_v) + } + (HeapCellValueTag::PStrLoc, h) => { + self.try_from_partial_string(vec![], h, stub_gen, store_v) + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { + let err = self.instantiation_error(); + Err(self.error_form(err, stub_gen())) + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { + Ok(vec![]) + } else { + let err = self.type_error(ValidType::List, store_v); + Err(self.error_form(err, stub_gen())) } } - - result.push(*a2); - } - - *list = result; - } - - pub(super) fn integers_to_bytevec(&self, r: RegType, caller: MachineStub) -> Vec { - let mut bytes: Vec = Vec::new(); - - match self.try_from_list(r, caller) { - Err(_) => { - unreachable!() - } - Ok(addrs) => { - for addr in addrs { - let addr = self.store(self.deref(addr)); - - match Number::try_from((addr, &self.heap)) { - Ok(Number::Fixnum(n)) => { - match u8::try_from(n) { - Ok(b) => { - bytes.push(b); - } - Err(_) => {} - } - - continue; - } - Ok(Number::Integer(n)) => { - if let Some(b) = n.to_u8() { - bytes.push(b); - } - - continue; - } - _ => {} - } - } + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = cstr_atom.as_str(); + Ok(cstr.chars().map(|c| char_as_cell!(c)).collect()) + } + _ => { + let err = self.type_error(ValidType::List, store_v); + Err(self.error_form(err, stub_gen())) } - } - bytes - } - - pub(super) fn try_from_list( - &self, - r: RegType, - caller: MachineStub, - ) -> Result, MachineStub> { - let a1 = self.store(self.deref(self[r])); - - match a1 { - Addr::Lis(l) => self.try_from_inner_list(vec![], l, caller, a1), - Addr::PStrLocation(h, n) => self.try_from_partial_string(vec![], h, n, caller, a1), - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { - Err(self.error_form(MachineError::instantiation_error(), caller)) - } - Addr::EmptyList => Ok(vec![]), - _ => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::List, a1), - caller, - )), - } + ) } fn try_from_inner_list( - &self, - mut result: Vec, + &mut self, + mut result: Vec, mut l: usize, - caller: MachineStub, - a1: Addr, - ) -> Result, MachineStub> { - result.push(self.heap[l].as_addr(l)); + stub_gen: impl Fn() -> FunctorStub, + a1: HeapCellValue, + ) -> Result, MachineStub> { + result.push(self.heap[l]); l += 1; loop { - match &self.heap[l] { - HeapCellValue::Addr(ref addr) => match self.store(self.deref(*addr)) { - Addr::Lis(hcp) => { - result.push(self.heap[hcp].as_addr(hcp)); - l = hcp + 1; - } - Addr::PStrLocation(h, n) => { - return self.try_from_partial_string(result, h, n, caller, a1); - } - Addr::EmptyList => { + let deref_v = self.deref(self.heap[l]); + let store_v = self.store(self.heap[l]); + + read_heap_cell!(store_v, + (HeapCellValueTag::Lis, hcp) => { + result.push(self.heap[hcp]); + l = hcp + 1; + } + (HeapCellValueTag::PStrOffset) => { + return self.try_from_partial_string(result, deref_v.get_value(), stub_gen, a1); + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { break; + } else { + let err = self.type_error(ValidType::List, a1); + return Err(self.error_form(err, stub_gen())); } - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { - return Err(self.error_form(MachineError::instantiation_error(), caller)) - } - _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::List, a1), - caller, - )) - } - }, + } _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::List, a1), - caller, - )) + if store_v.is_var() { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); + } else { + let err = self.type_error(ValidType::List, a1); + return Err(self.error_form(err, stub_gen())); + } } - } + ); } Ok(result) } fn try_from_partial_string( - &self, - mut chars: Vec, - mut h: usize, - mut n: usize, - caller: MachineStub, - a1: Addr, - ) -> Result, MachineStub> { - loop { - if let &HeapCellValue::PartialString(ref pstr, has_tail) = &self.heap[h] { - chars.extend(pstr.range_from(n..).map(Addr::Char)); - - if !has_tail { - return Ok(chars); + &mut self, + mut chars: Vec, + h: usize, + stub_gen: impl Fn() -> FunctorStub, + a1: HeapCellValue, + ) -> Result, MachineStub> { + let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h); + + while let Some(iteratee) = heap_pstr_iter.next() { + match iteratee { + PStrIteratee::Char(_, c) => + chars.push(char_as_cell!(c)), + PStrIteratee::PStrSegment(_, pstr_atom, n) => { + let pstr = PartialString::from(pstr_atom); + chars.extend(pstr.as_str_from(n).chars().map(|c| char_as_cell!(c))); } + } + } - let tail = self.heap[h + 1].as_addr(h + 1); - - match self.store(self.deref(tail)) { - Addr::EmptyList => { - return Ok(chars); - } - Addr::Lis(l) => { - return self.try_from_inner_list(chars, l, caller, a1); - } - Addr::PStrLocation(h1, n1) => { - chars.push(Addr::Char('\u{0}')); - - h = h1; - n = n1; - } - _ => { - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::List, a1), - caller, - )) - } + match self.heap[h].get_tag() { + HeapCellValueTag::PStr => { + if heap_pstr_iter.at_string_terminator() { + Ok(chars) + } else { + read_heap_cell!(self.heap[heap_pstr_iter.focus()], + (HeapCellValueTag::Lis, l) => { + self.try_from_inner_list(chars, l, stub_gen, a1) + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!(".") && arity == 2 { + let l = heap_pstr_iter.focus() + 1; + self.try_from_inner_list(chars, l, stub_gen, a1) + } else { + let err = self.type_error(ValidType::List, a1); + Err(self.error_form(err, stub_gen())) + } + } + _ => { + let err = self.type_error(ValidType::List, a1); + Err(self.error_form(err, stub_gen())) + } + ) } - } else { + } + HeapCellValueTag::CStr => Ok(chars), + _ => { unreachable!() } } } - // see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide. - pub(super) fn project_onto_key(&self, a: Addr) -> Result { - let stub = MachineError::functor_stub(clause_name!("keysort"), 2); - - match self.store(self.deref(a)) { - Addr::HeapCell(_) | Addr::StackCell(..) => { - Err(self.error_form(MachineError::instantiation_error(), stub)) - } - Addr::Str(s) => match self.heap.clone(s) { - HeapCellValue::NamedStr(2, ref name, Some(_)) if *name == clause_name!("-") => { - Ok(Addr::HeapCell(s + 1)) - } - _ => Err(self.error_form( - MachineError::type_error( - self.heap.h(), - ValidType::Pair, - self.heap[s].as_addr(s), - ), - stub, - )), - }, - a => Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Pair, a), - stub, - )), + // returns true on failure. + pub fn ground_test(&mut self) -> bool { + if self.registers[1].is_constant() { + return false; } - } - pub(super) fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { - let old_h = self.heap.h(); + let value = self.registers[1]; - let a1 = self[temp_v!(1)]; - let a2 = self[temp_v!(2)]; - - copy_term(CopyTerm::new(self), a1, attr_var_policy); + for v in stackful_preorder_iter(&mut self.heap, value) { + if v.is_var() { + return true; + } + } - (self.unify_fn)(self, Addr::HeapCell(old_h), a2); + false } - // returns true on failure. - pub(super) fn structural_eq_test(&self) -> bool { - let a1 = self[temp_v!(1)]; - let a2 = self[temp_v!(2)]; - - let mut var_pairs = IndexMap::new(); - - let iter = self.zipped_acyclic_pre_order_iter(a1, a2); - - for (v1, v2) in iter { - match ( - self.heap.index_addr(&v1).as_ref(), - self.heap.index_addr(&v2).as_ref(), - ) { - ( - HeapCellValue::Addr(Addr::Lis(_)), - HeapCellValue::Addr(Addr::PStrLocation(..)), - ) - | ( - HeapCellValue::Addr(Addr::PStrLocation(..)), - HeapCellValue::Addr(Addr::Lis(_)), - ) => {} - (HeapCellValue::NamedStr(ar1, n1, _), HeapCellValue::NamedStr(ar2, n2, _)) => { - if ar1 != ar2 || n1 != n2 { - return true; - } - } - (HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) => {} - ( - &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), - &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::StackCell(..)), - &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), - &HeapCellValue::Addr(v2 @ Addr::AttrVar(_)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), - &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::AttrVar(_)), - &HeapCellValue::Addr(v2 @ Addr::StackCell(..)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), - &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::HeapCell(_)), - &HeapCellValue::Addr(v2 @ Addr::StackCell(..)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::StackCell(..)), - &HeapCellValue::Addr(v2 @ Addr::StackCell(..)), - ) - | ( - &HeapCellValue::Addr(v1 @ Addr::StackCell(..)), - &HeapCellValue::Addr(v2 @ Addr::HeapCell(_)), - ) => match (var_pairs.get(&v1), var_pairs.get(&v2)) { - (Some(ref v2_p), Some(ref v1_p)) if **v1_p == v1 && **v2_p == v2 => { - continue; - } - (Some(_), _) | (_, Some(_)) => { - return true; - } - (None, None) => { - var_pairs.insert(v1, v2); - var_pairs.insert(v2, v1); - } - }, - ( - HeapCellValue::PartialString(ref pstr1, has_tail_1), - HeapCellValue::PartialString(ref pstr2, has_tail_2), - ) => { - if has_tail_1 != has_tail_2 { - return true; - } - - let pstr1_iter = pstr1.range_from(0..); - let pstr2_iter = pstr2.range_from(0..); + pub fn integers_to_bytevec( + &mut self, + value: HeapCellValue, + stub_gen: impl Fn() -> FunctorStub, + ) -> Vec { + let mut bytes: Vec = Vec::new(); - for (c1, c2) in pstr1_iter.zip(pstr2_iter) { - if c1 != c2 { - return true; - } - } - } - ( - HeapCellValue::Addr(Addr::PStrLocation(..)), - HeapCellValue::Addr(Addr::PStrLocation(..)), - ) => {} - ( - HeapCellValue::Atom(ref n1, ref spec_1), - HeapCellValue::Atom(ref n2, ref spec_2), - ) => { - if n1 != n2 || spec_1 != spec_2 { - return true; - } - } - (HeapCellValue::DBRef(ref db_ref_1), HeapCellValue::DBRef(ref db_ref_2)) => { - if db_ref_1 != db_ref_2 { - return true; - } - } - (v1, v2) => { - if let Ok(n1) = Number::try_from(v1) { - if let Ok(n2) = Number::try_from(v2) { - if n1 != n2 { - return true; - } else { - continue; - } - } else { - return true; - } - } + match self.try_from_list(value, stub_gen) { + Err(_) => { + unreachable!() + } + Ok(addrs) => { + for addr in addrs { + let addr = self.store(self.deref(addr)); - match (v1, v2) { - (HeapCellValue::Addr(a1), HeapCellValue::Addr(a2)) => { - if a1 != a2 { - return true; + match Number::try_from(addr) { + Ok(Number::Fixnum(n)) => match u8::try_from(n.get_num()) { + Ok(b) => bytes.push(b), + Err(_) => {} + }, + Ok(Number::Integer(n)) => { + if let Some(b) = n.to_u8() { + bytes.push(b); } } - _ => { - return true; - } + _ => {} } } } } - false + bytes } - // returns true on failure. - pub(super) fn ground_test(&self) -> bool { - let a = self.store(self.deref(self[temp_v!(1)])); - - for v in self.acyclic_pre_order_iter(a) { - match v { - Addr::HeapCell(..) => return true, - Addr::StackCell(..) => return true, - Addr::AttrVar(..) => return true, - _ => {} - } + // see 8.4.4.3 of Draft Technical Corrigendum 2 for an error guide. + pub fn project_onto_key(&mut self, value: HeapCellValue) -> Result { + let stub_gen = || functor_stub(atom!("keysort"), 2); + let store_v = self.store(self.deref(value)); + + if store_v.is_var() { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); } - false + read_heap_cell!(store_v, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + + if name == atom!("-") && arity == 2 { + Ok(heap_loc_as_cell!(s + 1)) + } else { + let err = self.type_error(ValidType::Pair, self.heap[s]); + Err(self.error_form(err, stub_gen())) + } + } + _ => { + let err = self.type_error(ValidType::Pair, store_v); + Err(self.error_form(err, stub_gen())) + } + ) } - pub(super) fn setup_built_in_call(&mut self, ct: BuiltInClauseType) { + pub fn setup_built_in_call(&mut self, ct: BuiltInClauseType) { self.num_of_args = ct.arity(); self.b0 = self.b; self.p = CodePtr::BuiltInClause(ct, self.p.local()); } - pub(super) fn allocate(&mut self, num_cells: usize) { - let e = self.stack.allocate_and_frame(num_cells); - let and_frame = self.stack.index_and_frame_mut(e); - - and_frame.prelude.e = self.e; - and_frame.prelude.cp = self.cp; - - self.e = e; - self.p += 1; - } - - pub(super) fn deallocate(&mut self) { + pub fn deallocate(&mut self) { let e = self.e; let frame = self.stack.index_and_frame(e); @@ -3046,8 +3650,8 @@ impl MachineState { } fn throw_interrupt_exception(&mut self) { - let err = MachineError::interrupt_error(); - let src = functor!("repl"); + let err = self.interrupt_error(); + let src = functor_stub(atom!("repl"), 0); let err = self.error_form(err, src); self.throw_exception(err); @@ -3121,11 +3725,8 @@ impl MachineState { self.p = CodePtr::Local(self.cp); } } - &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { - try_or_fail!( - self, - call_policy.context_call(self, name.clone(), arity, idx) - ) + &ClauseType::Named(ref name, _, ref idx) => { + try_or_fail!(self, call_policy.context_call(self, *name, arity, idx)) } &ClauseType::System(ref ct) => try_or_fail!( self, @@ -3144,7 +3745,7 @@ impl MachineState { self.last_call = false; } - pub(super) fn execute_ctrl_instr( + pub fn execute_ctrl_instr( &mut self, indices: &mut IndexStore, code_repo: &CodeRepo, @@ -3215,7 +3816,8 @@ impl MachineState { self.cc, ) { Some(_) => { - self.registers[self.num_of_args + 1] = Addr::Usize(self.cc); + self.registers[self.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); self.num_of_args += 1; self.execute_indexed_choice_instr( @@ -3240,10 +3842,7 @@ impl MachineState { .univ_prelude .num_cells; - self.cc = match self.stack.index_or_frame(self.b)[n - 1] { - Addr::Usize(cc) => cc, - _ => unreachable!(), - }; + self.cc = cell_as_fixnum!(self.stack[n - 1]).get_num() as usize; if is_next_clause { match code_repo.find_living_dynamic( @@ -3264,7 +3863,7 @@ impl MachineState { } } } else { - try_or_fail!(self, call_policy.trust(self, offset, global_variables,)) + try_or_fail!(self, call_policy.trust(self, offset, global_variables)) } } } @@ -3295,7 +3894,7 @@ impl MachineState { or_frame.prelude.b = self.b; or_frame.prelude.bp = self.p.local() + 1; or_frame.prelude.tr = self.tr; - or_frame.prelude.h = self.heap.h(); + or_frame.prelude.h = self.heap.len(); or_frame.prelude.b0 = self.b0; self.b = b; @@ -3304,7 +3903,7 @@ impl MachineState { self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i]; } - self.hb = self.heap.h(); + self.hb = self.heap.len(); self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset)); } &IndexedChoiceInstruction::Retry(l) => { @@ -3344,7 +3943,8 @@ impl MachineState { match code_repo.find_living_dynamic_else(p + next_i, self.cc) { Some(_) => { - self.registers[self.num_of_args + 1] = Addr::Usize(self.cc); + self.registers[self.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); self.num_of_args += 1; self.execute_choice_instr( @@ -3369,10 +3969,8 @@ impl MachineState { .univ_prelude .num_cells; - self.cc = match self.stack.index_or_frame(self.b)[n - 1] { - Addr::Usize(cc) => cc, - _ => unreachable!(), - }; + self.cc = cell_as_fixnum!(self.stack.index_or_frame(self.b)[n - 1]) + .get_num() as usize; if next_i > 0 { match code_repo.find_living_dynamic_else(p + next_i, self.cc) { @@ -3389,15 +3987,12 @@ impl MachineState { None => { try_or_fail!( self, - call_policy.trust_me(self, global_variables,) + call_policy.trust_me(self, global_variables) ) } } } else { - try_or_fail!( - self, - call_policy.trust_me(self, global_variables,) - ) + try_or_fail!(self, call_policy.trust_me(self, global_variables)) } } } @@ -3423,7 +4018,8 @@ impl MachineState { FirstOrNext::First => { match code_repo.find_living_dynamic_else(p + next_i, self.cc) { Some(_) => { - self.registers[self.num_of_args + 1] = Addr::Usize(self.cc); + self.registers[self.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); self.num_of_args += 1; self.execute_choice_instr( @@ -3448,10 +4044,8 @@ impl MachineState { .univ_prelude .num_cells; - self.cc = match self.stack.index_or_frame(self.b)[n - 1] { - Addr::Usize(cc) => cc, - _ => unreachable!(), - }; + self.cc = cell_as_fixnum!(self.stack.index_or_frame(self.b)[n - 1]) + .get_num() as usize; if next_i > 0 { match code_repo.find_living_dynamic_else(p + next_i, self.cc) { @@ -3499,7 +4093,7 @@ impl MachineState { or_frame.prelude.b = self.b; or_frame.prelude.bp = self.p.local() + offset; or_frame.prelude.tr = self.tr; - or_frame.prelude.h = self.heap.h(); + or_frame.prelude.h = self.heap.len(); or_frame.prelude.b0 = self.b0; self.b = b; @@ -3508,7 +4102,7 @@ impl MachineState { self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i]; } - self.hb = self.heap.h(); + self.hb = self.heap.len(); self.p += 1; } &ChoiceInstruction::DefaultRetryMeElse(offset) => { @@ -3557,14 +4151,14 @@ impl MachineState { &CutInstruction::GetLevel(r) => { let b0 = self.b0; - self[r] = Addr::CutPoint(b0); + self[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64)); self.p += 1; } &CutInstruction::GetLevelAndUnify(r) => { let b0 = self[perm_v!(1)]; let a = self[r]; - (self.unify_fn)(self, a, b0); + unify_fn!(self, a, b0); self.p += 1; } &CutInstruction::Cut(r) => { diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs new file mode 100644 index 00000000..540db78f --- /dev/null +++ b/src/machine/mock_wam.rs @@ -0,0 +1,766 @@ +pub use crate::arena::*; +pub use crate::atom_table::*; +use crate::heap_print::*; +pub use crate::machine::heap::*; +pub use crate::machine::Machine; +pub use crate::machine::machine_state::*; +pub use crate::machine::stack::*; +pub use crate::machine::streams::*; +pub use crate::macros::*; +pub use crate::parser::ast::*; +use crate::read::*; +pub use crate::types::*; + +#[cfg(test)] +use crate::machine::copier::CopierTarget; + +#[cfg(test)] +use std::ops::{Deref, DerefMut, Index, IndexMut}; + +// a mini-WAM for test purposes. + +pub struct MockWAM { + pub machine_st: MachineState, + pub op_dir: OpDir, + pub flags: MachineFlags, +} + +impl MockWAM { + pub fn new() -> Self { + let op_dir = default_op_dir(); + + Self { + machine_st: MachineState::new(), + op_dir, + flags: MachineFlags::default(), + } + } + + pub fn write_parsed_term_to_heap( + &mut self, + input_stream: Stream, + ) -> Result { + self.machine_st.read(input_stream, &self.op_dir) + } + + pub fn parse_and_write_parsed_term_to_heap( + &mut self, + term_string: &'static str, + ) -> Result { + let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena); + self.write_parsed_term_to_heap(stream) + } + + pub fn parse_and_print_term( + &mut self, + term_string: &'static str, + ) -> Result { + let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?; + + print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc); + + let mut printer = HCPrinter::new( + &mut self.machine_st.heap, + &mut self.machine_st.arena, + &self.op_dir, + PrinterOutputter::new(), + heap_loc_as_cell!(term_write_result.heap_loc), + ); + + printer.var_names = term_write_result + .var_dict + .into_iter() + .map(|(var, cell)| (cell, var)) + .collect(); + + Ok(printer.print().result()) + } +} + +#[cfg(test)] +pub struct TermCopyingMockWAM<'a> { + pub wam: &'a mut MockWAM, +} + +#[cfg(test)] +impl<'a> Index for TermCopyingMockWAM<'a> { + type Output = HeapCellValue; + + fn index(&self, index: usize) -> &HeapCellValue { + &self.wam.machine_st.heap[index] + } +} + +#[cfg(test)] +impl<'a> IndexMut for TermCopyingMockWAM<'a> { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut HeapCellValue { + &mut self.wam.machine_st.heap[index] + } +} + +#[cfg(test)] +impl<'a> Deref for TermCopyingMockWAM<'a> { + type Target = MockWAM; + + fn deref(&self) -> &Self::Target { + &self.wam + } +} + +#[cfg(test)] +impl<'a> DerefMut for TermCopyingMockWAM<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.wam + } +} + +#[cfg(test)] +impl<'a> CopierTarget for TermCopyingMockWAM<'a> { + fn store(&self, val: HeapCellValue) -> HeapCellValue { + read_heap_cell!(val, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + self.wam.machine_st.heap[h] + } + (HeapCellValueTag::StackVar, s) => { + self.wam.machine_st.stack[s] + } + _ => { + val + } + ) + } + + fn deref(&self, mut val: HeapCellValue) -> HeapCellValue { + loop { + let value = self.store(val); + + if value.is_var() && value != val { + val = value; + continue; + } + + return val; + } + } + + fn push(&mut self, val: HeapCellValue) { + self.wam.machine_st.heap.push(val); + } + + fn stack(&mut self) -> &mut Stack { + &mut self.wam.machine_st.stack + } + + fn threshold(&self) -> usize { + self.wam.machine_st.heap.len() + } +} + +#[cfg(test)] +pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) { + for (idx, cell) in heap.iter().enumerate() { + assert_eq!( + cell.get_mark_bit(), + true, + "cell {:?} at index {} is not marked", + cell, + idx + ); + assert!( + cell.get_forwarding_bit() != Some(true), + "cell {:?} at index {} is forwarded", + cell, + idx + ); + } +} + +#[cfg(test)] +pub fn all_cells_unmarked(heap: &Heap) { + for (idx, cell) in heap.iter().enumerate() { + assert!( + !cell.get_mark_bit(), + "cell {:?} at index {} is still marked", + cell, + idx + ); + + assert!( + cell.get_forwarding_bit() != Some(true), + "cell {:?} at index {} is still forwarded", + cell, + idx + ); + } +} + +#[cfg(test)] +pub(crate) fn write_parsed_term_to_heap( + machine_st: &mut MachineState, + input_stream: Stream, + op_dir: &OpDir, +) -> Result { + machine_st.read(input_stream, op_dir) +} + +#[cfg(test)] +pub(crate) fn parse_and_write_parsed_term_to_heap( + machine_st: &mut MachineState, + term_string: &'static str, + op_dir: &OpDir, +) -> Result { + let stream = Stream::from_static_string(term_string, &mut machine_st.arena); + write_parsed_term_to_heap(machine_st, stream, op_dir) +} + +impl Machine { + pub fn test_load_file(&mut self, file: &str) -> Vec { + use std::io::Read; + + let old_output = std::mem::replace( + &mut self.user_output, + Stream::from_owned_string("".to_owned(), &mut self.machine_st.arena), + ); + + let stream = Stream::from_owned_string( + std::fs::read_to_string(AsRef::::as_ref(file)).unwrap(), + &mut self.machine_st.arena, + ); + + self.load_file(file.into(), stream); + + let output = self.user_output.bytes().map(|b| b.unwrap()).collect(); + self.user_output = old_output; + output + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn unify_tests() { + let mut wam = MachineState::new(); + let mut op_dir = default_op_dir(); + + op_dir.insert( + (atom!("+"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("-"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("*"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("/"), Fixity::In), + OpDesc::build_with(400, YFX as u8), + ); + op_dir.insert( + (atom!("="), Fixity::In), + OpDesc::build_with(700, XFX as u8), + ); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(b,a).", &op_dir).unwrap(); + + unify!( + wam, + str_loc_as_cell!(0), + str_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.fail = false; + wam.heap.clear(); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap(); + + unify!( + wam, + str_loc_as_cell!(1), + heap_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(!wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.fail = false; + wam.heap.clear(); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap(); + + unify!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(!wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.fail = false; + wam.heap.clear(); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap(); + + unify!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(!wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.fail = false; + wam.heap.clear(); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap(); + + unify!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(!wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.fail = false; + wam.heap.clear(); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); + + all_cells_unmarked(&wam.heap); + + unify!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(!wam.fail); + } + + all_cells_unmarked(&wam.heap); + + wam.heap.clear(); + + wam.heap.push(pstr_as_cell!(atom!("this is a string"))); + wam.heap.push(heap_loc_as_cell!(1)); + + wam.heap.push(pstr_as_cell!(atom!("this is a string"))); + wam.heap.push(pstr_loc_as_cell!(4)); + + wam.heap.push(pstr_offset_as_cell!(0)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6))); + + unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2)); + + assert!(!wam.fail); + + assert_eq!(wam.heap[1], pstr_loc_as_cell!(4)); + + all_cells_unmarked(&wam.heap); + + wam.heap.clear(); + + wam.heap.push(list_loc_as_cell!(1)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(3)); + wam.heap.push(atom_as_cell!(atom!("b"))); + wam.heap.push(heap_loc_as_cell!(0)); + + wam.heap.push(list_loc_as_cell!(6)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(8)); + wam.heap.push(atom_as_cell!(atom!("b"))); + wam.heap.push(heap_loc_as_cell!(5)); + + unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); + + assert!(!wam.fail); + + all_cells_unmarked(&wam.heap); + + wam.heap.clear(); + + wam.heap.push(list_loc_as_cell!(1)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(3)); + wam.heap.push(atom_as_cell!(atom!("b"))); + wam.heap.push(heap_loc_as_cell!(0)); + + wam.heap.push(list_loc_as_cell!(6)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(8)); + wam.heap.push(atom_as_cell!(atom!("c"))); + wam.heap.push(heap_loc_as_cell!(5)); + + unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); + + assert!(wam.fail); + + wam.fail = false; + all_cells_unmarked(&wam.heap); + wam.heap.clear(); + + wam.heap.push(list_loc_as_cell!(1)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(3)); + wam.heap.push(atom_as_cell!(atom!("b"))); + wam.heap.push(heap_loc_as_cell!(5)); + + wam.heap.push(list_loc_as_cell!(6)); + wam.heap.push(atom_as_cell!(atom!("a"))); + wam.heap.push(list_loc_as_cell!(8)); + wam.heap.push(atom_as_cell!(atom!("b"))); + wam.heap.push(heap_loc_as_cell!(0)); + + unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); + + assert!(!wam.fail); + all_cells_unmarked(&wam.heap); + wam.heap.clear(); + + { + let term_write_result_1 = + parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap(); + + print_heap_terms(wam.heap.iter(), term_write_result_1.heap_loc); + + unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4)); + + assert_eq!(wam.heap[2], str_loc_as_cell!(4)); + } + } + + #[test] + fn test_unify_with_occurs_check() { + let mut wam = MachineState::new(); + let mut op_dir = default_op_dir(); + + op_dir.insert( + (atom!("+"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("-"), Fixity::In), + OpDesc::build_with(500, YFX as u8), + ); + op_dir.insert( + (atom!("*"), Fixity::In), + OpDesc::build_with(400, YFX as u8), + ); + op_dir.insert( + (atom!("/"), Fixity::In), + OpDesc::build_with(400, YFX as u8), + ); + + { + parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap(); + + let term_write_result_2 = + parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); + + all_cells_unmarked(&wam.heap); + + unify_with_occurs_check!( + wam, + str_loc_as_cell!(0), + str_loc_as_cell!(term_write_result_2.heap_loc) + ); + + assert!(wam.fail); + } + } + + #[test] + fn test_term_compare() { + use ordered_float::OrderedFloat; + use std::cmp::Ordering; + + let mut wam = MachineState::new(); + + wam.heap.push(heap_loc_as_cell!(0)); + wam.heap.push(heap_loc_as_cell!(1)); + + assert_eq!( + compare_term_test!(wam, wam.heap[0], wam.heap[1]), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!(wam, wam.heap[1], wam.heap[0]), + Some(Ordering::Greater) + ); + + assert_eq!( + compare_term_test!(wam, wam.heap[0], wam.heap[0]), + Some(Ordering::Equal) + ); + + assert_eq!( + compare_term_test!(wam, wam.heap[1], wam.heap[1]), + Some(Ordering::Equal) + ); + + assert_eq!( + compare_term_test!( + wam, + atom_as_cell!(atom!("atom")), + atom_as_cstr_cell!(atom!("string")) + ), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!( + wam, + atom_as_cell!(atom!("atom")), + atom_as_cell!(atom!("atom")) + ), + Some(Ordering::Equal) + ); + + assert_eq!( + compare_term_test!( + wam, + atom_as_cell!(atom!("atom")), + atom_as_cell!(atom!("aaa")) + ), + Some(Ordering::Greater) + ); + + assert_eq!( + compare_term_test!( + wam, + fixnum_as_cell!(Fixnum::build_with(6)), + heap_loc_as_cell!(1) + ), + Some(Ordering::Greater) + ); + + wam.heap.clear(); + + wam.heap.push(atom_as_cell!(atom!("f"), 1)); + wam.heap.push(heap_loc_as_cell!(1)); + + assert_eq!( + compare_term_test!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(0) + ), + Some(Ordering::Equal) + ); + + assert_eq!( + compare_term_test!( + wam, + heap_loc_as_cell!(0), + atom_as_cell!(atom!("a")) + ), + Some(Ordering::Greater) + ); + + wam.heap.clear(); + + // [1,2,3] + wam.heap.push(list_loc_as_cell!(1)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); + wam.heap.push(list_loc_as_cell!(3)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + wam.heap.push(list_loc_as_cell!(5)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3))); + wam.heap.push(empty_list_as_cell!()); + + // [1,2] + wam.heap.push(list_loc_as_cell!(8)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); + wam.heap.push(list_loc_as_cell!(10)); + wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); + wam.heap.push(empty_list_as_cell!()); + + assert_eq!( + compare_term_test!( + wam, + heap_loc_as_cell!(7), + heap_loc_as_cell!(7) + ), + Some(Ordering::Equal) + ); + + assert_eq!( + compare_term_test!( + wam, + heap_loc_as_cell!(0), + heap_loc_as_cell!(7) + ), + Some(Ordering::Greater) + ); + + assert_eq!( + compare_term_test!( + wam, + empty_list_as_cell!(), + heap_loc_as_cell!(7) + ), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!( + wam, + empty_list_as_cell!(), + fixnum_as_cell!(Fixnum::build_with(1)) + ), + Some(Ordering::Greater) + ); + + assert_eq!( + compare_term_test!( + wam, + empty_list_as_cell!(), + atom_as_cstr_cell!(atom!("string")) + ), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!( + wam, + empty_list_as_cell!(), + atom_as_cell!(atom!("atom")) + ), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!( + wam, + atom_as_cell!(atom!("atom")), + empty_list_as_cell!() + ), + Some(Ordering::Greater) + ); + + let one_p_one = typed_arena_ptr_as_cell!( + arena_alloc!(OrderedFloat(1.1), &mut wam.arena) + ); + + assert_eq!( + compare_term_test!( + wam, + one_p_one, + fixnum_as_cell!(Fixnum::build_with(1)) + ), + Some(Ordering::Less) + ); + + assert_eq!( + compare_term_test!( + wam, + fixnum_as_cell!(Fixnum::build_with(1)), + one_p_one + ), + Some(Ordering::Greater) + ); + } + + #[test] + fn is_cyclic_term_tests() { + let mut wam = MachineState::new(); + + assert!(!wam.is_cyclic_term(atom_as_cell!(atom!("f")))); + assert!(!wam.is_cyclic_term(fixnum_as_cell!(Fixnum::build_with(555)))); + + wam.heap.push(heap_loc_as_cell!(0)); + + assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0))); + + all_cells_unmarked(&wam.heap); + wam.heap.clear(); + + wam.heap.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))])); + + assert!(!wam.is_cyclic_term(str_loc_as_cell!(0))); + + all_cells_unmarked(&wam.heap); + + assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1))); + + all_cells_unmarked(&wam.heap); + + assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2))); + + all_cells_unmarked(&wam.heap); + + wam.heap[2] = str_loc_as_cell!(0); + + print_heap_terms(wam.heap.iter(), 0); + + assert!(wam.is_cyclic_term(str_loc_as_cell!(0))); + + all_cells_unmarked(&wam.heap); + + wam.heap[2] = atom_as_cell!(atom!("b")); + wam.heap[1] = str_loc_as_cell!(0); + + assert!(wam.is_cyclic_term(str_loc_as_cell!(0))); + + all_cells_unmarked(&wam.heap); + + assert!(wam.is_cyclic_term(heap_loc_as_cell!(1))); + + all_cells_unmarked(&wam.heap); + + wam.heap.clear(); + + wam.heap.push(pstr_as_cell!(atom!("a string"))); + wam.heap.push(empty_list_as_cell!()); + + assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0))); + } +} diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 1f7ef41a..ccb952cd 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1,67 +1,70 @@ -use prolog_parser::ast::*; -use prolog_parser::tabled_rc::*; -use prolog_parser::{clause_name, temp_v}; - -use lazy_static::lazy_static; - -use crate::clause_types::*; +pub mod arithmetic_ops; +pub mod attributed_variables; +pub mod code_repo; +pub mod code_walker; +#[macro_use] +pub mod loader; +pub mod compile; +pub mod copier; +pub mod gc; +pub mod heap; +pub mod load_state; +pub mod machine_errors; +pub mod machine_indices; +pub mod machine_state; +pub mod machine_state_impl; +pub mod mock_wam; +pub mod partial_string; +pub mod preprocessor; +pub mod stack; +pub mod streams; +pub mod system_calls; +pub mod term_stream; + +use crate::atom_table::*; use crate::forms::*; use crate::instructions::*; -use crate::machine::loader::*; -use crate::machine::term_stream::{LiveTermStream, LoadStatePayload, TermStream}; -use crate::read::*; - -mod attributed_variables; -pub(super) mod code_repo; -pub(crate) mod code_walker; -#[macro_use] -pub(crate) mod loader; -mod compile; -mod copier; -pub(crate) mod heap; -mod load_state; -pub(crate) mod machine_errors; -pub(crate) mod machine_indices; -pub(super) mod machine_state; -pub(crate) mod partial_string; -mod preprocessor; -mod raw_block; -mod stack; -pub(crate) mod streams; -mod term_stream; - -#[macro_use] -mod arithmetic_ops; -#[macro_use] -mod machine_state_impl; -mod system_calls; - use crate::machine::code_repo::*; use crate::machine::compile::*; +use crate::machine::heap::*; +use crate::machine::loader::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -pub use crate::machine::streams::Stream; +use crate::machine::streams::*; +use crate::types::*; use indexmap::IndexMap; -//use std::convert::TryFrom; -use prolog_parser::ast::ClauseName; -use std::fs::File; -use std::mem; +use lazy_static::lazy_static; + +use std::env; use std::path::PathBuf; use std::sync::atomic::AtomicBool; +lazy_static! { + pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false); +} + +#[derive(Debug)] +pub struct Machine { + pub(super) machine_st: MachineState, + pub(super) inner_heap: Heap, + pub(super) policies: MachinePolicies, + pub(super) indices: IndexStore, + pub(super) code_repo: CodeRepo, + pub(super) user_input: Stream, + pub(super) user_output: Stream, + pub(super) user_error: Stream, + pub(super) load_contexts: Vec, +} + #[derive(Debug)] pub(crate) struct MachinePolicies { call_policy: Box, cut_policy: Box, } -lazy_static! { - pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false); -} - impl MachinePolicies { #[inline] fn new() -> Self { @@ -80,10 +83,10 @@ impl Default for MachinePolicies { } #[derive(Debug)] -pub(super) struct LoadContext { +pub struct LoadContext { pub(super) path: PathBuf, pub(super) stream: Stream, - pub(super) module: ClauseName, + pub(super) module: Atom, } impl LoadContext { @@ -100,32 +103,49 @@ impl LoadContext { LoadContext { path: path_buf, stream, - module: clause_name!("user"), + module: atom!("user"), } } } -#[derive(Debug)] -pub struct Machine { - pub(super) machine_st: MachineState, - pub(super) policies: MachinePolicies, - pub(super) indices: IndexStore, - pub(super) code_repo: CodeRepo, - pub(super) user_input: Stream, - pub(super) user_output: Stream, - pub(super) user_error: Stream, - pub(super) load_contexts: Vec, -} - #[inline] fn current_dir() -> PathBuf { - std::env::current_dir().unwrap_or(PathBuf::from("./")) + env::current_dir().unwrap_or(PathBuf::from("./")) } include!(concat!(env!("OUT_DIR"), "/libraries.rs")); +pub struct MachinePreludeView<'a> { + pub indices: &'a mut IndexStore, + pub code_repo: &'a mut CodeRepo, + pub load_contexts: &'a mut Vec, +} + +impl Machine { + #[inline] + pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) { + ( + MachinePreludeView { + indices: &mut self.indices, + code_repo: &mut self.code_repo, + load_contexts: &mut self.load_contexts, + }, + &mut self.machine_st + ) + } + + pub fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) { + let err = self.machine_st.session_error(err); + let stub = functor_stub(key.0, key.1); + let err = self.machine_st.error_form(err, stub); + + self.machine_st.throw_exception(err); + return; + } +} + impl Machine { - fn run_module_predicate(&mut self, module_name: ClauseName, key: PredicateKey) { + fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) { if let Some(module) = self.indices.modules.get(&module_name) { if let Some(ref code_index) = module.code_dir.get(&key) { let p = code_index.local().unwrap(); @@ -140,27 +160,29 @@ impl Machine { unreachable!(); } - pub fn load_file(&mut self, path: String, stream: Stream) { - self.machine_st[temp_v!(1)] = - Addr::Stream(self.machine_st.heap.push(HeapCellValue::Stream(stream))); - - self.machine_st[temp_v!(2)] = Addr::Con(self.machine_st.heap.push(HeapCellValue::Atom( - clause_name!(path, self.machine_st.atom_tbl), - None, - ))); + pub fn load_file(&mut self, path: &str, stream: Stream) { + self.machine_st.registers[1] = stream_as_cell!(stream); + self.machine_st.registers[2] = atom_as_cell!( + self.machine_st.atom_tbl.build_with(path) + ); - self.run_module_predicate(clause_name!("loader"), (clause_name!("file_load"), 2)); + self.run_module_predicate(atom!("loader"), (atom!("file_load"), 2)); } fn load_top_level(&mut self) { let mut path_buf = current_dir(); - path_buf.push("toplevel.pl"); - let path = path_buf.to_str().unwrap().to_string(); + path_buf.push("src/toplevel.pl"); - self.load_file(path, Stream::from(include_str!("../toplevel.pl"))); + let path = path_buf.to_str().unwrap(); + let toplevel_stream = Stream::from_static_string( + include_str!("../toplevel.pl"), + &mut self.machine_st.arena, + ); - if let Some(toplevel) = self.indices.modules.get(&clause_name!("$toplevel")) { + self.load_file(path, toplevel_stream); + + if let Some(toplevel) = self.indices.modules.get(&atom!("$toplevel")) { load_module( &mut self.indices.code_dir, &mut self.indices.op_dir, @@ -178,9 +200,15 @@ impl Machine { path_buf.push("machine/attributed_variables.pl"); bootstrapping_compile( - Stream::from(include_str!("attributed_variables.pl")), + Stream::from_static_string( + include_str!("attributed_variables.pl"), + &mut self.machine_st.arena, + ), self, - ListingSource::from_file_and_path(clause_name!("attributed_variables"), path_buf), + ListingSource::from_file_and_path( + atom!("attributed_variables"), + path_buf, + ), ) .unwrap(); @@ -188,44 +216,49 @@ impl Machine { path_buf.push("machine/project_attributes.pl"); bootstrapping_compile( - Stream::from(include_str!("project_attributes.pl")), + Stream::from_static_string( + include_str!("project_attributes.pl"), + &mut self.machine_st.arena, + ), self, - ListingSource::from_file_and_path(clause_name!("project_attributes"), path_buf), + ListingSource::from_file_and_path(atom!("project_attributes"), path_buf), ) .unwrap(); - if let Some(module) = self.indices.modules.get(&clause_name!("$atts")) { - if let Some(code_index) = module.code_dir.get(&(clause_name!("driver"), 2)) { + if let Some(module) = self.indices.modules.get(&atom!("$atts")) { + if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) { self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap(); } } } pub fn run_top_level(&mut self) { - use std::env; - let mut arg_pstrs = vec![]; for arg in env::args() { - arg_pstrs.push(self.machine_st.heap.put_complete_string(&arg)); + arg_pstrs.push(put_complete_string( + &mut self.machine_st.heap, + &arg, + &mut self.machine_st.atom_tbl, + )); } - let list_addr = Addr::HeapCell(self.machine_st.heap.to_list(arg_pstrs.into_iter())); - - self.machine_st[temp_v!(1)] = list_addr; + self.machine_st.registers[1] = heap_loc_as_cell!( + iter_to_heap_list(&mut self.machine_st.heap, arg_pstrs.into_iter()) + ); - self.run_module_predicate(clause_name!("$toplevel"), (clause_name!("$repl"), 1)); + self.run_module_predicate(atom!("$toplevel"), (atom!("$repl"), 1)); } pub(crate) fn configure_modules(&mut self) { fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir) { for arity in 1..66 { - let key = (clause_name!("call"), arity); + let key = (atom!("call"), arity); match loader.code_dir.get(&key) { Some(src_code_index) => { let target_code_index = target_code_dir - .entry(key.clone()) + .entry(key) .or_insert_with(|| CodeIndex::new(IndexPtr::Undefined)); target_code_index.set(src_code_index.get()); @@ -237,15 +270,15 @@ impl Machine { } } - if let Some(loader) = self.indices.modules.swap_remove(&clause_name!("loader")) { - if let Some(builtins) = self.indices.modules.get_mut(&clause_name!("builtins")) { + if let Some(loader) = self.indices.modules.swap_remove(&atom!("loader")) { + if let Some(builtins) = self.indices.modules.get_mut(&atom!("builtins")) { // Import loader's exports into the builtins module so they will be // implicitly included in every further module. load_module( &mut builtins.code_dir, &mut builtins.op_dir, &mut builtins.meta_predicates, - &CompilationTarget::Module(clause_name!("builtins")), + &CompilationTarget::Module(atom!("builtins")), &loader, ); @@ -257,7 +290,7 @@ impl Machine { builtins .module_decl .exports - .push(ModuleExport::PredicateKey((clause_name!("call"), arity))); + .push(ModuleExport::PredicateKey((atom!("call"), arity))); } } @@ -267,17 +300,24 @@ impl Machine { update_call_n_indices(&loader, &mut self.indices.code_dir); - self.indices.modules.insert(clause_name!("loader"), loader); + self.indices.modules.insert(atom!("loader"), loader); } else { unreachable!() } } - pub fn new(user_input: Stream, user_output: Stream, user_error: Stream) -> Self { + pub fn new() -> Self { use ref_thread_local::RefThreadLocal; + let mut machine_st = MachineState::new(); + + let user_input = Stream::stdin(&mut machine_st.arena); + let user_output = Stream::stdout(&mut machine_st.arena); + let user_error = Stream::stderr(&mut machine_st.arena); + let mut wam = Machine { - machine_st: MachineState::new(), + machine_st, + inner_heap: Heap::new(), policies: MachinePolicies::new(), indices: IndexStore::new(), code_repo: CodeRepo::new(), @@ -293,23 +333,29 @@ impl Machine { lib_path.push("lib"); bootstrapping_compile( - Stream::from(LIBRARIES.borrow()["ops_and_meta_predicates"]), + Stream::from_static_string( + LIBRARIES.borrow()["ops_and_meta_predicates"], + &mut wam.machine_st.arena, + ), &mut wam, ListingSource::from_file_and_path( - clause_name!("ops_and_meta_predicates.pl"), + atom!("ops_and_meta_predicates.pl"), lib_path.clone(), ), ) .unwrap(); bootstrapping_compile( - Stream::from(LIBRARIES.borrow()["builtins"]), + Stream::from_static_string( + LIBRARIES.borrow()["builtins"], + &mut wam.machine_st.arena, + ), &mut wam, - ListingSource::from_file_and_path(clause_name!("builtins.pl"), lib_path.clone()), + ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()), ) .unwrap(); - if let Some(builtins) = wam.indices.modules.get(&clause_name!("builtins")) { + if let Some(builtins) = wam.indices.modules.get(&atom!("builtins")) { load_module( &mut wam.indices.code_dir, &mut wam.indices.op_dir, @@ -324,15 +370,15 @@ impl Machine { lib_path.pop(); // remove the "lib" at the end bootstrapping_compile( - Stream::from(include_str!("../loader.pl")), + Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena), &mut wam, - ListingSource::from_file_and_path(clause_name!("loader.pl"), lib_path.clone()), + ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()), ) .unwrap(); wam.configure_modules(); - if let Some(loader) = wam.indices.modules.get(&clause_name!("loader")) { + if let Some(loader) = wam.indices.modules.get(&atom!("loader")) { load_module( &mut wam.indices.code_dir, &mut wam.indices.op_dir, @@ -352,38 +398,21 @@ impl Machine { } pub(crate) fn configure_streams(&mut self) { - self.user_input.options_mut().alias = Some(clause_name!("user_input")); + self.user_input.options_mut().set_alias_to_atom_opt(Some(atom!("user_input"))); self.indices .stream_aliases - .insert(clause_name!("user_input"), self.user_input.clone()); + .insert(atom!("user_input"), self.user_input); - self.indices.streams.insert(self.user_input.clone()); + self.indices.streams.insert(self.user_input); - self.user_output.options_mut().alias = Some(clause_name!("user_output")); + self.user_output.options_mut().set_alias_to_atom_opt(Some(atom!("user_output"))); self.indices .stream_aliases - .insert(clause_name!("user_output"), self.user_output.clone()); - - self.user_error.options_mut().alias = Some(clause_name!("user_error")); + .insert(atom!("user_output"), self.user_output); - self.indices - .stream_aliases - .insert(clause_name!("user_error"), self.user_error.clone()); - - self.indices.streams.insert(self.user_output.clone()); - } - - fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) { - let h = self.machine_st.heap.h(); - - let err = MachineError::session_error(h, err); - let stub = MachineError::functor_stub(key.0, key.1); - let err = self.machine_st.error_form(err, stub); - - self.machine_st.throw_exception(err); - return; + self.indices.streams.insert(self.user_output); } fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) { @@ -604,13 +633,14 @@ impl MachineState { self.b0 = self.stack.index_or_frame(b).prelude.b0; self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp); + self.pdl.clear(); self.fail = false; } fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool { match self.p { - CodePtr::Local(LocalCodePtr::DirEntry(p)) - | CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..)) + CodePtr::Local(LocalCodePtr::DirEntry(p)) | + CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..)) if p < code_repo.code.len() => {} CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => { return false; @@ -690,7 +720,9 @@ impl MachineState { self.p = CodePtr::Local(self.attr_var_init.cp); let instigating_p = CodePtr::Local(self.attr_var_init.instigating_p); - let instigating_instr = code_repo.lookup_instr(false, &instigating_p).unwrap(); + let instigating_instr = code_repo + .lookup_instr(false, &instigating_p) + .unwrap(); if !instigating_instr.as_ref().is_head_instr() { let cp = self.p.local(); diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 79354874..da32db4f 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -1,43 +1,16 @@ -use crate::machine::machine_indices::*; -use crate::machine::*; +use crate::atom_table::*; +use crate::parser::ast::*; -use core::marker::PhantomData; +use crate::machine::machine_errors::CycleSearchResult; +use crate::machine::system_calls::BrentAlgState; +use crate::types::*; -use std::alloc; use std::cmp::Ordering; -use std::mem; -use std::ops::RangeFrom; -use std::ptr; -use std::slice; +use std::ops::Deref; use std::str; -use indexmap::IndexSet; - -#[derive(Debug)] -pub(crate) struct PartialString { - buf: *const u8, - len: usize, - _marker: PhantomData<[u8]>, -} - -impl Drop for PartialString { - fn drop(&mut self) { - unsafe { - let layout = alloc::Layout::from_size_align_unchecked(self.len, mem::align_of::()); - alloc::dealloc(self.buf as *mut u8, layout); - - self.buf = ptr::null(); - self.len = 0; - } - } -} - -impl Clone for PartialString { - #[inline] - fn clone(&self) -> Self { - self.clone_from_offset(0) - } -} +#[derive(Copy, Clone, Debug)] +pub struct PartialString(Atom); fn scan_for_terminator>(iter: Iter) -> usize { let mut terminator_idx = 0; @@ -53,432 +26,1114 @@ fn scan_for_terminator>(iter: Iter) -> usize { terminator_idx } -#[derive(Debug)] -pub(crate) struct PStrIter { - buf: *const u8, - len: usize, -} - -impl PStrIter { +impl From for PartialString { #[inline] - fn from(buf: *const u8, len: usize, idx: usize) -> Self { - PStrIter { - buf: (buf as usize + idx) as *const _, - len: len - idx, - } + fn from(buf: Atom) -> PartialString { + PartialString(buf) } } -impl Iterator for PStrIter { - type Item = char; - - fn next(&mut self) -> Option { - unsafe { - let slice = slice::from_raw_parts(self.buf, self.len); - let s = str::from_utf8(slice).unwrap(); - - if let Some(c) = s.chars().next() { - self.buf = self.buf.offset(c.len_utf8() as isize); - self.len -= c.len_utf8(); - - Some(c) - } else { - None - } - } +impl Into for PartialString { + #[inline] + fn into(self: Self) -> Atom { + self.0 } } impl PartialString { #[inline] - pub(super) fn new(src: &str) -> Option<(Self, &str)> { - let pstr = PartialString { - buf: ptr::null_mut(), - len: 0, - _marker: PhantomData, - }; + pub(super) fn new<'a>(src: &'a str, atom_tbl: &mut AtomTable) -> Option<(Self, &'a str)> { + let terminator_idx = scan_for_terminator(src.chars()); + let pstr = PartialString(atom_tbl.build_with(src)); + + Some(if terminator_idx != src.as_bytes().len() { + (pstr, &src[terminator_idx..]) + } else { + (pstr, "") + }) + } - unsafe { pstr.append_chars(src) } + #[inline(always)] + pub(crate) fn as_str_from(&self, n: usize) -> &str { + &self.0.as_str()[n..] } +} - unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> { - let terminator_idx = scan_for_terminator(src.chars()); +#[derive(Clone, Copy)] +pub struct HeapPStrIter<'a> { + pub heap: &'a [HeapCellValue], + pub focus: HeapCellValue, + orig_focus: usize, + brent_st: BrentAlgState, + stepper: fn(&mut HeapPStrIter<'a>) -> Option, +} - let layout = alloc::Layout::from_size_align_unchecked( - terminator_idx + '\u{0}'.len_utf8(), - mem::align_of::(), - ); +#[derive(Debug)] +pub struct PStrPrefixCmpResult { + pub focus: usize, + pub offset: usize, + pub prefix_len: usize, +} - self.buf = alloc::alloc(layout) as *const _; - self.len = terminator_idx + '\u{0}'.len_utf8(); +struct PStrIterStep { + iteratee: PStrIteratee, + next_hare: usize, +} - ptr::copy(src.as_ptr(), self.buf as *mut _, terminator_idx); +impl<'a> HeapPStrIter<'a> { + pub fn new(heap: &'a [HeapCellValue], h: usize) -> Self { + let value = heap[h]; + + Self { + heap, + focus: value, + orig_focus: h, + brent_st: BrentAlgState::new(h), + stepper: HeapPStrIter::pre_cycle_discovery_stepper, + } + } - self.write_terminator_at(terminator_idx); + #[inline(always)] + pub fn focus(&self) -> usize { + self.brent_st.hare + } - Some(if terminator_idx != src.as_bytes().len() { - (self, &src[terminator_idx..]) - } else { - (self, "") - }) + #[inline(always)] + pub fn at_string_terminator(&self) -> bool { + self.focus.is_string_terminator(self.heap) } - pub(super) fn clone_from_offset(&self, n: usize) -> Self { - let len = if self.len - '\u{0}'.len_utf8() > n { - self.len - n - '\u{0}'.len_utf8() - } else { - 0 - }; + #[inline(always)] + pub fn num_steps(&self) -> usize { + self.brent_st.num_steps() + } - let mut pstr = PartialString { - buf: ptr::null_mut(), - len: len + '\u{0}'.len_utf8(), - _marker: PhantomData, + pub fn compare_pstr_to_string(&mut self, s: &str) -> Option { + let mut result = PStrPrefixCmpResult { + focus: self.brent_st.hare, + offset: 0, + prefix_len: 0, }; - unsafe { - let layout = alloc::Layout::from_size_align_unchecked( - len + '\u{0}'.len_utf8(), - mem::align_of::(), - ); + while let Some(iteratee) = self.next() { + result.focus = iteratee.focus(); + result.offset = iteratee.offset(); - pstr.buf = alloc::alloc(layout); + match iteratee { + PStrIteratee::Char(_, c1) => { + if let Some(c2) = s[result.prefix_len..].chars().next() { + if c1 != c2 { + return None; + } else { + result.prefix_len += c1.len_utf8(); + result.offset += c1.len_utf8(); + } + } else { + return Some(result); + } + } + PStrIteratee::PStrSegment(_, pstr_atom, n) => { + let pstr = PartialString::from(pstr_atom); + let t = pstr.as_str_from(n); + let s = &s[result.prefix_len..]; + + if s.len() >= t.len() { + if s.starts_with(t) { + result.prefix_len += t.len(); + result.offset += t.len(); + } else { + return None; + } + } else if t.starts_with(&s) { + result.prefix_len += s.len(); + result.offset += s.len(); - if len > 0 { - ptr::copy( - (self.buf as usize + n) as *const u8, - pstr.buf as *mut _, - len, - ); + return Some(result); + } else { + return None; + } + } } - pstr.write_terminator_at(len); + if s.len() == result.prefix_len { + return Some(result); + } } - pstr + Some(result) } #[inline] - pub(super) fn write_terminator_at(&mut self, index: usize) { - unsafe { - ptr::write((self.buf as usize + index) as *mut u8, 0u8); + pub fn chars(mut self) -> PStrCharsIter<'a> { + let item = self.next(); + PStrCharsIter { iter: self, item } + } + + fn walk_hare_to_cycle_end(&mut self) { + // walk_hare_to_cycle_end assumes a cycle has been found, + // so it is always safe to unwrap self.step() + + let orig_hare = self.brent_st.hare; + + self.brent_st.hare = self.orig_focus; + self.brent_st.tortoise = self.orig_focus; + + for _ in 0 .. self.brent_st.lam { + self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare; } + + while self.brent_st.hare != self.brent_st.tortoise { + self.brent_st.tortoise = self.step(self.brent_st.tortoise).unwrap().next_hare; + self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare; + } + + self.focus = self.heap[orig_hare]; + self.brent_st.hare = orig_hare; } - #[inline] - pub(crate) fn range_from(&self, index: RangeFrom) -> PStrIter { - if self.len >= '\u{0}'.len_utf8() { - PStrIter::from(self.buf, self.len - '\u{0}'.len_utf8(), index.start) - } else { - PStrIter::from(self.buf, 0, 0) + pub fn to_string(&mut self) -> String { + let mut buf = String::with_capacity(32); + + while let Some(iteratee) = self.next() { + match iteratee { + PStrIteratee::Char(_, c) => { + buf.push(c); + } + PStrIteratee::PStrSegment(_, pstr_atom, n) => { + let pstr = PartialString::from(pstr_atom); + buf += pstr.as_str_from(n); + } + } } + + buf } #[inline] - pub(crate) fn at_end(&self, end_n: usize) -> bool { - end_n + 1 == self.len + pub fn is_continuable(&self) -> bool { + let mut focus = self.focus; + + loop { + read_heap_cell!(focus, + (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { + return true; + } + (HeapCellValueTag::Atom, (name, arity)) => { // TODO: use Str here? + return name == atom!(".") && arity == 2; + } + (HeapCellValueTag::Lis, h) => { + return read_heap_cell!(self.heap[h], + (HeapCellValueTag::Atom, (name, arity)) => { + arity == 0 && name.as_char().is_some() + } + (HeapCellValueTag::Char) => { + true + } + _ => { + false + } + ); + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if focus == self.heap[h] { + return false; + } + + focus = self.heap[h]; + } + _ => { + return false; + } + ); + } } - #[inline] - pub(crate) fn as_str_from(&self, n: usize) -> &str { - unsafe { - let slice = slice::from_raw_parts(self.buf, self.len - '\u{0}'.len_utf8()); + #[inline(always)] + pub fn cycle_detected(&self) -> bool { + self.stepper as usize == HeapPStrIter::post_cycle_discovery_stepper as usize + } + + fn step(&self, mut curr_hare: usize) -> Option { + loop { + read_heap_cell!(self.heap[curr_hare], + (HeapCellValueTag::CStr, cstr_atom) => { + return if self.focus == empty_list_as_cell!() { + None + } else { + Some(PStrIterStep { + iteratee: PStrIteratee::PStrSegment(curr_hare, cstr_atom, 0), + next_hare: curr_hare, + }) + } + } + (HeapCellValueTag::PStrLoc, h) => { + curr_hare = h; + } + (HeapCellValueTag::PStr, pstr_atom) => { + return Some(PStrIterStep { + iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, 0), + next_hare: curr_hare+1, + }); + } + (HeapCellValueTag::PStrOffset, pstr_offset) => { + if self.focus == empty_list_as_cell!() { + return None; + } + + let pstr_atom = cell_as_atom!(self.heap[pstr_offset]); + let n = cell_as_fixnum!(self.heap[curr_hare+1]).get_num() as usize; + + return if self.heap[pstr_offset].get_tag() == HeapCellValueTag::CStr { + Some(PStrIterStep { + iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n), + next_hare: pstr_offset, + }) + } else { + Some(PStrIterStep { + iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n), + next_hare: pstr_offset+1, + }) + }; + } + (HeapCellValueTag::Lis, h) => { + return if let Some(c) = self.heap[h].as_char() { + Some(PStrIterStep { + iteratee: PStrIteratee::Char(curr_hare, c), + next_hare: h+1, + }) + } else { + None + } + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); + + return if name == atom!(".") && arity == 2 { + if let Some(c) = self.heap[s+1].as_char() { + Some(PStrIterStep { + iteratee: PStrIteratee::Char(curr_hare, c), + next_hare: s+2, + }) + } else { + None + } + } else { + None + }; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + debug_assert!(arity == 0); + return None; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h == curr_hare { + return None; + } + + curr_hare = h; + } + _ => { + return None; + } + ); + } + } + + fn pre_cycle_discovery_stepper(&mut self) -> Option { + let PStrIterStep { iteratee, next_hare } = + match self.step(self.brent_st.hare) { + Some(results) => results, + None => { + return None; + } + }; + + self.focus = self.heap[iteratee.focus()]; + + if self.focus.is_string_terminator(self.heap) { + self.focus = empty_list_as_cell!(); + self.brent_st.hare = iteratee.focus(); + + return Some(iteratee); + } + + match self.brent_st.step(next_hare) { + Some(cycle_result) => { + debug_assert!(cycle_result == CycleSearchResult::NotList); + + self.walk_hare_to_cycle_end(); + self.stepper = HeapPStrIter::post_cycle_discovery_stepper; + } + None => { + self.focus = self.heap[next_hare]; + } + } - let s = str::from_utf8(slice).unwrap(); + Some(iteratee) + } - &s[n..] + fn post_cycle_discovery_stepper(&mut self) -> Option { + if self.brent_st.hare == self.brent_st.tortoise { + return None; } + + let PStrIterStep { iteratee, next_hare } = + match self.step(self.brent_st.hare) { + Some(results) => results, + None => { + return None; + } + }; + + self.focus = self.heap[next_hare]; + self.brent_st.hare = next_hare; + + Some(iteratee) } } -#[derive(Debug)] -pub(crate) struct HeapPStrIter<'a> { - focus: Addr, - machine_st: &'a MachineState, - seen: IndexSet, +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PStrIteratee { + Char(usize, char), + PStrSegment(usize, Atom, usize), } -impl<'a> HeapPStrIter<'a> { +impl PStrIteratee { #[inline] - pub(super) fn new(machine_st: &'a MachineState, focus: Addr) -> Self { - HeapPStrIter { - focus, - machine_st, - seen: IndexSet::new(), + fn offset(&self) -> usize { + match self { + PStrIteratee::Char(_, _) => 0, + PStrIteratee::PStrSegment(_, _, n) => *n, } } #[inline] - pub(crate) fn focus(&self) -> Addr { - self.machine_st.store(self.machine_st.deref(self.focus)) + fn focus(&self) -> usize { + match self { + PStrIteratee::Char(focus, _) => *focus, + PStrIteratee::PStrSegment(focus, _, _) => *focus, + } } +} - #[inline] - pub(crate) fn to_string(&mut self) -> String { - let mut buf = String::new(); +impl<'a> Iterator for HeapPStrIter<'a> { + type Item = PStrIteratee; - while let Some(iteratee) = self.next() { + #[inline(always)] + fn next(&mut self) -> Option { + (self.stepper)(self) + } +} + +pub struct PStrCharsIter<'a> { + pub iter: HeapPStrIter<'a>, + pub item: Option, +} + +impl<'a> PStrCharsIter<'a> { + pub fn peek(&self) -> Option { + if let Some(iteratee) = self.item { match iteratee { - PStrIteratee::Char(c) => { - buf.push(c); + PStrIteratee::Char(_, c) => { + return Some(c); + } + PStrIteratee::PStrSegment(_, pstr_atom, n) => { + let pstr = PartialString::from(pstr_atom); + return pstr.as_str_from(n).chars().next(); } - PStrIteratee::PStrSegment(h, n) => match &self.machine_st.heap[h] { - HeapCellValue::PartialString(ref pstr, _) => { - buf += pstr.as_str_from(n); - } - _ => { - unreachable!() - } - }, } } - buf + None } } -#[derive(Debug, Clone, Copy)] -pub(crate) enum PStrIteratee { - Char(char), - PStrSegment(usize, usize), +impl<'a> Deref for PStrCharsIter<'a> { + type Target = HeapPStrIter<'a>; + + fn deref(&self) -> &Self::Target { + &self.iter + } } -impl<'a> Iterator for HeapPStrIter<'a> { - type Item = PStrIteratee; +impl<'a> Iterator for PStrCharsIter<'a> { + type Item = char; fn next(&mut self) -> Option { - let addr = self.machine_st.store(self.machine_st.deref(self.focus)); - - if !self.seen.contains(&addr) { - self.seen.insert(addr); - } else { - return None; + while let Some(item) = self.item { + match item { + PStrIteratee::Char(_, c) => { + self.item = self.iter.next(); + return Some(c); + } + PStrIteratee::PStrSegment(f1, pstr_atom, n) => { + let pstr = PartialString::from(pstr_atom); + + match pstr.as_str_from(n).chars().next() { + Some(c) => { + self.item = Some(PStrIteratee::PStrSegment( + f1, + pstr_atom, + n + c.len_utf8(), + )); + + return Some(c); + } + None => { + self.item = self.iter.next(); + } + } + } + } } - match addr { - Addr::PStrLocation(h, n) => { - if let &HeapCellValue::PartialString(_, has_tail) = &self.machine_st.heap[h] { - self.focus = if has_tail { - Addr::HeapCell(h + 1) - } else { - Addr::EmptyList - }; + /* + if !self.iter.at_string_terminator() { + // at a cycle. emit the final character. + match self.iter.step(self.iter.brent_st.hare) { + Some(PStrIterStep { iteratee: PStrIteratee::Char(_, c), .. }) => { + self.iter.focus = empty_list_as_cell!(); + return Some(c); + } + Some(PStrIterStep { iteratee: PStrIteratee::PStrSegment(_, pstr_atom, _), .. }) => { + self.iter.focus = empty_list_as_cell!(); - return Some(PStrIteratee::PStrSegment(h, n)); - } else { - unreachable!() + let c = PartialString::from(pstr_atom).as_str_from(0).chars().next().unwrap(); + return Some(c); } - } - Addr::Lis(l) => { - let addr = self - .machine_st - .store(self.machine_st.deref(Addr::HeapCell(l))); - - let opt_c = match addr { - Addr::Con(h) if self.machine_st.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.machine_st.heap[h] { - if atom.is_char() { - atom.as_str().chars().next() - } else { - None - } - } else { - unreachable!() - } - } - Addr::Char(c) => Some(c), - _ => None, - }; - - if let Some(c) = opt_c { - self.focus = Addr::HeapCell(l + 1); - return Some(PStrIteratee::Char(c)); - } else { + _ => { + self.iter.focus = empty_list_as_cell!(); return None; } } - Addr::EmptyList => { - self.focus = Addr::EmptyList; - return None; - } - _ => { - return None; - } + } + */ + + None + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PStrCmpResult { + Ordered(Ordering), + FirstIterContinuable(PStrIteratee), + SecondIterContinuable(PStrIteratee), + Unordered, +} + +impl PStrCmpResult { + #[inline] + pub fn is_second_iter(&self) -> bool { + if let PStrCmpResult::SecondIterContinuable(_) = self { + true + } else { + false } } } #[inline] -pub(super) fn compare_pstr_prefixes<'a>( +pub fn compare_pstr_prefixes<'a>( i1: &mut HeapPStrIter<'a>, i2: &mut HeapPStrIter<'a>, -) -> Option { - let mut r1 = i1.next(); - let mut r2 = i2.next(); +) -> PStrCmpResult { + #[inline(always)] + fn consolidate_step(iter: &mut HeapPStrIter, step: &PStrIterStep) -> bool { + iter.focus = iter.heap[step.next_hare]; + + if iter.focus.is_string_terminator(iter.heap) { + iter.focus = empty_list_as_cell!(); + } + + !iter.brent_st.step(step.next_hare).is_some() + } + + let mut r1 = i1.step(i1.brent_st.hare); + let mut r2 = i2.step(i2.brent_st.hare); loop { - if let Some(r1i) = r1 { - if let Some(r2i) = r2 { - match (r1i, r2i) { - (PStrIteratee::Char(c1), PStrIteratee::Char(c2)) => { + if let Some(step_1) = r1.as_mut() { + if let Some(step_2) = r2.as_mut() { + match (step_1.iteratee, step_2.iteratee) { + (PStrIteratee::Char(_, c1), PStrIteratee::Char(_, c2)) => { if c1 != c2 { - return c1.partial_cmp(&c2); + return PStrCmpResult::Ordered(c1.cmp(&c2)); + } + + let c1_result = consolidate_step(i1, &step_1); + let c2_result = consolidate_step(i2, &step_2); + + if c1_result { + r1 = i1.step(i1.brent_st.hare); + } + + if c2_result { + r2 = i2.step(i2.brent_st.hare); + } + + if c1_result && c2_result { + continue; + } else { + break; } } - (PStrIteratee::Char(c1), PStrIteratee::PStrSegment(h, n)) => { - if let &HeapCellValue::PartialString(ref pstr, _) = &i2.machine_st.heap[h] { - if let Some(c2) = pstr.as_str_from(n).chars().next() { - if c1 != c2 { - return c1.partial_cmp(&c2); - } else { - r1 = i1.next(); - r2 = Some(PStrIteratee::PStrSegment(h, n + c2.len_utf8())); + (PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => { + let pstr = PartialString::from(pstr_atom); + + if let Some(c2) = pstr.as_str_from(n).chars().next() { + if c1 != c2 { + return PStrCmpResult::Ordered(c1.cmp(&c2)); + } + + let n1 = n + c2.len_utf8(); + + if n1 < pstr_atom.len() { + step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1); + if consolidate_step(i1, &step_1) { + r1 = i1.step(step_1.next_hare); continue; + } else { + break; } } else { - r2 = i2.next(); - continue; + let c1_result = consolidate_step(i1, &step_1); + let c2_result = consolidate_step(i2, &step_2); + + if c1_result { + r1 = i1.step(i1.brent_st.hare); + } + + if c2_result { + r2 = i2.step(i2.brent_st.hare); + } + + if c1_result && c2_result { + continue; + } else { + break; + } } } else { - unreachable!() + if consolidate_step(i2, &step_2) { + r2 = i2.step(step_2.next_hare); + continue; + } else { + break; + } } } - (PStrIteratee::PStrSegment(h, n), PStrIteratee::Char(c2)) => { - if let &HeapCellValue::PartialString(ref pstr, _) = &i1.machine_st.heap[h] { - if let Some(c1) = pstr.as_str_from(n).chars().next() { - if c1 != c2 { - return c2.partial_cmp(&c1); - } else { - r1 = i1.next(); - r2 = Some(PStrIteratee::PStrSegment(h, n + c1.len_utf8())); + (PStrIteratee::PStrSegment(f1, pstr_atom, n), PStrIteratee::Char(_, c2)) => { + let pstr = PartialString::from(pstr_atom); + if let Some(c1) = pstr.as_str_from(n).chars().next() { + if c1 != c2 { + return PStrCmpResult::Ordered(c2.cmp(&c1)); + } + + let n1 = n + c1.len_utf8(); + + if n1 < pstr_atom.len() { + step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1); + + if consolidate_step(i2, &step_2) { + r2 = i2.step(step_2.next_hare); continue; + } else { + break; } } else { - r1 = i1.next(); - continue; + let c1_result = consolidate_step(i1, &step_1); + let c2_result = consolidate_step(i2, &step_2); + + if c1_result { + r1 = i1.step(i1.brent_st.hare); + } + + if c2_result { + r2 = i2.step(i2.brent_st.hare); + } + + if c1_result && c2_result { + continue; + } else { + break; + } } } else { - unreachable!() + if consolidate_step(i1, &step_1) { + r1 = i1.step(step_1.next_hare); + continue; + } else { + break; + } } } - (PStrIteratee::PStrSegment(h1, n1), PStrIteratee::PStrSegment(h2, n2)) => { - match (&i1.machine_st.heap[h1], &i2.machine_st.heap[h2]) { - ( - &HeapCellValue::PartialString(ref pstr1, _), - &HeapCellValue::PartialString(ref pstr2, _), - ) => { - let str1 = pstr1.as_str_from(n1); - let str2 = pstr2.as_str_from(n2); - - if str1.starts_with(str2) { - r1 = Some(PStrIteratee::PStrSegment(h1, n1 + str2.len())); - r2 = i2.next(); + (PStrIteratee::PStrSegment(f1, pstr1_atom, n1), + PStrIteratee::PStrSegment(f2, pstr2_atom, n2)) => { + if pstr1_atom == pstr2_atom && n1 == n2 { + let c_result1 = consolidate_step(i1, &step_1); + let c_result2 = consolidate_step(i2, &step_2); + + if c_result1 { + r1 = i1.step(step_1.next_hare); + } + + if c_result2 { + r2 = i2.step(step_2.next_hare); + } + + if c_result1 && c_result2 { + continue; + } + + break; + } + + let pstr1 = PartialString::from(pstr1_atom); + let pstr2 = PartialString::from(pstr2_atom); + + let str1 = pstr1.as_str_from(n1); + let str2 = pstr2.as_str_from(n2); + match str1.len().cmp(&str2.len()) { + Ordering::Equal if str1 == str2 => { + let c_result1 = consolidate_step(i1, &step_1); + let c_result2 = consolidate_step(i2, &step_2); + + if c_result1 { + r1 = i1.step(step_1.next_hare); + } + + if c_result2 { + r2 = i2.step(step_2.next_hare); + } + + if c_result1 && c_result2 { continue; - } else if str2.starts_with(str1) { - r1 = i1.next(); - r2 = Some(PStrIteratee::PStrSegment(h2, n2 + str1.len())); + } + + break; + } + Ordering::Less if str2.starts_with(str1) => { + step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len()); + + if consolidate_step(i1, &step_1) { + r1 = i1.step(step_1.next_hare); + continue; + } else { + break; + } + } + Ordering::Greater if str1.starts_with(str2) => { + step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len()); + if consolidate_step(i2, &step_2) { + r2 = i2.step(step_2.next_hare); continue; } else { - return str1.partial_cmp(str2); + break; } } _ => { - unreachable!() + return PStrCmpResult::Ordered(str1.cmp(str2)); } } } } - - r1 = i1.next(); - r2 = i2.next(); - - continue; } } - let ordering = if r1.is_none() { - mem::swap(&mut r1, &mut r2); - Ordering::Less - } else { - Ordering::Greater - }; - - let machine_st = i1.machine_st; + break; + } - let check_focuses = || match (i1.focus(), i2.focus()) { - (Addr::EmptyList, Addr::EmptyList) => Some(Ordering::Equal), - (Addr::EmptyList, _) => Some(Ordering::Less), - (_, Addr::EmptyList) => Some(Ordering::Greater), - _ => None, - }; + // to have a cyclic term, the cell at i1.focus must be: + // + // 1) 'continuable' as a cell in a string traversal, and, + // 2) matchable by compare_pstr_prefixes to the cell at i2.focus. + // + // If both cells are continuable they must have been encountered + // and thus matched by the compare_pstr_prefixes loop previously, + // so here it suffices to check if they are both continuable. + + if i1.focus == i2.focus { + PStrCmpResult::Ordered(Ordering::Equal) + } else if i1.focus == empty_list_as_cell!() { + PStrCmpResult::Ordered(Ordering::Less) + } else if i2.focus == empty_list_as_cell!() { + PStrCmpResult::Ordered(Ordering::Greater) + } else if i1.is_continuable() { + if i2.is_continuable() { + return PStrCmpResult::Ordered(Ordering::Equal); + } - return match r1 { - Some(PStrIteratee::PStrSegment(h, n)) => { - if let &HeapCellValue::PartialString(ref pstr, _) = &machine_st.heap[h] { - if pstr.as_str_from(n).chars().next().is_some() { - Some(ordering) - } else { - check_focuses() - } - } else { - unreachable!() - } - } - Some(PStrIteratee::Char(_)) => Some(ordering), - None => check_focuses(), - }; + PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee) + } else if i2.is_continuable() { + PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee) + } else { + PStrCmpResult::Unordered } } -#[inline] -pub(super) fn compare_pstr_to_string<'a>( - heap_pstr_iter: &mut HeapPStrIter<'a>, - s: &String, -) -> Option { - let mut s_offset = 0; - - while let Some(iteratee) = heap_pstr_iter.next() { - match iteratee { - PStrIteratee::Char(c1) => { - if let Some(c2) = s[s_offset..].chars().next() { - if c1 != c2 { - return None; - } else { - s_offset += c1.len_utf8(); - } - } else { - return Some(s_offset); - } - } - PStrIteratee::PStrSegment(h, n) => match heap_pstr_iter.machine_st.heap[h] { - HeapCellValue::PartialString(ref pstr, _) => { - let t = pstr.as_str_from(n); +#[cfg(test)] +mod test { + use super::*; + use crate::machine::mock_wam::*; - if s[s_offset..].starts_with(t) { - s_offset += t.len(); - } else if t.starts_with(&s[s_offset..]) { - heap_pstr_iter.focus = Addr::PStrLocation(h, n + s[s_offset..].len()); + #[test] + fn pstr_iter_tests() { + let mut wam = MockWAM::new(); - s_offset += s[s_offset..].len(); - return Some(s_offset); - } else { - return None; - } - } - _ => { - unreachable!() - } - }, + let pstr_var_cell = put_partial_string( + &mut wam.machine_st.heap, + "abc ", + &mut wam.machine_st.atom_tbl, + ); + + let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); + + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + ); + assert_eq!(iter.next(), None); + + assert!(!iter.at_string_terminator()); + } + + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + + let pstr_second_var_cell = put_partial_string( + &mut wam.machine_st.heap, + "def", + &mut wam.machine_st.atom_tbl, + ); + + let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); + + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + ); + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(2, cell_as_atom!(pstr_second_cell), 0)) + ); + + assert_eq!(iter.next(), None); + assert!(!iter.at_string_terminator()); } - if s[s_offset..].is_empty() { - return Some(s_offset); + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(empty_list_as_cell!()); + + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); + + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + ); + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(2, cell_as_atom!(pstr_second_cell), 0)) + ); + + assert_eq!(iter.next(), None); + assert!(iter.at_string_terminator()); } - } - Some(s_offset) + wam.machine_st.heap.pop(); + wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); + + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); + + while let Some(_) = iter.next() {} + + assert!(!iter.at_string_terminator()); + } + + { + let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); + let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 0); + + assert_eq!( + compare_pstr_prefixes(&mut iter1, &mut iter2), + PStrCmpResult::Ordered(Ordering::Equal) + ); + } + + { + let second_h = wam.machine_st.heap.len(); + + // construct a structurally similar but different cyclic partial string + // matching the one beginning at wam.machine_st.heap[0]. + + put_partial_string( + &mut wam.machine_st.heap, + "ab", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.pop(); + + wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+2)); + + put_partial_string( + &mut wam.machine_st.heap, + "c ", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.pop(); + + wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+4)); + + wam.machine_st.heap.push(pstr_second_cell); + wam.machine_st.heap.push(pstr_loc_as_cell!(second_h+6)); + + wam.machine_st.heap.push(pstr_offset_as_cell!(second_h)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0))); + + let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); + let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, second_h); + + assert_eq!( + compare_pstr_prefixes(&mut iter1, &mut iter2), + PStrCmpResult::Ordered(Ordering::Equal) + ); + } + + wam.machine_st.heap.clear(); + + put_partial_string( + &mut wam.machine_st.heap, + "abc ", + &mut wam.machine_st.atom_tbl, + ); + + let pstr_cell = wam.machine_st.heap[0]; + + wam.machine_st.heap[1] = list_loc_as_cell!(2); + + wam.machine_st.heap.push(char_as_cell!('a')); + wam.machine_st.heap.push(list_loc_as_cell!(4)); + wam.machine_st.heap.push(char_as_cell!('b')); + wam.machine_st.heap.push(empty_list_as_cell!()); + + wam.machine_st.heap.push(pstr_cell); + wam.machine_st.heap.push(heap_loc_as_cell!(7)); + + { + let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); + let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 6); + + assert_eq!( + compare_pstr_prefixes(&mut iter1, &mut iter2), + PStrCmpResult::FirstIterContinuable(PStrIteratee::Char(1, 'a')), + ); + + assert_eq!(iter2.focus, heap_loc_as_cell!(7)); + } + + // test "abc" = [X,Y,Z]. + + wam.machine_st.heap.clear(); + + let cstr_var_cell = put_complete_string( + &mut wam.machine_st.heap, + "abc", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.push(list_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + + wam.machine_st.heap.push(list_loc_as_cell!(4)); + wam.machine_st.heap.push(heap_loc_as_cell!(4)); + + wam.machine_st.heap.push(list_loc_as_cell!(6)); + wam.machine_st.heap.push(heap_loc_as_cell!(6)); + + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + + assert_eq!( + wam.machine_st.heap[2], + char_as_cell!('a'), + ); + + assert_eq!( + wam.machine_st.heap[4], + char_as_cell!('b'), + ); + + assert_eq!( + wam.machine_st.heap[6], + char_as_cell!('c'), + ); + + // test "abc" = [X,Y,Z|D]. + + wam.machine_st.heap.clear(); + + let cstr_var_cell = put_complete_string( + &mut wam.machine_st.heap, + "abc", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.push(list_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); // X + + wam.machine_st.heap.push(list_loc_as_cell!(4)); + wam.machine_st.heap.push(heap_loc_as_cell!(4)); // Y + + wam.machine_st.heap.push(list_loc_as_cell!(6)); + wam.machine_st.heap.push(heap_loc_as_cell!(6)); // Z + + wam.machine_st.heap.push(heap_loc_as_cell!(7)); // D + + unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + + assert_eq!(wam.machine_st.fail, false); + + assert_eq!( + wam.machine_st.heap[2], + char_as_cell!('a'), + ); + + assert_eq!( + wam.machine_st.heap[4], + char_as_cell!('b'), + ); + + assert_eq!( + wam.machine_st.heap[6], + char_as_cell!('c'), + ); + + assert_eq!( + wam.machine_st.heap[7], + empty_list_as_cell!(), + ); + + // test "d" = [d]. + + wam.machine_st.heap.clear(); + + let cstr_var_cell = put_complete_string( + &mut wam.machine_st.heap, + "d", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.push(list_loc_as_cell!(2)); + wam.machine_st.heap.push(char_as_cell!('d')); + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + + assert_eq!(wam.machine_st.fail, false); + + // test "abc" = [X,b,Z]. + + wam.machine_st.heap.clear(); + + let cstr_var_cell = put_complete_string( + &mut wam.machine_st.heap, + "abc", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.push(list_loc_as_cell!(2)); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + + wam.machine_st.heap.push(list_loc_as_cell!(4)); + wam.machine_st.heap.push(char_as_cell!('b')); + + wam.machine_st.heap.push(list_loc_as_cell!(6)); + wam.machine_st.heap.push(heap_loc_as_cell!(6)); + + wam.machine_st.heap.push(empty_list_as_cell!()); + + unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + + assert_eq!(wam.machine_st.fail, false); + + assert_eq!( + wam.machine_st.heap[2], + char_as_cell!('a'), + ); + + assert_eq!( + wam.machine_st.heap[4], + char_as_cell!('b'), + ); + + assert_eq!( + wam.machine_st.heap[6], + char_as_cell!('c'), + ); + + // test "abcdef" = [a,b,c|X]. + + wam.machine_st.heap.clear(); + + put_complete_string( + &mut wam.machine_st.heap, + "abcdef", + &mut wam.machine_st.atom_tbl, + ); + + wam.machine_st.heap.push(pstr_as_cell!(atom!("abc"))); + wam.machine_st.heap.push(heap_loc_as_cell!(2)); + + unify!(wam.machine_st, heap_loc_as_cell!(0), pstr_loc_as_cell!(1)); + + print_heap_terms(wam.machine_st.heap.iter(), 0); + + assert_eq!(wam.machine_st.fail, false); + + assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(5)); + assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(1)); + assert_eq!(wam.machine_st.heap[4], atom_as_cstr_cell!(atom!("abcdef"))); + assert_eq!(wam.machine_st.heap[5], pstr_offset_as_cell!(4)); + assert_eq!(wam.machine_st.heap[6], fixnum_as_cell!(Fixnum::build_with("abc".len() as i64))); + + // test iteration on X = [b,c,b,c,b,c,b,c|...] as an offset. + + wam.machine_st.heap.clear(); + + wam.machine_st.heap.push(pstr_as_cell!(atom!("abc"))); + wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + wam.machine_st.heap.push(pstr_offset_as_cell!(0)); + wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); + + { + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 2); + + assert_eq!( + iter.next(), + Some(PStrIteratee::PStrSegment(2, atom!("abc"), 1)) + ); + + // assert!(iter.next().is_none()); + + while let Some(_) = iter.next() {} + } + } } diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index b93f270e..e2c74be1 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -1,12 +1,10 @@ -use prolog_parser::ast::*; -use prolog_parser::tabled_rc::*; -use prolog_parser::{atom, clause_name, rc_atom}; - +use crate::atom_table::*; +use crate::clause_types::*; use crate::forms::*; use crate::iterators::*; -use crate::machine::load_state::*; +use crate::machine::loader::*; use crate::machine::machine_errors::*; -use crate::machine::*; +use crate::parser::ast::*; use indexmap::IndexSet; @@ -30,89 +28,81 @@ pub(crate) enum CutContext { HasCutVariable, } -pub(crate) fn fold_by_str(terms: I, mut term: Term, sym: ClauseName) -> Term +pub(crate) fn fold_by_str(terms: I, mut term: Term, sym: Atom) -> Term where I: DoubleEndedIterator, { for prec in terms.rev() { - term = Term::Clause( - Cell::default(), - sym.clone(), - vec![Box::new(prec), Box::new(term)], - None, - ); + term = Term::Clause(Cell::default(), sym, vec![prec, term]); } term } pub(crate) fn to_op_decl( - prec: usize, - spec: &str, - name: ClauseName, + prec: u16, + spec: Atom, + name: Atom, ) -> Result { match spec { - "xfx" => Ok(OpDecl::new(prec, XFX, name)), - "xfy" => Ok(OpDecl::new(prec, XFY, name)), - "yfx" => Ok(OpDecl::new(prec, YFX, name)), - "fx" => Ok(OpDecl::new(prec, FX, name)), - "fy" => Ok(OpDecl::new(prec, FY, name)), - "xf" => Ok(OpDecl::new(prec, XF, name)), - "yf" => Ok(OpDecl::new(prec, YF, name)), + atom!("xfx") => Ok(OpDecl::new(OpDesc::build_with(prec, XFX as u8), name)), + atom!("xfy") => Ok(OpDecl::new(OpDesc::build_with(prec, XFY as u8), name)), + atom!("yfx") => Ok(OpDecl::new(OpDesc::build_with(prec, YFX as u8), name)), + atom!("fx") => Ok(OpDecl::new(OpDesc::build_with(prec, FX as u8), name)), + atom!("fy") => Ok(OpDecl::new(OpDesc::build_with(prec, FY as u8), name)), + atom!("xf") => Ok(OpDecl::new(OpDesc::build_with(prec, XF as u8), name)), + atom!("yf") => Ok(OpDecl::new(OpDesc::build_with(prec, YF as u8), name)), _ => Err(CompilationError::InconsistentEntry), } } fn setup_op_decl( - mut terms: Vec>, - atom_tbl: TabledData, + mut terms: Vec, + atom_tbl: &mut AtomTable, ) -> Result { - let name = match *terms.pop().unwrap() { - Term::Constant(_, Constant::Atom(name, _)) => name, - Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl), + let name = match terms.pop().unwrap() { + Term::Literal(_, Literal::Atom(name)) => name, + Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()), _ => return Err(CompilationError::InconsistentEntry), }; - let spec = match *terms.pop().unwrap() { - Term::Constant(_, Constant::Atom(name, _)) => name, - Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl), + let spec = match terms.pop().unwrap() { + Term::Literal(_, Literal::Atom(name)) => name, + Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()), _ => return Err(CompilationError::InconsistentEntry), }; - let prec = match *terms.pop().unwrap() { - Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) { + let prec = match terms.pop().unwrap() { + Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) { Ok(n) if n <= 1200 => n, _ => return Err(CompilationError::InconsistentEntry), }, _ => return Err(CompilationError::InconsistentEntry), }; - to_op_decl(prec, spec.as_str(), name) + to_op_decl(prec, spec, name) } fn setup_predicate_indicator(term: &mut Term) -> Result { match term { - Term::Clause(_, ref slash, ref mut terms, Some(_)) - if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 => + Term::Clause(_, slash, ref mut terms) + if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 => { - let arity = *terms.pop().unwrap(); - let name = *terms.pop().unwrap(); - - let arity = arity - .into_constant() - .and_then(|c| match c { - Constant::Integer(n) => n.to_usize(), - Constant::Fixnum(n) => usize::try_from(n).ok(), - _ => None, - }) - .ok_or(CompilationError::InvalidModuleExport)?; + let arity = terms.pop().unwrap(); + let name = terms.pop().unwrap(); - let name = name - .into_constant() - .and_then(|c| c.to_atom()) - .ok_or(CompilationError::InvalidModuleExport)?; + let arity = match arity { + Term::Literal(_, Literal::Integer(n)) => n.to_usize(), + Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(), + _ => None, + }.ok_or(CompilationError::InvalidModuleExport)?; + + let name = match name { + Term::Literal(_, Literal::Atom(name)) => Some(name), + _ => None, + }.ok_or(CompilationError::InvalidModuleExport)?; - if slash.as_str() == "/" { + if *slash == atom!("/") { Ok((name, arity)) } else { Ok((name, arity + 2)) @@ -148,13 +138,13 @@ fn setup_scoped_predicate_indicator(term: &mut Term) -> Result, + atom_tbl: &mut AtomTable, ) -> Result { setup_predicate_indicator(&mut term) .map(ModuleExport::PredicateKey) .or_else(|_| { - if let Term::Clause(_, name, terms, _) = term { - if terms.len() == 3 && name.as_str() == "op" { + if let Term::Clause(_, name, terms) = term { + if terms.len() == 3 && name == atom!("op") { Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?)) } else { Err(CompilationError::InvalidModuleDecl) @@ -167,18 +157,18 @@ fn setup_module_export( pub(super) fn setup_module_export_list( mut export_list: Term, - atom_tbl: TabledData, + atom_tbl: &mut AtomTable, ) -> Result, CompilationError> { let mut exports = vec![]; while let Term::Cons(_, t1, t2) = export_list { - let module_export = setup_module_export(*t1, atom_tbl.clone())?; + let module_export = setup_module_export(*t1, atom_tbl)?; exports.push(module_export); export_list = *t2; } - if let Term::Constant(_, Constant::EmptyList) = export_list { + if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list { Ok(exports) } else { Err(CompilationError::InvalidModuleDecl) @@ -186,35 +176,33 @@ pub(super) fn setup_module_export_list( } fn setup_module_decl( - mut terms: Vec>, - atom_tbl: TabledData, + mut terms: Vec, + atom_tbl: &mut AtomTable, ) -> Result { - let export_list = *terms.pop().unwrap(); - let name = terms - .pop() - .unwrap() - .into_constant() - .and_then(|c| c.to_atom()) - .ok_or(CompilationError::InvalidModuleDecl)?; + let export_list = terms.pop().unwrap(); + let name = terms.pop().unwrap(); + + let name = match name { + Term::Literal(_, Literal::Atom(name)) => Some(name), + _ => None, + }.ok_or(CompilationError::InvalidModuleDecl)?; let exports = setup_module_export_list(export_list, atom_tbl)?; + Ok(ModuleDecl { name, exports }) } -fn setup_use_module_decl(mut terms: Vec>) -> Result { - match *terms.pop().unwrap() { - Term::Clause(_, ref name, ref mut terms, None) - if name.as_str() == "library" && terms.len() == 1 => +fn setup_use_module_decl(mut terms: Vec) -> Result { + match terms.pop().unwrap() { + Term::Clause(_, name, mut terms) + if name == atom!("library") && terms.len() == 1 => { - terms - .pop() - .unwrap() - .into_constant() - .and_then(|c| c.to_atom()) - .map(|c| ModuleSource::Library(c)) - .ok_or(CompilationError::InvalidUseModuleDecl) + match terms.pop().unwrap() { + Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)), + _ => Err(CompilationError::InvalidModuleDecl), + } } - Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())), + Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)), _ => Err(CompilationError::InvalidUseModuleDecl), } } @@ -224,10 +212,10 @@ fn setup_double_quotes(mut terms: Vec>) -> Result { match dbl_quotes { - Term::Constant(_, Constant::Atom(name, _)) => { + Term::Literal(_, Literal::Atom(name, _)) => { match name.as_str() { "atom" => Ok(DoubleQuotes::Atom), "chars" => Ok(DoubleQuotes::Chars), @@ -250,34 +238,31 @@ fn setup_double_quotes(mut terms: Vec>) -> Result); fn setup_qualified_import( - mut terms: Vec>, - atom_tbl: TabledData, + mut terms: Vec, + atom_tbl: &mut AtomTable, ) -> Result { - let mut export_list = *terms.pop().unwrap(); - let module_src = match *terms.pop().unwrap() { - Term::Clause(_, ref name, ref mut terms, None) - if name.as_str() == "library" && terms.len() == 1 => + let mut export_list = terms.pop().unwrap(); + let module_src = match terms.pop().unwrap() { + Term::Clause(_, name, mut terms) + if name == atom!("library") && terms.len() == 1 => { - terms - .pop() - .unwrap() - .into_constant() - .and_then(|c| c.to_atom()) - .map(|c| ModuleSource::Library(c)) - .ok_or(CompilationError::InvalidUseModuleDecl) + match terms.pop().unwrap() { + Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)), + _ => Err(CompilationError::InvalidModuleDecl), + } } - Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())), + Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)), _ => Err(CompilationError::InvalidUseModuleDecl), }?; let mut exports = IndexSet::new(); while let Term::Cons(_, t1, t2) = export_list { - exports.insert(setup_module_export(*t1, atom_tbl.clone())?); + exports.insert(setup_module_export(*t1, atom_tbl)?); export_list = *t2; } - if let Term::Constant(_, Constant::EmptyList) = export_list { + if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list { Ok((module_src, exports)) } else { Err(CompilationError::InvalidModuleDecl) @@ -322,29 +307,29 @@ fn setup_qualified_import( * - * ? */ -fn setup_meta_predicate<'a>( - mut terms: Vec>, - load_state: &LoadState<'a>, -) -> Result<(ClauseName, ClauseName, Vec), CompilationError> { +fn setup_meta_predicate<'a, LS: LoadState<'a>>( + mut terms: Vec, + loader: &mut Loader<'a, LS>, +) -> Result<(Atom, Atom, Vec), CompilationError> { fn get_name_and_meta_specs( - name: ClauseName, - terms: &mut [Box], - ) -> Result<(ClauseName, Vec), CompilationError> { + name: Atom, + terms: &mut [Term], + ) -> Result<(Atom, Vec), CompilationError> { let mut meta_specs = vec![]; for meta_spec in terms.into_iter() { - match &**meta_spec { - Term::Constant(_, Constant::Atom(meta_spec, _)) => { - let meta_spec = match meta_spec.as_str() { - "+" => MetaSpec::Plus, - "-" => MetaSpec::Minus, - "?" => MetaSpec::Either, + match meta_spec { + Term::Literal(_, Literal::Atom(meta_spec)) => { + let meta_spec = match meta_spec { + atom!("+") => MetaSpec::Plus, + atom!("-") => MetaSpec::Minus, + atom!("?") => MetaSpec::Either, _ => return Err(CompilationError::InvalidMetaPredicateDecl), }; meta_specs.push(meta_spec); } - Term::Constant(_, Constant::Fixnum(n)) => match usize::try_from(*n) { + Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) { Ok(n) if n <= MAX_ARITY => { meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n)); } @@ -361,16 +346,15 @@ fn setup_meta_predicate<'a>( Ok((name, meta_specs)) } - match *terms.pop().unwrap() { - Term::Clause(_, name, mut terms, _) if name.as_str() == ":" && terms.len() == 2 => { - let spec = *terms.pop().unwrap(); - let module_name = *terms.pop().unwrap(); + match terms.pop().unwrap() { + Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => { + let spec = terms.pop().unwrap(); + let module_name = terms.pop().unwrap(); match module_name { - Term::Constant(_, Constant::Atom(module_name, _)) => match spec { - Term::Clause(_, name, mut terms, _) => { + Term::Literal(_, Literal::Atom(module_name)) => match spec { + Term::Clause(_, name, mut terms) => { let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; - Ok((module_name, name, meta_specs)) } _ => Err(CompilationError::InvalidMetaPredicateDecl), @@ -378,10 +362,10 @@ fn setup_meta_predicate<'a>( _ => Err(CompilationError::InvalidMetaPredicateDecl), } } - Term::Clause(_, name, mut terms, _) => { + Term::Clause(_, name, mut terms) => { let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?; Ok(( - load_state.compilation_target.module_name(), + loader.payload.compilation_target.module_name(), name, meta_specs, )) @@ -420,11 +404,11 @@ fn merge_clauses(tls: &mut VecDeque) -> Result, name: ClauseName) { +fn mark_cut_variables_as(terms: &mut Vec, name: Atom) { for term in terms.iter_mut() { match term { - &mut Term::Constant(_, Constant::Atom(ref mut var, _)) if var.as_str() == "!" => { - *var = name.clone() + &mut Term::Literal(_, Literal::Atom(ref mut var)) if *var == atom!("!") => { + *var = name; } _ => {} } @@ -433,12 +417,12 @@ fn mark_cut_variables_as(terms: &mut Vec, name: ClauseName) { fn mark_cut_variable(term: &mut Term) -> bool { let cut_var_found = match term { - &mut Term::Constant(_, Constant::Atom(ref var, _)) if var.as_str() == "!" => true, + &mut Term::Literal(_, Literal::Atom(ref var)) if *var == atom!("!") => true, _ => false, }; if cut_var_found { - *term = Term::Var(Cell::default(), rc_atom!("!")); + *term = Term::Var(Cell::default(), Rc::new(String::from("!"))); true } else { false @@ -463,21 +447,21 @@ fn check_for_internal_if_then(terms: &mut Vec) { return; } - if let Some(Term::Clause(_, ref name, ref subterms, _)) = terms.last() { - if name.as_str() != "->" || subterms.len() != 2 { + if let Some(Term::Clause(_, name, ref subterms)) = terms.last() { + if *name != atom!("->") || subterms.len() != 2 { return; } } else { return; } - if let Some(Term::Clause(_, _, mut subterms, _)) = terms.pop() { - let mut conq_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ",")); - let mut pre_cut_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ",")); + if let Some(Term::Clause(_, _, mut subterms)) = terms.pop() { + let mut conq_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(","))); + let mut pre_cut_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(","))); - conq_terms.push_front(Term::Constant( + conq_terms.push_front(Term::Literal( Cell::default(), - Constant::Atom(clause_name!("blocked_!"), None), + Literal::Atom(atom!("blocked_!")), )); while let Some(term) = pre_cut_terms.pop_back() { @@ -489,37 +473,44 @@ fn check_for_internal_if_then(terms: &mut Vec) { terms.push(fold_by_str( conq_terms.into_iter(), tail_term, - clause_name!(","), + atom!(","), )); } } -pub(super) fn setup_declaration<'a>( - load_state: &LoadState<'a>, - mut terms: Vec>, +pub(super) fn setup_declaration<'a, LS: LoadState<'a>>( + loader: &mut Loader<'a, LS>, + mut terms: Vec, ) -> Result { - let term = *terms.pop().unwrap(); - let atom_tbl = load_state.wam.machine_st.atom_tbl.clone(); + let term = terms.pop().unwrap(); match term { - Term::Clause(_, name, mut terms, _) => match (name.as_str(), terms.len()) { - ("dynamic", 1) => { - let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; + Term::Clause(_, name, mut terms) => match (name, terms.len()) { + (atom!("dynamic"), 1) => { + let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; Ok(Declaration::Dynamic(name, arity)) } - ("module", 2) => Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)), - ("op", 3) => Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)), - ("non_counted_backtracking", 1) => { - let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; + (atom!("module"), 2) => { + let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; + Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)) + } + (atom!("op"), 3) => { + let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; + Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)) + } + (atom!("non_counted_backtracking"), 1) => { + let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?; Ok(Declaration::NonCountedBacktracking(name, arity)) } - ("use_module", 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)), - ("use_module", 2) => { + (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)), + (atom!("use_module"), 2) => { + let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl; let (name, exports) = setup_qualified_import(terms, atom_tbl)?; + Ok(Declaration::UseQualifiedModule(name, exports)) } - ("meta_predicate", 1) => { - let (module_name, name, meta_specs) = setup_meta_predicate(terms, load_state)?; + (atom!("meta_predicate"), 1) => { + let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?; Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) } _ => Err(CompilationError::InconsistentEntry), @@ -529,43 +520,43 @@ pub(super) fn setup_declaration<'a>( } #[inline] -fn clause_to_query_term<'a>( - load_state: &mut LoadState<'a>, - name: ClauseName, - terms: Vec>, - fixity: Option, +fn clause_to_query_term<'a, LS: LoadState<'a>>( + loader: &mut Loader<'a, LS>, + name: Atom, + terms: Vec, ) -> QueryTerm { - let ct = load_state.get_clause_type(name, terms.len(), fixity); + let ct = loader.get_clause_type(name, terms.len()); QueryTerm::Clause(Cell::default(), ct, terms, false) } #[inline] -fn qualified_clause_to_query_term<'a>( - load_state: &mut LoadState<'a>, - module_name: ClauseName, - name: ClauseName, - terms: Vec>, - fixity: Option, +fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( + loader: &mut Loader<'a, LS>, + module_name: Atom, + name: Atom, + terms: Vec, ) -> QueryTerm { - let ct = load_state.get_qualified_clause_type(module_name, name, terms.len(), fixity); + let ct = loader.get_qualified_clause_type(module_name, name, terms.len()); QueryTerm::Clause(Cell::default(), ct, terms, false) } #[derive(Debug)] pub(crate) struct Preprocessor { + flags: MachineFlags, queue: VecDeque>, } impl Preprocessor { - pub(super) fn new() -> Self { + pub(super) fn new(flags: MachineFlags) -> Self { Preprocessor { + flags, queue: VecDeque::new(), } } fn setup_fact(&mut self, term: Term) -> Result { match term { - Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Ok(term), + Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term), _ => Err(CompilationError::InadmissibleFact), } } @@ -579,20 +570,17 @@ impl Preprocessor { } } - vars.insert(rc_atom!("!")); + vars.insert(Rc::new(String::from("!"))); vars.into_iter() .map(|v| Term::Var(Cell::default(), v)) .collect() } fn fabricate_rule_body(&self, vars: &Vec, body_term: Term) -> Term { - let vars_of_head = vars.iter().cloned().map(Box::new).collect(); - let head_term = Term::Clause(Cell::default(), clause_name!(""), vars_of_head, None); - - let rule = vec![Box::new(head_term), Box::new(body_term)]; - let turnstile = clause_name!(":-"); + let head_term = Term::Clause(Cell::default(), atom!(""), vars.clone()); + let rule = vec![head_term, body_term]; - Term::Clause(Cell::default(), turnstile, rule, None) + Term::Clause(Cell::default(), atom!(":-"), rule) } // the terms form the body of the rule. We create a head, by @@ -609,16 +597,16 @@ impl Preprocessor { fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque) { let vars = self.compute_head(&body_term); - let results = unfold_by_str(body_term, ";") + let results = unfold_by_str(body_term, atom!(";")) .into_iter() .map(|term| { - let mut subterms = unfold_by_str(term, ","); + let mut subterms = unfold_by_str(term, atom!(",")); mark_cut_variables(&mut subterms); check_for_internal_if_then(&mut subterms); let term = subterms.pop().unwrap(); - let clause = fold_by_str(subterms.into_iter(), term, clause_name!(",")); + let clause = fold_by_str(subterms.into_iter(), term, atom!(",")); self.fabricate_rule_body(&vars, clause) }) @@ -628,80 +616,78 @@ impl Preprocessor { } fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque) { - let mut prec_seq = unfold_by_str(prec, ","); - let comma_sym = clause_name!(","); - let cut_sym = atom!("!"); + let mut prec_seq = unfold_by_str(prec, atom!(",")); + let comma_sym = atom!(","); + let cut_sym = Literal::Atom(atom!("!")); - prec_seq.push(Term::Constant(Cell::default(), cut_sym)); + prec_seq.push(Term::Literal(Cell::default(), cut_sym)); - mark_cut_variables_as(&mut prec_seq, clause_name!("blocked_!")); + mark_cut_variables_as(&mut prec_seq, atom!("blocked_!")); - let mut conq_seq = unfold_by_str(conq, ","); + let mut conq_seq = unfold_by_str(conq, atom!(",")); mark_cut_variables(&mut conq_seq); prec_seq.extend(conq_seq.into_iter()); - let back_term = Box::new(prec_seq.pop().unwrap()); - let front_term = Box::new(prec_seq.pop().unwrap()); + let back_term = prec_seq.pop().unwrap(); + let front_term = prec_seq.pop().unwrap(); let body_term = Term::Clause( Cell::default(), - comma_sym.clone(), + comma_sym, vec![front_term, back_term], - None, ); self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym)) } - fn to_query_term<'a>( + fn to_query_term<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, + loader: &mut Loader<'a, LS>, term: Term, ) -> Result { match term { - Term::Constant(_, Constant::Atom(name, fixity)) => { - if name.as_str() == "!" || name.as_str() == "blocked_!" { + Term::Literal(_, Literal::Atom(name)) => { + if name == atom!("!") || name == atom!("blocked_!") { Ok(QueryTerm::BlockedCut) } else { - Ok(clause_to_query_term(load_state, name, vec![], fixity)) + Ok(clause_to_query_term(loader, name, vec![])) } } - Term::Constant(_, Constant::Char('!')) => Ok(QueryTerm::BlockedCut), + Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut), Term::Var(_, ref v) if v.as_str() == "!" => { Ok(QueryTerm::UnblockedCut(Cell::default())) } - Term::Clause(r, name, mut terms, fixity) => match (name.as_str(), terms.len()) { - (";", 2) => { - let term = Term::Clause(r, name.clone(), terms, fixity); + Term::Clause(r, name, mut terms) => match (name, terms.len()) { + (atom!(";"), 2) => { + let term = Term::Clause(r, name, terms); let (stub, clauses) = self.fabricate_disjunct(term); self.queue.push_back(clauses); Ok(QueryTerm::Jump(stub)) } - ("->", 2) => { - let conq = *terms.pop().unwrap(); - let prec = *terms.pop().unwrap(); + (atom!("->"), 2) => { + let conq = terms.pop().unwrap(); + let prec = terms.pop().unwrap(); let (stub, clauses) = self.fabricate_if_then(prec, conq); self.queue.push_back(clauses); Ok(QueryTerm::Jump(stub)) } - ("\\+", 1) => { - terms.push(Box::new(Term::Constant( + (atom!("\\+"), 1) => { + terms.push(Term::Literal( Cell::default(), - Constant::Atom(clause_name!("$fail"), None), - ))); + Literal::Atom(atom!("$fail")), + )); - let conq = - Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None)); + let conq = Term::Literal(Cell::default(), Literal::Atom(atom!("true"))); - let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None); - let terms = vec![Box::new(prec), Box::new(conq)]; + let prec = Term::Clause(Cell::default(), atom!("->"), terms); + let terms = vec![prec, conq]; - let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None); + let term = Term::Clause(Cell::default(), atom!(";"), terms); let (stub, clauses) = self.fabricate_disjunct(term); debug_assert!(clauses.len() > 0); @@ -709,104 +695,102 @@ impl Preprocessor { Ok(QueryTerm::Jump(stub)) } - ("$get_level", 1) => { - if let Term::Var(_, ref var) = *terms[0] { + (atom!("$get_level"), 1) => { + if let Term::Var(_, ref var) = &terms[0] { Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone())) } else { Err(CompilationError::InadmissibleQueryTerm) } } - (":", 2) => { - let predicate_name = *terms.pop().unwrap(); - let module_name = *terms.pop().unwrap(); + (atom!(":"), 2) => { + let predicate_name = terms.pop().unwrap(); + let module_name = terms.pop().unwrap(); match (module_name, predicate_name) { ( - Term::Constant(_, Constant::Atom(module_name, _)), - Term::Constant(_, Constant::Atom(predicate_name, fixity)), + Term::Literal(_, Literal::Atom(module_name)), + Term::Literal(_, Literal::Atom(predicate_name)), ) => Ok(qualified_clause_to_query_term( - load_state, + loader, module_name, predicate_name, vec![], - fixity, )), ( - Term::Constant(_, Constant::Atom(module_name, _)), - Term::Clause(_, name, terms, fixity), + Term::Literal(_, Literal::Atom(module_name)), + Term::Clause(_, name, terms), ) => Ok(qualified_clause_to_query_term( - load_state, + loader, module_name, name, terms, - fixity, )), (module_name, predicate_name) => { - terms.push(Box::new(module_name)); - terms.push(Box::new(predicate_name)); + terms.push(module_name); + terms.push(predicate_name); - Ok(clause_to_query_term(load_state, name, terms, fixity)) + Ok(clause_to_query_term(loader, name, terms)) } } } - _ => Ok(clause_to_query_term(load_state, name, terms, fixity)), + _ => Ok(clause_to_query_term(loader, name, terms)), }, Term::Var(..) => Ok(QueryTerm::Clause( Cell::default(), ClauseType::CallN, - vec![Box::new(term)], + vec![term], false, )), _ => Err(CompilationError::InadmissibleQueryTerm), } } - fn pre_query_term<'a>( + fn pre_query_term<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, + loader: &mut Loader<'a, LS>, term: Term, ) -> Result { match term { - Term::Clause(r, name, mut subterms, fixity) => { - if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" { - self.to_query_term(load_state, *subterms.pop().unwrap()) + Term::Clause(r, name, mut subterms) => { + if subterms.len() == 1 && name == atom!("$call_with_default_policy") { + self.to_query_term(loader, subterms.pop().unwrap()) .map(|mut query_term| { query_term.set_default_caller(); query_term }) } else { - let clause = Term::Clause(r, name, subterms, fixity); - self.to_query_term(load_state, clause) + let clause = Term::Clause(r, name, subterms); + self.to_query_term(loader, clause) } } - _ => self.to_query_term(load_state, term), + _ => self.to_query_term(loader, term), } } - fn setup_query<'a>( + fn setup_query<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, - terms: Vec>, + loader: &mut Loader<'a, LS>, + terms: Vec, cut_context: CutContext, ) -> Result, CompilationError> { let mut query_terms = vec![]; let mut work_queue = VecDeque::from(terms); while let Some(term) = work_queue.pop_front() { - let mut term = *term; + let mut term = term; - if let Term::Clause(cell, name, terms, op_spec) = term { - if name.as_str() == "," && terms.len() == 2 { - let term = Term::Clause(cell, name, terms, op_spec); - let mut subterms = unfold_by_str(term, ","); + if let Term::Clause(cell, name, terms) = term { + if name == atom!(",") && terms.len() == 2 { + let term = Term::Clause(cell, name, terms); + let mut subterms = unfold_by_str(term, atom!(",")); while let Some(subterm) = subterms.pop() { - work_queue.push_front(Box::new(subterm)); + work_queue.push_front(subterm); } continue; } else { - term = Term::Clause(cell, name, terms, op_spec); + term = Term::Clause(cell, name, terms); } } @@ -814,30 +798,30 @@ impl Preprocessor { mark_cut_variable(&mut term); } - query_terms.push(self.pre_query_term(load_state, term)?); + query_terms.push(self.pre_query_term(loader, term)?); } Ok(query_terms) } - fn setup_rule<'a>( + fn setup_rule<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, - mut terms: Vec>, + loader: &mut Loader<'a, LS>, + mut terms: Vec, cut_context: CutContext, ) -> Result { let post_head_terms: Vec<_> = terms.drain(1..).collect(); - let mut query_terms = self.setup_query(load_state, post_head_terms, cut_context)?; + let mut query_terms = self.setup_query(loader, post_head_terms, cut_context)?; let clauses = query_terms.drain(1..).collect(); let qt = query_terms.pop().unwrap(); - match *terms.pop().unwrap() { - Term::Clause(_, name, terms, _) => Ok(Rule { + match terms.pop().unwrap() { + Term::Clause(_, name, terms) => Ok(Rule { head: (name, terms, qt), clauses, }), - Term::Constant(_, Constant::Atom(name, _)) => Ok(Rule { + Term::Literal(_, Literal::Atom(name)) => Ok(Rule { head: (name, vec![], qt), clauses, }), @@ -845,37 +829,37 @@ impl Preprocessor { } } - fn try_term_to_query<'a>( + fn try_term_to_query<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, - terms: Vec>, + loader: &mut Loader<'a, LS>, + terms: Vec, cut_context: CutContext, ) -> Result { Ok(TopLevel::Query(self.setup_query( - load_state, + loader, terms, cut_context, )?)) } - pub(super) fn try_term_to_tl<'a>( + pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, + loader: &mut Loader<'a, LS>, term: Term, cut_context: CutContext, ) -> Result { match term { - Term::Clause(r, name, terms, fixity) => { - if name.as_str() == "?-" { - self.try_term_to_query(load_state, terms, cut_context) - } else if name.as_str() == ":-" && terms.len() == 2 { + Term::Clause(r, name, terms) => { + if name == atom!("?-") { + self.try_term_to_query(loader, terms, cut_context) + } else if name == atom!(":-") && terms.len() == 2 { Ok(TopLevel::Rule(self.setup_rule( - load_state, + loader, terms, cut_context, )?)) } else { - let term = Term::Clause(r, name, terms, fixity); + let term = Term::Clause(r, name, terms); Ok(TopLevel::Fact(self.setup_fact(term)?)) } } @@ -883,30 +867,30 @@ impl Preprocessor { } } - fn try_terms_to_tls<'a, I: IntoIterator>( + fn try_terms_to_tls<'a, I: IntoIterator, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, + loader: &mut Loader<'a, LS>, terms: I, cut_context: CutContext, ) -> Result, CompilationError> { let mut results = VecDeque::new(); for term in terms.into_iter() { - results.push_back(self.try_term_to_tl(load_state, term, cut_context)?); + results.push_back(self.try_term_to_tl(loader, term, cut_context)?); } Ok(results) } - pub(super) fn parse_queue<'a>( + pub(super) fn parse_queue<'a, LS: LoadState<'a>>( &mut self, - load_state: &mut LoadState<'a>, + loader: &mut Loader<'a, LS>, ) -> Result, CompilationError> { let mut queue = VecDeque::new(); while let Some(terms) = self.queue.pop_front() { let clauses = merge_clauses(&mut self.try_terms_to_tls( - load_state, + loader, terms, CutContext::HasCutVariable, )?)?; diff --git a/src/machine/stack.rs b/src/machine/stack.rs index a3c91713..1ab988cd 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -1,16 +1,15 @@ use core::marker::PhantomData; +use crate::types::*; + use crate::machine::machine_indices::*; -use crate::machine::raw_block::*; +use crate::raw_block::*; use std::mem; use std::ops::{Index, IndexMut}; use std::ptr; -#[derive(Debug)] -struct StackTraits {} - -impl RawBlockTraits for StackTraits { +impl RawBlockTraits for Stack { #[inline] fn init_size() -> usize { 10 * 1024 * 1024 @@ -18,31 +17,23 @@ impl RawBlockTraits for StackTraits { #[inline] fn align() -> usize { - mem::align_of::() - } - - #[inline] - fn base_offset(base: *const u8) -> *const u8 { - unsafe { base.offset(Self::align() as isize) } + mem::align_of::() } } -const fn prelude_size() -> usize { - let size = mem::size_of::(); - let align = mem::align_of::(); - - (size & !(align - 1)) + align +#[inline(always)] +pub const fn prelude_size() -> usize { + mem::size_of::() } #[derive(Debug)] -pub(crate) struct Stack { - buf: RawBlock, - _marker: PhantomData, +pub struct Stack { + buf: RawBlock, + _marker: PhantomData, } impl Drop for Stack { fn drop(&mut self) { - self.drop_in_place(); self.buf.deallocate(); } } @@ -57,7 +48,7 @@ pub(crate) struct AndFramePrelude { pub(crate) univ_prelude: FramePrelude, pub(crate) e: usize, pub(crate) cp: LocalCodePtr, - pub(crate) interrupt_cp: LocalCodePtr, + pub(crate) interrupt_cp: LocalCodePtr, // TODO: get rid of it! } #[derive(Debug)] @@ -67,22 +58,22 @@ pub(crate) struct AndFrame { impl AndFrame { pub(crate) fn size_of(num_cells: usize) -> usize { - prelude_size::() + num_cells * mem::size_of::() + prelude_size::() + num_cells * mem::size_of::() } } impl Index for AndFrame { - type Output = Addr; + type Output = HeapCellValue; fn index(&self, index: usize) -> &Self::Output { let prelude_offset = prelude_size::(); - let index_offset = (index - 1) * mem::size_of::(); + let index_offset = (index - 1) * mem::size_of::(); unsafe { let ptr = mem::transmute::<&AndFrame, *const u8>(self); let ptr = ptr as usize + prelude_offset + index_offset; - &*(ptr as *const Addr) + &*(ptr as *const HeapCellValue) } } } @@ -90,13 +81,35 @@ impl Index for AndFrame { impl IndexMut for AndFrame { fn index_mut(&mut self, index: usize) -> &mut Self::Output { let prelude_offset = prelude_size::(); - let index_offset = (index - 1) * mem::size_of::(); + let index_offset = (index - 1) * mem::size_of::(); unsafe { let ptr = mem::transmute::<&mut AndFrame, *const u8>(self); let ptr = ptr as usize + prelude_offset + index_offset; - &mut *(ptr as *mut Addr) + &mut *(ptr as *mut HeapCellValue) + } + } +} + +impl Index for Stack { + type Output = HeapCellValue; + + #[inline] + fn index(&self, index: usize) -> &Self::Output { + unsafe { + let ptr = self.buf.base as usize + index; + &*(ptr as *const HeapCellValue) + } + } +} + +impl IndexMut for Stack { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + unsafe { + let ptr = self.buf.base as usize + index; + &mut *(ptr as *mut HeapCellValue) } } } @@ -119,18 +132,18 @@ pub(crate) struct OrFrame { } impl Index for OrFrame { - type Output = Addr; + type Output = HeapCellValue; #[inline] fn index(&self, index: usize) -> &Self::Output { let prelude_offset = prelude_size::(); - let index_offset = index * mem::size_of::(); + let index_offset = index * mem::size_of::(); unsafe { let ptr = mem::transmute::<&OrFrame, *const u8>(self); let ptr = ptr as usize + prelude_offset + index_offset; - &*(ptr as *const Addr) + &*(ptr as *const HeapCellValue) } } } @@ -139,20 +152,20 @@ impl IndexMut for OrFrame { #[inline] fn index_mut(&mut self, index: usize) -> &mut Self::Output { let prelude_offset = prelude_size::(); - let index_offset = index * mem::size_of::(); + let index_offset = index * mem::size_of::(); unsafe { let ptr = mem::transmute::<&mut OrFrame, *const u8>(self); let ptr = ptr as usize + prelude_offset + index_offset; - &mut *(ptr as *mut Addr) + &mut *(ptr as *mut HeapCellValue) } } } impl OrFrame { pub(crate) fn size_of(num_cells: usize) -> usize { - prelude_size::() + num_cells * mem::size_of::() + prelude_size::() + num_cells * mem::size_of::() } } @@ -164,26 +177,39 @@ impl Stack { } } + #[inline(always)] + unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 { + loop { + let ptr = self.buf.alloc(frame_size); + + if ptr.is_null() { + self.buf.grow(); + } else { + return ptr; + } + } + } + pub(crate) fn allocate_and_frame(&mut self, num_cells: usize) -> usize { let frame_size = AndFrame::size_of(num_cells); unsafe { - let new_top = self.buf.new_block(frame_size); - let e = self.buf.top as usize - self.buf.base as usize; + let e = self.buf.ptr as usize - self.buf.base as usize; + let new_ptr = self.alloc(frame_size); + let mut offset = prelude_size::(); for idx in 0..num_cells { - let offset = prelude_size::() + idx * mem::size_of::(); ptr::write( - (self.buf.top as usize + offset) as *mut Addr, - Addr::StackCell(e, idx + 1), + (new_ptr as usize + offset) as *mut HeapCellValue, + stack_loc_as_cell!(AndFrame, e, idx + 1), ); + + offset += mem::size_of::(); } - let and_frame = &mut *(self.buf.top as *mut AndFrame); + let and_frame = &mut *(new_ptr as *mut AndFrame); and_frame.prelude.univ_prelude.num_cells = num_cells; - self.buf.top = new_top; - e } } @@ -192,27 +218,27 @@ impl Stack { let frame_size = OrFrame::size_of(num_cells); unsafe { - let new_top = self.buf.new_block(frame_size); - let b = self.buf.top as usize - self.buf.base as usize; + let b = self.buf.ptr as usize - self.buf.base as usize; + let new_ptr = self.alloc(frame_size); + let mut offset = prelude_size::(); for idx in 0..num_cells { - let offset = prelude_size::() + idx * mem::size_of::(); ptr::write( - (self.buf.top as usize + offset) as *mut Addr, - Addr::StackCell(b, idx), + (new_ptr as usize + offset) as *mut HeapCellValue, + stack_loc_as_cell!(OrFrame, b, idx), ); + + offset += mem::size_of::(); } - let or_frame = &mut *(self.buf.top as *mut OrFrame); + let or_frame = &mut *(new_ptr as *mut OrFrame); or_frame.prelude.univ_prelude.num_cells = num_cells; - self.buf.top = new_top; - b } } - #[inline] + #[inline(always)] pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame { unsafe { let ptr = self.buf.base as usize + e; @@ -220,7 +246,7 @@ impl Stack { } } - #[inline] + #[inline(always)] pub(crate) fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame { unsafe { let ptr = self.buf.base as usize + e; @@ -228,7 +254,7 @@ impl Stack { } } - #[inline] + #[inline(always)] pub(crate) fn index_or_frame(&self, b: usize) -> &OrFrame { unsafe { let ptr = self.buf.base as usize + b; @@ -236,7 +262,7 @@ impl Stack { } } - #[inline] + #[inline(always)] pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame { unsafe { let ptr = self.buf.base as usize + b; @@ -244,31 +270,65 @@ impl Stack { } } - #[inline] + #[inline(always)] pub(crate) fn truncate(&mut self, b: usize) { - if b == 0 { - self.inner_truncate(mem::align_of::()); - } else { - self.inner_truncate(b); + let base = self.buf.base as usize + b; + + if base < self.buf.ptr as usize { + self.buf.ptr = base as *mut _; } } +} - #[inline] - fn inner_truncate(&mut self, b: usize) { - let base = b + self.buf.base as usize; +#[cfg(test)] +mod tests { + use super::*; + + use crate::machine::mock_wam::*; + + #[test] + fn stack_tests() { + let mut wam = MockWAM::new(); - if base < self.buf.top as usize { - self.buf.top = base as *const _; + let e = wam.machine_st.stack.allocate_and_frame(10); // create an AND frame! + let and_frame = wam.machine_st.stack.index_and_frame_mut(e); + + assert_eq!( + e, + 0// 10 * mem::size_of::() + prelude_size::() + ); + + assert_eq!(and_frame.prelude.univ_prelude.num_cells, 10); + + for idx in 0..10 { + assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, e, idx + 1)); + } + + and_frame[5] = empty_list_as_cell!(); + + assert_eq!(and_frame[5], empty_list_as_cell!()); + + let b = wam.machine_st.stack.allocate_or_frame(5); + + let or_frame = wam.machine_st.stack.index_or_frame_mut(b); + + for idx in 0..5 { + assert_eq!(or_frame[idx], stack_loc_as_cell!(OrFrame, b, idx)); + } + + let next_e = wam.machine_st.stack.allocate_and_frame(9); // create an AND frame! + let and_frame = wam.machine_st.stack.index_and_frame_mut(next_e); + + for idx in 0..9 { + assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, next_e, idx + 1)); } - } - pub(crate) fn drop_in_place(&mut self) { - self.truncate(mem::align_of::()); + let and_frame = wam.machine_st.stack.index_and_frame(e); + assert_eq!(and_frame[5], empty_list_as_cell!()); - debug_assert!(if self.buf.top.is_null() { - self.buf.top == self.buf.base - } else { - self.buf.top as usize == self.buf.base as usize + mem::align_of::() - }); + assert_eq!( + wam.machine_st.stack[stack_loc!(AndFrame, e, 5)], + empty_list_as_cell!() + ); } } diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 69f66022..064d9fa8 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1,47 +1,52 @@ -use prolog_parser::ast::*; -use prolog_parser::clause_name; +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::parser::char_reader::*; +use crate::read::*; +use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -use crate::read::readline::*; -use crate::read::PrologStream; +use crate::types::*; + +pub use modular_bitfield::prelude::*; -use std::cell::RefCell; use std::cmp::Ordering; use std::error::Error; use std::fmt; -use std::fs::File; -use std::hash::{Hash, Hasher}; +use std::fs::{File, OpenOptions}; +use std::hash::{Hash}; use std::io; -use std::io::{stderr, stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; +use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write}; use std::mem; -use std::net::{Shutdown, TcpStream}; -use std::ops::DerefMut; -use std::rc::Rc; +use std::net::{TcpStream, Shutdown}; +use std::ops::{Deref, DerefMut}; +use std::ptr; use native_tls::TlsStream; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) enum StreamType { +#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)] +#[bits = 1] +pub enum StreamType { Binary, Text, } impl StreamType { #[inline] - pub(crate) fn as_str(&self) -> &'static str { + pub(crate) fn as_atom(&self) -> Atom { match self { - StreamType::Binary => "binary_stream", - StreamType::Text => "text_stream", + StreamType::Binary => atom!("binary_stream"), + StreamType::Text => atom!("text_stream"), } } #[inline] - pub(crate) fn as_property_str(&self) -> &'static str { + pub(crate) fn as_property_atom(&self) -> Atom { match self { - StreamType::Binary => "binary", - StreamType::Text => "text", + StreamType::Binary => atom!("binary"), + StreamType::Text => atom!("text"), } } @@ -54,14 +59,16 @@ impl StreamType { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub(crate) enum EOFAction { +#[derive(Debug, BitfieldSpecifier, Clone, Copy, PartialEq, Eq, Hash)] +#[bits = 2] +pub enum EOFAction { EOFCode, Error, Reset, } -#[derive(Debug, PartialEq)] +#[derive(Debug, BitfieldSpecifier, Copy, Clone, PartialEq)] +#[bits = 2] pub(crate) enum AtEndOfStream { Not, At, @@ -70,165 +77,706 @@ pub(crate) enum AtEndOfStream { impl AtEndOfStream { #[inline] - pub(crate) fn as_str(&self) -> &'static str { + pub(crate) fn as_atom(&self) -> Atom { match self { - AtEndOfStream::Not => "not", - AtEndOfStream::Past => "past", - AtEndOfStream::At => "at", + AtEndOfStream::Not => atom!("not"), + AtEndOfStream::Past => atom!("past"), + AtEndOfStream::At => atom!("at"), } } } impl EOFAction { #[inline] - pub(crate) fn as_str(&self) -> &'static str { + pub(crate) fn as_atom(&self) -> Atom { match self { - EOFAction::EOFCode => "eof_code", - EOFAction::Error => "error", - EOFAction::Reset => "reset", + EOFAction::EOFCode => atom!("eof_code"), + EOFAction::Error => atom!("error"), + EOFAction::Reset => atom!("reset"), } } } -fn parser_top_to_bytes(mut buf: Vec>) -> io::Result> { - let mut str_buf = String::new(); +#[derive(Debug)] +pub struct ByteStream(Cursor>); - while let Some(c) = buf.pop() { - str_buf.push(c?); +impl Read for ByteStream { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.0.read(buf) + } +} + +impl Write for ByteStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.0.write(buf) } - unsafe { - let array = str_buf.as_bytes_mut(); - array.reverse(); - Ok(Vec::from(array)) + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.0.flush() } } -/* all these streams are closed automatically when the instance is - * dropped. */ -enum StreamInstance { - Bytes(Cursor>), - InputFile(ClauseName, File), - OutputFile(ClauseName, File, bool), // File, append. - Null, - PausedPrologStream(Vec, Box), - ReadlineStream(ReadlineStream), - StaticStr(Cursor<&'static str>), - Stderr, - Stdout, - TcpStream(ClauseName, TcpStream), - TlsStream(ClauseName, TlsStream), +#[derive(Debug)] +pub struct InputFileStream { + file_name: Atom, + file: File, } -impl StreamInstance { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self { - StreamInstance::PausedPrologStream(ref mut put_back, ref mut stream) => { - let mut index = 0; +impl Read for InputFileStream { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.file.read(buf) + } +} - while index < buf.len() { - if let Some(b) = put_back.pop() { - buf[index] = b; - index += 1; - } else { - break; - } - } +#[derive(Debug)] +pub struct OutputFileStream { + file_name: Atom, + file: File, + is_append: bool, +} - if index == buf.len() { - Ok(buf.len()) - } else { - stream - .read(&mut buf[index..]) - .map(|bytes_read| bytes_read + index) - } - } - StreamInstance::InputFile(_, ref mut file) => file.read(buf), - StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.read(buf), - StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.read(buf), - StreamInstance::ReadlineStream(ref mut rl_stream) => rl_stream.read(buf), - StreamInstance::StaticStr(ref mut src) => src.read(buf), - StreamInstance::Bytes(ref mut cursor) => cursor.read(buf), - StreamInstance::OutputFile(..) - | StreamInstance::Stderr - | StreamInstance::Stdout - | StreamInstance::Null => Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::ReadFromOutputStream, - )), +impl Write for OutputFileStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.file.write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.file.flush() + } +} + +#[derive(Debug)] +pub struct StaticStringStream { + stream: Cursor<&'static str>, +} + +impl Read for StaticStringStream { + #[inline(always)] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.stream.read(buf) + } +} + +impl CharRead for StaticStringStream { + #[inline(always)] + fn peek_char(&mut self) -> Option> { + let pos = self.stream.position() as usize; + self.stream.get_ref()[pos ..].chars().next().map(Ok) + } + + #[inline(always)] + fn consume(&mut self, nread: usize) { + self.stream.seek(SeekFrom::Current(nread as i64)).unwrap(); + } + + #[inline(always)] + fn put_back_char(&mut self, c: char) { + self.stream.seek(SeekFrom::Current(- (c.len_utf8() as i64))).unwrap(); + } +} + +#[derive(Debug)] +pub struct NamedTcpStream { + address: Atom, + tcp_stream: TcpStream, +} + +impl Read for NamedTcpStream { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.tcp_stream.read(buf) + } +} + +impl Write for NamedTcpStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.tcp_stream.write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.tcp_stream.flush() + } +} + +#[derive(Debug)] +pub struct NamedTlsStream { + address: Atom, + tls_stream: TlsStream, +} + +impl Read for NamedTlsStream { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.tls_stream.read(buf) + } +} + +impl Write for NamedTlsStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.tls_stream.write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.tls_stream.flush() + } +} + +/* +#[derive(Debug)] +pub struct NullStream {} +*/ + +#[derive(Debug)] +pub struct StandardOutputStream {} + +impl Write for StandardOutputStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + io::stdout().write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + io::stdout().flush() + } +} + +#[derive(Debug)] +pub struct StandardErrorStream {} + +impl Write for StandardErrorStream { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + io::stderr().write(buf) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + io::stderr().flush() + } +} + +#[bitfield] +#[repr(u64)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct StreamOptions { + pub stream_type: StreamType, + pub reposition: bool, + pub eof_action: EOFAction, + pub has_alias: bool, + pub alias: B59, +} + +impl StreamOptions { + #[inline] + pub fn get_alias(self) -> Option { + if self.has_alias() { + Some(Atom::from((self.alias() << 3) as usize)) + } else { + None + } + } + + #[inline] + pub fn set_alias_to_atom_opt(&mut self, alias: Option) { + self.set_has_alias(alias.is_some()); + + if let Some(alias) = alias { + self.set_alias(alias.flat_index()); } } } -impl fmt::Debug for StreamInstance { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { - &StreamInstance::Bytes(ref bytes) => write!(fmt, "Bytes({:?})", bytes), - &StreamInstance::StaticStr(_) => write!(fmt, "StaticStr(_)"), // Hacky solution. - &StreamInstance::InputFile(_, ref file) => write!(fmt, "InputFile({:?})", file), - &StreamInstance::OutputFile(_, ref file, _) => write!(fmt, "OutputFile({:?})", file), - &StreamInstance::Null => write!(fmt, "Null"), - &StreamInstance::PausedPrologStream(ref put_back, ref stream) => { - write!(fmt, "PausedPrologStream({:?}, {:?})", put_back, stream) - } - &StreamInstance::ReadlineStream(ref readline_stream) => { - write!(fmt, "ReadlineStream({:?})", readline_stream) +impl Default for StreamOptions { + #[inline] + fn default() -> Self { + StreamOptions::new() + .with_stream_type(StreamType::Text) + .with_reposition(false) + .with_eof_action(EOFAction::EOFCode) + .with_has_alias(false) + .with_alias(0) + } +} + +#[derive(Debug, Copy, Clone)] +pub struct StreamLayout { + pub options: StreamOptions, + pub lines_read: usize, + past_end_of_stream: bool, + stream: T, +} + +impl StreamLayout { + #[inline] + pub fn new(stream: T) -> Self { + Self { + options: StreamOptions::default(), + lines_read: 0, + past_end_of_stream: false, + stream, + } + } +} + +impl Deref for StreamLayout { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.stream + } +} + +impl DerefMut for StreamLayout { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.stream + } +} + +macro_rules! arena_allocated_impl_for_stream { + ($stream_type:ty, $stream_tag:ident) => { + impl ArenaAllocated for StreamLayout<$stream_type> { + type PtrToAllocated = TypedArenaPtr>; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::$stream_tag } - &StreamInstance::Stderr => write!(fmt, "Stderr"), - &StreamInstance::Stdout => write!(fmt, "Stdout"), - &StreamInstance::TcpStream(_, ref tcp_stream) => { - write!(fmt, "TcpStream({:?})", tcp_stream) + + #[inline] + fn size(&self) -> usize { + mem::size_of::>() } - &StreamInstance::TlsStream(_, ref tls_stream) => { - write!(fmt, "TlsStream({:?})", tls_stream) + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } } } + }; +} + +/* +pub mod testing { + use super::PausedPrologStream; + + impl PausedPrologStream { + #[allow(dead_code)] + pub fn write_test_input(&mut self, string: &str) { + self.bytes.extend(string.as_bytes().iter().rev()); + } + } +} +*/ +/* +impl ArenaAllocated for PausedPrologStream { + type PtrToAllocated = TypedArenaPtr; + + #[inline] + fn tag() -> ArenaHeaderTag { + ArenaHeaderTag::PausedPrologStream + } + + #[inline] + fn size(&self) -> usize { + mem::size_of::() + } + + #[inline] + fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { + unsafe { + ptr::write(dst, self); + TypedArenaPtr::new(dst as *mut Self) + } } } #[derive(Debug)] -pub(crate) struct InnerStream { - options: StreamOptions, - stream_inst: StreamInstance, - past_end_of_stream: bool, - lines_read: usize, +pub struct PausedPrologStream { + bytes: Vec, + paused_stream: Stream, } -#[derive(Debug, Clone)] -struct WrappedStreamInstance(Rc>); +impl PausedPrologStream { + #[inline] + pub fn new() -> Self { + PausedPrologStream { + bytes: vec![], + paused_stream: Stream::Null(StreamOptions::default()), + } + } +} -impl WrappedStreamInstance { +impl Read for PausedPrologStream { #[inline] - fn new(stream_inst: StreamInstance, past_end_of_stream: bool) -> Self { - WrappedStreamInstance(Rc::new(RefCell::new(InnerStream { - options: StreamOptions::default(), - stream_inst, - past_end_of_stream, - lines_read: 0, - }))) + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.paused_stream.read(buf) } } +*/ + +arena_allocated_impl_for_stream!(CharReader, ByteStream); +arena_allocated_impl_for_stream!(CharReader, InputFileStream); +arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream); +arena_allocated_impl_for_stream!(CharReader, NamedTcpStream); +arena_allocated_impl_for_stream!(CharReader, NamedTlsStream); +arena_allocated_impl_for_stream!(ReadlineStream, ReadlineStream); +arena_allocated_impl_for_stream!(StaticStringStream, StaticStringStream); +arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream); +arena_allocated_impl_for_stream!(StandardErrorStream, StandardErrorStream); + +#[derive(Debug, Copy, Clone)] +pub enum Stream { + Byte(TypedArenaPtr>>), + InputFile(TypedArenaPtr>>), + OutputFile(TypedArenaPtr>), + StaticString(TypedArenaPtr>), + NamedTcp(TypedArenaPtr>>), + NamedTls(TypedArenaPtr>>), + Null(StreamOptions), + Readline(TypedArenaPtr>), + StandardOutput(TypedArenaPtr>), + StandardError(TypedArenaPtr>), +} + +impl From>> for Stream { + #[inline] + fn from(stream: TypedArenaPtr>) -> Stream { + Stream::Readline(stream) + } +} + +impl Stream { + #[inline] + pub fn from_readline_stream(stream: ReadlineStream, arena: &mut Arena) -> Stream { + Stream::Readline(arena_alloc!(StreamLayout::new(stream), arena)) + } + + #[inline] + pub fn from_owned_string(string: String, arena: &mut Arena) -> Stream { + Stream::Byte(arena_alloc!( + StreamLayout::new(CharReader::new(ByteStream(Cursor::new(string.into_bytes())))), + arena + )) + } + + #[inline] + pub fn from_static_string(src: &'static str, arena: &mut Arena) -> Stream { + Stream::StaticString(arena_alloc!( + StreamLayout::new(StaticStringStream { + stream: Cursor::new(src) + }), + arena + )) + } + + #[inline] + pub fn stdin(arena: &mut Arena) -> Stream { + Stream::Readline(arena_alloc!( + StreamLayout::new(ReadlineStream::new("")), + arena + )) + } + + pub fn from_tag(tag: ArenaHeaderTag, ptr: *const u8) -> Self { + match tag { + ArenaHeaderTag::ByteStream => Stream::Byte(TypedArenaPtr::new(ptr as *mut _)), + ArenaHeaderTag::InputFileStream => Stream::InputFile(TypedArenaPtr::new(ptr as *mut _)), + ArenaHeaderTag::OutputFileStream => { + Stream::OutputFile(TypedArenaPtr::new(ptr as *mut _)) + } + ArenaHeaderTag::NamedTcpStream => Stream::NamedTcp(TypedArenaPtr::new(ptr as *mut _)), + ArenaHeaderTag::NamedTlsStream => Stream::NamedTls(TypedArenaPtr::new(ptr as *mut _)), + ArenaHeaderTag::ReadlineStream => Stream::Readline(TypedArenaPtr::new(ptr as *mut _)), + ArenaHeaderTag::StaticStringStream => { + Stream::StaticString(TypedArenaPtr::new(ptr as *mut _)) + } + ArenaHeaderTag::StandardOutputStream => { + Stream::StandardOutput(TypedArenaPtr::new(ptr as *mut _)) + } + ArenaHeaderTag::StandardErrorStream => { + Stream::StandardError(TypedArenaPtr::new(ptr as *mut _)) + } + ArenaHeaderTag::NullStream => Stream::Null(StreamOptions::default()), + _ => unreachable!(), + } + } + + #[inline] + pub fn is_stderr(&self) -> bool { + if let Stream::StandardError(_) = self { + true + } else { + false + } + } + + #[inline] + pub fn is_stdout(&self) -> bool { + if let Stream::StandardOutput(_) = self { + true + } else { + false + } + } + + #[inline] + pub fn is_stdin(&self) -> bool { + if let Stream::Readline(_) = self { + true + } else { + false + } + } + + pub fn as_ptr(&self) -> *const ArenaHeader { + match self { + Stream::Byte(ptr) => ptr.header_ptr(), + Stream::InputFile(ptr) => ptr.header_ptr(), + Stream::OutputFile(ptr) => ptr.header_ptr(), + Stream::StaticString(ptr) => ptr.header_ptr(), + Stream::NamedTcp(ptr) => ptr.header_ptr(), + Stream::NamedTls(ptr) => ptr.header_ptr(), + Stream::Null(_) => ptr::null(), + Stream::Readline(ptr) => ptr.header_ptr(), + Stream::StandardOutput(ptr) => ptr.header_ptr(), + Stream::StandardError(ptr) => ptr.header_ptr(), + } + } + + pub fn options(&self) -> &StreamOptions { + match self { + Stream::Byte(ref ptr) => &ptr.options, + Stream::InputFile(ref ptr) => &ptr.options, + Stream::OutputFile(ref ptr) => &ptr.options, + Stream::StaticString(ref ptr) => &ptr.options, + Stream::NamedTcp(ref ptr) => &ptr.options, + Stream::NamedTls(ref ptr) => &ptr.options, + Stream::Null(ref options) => options, + Stream::Readline(ref ptr) => &ptr.options, + Stream::StandardOutput(ref ptr) => &ptr.options, + Stream::StandardError(ref ptr) => &ptr.options, + } + } + + pub fn options_mut(&mut self) -> &mut StreamOptions { + match self { + Stream::Byte(ref mut ptr) => &mut ptr.options, + Stream::InputFile(ref mut ptr) => &mut ptr.options, + Stream::OutputFile(ref mut ptr) => &mut ptr.options, + Stream::StaticString(ref mut ptr) => &mut ptr.options, + Stream::NamedTcp(ref mut ptr) => &mut ptr.options, + Stream::NamedTls(ref mut ptr) => &mut ptr.options, + Stream::Null(ref mut options) => options, + Stream::Readline(ref mut ptr) => &mut ptr.options, + Stream::StandardOutput(ref mut ptr) => &mut ptr.options, + Stream::StandardError(ref mut ptr) => &mut ptr.options, + } + } + + /* + fn unpause_stream(&mut self) { + let stream_inst = match self { + Stream::PausedProlog(paused) if paused.bytes.is_empty() => { + mem::replace(&mut paused.paused_stream, Stream::Null(StreamOptions::default())) + } + _ => { + return; + } + }; + + *self = stream_inst; + } + */ + + #[inline] + pub(crate) fn add_lines_read(&mut self, incr_num_lines_read: usize) { + match self { + Stream::Byte(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::InputFile(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::OutputFile(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::StaticString(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::NamedTcp(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::NamedTls(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::Null(_) => {} + Stream::Readline(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::StandardOutput(ptr) => ptr.lines_read += incr_num_lines_read, + Stream::StandardError(ptr) => ptr.lines_read += incr_num_lines_read, + } + } + + #[inline] + pub(crate) fn set_lines_read(&mut self, value: usize) { + match self { + Stream::Byte(ptr) => ptr.lines_read = value, + Stream::InputFile(ptr) => ptr.lines_read = value, + Stream::OutputFile(ptr) => ptr.lines_read = value, + Stream::StaticString(ptr) => ptr.lines_read = value, + Stream::NamedTcp(ptr) => ptr.lines_read = value, + Stream::NamedTls(ptr) => ptr.lines_read = value, + Stream::Null(_) => {} + Stream::Readline(ptr) => ptr.lines_read = value, + Stream::StandardOutput(ptr) => ptr.lines_read = value, + Stream::StandardError(ptr) => ptr.lines_read = value, + } + } + + #[inline] + pub(crate) fn lines_read(&self) -> usize { + match self { + Stream::Byte(ptr) => ptr.lines_read, + Stream::InputFile(ptr) => ptr.lines_read, + Stream::OutputFile(ptr) => ptr.lines_read, + Stream::StaticString(ptr) => ptr.lines_read, + Stream::NamedTcp(ptr) => ptr.lines_read, + Stream::NamedTls(ptr) => ptr.lines_read, + Stream::Null(_) => 0, + Stream::Readline(ptr) => ptr.lines_read, + Stream::StandardOutput(ptr) => ptr.lines_read, + Stream::StandardError(ptr) => ptr.lines_read, + } + } +} + +impl CharRead for Stream { + fn peek_char(&mut self) -> Option> { + match self { + Stream::InputFile(file) => (*file).peek_char(), + Stream::NamedTcp(tcp_stream) => (*tcp_stream).peek_char(), + Stream::NamedTls(tls_stream) => (*tls_stream).peek_char(), + Stream::Readline(rl_stream) => (*rl_stream).peek_char(), + Stream::StaticString(src) => (*src).peek_char(), + Stream::Byte(cursor) => (*cursor).peek_char(), + Stream::OutputFile(_) | + Stream::StandardError(_) | + Stream::StandardOutput(_) | + Stream::Null(_) => Some(Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::ReadFromOutputStream, + ))), + } + } + + fn read_char(&mut self) -> Option> { + match self { + Stream::InputFile(file) => (*file).read_char(), + Stream::NamedTcp(tcp_stream) => (*tcp_stream).read_char(), + Stream::NamedTls(tls_stream) => (*tls_stream).read_char(), + Stream::Readline(rl_stream) => (*rl_stream).read_char(), + Stream::StaticString(src) => (*src).read_char(), + Stream::Byte(cursor) => (*cursor).read_char(), + Stream::OutputFile(_) | + Stream::StandardError(_) | + Stream::StandardOutput(_) | + Stream::Null(_) => Some(Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::ReadFromOutputStream, + ))), + } + } + + fn put_back_char(&mut self, c: char) { + match self { + Stream::InputFile(file) => file.put_back_char(c), + Stream::NamedTcp(tcp_stream) => tcp_stream.put_back_char(c), + Stream::NamedTls(tls_stream) => tls_stream.put_back_char(c), + Stream::Readline(rl_stream) => rl_stream.put_back_char(c), + Stream::StaticString(src) => src.put_back_char(c), + Stream::Byte(cursor) => cursor.put_back_char(c), + Stream::OutputFile(_) | + Stream::StandardError(_) | + Stream::StandardOutput(_) | + Stream::Null(_) => {} + } + } + + fn consume(&mut self, nread: usize) { + match self { + Stream::InputFile(ref mut file) => file.consume(nread), + Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.consume(nread), + Stream::NamedTls(ref mut tls_stream) => tls_stream.consume(nread), + Stream::Readline(ref mut rl_stream) => rl_stream.consume(nread), + Stream::StaticString(ref mut src) => src.consume(nread), + Stream::Byte(ref mut cursor) => cursor.consume(nread), + Stream::OutputFile(_) | + Stream::StandardError(_) | + Stream::StandardOutput(_) | + Stream::Null(_) => {} + } + } +} + +impl Read for Stream { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let bytes_read = match self { + Stream::InputFile(file) => (*file).read(buf), + Stream::NamedTcp(tcp_stream) => (*tcp_stream).read(buf), + Stream::NamedTls(tls_stream) => (*tls_stream).read(buf), + Stream::Readline(rl_stream) => (*rl_stream).read(buf), + Stream::StaticString(src) => (*src).read(buf), + Stream::Byte(cursor) => (*cursor).read(buf), + Stream::OutputFile(_) + | Stream::StandardError(_) + | Stream::StandardOutput(_) + | Stream::Null(_) => Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::ReadFromOutputStream, + )), + }; -impl PartialEq for WrappedStreamInstance { - #[inline] - fn eq(&self, other: &Self) -> bool { - Rc::ptr_eq(&self.0, &other.0) + bytes_read } } -impl Eq for WrappedStreamInstance {} - -impl Hash for WrappedStreamInstance { - fn hash(&self, state: &mut H) { - let rc = &self.0; - let ptr = Rc::into_raw(rc.clone()); - - state.write_usize(ptr as usize); +impl Write for Stream { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + match self { + Stream::OutputFile(ref mut file) => file.write(buf), + Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.get_mut().write(buf), + Stream::NamedTls(ref mut tls_stream) => tls_stream.get_mut().write(buf), + Stream::Byte(ref mut cursor) => cursor.get_mut().write(buf), + Stream::StandardOutput(stream) => stream.write(buf), + Stream::StandardError(stream) => stream.write(buf), + Stream::StaticString(_) | + Stream::Readline(_) | + Stream::InputFile(..) | + Stream::Null(_) => Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::WriteToInputStream, + )), + } + } - unsafe { - // necessary to avoid memory leak. - let _ = Rc::from_raw(ptr); - }; + fn flush(&mut self) -> std::io::Result<()> { + match self { + Stream::OutputFile(ref mut file) => file.stream.flush(), + Stream::NamedTcp(ref mut tcp_stream) => tcp_stream.stream.get_mut().flush(), + Stream::NamedTls(ref mut tls_stream) => tls_stream.stream.get_mut().flush(), + Stream::Byte(ref mut cursor) => cursor.stream.get_mut().flush(), + Stream::StandardError(stream) => stream.stream.flush(), + Stream::StandardOutput(stream) => stream.stream.flush(), + Stream::StaticString(_) | + Stream::Readline(_) | + Stream::InputFile(_) | + Stream::Null(_) => Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::FlushToInputStream, + )), + } } } @@ -236,8 +784,8 @@ impl Hash for WrappedStreamInstance { enum StreamError { PeekByteFailed, PeekByteFromNonPeekableStream, - PeekCharFailed, - PeekCharFromNonPeekableStream, + #[allow(unused)] PeekCharFailed, + #[allow(unused)] PeekCharFromNonPeekableStream, ReadFromOutputStream, WriteToInputStream, FlushToInputStream, @@ -273,31 +821,6 @@ impl fmt::Display for StreamError { impl Error for StreamError {} -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct StreamOptions { - pub(crate) stream_type: StreamType, - pub(crate) reposition: bool, - pub(crate) alias: Option, - pub(crate) eof_action: EOFAction, -} - -impl Default for StreamOptions { - #[inline] - fn default() -> Self { - StreamOptions { - stream_type: StreamType::Text, - reposition: false, - alias: None, - eof_action: EOFAction::EOFCode, - } - } -} - -#[derive(Debug, Clone, Hash)] -pub struct Stream { - stream_inst: WrappedStreamInstance, -} - impl PartialOrd for Stream { #[inline] fn partial_cmp(&self, other: &Stream) -> Option { @@ -315,123 +838,44 @@ impl Ord for Stream { impl PartialEq for Stream { #[inline] fn eq(&self, other: &Self) -> bool { - self.stream_inst == other.stream_inst + self.as_ptr() == other.as_ptr() } } impl Eq for Stream {} -impl From for Stream { - fn from(string: String) -> Self { - Stream::from_inst(StreamInstance::Bytes(Cursor::new(string.into_bytes()))) - } -} - -impl From for Stream { - fn from(rl_stream: ReadlineStream) -> Self { - Stream::from_inst(StreamInstance::ReadlineStream(rl_stream)) - } -} - -impl From<&'static str> for Stream { - fn from(src: &'static str) -> Stream { - Stream::from_inst(StreamInstance::StaticStr(Cursor::new(src))) - } -} - impl Stream { - #[inline] - pub(crate) fn as_ptr(&self) -> *const u8 { - let rc = self.stream_inst.0.clone(); - let ptr = Rc::into_raw(rc); - - unsafe { - // must be done to avoid memory leak. - let _ = Rc::from_raw(ptr); - } - - ptr as *const u8 - } - - pub fn bytes(&self) -> Option>> { - /* - // Replacement of workaround for when we have stable https://github.com/rust-lang/rust/issues/81061 - std::cell::Ref::filter_map( - self.stream_inst.0.borrow(), - |inner_stream| match inner_stream.stream_inst { - StreamInstance::Bytes(cursor) => Some(cursor.get_ref()), - _ => None, - }, - ) - .ok() - */ - let val = std::cell::Ref::map(self.stream_inst.0.borrow(), |inner_stream| { - &inner_stream.stream_inst - }); - match std::ops::Deref::deref(&val) { - StreamInstance::Bytes(_) => Some(std::cell::Ref::map( - std::cell::Ref::clone(&val), - |instance| match instance { - StreamInstance::Bytes(cursor) => cursor.get_ref(), - _ => unreachable!(), - }, - )), - _ => None, - } - } - - #[inline] - pub(crate) fn lines_read(&mut self) -> usize { - self.stream_inst.0.borrow_mut().lines_read - } - - #[inline] - pub(crate) fn add_lines_read(&mut self, incr_num_lines_read: usize) { - self.stream_inst.0.borrow_mut().lines_read += incr_num_lines_read; - } - - #[inline] - pub(crate) fn options(&self) -> std::cell::Ref<'_, StreamOptions> { - std::cell::Ref::map(self.stream_inst.0.borrow(), |inner_stream| { - &inner_stream.options - }) - } - - #[inline] - pub(crate) fn options_mut(&mut self) -> std::cell::RefMut<'_, StreamOptions> { - std::cell::RefMut::map(self.stream_inst.0.borrow_mut(), |inner_stream| { - &mut inner_stream.options - }) - } - #[inline] pub(crate) fn position(&mut self) -> Option<(u64, usize)> { // returns lines_read, position. - let result = match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::InputFile(_, ref mut file) => file.seek(SeekFrom::Current(0)).ok(), - StreamInstance::TcpStream(..) - | StreamInstance::TlsStream(..) - | StreamInstance::ReadlineStream(..) - | StreamInstance::StaticStr(..) - | StreamInstance::PausedPrologStream(..) - | StreamInstance::Bytes(..) => Some(0), + let result = match self { + Stream::InputFile(ref mut file_stream) => { + file_stream.get_mut().file.seek(SeekFrom::Current(0)).ok() + } + Stream::NamedTcp(..) + | Stream::NamedTls(..) + | Stream::Readline(..) + | Stream::StaticString(..) + | Stream::Byte(..) => Some(0), _ => None, }; - result.map(|position| (position, self.stream_inst.0.borrow().lines_read)) + result.map(|position| (position, self.lines_read())) } #[inline] pub(crate) fn set_position(&mut self, position: u64) { - match self.stream_inst.0.borrow_mut().deref_mut() { - InnerStream { - past_end_of_stream, - stream_inst: StreamInstance::InputFile(_, ref mut file), - .. - } => { - file.seek(SeekFrom::Start(position)).unwrap(); + match self { + Stream::InputFile(stream_layout) => { + let StreamLayout { + past_end_of_stream, + stream, + .. + } = &mut **stream_layout; - if let Ok(metadata) = file.metadata() { + stream.get_mut().file.seek(SeekFrom::Start(position)).unwrap(); + + if let Ok(metadata) = stream.get_ref().file.metadata() { *past_end_of_stream = position > metadata.len(); } } @@ -441,7 +885,19 @@ impl Stream { #[inline] pub(crate) fn past_end_of_stream(&self) -> bool { - self.stream_inst.0.borrow_mut().past_end_of_stream + match self { + Stream::Byte(stream) => stream.past_end_of_stream, + Stream::InputFile(stream) => stream.past_end_of_stream, + Stream::OutputFile(stream) => stream.past_end_of_stream, + // Stream::PausedProlog(stream) => stream.paused_stream.past_end_of_stream(), + Stream::StaticString(stream) => stream.past_end_of_stream, + Stream::NamedTcp(stream) => stream.past_end_of_stream, + Stream::NamedTls(stream) => stream.past_end_of_stream, + Stream::Null(_) => false, + Stream::Readline(stream) => stream.past_end_of_stream, + Stream::StandardOutput(stream) => stream.past_end_of_stream, + Stream::StandardError(stream) => stream.past_end_of_stream, + } } #[inline] @@ -450,8 +906,19 @@ impl Stream { } #[inline] - pub(crate) fn set_past_end_of_stream(&mut self) { - self.stream_inst.0.borrow_mut().past_end_of_stream = true; + pub(crate) fn set_past_end_of_stream(&mut self, value: bool) { + match self { + Stream::Byte(stream) => stream.past_end_of_stream = value, + Stream::InputFile(stream) => stream.past_end_of_stream = value, + Stream::OutputFile(stream) => stream.past_end_of_stream = value, + Stream::StaticString(stream) => stream.past_end_of_stream = value, + Stream::NamedTcp(stream) => stream.past_end_of_stream = value, + Stream::NamedTls(stream) => stream.past_end_of_stream = value, + Stream::Null(_) => {} + Stream::Readline(stream) => stream.past_end_of_stream = value, + Stream::StandardOutput(stream) => stream.past_end_of_stream = value, + Stream::StandardError(stream) => stream.past_end_of_stream = value, + } } #[inline] @@ -460,14 +927,16 @@ impl Stream { return AtEndOfStream::Past; } - match self.stream_inst.0.borrow_mut().deref_mut() { - InnerStream { + if let Stream::InputFile(stream_layout) = self { + let StreamLayout { past_end_of_stream, - stream_inst: StreamInstance::InputFile(_, ref mut file), + stream, .. - } => match file.metadata() { + } = &mut **stream_layout; + + match stream.get_ref().file.metadata() { Ok(metadata) => { - if let Ok(position) = file.seek(SeekFrom::Current(0)) { + if let Ok(position) = stream.get_mut().file.seek(SeekFrom::Current(0)) { return match position.cmp(&metadata.len()) { Ordering::Equal => AtEndOfStream::At, Ordering::Less => AtEndOfStream::Not, @@ -485,120 +954,130 @@ impl Stream { *past_end_of_stream = true; AtEndOfStream::Past } - }, - _ => AtEndOfStream::Not, + } + } else { + AtEndOfStream::Not } } #[inline] - pub(crate) fn file_name(&self) -> Option { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::InputFile(ref name, _) => Some(name.clone()), - StreamInstance::OutputFile(ref name, ..) => Some(name.clone()), - StreamInstance::TcpStream(ref name, _) => Some(name.clone()), + pub(crate) fn file_name(&self) -> Option { + match self { + Stream::InputFile(file) => Some(file.stream.get_ref().file_name), + Stream::OutputFile(file) => Some(file.stream.file_name), + Stream::NamedTcp(tcp) => Some(tcp.stream.get_ref().address), + Stream::NamedTls(tls) => Some(tls.stream.get_ref().address), _ => None, } } #[inline] - pub(crate) fn mode(&self) -> &'static str { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::Bytes(_) - | StreamInstance::PausedPrologStream(..) - | StreamInstance::ReadlineStream(_) - | StreamInstance::StaticStr(_) - | StreamInstance::InputFile(..) => "read", - StreamInstance::TcpStream(..) | StreamInstance::TlsStream(..) => "read_append", - StreamInstance::OutputFile(_, _, true) => "append", - StreamInstance::Stderr - | StreamInstance::Stdout - | StreamInstance::OutputFile(_, _, false) => "write", - StreamInstance::Null => "", - } - } - - #[inline] - fn from_inst(stream_inst: StreamInstance) -> Self { - Stream { - stream_inst: WrappedStreamInstance::new(stream_inst, false), + pub(crate) fn mode(&self) -> Atom { + match self { + Stream::Byte(_) + | Stream::Readline(_) + | Stream::StaticString(_) + | Stream::InputFile(..) => atom!("read"), + Stream::NamedTcp(..) | Stream::NamedTls(..) => atom!("read_append"), + Stream::OutputFile(file) if file.is_append => atom!("append"), + Stream::OutputFile(_) | Stream::StandardError(_) | Stream::StandardOutput(_) => atom!("write"), + Stream::Null(_) => atom!(""), } } #[inline] - pub fn stdout() -> Self { - Stream::from_inst(StreamInstance::Stdout) + pub fn stdout(arena: &mut Arena) -> Self { + Stream::StandardOutput(arena_alloc!( + StreamLayout::new(StandardOutputStream {}), + arena + )) } #[inline] - pub fn stderr() -> Self { - Stream::from_inst(StreamInstance::Stderr) + pub fn stderr(arena: &mut Arena) -> Self { + Stream::StandardError(arena_alloc!( + StreamLayout::new(StandardErrorStream {}), + arena + )) } #[inline] - pub(crate) fn from_tcp_stream(address: ClauseName, tcp_stream: TcpStream) -> Self { + pub(crate) fn from_tcp_stream( + address: Atom, + tcp_stream: TcpStream, + arena: &mut Arena, + ) -> Self { tcp_stream.set_read_timeout(None).unwrap(); tcp_stream.set_write_timeout(None).unwrap(); - Stream::from_inst(StreamInstance::TcpStream(address, tcp_stream)) - } - - #[inline] - pub(crate) fn from_tls_stream(address: ClauseName, tls_stream: TlsStream) -> Self { - Stream::from_inst(StreamInstance::TlsStream(address, tls_stream)) - } - - #[inline] - pub(crate) fn from_file_as_output(name: ClauseName, file: File, in_append_mode: bool) -> Self { - Stream::from_inst(StreamInstance::OutputFile(name, file, in_append_mode)) - } - - #[inline] - pub(crate) fn from_file_as_input(name: ClauseName, file: File) -> Self { - Stream::from_inst(StreamInstance::InputFile(name, file)) + Stream::NamedTcp(arena_alloc!( + StreamLayout::new(CharReader::new(NamedTcpStream { + address, + tcp_stream + })), + arena + )) } #[inline] - pub(crate) fn is_stderr(&self) -> bool { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::Stderr => true, - _ => false, - } + pub(crate) fn from_tls_stream( + address: Atom, + tls_stream: TlsStream, + arena: &mut Arena, + ) -> Self { + Stream::NamedTls(arena_alloc!( + StreamLayout::new(CharReader::new(NamedTlsStream { + address, + tls_stream + })), + arena + )) } #[inline] - pub(crate) fn is_stdout(&self) -> bool { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::Stdout => true, - _ => false, - } + pub(crate) fn from_file_as_output( + file_name: Atom, + file: File, + is_append: bool, + arena: &mut Arena, + ) -> Self { + Stream::OutputFile(arena_alloc!( + StreamLayout::new(OutputFileStream { + file_name, + file, + is_append + }), + arena + )) } #[inline] - pub(crate) fn is_stdin(&self) -> bool { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::ReadlineStream(_) => true, - _ => false, - } + pub(crate) fn from_file_as_input(file_name: Atom, file: File, arena: &mut Arena) -> Self { + Stream::InputFile(arena_alloc!( + StreamLayout::new(CharReader::new(InputFileStream { file_name, file })), + arena + )) } #[inline] pub(crate) fn close(&mut self) -> Result<(), std::io::Error> { - let result = match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::TcpStream(_, ref mut tcp_stream) => { - tcp_stream.shutdown(Shutdown::Both) + let result = match self { + Stream::NamedTcp(ref mut tcp_stream) => { + tcp_stream.inner_mut().tcp_stream.shutdown(Shutdown::Both) }, - StreamInstance::TlsStream(_, ref mut tls_stream) => { - tls_stream.shutdown() + Stream::NamedTls(ref mut tls_stream) => { + tls_stream.inner_mut().tls_stream.shutdown() } _ => Ok(()) }; - self.stream_inst.0.borrow_mut().stream_inst = StreamInstance::Null; + + *self = Stream::Null(StreamOptions::default()); result } #[inline] pub(crate) fn is_null_stream(&self) -> bool { - if let StreamInstance::Null = self.stream_inst.0.borrow().stream_inst { + if let Stream::Null(_) = self { true } else { false @@ -607,98 +1086,77 @@ impl Stream { #[inline] pub(crate) fn is_input_stream(&self) -> bool { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::TcpStream(..) - | StreamInstance::TlsStream(..) - | StreamInstance::Bytes(_) - | StreamInstance::PausedPrologStream(..) - | StreamInstance::ReadlineStream(_) - | StreamInstance::StaticStr(_) - | StreamInstance::InputFile(..) => true, + match self { + Stream::NamedTcp(..) + | Stream::NamedTls(..) + | Stream::Byte(_) + | Stream::Readline(_) + | Stream::StaticString(_) + | Stream::InputFile(..) => true, _ => false, } } #[inline] pub(crate) fn is_output_stream(&self) -> bool { - match self.stream_inst.0.borrow().stream_inst { - StreamInstance::Stderr - | StreamInstance::Stdout - | StreamInstance::TcpStream(..) - | StreamInstance::TlsStream(..) - | StreamInstance::Bytes(_) - | StreamInstance::OutputFile(..) => true, + match self { + Stream::StandardError(_) + | Stream::StandardOutput(_) + | Stream::NamedTcp(..) + | Stream::NamedTls(..) + | Stream::Byte(_) + | Stream::OutputFile(..) => true, _ => false, } } - fn unpause_stream(&mut self) { - let stream_inst = match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::PausedPrologStream(ref put_back, ref mut stream_inst) - if put_back.is_empty() => - { - mem::replace(&mut **stream_inst, StreamInstance::Null) - } - _ => { - return; - } - }; - - self.stream_inst.0.borrow_mut().stream_inst = stream_inst; - } - // returns true on success. #[inline] pub(super) fn reset(&mut self) -> bool { - self.stream_inst.0.borrow_mut().lines_read = 0; - self.stream_inst.0.borrow_mut().past_end_of_stream = false; + self.set_lines_read(0); + self.set_past_end_of_stream(false); loop { - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::Bytes(ref mut cursor) => { - cursor.set_position(0); + match self { + Stream::Byte(ref mut cursor) => { + cursor.stream.get_mut().0.set_position(0); return true; } - StreamInstance::InputFile(_, ref mut file) => { - file.seek(SeekFrom::Start(0)).unwrap(); + Stream::InputFile(ref mut file_stream) => { + file_stream.stream.get_mut().file.seek(SeekFrom::Start(0)).unwrap(); return true; } - StreamInstance::PausedPrologStream(ref mut put_back, _) => { - put_back.clear(); - } - StreamInstance::ReadlineStream(_) => { + Stream::Readline(_) => { return true; } _ => { return false; } } - - self.unpause_stream(); } } #[inline] pub(crate) fn peek_byte(&mut self) -> std::io::Result { - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::Bytes(ref mut cursor) => { + match self { + Stream::Byte(ref mut cursor) => { let mut b = [0u8; 1]; - let pos = cursor.position(); + let pos = cursor.stream.get_mut().0.position(); match cursor.read(&mut b)? { 1 => { - cursor.set_position(pos); + cursor.stream.get_mut().0.set_position(pos); Ok(b[0]) } _ => Err(std::io::Error::new(ErrorKind::UnexpectedEof, "end of file")), } } - StreamInstance::InputFile(_, ref mut file) => { + Stream::InputFile(ref mut file) => { let mut b = [0u8; 1]; match file.read(&mut b)? { 1 => { - file.seek(SeekFrom::Current(-1))?; + file.stream.get_mut().file.seek(SeekFrom::Current(-1))?; Ok(b[0]) } _ => Err(std::io::Error::new( @@ -707,10 +1165,10 @@ impl Stream { )), } } - StreamInstance::ReadlineStream(ref mut stream) => stream.peek_byte(), - StreamInstance::TcpStream(_, ref mut tcp_stream) => { + Stream::Readline(ref mut stream) => stream.stream.peek_byte(), + Stream::NamedTcp(ref mut stream) => { let mut b = [0u8; 1]; - tcp_stream.peek(&mut b)?; + stream.stream.get_mut().tcp_stream.peek(&mut b)?; Ok(b[0]) } _ => Err(std::io::Error::new( @@ -719,113 +1177,37 @@ impl Stream { )), } } - - #[inline] - pub(crate) fn peek_char(&mut self) -> std::io::Result { - use unicode_reader::CodePoints; - - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::InputFile(_, ref mut file) => { - let c = { - let mut iter = CodePoints::from(&*file); - - if let Some(Ok(c)) = iter.next() { - c - } else { - return Err(std::io::Error::new( - ErrorKind::UnexpectedEof, - StreamError::PeekCharFailed, - )); - } - }; - - file.seek(SeekFrom::Current(-(c.len_utf8() as i64)))?; - - Ok(c) - } - StreamInstance::ReadlineStream(ref mut stream) => stream.peek_char(), - StreamInstance::TcpStream(_, ref tcp_stream) => { - let c = { - let mut buf = [0u8; 8]; - tcp_stream.peek(&mut buf)?; - - let mut iter = CodePoints::from(buf.bytes()); - - if let Some(Ok(c)) = iter.next() { - c - } else { - return Err(std::io::Error::new( - ErrorKind::UnexpectedEof, - StreamError::PeekCharFailed, - )); - } - }; - - Ok(c) - } - _ => Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::PeekCharFromNonPeekableStream, - )), - } - } - - #[inline] - pub(crate) fn pause_stream(&mut self, buf: Vec>) -> io::Result<()> { - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::PausedPrologStream(ref mut inner_buf, _) => { - inner_buf.extend(parser_top_to_bytes(buf)?.into_iter()); - return Ok(()); - } - _ => {} - } - - if !buf.is_empty() { - let stream_inst = mem::replace( - &mut self.stream_inst.0.borrow_mut().stream_inst, - StreamInstance::Null, - ); - - self.stream_inst.0.borrow_mut().stream_inst = StreamInstance::PausedPrologStream( - parser_top_to_bytes(buf)?, - Box::new(stream_inst), - ); - } - - Ok(()) - } } impl MachineState { #[inline] pub(crate) fn eof_action( &mut self, - result: Addr, - stream: &mut Stream, - caller: ClauseName, + result: HeapCellValue, + mut stream: Stream, + caller: Atom, arity: usize, ) -> CallResult { - let eof_action = stream.options().eof_action; + let eof_action = stream.options().eof_action(); match eof_action { EOFAction::Error => { - stream.set_past_end_of_stream(); - return Err(self.open_past_eos_error(stream.clone(), caller, arity)); + stream.set_past_end_of_stream(true); + return Err(self.open_past_eos_error(stream, caller, arity)); } EOFAction::EOFCode => { - let end_of_stream = if stream.options().stream_type == StreamType::Binary { - Addr::Fixnum(-1) + let end_of_stream = if stream.options().stream_type() == StreamType::Binary { + fixnum_as_cell!(Fixnum::build_with(-1)) } else { - self.heap - .to_unifiable(HeapCellValue::Atom(clause_name!("end_of_file"), None)) + atom_as_cell!(atom!("end_of_file")) }; - stream.set_past_end_of_stream(); - Ok(self.unify(result, end_of_stream)) + stream.set_past_end_of_stream(true); + Ok(unify!(self, result, end_of_stream)) } EOFAction::Reset => { if !stream.reset() { - stream.set_past_end_of_stream(); + stream.set_past_end_of_stream(true); } Ok(self.fail = stream.past_end_of_stream()) @@ -834,182 +1216,176 @@ impl MachineState { } pub(crate) fn to_stream_options( - &self, - alias: Addr, - eof_action: Addr, - reposition: Addr, - stream_type: Addr, + &mut self, + alias: HeapCellValue, + eof_action: HeapCellValue, + reposition: HeapCellValue, + stream_type: HeapCellValue, ) -> StreamOptions { - let alias = match self.store(self.deref(alias)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - Some(name.clone()) - } else { - unreachable!() - } + let alias = read_heap_cell!(self.store(MachineState::deref(self, alias)), + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + Some(name) } - _ => None, - }; + _ => { + None + } + ); - let eof_action = match self.store(self.deref(eof_action)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - match name.as_str() { - "eof_code" => EOFAction::EOFCode, - "error" => EOFAction::Error, - "reset" => EOFAction::Reset, - _ => unreachable!(), - } - } else { - unreachable!() + let eof_action = read_heap_cell!(self.store(MachineState::deref(self, eof_action)), + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + match name { + atom!("eof_code") => EOFAction::EOFCode, + atom!("error") => EOFAction::Error, + atom!("reset") => EOFAction::Reset, + _ => unreachable!(), } } _ => { unreachable!() } - }; + ); - let reposition = match self.store(self.deref(reposition)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.as_str() == "true" - } else { - unreachable!() - } + let reposition = read_heap_cell!(self.store(MachineState::deref(self, reposition)), + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + name == atom!("true") } _ => { unreachable!() } - }; + ); - let stream_type = match self.store(self.deref(stream_type)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - match name.as_str() { - "text" => StreamType::Text, - "binary" => StreamType::Binary, - _ => unreachable!(), - } - } else { - unreachable!() + let stream_type = read_heap_cell!(self.store(MachineState::deref(self, stream_type)), + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + match name { + atom!("text") => StreamType::Text, + atom!("binary") => StreamType::Binary, + _ => unreachable!(), } } _ => { unreachable!() } - }; + ); let mut options = StreamOptions::default(); - options.stream_type = stream_type; - options.reposition = reposition; - options.alias = alias; - options.eof_action = eof_action; + options.set_stream_type(stream_type); + options.set_reposition(reposition); + options.set_alias_to_atom_opt(alias); + options.set_eof_action(eof_action); options } pub(crate) fn get_stream_or_alias( &mut self, - addr: Addr, + addr: HeapCellValue, stream_aliases: &StreamAliasDir, - caller: &'static str, + caller: Atom, arity: usize, ) -> Result { - Ok(match self.store(self.deref(addr)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, ref spec) = self.heap.clone(h) { - match stream_aliases.get(atom) { - Some(stream) if !stream.is_null_stream() => stream.clone(), - _ => { - let stub = MachineError::functor_stub(clause_name!(caller), arity); - - let addr = self - .heap - .to_unifiable(HeapCellValue::Atom(atom.clone(), spec.clone())); - - return Err(self.error_form( - MachineError::existence_error( - self.heap.h(), - ExistenceError::Stream(addr), - ), - stub, - )); - } + let addr = self.store(MachineState::deref(self, addr)); + + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + return match stream_aliases.get(&name) { + Some(stream) if !stream.is_null_stream() => Ok(*stream), + _ => { + let stub = functor_stub(caller, arity); + let addr = atom_as_cell!(name); + + let existence_error = self.existence_error(ExistenceError::Stream(addr)); + + Err(self.error_form(existence_error, stub)) } - } else { - unreachable!() - } + }; } - Addr::Stream(h) => { - if let HeapCellValue::Stream(ref stream) = &self.heap[h] { - if stream.is_null_stream() { - return Err(self.open_permission_error(Addr::Stream(h), caller, arity)); - } else { - stream.clone() - } - } else { - unreachable!() - } + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Stream, stream) => { + return if stream.is_null_stream() { + Err(self.open_permission_error(stream_as_cell!(stream), caller, arity)) + } else { + Ok(stream) + }; + } + _ => { + } + ); } - addr => { - let stub = MachineError::functor_stub(clause_name!(caller), arity); - - if addr.is_ref() { - return Err(self.error_form(MachineError::instantiation_error(), stub)); - } else { - return Err(self.error_form( - MachineError::domain_error(DomainErrorType::StreamOrAlias, addr), - stub, - )); - } + _ => { } - }) + ); + + let stub = functor_stub(caller, arity); + + if addr.is_var() { + let instantiation_error = self.instantiation_error(); + Err(self.error_form(instantiation_error, stub)) + } else { + let domain_error = self.domain_error(DomainErrorType::StreamOrAlias, addr); + Err(self.error_form(domain_error, stub)) + } } pub(crate) fn open_parsing_stream( - &self, - stream: Stream, - stub_name: &'static str, + &mut self, + mut stream: Stream, + stub_name: Atom, stub_arity: usize, - ) -> Result { - match parsing_stream(stream) { - Ok(parsing_stream) => Ok(parsing_stream), - Err(e) => { - let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let err = MachineError::session_error(self.heap.h(), SessionError::from(e)); + ) -> Result { + match stream.peek_char() { + None => Ok(stream), // empty stream is handled gracefully by Lexer::eof + Some(Err(e)) => { + let err = self.session_error(SessionError::from(e)); + let stub = functor_stub(stub_name, stub_arity); Err(self.error_form(err, stub)) } + Some(Ok(c)) => { + if c == '\u{feff}' { + // skip UTF-8 BOM + stream.consume(c.len_utf8()); + } + + Ok(stream) + } } } pub(crate) fn stream_permission_error( - &self, + &mut self, perm: Permission, - err_string: &'static str, + err_atom: Atom, stream: Stream, - caller: ClauseName, + caller: Atom, arity: usize, ) -> MachineStub { - let stub = MachineError::functor_stub(caller, arity); - let payload = vec![HeapCellValue::Stream(stream)]; + let stub = functor_stub(caller, arity); + let payload = vec![stream_as_cell!(stream)]; - let err = MachineError::permission_error(self.heap.h(), perm, err_string, payload); + let err = self.permission_error(perm, err_atom, payload); return self.error_form(err, stub); } #[inline] pub(crate) fn open_past_eos_error( - &self, + &mut self, stream: Stream, - caller: ClauseName, + caller: Atom, arity: usize, ) -> MachineStub { self.stream_permission_error( Permission::InputStream, - "past_end_of_stream", + atom!("past_end_of_stream"), stream, caller, arity, @@ -1017,67 +1393,58 @@ impl MachineState { } pub(crate) fn open_permission_error( - &self, + &mut self, culprit: T, - stub_name: &'static str, + stub_name: Atom, stub_arity: usize, ) -> MachineStub { - let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let err = - MachineError::permission_error(self.heap.h(), Permission::Open, "source_sink", culprit); + let stub = functor_stub(stub_name, stub_arity); + let err = self.permission_error(Permission::Open, atom!("source_sink"), culprit); return self.error_form(err, stub); } pub(crate) fn occupied_alias_permission_error( - &self, - alias: ClauseName, - stub_name: &'static str, + &mut self, + alias: Atom, + stub_name: Atom, stub_arity: usize, ) -> MachineStub { - let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let err = MachineError::permission_error( - self.heap.h(), + let stub = functor_stub(stub_name, stub_arity); + let alias_name = atom!("alias"); + + let err = self.permission_error( Permission::Open, - "source_sink", - functor!("alias", [clause_name(alias)]), + atom!("source_sink"), + functor!(alias_name, [atom(alias)]), ); return self.error_form(err, stub); } - pub(crate) fn reposition_error( - &self, - stub_name: &'static str, - stub_arity: usize, - ) -> MachineStub { - let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let rep_stub = functor!("reposition", [atom("true")]); + pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub { + let stub = functor_stub(stub_name, stub_arity); - let err = MachineError::permission_error( - self.heap.h(), - Permission::Open, - "source_sink", - rep_stub, - ); + let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]); + let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub); return self.error_form(err, stub); } pub(crate) fn check_stream_properties( &mut self, - stream: &mut Stream, + stream: Stream, expected_type: StreamType, - input: Option, - caller: ClauseName, + input: Option, + caller: Atom, arity: usize, ) -> CallResult { let opt_err = if input.is_some() && !stream.is_input_stream() { - Some("stream") // 8.14.2.3 g) + Some(atom!("stream")) // 8.14.2.3 g) } else if input.is_none() && !stream.is_output_stream() { - Some("stream") // 8.14.2.3 g) - } else if stream.options().stream_type != expected_type { - Some(expected_type.other().as_str()) // 8.14.2.3 h) + Some(atom!("stream")) // 8.14.2.3 g) + } else if stream.options().stream_type() != expected_type { + Some(expected_type.other().as_atom()) // 8.14.2.3 h) } else { None }; @@ -1088,14 +1455,8 @@ impl MachineState { Permission::OutputStream }; - if let Some(err_string) = opt_err { - return Err(self.stream_permission_error( - permission, - err_string, - stream.clone(), - caller, - arity, - )); + if let Some(err_atom) = opt_err { + return Err(self.stream_permission_error(permission, err_atom, stream, caller, arity)); } if let Some(input) = input { @@ -1106,53 +1467,96 @@ impl MachineState { Ok(()) } -} -impl Read for Stream { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - let bytes_read = self.stream_inst.0.borrow_mut().stream_inst.read(buf)?; - self.unpause_stream(); - Ok(bytes_read) - } -} + pub(crate) fn stream_from_file_spec( + &mut self, + file_spec: Atom, + indices: &mut IndexStore, + options: &StreamOptions, + ) -> Result { + if file_spec == atom!("") { + let stub = functor_stub(atom!("open"), 4); + let err = self.domain_error(DomainErrorType::SourceSink, self[temp_v!(1)]); -impl Write for Stream { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::OutputFile(_, ref mut file, _) => file.write(buf), - StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.write(buf), - StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.write(buf), - StreamInstance::Bytes(ref mut cursor) => cursor.write(buf), - StreamInstance::Stdout => stdout().write(buf), - StreamInstance::Stderr => stderr().write(buf), - StreamInstance::PausedPrologStream(..) - | StreamInstance::StaticStr(_) - | StreamInstance::ReadlineStream(_) - | StreamInstance::InputFile(..) - | StreamInstance::Null => Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::WriteToInputStream, - )), + return Err(self.error_form(err, stub)); } - } - fn flush(&mut self) -> std::io::Result<()> { - match self.stream_inst.0.borrow_mut().stream_inst { - StreamInstance::OutputFile(_, ref mut file, _) => file.flush(), - StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.flush(), - StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.flush(), - StreamInstance::Bytes(ref mut cursor) => cursor.flush(), - StreamInstance::Stderr => stderr().flush(), - StreamInstance::Stdout => stdout().flush(), - StreamInstance::PausedPrologStream(..) - | StreamInstance::StaticStr(_) - | StreamInstance::ReadlineStream(_) - | StreamInstance::InputFile(..) - | StreamInstance::Null => Err(std::io::Error::new( - ErrorKind::PermissionDenied, - StreamError::FlushToInputStream, - )), + // 8.11.5.3l) + if let Some(alias) = options.get_alias() { + if indices.stream_aliases.contains_key(&alias) { + return Err(self.occupied_alias_permission_error(alias, atom!("open"), 4)); + } } + + let mode = MachineState::deref(self, self[temp_v!(2)]); + let mode = cell_as_atom!(self.store(mode)); + + let mut open_options = OpenOptions::new(); + + let (is_input_file, in_append_mode) = match mode { + atom!("read") => { + open_options.read(true).write(false).create(false); + (true, false) + } + atom!("write") => { + open_options + .read(false) + .write(true) + .truncate(true) + .create(true); + + (false, false) + } + atom!("append") => { + open_options + .read(false) + .write(true) + .create(true) + .append(true); + + (false, true) + } + _ => { + let stub = functor_stub(atom!("open"), 4); + let err = self.domain_error(DomainErrorType::IOMode, self[temp_v!(2)]); + + // 8.11.5.3h) + return Err(self.error_form(err, stub)); + } + }; + + let file = match open_options.open(file_spec.as_str()) { + Ok(file) => file, + Err(err) => { + match err.kind() { + ErrorKind::NotFound => { + // 8.11.5.3j) + let stub = functor_stub(atom!("open"), 4); + + let err = self.existence_error( + ExistenceError::SourceSink(self[temp_v!(1)]), + ); + + return Err(self.error_form(err, stub)); + } + ErrorKind::PermissionDenied => { + // 8.11.5.3k) + return Err(self.open_permission_error(self[temp_v!(1)], atom!("open"), 4)); + } + _ => { + let stub = functor_stub(atom!("open"), 4); + let err = self.syntax_error(ParserError::IO(err)); + + return Err(self.error_form(err, stub)); + } + } + } + }; + + Ok(if is_input_file { + Stream::from_file_as_input(file_spec, file, &mut self.arena) + } else { + Stream::from_file_as_output(file_spec, file, in_append_mode, &mut self.arena) + }) } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 0505e138..9f3dd089 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1,30 +1,32 @@ -use prolog_parser::ast::*; -use prolog_parser::parser::*; -use prolog_parser::{ - alpha_char, alpha_numeric_char, binary_digit_char, clause_name, decimal_digit_char, - exponent_char, graphic_char, graphic_token_char, hexadecimal_digit_char, layout_char, - meta_char, new_line_char, octal_digit_char, octet_char, prolog_char, sign_char, solo_char, - symbolic_control_char, symbolic_hexadecimal_char, temp_v, -}; +use crate::parser::ast::*; +use crate::parser::parser::*; use lazy_static::lazy_static; +use crate::arena::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::forms::*; +use crate::heap_iter::*; use crate::heap_print::*; use crate::instructions::*; use crate::machine; use crate::machine::code_repo::CodeRepo; use crate::machine::code_walker::*; use crate::machine::copier::*; +use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; +use crate::machine::partial_string::*; use crate::machine::preprocessor::to_op_decl; +use crate::machine::stack::*; use crate::machine::streams::*; +use crate::parser::char_reader::*; +use crate::parser::rug::Integer; +use crate::read::*; +use crate::types::*; -use crate::read::readline; -use crate::rug::Integer; use ordered_float::OrderedFloat; use indexmap::IndexSet; @@ -40,7 +42,6 @@ use std::iter::{once, FromIterator}; use std::net::{TcpListener, TcpStream}; use std::num::NonZeroU32; use std::ops::Sub; -use std::rc::Rc; use std::process; use chrono::{offset::Local, DateTime}; @@ -92,147 +93,287 @@ pub(crate) fn get_key() -> KeyEvent { key } -#[derive(Debug)] -struct BrentAlgState { - hare: Addr, - tortoise: Addr, - power: usize, - steps: usize, +#[derive(Debug, Clone, Copy)] +pub struct BrentAlgState { + pub hare: usize, + pub tortoise: usize, + pub power: usize, + pub lam: usize, + pub pstr_chars: usize, } impl BrentAlgState { - fn new(hare: Addr) -> Self { - BrentAlgState { - hare: hare, + pub fn new(hare: usize) -> Self { + Self { + hare, tortoise: hare, - power: 2, - steps: 0, + power: 1, + lam: 0, + pstr_chars: 0, } } - #[inline] - fn conclude_or_move_tortoise(&mut self) -> Option { + #[inline(always)] + pub fn step(&mut self, hare: usize) -> Option { + self.hare = hare; + self.lam += 1; + if self.tortoise == self.hare { return Some(CycleSearchResult::NotList); - } else if self.steps == self.power { + } else if self.lam == self.power { self.tortoise = self.hare; self.power <<= 1; + self.lam = 0; } None } - #[inline] - fn step(&mut self, hare: Addr) -> Option { - self.hare = hare; - self.steps += 1; - - self.conclude_or_move_tortoise() + #[inline(always)] + pub fn num_steps(&self) -> usize { + return self.lam + self.pstr_chars + self.power - 1; } - fn to_result(self) -> CycleSearchResult { - match self.hare { - addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => { - CycleSearchResult::PartialList(self.steps, addr.as_var().unwrap()) - } - Addr::PStrLocation(h, n) => CycleSearchResult::PStrLocation(self.steps, h, n), - Addr::EmptyList => CycleSearchResult::ProperList(self.steps), - _ => CycleSearchResult::NotList, + pub fn to_result(mut self, heap: &[HeapCellValue]) -> CycleSearchResult { + if let Some(var) = heap[self.hare].as_var() { + return CycleSearchResult::PartialList(self.num_steps(), var); } + + read_heap_cell!(heap[self.hare], + (HeapCellValueTag::PStrOffset) => { + let n = cell_as_fixnum!(heap[self.hare+1]).get_num() as usize; + + let pstr = cell_as_string!(heap[self.hare]); + self.pstr_chars += pstr.as_str_from(n).chars().count(); + + CycleSearchResult::PStrLocation(self.num_steps(), n) + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { + CycleSearchResult::ProperList(self.num_steps()) + } else { + CycleSearchResult::NotList + } + } + _ => { + CycleSearchResult::NotList + } + ) } -} -fn is_builtin_predicate(name: &ClauseName) -> bool { - let in_builtins = name.owning_module().as_str() == "builtins"; - let hidden_name = name.as_str().starts_with("$"); + fn add_pstr_chars_and_step(&mut self, heap: &[HeapCellValue], h: usize) -> Option { + read_heap_cell!(heap[h], + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = PartialString::from(cstr_atom); + + self.pstr_chars += cstr.as_str_from(0).chars().count(); + Some(CycleSearchResult::ProperList(self.num_steps())) + } + (HeapCellValueTag::PStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + + self.pstr_chars += pstr.as_str_from(0).chars().count() - 1; + self.step(h+1) + } + (HeapCellValueTag::PStrOffset, offset) => { + let pstr = cell_as_string!(heap[offset]); + let n = cell_as_fixnum!(heap[h+1]).get_num() as usize; + + self.pstr_chars += pstr.as_str_from(n).chars().count(); - in_builtins || hidden_name + if let HeapCellValueTag::PStr = heap[offset].get_tag() { + self.pstr_chars -= 1; + self.step(offset+1) + } else { + debug_assert!(heap[offset].get_tag() == HeapCellValueTag::CStr); + Some(CycleSearchResult::ProperList(self.num_steps())) + } + } + _ => { + unreachable!() + } + ) + } } impl MachineState { - // a step in Brent's algorithm. - fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { - match self.store(self.deref(brent_st.hare)) { - Addr::EmptyList => Some(CycleSearchResult::ProperList(brent_st.steps)), - addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => { - Some(CycleSearchResult::PartialList( - brent_st.steps, - addr.as_var().unwrap(), - )) - } - Addr::PStrLocation(h, n) => match &self.heap[h] { - HeapCellValue::PartialString(ref pstr, _) => { - if let Some(c) = pstr.range_from(n..).next() { - brent_st.step(Addr::PStrLocation(h, n + c.len_utf8())) - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }, - Addr::Lis(l) => brent_st.step(Addr::HeapCell(l + 1)), - _ => Some(CycleSearchResult::NotList), + #[inline(always)] + pub fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { + let deref_v = self.deref(self.heap[brent_st.hare]); + let store_v = self.store(deref_v); + + if let Some(var) = store_v.as_var() { + return Some(CycleSearchResult::PartialList(brent_st.num_steps(), var)); + } + + if store_v == empty_list_as_cell!() { + return Some(CycleSearchResult::ProperList(brent_st.num_steps())); } + + read_heap_cell!(store_v, + (HeapCellValueTag::PStrLoc, h) => { + brent_st.add_pstr_chars_and_step(&self.heap, h) + } + (HeapCellValueTag::PStrOffset) => { + brent_st.add_pstr_chars_and_step(&self.heap, brent_st.hare) + } + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = PartialString::from(cstr_atom); + + brent_st.pstr_chars += cstr.as_str_from(0).chars().count(); + Some(CycleSearchResult::ProperList(brent_st.num_steps())) + } + (HeapCellValueTag::Lis, h) => { + brent_st.step(h+1) + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + + if name == atom!(".") && arity == 2 { + brent_st.step(s+2) + } else { + Some(CycleSearchResult::NotList) + } + } + (HeapCellValueTag::Atom, (_name, arity)) => { + debug_assert!(arity == 0); + Some(CycleSearchResult::NotList) + } + _ => { + Some(CycleSearchResult::NotList) + } + ) } - pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult { - let hare = match self.store(self.deref(addr)) { - Addr::Lis(offset) if max_steps > 0 => Addr::Lis(offset), - Addr::Lis(offset) => { - return CycleSearchResult::UntouchedList(offset); + pub fn detect_cycles(&self, value: HeapCellValue) -> CycleSearchResult { + let deref_v = self.deref(value); + let store_v = self.store(deref_v); + + let mut pstr_chars = 0; + + let hare = read_heap_cell!(store_v, + (HeapCellValueTag::Lis, offset) => { + offset+1 } - Addr::PStrLocation(h, n) if max_steps > 0 => Addr::PStrLocation(h, n), - Addr::PStrLocation(h, _) => { - return CycleSearchResult::UntouchedList(h); + (HeapCellValueTag::PStrLoc, h) => { + let (h_offset, n) = pstr_loc_and_offset(&self.heap, h); + let n = n.get_num() as usize; + let pstr = cell_as_string!(self.heap[h_offset]); + + pstr_chars = pstr.as_str_from(n).chars().count() - 1; + + if self.heap[h].get_tag() == HeapCellValueTag::PStrOffset { + debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset); + + if self.heap[h_offset].get_tag() == HeapCellValueTag::CStr { + return CycleSearchResult::ProperList(pstr_chars + 1); + } + } + + h_offset+1 + } + (HeapCellValueTag::PStrOffset) => { + unreachable!() } - Addr::EmptyList => { - return CycleSearchResult::EmptyList; + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = PartialString::from(cstr_atom); + return CycleSearchResult::ProperList(cstr.as_str_from(0).chars().count()); } - Addr::Con(h) if max_steps > 0 => { - if let HeapCellValue::PartialString(..) = &self.heap[h] { - Addr::PStrLocation(h, 0) + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); + + if name == atom!("[]") && arity == 0 { + return CycleSearchResult::EmptyList; + } else if name == atom!(".") && arity == 2 { + s + 2 } else { return CycleSearchResult::NotList; } } - Addr::Con(h) => { - if let HeapCellValue::PartialString(..) = &self.heap[h] { - return CycleSearchResult::UntouchedList(h); + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { + return CycleSearchResult::EmptyList; + } else { + return CycleSearchResult::NotList; } - - return CycleSearchResult::NotList; } _ => { return CycleSearchResult::NotList; } - }; + ); let mut brent_st = BrentAlgState::new(hare); - loop { - if brent_st.steps == max_steps { - return brent_st.to_result(); - } + brent_st.power += 1; // advance a step. + brent_st.pstr_chars = pstr_chars; + loop { if let Some(result) = self.brents_alg_step(&mut brent_st) { return result; } } } - pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult { - let addr = self.store(self.deref(addr)); - let hare = match addr { - Addr::Lis(offset) => Addr::Lis(offset), - Addr::EmptyList => { - return CycleSearchResult::EmptyList; - } - Addr::PStrLocation(h, n) => Addr::PStrLocation(h, n), - Addr::Con(h) => { - if let HeapCellValue::PartialString(..) = &self.heap[h] { - Addr::PStrLocation(h, 0) + pub fn detect_cycles_with_max(&self, max_steps: usize, value: HeapCellValue) -> CycleSearchResult { + let deref_v = self.deref(value); + let store_v = self.store(deref_v); + + // let mut pstr_chars = 0; + + let hare = read_heap_cell!(store_v, + (HeapCellValueTag::Lis, offset) => { + if max_steps > 0 { + offset+1 + } else { + return CycleSearchResult::UntouchedList(offset); + } + } + (HeapCellValueTag::PStrLoc, h) => { + let (h_offset, _n) = pstr_loc_and_offset(&self.heap, h); + + if self.heap[h].get_tag() == HeapCellValueTag::PStr { + h_offset+1 + } else { + debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset); + h + } + } + (HeapCellValueTag::PStrOffset) => { + unreachable!() + } + (HeapCellValueTag::CStr, cstr_atom) => { + return if max_steps > 0 { + let cstr = PartialString::from(cstr_atom); + let pstr_chars = cstr.as_str_from(0).chars().count(); + + if pstr_chars < max_steps { + CycleSearchResult::ProperList(pstr_chars) + } else { + CycleSearchResult::UntouchedCStr(cstr_atom, max_steps) + } + } else { + CycleSearchResult::UntouchedCStr(cstr_atom, 0) + }; + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + + if name == atom!("[]") && arity == 0 { + return CycleSearchResult::EmptyList; + } else if name == atom!(".") && arity == 2 { + if max_steps > 0 { + s + 2 + } else { + return CycleSearchResult::UntouchedList(s + 1); + } + } else { + return CycleSearchResult::NotList; + } + } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { + return CycleSearchResult::EmptyList; } else { return CycleSearchResult::NotList; } @@ -240,221 +381,179 @@ impl MachineState { _ => { return CycleSearchResult::NotList; } - }; + ); let mut brent_st = BrentAlgState::new(hare); + brent_st.power += 1; // advance a step. + // brent_st.pstr_chars = pstr_chars; + loop { + if brent_st.num_steps() == max_steps { + return brent_st.to_result(&self.heap); + } + if let Some(result) = self.brents_alg_step(&mut brent_st) { return result; } } } - fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) { - let target_n = self[temp_v!(1)]; - self.unify(Addr::Usize(n), target_n); + fn term_variables_under_max_depth( + &mut self, + term: HeapCellValue, + max_depth: usize, + list_of_vars: HeapCellValue, + ) { + let mut seen_set = IndexSet::new(); + + { + let mut iter = stackful_post_order_iter(&mut self.heap, term); + + while let Some(value) = iter.next() { + if iter.parent_stack_len() >= max_depth { + iter.pop_stack(); + continue; + } + + let value = unmark_cell_bits!(value); + + if value.is_var() && !seen_set.contains(&value) { + seen_set.insert(value); + } + } + } + + let outcome = heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, + seen_set.into_iter().rev(), + ) + ); + + unify_fn!(self, list_of_vars, outcome); + } + + fn finalize_skip_max_list(&mut self, n: usize, value: HeapCellValue) { + let target_n = self.registers[1]; + self.unify_fixnum(Fixnum::build_with(n as i64), target_n); if !self.fail { - let xs = self[temp_v!(4)]; - self.unify(addr, xs); + let xs = self.registers[4]; + unify!(self, value, xs); } } - fn skip_max_list_result(&mut self, max_steps: Option) { + fn skip_max_list_result(&mut self, max_steps: Option) { let search_result = if let Some(max_steps) = max_steps { if max_steps == -1 { - self.detect_cycles(self[temp_v!(3)]) + self.detect_cycles(self.registers[3]) } else { - self.detect_cycles_with_max(max_steps as usize, self[temp_v!(3)]) + self.detect_cycles_with_max(max_steps as usize, self.registers[3]) } } else { - self.detect_cycles(self[temp_v!(3)]) + self.detect_cycles(self.registers[3]) }; match search_result { - CycleSearchResult::PStrLocation(steps, h, n) => { - self.finalize_skip_max_list(steps, Addr::PStrLocation(h, n)); + CycleSearchResult::PStrLocation(steps, pstr_loc) => { + self.finalize_skip_max_list(steps, heap_loc_as_cell!(pstr_loc)); + } + CycleSearchResult::UntouchedList(l) => { + self.finalize_skip_max_list(0, list_loc_as_cell!(l)); + } + CycleSearchResult::UntouchedCStr(cstr_atom, n) => { + self.finalize_skip_max_list(n, string_as_cstr_cell!(cstr_atom)); + } + CycleSearchResult::EmptyList => { + self.finalize_skip_max_list(0, empty_list_as_cell!()); + } + CycleSearchResult::PartialList(n, r) => { + self.finalize_skip_max_list(n, r.as_heap_cell_value()); } - CycleSearchResult::UntouchedList(l) => self.finalize_skip_max_list(0, Addr::Lis(l)), - CycleSearchResult::EmptyList => self.finalize_skip_max_list(0, Addr::EmptyList), - CycleSearchResult::PartialList(n, r) => self.finalize_skip_max_list(n, r.as_addr()), CycleSearchResult::ProperList(steps) => { - self.finalize_skip_max_list(steps, Addr::EmptyList) + self.finalize_skip_max_list(steps, empty_list_as_cell!()) } CycleSearchResult::NotList => { - let xs0 = self[temp_v!(3)]; + let xs0 = self.registers[3]; self.finalize_skip_max_list(0, xs0); } }; } - pub(super) fn skip_max_list(&mut self) -> CallResult { - let max_steps = self.store(self.deref(self[temp_v!(2)])); - - match max_steps { - Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(_) => { - let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); - return Err(self.error_form(MachineError::instantiation_error(), stub)); - } - addr => { - let max_steps_n = match Number::try_from((max_steps, &self.heap)) { - Ok(Number::Integer(n)) => n.to_isize(), - Ok(Number::Fixnum(n)) => Some(n), - _ => None, - }; - - if max_steps_n.map(|i| i >= -1).unwrap_or(false) { - let n = self.store(self.deref(self[temp_v!(1)])); - - match Number::try_from((n, &self.heap)) { - Ok(Number::Integer(n)) => { - if n.as_ref() == &0 { - let xs0 = self[temp_v!(3)]; - let xs = self[temp_v!(4)]; - - self.unify(xs0, xs); - } else { - self.skip_max_list_result(max_steps_n); - } - } - Ok(Number::Fixnum(n)) => { - if n == 0 { - let xs0 = self[temp_v!(3)]; - let xs = self[temp_v!(4)]; - - self.unify(xs0, xs); - } else { - self.skip_max_list_result(max_steps_n); - } - } - _ => { - self.skip_max_list_result(max_steps_n); - } - } - } else { - let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, addr), - stub, - )); - } - } - } - - Ok(()) - } + pub fn skip_max_list(&mut self) -> CallResult { + let max_steps = self.store(self.deref(self.registers[2])); - fn stream_from_file_spec( - &self, - file_spec: ClauseName, - indices: &mut IndexStore, - options: &StreamOptions, - ) -> Result { - if file_spec.as_str().is_empty() { - let stub = MachineError::functor_stub(clause_name!("open"), 4); - let err = MachineError::domain_error(DomainErrorType::SourceSink, self[temp_v!(1)]); + if max_steps.is_var() { + let stub = functor_stub(atom!("$skip_max_list"), 4); + let err = self.instantiation_error(); return Err(self.error_form(err, stub)); } - // 8.11.5.3l) - if let Some(ref alias) = &options.alias { - if indices.stream_aliases.contains_key(alias) { - return Err(self.occupied_alias_permission_error(alias.clone(), "open", 4)); - } - } - - let mode = atom_from!(self, self.store(self.deref(self[temp_v!(2)]))); - let mut open_options = fs::OpenOptions::new(); - - let (is_input_file, in_append_mode) = match mode.as_str() { - "read" => { - open_options.read(true).write(false).create(false); - (true, false) - } - "write" => { - open_options - .read(false) - .write(true) - .truncate(true) - .create(true); - (false, false) - } - "append" => { - open_options - .read(false) - .write(true) - .create(true) - .append(true); - (false, true) - } - _ => { - let stub = MachineError::functor_stub(clause_name!("open"), 4); - let err = MachineError::domain_error(DomainErrorType::IOMode, self[temp_v!(2)]); - - // 8.11.5.3h) - return Err(self.error_form(err, stub)); - } + let max_steps_n = match Number::try_from(max_steps) { + Ok(Number::Fixnum(n)) => Some(n.get_num()), + Ok(Number::Integer(n)) => n.to_i64(), + _ => None, }; - let file = match open_options.open(file_spec.as_str()) { - Ok(file) => file, - Err(err) => { - match err.kind() { - ErrorKind::NotFound => { - // 8.11.5.3j) - let stub = MachineError::functor_stub(clause_name!("open"), 4); - - let err = MachineError::existence_error( - self.heap.h(), - ExistenceError::SourceSink(self[temp_v!(1)]), - ); + if max_steps_n.map(|i| i >= -1).unwrap_or(false) { + let n = self.store(self.deref(self.registers[1])); - return Err(self.error_form(err, stub)); - } - ErrorKind::PermissionDenied => { - // 8.11.5.3k) - return Err(self.open_permission_error(self[temp_v!(1)], "open", 4)); - } - _ => { - let stub = MachineError::functor_stub(clause_name!("open"), 4); + match Number::try_from(n) { + Ok(Number::Integer(n)) => { + if &*n == &0 { + let xs0 = self.registers[3]; + let xs = self.registers[4]; - let err = MachineError::syntax_error(self.heap.h(), ParserError::IO(err)); + unify!(self, xs0, xs); + } else { + self.skip_max_list_result(max_steps_n); + } + } + Ok(Number::Fixnum(n)) => { + if n.get_num() == 0 { + let xs0 = self.registers[3]; + let xs = self.registers[4]; - return Err(self.error_form(err, stub)); + unify!(self, xs0, xs); + } else { + self.skip_max_list_result(max_steps_n); } } + _ => { + self.skip_max_list_result(max_steps_n); + } } - }; - - Ok(if is_input_file { - Stream::from_file_as_input(file_spec, file) } else { - Stream::from_file_as_output(file_spec, file, in_append_mode) - }) + let stub = functor_stub(atom!("$skip_max_list"), 4); + let err = self.type_error(ValidType::Integer, max_steps); + + return Err(self.error_form(err, stub)); + } + + Ok(()) } +} +impl MachineState { #[inline] - fn install_new_block(&mut self, r: RegType) -> usize { + fn install_new_block(&mut self, value: HeapCellValue) -> usize { self.block = self.b; + self.unify_fixnum(Fixnum::build_with(self.block as i64), value); - let c = Constant::Usize(self.block); - let addr = self[r]; - - self.write_constant_to_var(addr, &c); self.block } - fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: Addr) -> usize { - let threshold = self.lifted_heap.h() - lh_offset; + fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: HeapCellValue) -> usize { + let threshold = self.lifted_heap.len() - lh_offset; let mut copy_ball_term = CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.lifted_heap); - copy_ball_term.push(HeapCellValue::Addr(Addr::Lis(threshold + 1))); - copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 3))); - copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 2))); + copy_ball_term.push(list_loc_as_cell!(threshold + 1)); + copy_ball_term.push(heap_loc_as_cell!(threshold + 3)); + copy_ball_term.push(heap_loc_as_cell!(threshold + 2)); copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy); @@ -471,124 +570,70 @@ impl MachineState { Ok(self.p = CodePtr::REPL(repl_code_ptr, p)) } - fn truncate_if_no_lifted_heap_diff(&mut self, addr_constr: AddrConstr) - where - AddrConstr: Fn(usize) -> Addr, - { - match self.store(self.deref(self[temp_v!(1)])) { - Addr::Usize(lh_offset) => { - if lh_offset >= self.lifted_heap.h() { + #[inline(always)] + fn truncate_if_no_lifted_heap_diff( + &mut self, + addr_constr: impl Fn(usize) -> HeapCellValue, + ) { + read_heap_cell!(self.store(self.deref(self.registers[1])), + (HeapCellValueTag::Fixnum, n) => { + let lh_offset = n.get_num() as usize; + + if lh_offset >= self.lifted_heap.len() { self.lifted_heap.truncate(lh_offset); } else { - let threshold = self.lifted_heap.h() - lh_offset; - self.lifted_heap - .push(HeapCellValue::Addr(addr_constr(threshold))); + let threshold = self.lifted_heap.len() - lh_offset; + self.lifted_heap.push(addr_constr(threshold)); } } - _ => self.fail = true, - } + _ => { + self.fail = true; + } + ); } - fn get_next_db_ref(&mut self, indices: &IndexStore, db_ref: &DBRef) { + fn get_next_db_ref(&self, indices: &IndexStore, db_ref: &DBRef) -> Option { match db_ref { - &DBRef::NamedPred(ref name, arity, _) => { - let key = (name.clone(), arity); - let mut iter = indices.code_dir.range(key..).skip(1); - - while let Some(((name, arity), idx)) = iter.next() { - if idx.is_undefined() { - self.fail = true; - return; - } - - if is_builtin_predicate(&name) { - continue; - } + DBRef::NamedPred(name, arity) => { + let key = (*name, *arity); - let a2 = self[temp_v!(2)]; + if let Some((last_idx, _, _)) = indices.code_dir.get_full(&key) { + for idx in last_idx + 1 .. indices.code_dir.len() { + let ((name, arity), idx) = indices.code_dir.get_index(idx).unwrap(); - if let Some(r) = a2.as_var() { - let spec = get_clause_spec( - name.clone(), - *arity, - &CompositeOpDir::new(&indices.op_dir, None), - ); - - let addr = self - .heap - .to_unifiable(HeapCellValue::DBRef(DBRef::NamedPred( - name.clone(), - *arity, - spec, - ))); + if idx.is_undefined() { + return None; + } - self.bind(r, addr); + if SystemClauseType::from(*name, *arity).is_some() { + continue; + } - return; + return Some(DBRef::NamedPred(*name, *arity)); } } - - self.fail = true; } - &DBRef::Op(_, spec, ref name, ref op_dir, _) => { - let fixity = match spec { - XF | YF => Fixity::Post, - FX | FY => Fixity::Pre, - _ => Fixity::In, - }; - - let key = OrderedOpDirKey(name.clone(), fixity); + DBRef::Op(name, fixity, op_dir) => { + let key = (*name, *fixity); - match op_dir.range(key..).skip(1).next() { - Some((OrderedOpDirKey(name, _), (priority, spec))) => { - let a2 = self[temp_v!(2)]; - - if let Some(r) = a2.as_var() { - let addr = self.heap.to_unifiable(HeapCellValue::DBRef(DBRef::Op( - *priority, - *spec, - name.clone(), - op_dir.clone(), - SharedOpDesc::new(*priority, *spec), - ))); - - self.bind(r, addr); - } else { - self.fail = true; - } + if let Some((last_idx, _, _)) = op_dir.get_full(&key) { + if let Some(((name, fixity), _)) = op_dir.get_index(last_idx+1) { + return Some(DBRef::Op(*name, *fixity, *op_dir)); } - None => self.fail = true, } } } - } - - fn int_to_char( - &self, - n: &Integer, - stub: &'static str, - arity: usize, - ) -> Result { - let c = n.to_u32().and_then(std::char::from_u32); - if let Some(c) = c { - Ok(c) - } else { - let stub = MachineError::functor_stub(clause_name!(stub), arity); - let err = MachineError::representation_error(RepFlag::CharacterCode); - let err = self.error_form(err, stub); - - Err(err) - } + None } fn parse_number_from_string( &mut self, mut string: String, indices: &IndexStore, - stub: MachineStub, + stub_gen: impl Fn() -> FunctorStub, ) -> CallResult { - let nx = self[temp_v!(2)]; + let nx = self.registers[2]; if let Some(c) = string.chars().last() { if layout_char!(c) { @@ -600,106 +645,159 @@ impl MachineState { } }); let err = ParserError::UnexpectedChar(c, line_num, col_num); + let err = self.syntax_error(err); - let h = self.heap.h(); - let err = MachineError::syntax_error(h, err); - - return Err(self.error_form(err, stub)); + return Err(self.error_form(err, stub_gen())); } } string.push('.'); - let mut stream = match parsing_stream(std::io::Cursor::new(string)) { - Ok(stream) => stream, - Err(e) => { - let err = MachineError::session_error(self.heap.h(), SessionError::from(e)); - - return Err(self.error_form(err, stub)); - } - }; - - let mut parser = Parser::new(&mut stream, self.atom_tbl.clone(), self.machine_flags()); + let stream = CharReader::new(std::io::Cursor::new(string)); + let mut parser = Parser::new(stream, self); match parser.read_term(&CompositeOpDir::new(&indices.op_dir, None)) { Err(err) => { - let h = self.heap.h(); - let err = MachineError::syntax_error(h, err); - - return Err(self.error_form(err, stub)); + let err = self.syntax_error(err); + return Err(self.error_form(err, stub_gen())); } - Ok(Term::Constant(_, Constant::Rational(n))) => { - let addr = self.heap.put_constant(Constant::Rational(n)); - (self.unify_fn)(self, nx, addr); + Ok(Term::Literal(_, Literal::Rational(n))) => { + self.unify_rational(n, nx); } - Ok(Term::Constant(_, Constant::Float(n))) => { - let addr = self.heap.put_constant(Constant::Float(n)); - (self.unify_fn)(self, nx, addr); + Ok(Term::Literal(_, Literal::Float(n))) => { + self.unify_f64(n, nx); } - Ok(Term::Constant(_, Constant::Integer(n))) => { - let addr = self.heap.put_constant(Constant::Integer(n)); - (self.unify_fn)(self, nx, addr); + Ok(Term::Literal(_, Literal::Integer(n))) => { + self.unify_big_int(n, nx); } - Ok(Term::Constant(_, Constant::Fixnum(n))) => { - let addr = self.heap.put_constant(Constant::Fixnum(n)); - (self.unify_fn)(self, nx, addr); + Ok(Term::Literal(_, Literal::Fixnum(n))) => { + self.unify_fixnum(n, nx); } _ => { let err = ParserError::ParseBigInt(0, 0); + let err = self.syntax_error(err); - let h = self.heap.h(); - let err = MachineError::syntax_error(h, err); - - return Err(self.error_form(err, stub)); + return Err(self.error_form(err, stub_gen())); } } Ok(()) } - fn call_continuation_chunk(&mut self, chunk: Addr, return_p: LocalCodePtr) -> LocalCodePtr { + fn call_continuation_chunk(&mut self, chunk: HeapCellValue, return_p: LocalCodePtr) -> LocalCodePtr { let chunk = self.store(self.deref(chunk)); - match chunk { - Addr::Str(s) => { - match &self.heap[s] { - HeapCellValue::NamedStr(arity, ..) => { - let num_cells = arity - 1; - let p_functor = self.heap[s + 1].as_addr(s + 1); + let s = chunk.get_value(); + let arity = cell_as_atom_cell!(self.heap[s]).get_arity(); - let cp = self.heap.to_local_code_ptr(&p_functor).unwrap(); - let prev_e = self.e; + let num_cells = arity - 1; + let p_functor = self.heap[s + 1]; - let e = self.stack.allocate_and_frame(num_cells); - let and_frame = self.stack.index_and_frame_mut(e); + let cp = to_local_code_ptr(&self.heap, p_functor).unwrap(); + let prev_e = self.e; - and_frame.prelude.e = prev_e; - and_frame.prelude.cp = return_p; + let e = self.stack.allocate_and_frame(num_cells); + let and_frame = self.stack.index_and_frame_mut(e); - self.p = CodePtr::Local(cp + 1); + and_frame.prelude.e = prev_e; + and_frame.prelude.cp = return_p; - // adjust cut point to occur after call_continuation. - if num_cells > 0 { - if let Addr::CutPoint(_) = self.heap[s + 2].as_addr(s + 2) { - and_frame[1] = Addr::CutPoint(self.b); - } else { - and_frame[1] = self.heap[s + 2].as_addr(s + 2); - } - } + self.p = CodePtr::Local(cp + 1); - for index in s + 3..s + 2 + num_cells { - and_frame[index - (s + 1)] = self.heap[index].as_addr(index); - } + // adjust cut point to occur after call_continuation. + if num_cells > 0 { + if let HeapCellValueTag::Fixnum = self.heap[s + 2].get_tag() { + and_frame[1] = fixnum_as_cell!(Fixnum::build_with(self.b as i64)); + } else { + and_frame[1] = self.heap[s + 2]; + } + } - self.e = e; + for index in s + 3..s + 2 + num_cells { + and_frame[index - (s + 1)] = self.heap[index]; + } - self.p.local() + self.e = e; + self.p.local() + } + + pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option { + read_heap_cell!(value, + (HeapCellValueTag::CStr, cstr_atom) => { + // avoid allocating a String if possible ... + Some(AtomOrString::Atom(cstr_atom)) + } + (HeapCellValueTag::Atom, (atom, arity)) => { + if arity == 0 { + // ... likewise. + Some(AtomOrString::Atom(atom)) + } else { + None + } + } + _ => { + if value.is_constant() { + return None; + } + + let h = self.heap.len(); + self.heap.push(value); + + let mut iter = HeapPStrIter::new(&self.heap, h); + let string = iter.to_string(); + let at_terminator = iter.at_string_terminator(); + + self.heap.pop(); + + // if the iteration doesn't terminate like a string + // (i.e. with the [] atom or a CStr), it is not + // "str_like" so return None. + if at_terminator { + Some(AtomOrString::String(string)) + } else { + None + } + } + ) + } + + fn codes_to_string( + &mut self, + addrs: impl Iterator, + stub_gen: impl Fn() -> FunctorStub, + ) -> Result { + let mut string = String::new(); + + for addr in addrs { + match Number::try_from(addr) { + Ok(Number::Fixnum(n)) => { + match u32::try_from(n.get_num()) { + Ok(n) => { + if let Some(c) = std::char::from_u32(n) { + string.push(c); + continue; + } + } + _ => {} + } + } + Ok(Number::Integer(n)) => { + if let Some(c) = n.to_u32().and_then(std::char::from_u32) { + string.push(c); + continue; } - _ => unreachable!(), + } + _ => { + let err = self.type_error(ValidType::Integer, addr); + return Err(self.error_form(err, stub_gen())); } } - _ => unreachable!(), + + let err = self.representation_error(RepFlag::CharacterCode); + return Err(self.error_form(err, stub_gen())); } + + Ok(string) } pub(super) fn system_call( @@ -714,10 +812,10 @@ impl MachineState { ) -> CallResult { match ct { &SystemClauseType::BindFromRegister => { - let reg = self.store(self.deref(self[temp_v!(2)])); - let n = match Number::try_from((reg, &self.heap)) { + let reg = self.store(self.deref(self.registers[2])); + let n = match Number::try_from(reg) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), Ok(Number::Integer(n)) => n.to_usize(), - Ok(Number::Fixnum(n)) => usize::try_from(n).ok(), _ => { unreachable!() } @@ -725,10 +823,10 @@ impl MachineState { if let Some(n) = n { if n <= MAX_ARITY { - let target = self[temp_v!(n)]; - let addr = self[temp_v!(1)]; + let target = self.registers[n]; + let addr = self.registers[1]; - (self.unify_fn)(self, addr, target); + unify_fn!(self, addr, target); return return_from_clause!(self.last_call, self); } } @@ -737,14 +835,11 @@ impl MachineState { } &SystemClauseType::CurrentHostname => { match hostname::get().ok() { - Some(host) => match host.into_string().ok() { + Some(host) => match host.to_str() { Some(host) => { - let hostname = self.heap.to_unifiable(HeapCellValue::Atom( - clause_name!(host, self.atom_tbl), - None, - )); + let hostname = self.atom_tbl.build_with(host); - (self.unify_fn)(self, self[temp_v!(1)], hostname); + self.unify_atom(hostname, self.store(self.deref(self.registers[1]))); return return_from_clause!(self.last_call, self); } None => {} @@ -756,171 +851,202 @@ impl MachineState { return Ok(()); } &SystemClauseType::CurrentInput => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); + let stream = *current_input_stream; - let stream = current_input_stream.clone(); + if let Some(var) = addr.as_var() { + self.bind(var, stream_as_cell!(stream)); + return return_from_clause!(self.last_call, self); + } - match addr { - addr if addr.is_ref() => { - let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - (self.unify_fn)(self, stream, addr); - } - Addr::Stream(other_stream) => { - if let HeapCellValue::Stream(ref other_stream) = &self.heap[other_stream] { - self.fail = current_input_stream != other_stream; - } else { - unreachable!() - } - } - addr => { - let stub = MachineError::functor_stub(clause_name!("current_input"), 1); + read_heap_cell!(addr, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Stream, other_stream) => { + self.fail = stream != other_stream; + } + _ => { + let stub = functor_stub(atom!("current_input"), 1); + let err = self.domain_error(DomainErrorType::Stream, addr); - let err = MachineError::domain_error(DomainErrorType::Stream, addr); + return Err(self.error_form(err, stub)); + } + ); + } + _ => { + let stub = functor_stub(atom!("current_input"), 1); + let err = self.domain_error(DomainErrorType::Stream, addr); return Err(self.error_form(err, stub)); } - } + ); } &SystemClauseType::CurrentOutput => { - let addr = self.store(self.deref(self[temp_v!(1)])); - let stream = current_output_stream.clone(); + let addr = self.store(self.deref(self.registers[1])); + let stream = *current_output_stream; - match addr { - addr if addr.is_ref() => { - let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - (self.unify_fn)(self, stream, addr); - } - Addr::Stream(other_stream) => { - if let HeapCellValue::Stream(ref other_stream) = &self.heap[other_stream] { - self.fail = current_output_stream != other_stream; - } else { - unreachable!() - } - } - addr => { - let stub = MachineError::functor_stub(clause_name!("current_input"), 1); + if let Some(var) = addr.as_var() { + self.bind(var, stream_as_cell!(stream)); + return return_from_clause!(self.last_call, self); + } - let err = MachineError::domain_error(DomainErrorType::Stream, addr); + read_heap_cell!(addr, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Stream, other_stream) => { + self.fail = stream != other_stream; + } + _ => { + let stub = functor_stub(atom!("current_output"), 1); + let err = self.domain_error(DomainErrorType::Stream, addr); + + return Err(self.error_form(err, stub)); + } + ); + } + _ => { + let stub = functor_stub(atom!("current_output"), 1); + let err = self.domain_error(DomainErrorType::Stream, addr); return Err(self.error_form(err, stub)); } - } + ); } &SystemClauseType::DirectoryFiles => { - let dir = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - let path = std::path::Path::new(&dir); - let mut files = Vec::new(); - - if let Ok(entries) = fs::read_dir(path) { - for entry in entries { - if let Ok(entry) = entry { - match entry.file_name().into_string() { - Ok(name) => { - files.push(self.heap.put_complete_string(&name)); - } - _ => { - let stub = MachineError::functor_stub( - clause_name!("directory_files"), - 2, - ); - let err = - MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); - - return Err(err); + if let Some(dir) = self.value_to_str_like(self.registers[1]) { + let path = std::path::Path::new(dir.as_str()); + let mut files = Vec::new(); + + if let Ok(entries) = fs::read_dir(path) { + for entry in entries { + if let Ok(entry) = entry { + if let Some(name) = entry.file_name().to_str() { + let name = self.atom_tbl.build_with(name); + files.push(atom_as_cstr_cell!(name)); + + continue; } } + + let stub = functor_stub(atom!("directory_files"), 2); + let err = self.representation_error(RepFlag::Character); + let err = self.error_form(err, stub); + + return Err(err); } + + let files_list = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, files.into_iter()) + ); + + unify!(self, self.registers[2], files_list); + return return_from_clause!(self.last_call, self); } } - let files_list = Addr::HeapCell(self.heap.to_list(files.into_iter())); - (self.unify_fn)(self, self[temp_v!(2)], files_list); + self.fail = true; } &SystemClauseType::FileSize => { - let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - let len = Integer::from(fs::metadata(&file).unwrap().len()); - - let len = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(len))); + if let Some(file) = self.value_to_str_like(self.registers[1]) { + let len = Number::arena_from( + fs::metadata(file.as_str()).unwrap().len(), + &mut self.arena, + ); - (self.unify_fn)(self, self[temp_v!(2)], len); + match len { + Number::Fixnum(n) => self.unify_fixnum(n, self.registers[2]), + Number::Integer(n) => self.unify_big_int(n, self.registers[2]), + _ => unreachable!(), + } + } else { + self.fail = true; + } } &SystemClauseType::FileExists => { - let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - if !std::path::Path::new(&file).exists() || !fs::metadata(&file).unwrap().is_file() - { + if let Some(file) = self.value_to_str_like(self.registers[1]) { + let file_str = file.as_str(); + + if !std::path::Path::new(file_str).exists() || !fs::metadata(file_str).unwrap().is_file() { + self.fail = true; + } + } else { self.fail = true; - return Ok(()); } } &SystemClauseType::DirectoryExists => { - let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - if !std::path::Path::new(&directory).exists() - || !fs::metadata(&directory).unwrap().is_dir() - { + if let Some(dir) = self.value_to_str_like(self.registers[1]) { + let dir_str = dir.as_str(); + + if !std::path::Path::new(dir_str).exists() + || !fs::metadata(dir_str).unwrap().is_dir() + { + self.fail = true; + return Ok(()); + } + } else { self.fail = true; - return Ok(()); } } &SystemClauseType::DirectorySeparator => { - let addr = self - .heap - .put_constant(Constant::Char(std::path::MAIN_SEPARATOR)); - (self.unify_fn)(self, self[temp_v!(1)], addr); + self.unify_char(std::path::MAIN_SEPARATOR, self.registers[1]); } &SystemClauseType::MakeDirectory => { - let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - - match fs::create_dir(directory) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + if let Some(dir) = self.value_to_str_like(self.registers[1]) { + match fs::create_dir(dir.as_str()) { + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); + } } + } else { + self.fail = true; } } &SystemClauseType::MakeDirectoryPath => { - let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); + if let Some(dir) = self.value_to_str_like(self.registers[1]) { - match fs::create_dir_all(directory) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + match fs::create_dir_all(dir.as_str()) { + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); + } } + } else { + self.fail = true; } } &SystemClauseType::DeleteFile => { - let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - - match fs::remove_file(file) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + if let Some(file) = self.value_to_str_like(self.registers[1]) { + match fs::remove_file(file.as_str()) { + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); + } } } } &SystemClauseType::RenameFile => { - let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - let renamed = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); - - match fs::rename(file, renamed) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + if let Some(file) = self.value_to_str_like(self.registers[1]) { + if let Some(renamed) = self.value_to_str_like(self.registers[2]) { + if fs::rename(file.as_str(), renamed.as_str()).is_ok() { + return return_from_clause!(self.last_call, self); + } } } + + self.fail = true; } &SystemClauseType::DeleteDirectory => { - let directory = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - - match fs::remove_dir(directory) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + if let Some(dir) = self.value_to_str_like(self.registers[1]) { + match fs::remove_dir(dir.as_str()) { + Ok(_) => {} + _ => { + self.fail = true; + return Ok(()); + } } } } @@ -929,283 +1055,211 @@ impl MachineState { let current = match dir.to_str() { Some(d) => d, _ => { - let stub = - MachineError::functor_stub(clause_name!("working_directory"), 2); - let err = MachineError::representation_error(RepFlag::Character); + let stub = functor_stub(atom!("working_directory"), 2); + let err = self.representation_error(RepFlag::Character); let err = self.error_form(err, stub); return Err(err); } }; - let chars = self.heap.put_complete_string(current); - (self.unify_fn)(self, self[temp_v!(1)], chars); + let current_atom = self.atom_tbl.build_with(¤t); - let next = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); + self.unify_complete_string( + current_atom, + self.store(self.deref(self.registers[1])), + ); - match env::set_current_dir(std::path::Path::new(&next)) { - Ok(_) => {} - _ => { - self.fail = true; - return Ok(()); + if self.fail { + return Ok(()); + } + + if let Some(next) = self.value_to_str_like(self.registers[2]) { + if env::set_current_dir(std::path::Path::new(next.as_str())).is_ok() { + return return_from_clause!(self.last_call, self); } } - } else { - self.fail = true; - return Ok(()); } + + self.fail = true; } &SystemClauseType::PathCanonical => { - let path = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); + if let Some(path) = self.value_to_str_like(self.registers[1]) { + match fs::canonicalize(path.as_str()) { + Ok(canonical) => { + let cs = match canonical.to_str() { + Some(s) => s, + _ => { + let stub = functor_stub(atom!("path_canonical"), 2); + let err = self.representation_error(RepFlag::Character); + let err = self.error_form(err, stub); - match fs::canonicalize(path) { - Ok(canonical) => { - let cs = match canonical.to_str() { - Some(s) => s, - _ => { - let stub = - MachineError::functor_stub(clause_name!("path_canonical"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); + return Err(err); + } + }; - return Err(err); - } - }; - let chars = self.heap.put_complete_string(cs); - (self.unify_fn)(self, self[temp_v!(2)], chars); - } - _ => { - self.fail = true; - return Ok(()); + let canonical_atom = self.atom_tbl.build_with(cs); + + self.unify_complete_string( + canonical_atom, + self.store(self.deref(self.registers[2])), + ); + + return return_from_clause!(self.last_call, self); + } + _ => { + } } } + + self.fail = true; } &SystemClauseType::FileTime => { - let file = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); + if let Some(file) = self.value_to_str_like(self.registers[1]) { + let which = cell_as_atom!(self.store(self.deref(self.registers[2]))); + + if let Ok(md) = fs::metadata(file.as_str()) { + if let Ok(time) = match which { + atom!("modification") => md.modified(), + atom!("access") => md.accessed(), + atom!("creation") => md.created(), + _ => { + unreachable!() + } + } { + let chars_atom = self.systemtime_to_timestamp(time); - let which = match self.store(self.deref(self[temp_v!(2)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.as_str() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + self.unify_complete_string( + chars_atom, + self.registers[3], + ); - if let Ok(md) = fs::metadata(file) { - if let Ok(time) = match which { - "modification" => md.modified(), - "access" => md.accessed(), - "creation" => md.created(), - _ => { - unreachable!() + return return_from_clause!(self.last_call, self); } - } { - let chars = self.systemtime_to_timestamp(time); - (self.unify_fn)(self, self[temp_v!(3)], chars); - } else { - self.fail = true; - return Ok(()); } - } else { - self.fail = true; - return Ok(()); } + + self.fail = true; } &SystemClauseType::AtomChars => { - let a1 = self[temp_v!(1)]; + let a1 = self.store(self.deref(self.registers[1])); - match self.store(self.deref(a1)) { - Addr::Char(c) => { - let iter = once(Addr::Char(c)); - let list_of_chars = Addr::HeapCell(self.heap.to_list(iter)); + read_heap_cell!(a1, + (HeapCellValueTag::Char) => { + let h = self.heap.len(); - let a2 = self[temp_v!(2)]; - (self.unify_fn)(self, a2, list_of_chars); - } - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { - let s = self.heap.put_complete_string(name.as_str()); - let a2 = self[temp_v!(2)]; + self.heap.push(a1); + self.heap.push(empty_list_as_cell!()); - (self.unify_fn)(self, s, a2); + unify!(self, self.registers[2], list_loc_as_cell!(h)); + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + self.unify_complete_string( + name, + self.store(self.deref(self.registers[2])), + ); } else { - unreachable!() + self.fail = true; } } - Addr::EmptyList => { - let a2 = self[temp_v!(2)]; - let chars = vec![Addr::Char('['), Addr::Char(']')]; - - let list_of_chars = Addr::HeapCell(self.heap.to_list(chars.into_iter())); - - (self.unify_fn)(self, a2, list_of_chars); - } - addr if addr.is_ref() => { - let mut iter = self.heap_pstr_iter(self[temp_v!(2)]); - let string = iter.to_string(); - - match iter.focus() { - Addr::EmptyList => { - if &string == "[]" { - (self.unify_fn)(self, addr, Addr::EmptyList); - } else { - let chars = clause_name!(string, self.atom_tbl); - let atom = - self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let a2 = self.store(self.deref(self.registers[2])); - (self.unify_fn)(self, addr, atom); + if let Some(str_like) = self.value_to_str_like(a2) { + let atom = match str_like { + AtomOrString::Atom(atom) => { + atom } - } - focus => { - if let Addr::Lis(l) = focus { - let stub = - MachineError::functor_stub(clause_name!("atom_chars"), 2); - - let err = MachineError::type_error( - self.heap.h(), - ValidType::Character, - Addr::HeapCell(l), - ); - - return Err(self.error_form(err, stub)); - } else { - unreachable!() + AtomOrString::String(string) => { + self.atom_tbl.build_with(&string) } - } + }; + + self.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); + return return_from_clause!(self.last_call, self); } + + self.fail = true; } - _ => unreachable!(), - }; + _ => { + unreachable!(); + } + ); } &SystemClauseType::AtomCodes => { - let a1 = self[temp_v!(1)]; - - match self.store(self.deref(a1)) { - Addr::Char(c) => { - let iter = once(Addr::Fixnum(c as isize)); - let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); + let a1 = self.store(self.deref(self.registers[1])); - let a2 = self[temp_v!(2)]; - (self.unify_fn)(self, a2, list_of_codes); - } - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { - let a2 = self.store(self.deref(self[temp_v!(2)])); + read_heap_cell!(a1, + (HeapCellValueTag::Char, c) => { + let h = self.heap.len(); - let iter = name.as_str().chars().map(|c| Addr::Fixnum(c as isize)); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64))); + self.heap.push(empty_list_as_cell!()); - let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); + unify!(self, list_loc_as_cell!(h), self.registers[2]); + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + let iter = name.chars() + .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); - (self.unify_fn)(self, a2, list_of_codes); + let h = iter_to_heap_list(&mut self.heap, iter); + unify!(self, heap_loc_as_cell!(h), self.registers[2]); } else { - unreachable!() + self.fail = true; } } - Addr::EmptyList => { - let chars = vec![Addr::Fixnum('[' as isize), Addr::Fixnum(']' as isize)]; - - let list_of_codes = Addr::HeapCell(self.heap.to_list(chars.into_iter())); - let a2 = self[temp_v!(2)]; + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let stub_gen = || functor_stub(atom!("atom_codes"), 2); - (self.unify_fn)(self, a2, list_of_codes); - } - addr if addr.is_ref() => { - let stub = MachineError::functor_stub(clause_name!("atom_codes"), 2); - - match self.try_from_list(temp_v!(2), stub) { - Err(e) => return Err(e), + match self.try_from_list(self.registers[2], stub_gen) { Ok(addrs) => { - let mut chars = String::new(); - - for addr in addrs { - let addr = self.store(self.deref(addr)); + let string = self.codes_to_string(addrs.into_iter(), stub_gen)?; + let atom = self.atom_tbl.build_with(&string); - match Number::try_from((addr, &self.heap)) { - Ok(Number::Fixnum(n)) => { - let c = self.int_to_char( - &Integer::from(n), - "atom_codes", - 2, - )?; - - chars.push(c); - continue; - } - Ok(Number::Integer(n)) => { - let c = self.int_to_char(&n, "atom_codes", 2)?; - chars.push(c); - - continue; - } - _ => { - let stub = MachineError::functor_stub( - clause_name!("atom_codes"), - 2, - ); - - let err = MachineError::type_error( - self.heap.h(), - ValidType::Integer, - addr, - ); - - return Err(self.error_form(err, stub)); - } - } - } - - let string = self.heap.to_unifiable(HeapCellValue::Atom( - clause_name!(chars, self.atom_tbl), - None, - )); - - self.bind(addr.as_var().unwrap(), string); + self.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); + } + Err(e) => { + return Err(e); } } } _ => { - unreachable!() + unreachable!(); } - }; + ); } &SystemClauseType::AtomLength => { - let a1 = self.store(self.deref(self[temp_v!(1)])); + let a1 = self.store(self.deref(self.registers[1])); - let atom = match self.store(self.deref(a1)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.clone() + let len: i64 = read_heap_cell!(a1, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + name.chars().count() as i64 } else { - unreachable!() + self.fail = true; + return Ok(()); } } - Addr::EmptyList => { - clause_name!("[]") - } - Addr::Char(c) => { - clause_name!(c.to_string(), self.atom_tbl) + (HeapCellValueTag::Char) => { + 1 } _ => { unreachable!() } - }; - - let len = Integer::from(atom.as_str().chars().count()); - let len = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(len))); - - let a2 = self[temp_v!(2)]; + ); - (self.unify_fn)(self, a2, len); + self.unify_fixnum( + Fixnum::build_with(len), + self.store(self.deref(self.registers[2])), + ); } &SystemClauseType::CallContinuation => { - let stub = MachineError::functor_stub(clause_name!("call_continuation"), 1); + let stub_gen = || functor_stub(atom!("call_continuation"), 1); + let a1 = self.store(self.deref(self.registers[1])); - match self.try_from_list(temp_v!(1), stub) { + match self.try_from_list(a1, stub_gen) { Err(e) => return Err(e), Ok(cont_chunks) => { let mut return_p = if self.last_call { @@ -1225,125 +1279,97 @@ impl MachineState { return Ok(()); } &SystemClauseType::CharsToNumber => { - let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); + let stub_gen = || functor_stub(atom!("number_chars"), 2); + let a1 = self.store(self.deref(self.registers[1])); - match self.try_from_list(temp_v!(1), stub) { - Err(e) => { - return Err(e); - } - Ok(addrs) => match self.try_char_list(addrs) { - Ok(string) => { - let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); - self.parse_number_from_string(string, indices, stub)?; - } - Err(err) => { - let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); - - return Err(self.error_form(err, stub)); - } - }, + if let Some(atom_or_string) = self.value_to_str_like(a1) { + self.parse_number_from_string(atom_or_string.to_string(), indices, stub_gen)?; + } else { + // a1 is a ground list at the call site within + // number_chars/2, so failure of value_to_str_like + // means the list contains a non-character. + let err = self.type_error(ValidType::Character, a1); + return Err(self.error_form(err, stub_gen())); } } &SystemClauseType::CreatePartialString => { - let atom = match self.store(self.deref(self[temp_v!(1)])) { - Addr::Con(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.clone() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + let atom = cell_as_atom!(self.store(self.deref(self.registers[1]))); - if atom.as_str().is_empty() { + if atom == atom!("") { self.fail = true; return Ok(()); } - let pstr = self.heap.allocate_pstr(atom.as_str()); - (self.unify_fn)(self, self[temp_v!(2)], pstr); + let pstr_h = self.heap.len(); - if !self.fail { - let h = self.heap.h(); - let pstr_tail = self.heap[h - 1].as_addr(h - 1); + self.heap.push(pstr_as_cell!(atom)); + self.heap.push(heap_loc_as_cell!(pstr_h+1)); - (self.unify_fn)(self, self[temp_v!(3)], pstr_tail); + unify!(self, self.registers[2], pstr_loc_as_cell!(pstr_h)); + + if !self.fail { + self.bind(Ref::heap_cell(pstr_h+1), self.registers[3]); } } &SystemClauseType::IsPartialString => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let value = self.store(self.deref(self.registers[1])); - match addr { - Addr::EmptyList => { - return return_from_clause!(self.last_call, self); - } - Addr::AttrVar(_) | Addr::HeapCell(_) | Addr::StackCell(..) => { - self.fail = true; - return Ok(()); - } - _ => {} - } + let h = self.heap.len(); + self.heap.push(value); - let mut heap_pstr_iter = self.heap_pstr_iter(addr); + let mut iter = HeapPStrIter::new(&self.heap, h); - while let Some(_) = heap_pstr_iter.next() {} + while let Some(_) = iter.next() {} - self.fail = match heap_pstr_iter.focus() { - Addr::AttrVar(_) - | Addr::HeapCell(_) - | Addr::StackCell(..) - | Addr::EmptyList => false, - _ => true, - }; + let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator(); + self.fail = !at_end_of_pstr; + + self.heap.pop(); } &SystemClauseType::PartialStringTail => { - let pstr = self.store(self.deref(self[temp_v!(1)])); + let pstr = self.store(self.deref(self.registers[1])); - match pstr { - Addr::PStrLocation(h, _) => { - if let HeapCellValue::PartialString(_, true) = &self.heap[h] { - let tail = self.heap[h + 1].as_addr(h + 1); - let target = self[temp_v!(2)]; + read_heap_cell!(pstr, + (HeapCellValueTag::PStrLoc, h) => { + let (h, _) = pstr_loc_and_offset(&self.heap, h); - (self.unify_fn)(self, tail, target); + if HeapCellValueTag::CStr == self.heap[h].get_tag() { + self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2]))); } else { - self.fail = true; - return Ok(()); + unify_fn!(self, heap_loc_as_cell!(h+1), self.registers[2]); } } - Addr::Lis(h) => { - (self.unify_fn)(self, Addr::HeapCell(h + 1), self[temp_v!(2)]); + (HeapCellValueTag::CStr) => { + self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2]))); } - Addr::EmptyList => { - self.fail = true; - return Ok(()); + (HeapCellValueTag::Lis, h) => { + unify_fn!(self, heap_loc_as_cell!(h+1), self.registers[2]); } _ => { - unreachable!() + self.fail = true; } - } + ); } &SystemClauseType::PeekByte => { + let stub_gen = || functor_stub(atom!("peek_byte"), 2); + let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "peek_byte", + atom!("peek_byte"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Binary, - Some(self[temp_v!(2)]), - clause_name!("peek_byte"), + Some(self.registers[2]), + atom!("peek_byte"), 2, )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1351,45 +1377,38 @@ impl MachineState { } if stream.at_end_of_stream() { - stream.set_past_end_of_stream(); - (self.unify_fn)(self, self[temp_v!(2)], Addr::Fixnum(-1)); + stream.set_past_end_of_stream(true); + + self.unify_fixnum( + Fixnum::build_with(-1), + self.store(self.deref(self.registers[2])), + ); + return return_from_clause!(self.last_call, self); } - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - addr => match Number::try_from((addr, &self.heap)) { + let addr = match self.store(self.deref(self.registers[2])) { + addr if addr.is_var() => addr, + addr => match Number::try_from(addr) { Ok(Number::Integer(n)) => { if let Some(nb) = n.to_u8() { - Addr::Usize(nb as usize) + fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("peek_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } } Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n) { - Addr::Usize(nb as usize) + if let Ok(nb) = u8::try_from(n.get_num()) { + fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("peek_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } } _ => { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("peek_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } }, }; @@ -1397,15 +1416,7 @@ impl MachineState { loop { match stream.peek_byte().map_err(|e| e.kind()) { Ok(b) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Usize(b as usize)); - break; - } else if addr == Addr::Usize(b as usize) { - break; - } else { - self.fail = true; - return Ok(()); - } + self.unify_fixnum(Fixnum::build_with(b as i64), addr); } Err(ErrorKind::PermissionDenied) => { self.fail = true; @@ -1413,13 +1424,13 @@ impl MachineState { } _ => { self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("peek_byte"), + self.registers[2], + stream, + atom!("peek_byte"), 2, )?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1429,23 +1440,25 @@ impl MachineState { } } &SystemClauseType::PeekChar => { + let stub_gen = || functor_stub(atom!("peek_char"), 2); + let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "peek_char", + atom!("peek_char"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, - Some(self[temp_v!(2)]), - clause_name!("peek_char"), + Some(self.registers[2]), + atom!("peek_char"), 2, )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1453,106 +1466,87 @@ impl MachineState { } if stream.at_end_of_stream() { - let end_of_file = clause_name!("end_of_file"); - let end_of_file = self - .heap - .to_unifiable(HeapCellValue::Atom(end_of_file, None)); - - stream.set_past_end_of_stream(); + let end_of_file = atom!("end_of_file"); + stream.set_past_end_of_stream(true); - (self.unify_fn)(self, self[temp_v!(2)], end_of_file); + self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); return return_from_clause!(self.last_call, self); } - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { - HeapCellValue::Atom(ref atom, _) if atom.is_char() => { - if let Some(c) = atom.as_str().chars().next() { - Addr::Char(c) + let a2 = self.store(self.deref(self.registers[2])); + + let a2 = read_heap_cell!(a2, + (HeapCellValueTag::Char) => { + a2 + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + if let Some(c) = name.as_char() { + char_as_cell!(c) } else { - unreachable!() + let err = self.type_error(ValidType::InCharacter, a2); + return Err(self.error_form(err, stub_gen())); } + } else { + let err = self.type_error(ValidType::InCharacter, a2); + return Err(self.error_form(err, stub_gen())); } - culprit => { - return Err(self.type_error( - ValidType::InCharacter, - culprit.as_addr(h), - clause_name!("peek_char"), - 2, - )); - } - }, - Addr::Char(d) => Addr::Char(d), - culprit => { - return Err(self.type_error( - ValidType::InCharacter, - culprit, - clause_name!("peek_char"), - 2, - )); } - }; + (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { + a2 + } + _ => { + let err = self.type_error(ValidType::InCharacter, a2); + return Err(self.error_form(err, stub_gen())); + } + ); loop { - match stream.peek_char().map_err(|e| e.kind()) { - Ok(d) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Char(d)); - break; - } else if addr == Addr::Char(d) { - break; - } else { - self.fail = true; - return Ok(()); - } + match stream.peek_char().map(|result| result.map_err(|e| e.kind())) { + Some(Ok(d)) => { + self.unify_char(d, a2); } - Err(ErrorKind::PermissionDenied) => { + Some(Err(ErrorKind::PermissionDenied)) => { self.fail = true; break; } _ => { self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("peek_char"), + self.registers[2], + stream, + atom!("peek_char"), 2, )?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } - } /* - _ => { - let stub = MachineError::functor_stub(clause_name!("peek_char"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); - - return Err(err); - }*/ + } } } } &SystemClauseType::PeekCode => { + let stub_gen = || functor_stub(atom!("peek_code"), 2); + let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "peek_code", + atom!("peek_code"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, - Some(self[temp_v!(2)]), - clause_name!("peek_code"), + Some(self.registers[2]), + atom!("peek_code"), 2, )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1560,89 +1554,73 @@ impl MachineState { } if stream.at_end_of_stream() { - let end_of_file = clause_name!("end_of_file"); - let end_of_file = self - .heap - .to_unifiable(HeapCellValue::Atom(end_of_file, None)); - - stream.set_past_end_of_stream(); + let end_of_file = atom!("end_of_file"); + stream.set_past_end_of_stream(true); - (self.unify_fn)(self, self[temp_v!(2)], end_of_file); + self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); return return_from_clause!(self.last_call, self); } - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - addr => match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - let n = n - .to_u32() - .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + let a2 = self.store(self.deref(self.registers[2])); - if let Some(n) = n { - Addr::Fixnum(n as isize) - } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("peek_code"), - 2, - )); + let addr = read_heap_cell!(a2, + (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { + a2 + } + _ => { + match Number::try_from(a2) { + Ok(Number::Integer(n)) => { + let n = n + .to_u32() + .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + + if let Some(n) = n { + fixnum_as_cell!(Fixnum::build_with(n as i64)) + } else { + let err = self.representation_error(RepFlag::InCharacterCode); + return Err(self.error_form(err, stub_gen())); + } } - } - Ok(Number::Fixnum(n)) => { - let n = u32::try_from(n) - .ok() - .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + Ok(Number::Fixnum(n)) => { + let n = u32::try_from(n.get_num()) + .ok() + .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); - if let Some(n) = n { - Addr::Fixnum(n as isize) - } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("peek_code"), - 2, - )); + if let Some(n) = n { + fixnum_as_cell!(Fixnum::build_with(n as i64)) + } else { + let err = self.representation_error(RepFlag::InCharacterCode); + return Err(self.error_form(err, stub_gen())); + } + } + _ => { + let err = self.type_error(ValidType::Integer, self.registers[2]); + return Err(self.error_form(err, stub_gen())); } } - _ => { - return Err(self.type_error( - ValidType::Integer, - self[temp_v!(2)], - clause_name!("peek_code"), - 2, - )); - } - }, - }; + } + ); loop { let result = stream.peek_char(); - match result.map_err(|e| e.kind()) { - Ok(c) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Fixnum(c as isize)); - break; - } else if addr == Addr::Fixnum(c as isize) { - break; - } else { - self.fail = true; - return Ok(()); - } + match result.map(|result| result.map_err(|e| e.kind())) { + Some(Ok(c)) => { + self.unify_fixnum(Fixnum::build_with(c as i64), addr); } - Err(ErrorKind::PermissionDenied) => { + Some(Err(ErrorKind::PermissionDenied)) => { self.fail = true; break; } _ => { self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("peek_code"), + self.registers[2], + stream, + atom!("peek_code"), 2, )?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -1652,16 +1630,16 @@ impl MachineState { } } &SystemClauseType::NumberToChars => { - let n = self[temp_v!(1)]; - let chs = self[temp_v!(2)]; + let n = self.registers[1]; + let chs = self.registers[2]; let n = self.store(self.deref(n)); - let string = match Number::try_from((n, &self.heap)) { + let string = match Number::try_from(n) { Ok(Number::Float(OrderedFloat(n))) => { format!("{0:<20?}", n) } - Ok(Number::Fixnum(n)) => n.to_string(), + Ok(Number::Fixnum(n)) => n.get_num().to_string(), Ok(Number::Integer(n)) => n.to_string(), Ok(Number::Rational(r)) => { // n has already been confirmed as an integer, and @@ -1674,20 +1652,18 @@ impl MachineState { } }; - let chars = string.trim().chars().map(|c| Addr::Char(c)); - let char_list = Addr::HeapCell(self.heap.to_list(chars)); - - (self.unify_fn)(self, char_list, chs); + let chars_atom = self.atom_tbl.build_with(&string.trim()); + self.unify_complete_string(chars_atom, self.store(self.deref(chs))); } &SystemClauseType::NumberToCodes => { - let n = self[temp_v!(1)]; - let chs = self[temp_v!(2)]; + let n = self.store(self.deref(self.registers[1])); + let chs = self.registers[2]; - let string = match Number::try_from((n, &self.heap)) { + let string = match Number::try_from(n) { Ok(Number::Float(OrderedFloat(n))) => { format!("{0:<20?}", n) } - Ok(Number::Fixnum(n)) => n.to_string(), + Ok(Number::Fixnum(n)) => n.get_num().to_string(), Ok(Number::Integer(n)) => n.to_string(), Ok(Number::Rational(r)) => { // n has already been confirmed as an integer, and @@ -1700,219 +1676,199 @@ impl MachineState { } }; - let codes = string.trim().chars().map(|c| Addr::Fixnum(c as isize)); - - let codes_list = Addr::HeapCell(self.heap.to_list(codes)); + let codes = string.trim().chars().map(|c| { + fixnum_as_cell!(Fixnum::build_with(c as i64)) + }); - (self.unify_fn)(self, codes_list, chs); + let h = iter_to_heap_list(&mut self.heap, codes); + unify!(self, heap_loc_as_cell!(h), chs); } &SystemClauseType::CodesToNumber => { - let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); + let stub_gen = || functor_stub(atom!("number_codes"), 2); - match self.try_from_list(temp_v!(1), stub) { + match self.try_from_list(self.registers[1], stub_gen) { Err(e) => { return Err(e); } - Ok(addrs) => match self.try_char_list(addrs) { - Ok(chars) => { - let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); - self.parse_number_from_string(chars, indices, stub)?; - } - Err(err) => { - let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); - - return Err(self.error_form(err, stub)); - } - }, + Ok(addrs) => { + let string = self.codes_to_string(addrs.into_iter(), stub_gen)?; + self.parse_number_from_string(string, indices, stub_gen)?; + } } } &SystemClauseType::LiftedHeapLength => { - let a1 = self[temp_v!(1)]; - let lh_len = Addr::Usize(self.lifted_heap.h()); + let a1 = self.registers[1]; + let lh_len = Fixnum::build_with(self.lifted_heap.len() as i64); - (self.unify_fn)(self, a1, lh_len); + self.unify_fixnum(lh_len, a1); } &SystemClauseType::CharCode => { - let a1 = self[temp_v!(1)]; - - match self.store(self.deref(a1)) { - Addr::Con(h) if self.heap.atom_at(h) => { - let c = if let HeapCellValue::Atom(name, _) = &self.heap[h] { - if name.is_char() { - name.as_str().chars().next().unwrap() - } else { - self.fail = true; - return Ok(()); - } - } else { - unreachable!() - }; + let stub_gen = || functor_stub(atom!("char_code"), 2); + let a1 = self.store(self.deref(self.registers[1])); - let a2 = self[temp_v!(2)]; - (self.unify_fn)(self, Addr::Fixnum(c as isize), a2); + let c = read_heap_cell!(a1, + (HeapCellValueTag::Atom, (name, _arity)) => { + name.as_char().unwrap() } - Addr::Char(c) => { - let a2 = self[temp_v!(2)]; - (self.unify_fn)(self, Addr::Fixnum(c as isize), a2); + (HeapCellValueTag::Char, c) => { + c } - addr if addr.is_ref() => { - let a2 = self[temp_v!(2)]; - let a2 = self.store(self.deref(a2)); + _ => { + let a2 = self.store(self.deref(self.registers[2])); + + match Number::try_from(a2) { + Ok(Number::Integer(n)) => { + let c = match n.to_u32().and_then(std::char::from_u32) { + Some(c) => c, + _ => { + let err = self.representation_error(RepFlag::CharacterCode); + return Err(self.error_form(err, stub_gen())); + } + }; - let c = match Number::try_from((a2, &self.heap)) { - Ok(Number::Integer(n)) => self.int_to_char(&n, "char_code", 2)?, + self.unify_char(c, a2); + return return_from_clause!(self.last_call, self); + } Ok(Number::Fixnum(n)) => { - self.int_to_char(&Integer::from(n), "char_code", 2)? + match u32::try_from(n.get_num()) { + Ok(n) => { + if let Some(c) = std::char::from_u32(n) { + self.unify_char(c, a1); + return return_from_clause!(self.last_call, self); + } + } + _ => {} + } + + let err = self.representation_error(RepFlag::CharacterCode); + return Err(self.error_form(err, stub_gen())); } _ => { self.fail = true; return Ok(()); } - }; - - (self.unify_fn)(self, Addr::Char(c), addr); - } - _ => { - unreachable!(); + } } - }; + ); + + self.unify_fixnum( + Fixnum::build_with(c as i64), + self.store(self.deref(self.registers[2])), + ); } &SystemClauseType::CharType => { - let a1 = self.store(self.deref(self[temp_v!(1)])); - let a2 = self.store(self.deref(self[temp_v!(2)])); - - let c = match a1 { - Addr::Char(c) => c, - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - name.as_str().chars().next().unwrap() - } else { - unreachable!() - } + let a1 = self.store(self.deref(self.registers[1])); + let a2 = self.store(self.deref(self.registers[2])); + + let c = read_heap_cell!(a1, + (HeapCellValueTag::Char, c) => { + c } - _ => unreachable!(), - }; - let chars = match a2 { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - name.as_str().to_string() - } else { - unreachable!() - } + (HeapCellValueTag::Atom, (name, _arity)) => { + name.as_char().unwrap() } - Addr::Char(c) => c.to_string(), - _ => unreachable!(), - }; + _ => { + unreachable!() + } + ); + + let chars = cell_as_atom!(a2); self.fail = true; // This predicate fails by default. + macro_rules! macro_check { - ($id:ident, $name:tt) => { + ($id:ident, $name:expr) => { if $id!(c) && chars == $name { self.fail = false; - return return_from_clause!(self.last_call, self); } }; } + macro_rules! method_check { - ($id:ident, $name:tt) => { + ($id:ident, $name:expr) => { if c.$id() && chars == $name { self.fail = false; - return return_from_clause!(self.last_call, self); } }; } - macro_check!(alpha_char, "alpha"); - method_check!(is_alphabetic, "alphabetic"); - method_check!(is_alphanumeric, "alphanumeric"); - macro_check!(alpha_numeric_char, "alnum"); - method_check!(is_ascii, "ascii"); - method_check!(is_ascii_punctuation, "ascii_ponctuaction"); - method_check!(is_ascii_graphic, "ascii_graphic"); - // macro_check!(backslash_char, "backslash"); - // macro_check!(back_quote_char, "back_quote"); - macro_check!(binary_digit_char, "binary_digit"); - // macro_check!(capital_letter_char, "upper"); + + macro_check!(alpha_char, atom!("alpha")); + method_check!(is_alphabetic, atom!("alphabetic")); + method_check!(is_alphanumeric, atom!("alphanumeric")); + macro_check!(alpha_numeric_char, atom!("alnum")); + method_check!(is_ascii, atom!("ascii")); + method_check!(is_ascii_punctuation, atom!("ascii_ponctuaction")); + method_check!(is_ascii_graphic, atom!("ascii_graphic")); + // macro_check!(backslash_char, atom!("backslash")); + // macro_check!(back_quote_char, atom!("back_quote")); + macro_check!(binary_digit_char, atom!("binary_digit")); + // macro_check!(capital_letter_char, atom!("upper")); // macro_check!(comment_1_char, "comment_1"); // macro_check!(comment_2_char, "comment_2"); - method_check!(is_control, "control"); - // macro_check!(cut_char, "cut"); - macro_check!(decimal_digit_char, "decimal_digit"); - // macro_check!(decimal_point_char, "decimal_point"); - // macro_check!(double_quote_char, "double_quote"); - macro_check!(exponent_char, "exponent"); - macro_check!(graphic_char, "graphic"); - macro_check!(graphic_token_char, "graphic_token"); - macro_check!(hexadecimal_digit_char, "hexadecimal_digit"); - macro_check!(layout_char, "layout"); - method_check!(is_lowercase, "lower"); - macro_check!(meta_char, "meta"); - // macro_check!(new_line_char, "new_line"); - method_check!(is_numeric, "numeric"); - macro_check!(octal_digit_char, "octal_digit"); - macro_check!(octet_char, "octet"); - macro_check!(prolog_char, "prolog"); - // macro_check!(semicolon_char, "semicolon"); - macro_check!(sign_char, "sign"); - // macro_check!(single_quote_char, "single_quote"); - // macro_check!(small_letter_char, "lower"); - macro_check!(solo_char, "solo"); - // macro_check!(space_char, "space"); - macro_check!(symbolic_hexadecimal_char, "symbolic_hexadecimal"); - macro_check!(symbolic_control_char, "symbolic_control"); - method_check!(is_uppercase, "upper"); - // macro_check!(variable_indicator_char, "variable_indicator"); - method_check!(is_whitespace, "whitespace"); + method_check!(is_control, atom!("control")); + // macro_check!(cut_char, atom!("cut")); + macro_check!(decimal_digit_char, atom!("decimal_digit")); + // macro_check!(decimal_point_char, atom!("decimal_point")); + // macro_check!(double_quote_char, atom!("double_quote")); + macro_check!(exponent_char, atom!("exponent")); + macro_check!(graphic_char, atom!("graphic")); + macro_check!(graphic_token_char, atom!("graphic_token")); + macro_check!(hexadecimal_digit_char, atom!("hexadecimal_digit")); + macro_check!(layout_char, atom!("layout")); + method_check!(is_lowercase, atom!("lower")); + macro_check!(meta_char, atom!("meta")); + // macro_check!(new_line_char, atom!("new_line")); + method_check!(is_numeric, atom!("numeric")); + macro_check!(octal_digit_char, atom!("octal_digit")); + macro_check!(octet_char, atom!("octet")); + macro_check!(prolog_char, atom!("prolog")); + // macro_check!(semicolon_char, atom!("semicolon")); + macro_check!(sign_char, atom!("sign")); + // macro_check!(single_quote_char, atom!("single_quote")); + // macro_check!(small_letter_char, atom!("lower")); + macro_check!(solo_char, atom!("solo")); + // macro_check!(space_char, atom!("space")); + macro_check!(symbolic_hexadecimal_char, atom!("symbolic_hexadecimal")); + macro_check!(symbolic_control_char, atom!("symbolic_control")); + method_check!(is_uppercase, atom!("upper")); + // macro_check!(variable_indicator_char, atom!("variable_indicator")); + method_check!(is_whitespace, atom!("whitespace")); } &SystemClauseType::CheckCutPoint => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); + let old_b = cell_as_fixnum!(addr).get_num() as usize; - match addr { - Addr::Usize(old_b) | Addr::CutPoint(old_b) => { - let prev_b = self.stack.index_or_frame(self.b).prelude.b; - let prev_b = self.stack.index_or_frame(prev_b).prelude.b; + let prev_b = self.stack.index_or_frame(self.b).prelude.b; + let prev_b = self.stack.index_or_frame(prev_b).prelude.b; - if prev_b > old_b { - self.fail = true; - } - } - _ => self.fail = true, - }; + if prev_b > old_b { + self.fail = true; + } } &SystemClauseType::CopyTermWithoutAttrVars => { self.copy_term(AttrVarPolicy::StripAttributes); } &SystemClauseType::FetchGlobalVar => { - let (key_h, key) = match self.store(self.deref(self[temp_v!(1)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - (h, atom.clone()) - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; - - let addr = self[temp_v!(2)]; + let key = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let addr = self.registers[2]; match indices.global_variables.get_mut(&key) { Some((ref ball, ref mut loc)) => match loc { - Some(ref value_addr) => { - (self.unify_fn)(self, addr, *value_addr); + Some(value_loc) => { + unify_fn!(self, addr, *value_loc); } - loc @ None if !ball.stub.is_empty() => { - let h = self.heap.h(); + None if !ball.stub.is_empty() => { + let h = self.heap.len(); let stub = ball.copy_and_align(h); self.heap.extend(stub.into_iter()); - (self.unify_fn)(self, addr, Addr::HeapCell(h)); + + unify_fn!(self, addr, heap_loc_as_cell!(h)); if !self.fail { - *loc = Some(Addr::HeapCell(h)); - self.trail(TrailRef::BlackboardEntry(key_h)); + *loc = Some(heap_loc_as_cell!(h)); + self.trail(TrailRef::BlackboardEntry(key)); } } _ => self.fail = true, @@ -1922,308 +1878,252 @@ impl MachineState { } &SystemClauseType::PutCode => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "put_code", + atom!("put_code"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, None, - clause_name!("put_code"), + atom!("put_code"), 2, )?; - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - let stub = MachineError::functor_stub(clause_name!("put_code"), 2); - let err = MachineError::instantiation_error(); + let stub_gen = || functor_stub(atom!("put_code"), 2); - return Err(self.error_form(err, stub)); - } - addr => { - match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); - } - } - Ok(Number::Fixnum(n)) => { - if let Some(c) = - u32::try_from(n).ok().and_then(|c| char::try_from(c).ok()) - { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); - } - } - _ => { - let stub = MachineError::functor_stub(clause_name!("put_code"), 2); - let err = MachineError::type_error( - self.heap.h(), - ValidType::Integer, - self[temp_v!(2)], - ); - - return Err(self.error_form(err, stub)); + let addr = self.store(self.deref(self.registers[2])); + + if addr.is_var() { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); + } else { + match Number::try_from(addr) { + Ok(Number::Integer(n)) => { + if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) { + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); } } + Ok(Number::Fixnum(n)) => { + let n = n.get_num(); - let stub = MachineError::functor_stub(clause_name!("put_code"), 2); - let err = MachineError::representation_error(RepFlag::CharacterCode); - - return Err(self.error_form(err, stub)); + if let Some(c) = u32::try_from(n).ok().and_then(|c| char::from_u32(c)) { + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); + } + } + _ => { + let err = self.type_error(ValidType::Integer, addr); + return Err(self.error_form(err, stub_gen())); + } } + + let err = self.representation_error(RepFlag::CharacterCode); + return Err(self.error_form(err, stub_gen())); } } &SystemClauseType::PutChar => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "put_char", + atom!("put_char"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, None, - clause_name!("put_char"), + atom!("put_char"), 2, )?; - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - let stub = MachineError::functor_stub(clause_name!("put_char"), 2); - let err = MachineError::instantiation_error(); + let stub_gen = || functor_stub(atom!("put_char"), 2); + let addr = self.store(self.deref(self.registers[2])); - return Err(self.error_form(err, stub)); - } - addr => { - match self.store(self.deref(self[temp_v!(2)])) { - Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { - HeapCellValue::Atom(ref atom, _) if atom.is_char() => { - if let Some(c) = atom.as_str().chars().next() { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); - } else { - unreachable!() - } - } - _ => {} - }, - Addr::Char(c) => { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); - } - _ => {} + if addr.is_var() { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); + } else { + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, _arity)) => { + let c = name.as_char().unwrap(); + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); } + (HeapCellValueTag::Char, c) => { + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); + } + _ => { + } + ); - let stub = MachineError::functor_stub(clause_name!("put_char"), 2); - let err = - MachineError::type_error(self.heap.h(), ValidType::Character, addr); - - return Err(self.error_form(err, stub)); - } + let err = self.type_error(ValidType::Character, addr); + return Err(self.error_form(err, stub_gen())); } } &SystemClauseType::PutChars => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "$put_chars", + atom!("$put_chars"), 2, )?; let mut bytes = Vec::new(); - let string = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); + let stub_gen = || functor_stub(atom!("$put_chars"), 2); + + if let Some(string) = self.value_to_str_like(self.registers[2]) { + if stream.options().stream_type() == StreamType::Binary { + for c in string.as_str().chars() { + if c as u32 > 255 { + let err = self.type_error(ValidType::Byte, char_as_cell!(c)); + return Err(self.error_form(err, stub_gen())); + } - if stream.options().stream_type == StreamType::Binary { - for c in string.chars() { - bytes.push(c as u8); + bytes.push(c as u8); + } + } else { + bytes = string.as_str().bytes().collect(); } - } else { - bytes = string.into_bytes(); - } - match stream.write_all(&bytes) { - Ok(_) => { - return return_from_clause!(self.last_call, self); - } - _ => { - let stub = MachineError::functor_stub(clause_name!("$put_chars"), 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, - )); + match stream.write_all(&bytes) { + Ok(_) => { + return return_from_clause!(self.last_call, self); + } + _ => { + let addr = stream_as_cell!(stream); + let err = self.existence_error(ExistenceError::Stream(addr)); + + return Err(self.error_form(err, stub_gen())); + } } + } else { + self.fail = true; } } &SystemClauseType::PutByte => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "put_byte", + atom!("put_byte"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Binary, None, - clause_name!("put_byte"), + atom!("put_byte"), 2, )?; - match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => { - let stub = MachineError::functor_stub(clause_name!("put_byte"), 2); - let err = MachineError::instantiation_error(); + let stub_gen = || functor_stub(atom!("put_byte"), 2); + let addr = self.store(self.deref(self.registers[2])); - return Err(self.error_form(err, stub)); - } - addr => { - match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => { - if let Some(nb) = n.to_u8() { - match stream.write(&mut [nb]) { - Ok(1) => { - return return_from_clause!(self.last_call, self); - } - _ => { - let stub = MachineError::functor_stub( - clause_name!("put_byte"), - 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, - )); - } + if addr.is_var() { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); + } else { + match Number::try_from(addr) { + Ok(Number::Integer(n)) => { + if let Some(nb) = n.to_u8() { + match stream.write(&mut [nb]) { + Ok(1) => { + return return_from_clause!(self.last_call, self); + } + _ => { + let err = self.existence_error( + ExistenceError::Stream(stream_as_cell!(stream)) + ); + + return Err(self.error_form(err, stub_gen())); } } } - Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n) { - match stream.write(&mut [nb]) { - Ok(1) => { - return return_from_clause!(self.last_call, self); - } - _ => { - let stub = MachineError::functor_stub( - clause_name!("put_byte"), - 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, - )); - } + } + Ok(Number::Fixnum(n)) => { + if let Ok(nb) = u8::try_from(n.get_num()) { + match stream.write(&mut [nb]) { + Ok(1) => { + return return_from_clause!(self.last_call, self); + } + _ => { + let err = self.existence_error( + ExistenceError::Stream(stream_as_cell!(stream)) + ); + + return Err(self.error_form(err, stub_gen())); } } } - _ => {} } - - let stub = MachineError::functor_stub(clause_name!("put_byte"), 2); - let err = MachineError::type_error( - self.heap.h(), - ValidType::Byte, - self[temp_v!(2)], - ); - - return Err(self.error_form(err, stub)); + _ => { + } } } + + let err = self.type_error(ValidType::Byte, self.registers[2]); + return Err(self.error_form(err, stub_gen())); } &SystemClauseType::GetByte => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "get_byte", + atom!("get_byte"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Binary, - Some(self[temp_v!(2)]), - clause_name!("get_byte"), + Some(self.registers[2]), + atom!("get_byte"), 2, )?; if stream.past_end_of_stream() { - self.eof_action(self[temp_v!(2)], &mut stream, clause_name!("get_byte"), 2)?; + self.eof_action(self.registers[2], stream, atom!("get_byte"), 2)?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } } - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - addr => match Number::try_from((addr, &self.heap)) { + let stub_gen = || functor_stub(atom!("get_byte"), 2); + let addr = self.store(self.deref(self.registers[2])); + + let addr = if addr.is_var() { + addr + } else { + match Number::try_from(addr) { Ok(Number::Integer(n)) => { if let Some(nb) = n.to_u8() { - Addr::Usize(nb as usize) + fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("get_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } } Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n) { - Addr::Usize(nb as usize) + if let Ok(nb) = u8::try_from(n.get_num()) { + fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("get_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } } _ => { - return Err(self.type_error( - ValidType::InByte, - addr, - clause_name!("get_byte"), - 2, - )); + let err = self.type_error(ValidType::InByte, addr); + return Err(self.error_form(err, stub_gen())); } - }, + } }; loop { @@ -2231,19 +2131,12 @@ impl MachineState { match stream.read(&mut b) { Ok(1) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Usize(b[0] as usize)); - break; - } else if addr == Addr::Usize(b[0] as usize) { - break; - } else { - self.fail = true; - return Ok(()); - } + self.unify_fixnum(Fixnum::build_with(b[0] as i64), addr); + break; } _ => { - stream.set_past_end_of_stream(); - (self.unify_fn)(self, self[temp_v!(2)], Addr::Fixnum(-1)); + stream.set_past_end_of_stream(true); + self.unify_fixnum(Fixnum::build_with(-1), self.registers[2]); return return_from_clause!(self.last_call, self); } } @@ -2251,22 +2144,22 @@ impl MachineState { } &SystemClauseType::GetChar => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "get_char", + atom!("get_char"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, - Some(self[temp_v!(2)]), - clause_name!("get_char"), + Some(self.registers[2]), + atom!("get_char"), 2, )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -2274,98 +2167,73 @@ impl MachineState { } if stream.at_end_of_stream() { - let end_of_file = clause_name!("end_of_file"); - let end_of_file = self - .heap - .to_unifiable(HeapCellValue::Atom(end_of_file, None)); - - stream.set_past_end_of_stream(); + let end_of_file = atom!("end_of_file"); + stream.set_past_end_of_stream(true); - (self.unify_fn)(self, self[temp_v!(2)], end_of_file); + self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); return return_from_clause!(self.last_call, self); } - let mut iter = self.open_parsing_stream(stream.clone(), "get_char", 2)?; + let stub_gen = || functor_stub(atom!("get_char"), 2); + let mut iter = self.open_parsing_stream(stream, atom!("get_char"), 2)?; - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { - HeapCellValue::Atom(ref atom, _) if atom.is_char() => { - if let Some(c) = atom.as_str().chars().next() { - Addr::Char(c) - } else { - unreachable!() - } + let addr = self.store(self.deref(self.registers[2])); + + let addr = if addr.is_var() { + addr + } else { + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (atom, _arity)) => { + char_as_cell!(atom.as_char().unwrap()) } - culprit => { - return Err(self.type_error( - ValidType::InCharacter, - culprit.as_addr(h), - clause_name!("get_char"), - 2, - )); + (HeapCellValueTag::Char) => { + addr } - }, - Addr::Char(d) => Addr::Char(d), - culprit => { - return Err(self.type_error( - ValidType::InCharacter, - culprit, - clause_name!("get_char"), - 2, - )); - } + _ => { + let err = self.type_error(ValidType::InCharacter, addr); + return Err(self.error_form(err, stub_gen())); + } + ) }; loop { - let result = iter.next(); + let result = iter.read_char(); match result { - Some(Ok(d)) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Char(d)); - break; - } else if addr == Addr::Char(d) { - break; - } else { - self.fail = true; + Some(Ok(c)) => { + self.unify_char(c, addr); + + if self.fail { return Ok(()); } } _ => { self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("get_char"), + self.registers[2], + stream, + atom!("get_char"), 2, )?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); } - } /* - _ => { - let stub = MachineError::functor_stub(clause_name!("get_char"), 2); - let err = MachineError::representation_error(RepFlag::Character); - let err = self.error_form(err, stub); - - return Err(err); - }*/ + } } } } &SystemClauseType::GetNChars => { let stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "get_n_chars", + atom!("get_n_chars"), 3, )?; - let num = match Number::try_from((self[temp_v!(2)], &self.heap)) { - Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + let num = match Number::try_from(self.store(self.deref(self.registers[2]))) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match n.to_usize() { Some(u) => u, _ => { @@ -2380,18 +2248,20 @@ impl MachineState { let mut string = String::new(); - if stream.options().stream_type == StreamType::Binary { + if stream.options().stream_type() == StreamType::Binary { let mut buf = vec![]; let mut chunk = stream.take(num as u64); + chunk.read_to_end(&mut buf).ok(); + for c in buf { string.push(c as char); } } else { - let mut iter = self.open_parsing_stream(stream.clone(), "get_n_chars", 2)?; + let mut iter = self.open_parsing_stream(stream, atom!("get_n_chars"), 2)?; for _ in 0..num { - let result = iter.next(); + let result = iter.read_char(); match result { Some(Ok(c)) => { @@ -2403,27 +2273,28 @@ impl MachineState { } } }; - let string = self.heap.put_complete_string(&string); - (self.unify_fn)(self, self[temp_v!(3)], string); + + let atom = self.atom_tbl.build_with(&string); + self.unify_complete_string(atom, self.store(self.deref(self.registers[3]))); } &SystemClauseType::GetCode => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "get_code", + atom!("get_code"), 2, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, - Some(self[temp_v!(2)]), - clause_name!("get_code"), + Some(self.registers[2]), + atom!("get_code"), 2, )?; if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -2431,87 +2302,74 @@ impl MachineState { } if stream.at_end_of_stream() { - let end_of_file = Integer::from(-1); - let end_of_file = self - .heap - .to_unifiable(HeapCellValue::Integer(Rc::new(end_of_file))); + let end_of_file = atom!("end_of_file"); - stream.set_past_end_of_stream(); + stream.set_past_end_of_stream(true); - (self.unify_fn)(self, self[temp_v!(2)], end_of_file); + self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); return return_from_clause!(self.last_call, self); } - let addr = match self.store(self.deref(self[temp_v!(2)])) { - addr if addr.is_ref() => addr, - addr => match Number::try_from((addr, &self.heap)) { + let stub_gen = || functor_stub(atom!("get_code"), 2); + let addr = self.store(self.deref(self.registers[2])); + + let addr = if addr.is_var() { + addr + } else { + match Number::try_from(addr) { Ok(Number::Integer(n)) => { let n = n .to_u32() - .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + .and_then(|n| std::char::from_u32(n)); if let Some(n) = n { - Addr::Fixnum(n as isize) + fixnum_as_cell!(Fixnum::build_with(n as i64)) } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("get_code"), - 2, - )); + let err = self.representation_error(RepFlag::InCharacterCode); + return Err(self.error_form(err, stub_gen())); } } Ok(Number::Fixnum(n)) => { - let n = u32::try_from(n) + let nf = u32::try_from(n.get_num()) .ok() - .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + .and_then(|n| std::char::from_u32(n)); - if let Some(n) = n { - Addr::Fixnum(n as isize) + if nf.is_some() { + fixnum_as_cell!(n) } else { - return Err(self.representation_error( - RepFlag::InCharacterCode, - clause_name!("get_code"), - 2, - )); + let err = self.representation_error(RepFlag::InCharacterCode); + return Err(self.error_form(err, stub_gen())); } } _ => { - return Err(self.type_error( - ValidType::Integer, - self[temp_v!(2)], - clause_name!("get_code"), - 2, - )); + let err = self.type_error(ValidType::Integer, self.registers[2]); + return Err(self.error_form(err, stub_gen())); } - }, + } }; - let mut iter = self.open_parsing_stream(stream.clone(), "get_code", 2)?; + let mut iter = self.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?; loop { - let result = iter.next(); + let result = iter.read_char(); match result { Some(Ok(c)) => { - if let Some(var) = addr.as_var() { - self.bind(var, Addr::Fixnum(c as isize)); - break; - } else if addr == Addr::Fixnum(c as isize) { - break; - } else { - self.fail = true; + self.unify_fixnum(Fixnum::build_with(c as i64), addr); + + if self.fail { return Ok(()); } } _ => { self.eof_action( - self[temp_v!(2)], - &mut stream, - clause_name!("get_code"), + self.registers[2], + stream, + atom!("get_code"), 2, )?; - if EOFAction::Reset != stream.options().eof_action { + if EOFAction::Reset != stream.options().eof_action() { return return_from_clause!(self.last_call, self); } else if self.fail { return Ok(()); @@ -2536,9 +2394,9 @@ impl MachineState { indices.streams = indices.streams.sub(&null_streams); if let Some(first_stream) = first_stream { - let stream = self.heap.to_unifiable(HeapCellValue::Stream(first_stream)); + let stream = stream_as_cell!(first_stream); - let var = self.store(self.deref(self[temp_v!(1)])).as_var().unwrap(); + let var = self.store(self.deref(self.registers[1])).as_var().unwrap(); self.bind(var, stream); } else { self.fail = true; @@ -2546,25 +2404,14 @@ impl MachineState { } } &SystemClauseType::NextStream => { - let prev_stream = match self.store(self.deref(self[temp_v!(1)])) { - Addr::Stream(h) => { - if let HeapCellValue::Stream(ref stream) = &self.heap[h] { - stream.clone() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + let prev_stream = cell_as_stream!(self.store(self.deref(self.registers[1]))); let mut next_stream = None; let mut null_streams = BTreeSet::new(); for stream in indices .streams - .range(prev_stream.clone()..) + .range(prev_stream..) .skip(1) .cloned() { @@ -2579,8 +2426,8 @@ impl MachineState { indices.streams = indices.streams.sub(&null_streams); if let Some(next_stream) = next_stream { - let var = self.store(self.deref(self[temp_v!(2)])).as_var().unwrap(); - let next_stream = self.heap.to_unifiable(HeapCellValue::Stream(next_stream)); + let var = self.store(self.deref(self.registers[2])).as_var().unwrap(); + let next_stream = stream_as_cell!(next_stream); self.bind(var, next_stream); } else { @@ -2590,21 +2437,19 @@ impl MachineState { } &SystemClauseType::FlushOutput => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "flush_output", + atom!("flush_output"), 1, )?; if !stream.is_output_stream() { - let stub = MachineError::functor_stub(clause_name!("flush_output"), 1); - - let addr = vec![HeapCellValue::Stream(stream)]; + let stub = functor_stub(atom!("flush_output"), 1); + let addr = stream_as_cell!(stream); // vec![HeapCellValue::Stream(stream)]; - let err = MachineError::permission_error( - self.heap.h(), + let err = self.permission_error( Permission::OutputStream, - "stream", + atom!("stream"), addr, ); @@ -2618,14 +2463,17 @@ impl MachineState { code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL, }; + let key = get_key(); + if key == ctrl_c { - let stub = MachineError::functor_stub(clause_name!("get_single_char"), 1); - let err = MachineError::interrupt_error(); + let stub = functor_stub(atom!("get_single_char"), 1); + let err = self.interrupt_error(); let err = self.error_form(err, stub); return Err(err); } + let c = match key.code { KeyCode::Enter => '\n', KeyCode::Tab => '\t', @@ -2633,37 +2481,30 @@ impl MachineState { _ => unreachable!(), }; - let a1 = self[temp_v!(1)]; - - (self.unify_fn)(self, Addr::Char(c), a1); + self.unify_char(c, self.store(self.deref(self.registers[1]))); } &SystemClauseType::HeadIsDynamic => { - let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); - - self.fail = !match self.store(self.deref(self[temp_v!(2)])) { - Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(arity, ref name, ..) => { - indices.is_dynamic_predicate(module_name, (name.clone(), arity)) - } - _ => unreachable!(), - }, - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - indices.is_dynamic_predicate(module_name, (name.clone(), 0)) - } else { - unreachable!() - } - } + let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); + + let (name, arity) = read_heap_cell!(self.store(self.deref(self.registers[2])), + (HeapCellValueTag::Str, s) => { + cell_as_atom_cell!(self.heap[s]).get_name_and_arity() + } + (HeapCellValueTag::Atom, (name, _arity)) => { + (name, 0) + } _ => { - unreachable!() - } - }; + unreachable!() + } + ); + + self.fail = !indices.is_dynamic_predicate(module_name, (name, arity)); } &SystemClauseType::Close => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "close", + atom!("close"), 2, )?; @@ -2676,404 +2517,423 @@ impl MachineState { if stream == *current_input_stream { *current_input_stream = indices .stream_aliases - .get(&clause_name!("user_input")) + .get(&atom!("user_input")) .cloned() .unwrap(); - indices.streams.insert(current_input_stream.clone()); + indices.streams.insert(*current_input_stream); } else if stream == *current_output_stream { *current_output_stream = indices .stream_aliases - .get(&clause_name!("user_output")) + .get(&atom!("user_output")) .cloned() .unwrap(); - indices.streams.insert(current_output_stream.clone()); + indices.streams.insert(*current_output_stream); } if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() { let close_result = stream.close(); - if let Some(ref alias) = stream.options().alias { - indices.stream_aliases.remove(alias); + if let Some(alias) = stream.options().get_alias() { + indices.stream_aliases.remove(&alias); } if let Err(_) = close_result { - let stub = MachineError::functor_stub( - clause_name!("close"), - 1, - ); - - let addr = self.heap.to_unifiable( - HeapCellValue::Stream(stream.clone()), - ); + let stub = functor_stub(atom!("close"), 1); + let addr = stream_as_cell!(stream); + let err = self.existence_error(ExistenceError::Stream(addr)); - return Err(self.error_form( - MachineError::existence_error( - self.heap.h(), - ExistenceError::Stream(addr), - ), - stub, - )); + return Err(self.error_form(err, stub)); } } } - &SystemClauseType::CopyToLiftedHeap => match self.store(self.deref(self[temp_v!(1)])) { - Addr::Usize(lh_offset) => { - let copy_target = self[temp_v!(2)]; + &SystemClauseType::CopyToLiftedHeap => { + let lh_offset = cell_as_fixnum!( + self.store(self.deref(self.registers[1])) + ).get_num() as usize; - let old_threshold = self.copy_findall_solution(lh_offset, copy_target); - let new_threshold = self.lifted_heap.h() - lh_offset; + let copy_target = self.registers[2]; - self.lifted_heap[old_threshold] = - HeapCellValue::Addr(Addr::HeapCell(new_threshold)); + let old_threshold = self.copy_findall_solution(lh_offset, copy_target); + let new_threshold = self.lifted_heap.len() - lh_offset; - for addr in self.lifted_heap.iter_mut_from(old_threshold + 1) { - match addr { - HeapCellValue::Addr(ref mut addr) => { - *addr -= self.heap.h() + lh_offset; - } - _ => {} - } - } - } - _ => { - self.fail = true; + self.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold); + + for addr in self.lifted_heap[old_threshold + 1 ..].iter_mut() { + *addr -= self.heap.len() + lh_offset; } }, &SystemClauseType::DeleteAttribute => { - let ls0 = self.store(self.deref(self[temp_v!(1)])); + let ls0 = self.store(self.deref(self.registers[1])); - if let Addr::Lis(l1) = ls0 { - if let Addr::Lis(l2) = self.store(self.deref(Addr::HeapCell(l1 + 1))) { - let old_addr = self.heap[l1 + 1].as_addr(l1 + 1); - let tail = self.store(self.deref(Addr::HeapCell(l2 + 1))); + if let HeapCellValueTag::Lis = ls0.get_tag() { + let l1 = ls0.get_value(); + let ls1 = self.store(self.deref(heap_loc_as_cell!(l1 + 1))); - let tail = if tail.is_ref() { - Addr::HeapCell(l1 + 1) + if let HeapCellValueTag::Lis = ls1.get_tag() { + let l2 = ls1.get_value(); + + let old_addr = self.heap[l1+1]; + let tail = self.store(self.deref(heap_loc_as_cell!(l2 + 1))); + + let tail = if tail.is_var() { + heap_loc_as_cell!(l1 + 1) } else { tail }; - let trail_ref = match old_addr { - Addr::HeapCell(h) => TrailRef::AttrVarHeapLink(h), - Addr::Lis(l) => TrailRef::AttrVarListLink(l1 + 1, l), - _ => unreachable!(), - }; + let trail_ref = read_heap_cell!(old_addr, + (HeapCellValueTag::Var, h) => { + TrailRef::AttrVarHeapLink(h) + } + (HeapCellValueTag::Lis, l) => { + TrailRef::AttrVarListLink(l1 + 1, l) + } + _ => { + unreachable!() + } + ); - self.heap[l1 + 1] = HeapCellValue::Addr(tail); + self.heap[l1 + 1] = tail; self.trail(trail_ref); } } } &SystemClauseType::DeleteHeadAttribute => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); - match addr { - Addr::AttrVar(h) => { - let addr = self.heap[h + 1].as_addr(h + 1); - let addr = self.store(self.deref(addr)); + debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar); - match addr { - Addr::Lis(l) => { - let tail = self.store(self.deref(Addr::HeapCell(l + 1))); - let tail = if tail.is_ref() { - self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h)); - self.trail(TrailRef::Ref(Ref::AttrVar(h))); + let h = addr.get_value(); + let addr = self.store(self.deref(self.heap[h + 1])); - Addr::HeapCell(h + 1) - } else { - tail - }; + debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis); - self.heap[h + 1] = HeapCellValue::Addr(tail); - self.trail(TrailRef::AttrVarListLink(h + 1, l)); - } - _ => { - unreachable!(); - } - } - } - _ => { - unreachable!(); - } - } + let l = addr.get_value(); + let tail = self.store(self.deref(heap_loc_as_cell!(l + 1))); + + let tail = if tail.is_var() { + self.heap[h] = heap_loc_as_cell!(h); + self.trail(TrailRef::Ref(Ref::attr_var(h))); + + heap_loc_as_cell!(h + 1) + } else { + tail + }; + + self.heap[h + 1] = tail; + self.trail(TrailRef::AttrVarListLink(h + 1, l)); } &SystemClauseType::DynamicModuleResolution(narity) => { - let module_name = self.store(self.deref(self[temp_v!(1 + narity)])); + let module_name = self.store(self.deref(self.registers[1 + narity])); + let module_name = cell_as_atom!(module_name); - let module_name = match module_name { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref module_name, _) = self.heap[h] { - module_name.clone() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + let addr = self.store(self.deref(self.registers[2 + narity])); - match self.store(self.deref(self[temp_v!(2 + narity)])) { - Addr::Str(a) => { - if let HeapCellValue::NamedStr(arity, name, _) = self.heap.clone(a) { - for i in (arity + 1..arity + narity + 1).rev() { - self.registers[i] = self.registers[i - arity]; - } + read_heap_cell!(addr, + (HeapCellValueTag::Str, a) => { + let (name, arity) = cell_as_atom_cell!(self.heap[a]) + .get_name_and_arity(); - for i in 1..arity + 1 { - self.registers[i] = self.heap[a + i].as_addr(a + i); - } + for i in (arity + 1..arity + narity + 1).rev() { + self.registers[i] = self.registers[i - arity]; + } - return self.module_lookup( - indices, - call_policy, - (name, arity + narity), - module_name, - true, - &indices.stream_aliases, - ); - } else { - unreachable!() + for i in 1..arity + 1 { + self.registers[i] = self.heap[a + i]; } + + return self.module_lookup( + indices, + call_policy, + (name, arity + narity), + module_name, + true, + &indices.stream_aliases, + ); } - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { - return self.module_lookup( - indices, - call_policy, - (name.clone(), narity), - module_name, - true, - &indices.stream_aliases, - ); - } else { - unreachable!() - } + (HeapCellValueTag::Atom, (name, _arity)) => { + return self.module_lookup( + indices, + call_policy, + (name, narity), + module_name, + true, + &indices.stream_aliases, + ); } - Addr::Char(c) => { + (HeapCellValueTag::Char, c) => { + let key = (self.atom_tbl.build_with(&c.to_string()), narity); + return self.module_lookup( indices, call_policy, - (clause_name!(c.to_string(), self.atom_tbl), narity), + key, module_name, true, &indices.stream_aliases, ); } - addr => { - let stub = MachineError::functor_stub(clause_name!("(:)"), 2); - - let type_error = - MachineError::type_error(self.heap.h(), ValidType::Callable, addr); + _ => { + let stub = functor_stub(atom!("(:)"), 2); + let err = self.type_error(ValidType::Callable, addr); - let type_error = self.error_form(type_error, stub); - return Err(type_error); + return Err(self.error_form(err, stub)); } - } + ); } &SystemClauseType::EnqueueAttributedVar => { - let addr = self[temp_v!(1)]; + let addr = self.store(self.deref(self.registers[1])); - match self.store(self.deref(addr)) { - Addr::AttrVar(h) => { - self.attr_var_init.attr_var_queue.push(h); - } - _ => {} - } + read_heap_cell!(addr, + (HeapCellValueTag::AttrVar, h) => { + self.attr_var_init.attr_var_queue.push(h); + } + _ => { + } + ); } &SystemClauseType::GetNextDBRef => { - let a1 = self[temp_v!(1)]; + let a1 = self.store(self.deref(self.registers[1])); - match self.store(self.deref(a1)) { - addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) - | addr @ Addr::AttrVar(_) => { - let mut iter = indices.code_dir.iter(); + if let Some(name_var) = a1.as_var() { + let mut iter = indices.code_dir.iter(); - while let Some(((name, arity), _)) = iter.next() { - if is_builtin_predicate(&name) { - continue; - } + while let Some(((name, arity), _)) = iter.next() { + if SystemClauseType::from(*name, *arity).is_some() { + continue; + } - let spec = get_clause_spec( - name.clone(), - *arity, - &CompositeOpDir::new(&indices.op_dir, None), - ); + let arity_var = self.deref(self.registers[2]) + .as_var().unwrap(); - let db_ref = DBRef::NamedPred(name.clone(), *arity, spec); - let r = addr.as_var().unwrap(); + self.bind(name_var, atom_as_cell!(name)); + self.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64))); + + return return_from_clause!(self.last_call, self); + } - let addr = self.heap.to_unifiable(HeapCellValue::DBRef(db_ref)); + self.fail = true; + } else if a1.get_tag() == HeapCellValueTag::Atom { + let name = cell_as_atom!(a1); + let arity = cell_as_fixnum!(self.store(self.deref(self.registers[2]))) + .get_num() as usize; - self.bind(r, addr); + match self.get_next_db_ref(indices, &DBRef::NamedPred(name, arity)) { + Some(DBRef::NamedPred(name, arity)) => { + let atom_var = self.deref(self.registers[3]) + .as_var().unwrap(); - return return_from_clause!(self.last_call, self); - } + let arity_var = self.deref(self.registers[4]) + .as_var().unwrap(); - self.fail = true; - } - Addr::Con(h) => match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::Op(..)) => { - self.fail = true; - } - HeapCellValue::DBRef(ref db_ref) => { - self.get_next_db_ref(indices, db_ref); + self.bind(atom_var, atom_as_cell!(name)); + self.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64))); } - _ => { + Some(DBRef::Op(..)) | None => { self.fail = true; } - }, - _ => { - self.fail = true; } + } else { + self.fail = true; + return Ok(()); } } &SystemClauseType::GetNextOpDBRef => { - let a1 = self[temp_v!(1)]; + let prec = self.store(self.deref(self.registers[1])); + + if let Some(prec_var) = prec.as_var() { + let spec = self.store(self.deref(self.registers[2])); + let op = self.store(self.deref(self.registers[3])); + let orig_op = self.store(self.deref(self.registers[7])); + + let spec_num = if spec.get_tag() == HeapCellValueTag::Atom { + (match cell_as_atom!(spec) { + atom!("xfx") => XFX, + atom!("xfy") => XFY, + atom!("yfx") => YFX, + atom!("fx") => FX, + atom!("fy") => FY, + atom!("xf") => XF, + _ => unreachable!(), + }) as u8 + } else { + 0 + }; + + let unossified_op_dir = if !orig_op.is_var() { + let orig_op = cell_as_atom!(orig_op); + + let op_descs = [ + indices.op_dir.get_key_value(&(orig_op, Fixity::In)), + indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)), + indices.op_dir.get_key_value(&(orig_op, Fixity::Post)), + ]; + + let number_of_keys = op_descs[0].is_some() as usize + + op_descs[1].is_some() as usize + + op_descs[2].is_some() as usize; + + match number_of_keys { + 0 => { + self.fail = true; + return Ok(()); + } + 1 => { + for op_desc in op_descs { + if let Some((_, op_desc)) = op_desc { + let (op_prec, op_spec) = + (op_desc.get_prec(), op_desc.get_spec()); + + let op_spec = match op_spec as u32 { + XFX => atom!("xfx"), + XFY => atom!("xfy"), + YFX => atom!("yfx"), + FX => atom!("fx"), + FY => atom!("fy"), + XF => atom!("xf"), + YF => atom!("yf"), + _ => unreachable!(), + }; + + let op_prec = Fixnum::build_with(op_prec as i64); + + self.unify_fixnum(op_prec, prec); + self.unify_atom(op_spec, spec); + } + } + + return return_from_clause!(self.last_call, self); + } + _ => { + let mut unossified_op_dir = OssifiedOpDir::new(); + + for op_desc in op_descs { + if let Some((key, op_desc)) = op_desc { + let (prec, spec) = (op_desc.get_prec(), op_desc.get_spec()); + unossified_op_dir.insert(*key, (prec as usize, spec as Specifier)); + } + } - match self.store(self.deref(a1)) { - addr @ Addr::HeapCell(_) - | addr @ Addr::StackCell(..) - | addr @ Addr::AttrVar(_) => { + unossified_op_dir + } + } + } else { let mut unossified_op_dir = OssifiedOpDir::new(); unossified_op_dir.extend(indices.op_dir.iter().filter_map( - |(key, op_dir_val)| { - let (name, fixity) = key.clone(); - - let prec = op_dir_val.shared_op_desc().prec(); + |(key, op_desc)| { + let (other_prec, other_spec) = (op_desc.get_prec(), op_desc.get_spec()); + let name = key.0; - if prec == 0 { + if other_prec == 0 { return None; } - let assoc = op_dir_val.shared_op_desc().assoc(); + if (!orig_op.is_var() && atom_as_cell!(name) != orig_op) || + (!spec.is_var() && other_spec != spec_num) { + return None; + } - Some((OrderedOpDirKey(name, fixity), (prec, assoc))) - }, + Some((*key, (other_prec as usize, other_spec as Specifier))) + } )); - let ossified_op_dir = Rc::new(unossified_op_dir); + unossified_op_dir + }; - match ossified_op_dir.iter().next() { - Some((OrderedOpDirKey(name, _), (priority, spec))) => { - let db_ref = DBRef::Op( - *priority, - *spec, - name.clone(), - ossified_op_dir.clone(), - SharedOpDesc::new(*priority, *spec), - ); + let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.arena); + + match ossified_op_dir.iter().next() { + Some(((op_atom, _), (op_prec, op_spec))) => { + let ossified_op_dir_var = self.store(self.deref(self.registers[4])) + .as_var().unwrap(); + + let spec_atom = match *op_spec { + FX => atom!("fx"), + FY => atom!("fy"), + XF => atom!("xf"), + YF => atom!("yf"), + XFX => atom!("xfx"), + XFY => atom!("xfy"), + YFX => atom!("yfx"), + _ => { + self.fail = true; + return Ok(()); + } + }; - let r = addr.as_var().unwrap(); - let addr = self.heap.to_unifiable(HeapCellValue::DBRef(db_ref)); + let spec_var = spec.as_var().unwrap(); + let op_var = op.as_var().unwrap(); - self.bind(r, addr); - } - None => { - self.fail = true; - return Ok(()); - } - } - } - Addr::Con(h) => match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::NamedPred(..)) => { - self.fail = true; + self.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64))); + self.bind(spec_var, atom_as_cell!(spec_atom)); + self.bind(op_var, atom_as_cell!(op_atom)); + self.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir)); } - HeapCellValue::DBRef(ref db_ref) => { - self.get_next_db_ref(indices, db_ref); - } - _ => { + None => { self.fail = true; + return Ok(()); } - }, - _ => { - self.fail = true; } - } - } - &SystemClauseType::LookupDBRef => { - let a1 = self[temp_v!(1)]; - - match self.store(self.deref(a1)) { - Addr::Con(h) => match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::NamedPred(name, arity, spec)) => { - let a2 = self[temp_v!(2)]; - let a3 = self[temp_v!(3)]; + } else { + let spec = cell_as_atom!(self.store(self.deref(self.registers[2]))); + let op_atom = cell_as_atom!(self.store(self.deref(self.registers[3]))); + let ossified_op_dir_cell = self.store(self.deref(self.registers[4])); - let atom = self.heap.to_unifiable(HeapCellValue::Atom(name, spec)); + if ossified_op_dir_cell.is_var() { + self.fail = true; + return Ok(()); + } - (self.unify_fn)(self, a2, atom); + let ossified_op_dir = cell_as_ossified_op_dir!( + ossified_op_dir_cell + ); - if !self.fail { - (self.unify_fn)(self, a3, Addr::Usize(arity)); - } - } + let fixity = match spec { + atom!("xfy") | atom!("yfx") | atom!("xfx") => Fixity::In, + atom!("xf") | atom!("yf") => Fixity::Post, + atom!("fx") | atom!("fy") => Fixity::Pre, _ => { self.fail = true; + return Ok(()); } - }, - _ => { - self.fail = true; - } - } - } - &SystemClauseType::LookupOpDBRef => { - let a1 = self[temp_v!(1)]; - - match self.store(self.deref(a1)) { - Addr::Con(h) => match self.heap.clone(h) { - HeapCellValue::DBRef(DBRef::Op( - priority, - spec, - name, - _, - shared_op_desc, - )) => { - let prec = self[temp_v!(2)]; - let specifier = self[temp_v!(3)]; - let op = self[temp_v!(4)]; - - let spec = match spec { - FX => "fx", - FY => "fy", - XF => "xf", - YF => "yf", - XFX => "xfx", - XFY => "xfy", - YFX => "yfx", + }; + + match self.get_next_db_ref(indices, &DBRef::Op(op_atom, fixity, ossified_op_dir)) { + Some(DBRef::Op(op_atom, fixity, ossified_op_dir)) => { + let (prec, spec) = ossified_op_dir.get(&(op_atom, fixity)).unwrap(); + + let prec_var = self.deref(self.registers[5]) + .as_var().unwrap(); + + let spec_var = self.deref(self.registers[6]) + .as_var().unwrap(); + + let op_var = self.deref(self.registers[7]) + .as_var().unwrap(); + + let spec_atom = match *spec { + FX => atom!("fx"), + FY => atom!("fy"), + XF => atom!("xf"), + YF => atom!("yf"), + XFX => atom!("xfx"), + XFY => atom!("xfy"), + YFX => atom!("yfx"), _ => { self.fail = true; return Ok(()); } }; - let a3 = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!(spec), None)); - - let a4 = self - .heap - .to_unifiable(HeapCellValue::Atom(name, Some(shared_op_desc))); - - (self.unify_fn)(self, Addr::Usize(priority), prec); - - if !self.fail { - (self.unify_fn)(self, a3, specifier); - } - - if !self.fail { - (self.unify_fn)(self, a4, op); - } + self.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64))); + self.bind(spec_var, atom_as_cell!(spec_atom)); + self.bind(op_var, atom_as_cell!(op_atom)); } - _ => { + Some(DBRef::NamedPred(..)) | None => { self.fail = true; } - }, - _ => { - self.fail = true; } } } @@ -3086,62 +2946,82 @@ impl MachineState { self.fail = result; } &SystemClauseType::CpuNow => { - let a1 = self[temp_v!(1)]; - let a2 = ProcessTime::now().as_duration().as_secs_f64(); - let addr = self.heap.put_constant(Constant::Float(OrderedFloat(a2))); + let secs = ProcessTime::now().as_duration().as_secs_f64(); + let secs = arena_alloc!(OrderedFloat(secs), &mut self.arena); - (self.unify_fn)(self, a1, addr); + self.unify_f64(secs, self.registers[1]); } &SystemClauseType::CurrentTime => { - let str = self.systemtime_to_timestamp(SystemTime::now()); - (self.unify_fn)(self, self[temp_v!(1)], str); + let timestamp = self.systemtime_to_timestamp(SystemTime::now()); + self.unify_atom(timestamp, self.registers[1]); + } + &SystemClauseType::Open => { + let alias = self.registers[4]; + let eof_action = self.registers[5]; + let reposition = self.registers[6]; + let stream_type = self.registers[7]; + + let options = self.to_stream_options(alias, eof_action, reposition, stream_type); + let src_sink = self.store(self.deref(self.registers[1])); + + if let Some(atom_or_string) = self.value_to_str_like(src_sink) { + let file_spec = self.atom_tbl.build_with(atom_or_string.as_str()); + let mut stream = self.stream_from_file_spec(file_spec, indices, &options)?; + + *stream.options_mut() = options; + indices.streams.insert(stream); + + if let Some(alias) = stream.options().get_alias() { + indices.stream_aliases.insert(alias, stream); + } + + let stream_var = self.store(self.deref(self.registers[3])); + self.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream)); + } else { + let err = self.domain_error(DomainErrorType::SourceSink, src_sink); + let stub = functor_stub(atom!("open"), 4); + + return Err(self.error_form(err, stub)); + } } &SystemClauseType::OpDeclaration => { - let priority = self[temp_v!(1)]; - let specifier = self[temp_v!(2)]; - let op = self[temp_v!(3)]; + let priority = self.registers[1]; + let specifier = self.registers[2]; + let op = self.registers[3]; let priority = self.store(self.deref(priority)); - let priority = match Number::try_from((priority, &self.heap)) { - Ok(Number::Integer(n)) => n.to_usize().unwrap(), - Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + let priority = match Number::try_from(priority) { + Ok(Number::Integer(n)) => n.to_u16().unwrap(), + Ok(Number::Fixnum(n)) => u16::try_from(n.get_num()).unwrap(), _ => { unreachable!(); } }; - let specifier = match self.store(self.deref(specifier)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref specifier, _) = &self.heap[h] { - specifier.clone() - } else { - unreachable!() - } - } - _ => unreachable!(), - }; + let specifier = cell_as_atom_cell!(self.store(self.deref(specifier))) + .get_name(); - let op = match self.store(self.deref(op)) { - Addr::Char(c) => clause_name!(c.to_string(), self.atom_tbl), - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.clone() - } else { - unreachable!() - } + let op = read_heap_cell!(self.store(self.deref(op)), + (HeapCellValueTag::Char) => { + self.atom_tbl.build_with(&op.to_string()) } - _ => unreachable!(), - }; + (HeapCellValueTag::Atom, (name, _arity)) => { + name + } + _ => { + unreachable!() + } + ); - let result = to_op_decl(priority, specifier.as_str(), op) + let result = to_op_decl(priority, specifier, op) .map_err(SessionError::from) .and_then(|mut op_decl| { - if op_decl.prec == 0 { + if op_decl.op_desc.get_prec() == 0 { Ok(op_decl.remove(&mut indices.op_dir)) } else { let spec = get_op_desc( - op_decl.name.clone(), + op_decl.name, &CompositeOpDir::new(&indices.op_dir, None), ); @@ -3153,128 +3033,96 @@ impl MachineState { Ok(()) => {} Err(e) => { // 8.14.3.3 l) - let e = MachineError::session_error(self.heap.h(), e); - let stub = MachineError::functor_stub(clause_name!("op"), 3); - let permission_error = self.error_form(e, stub); + let err = self.session_error(e); + let stub = functor_stub(atom!("op"), 3); - return Err(permission_error); + return Err(self.error_form(err, stub)); } - }; - } - &SystemClauseType::Open => { - let alias = self[temp_v!(4)]; - let eof_action = self[temp_v!(5)]; - let reposition = self[temp_v!(6)]; - let stream_type = self[temp_v!(7)]; - - let options = self.to_stream_options(alias, eof_action, reposition, stream_type); - - let mut iter = self.heap_pstr_iter(self[temp_v!(1)]); - let file_spec = clause_name!(iter.to_string(), self.atom_tbl); - - let mut stream = self.stream_from_file_spec(file_spec, indices, &options)?; - - *stream.options_mut() = options; - - indices.streams.insert(stream.clone()); - - if let Some(ref alias) = &stream.options().alias { - indices.stream_aliases.insert(alias.clone(), stream.clone()); } - - let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - let stream_var = self.store(self.deref(self[temp_v!(3)])); - - self.bind(stream_var.as_var().unwrap(), stream); } &SystemClauseType::SetStreamOptions => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "open", + atom!("open"), 4, )?; - let alias = self[temp_v!(2)]; - let eof_action = self[temp_v!(3)]; - let reposition = self[temp_v!(4)]; - let stream_type = self[temp_v!(5)]; + let alias = self.registers[2]; + let eof_action = self.registers[3]; + let reposition = self.registers[4]; + let stream_type = self.registers[5]; let options = self.to_stream_options(alias, eof_action, reposition, stream_type); *stream.options_mut() = options; } &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => { - self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h)) + self.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h)) } &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { - self.truncate_if_no_lifted_heap_diff(|_| Addr::EmptyList) + self.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!()) } &SystemClauseType::GetAttributedVariableList => { - let attr_var = self.store(self.deref(self[temp_v!(1)])); - let attr_var_list = match attr_var { - Addr::AttrVar(h) => h + 1, - attr_var @ Addr::HeapCell(_) | attr_var @ Addr::StackCell(..) => { + let attr_var = self.store(self.deref(self.registers[1])); + let attr_var_list = read_heap_cell!(attr_var, + (HeapCellValueTag::AttrVar, h) => { + h + 1 + } + (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { // create an AttrVar in the heap. - let h = self.heap.h(); + let h = self.heap.len(); - self.heap.push(HeapCellValue::Addr(Addr::AttrVar(h))); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + 1))); + self.heap.push(attr_var_as_cell!(h)); + self.heap.push(heap_loc_as_cell!(h+1)); - self.bind(Ref::AttrVar(h), attr_var); + self.bind(Ref::attr_var(h), attr_var); h + 1 } _ => { self.fail = true; return Ok(()); } - }; + ); - let list_addr = self[temp_v!(2)]; - self.bind(Ref::HeapCell(attr_var_list), list_addr); + let list_addr = self.store(self.deref(self.registers[2])); + self.bind(Ref::heap_cell(attr_var_list), list_addr); } &SystemClauseType::GetAttrVarQueueDelimiter => { - let addr = self[temp_v!(1)]; - let value = Addr::Usize(self.attr_var_init.attr_var_queue.len()); + let addr = self.registers[1]; + let value = Fixnum::build_with(self.attr_var_init.attr_var_queue.len() as i64); - (self.unify_fn)(self, addr, value); + self.unify_fixnum(value, self.store(self.deref(addr))); } &SystemClauseType::GetAttrVarQueueBeyond => { - let addr = self[temp_v!(1)]; + let addr = self.registers[1]; let addr = self.store(self.deref(addr)); - let b = match addr { - Addr::Usize(b) => Some(b), - _ => match Number::try_from((addr, &self.heap)) { - Ok(Number::Integer(n)) => n.to_usize(), - Ok(Number::Fixnum(n)) => usize::try_from(n).ok(), - _ => { - self.fail = true; - return Ok(()); - } - }, + let b = match Number::try_from(addr) { + Ok(Number::Integer(n)) => n.to_usize(), + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), + _ => { + self.fail = true; + return Ok(()); + } }; if let Some(b) = b { let iter = self.gather_attr_vars_created_since(b); - let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); - let list_addr = self[temp_v!(2)]; + let var_list_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, iter) + ); - (self.unify_fn)(self, var_list_addr, list_addr); + let list_addr = self.registers[2]; + unify!(self, var_list_addr, list_addr); } } &SystemClauseType::GetContinuationChunk => { - let e = self.store(self.deref(self[temp_v!(1)])); - - let e = if let Addr::Usize(e) = e { - e - } else { - self.fail = true; - return Ok(()); - }; + let e = self.store(self.deref(self.registers[1])); + let e = cell_as_fixnum!(e).get_num() as usize; - let p_functor = self.store(self.deref(self[temp_v!(2)])); - let p = self.heap.to_local_code_ptr(&p_functor).unwrap(); + let p_functor = self.store(self.deref(self.registers[2])); + let p = to_local_code_ptr(&self.heap, p_functor).unwrap(); let num_cells = match code_repo.lookup_instr(self.last_call, &CodePtr::Local(p)) { Some(line) => { @@ -3290,137 +3138,81 @@ impl MachineState { let mut addrs = vec![]; - for index in 1..num_cells + 1 { - addrs.push(self.stack.index_and_frame(e)[index]); + for idx in 1..num_cells + 1 { + addrs.push(self.stack[stack_loc!(AndFrame, e, idx)]); } - let chunk = Addr::HeapCell(self.heap.h()); + let chunk = str_loc_as_cell!(self.heap.len()); - self.heap.push(HeapCellValue::NamedStr( - 1 + num_cells, - clause_name!("cont_chunk"), - None, - )); - - self.heap.push(HeapCellValue::Addr(p_functor)); - self.heap.extend(addrs.into_iter().map(HeapCellValue::Addr)); + self.heap.push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); + self.heap.push(p_functor); + self.heap.extend(addrs); - (self.unify_fn)(self, self[temp_v!(3)], chunk); + unify!(self, self.registers[3], chunk); } &SystemClauseType::GetLiftedHeapFromOffsetDiff => { - let lh_offset = self[temp_v!(1)]; + let lh_offset = self.registers[1]; + let lh_offset = cell_as_fixnum!(self.store(self.deref(lh_offset))).get_num() as usize; - match self.store(self.deref(lh_offset)) { - Addr::Usize(lh_offset) => { - if lh_offset >= self.lifted_heap.h() { - let solutions = self[temp_v!(2)]; - let diff = self[temp_v!(3)]; - - (self.unify_fn)(self, solutions, diff); - } else { - let h = self.heap.h(); - let mut last_index = h; + if lh_offset >= self.lifted_heap.len() { + let solutions = self.registers[2]; + let diff = self.registers[3]; - for value in self.lifted_heap.iter_from(lh_offset) { - last_index = self.heap.h(); + unify_fn!(self, solutions, diff); + } else { + let h = self.heap.len(); + let mut last_index = h; - match value { - HeapCellValue::Addr(ref addr) => { - self.heap.push(HeapCellValue::Addr(*addr + h)); - } - value => { - self.heap.push(value.context_free_clone()); - } - } - } + for value in self.lifted_heap[lh_offset ..].iter().cloned() { + last_index = self.heap.len(); + self.heap.push(value + h); + } - if last_index < self.heap.h() { - let addr_opt = - if let HeapCellValue::Addr(ref addr) = &self.heap[last_index] { - Some(*addr) - } else { - None - }; - - addr_opt.map(|addr| { - let diff = self[temp_v!(3)]; - (self.unify_fn)(self, diff, addr); - }); - } + if last_index < self.heap.len() { + let diff = self.registers[3]; + unify_fn!(self, diff, self.heap[last_index]); + } - self.lifted_heap.truncate(lh_offset); + self.lifted_heap.truncate(lh_offset); - let solutions = self[temp_v!(2)]; - (self.unify_fn)(self, Addr::HeapCell(h), solutions); - } - } - _ => { - self.fail = true; - } + let solutions = self.registers[2]; + unify_fn!(self, heap_loc_as_cell!(h), solutions); } } &SystemClauseType::GetLiftedHeapFromOffset => { - let lh_offset = self[temp_v!(1)]; + let lh_offset = self.registers[1]; + let lh_offset = cell_as_fixnum!(self.store(self.deref(lh_offset))).get_num() as usize; - match self.store(self.deref(lh_offset)) { - Addr::Usize(lh_offset) => { - if lh_offset >= self.lifted_heap.h() { - let solutions = self[temp_v!(2)]; - (self.unify_fn)(self, solutions, Addr::EmptyList); - } else { - let h = self.heap.h(); + if lh_offset >= self.lifted_heap.len() { + let solutions = self.registers[2]; + unify_fn!(self, solutions, empty_list_as_cell!()); + } else { + let h = self.heap.len(); - for addr in self.lifted_heap.iter_from(lh_offset) { - match addr { - HeapCellValue::Addr(ref addr) => { - self.heap.push(HeapCellValue::Addr(*addr + h)); - } - value => { - self.heap.push(value.context_free_clone()); - } - } - } + for addr in self.lifted_heap[lh_offset..].iter().cloned() { + self.heap.push(addr + h); + } - self.lifted_heap.truncate(lh_offset); + self.lifted_heap.truncate(lh_offset); - let solutions = self[temp_v!(2)]; - (self.unify_fn)(self, Addr::HeapCell(h), solutions); - } - } - _ => { - self.fail = true; - } + let solutions = self.registers[2]; + unify_fn!(self, heap_loc_as_cell!(h), solutions); } } &SystemClauseType::GetDoubleQuotes => { - let a1 = self[temp_v!(1)]; - - match self.flags.double_quotes { - DoubleQuotes::Chars => { - let atom = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("chars"), None)); + let a1 = self.store(self.deref(self.registers[1])); - (self.unify_fn)(self, a1, atom); - } - DoubleQuotes::Atom => { - let atom = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("atom"), None)); - - (self.unify_fn)(self, a1, atom); - } - DoubleQuotes::Codes => { - let atom = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("codes"), None)); - - (self.unify_fn)(self, a1, atom); - } - } + self.unify_atom( + match self.flags.double_quotes { + DoubleQuotes::Chars => atom!("chars"), + DoubleQuotes::Atom => atom!("atom"), + DoubleQuotes::Codes => atom!("codes"), + }, + a1, + ); } &SystemClauseType::GetSCCCleaner => { - let dest = self[temp_v!(1)]; + let dest = self.registers[1]; match cut_policy.downcast_mut::().ok() { Some(sgc_policy) => { @@ -3440,15 +3232,15 @@ impl MachineState { } } None => {} - }; + } self.fail = true; } &SystemClauseType::Halt => { - let code = self.store(self.deref(self[temp_v!(1)])); + let code = self.store(self.deref(self.registers[1])); - let code = match Number::try_from((code, &self.heap)) { - Ok(Number::Fixnum(n)) => n as i32, + let code = match Number::try_from(code) { + Ok(Number::Fixnum(n)) => i32::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => n.to_i32().unwrap(), Ok(Number::Rational(r)) => { // n has already been confirmed as an integer, and @@ -3464,7 +3256,7 @@ impl MachineState { std::process::exit(code); } &SystemClauseType::InstallSCCCleaner => { - let addr = self[temp_v!(1)]; + let addr = self.registers[1]; let b = self.b; let prev_block = self.block; @@ -3475,7 +3267,7 @@ impl MachineState { match cut_policy.downcast_mut::().ok() { Some(cut_policy) => { - self.install_new_block(temp_v!(2)); + self.install_new_block(self.registers[2]); cut_policy.push_cont_pt(addr, b, prev_block); } None => panic!( @@ -3486,155 +3278,111 @@ impl MachineState { } &SystemClauseType::InstallInferenceCounter => { // A1 = B, A2 = L - let a1 = self.store(self.deref(self[temp_v!(1)])); - let a2 = self.store(self.deref(self[temp_v!(2)])); + let a1 = self.store(self.deref(self.registers[1])); + let a2 = self.store(self.deref(self.registers[2])); if call_policy.downcast_ref::().is_err() { CWILCallPolicy::new_in_place(call_policy); } - let n = match Number::try_from((a2, &self.heap)) { - Ok(Number::Integer(n)) => Integer::from(&*n.clone()), - Ok(Number::Fixnum(n)) => Integer::from(n), + let n = match Number::try_from(a2) { + Ok(Number::Fixnum(bp)) => bp.get_num() as usize, + Ok(Number::Integer(n)) => n.to_usize().unwrap(), _ => { - let stub = MachineError::functor_stub( - clause_name!("call_with_inference_limit"), + let stub = functor_stub( + atom!("call_with_inference_limit"), 3, ); - return Err(self.error_form( - MachineError::type_error(self.heap.h(), ValidType::Integer, a2), - stub, - )); + let err = self.type_error(ValidType::Integer, a2); + return Err(self.error_form(err, stub)); } }; - match a1 { - Addr::Usize(bp) | Addr::CutPoint(bp) => { - match call_policy.downcast_mut::().ok() { - Some(call_policy) => { - let count = call_policy.add_limit(n, bp).clone(); - let count = self - .heap - .to_unifiable(HeapCellValue::Integer(Rc::new(count))); - - let a3 = self[temp_v!(3)]; - (self.unify_fn)(self, a3, count); - } - None => { - panic!( - "install_inference_counter: should have installed \\ - CWILCallPolicy." - ) - } - } + let bp = cell_as_fixnum!(a1).get_num() as usize; + + match call_policy.downcast_mut::().ok() { + Some(call_policy) => { + let count = call_policy.add_limit(n, bp); + let count = arena_alloc!(count.clone(), &mut self.arena); + + let a3 = self.store(self.deref(self.registers[3])); + self.unify_big_int(count, a3); } - _ => { - unreachable!(); + None => { + panic!( + "install_inference_counter: should have installed \\ + CWILCallPolicy." + ) } } } &SystemClauseType::ModuleExists => { - let module = self.store(self.deref(self[temp_v!(1)])); + let module = self.store(self.deref(self.registers[1])); + let module_name = cell_as_atom!(module); - match module { - Addr::Con(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - self.fail = !indices.modules.contains_key(name); - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + self.fail = !indices.modules.contains_key(&module_name); } &SystemClauseType::NoSuchPredicate => { - let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); - - self.fail = match self.store(self.deref(self[temp_v!(2)])) { - Addr::Str(s) => match &self.heap[s] { - &HeapCellValue::NamedStr(arity, ref name, ref spec) => { - if CLAUSE_TYPE_FORMS - .borrow() - .get(&(name.as_str(), arity)) - .is_some() - { - true - } else { - let index = indices - .get_predicate_code_index( - name.clone(), - arity, - module_name, - spec.clone(), - ) - .map(|index| index.get()) - .unwrap_or(IndexPtr::DynamicUndefined); - - match index { - IndexPtr::DynamicUndefined => false, - _ => true, - } - } - } - _ => { - unreachable!() - } - }, - Addr::Con(h) if self.heap.atom_at(h) => { - if let &HeapCellValue::Atom(ref name, ref spec) = &self.heap[h] { - let spec = - fetch_atom_op_spec(name.clone(), spec.clone(), &indices.op_dir); - - if CLAUSE_TYPE_FORMS - .borrow() - .get(&(name.as_str(), 0)) - .is_some() - { - true - } else { - let index = indices - .get_predicate_code_index( - name.clone(), - 0, - module_name, - spec.clone(), - ) - .map(|index| index.get()) - .unwrap_or(IndexPtr::DynamicUndefined); - - match index { - IndexPtr::DynamicUndefined => false, - _ => true, - } + let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let head = self.store(self.deref(self.registers[2])); + + self.fail = read_heap_cell!(head, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); + + if clause_type_form(name, arity).is_some() { + true + } else { + let index = indices.get_predicate_code_index( + name, + arity, + module_name, + ) + .map(|index| index.get()) + .unwrap_or(IndexPtr::DynamicUndefined); + + match index { + IndexPtr::DynamicUndefined => false, + _ => true, } + } + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + if clause_type_form(name, 0).is_some() { + true } else { - unreachable!() + let index = indices.get_predicate_code_index( + name, + 0, + module_name, + ) + .map(|index| index.get()) + .unwrap_or(IndexPtr::DynamicUndefined); + + match index { + IndexPtr::DynamicUndefined => false, + _ => true, + } } } - head => { - let err = - MachineError::type_error(self.heap.h(), ValidType::Callable, head); - let stub = MachineError::functor_stub(clause_name!("clause"), 2); + _ => { + let err = self.type_error(ValidType::Callable, head); + let stub = functor_stub(atom!("clause"), 2); return Err(self.error_form(err, stub)); } - }; + ); } &SystemClauseType::RedoAttrVarBinding => { - let var = self.store(self.deref(self[temp_v!(1)])); - let value = self.store(self.deref(self[temp_v!(2)])); + let var = self.store(self.deref(self.registers[1])); + let value = self.store(self.deref(self.registers[2])); - match var { - Addr::AttrVar(h) => { - self.heap[h] = HeapCellValue::Addr(value); - } - _ => { - unreachable!() - } - } + debug_assert_eq!(HeapCellValueTag::AttrVar, var.get_tag()); + self.heap[var.get_value()] = value; } &SystemClauseType::ResetAttrVarState => { self.attr_var_init.reset(); @@ -3642,19 +3390,13 @@ impl MachineState { &SystemClauseType::RemoveCallPolicyCheck => { let restore_default = match call_policy.downcast_mut::().ok() { Some(call_policy) => { - let a1 = self.store(self.deref(self[temp_v!(1)])); + let a1 = self.store(self.deref(self.registers[1])); + let bp = cell_as_fixnum!(a1).get_num() as usize; - match a1 { - Addr::Usize(bp) | Addr::CutPoint(bp) => { - if call_policy.is_empty() && bp == self.b { - Some(call_policy.into_inner()) - } else { - None - } - } - _ => { - panic!("remove_call_policy_check: expected Usize in A1."); - } + if call_policy.is_empty() && bp == self.b { + Some(call_policy.into_inner()) + } else { + None } } None => panic!( @@ -3670,23 +3412,15 @@ impl MachineState { &SystemClauseType::RemoveInferenceCounter => { match call_policy.downcast_mut::().ok() { Some(call_policy) => { - let a1 = self.store(self.deref(self[temp_v!(1)])); + let a1 = self.store(self.deref(self.registers[1])); + let bp = cell_as_fixnum!(a1).get_num() as usize; - match a1 { - Addr::Usize(bp) | Addr::CutPoint(bp) => { - let count = call_policy.remove_limit(bp).clone(); - let count = self - .heap - .to_unifiable(HeapCellValue::Integer(Rc::new(count))); + let count = call_policy.remove_limit(bp).clone(); + let count = arena_alloc!(count.clone(), &mut self.arena); - let a2 = self[temp_v!(2)]; + let a2 = self.store(self.deref(self.registers[2])); - (self.unify_fn)(self, a2, count); - } - _ => { - panic!("remove_inference_counter: expected Usize in A1."); - } - } + self.unify_big_int(count, a2); } None => panic!( "remove_inference_counter: requires \\ @@ -3702,16 +3436,14 @@ impl MachineState { let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells; for i in 1..frame_len - 1 { - self[RegType::Temp(i)] = self.stack.index_and_frame(e)[i]; + self.registers[i] = self.stack[stack_loc!(AndFrame, e, i)]; } - if let &Addr::CutPoint(b0) = &self.stack.index_and_frame(e)[frame_len - 1] { - self.b0 = b0; - } + self.b0 = cell_as_fixnum!(self.stack[stack_loc!(AndFrame, e, frame_len - 1)]) + .get_num() as usize; - if let &Addr::Usize(num_of_args) = &self.stack.index_and_frame(e)[frame_len] { - self.num_of_args = num_of_args; - } + self.num_of_args = cell_as_fixnum!(self.stack[stack_loc!(AndFrame, e, frame_len)]) + .get_num() as usize; self.deallocate(); self.p = CodePtr::Local(self.stack.index_and_frame(e).prelude.interrupt_cp); @@ -3737,21 +3469,18 @@ impl MachineState { } &SystemClauseType::SetCutPointByDefault(r) => deref_cut(self, r), &SystemClauseType::SetInput => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); let stream = - self.get_stream_or_alias(addr, &indices.stream_aliases, "set_input", 1)?; + self.get_stream_or_alias(addr, &indices.stream_aliases, atom!("set_input"), 1)?; if !stream.is_input_stream() { - let stub = MachineError::functor_stub(clause_name!("set_input"), 1); + let stub = functor_stub(atom!("set_input"), 1); - let user_alias = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("user"), None)); + let user_alias = atom_as_cell!(atom!("user")); - let err = MachineError::permission_error( - self.heap.h(), + let err = self.permission_error( Permission::InputStream, - "stream", + atom!("stream"), user_alias, ); @@ -3761,21 +3490,17 @@ impl MachineState { *current_input_stream = stream; } &SystemClauseType::SetOutput => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); let stream = - self.get_stream_or_alias(addr, &indices.stream_aliases, "set_output", 1)?; + self.get_stream_or_alias(addr, &indices.stream_aliases, atom!("set_output"), 1)?; if !stream.is_output_stream() { - let stub = MachineError::functor_stub(clause_name!("set_input"), 1); - - let user_alias = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("user"), None)); + let stub = functor_stub(atom!("set_input"), 1); - let err = MachineError::permission_error( - self.heap.h(), + let user_alias = atom_as_cell!(atom!("user")); + let err = self.permission_error( Permission::OutputStream, - "stream", + atom!("stream"), user_alias, ); @@ -3784,68 +3509,41 @@ impl MachineState { *current_output_stream = stream; } - &SystemClauseType::SetDoubleQuotes => match self[temp_v!(1)] { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - self.flags.double_quotes = match atom.as_str() { - "atom" => DoubleQuotes::Atom, - "chars" => DoubleQuotes::Chars, - "codes" => DoubleQuotes::Codes, - _ => { - self.fail = true; - return Ok(()); - } - }; - } else { - unreachable!() - } - } - _ => { - self.fail = true; - } - }, - &SystemClauseType::InferenceLevel => { - let a1 = self[temp_v!(1)]; - let a2 = self.store(self.deref(self[temp_v!(2)])); - - match a2 { - Addr::CutPoint(bp) | Addr::Usize(bp) => { - let prev_b = self.stack.index_or_frame(self.b).prelude.b; - - if prev_b <= bp { - let a2 = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("!"), None)); + &SystemClauseType::SetDoubleQuotes => { + let atom = cell_as_atom!(self.registers[1]); - (self.unify_fn)(self, a1, a2); - } else { - let a2 = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("true"), None)); - - (self.unify_fn)(self, a1, a2); - } - } + self.flags.double_quotes = match atom { + atom!("atom") => DoubleQuotes::Atom, + atom!("chars") => DoubleQuotes::Chars, + atom!("codes") => DoubleQuotes::Codes, _ => { self.fail = true; + return Ok(()); } + }; + } + &SystemClauseType::InferenceLevel => { + let a1 = self.registers[1]; + let a2 = self.store(self.deref(self.registers[2])); + + let bp = cell_as_fixnum!(a2).get_num() as usize; + let prev_b = self.stack.index_or_frame(self.b).prelude.b; + + if prev_b <= bp { + self.unify_atom(atom!("!"), a1) + } else { + self.unify_atom(atom!("true"), a1); } } &SystemClauseType::CleanUpBlock => { - let nb = self.store(self.deref(self[temp_v!(1)])); + let nb = self.store(self.deref(self.registers[1])); + let nb = cell_as_fixnum!(nb).get_num() as usize; - match nb { - Addr::Usize(nb) => { - let b = self.b; + let b = self.b; - if nb > 0 && self.stack.index_or_frame(b).prelude.b == nb { - self.b = self.stack.index_or_frame(nb).prelude.b; - } - } - _ => { - self.fail = true; - } - }; + if nb > 0 && self.stack.index_or_frame(b).prelude.b == nb { + self.b = self.stack.index_or_frame(nb).prelude.b; + } } &SystemClauseType::EraseBall => { self.ball.reset(); @@ -3854,10 +3552,10 @@ impl MachineState { self.fail = true; } &SystemClauseType::GetBall => { - let addr = self.store(self.deref(self[temp_v!(1)])); - let h = self.heap.h(); + let addr = self.store(self.deref(self.registers[1])); + let h = self.heap.len(); - if self.ball.stub.h() > 0 { + if self.ball.stub.len() > 0 { let stub = self.ball.copy_and_align(h); self.heap.extend(stub.into_iter()); } else { @@ -3865,96 +3563,87 @@ impl MachineState { return Ok(()); } - let ball = self.heap[h].as_addr(h); - match addr.as_var() { - Some(r) => self.bind(r, ball), + Some(r) => self.bind(r, self.heap[h]), _ => self.fail = true, }; } &SystemClauseType::GetCurrentBlock => { - let c = Constant::Usize(self.block); - let addr = self[temp_v!(1)]; - - self.write_constant_to_var(addr, &c); + let n = Fixnum::build_with(i64::try_from(self.block).unwrap()); + self.unify_fixnum(n, self.registers[1]); } &SystemClauseType::GetBValue => { - let a1 = self[temp_v!(1)]; - let a2 = Addr::Usize(self.b); - - (self.unify_fn)(self, a1, a2); + let n = Fixnum::build_with(i64::try_from(self.b).unwrap()); + self.unify_fixnum(n, self.registers[1]); } &SystemClauseType::GetCutPoint => { - let a1 = self[temp_v!(1)]; - let a2 = Addr::CutPoint(self.b0); - - (self.unify_fn)(self, a1, a2); + let n = Fixnum::build_with(i64::try_from(self.b0).unwrap()); + self.unify_fixnum(n, self.registers[1]); } &SystemClauseType::InstallNewBlock => { - self.install_new_block(temp_v!(1)); + self.install_new_block(self.registers[1]); } &SystemClauseType::NextEP => { - let first_arg = self.store(self.deref(self[temp_v!(1)])); + let first_arg = self.store(self.deref(self.registers[1])); - match first_arg { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = self.heap.clone(h) { - if name.as_str() == "first" { - if self.e == 0 { - self.fail = true; - return Ok(()); - } + read_heap_cell!(first_arg, + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(name, atom!("first")); + debug_assert_eq!(arity, 0); + + if self.e == 0 { + self.fail = true; + return Ok(()); + } - let cp = - (self.stack.index_and_frame(self.e).prelude.cp - 1).unwrap(); + let and_frame = self.stack.index_and_frame(self.e); + let cp = (and_frame.prelude.cp - 1).unwrap(); - let e = self.stack.index_and_frame(self.e).prelude.e; - let e = Addr::Usize(e); + let e = and_frame.prelude.e; + let e = Fixnum::build_with(i64::try_from(e).unwrap()); - let p = cp.as_functor(&mut self.heap); + let p = str_loc_as_cell!(self.heap.len()); - (self.unify_fn)(self, self[temp_v!(2)], e); + self.heap.extend(cp.as_functor()); + self.unify_fixnum(e, self.registers[2]); - if !self.fail { - (self.unify_fn)(self, self[temp_v!(3)], p); - } - } else { - unreachable!() - } - } else { - unreachable!() + if !self.fail { + unify!(self, p, self.registers[3]); } } - Addr::Usize(e) => { + (HeapCellValueTag::Fixnum, n) => { + let e = n.get_num() as usize; + if e == 0 { self.fail = true; return Ok(()); } - // get the call site so that the number of active permanent variables can be read - // from it later. - let cp = (self.stack.index_and_frame(e).prelude.cp - 1).unwrap(); + // get the call site so that the number of + // active permanent variables can be read from + // it later. + let and_frame = self.stack.index_and_frame(e); + let cp = (and_frame.prelude.cp - 1).unwrap(); - let p = cp.as_functor(&mut self.heap); - let e = self.stack.index_and_frame(e).prelude.e; + let p = str_loc_as_cell!(self.heap.len()); + self.heap.extend(cp.as_functor()); - let e = Addr::Usize(e); - - (self.unify_fn)(self, self[temp_v!(2)], e); + let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap()); + self.unify_fixnum(e, self.registers[2]); if !self.fail { - (self.unify_fn)(self, self[temp_v!(3)], p); + unify!(self, p, self.registers[3]); } } _ => { - unreachable!() + unreachable!(); } - } + ); } &SystemClauseType::PointsToContinuationResetMarker => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); - let p = match self.heap.to_local_code_ptr(&addr) { + let p = match to_local_code_ptr(&self.heap, addr) { Some(p) => p + 1, None => { self.fail = true; @@ -3970,11 +3659,11 @@ impl MachineState { return Ok(()); } &SystemClauseType::QuotedToken => { - let addr = self.store(self.deref(self[temp_v!(1)])); + let addr = self.store(self.deref(self.registers[1])); - match addr { - Addr::Fixnum(n) => { - let n = u32::try_from(n).ok(); + read_heap_cell!(addr, + (HeapCellValueTag::Fixnum, n) => { + let n = u32::try_from(n.get_num()).ok(); let n = n.and_then(std::char::from_u32); self.fail = match n { @@ -3982,111 +3671,96 @@ impl MachineState { None => true, }; } - Addr::Char(c) => { + (HeapCellValueTag::Char, c) => { self.fail = non_quoted_token(once(c)); } - Addr::Con(h) => { - if let HeapCellValue::Atom(atom, _) = &self.heap[h] { - self.fail = non_quoted_token(atom.as_str().chars()); - } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + self.fail = non_quoted_token(name.as_str().chars()); } _ => { self.fail = true; } - } + ); } &SystemClauseType::ReadQueryTerm => { current_input_stream.reset(); - readline::set_prompt(true); - let result = self.read_term(current_input_stream.clone(), indices); - readline::set_prompt(false); + set_prompt(true); + let result = self.read_term(*current_input_stream, indices); + set_prompt(false); match result { Ok(()) => {} Err(e) => { - *current_input_stream = readline::input_stream(); + *current_input_stream = input_stream(&mut self.arena); return Err(e); } } } &SystemClauseType::ReadTerm => { - readline::set_prompt(false); + set_prompt(false); let stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "read_term", + atom!("read_term"), 3, )?; self.read_term(stream, indices)?; } &SystemClauseType::ReadTermFromChars => { - let mut heap_pstr_iter = self.heap_pstr_iter(self[temp_v!(1)]); - let chars = heap_pstr_iter.to_string(); - - if let Addr::EmptyList = heap_pstr_iter.focus() { - let term_write_result = match self.read( - Stream::from(chars), - self.atom_tbl.clone(), - &indices.op_dir, - ) { + if let Some(atom_or_string) = self.value_to_str_like(self.registers[1]) { + let chars = atom_or_string.to_string(); + let stream = Stream::from_owned_string(chars, &mut self.arena); + + let term_write_result = match self.read(stream, &indices.op_dir) { Ok(term_write_result) => term_write_result, Err(e) => { - let stub = - MachineError::functor_stub(clause_name!("read_term_from_chars"), 2); - - let h = self.heap.h(); - let e = MachineError::session_error(h, SessionError::from(e)); + let stub = functor_stub(atom!("read_term_from_chars"), 2); + let e = self.session_error(SessionError::from(e)); return Err(self.error_form(e, stub)); } }; - let result = Addr::HeapCell(term_write_result.heap_loc); + let result = heap_loc_as_cell!(term_write_result.heap_loc); + let var = self.store(self.deref(self.registers[2])).as_var().unwrap(); - if let Some(var) = self.store(self.deref(self[temp_v!(2)])).as_var() { - self.bind(var, result); - } else { - unreachable!() - } + self.bind(var, result); } else { unreachable!() } } &SystemClauseType::ResetBlock => { - let addr = self.deref(self[temp_v!(1)]); + let addr = self.deref(self.registers[1]); self.reset_block(addr); } &SystemClauseType::ResetContinuationMarker => { - self[temp_v!(3)] = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("none"), None)); + self.registers[3] = atom_as_cell!(atom!("none")); - let h = self.heap.h(); + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); - self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); - self[temp_v!(4)] = Addr::HeapCell(h); + self.registers[4] = heap_loc_as_cell!(h); } &SystemClauseType::SetBall => { self.set_ball(); } &SystemClauseType::SetSeed => { - let seed = self.store(self.deref(self[temp_v!(1)])); + let seed = self.store(self.deref(self.registers[1])); + let mut rand = RANDOM_STATE.borrow_mut(); - let seed = match Number::try_from((seed, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n), - Ok(Number::Integer(n)) => Integer::from(n.as_ref()), - Ok(Number::Rational(n)) if n.denom() == &1 => n.numer().clone(), + match Number::try_from(seed) { + Ok(Number::Fixnum(n)) => rand.seed(&Integer::from(n)), + Ok(Number::Integer(n)) => rand.seed(&*n), + Ok(Number::Rational(n)) if n.denom() == &1 => rand.seed(n.numer()), _ => { self.fail = true; return Ok(()); } - }; - - let mut rand = RANDOM_STATE.borrow_mut(); - rand.seed(&seed); + } } &SystemClauseType::SkipMaxList => { if let Err(err) = self.skip_max_list() { @@ -4094,11 +3768,11 @@ impl MachineState { } } &SystemClauseType::Sleep => { - let time = self.store(self.deref(self[temp_v!(1)])); + let time = self.store(self.deref(self.registers[1])); - let time = match Number::try_from((time, &self.heap)) { - Ok(Number::Float(OrderedFloat(n))) => n, - Ok(Number::Fixnum(n)) => n as f64, + let time = match Number::try_from(time) { + Ok(Number::Float(n)) => n.into_inner(), + Ok(Number::Fixnum(n)) => n.get_num() as f64, Ok(Number::Integer(n)) => n.to_f64(), _ => { unreachable!() @@ -4107,96 +3781,78 @@ impl MachineState { let duration = Duration::new(1, 0); let duration = duration.mul_f64(time); - ::std::thread::sleep(duration); + + std::thread::sleep(duration); } &SystemClauseType::SocketClientOpen => { - let addr = self.store(self.deref(self[temp_v!(1)])); - let port = self.store(self.deref(self[temp_v!(2)])); + let addr = self.store(self.deref(self.registers[1])); + let port = self.store(self.deref(self.registers[2])); - let socket_atom = match addr { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { - name.clone() - } else { - unreachable!() - } + let socket_atom = cell_as_atom!(addr); + + let _port = read_heap_cell!(port, + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + name } _ => { - unreachable!() + self.atom_tbl.build_with(&match Number::try_from(port) { + Ok(Number::Fixnum(n)) => n.get_num().to_string(), + Ok(Number::Integer(n)) => n.to_string(), + _ => { + unreachable!() + } + }) } - }; + ); - let port = match port { - Addr::Fixnum(n) => n.to_string(), - Addr::Usize(n) => n.to_string(), - Addr::Con(h) => match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => name.as_str().to_string(), - HeapCellValue::Integer(ref n) => n.to_string(), - _ => { - unreachable!() - } - }, - _ => { - unreachable!() - } + let socket_addr = if socket_atom == atom!("") { + atom!("127.0.0.1") + } else { + socket_atom }; - let socket_addr = format!( - "{}:{}", - if socket_atom.as_str() == "" { - "127.0.0.1" - } else { - socket_atom.as_str() - }, - port, - ); - - let alias = self[temp_v!(4)]; - let eof_action = self[temp_v!(5)]; - let reposition = self[temp_v!(6)]; - let stream_type = self[temp_v!(7)]; + let alias = self.registers[4]; + let eof_action = self.registers[5]; + let reposition = self.registers[6]; + let stream_type = self.registers[7]; let options = self.to_stream_options(alias, eof_action, reposition, stream_type); - if options.reposition { - return Err(self.reposition_error("socket_client_open", 3)); + if options.reposition() { + return Err(self.reposition_error(atom!("socket_client_open"), 3)); } - if let Some(ref alias) = &options.alias { - if indices.stream_aliases.contains_key(alias) { + if let Some(alias) = options.get_alias() { + if indices.stream_aliases.contains_key(&alias) { return Err(self.occupied_alias_permission_error( - alias.clone(), - "socket_client_open", + alias, + atom!("socket_client_open"), 3, )); } } - let stream = match TcpStream::connect(&socket_addr).map_err(|e| e.kind()) { + let stream = match TcpStream::connect(socket_addr.as_str()).map_err(|e| e.kind()) { Ok(tcp_stream) => { - let socket_addr = clause_name!(socket_addr, self.atom_tbl); - - let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream); + let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream, &mut self.arena); *stream.options_mut() = options; - if let Some(ref alias) = &stream.options().alias { - indices.stream_aliases.insert(alias.clone(), stream.clone()); + if let Some(alias) = stream.options().get_alias() { + indices.stream_aliases.insert(alias, stream); } - indices.streams.insert(stream.clone()); + indices.streams.insert(stream); - self.heap.to_unifiable(HeapCellValue::Stream(stream)) + stream_as_cell!(stream) } Err(ErrorKind::PermissionDenied) => { - return Err(self.open_permission_error(addr, "socket_client_open", 3)); + return Err(self.open_permission_error(addr, atom!("socket_client_open"), 3)); } Err(ErrorKind::NotFound) => { - let stub = - MachineError::functor_stub(clause_name!("socket_client_open"), 3); - - let err = MachineError::existence_error( - self.heap.h(), + let stub = functor_stub(atom!("socket_client_open"), 3); + let err = self.existence_error( ExistenceError::SourceSink(addr), ); @@ -4209,45 +3865,39 @@ impl MachineState { } }; - let stream_addr = self.store(self.deref(self[temp_v!(3)])); + let stream_addr = self.store(self.deref(self.registers[3])); self.bind(stream_addr.as_var().unwrap(), stream); } &SystemClauseType::SocketServerOpen => { - let addr = self.store(self.deref(self[temp_v!(1)])); - let socket_atom = match addr { - Addr::EmptyList => "127.0.0.1".to_string(), - Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => name.as_str().to_string(), - _ => { - unreachable!() - } - }, - _ => { - unreachable!() - } + let addr = self.store(self.deref(self.registers[1])); + let socket_atom = cell_as_atom_cell!(addr).get_name(); + + let socket_atom = if socket_atom == atom!("[]") { + atom!("127.0.0.1") + } else { + socket_atom }; - let port = match self.store(self.deref(self[temp_v!(2)])) { - Addr::Fixnum(n) => n.to_string(), - Addr::Usize(n) => n.to_string(), - Addr::Con(h) => match &self.heap[h] { - HeapCellValue::Integer(ref n) => n.to_string(), + let port = self.store(self.deref(self.registers[2])); + + let port = if port.is_var() { + String::from("0") + } else { + match Number::try_from(port) { + Ok(Number::Fixnum(n)) => n.get_num().to_string(), + Ok(Number::Integer(n)) => n.to_string(), _ => { unreachable!() } - }, - addr if addr.is_ref() => "0".to_string(), - _ => { - unreachable!() } }; let had_zero_port = &port == "0"; - let server_addr = if socket_atom.is_empty() { + let server_addr = if socket_atom == atom!("") { port } else { - format!("{}:{}", socket_atom, port) + format!("{}:{}", socket_atom.as_str(), port) }; let (tcp_listener, port) = @@ -4256,18 +3906,14 @@ impl MachineState { let port = tcp_listener.local_addr().map(|addr| addr.port()).ok(); if let Some(port) = port { - ( - self.heap - .to_unifiable(HeapCellValue::TcpListener(tcp_listener)), - port as usize, - ) + (arena_alloc!(tcp_listener, &mut self.arena), port as usize) } else { self.fail = true; return Ok(()); } } Err(ErrorKind::PermissionDenied) => { - return Err(self.open_permission_error(addr, "socket_server_open", 2)); + return Err(self.open_permission_error(addr, atom!("socket_server_open"), 2)); } _ => { self.fail = true; @@ -4275,334 +3921,313 @@ impl MachineState { } }; - let addr = self.store(self.deref(self[temp_v!(3)])); - self.bind(addr.as_var().unwrap(), tcp_listener); + let addr = self.store(self.deref(self.registers[3])); + self.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener)); if had_zero_port { - (self.unify_fn)(self, self[temp_v!(2)], Addr::Usize(port)); + self.unify_fixnum(Fixnum::build_with(port as i64), self.registers[2]); } } &SystemClauseType::SocketServerAccept => { - let alias = self[temp_v!(4)]; - let eof_action = self[temp_v!(5)]; - let reposition = self[temp_v!(6)]; - let stream_type = self[temp_v!(7)]; + let alias = self.registers[4]; + let eof_action = self.registers[5]; + let reposition = self.registers[6]; + let stream_type = self.registers[7]; let options = self.to_stream_options(alias, eof_action, reposition, stream_type); - if options.reposition { - return Err(self.reposition_error("socket_server_accept", 4)); + if options.reposition() { + return Err(self.reposition_error(atom!("socket_server_accept"), 4)); } - if let Some(ref alias) = &options.alias { - if indices.stream_aliases.contains_key(alias) { + if let Some(alias) = options.get_alias() { + if indices.stream_aliases.contains_key(&alias) { return Err(self.occupied_alias_permission_error( - alias.clone(), - "socket_server_accept", + alias, + atom!("socket_server_accept"), 4, )); } } - match self.store(self.deref(self[temp_v!(1)])) { - Addr::TcpListener(h) => match &mut self.heap[h] { - HeapCellValue::TcpListener(ref mut tcp_listener) => { - match tcp_listener.accept().ok() { - Some((tcp_stream, socket_addr)) => { - let client = - clause_name!(format!("{}", socket_addr), self.atom_tbl); + let culprit = self.store(self.deref(self.registers[1])); - let mut tcp_stream = - Stream::from_tcp_stream(client.clone(), tcp_stream); + read_heap_cell!(culprit, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::TcpListener, tcp_listener) => { + match tcp_listener.accept().ok() { + Some((tcp_stream, socket_addr)) => { + let client = self.atom_tbl.build_with(&socket_addr.to_string()); - *tcp_stream.options_mut() = options; + let mut tcp_stream = Stream::from_tcp_stream( + client, + tcp_stream, + &mut self.arena, + ); - if let Some(ref alias) = &tcp_stream.options().alias { - indices - .stream_aliases - .insert(alias.clone(), tcp_stream.clone()); - } + *tcp_stream.options_mut() = options; - indices.streams.insert(tcp_stream.clone()); + if let Some(alias) = &tcp_stream.options().get_alias() { + indices.stream_aliases.insert(*alias, tcp_stream); + } - let tcp_stream = - self.heap.to_unifiable(HeapCellValue::Stream(tcp_stream)); + indices.streams.insert(tcp_stream); - let client = - self.heap.to_unifiable(HeapCellValue::Atom(client, None)); + let tcp_stream = stream_as_cell!(tcp_stream); + let client = atom_as_cell!(client); - let client_addr = self.store(self.deref(self[temp_v!(2)])); - let stream_addr = self.store(self.deref(self[temp_v!(3)])); + let client_addr = self.store(self.deref(self.registers[2])); + let stream_addr = self.store(self.deref(self.registers[3])); - self.bind(client_addr.as_var().unwrap(), client); - self.bind(stream_addr.as_var().unwrap(), tcp_stream); - } - None => { - self.fail = true; - return Ok(()); - } - } - } - culprit => { - let culprit = culprit.as_addr(h); - - return Err(self.type_error( - ValidType::TcpListener, - culprit, - clause_name!("socket_server_accept"), - 4, - )); - } - }, - culprit => { - return Err(self.type_error( - ValidType::TcpListener, - culprit, - clause_name!("socket_server_accept"), - 4, - )); + self.bind(client_addr.as_var().unwrap(), client); + self.bind(stream_addr.as_var().unwrap(), tcp_stream); + + return return_from_clause!(self.last_call, self); + } + None => { + self.fail = true; + return Ok(()); + } + } + } + _ => { + } + ); } - } - } - &SystemClauseType::SocketServerClose => { - match self.store(self.deref(self[temp_v!(1)])) { - Addr::TcpListener(h) => { - let closed_tcp_listener = clause_name!("$closed_tcp_listener"); - self.heap[h] = HeapCellValue::Atom(closed_tcp_listener, None); - } - culprit => { - return Err(self.type_error( - ValidType::TcpListener, - culprit, - clause_name!("socket_server_close"), - 1, - )); + _ => { } - } + ); } &SystemClauseType::TLSClientConnect => { - let hostname = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - - let stream0 = self.get_stream_or_alias( - self[temp_v!(2)], - &indices.stream_aliases, - "tls_client_negotiate", - 3, - )?; - - let connector = TlsConnector::new().unwrap(); - let stream = - match connector.connect(&hostname, stream0) { - Ok(tls_stream) => tls_stream, - Err(_) => { - return Err(self.open_permission_error( - self[temp_v!(1)], - "tls_client_negotiate", - 3, - )); - } - }; + if let Some(hostname) = self.value_to_str_like(self.registers[1]) { + let stream0 = self.get_stream_or_alias( + self.registers[2], + &indices.stream_aliases, + atom!("tls_client_negotiate"), + 3, + )?; + + let connector = TlsConnector::new().unwrap(); + let stream = + match connector.connect(hostname.as_str(), stream0) { + Ok(tls_stream) => tls_stream, + Err(_) => { + return Err(self.open_permission_error( + self[temp_v!(1)], + atom!("tls_client_negotiate"), + 3, + )); + } + }; - let addr = clause_name!("TLS".to_string(), self.atom_tbl); - let stream = Stream::from_tls_stream(addr, stream); - indices.streams.insert(stream.clone()); + let addr = atom!("TLS"); + let stream = Stream::from_tls_stream(addr, stream, &mut self.arena); + indices.streams.insert(stream); - let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - let stream_addr = self.store(self.deref(self[temp_v!(3)])); - self.bind(stream_addr.as_var().unwrap(), stream); + self.heap.push(stream_as_cell!(stream)); + let stream_addr = self.store(self.deref(self.registers[3])); + self.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); + } else { + unreachable!(); + } } &SystemClauseType::TLSAcceptClient => { - let pkcs12 = self.string_encoding_bytes(1, "octet"); - let password = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); - let identity = - match Identity::from_pkcs12(&pkcs12, &password) { - Ok(identity) => identity, - Err(_) => { - return Err(self.open_permission_error( - self[temp_v!(1)], - "tls_server_negotiate", - 3, - )); - } - }; - - let stream0 = self.get_stream_or_alias( - self[temp_v!(3)], - &indices.stream_aliases, - "tls_server_negotiate", - 3, - )?; - - let acceptor = TlsAcceptor::new(identity).unwrap(); - - let stream = - match acceptor.accept(stream0) { - Ok(tls_stream) => tls_stream, - Err(_) => { - return Err(self.open_permission_error( - self[temp_v!(3)], - "tls_server_negotiate", - 3, - )); - } - }; - let addr = clause_name!("TLS".to_string(), self.atom_tbl); - let stream = Stream::from_tls_stream(addr, stream); - indices.streams.insert(stream.clone()); - - let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream)); - let stream_addr = self.store(self.deref(self[temp_v!(4)])); - self.bind(stream_addr.as_var().unwrap(), stream); - } - &SystemClauseType::SetStreamPosition => { - let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], - &indices.stream_aliases, - "set_stream_position", - 2, - )?; + let pkcs12 = self.string_encoding_bytes(self.registers[1], atom!("octet")); + + if let Some(password) = self.value_to_str_like(self.registers[2]) { + let identity = + match Identity::from_pkcs12(&pkcs12, password.as_str()) { + Ok(identity) => identity, + Err(_) => { + return Err(self.open_permission_error( + self.registers[1], + atom!("tls_server_negotiate"), + 3, + )); + } + }; - if !stream.options().reposition { - let stub = MachineError::functor_stub(clause_name!("set_stream_position"), 2); + let stream0 = self.get_stream_or_alias( + self.registers[3], + &indices.stream_aliases, + atom!("tls_server_negotiate"), + 3, + )?; + + let acceptor = TlsAcceptor::new(identity).unwrap(); + + let stream = + match acceptor.accept(stream0) { + Ok(tls_stream) => tls_stream, + Err(_) => { + return Err(self.open_permission_error( + self.registers[3], + atom!("tls_server_negotiate"), + 3, + )); + } + }; - let err = MachineError::permission_error( - self.heap.h(), - Permission::Reposition, - "stream", - vec![HeapCellValue::Stream(stream)], - ); + let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.arena); + indices.streams.insert(stream); - return Err(self.error_form(err, stub)); + let stream_addr = self.store(self.deref(self.registers[4])); + self.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); + } else { + unreachable!(); } + } + &SystemClauseType::SocketServerClose => { + let culprit = self.store(self.deref(self.registers[1])); + + read_heap_cell!(culprit, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::TcpListener, tcp_listener) => { + unsafe { + // dropping closes the instance. + std::ptr::drop_in_place(&mut tcp_listener as *mut _); + } - let position = self.store(self.deref(self[temp_v!(2)])); - - let position = match Number::try_from((position, &self.heap)) { - Ok(Number::Fixnum(n)) => n as u64, - Ok(Number::Integer(n)) => { - if let Some(n) = n.to_u64() { - n - } else { - self.fail = true; - return Ok(()); - } + tcp_listener.set_tag(ArenaHeaderTag::Dropped); + return return_from_clause!(self.last_call, self); + } + _ => { + } + ); } _ => { - unreachable!() } - }; + ); - stream.set_position(position); + let err = self.type_error(ValidType::TcpListener, culprit); + let stub = functor_stub(atom!("socket_server_close"), 1); + + return Err(self.error_form(err, stub)); } - &SystemClauseType::StreamProperty => { + &SystemClauseType::SetStreamPosition => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "stream_property", + atom!("set_stream_position"), 2, )?; - let property = match self.store(self.deref(self[temp_v!(2)])) { - Addr::Con(h) if self.heap.atom_at(h) => match &self.heap[h] { - HeapCellValue::Atom(ref name, _) => match name.as_str() { - "file_name" => { - if let Some(file_name) = stream.file_name() { - HeapCellValue::Atom(file_name, None) - } else { - self.fail = true; - return Ok(()); - } - } - "mode" => HeapCellValue::Atom(clause_name!(stream.mode()), None), - "direction" => HeapCellValue::Atom( - if stream.is_input_stream() && stream.is_output_stream() { - clause_name!("input_output") - } else if stream.is_input_stream() { - clause_name!("input") - } else { - clause_name!("output") - }, - None, - ), - "alias" => { - if let Some(alias) = &stream.options().alias { - HeapCellValue::Atom(alias.clone(), None) - } else { - self.fail = true; - return Ok(()); - } - } - "position" => { - if let Some((position, lines_read)) = stream.position() { - let h = self.heap.h(); - - let position_term = functor!( - "position_and_lines_read", - [integer(position), integer(lines_read)] - ); + if !stream.options().reposition() { + let stub = functor_stub(atom!("set_stream_position"), 2); - self.heap.extend(position_term.into_iter()); + let err = self.permission_error( + Permission::Reposition, + atom!("stream"), + vec![stream_as_cell!(stream)], + ); - HeapCellValue::Addr(Addr::HeapCell(h)) - } else { - self.fail = true; - return Ok(()); - } - } - "end_of_stream" => { - let end_of_stream_pos = stream.position_relative_to_end(); - HeapCellValue::Atom(clause_name!(end_of_stream_pos.as_str()), None) - } - "eof_action" => HeapCellValue::Atom( - clause_name!(stream.options().eof_action.as_str()), - None, - ), - "reposition" => HeapCellValue::Atom( - clause_name!(if stream.options().reposition { - "true" - } else { - "false" - }), - None, - ), - "type" => HeapCellValue::Atom( - clause_name!(stream.options().stream_type.as_property_str()), - None, - ), - _ => { - unreachable!() - } - }, - _ => { - unreachable!() + return Err(self.error_form(err, stub)); + } + + let position = self.store(self.deref(self.registers[2])); + + let position = match Number::try_from(position) { + Ok(Number::Fixnum(n)) => n.get_num() as u64, + Ok(Number::Integer(n)) => { + if let Some(n) = n.to_u64() { + n + } else { + self.fail = true; + return Ok(()); } - }, + } _ => { unreachable!() } }; - let property = self.heap.to_unifiable(property); - (self.unify_fn)(self, self[temp_v!(3)], property); + stream.set_position(position); } - &SystemClauseType::StoreGlobalVar => { - let key = match self.store(self.deref(self[temp_v!(1)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.clone() + &SystemClauseType::StreamProperty => { + let mut stream = self.get_stream_or_alias( + self.registers[1], + &indices.stream_aliases, + atom!("stream_property"), + 2, + )?; + + let atom = cell_as_atom!(self.store(self.deref(self.registers[2]))); + + let property = match atom { + atom!("file_name") => { + atom_as_cell!(if let Some(file_name) = stream.file_name() { + file_name } else { - unreachable!() + self.fail = true; + return Ok(()); + }) + } + atom!("mode") => atom_as_cell!(stream.mode()), + atom!("direction") => + atom_as_cell!(if stream.is_input_stream() && stream.is_output_stream() { + atom!("input_output") + } else if stream.is_input_stream() { + atom!("input") + } else { + atom!("output") + }), + atom!("alias") => { + atom_as_cell!(if let Some(alias) = stream.options().get_alias() { + alias + } else { + self.fail = true; + return Ok(()); + }) + } + atom!("position") => { + if let Some((position, lines_read)) = stream.position() { + let h = self.heap.len(); + + let position_term = functor!( + atom!("position_and_lines_read"), + [integer(position, &mut self.arena), + integer(lines_read, &mut self.arena)] + ); + + self.heap.extend(position_term.into_iter()); + str_loc_as_cell!(h) + } else { + self.fail = true; + return Ok(()); } } + atom!("end_of_stream") => { + let end_of_stream_pos = stream.position_relative_to_end(); + atom_as_cell!(end_of_stream_pos.as_atom()) + } + atom!("eof_action") => { + atom_as_cell!(stream.options().eof_action().as_atom()) + } + atom!("reposition") => + atom_as_cell!(if stream.options().reposition() { + atom!("true") + } else { + atom!("false") + }), + atom!("type") => { + atom_as_cell!(stream.options().stream_type().as_property_atom()) + } _ => { unreachable!() } }; - let value = self[temp_v!(2)]; + unify!(self, property, self.registers[3]); + } + &SystemClauseType::StoreGlobalVar => { + let key = cell_as_atom!(self.store(self.deref(self.registers[1]))); + + let value = self.registers[2]; let mut ball = Ball::new(); - ball.boundary = self.heap.h(); + ball.boundary = self.heap.len(); copy_term( CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut ball.stub), @@ -4613,74 +4238,101 @@ impl MachineState { indices.global_variables.insert(key, (ball, None)); } &SystemClauseType::StoreBacktrackableGlobalVar => { - let (key_h, key) = match self.store(self.deref(self[temp_v!(1)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - (h, atom.clone()) - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; - - let new_value = self.store(self.deref(self[temp_v!(2)])); + let key = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let new_value = self.store(self.deref(self.registers[2])); match indices.global_variables.get_mut(&key) { Some((_, ref mut loc)) => match loc { Some(ref mut value) => { - let old_value_loc = self.heap.push(HeapCellValue::Addr(*value)); - self.trail(TrailRef::BlackboardOffset(key_h, old_value_loc)); + self.trail(TrailRef::BlackboardOffset(key, *value)); *value = new_value; } loc @ None => { - self.trail(TrailRef::BlackboardEntry(key_h)); + self.trail(TrailRef::BlackboardEntry(key)); *loc = Some(new_value); } }, None => { - self.trail(TrailRef::BlackboardEntry(key_h)); + self.trail(TrailRef::BlackboardEntry(key)); indices .global_variables .insert(key, (Ball::new(), Some(new_value))); } } } - &SystemClauseType::Succeed => {} &SystemClauseType::TermAttributedVariables => { - let seen_vars = self.attr_vars_of_term(self[temp_v!(1)]); - let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter())); + if self.registers[1].is_constant() { + self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2]))); + return return_from_clause!(self.last_call, self); + } + + let seen_vars = self.attr_vars_of_term(self.registers[1]); + let outcome = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, seen_vars.into_iter()) + ); - (self.unify_fn)(self, self[temp_v!(2)], outcome); + unify_fn!(self, self.registers[2], outcome); } + &SystemClauseType::Succeed => {} &SystemClauseType::TermVariables => { - let a1 = self[temp_v!(1)]; + let a1 = self.registers[1]; + let a2 = self.registers[2]; + + let stored_v = self.store(self.deref(a1)); + + if stored_v.is_constant() { + self.unify_atom(atom!("[]"), self.store(self.deref(a2))); + return return_from_clause!(self.last_call, self); + } + let mut seen_set = IndexSet::new(); - let mut seen_vars = vec![]; - for addr in self.acyclic_pre_order_iter(a1) { - if addr.is_ref() && !seen_set.contains(&addr) { - seen_vars.push(addr); - seen_set.insert(addr); + { + let mut iter = stackless_preorder_iter(&mut self.heap, stored_v); + + while let Some(addr) = iter.next() { + let addr = unmark_cell_bits!(addr); + + if addr.is_var() { + seen_set.insert(addr); + } } } - let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter())); - (self.unify_fn)(self, self[temp_v!(2)], outcome); + let outcome = heap_loc_as_cell!( + filtered_iter_to_heap_list( + &mut self.heap, + seen_set.into_iter().rev(), + |heap, value| { + heap_bound_store( + heap, + heap_bound_deref(heap, value), + ).is_var() + }, + ) + ); + + unify_fn!(self, a2, outcome); + } + &SystemClauseType::TermVariablesUnderMaxDepth => { + // Term, MaxDepth, VarList + let max_depth = cell_as_fixnum!( + self.store(self.deref(self.registers[2])) + ).get_num() as usize; + + self.term_variables_under_max_depth(self.registers[1], max_depth, self.registers[3]); } &SystemClauseType::TruncateLiftedHeapTo => { - match self.store(self.deref(self[temp_v!(1)])) { - Addr::Usize(lh_offset) => self.lifted_heap.truncate(lh_offset), - _ => self.fail = true, - } + let a1 = self.store(self.deref(self.registers[1])); + let lh_offset = cell_as_fixnum!(a1).get_num() as usize; + + self.lifted_heap.truncate(lh_offset); } &SystemClauseType::UnifyWithOccursCheck => { - let a1 = self[temp_v!(1)]; - let a2 = self[temp_v!(2)]; + let a1 = self.registers[1]; + let a2 = self.registers[2]; - self.unify_with_occurs_check(a1, a2); + unify_with_occurs_check!(self, a1, a2); } &SystemClauseType::UnwindEnvironments => { let mut e = self.e; @@ -4694,66 +4346,52 @@ impl MachineState { return Ok(()); } - cp = self.stack.index_and_frame(e).prelude.cp; - e = self.stack.index_and_frame(e).prelude.e; + let and_frame = self.stack.index_and_frame(e); + + cp = and_frame.prelude.cp; + e = and_frame.prelude.e; } } &SystemClauseType::UnwindStack => { self.unwind_stack(); } + /* &SystemClauseType::Variant => { self.fail = self.structural_eq_test(); } + */ &SystemClauseType::WAMInstructions => { - let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); - - let name = self[temp_v!(2)]; - let arity = self[temp_v!(3)]; + let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); - let name = match self.store(self.deref(name)) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.clone() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - }; + let name = self.registers[2]; + let arity = self.registers[3]; + let name = cell_as_atom!(self.store(self.deref(name))); let arity = self.store(self.deref(arity)); - let arity = match Number::try_from((arity, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n), - Ok(Number::Integer(n)) => Integer::from(n.as_ref()), + let arity = match Number::try_from(arity) { + Ok(Number::Fixnum(n)) => n.get_num() as usize, + Ok(Number::Integer(n)) => n.to_usize().unwrap(), _ => { unreachable!() } }; - let key = (name.clone(), arity.to_usize().unwrap()); + let key = (name, arity); - let first_idx = match module_name.as_str() { - "user" => indices.code_dir.get(&key), + let first_idx = match module_name { + atom!("user") => indices.code_dir.get(&key), _ => match indices.modules.get(&module_name) { Some(module) => module.code_dir.get(&key), None => { - let stub = MachineError::functor_stub(key.0, key.1); - let h = self.heap.h(); - - let err = MachineError::session_error( - h, + let stub = functor_stub(key.0, key.1); + let err = self.session_error( SessionError::from(CompilationError::InvalidModuleResolution( module_name, )), ); - let err = self.error_form(err, stub); - - self.throw_exception(err); - return Ok(()); + return Err(self.error_form(err, stub)); } }, }; @@ -4767,34 +4405,39 @@ impl MachineState { } } _ => { - let arity = arity.to_usize().unwrap(); - let stub = MachineError::functor_stub(name.clone(), arity); - let h = self.heap.h(); - - let err = MachineError::existence_error( - h, + let stub = functor_stub(name, arity); + let err = self.existence_error( ExistenceError::Procedure(name, arity), ); - let err = self.error_form(err, stub); - - self.throw_exception(err); - return Ok(()); + return Err(self.error_form(err, stub)); } }; - let mut h = self.heap.h(); + let mut h = self.heap.len(); + let mut functors = vec![]; let mut functor_list = vec![]; walk_code(&code_repo.code, first_idx, |instr| { let old_len = functors.len(); - instr.enqueue_functors(h, &mut functors); + instr.enqueue_functors(h, &mut self.arena, &mut functors); let new_len = functors.len(); for index in old_len..new_len { - functor_list.push(Addr::HeapCell(h)); - h += functors[index].len(); + let functor_len = functors[index].len(); + + match functor_len { + 0 => {} + 1 => { + functor_list.push(heap_loc_as_cell!(h)); + h += functor_len; + } + _ => { + functor_list.push(str_loc_as_cell!(h)); + h += functor_len; + } + } } }); @@ -4802,64 +4445,69 @@ impl MachineState { self.heap.extend(functor.into_iter()); } - let listing = Addr::HeapCell(self.heap.to_list(functor_list.into_iter())); - let listing_var = self[temp_v!(4)]; + let listing = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, functor_list.into_iter()) + ); + + let listing_var = self.registers[4]; - (self.unify_fn)(self, listing, listing_var); + unify!(self, listing, listing_var); } &SystemClauseType::WriteTerm => { let mut stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "write_term", + atom!("write_term"), 3, )?; self.check_stream_properties( - &mut stream, + stream, StreamType::Text, None, // input - clause_name!("write_term"), + atom!("write_term"), 3, )?; let opt_err = if !stream.is_output_stream() { - Some("stream") // 8.14.2.3 g) - } else if stream.options().stream_type == StreamType::Binary { - Some("binary_stream") // 8.14.2.3 h) + Some(atom!("stream")) // 8.14.2.3 g) + } else if stream.options().stream_type() == StreamType::Binary { + Some(atom!("binary_stream")) // 8.14.2.3 h) } else { None }; - if let Some(err_string) = opt_err { + if let Some(err_atom) = opt_err { return Err(self.stream_permission_error( Permission::OutputStream, - err_string, + err_atom, stream, - clause_name!("write_term"), + atom!("write_term"), 3, )); } - let addr = self[temp_v!(2)]; - let printer = match self.write_term(&indices.op_dir)? { + Some(printer) => printer, None => { - self.fail = true; + // this next line is executed by + // MachineState::write_term in this case. it's + // commented here because rustc can't prove + // that it's no longer borrowed. + + // self.fail = true; return Ok(()); } - Some(printer) => printer, }; - let output = printer.print(addr); + let output = printer.print(); match write!(&mut stream, "{}", output.result()) { Ok(_) => {} Err(_) => { - let stub = MachineError::functor_stub(clause_name!("open"), 4); - let err = MachineError::existence_error( - self.heap.h(), - ExistenceError::Stream(self[temp_v!(1)]), + let stub = functor_stub(atom!("open"), 4); + let err = self.existence_error( + ExistenceError::Stream(self.registers[1]), ); return Err(self.error_form(err, stub)); @@ -4869,20 +4517,23 @@ impl MachineState { stream.flush().unwrap(); } &SystemClauseType::WriteTermToChars => { - let addr = self[temp_v!(2)]; - let printer = match self.write_term(&indices.op_dir)? { None => { - self.fail = true; + // this next line is executed by + // MachineState::write_term in this case. it's + // commented here because rustc can't prove + // that it's no longer borrowed. + + // self.fail = true; return Ok(()); } Some(printer) => printer, }; - let result = printer.print(addr).result(); - let chars = self.heap.put_complete_string(&result); + let result = printer.print().result(); + let chars = put_complete_string(&mut self.heap, &result, &mut self.atom_tbl); - let result_addr = self.store(self.deref(self[temp_v!(1)])); + let result_addr = self.store(self.deref(self.registers[1])); if let Some(var) = result_addr.as_var() { self.bind(var, chars); @@ -4892,14 +4543,14 @@ impl MachineState { } &SystemClauseType::ScryerPrologVersion => { use git_version::git_version; - let version = self[temp_v!(1)]; + let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); - let chars = buffer.chars().map(|c| Addr::Char(c)); - let result = Addr::HeapCell(self.heap.to_list(chars)); - (self.unify_fn)(self, version, result); + let buffer_atom = self.atom_tbl.build_with(buffer); + + self.unify_complete_string(buffer_atom, self.store(self.deref(self.registers[1]))); } &SystemClauseType::CryptoRandomByte => { - let arg = self[temp_v!(1)]; + let arg = self.registers[1]; let mut bytes: [u8; 1] = [0]; match rng().fill(&mut bytes) { @@ -4913,149 +4564,163 @@ impl MachineState { } } - let byte = self - .heap - .to_unifiable(HeapCellValue::Integer(Rc::new(Integer::from(bytes[0])))); - - (self.unify_fn)(self, arg, byte); + let byte = Fixnum::build_with(bytes[0] as i64); + self.unify_fixnum(byte, arg); } &SystemClauseType::CryptoDataHash => { - let encoding = self.atom_argument_to_string(2); - let bytes = self.string_encoding_bytes(1, &encoding); + let encoding = cell_as_atom!(self.registers[2]); + let bytes = self.string_encoding_bytes(self.registers[1], encoding); - let algorithm = self.atom_argument_to_string(4); + let algorithm = cell_as_atom!(self.registers[4]); - let ints_list = match algorithm.as_str() { - "sha3_224" => { + let ints_list = match algorithm { + atom!("sha3_224") => { let mut context = Sha3_224::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "sha3_256" => { + atom!("sha3_256") => { let mut context = Sha3_256::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "sha3_384" => { + atom!("sha3_384") => { let mut context = Sha3_384::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "sha3_512" => { + atom!("sha3_512") => { let mut context = Sha3_512::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "blake2s256" => { + atom!("blake2s256") => { let mut context = Blake2s::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "blake2b512" => { + atom!("blake2b512") => { let mut context = Blake2b::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } - "ripemd160" => { + atom!("ripemd160") => { let mut context = Ripemd160::new(); context.input(&bytes); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, context .result() .as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } _ => { let ints = digest::digest( - match algorithm.as_str() { - "sha256" => &digest::SHA256, - "sha384" => &digest::SHA384, - "sha512" => &digest::SHA512, - "sha512_256" => &digest::SHA512_256, + match algorithm { + atom!("sha256") => &digest::SHA256, + atom!("sha384") => &digest::SHA384, + atom!("sha512") => &digest::SHA512, + atom!("sha512_256") => &digest::SHA512_256, _ => { unreachable!() } }, &bytes, ); - Addr::HeapCell( - self.heap.to_list( + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, ints.as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) } }; - (self.unify_fn)(self, self[temp_v!(3)], ints_list); + unify!(self, self.registers[3], ints_list); } &SystemClauseType::CryptoDataHKDF => { - let encoding = self.atom_argument_to_string(2); - let data = self.string_encoding_bytes(1, &encoding); - let stub1 = MachineError::functor_stub(clause_name!("crypto_data_hkdf"), 4); - let salt = self.integers_to_bytevec(temp_v!(3), stub1); - let stub2 = MachineError::functor_stub(clause_name!("crypto_data_hkdf"), 4); - let info = self.integers_to_bytevec(temp_v!(4), stub2); + let encoding = cell_as_atom!(self.registers[2]); + let data = self.string_encoding_bytes(self.registers[1], encoding); - let algorithm = self.atom_argument_to_string(5); + let stub1_gen = || functor_stub(atom!("crypto_data_hkdf"), 4); + let salt = self.integers_to_bytevec(self.registers[3], stub1_gen); - let length = self.store(self.deref(self[temp_v!(6)])); + let stub2_gen = || functor_stub(atom!("crypto_data_hkdf"), 4); + let info = self.integers_to_bytevec(self.registers[4], stub2_gen); - let length = match Number::try_from((length, &self.heap)) { - Ok(Number::Fixnum(n)) => usize::try_from(n).unwrap(), + let algorithm = cell_as_atom!(self.registers[5]); + + let length = self.store(self.deref(self.registers[6])); + + let length = match Number::try_from(length) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match n.to_usize() { Some(u) => u, _ => { @@ -5069,18 +4734,21 @@ impl MachineState { }; let ints_list = { - let digest_alg = match algorithm.as_str() { - "sha256" => hkdf::HKDF_SHA256, - "sha384" => hkdf::HKDF_SHA384, - "sha512" => hkdf::HKDF_SHA512, + let digest_alg = match algorithm { + atom!("sha256") => hkdf::HKDF_SHA256, + atom!("sha384") => hkdf::HKDF_SHA384, + atom!("sha512") => hkdf::HKDF_SHA512, _ => { self.fail = true; return Ok(()); } }; + let salt = hkdf::Salt::new(digest_alg, &salt); let mut bytes: Vec = Vec::new(); + bytes.resize(length, 0); + match salt.extract(&data).expand(&[&info[..]], MyKey(length)) { Ok(r) => { r.fill(&mut bytes).unwrap(); @@ -5091,27 +4759,28 @@ impl MachineState { } } - Addr::HeapCell( - self.heap.to_list( + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, bytes .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) }; - (self.unify_fn)(self, self[temp_v!(7)], ints_list); + unify!(self, self.registers[7], ints_list); } &SystemClauseType::CryptoPasswordHash => { - let stub1 = MachineError::functor_stub(clause_name!("crypto_password_hash"), 3); - let data = self.integers_to_bytevec(temp_v!(1), stub1); - let stub2 = MachineError::functor_stub(clause_name!("crypto_password_hash"), 3); - let salt = self.integers_to_bytevec(temp_v!(2), stub2); + let stub1_gen = || functor_stub(atom!("crypto_password_hash"), 3); + let data = self.integers_to_bytevec(self.registers[1], stub1_gen); + let stub2_gen = || functor_stub(atom!("crypto_password_hash"), 3); + let salt = self.integers_to_bytevec(self.registers[2], stub2_gen); - let iterations = self.store(self.deref(self[temp_v!(3)])); + let iterations = self.store(self.deref(self.registers[3])); - let iterations = match Number::try_from((iterations, &self.heap)) { - Ok(Number::Fixnum(n)) => u64::try_from(n).unwrap(), + let iterations = match Number::try_from(iterations) { + Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match n.to_u64() { Some(i) => i, None => { @@ -5126,6 +4795,7 @@ impl MachineState { let ints_list = { let mut bytes = [0u8; digest::SHA512_OUTPUT_LEN]; + pbkdf2::derive( pbkdf2::PBKDF2_HMAC_SHA512, NonZeroU32::new(iterations as u32).unwrap(), @@ -5134,31 +4804,36 @@ impl MachineState { &mut bytes, ); - Addr::HeapCell( - self.heap.to_list( + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, bytes .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ) }; - (self.unify_fn)(self, self[temp_v!(4)], ints_list); + unify!(self, self.registers[4], ints_list); } &SystemClauseType::CryptoDataEncrypt => { - let encoding = self.atom_argument_to_string(3); - let data = self.string_encoding_bytes(1, &encoding); - let aad = self.string_encoding_bytes(2, &encoding); - let stub2 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 7); - let key = self.integers_to_bytevec(temp_v!(4), stub2); - let stub3 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 7); - let iv = self.integers_to_bytevec(temp_v!(5), stub3); + let encoding = cell_as_atom!(self.registers[3]); + + let data = self.string_encoding_bytes(self.registers[1], encoding); + let aad = self.string_encoding_bytes(self.registers[2], encoding); + + let stub2_gen = || functor_stub(atom!("crypto_data_encrypt"), 7); + let key = self.integers_to_bytevec(self.registers[4], stub2_gen); + + let stub3_gen = || functor_stub(atom!("crypto_data_encrypt"), 7); + let iv = self.integers_to_bytevec(self.registers[5], stub3_gen); let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap(); let key = aead::LessSafeKey::new(unbound_key); - let mut in_out = data.clone(); + let mut in_out = data; + let tag = match key.seal_in_place_separate_tag( nonce, aead::Aad::from(aad), @@ -5171,36 +4846,39 @@ impl MachineState { } }; - let tag_list = Addr::HeapCell( - self.heap.to_list( + let tag_list = heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, tag.as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ); let complete_string = { let buffer = String::from_iter(in_out.iter().map(|b| *b as char)); - self.heap.put_complete_string(&buffer) + put_complete_string(&mut self.heap, &buffer, &mut self.atom_tbl) }; - (self.unify_fn)(self, self[temp_v!(6)], tag_list); - (self.unify_fn)(self, self[temp_v!(7)], complete_string); + unify!(self, self.registers[6], tag_list); + unify!(self, self.registers[7], complete_string); } &SystemClauseType::CryptoDataDecrypt => { - let data = self.string_encoding_bytes(1, "octet"); - let encoding = self.atom_argument_to_string(5); - let aad = self.string_encoding_bytes(2, &encoding); - let stub1 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 7); - let key = self.integers_to_bytevec(temp_v!(3), stub1); - let stub2 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 7); - let iv = self.integers_to_bytevec(temp_v!(4), stub2); + let data = self.string_encoding_bytes(self.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.registers[5]); + + let aad = self.string_encoding_bytes(self.registers[2], encoding); + let stub1_gen = || functor_stub(atom!("crypto_data_decrypt"), 7); + + let key = self.integers_to_bytevec(self.registers[3], stub1_gen); + let stub2_gen = || functor_stub(atom!("crypto_data_decrypt"), 7); + let iv = self.integers_to_bytevec(self.registers[4], stub2_gen); let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap(); let key = aead::LessSafeKey::new(unbound_key); - let mut in_out = data.clone(); + let mut in_out = data; let complete_string = { let decrypted_data = @@ -5212,9 +4890,9 @@ impl MachineState { } }; - let buffer = match encoding.as_str() { - "octet" => String::from_iter(decrypted_data.iter().map(|b| *b as char)), - "utf8" => match String::from_utf8(decrypted_data.to_vec()) { + let buffer = match encoding { + atom!("octet") => String::from_iter(decrypted_data.iter().map(|b| *b as char)), + atom!("utf8") => match String::from_utf8(decrypted_data.to_vec()) { Ok(str) => str, _ => { self.fail = true; @@ -5226,67 +4904,80 @@ impl MachineState { } }; - self.heap.put_complete_string(&buffer) + put_complete_string(&mut self.heap, &buffer, &mut self.atom_tbl) }; - (self.unify_fn)(self, self[temp_v!(6)], complete_string); + unify!(self, self.registers[6], complete_string); } &SystemClauseType::CryptoCurveScalarMult => { - let curve = self.atom_argument_to_string(1); - let curve_id = match curve.as_str() { - "secp112r1" => Nid::SECP112R1, - "secp256k1" => Nid::SECP256K1, + let curve = cell_as_atom!(self.registers[1]); + + let curve_id = match curve { + atom!("secp112r1") => Nid::SECP112R1, + atom!("secp256k1") => Nid::SECP256K1, _ => { unreachable!() } }; - let scalar = self.store(self.deref(self[temp_v!(2)])); + let scalar = self.store(self.deref(self.registers[2])); - let scalar = match Number::try_from((scalar, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n), - Ok(Number::Integer(n)) => Integer::from(&*n.clone()), + let scalar = match Number::try_from(scalar) { + Ok(Number::Fixnum(n)) => Integer::from(n.get_num()), + Ok(Number::Integer(n)) => Integer::from(&*n), _ => { unreachable!() } }; - let stub = MachineError::functor_stub(clause_name!("crypto_curve_scalar_mult"), 5); - let qbytes = self.integers_to_bytevec(temp_v!(3), stub); + let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 5); + let qbytes = self.integers_to_bytevec(self.registers[3], stub_gen); let mut bnctx = BigNumContext::new().unwrap(); let group = EcGroup::from_curve_name(curve_id).unwrap(); let mut point = EcPoint::from_bytes(&group, &qbytes, &mut bnctx).unwrap(); let scalar_bn = BigNum::from_dec_str(&scalar.to_string()).unwrap(); let mut result = EcPoint::new(&group).unwrap(); + result.mul(&group, &mut point, &scalar_bn, &mut bnctx).ok(); let mut rx = BigNum::new().unwrap(); let mut ry = BigNum::new().unwrap(); + result .affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx) .ok(); - let sx = self - .heap - .put_complete_string(&rx.to_dec_str().unwrap().to_string()); - let sy = self - .heap - .put_complete_string(&ry.to_dec_str().unwrap().to_string()); - (self.unify_fn)(self, self[temp_v!(4)], sx); - (self.unify_fn)(self, self[temp_v!(5)], sy); + let sx = put_complete_string( + &mut self.heap, + &rx.to_dec_str().unwrap(), + &mut self.atom_tbl, + ); + + let sy = put_complete_string( + &mut self.heap, + &ry.to_dec_str().unwrap(), + &mut self.atom_tbl, + ); + + unify!(self, self.registers[4], sx); + unify!(self, self.registers[5], sy); } &SystemClauseType::Ed25519NewKeyPair => { let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap(); let complete_string = { let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char)); - self.heap.put_complete_string(&buffer) + put_complete_string( + &mut self.heap, + &buffer, + &mut self.atom_tbl, + ) }; - (self.unify_fn)(self, self[temp_v!(1)], complete_string); + unify!(self, self.registers[1], complete_string) } &SystemClauseType::Ed25519KeyPairPublicKey => { - let bytes = self.string_encoding_bytes(1, "octet"); + let bytes = self.string_encoding_bytes(self.registers[1], atom!("octet")); let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) { Ok(kp) => kp, @@ -5300,15 +4991,20 @@ impl MachineState { let buffer = String::from_iter( key_pair.public_key().as_ref().iter().map(|b| *b as char), ); - self.heap.put_complete_string(&buffer) + + put_complete_string( + &mut self.heap, + &buffer, + &mut self.atom_tbl, + ) }; - (self.unify_fn)(self, self[temp_v!(2)], complete_string); + unify!(self, self.registers[2], complete_string); } &SystemClauseType::Ed25519Sign => { - let key = self.string_encoding_bytes(1, "octet"); - let encoding = self.atom_argument_to_string(3); - let data = self.string_encoding_bytes(2, &encoding); + let key = self.string_encoding_bytes(self.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.registers[3]); + let data = self.string_encoding_bytes(self.registers[2], encoding); let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) { Ok(kp) => kp, @@ -5320,24 +5016,26 @@ impl MachineState { let sig = key_pair.sign(&data); - let sig_list = Addr::HeapCell( - self.heap.to_list( + let sig_list = heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, sig.as_ref() .iter() - .map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))), - ), + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) ); - (self.unify_fn)(self, self[temp_v!(4)], sig_list); + unify!(self, self.registers[4], sig_list); } &SystemClauseType::Ed25519Verify => { - let key = self.string_encoding_bytes(1, "octet"); - let encoding = self.atom_argument_to_string(3); - let data = self.string_encoding_bytes(2, &encoding); - let stub = MachineError::functor_stub(clause_name!("ed25519_verify"), 5); - let signature = self.integers_to_bytevec(temp_v!(4), stub); + let key = self.string_encoding_bytes(self.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.registers[3]); + let data = self.string_encoding_bytes(self.registers[2], encoding); + let stub_gen = || functor_stub(atom!("ed25519_verify"), 5); + let signature = self.integers_to_bytevec(self.registers[4], stub_gen); let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key); + match peer_public_key.verify(&data, &signature) { Ok(_) => {} _ => { @@ -5347,73 +5045,112 @@ impl MachineState { } } &SystemClauseType::Curve25519ScalarMult => { - let stub1 = MachineError::functor_stub(clause_name!("curve25519_scalar_mult"), 3); - let scalar_bytes = self.integers_to_bytevec(temp_v!(1), stub1); + let stub1_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3); + let scalar_bytes = self.integers_to_bytevec(self.registers[1], stub1_gen); let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap()); - let stub2 = MachineError::functor_stub(clause_name!("curve25519_scalar_mult"), 3); - let point_bytes = self.integers_to_bytevec(temp_v!(2), stub2); + let stub2_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3); + let point_bytes = self.integers_to_bytevec(self.registers[2], stub2_gen); let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap()); let result = scalarmult(&scalar, &point).unwrap(); let string = String::from_iter(result[..].iter().map(|b| *b as char)); - let cstr = self.heap.put_complete_string(&string); - (self.unify_fn)(self, self[temp_v!(3)], cstr); + let cstr = put_complete_string(&mut self.heap, &string, &mut self.atom_tbl); + + unify!(self, self.registers[3], cstr); } &SystemClauseType::FirstNonOctet => { - for c in self.heap_pstr_iter(self[temp_v!(1)]).to_string().chars() { - if c as u32 > 255 { - let chars = clause_name!(String::from(c.to_string()), self.atom_tbl); - let non_octet = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); - (self.unify_fn)(self, self[temp_v!(2)], non_octet); - return return_from_clause!(self.last_call, self); + let addr = self.store(self.deref(self.registers[1])); + + if let Some(string) = self.value_to_str_like(addr) { + for c in string.as_str().chars() { + if c as u32 > 255 { + let non_octet = self.atom_tbl.build_with(&c.to_string()); + self.unify_atom(non_octet, self.registers[2]); + return return_from_clause!(self.last_call, self); + } } } + self.fail = true; return Ok(()); } &SystemClauseType::LoadHTML => { - let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - let doc = select::document::Document::from_read(string.as_bytes()).unwrap(); - let result = self.html_node_to_term(indices, doc.nth(0).unwrap()); + if let Some(string) = self.value_to_str_like(self.registers[1]) { + let doc = select::document::Document::from_read(string.as_str().as_bytes()) + .unwrap(); - (self.unify_fn)(self, self[temp_v!(2)], result); + let result = self.html_node_to_term(indices, doc.nth(0).unwrap()); + unify!(self, self.registers[2], result); + } else { + self.fail = true; + return Ok(()); + } } &SystemClauseType::LoadXML => { - let string = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - match roxmltree::Document::parse(&string) { - Ok(doc) => { - let result = self.xml_node_to_term(indices, doc.root_element()); - (self.unify_fn)(self, self[temp_v!(2)], result); - } - _ => { - self.fail = true; - return Ok(()); + if let Some(string) = self.value_to_str_like(self.registers[1]) { + match roxmltree::Document::parse(string.as_str()) { + Ok(doc) => { + let result = self.xml_node_to_term(indices, doc.root_element()); + unify!(self, self.registers[2], result); + } + _ => { + self.fail = true; + return Ok(()); + } } + } else { + self.fail = true; + return Ok(()); } } &SystemClauseType::GetEnv => { - let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - match env::var(key) { - Ok(value) => { - let cstr = self.heap.put_complete_string(&value); - (self.unify_fn)(self, self[temp_v!(2)], cstr); - } - _ => { - self.fail = true; - return Ok(()); + if let Some(key) = self.value_to_str_like(self.registers[1]) { + match env::var(key.as_str()) { + Ok(value) => { + let cstr = put_complete_string( + &mut self.heap, + &value, + &mut self.atom_tbl, + ); + + unify!(self, self.registers[2], cstr); + } + _ => { + self.fail = true; + return Ok(()); + } } + } else { + self.fail = true; + return Ok(()); } } &SystemClauseType::SetEnv => { - let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - let value = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); - env::set_var(key, value); + let key = self.value_to_str_like(self.registers[1]).unwrap(); + let value = self.value_to_str_like(self.registers[2]).unwrap(); + + env::set_var(key.as_str(), value.as_str()); } &SystemClauseType::UnsetEnv => { - let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); - env::remove_var(key); + let key = self.value_to_str_like(self.registers[1]).unwrap(); + env::remove_var(key.as_str()); + } + &SystemClauseType::PID => { + let pid = process::id(); + + match fixnum!(Number, pid as i64, &mut self.arena) { + Number::Fixnum(pid) => { + self.unify_fixnum(pid, self.registers[1]); + } + Number::Integer(pid) => { + self.unify_big_int(pid, self.registers[1]); + } + _ => { + unreachable!(); + } + } } &SystemClauseType::Shell => { // shell executes a command in a system shell @@ -5426,8 +5163,8 @@ impl MachineState { Ok(status) => { match status.code() { Some(code) => { - let addr = machine.heap.put_constant(Constant::Integer(Rc::new(Integer::from(code)))); - (machine.unify_fn)(machine, machine[temp_v!(2)], addr); + let code = integer_as_cell!(Number::arena_from(code, &mut machine.arena)); + unify!(machine, code, machine.registers[2]); } _ => { machine.fail = true; @@ -5440,12 +5177,13 @@ impl MachineState { } } - let command = self.heap_pstr_iter(self[temp_v!(1)]).to_string(); + let command = self.value_to_str_like(self.store(self.deref(self.registers[1]))).unwrap(); + match env::var("SHELL") { Ok(value) => { let command = process::Command::new(&value) .arg("-c") - .arg(command) + .arg(command.as_str()) .status(); command_result(self, command); } @@ -5454,7 +5192,7 @@ impl MachineState { Ok(value) => { let command = process::Command::new(&value) .arg("/C") - .arg(command) + .arg(command.as_str()) .status(); command_result(self, command); } @@ -5465,39 +5203,38 @@ impl MachineState { } }; } - &SystemClauseType::PID => { - let a1 = self[temp_v!(1)]; - let pid = process::id(); - let addr = self.heap.put_constant(Constant::Integer(Rc::new(Integer::from(pid)))); - (self.unify_fn)(self, a1, addr); - } &SystemClauseType::CharsBase64 => { - let padding = self.atom_argument_to_string(3); - let charset = self.atom_argument_to_string(4); + let padding = cell_as_atom!(self.registers[3]); + let charset = cell_as_atom!(self.registers[4]); - let config = if padding == "true" { - if charset == "standard" { + let config = if padding == atom!("true") { + if charset == atom!("standard") { base64::STANDARD } else { base64::URL_SAFE } } else { - if charset == "standard" { + if charset == atom!("standard") { base64::STANDARD_NO_PAD } else { base64::URL_SAFE_NO_PAD } }; - if self.store(self.deref(self[temp_v!(1)])).is_ref() { - let b64 = self.heap_pstr_iter(self[temp_v!(2)]).to_string(); - let bytes = base64::decode_config(b64, config); + if self.store(self.deref(self.registers[1])).is_var() { + let b64 = self.value_to_str_like(self.registers[2]).unwrap(); + let bytes = base64::decode_config(b64.as_str(), config); match bytes { Ok(bs) => { let string = String::from_iter(bs.iter().map(|b| *b as char)); - let cstr = self.heap.put_complete_string(&string); - (self.unify_fn)(self, self[temp_v!(1)], cstr); + let cstr = put_complete_string( + &mut self.heap, + &string, + &mut self.atom_tbl, + ); + + unify!(self, self.registers[1], cstr); } _ => { self.fail = true; @@ -5506,28 +5243,40 @@ impl MachineState { } } else { let mut bytes = vec![]; - for c in self.heap_pstr_iter(self[temp_v!(1)]).to_string().chars() { + for c in self.value_to_str_like(self.registers[1]).unwrap().as_str().chars() { + if c as u32 > 255 { + let stub = functor_stub(atom!("chars_base64"), 3); + + let err = self.type_error( + ValidType::Byte, + char_as_cell!(c), + ); + + return Err(self.error_form(err, stub)); + } + bytes.push(c as u8); } + let b64 = base64::encode_config(bytes, config); + let cstr = put_complete_string( + &mut self.heap, + &b64, + &mut self.atom_tbl, + ); - let cstr = self.heap.put_complete_string(&b64); - (self.unify_fn)(self, self[temp_v!(2)], cstr); + unify!(self, self.registers[2], cstr); } } &SystemClauseType::LoadLibraryAsStream => { - let library_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)]))); + let library_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); - use crate::LIBRARIES; + use crate::machine::LIBRARIES; match LIBRARIES.borrow().get(library_name.as_str()) { Some(library) => { - let var_ref = Ref::HeapCell( - self.heap - .push(HeapCellValue::Stream(Stream::from(*library))), - ); - - self.bind(var_ref, self[temp_v!(2)]); + let lib_stream = Stream::from_static_string(library, &mut self.arena); + unify!(self, stream_as_cell!(lib_stream), self.registers[2]); let mut path_buf = machine::current_dir(); @@ -5535,35 +5284,31 @@ impl MachineState { path_buf.push(library_name.as_str()); let library_path_str = path_buf.to_str().unwrap(); - let library_path = - clause_name!(library_path_str.to_string(), self.atom_tbl); + let library_path = self.atom_tbl.build_with(library_path_str); - let library_path_ref = - Ref::HeapCell(self.heap.push(HeapCellValue::Atom(library_path, None))); - - self.bind(library_path_ref, self[temp_v!(3)]); + self.unify_atom(library_path, self.registers[3]); } None => { - return Err(self.error_form( - MachineError::existence_error( - self.heap.h(), - ExistenceError::ModuleSource(ModuleSource::Library(library_name)), - ), - MachineError::functor_stub(clause_name!("load"), 1), - )); + let stub = functor_stub(atom!("load"), 1); + let err = self.existence_error( + ExistenceError::ModuleSource(ModuleSource::Library(library_name)) + ); + + return Err(self.error_form(err, stub)); } } } &SystemClauseType::DevourWhitespace => { let stream = self.get_stream_or_alias( - self[temp_v!(1)], + self.registers[1], &indices.stream_aliases, - "$devour_whitespace", + atom!("$devour_whitespace"), 1, )?; - match self.devour_whitespace(stream, self.atom_tbl.clone()) { - Ok(false) => {} // not at EOF. + match self.devour_whitespace(stream) { + Ok(false) => { // not at EOF. + } _ => { self.fail = true; return Ok(()); @@ -5572,25 +5317,13 @@ impl MachineState { } &SystemClauseType::IsSTOEnabled => { if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize { - let value = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("true"), None)); - - (self.unify_fn)(self, self[temp_v!(1)], value); + self.unify_atom(atom!("true"), self.registers[1]); } else if self.unify_fn as usize == MachineState::unify_with_occurs_check_with_error as usize { - let value = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("error"), None)); - - (self.unify_fn)(self, self[temp_v!(1)], value); + self.unify_atom(atom!("error"), self.registers[1]); } else { - let value = self - .heap - .to_unifiable(HeapCellValue::Atom(clause_name!("false"), None)); - - (self.unify_fn)(self, self[temp_v!(1)], value); + self.unify_atom(atom!("false"), self.registers[1]); } } &SystemClauseType::SetSTOAsUnify => { @@ -5616,9 +5349,13 @@ impl MachineState { if path.is_dir() { if let Some(path) = path.to_str() { - let path_string = self.heap.put_complete_string(path); + let path_string = put_complete_string( + &mut self.heap, + path, + &mut self.atom_tbl, + ); - self.unify(self[temp_v!(1)], path_string); + unify!(self, self.registers[1], path_string); return return_from_clause!(self.last_call, self); } } @@ -5629,66 +5366,51 @@ impl MachineState { self.fail = false; } &SystemClauseType::PopCount => { - let number = self.store(self.deref(self[temp_v!(1)])); - let count = match Number::try_from((number, &self.heap)) { - Ok(Number::Fixnum(n)) => Integer::from(n.count_ones()), - Ok(Number::Integer(n)) => Integer::from((&*n).count_ones().unwrap()), + let number = self.store(self.deref(self.registers[1])); + let pop_count = integer_as_cell!(match Number::try_from(number) { + Ok(Number::Fixnum(n)) => { + Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64)) + } + Ok(Number::Integer(n)) => { + Number::arena_from(n.count_ones().unwrap(), &mut self.arena) + } _ => { unreachable!() } - }; + }); - let pop_count = self.heap.to_unifiable(HeapCellValue::Integer(Rc::new(count))); - (self.unify_fn)(self, self[temp_v!(2)], pop_count); + unify!(self, self.registers[2], pop_count); } }; return_from_clause!(self.last_call, self) } - pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Addr { + pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Atom { let datetime: DateTime = system_time.into(); let mut fstr = "[".to_string(); - let specifiers = vec![ + const SPECIFIERS: [&'static str; 19] = [ "Y", "m", "d", "H", "M", "S", "y", "b", "B", "a", "A", "w", "u", "U", "W", "j", "D", "x", "v", ]; - for spec in specifiers { + + for spec in SPECIFIERS { fstr.push_str(&format!("'{}'=\"%{}\", ", spec, spec).to_string()); } + fstr.push_str("finis]."); let s = datetime.format(&fstr).to_string(); - self.heap.put_complete_string(&s) - } - pub(super) fn atom_argument_to_string(&mut self, atom_arg: usize) -> String { - match self.store(self.deref(self[temp_v!(atom_arg)])) { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { - atom.as_str().to_string() - } else { - unreachable!() - } - } - _ => { - unreachable!() - } - } + self.atom_tbl.build_with(&s) } - pub(super) fn string_encoding_bytes(&mut self, data_arg: usize, encoding: &str) -> Vec { - let data = self.heap_pstr_iter(self[temp_v!(data_arg)]).to_string(); + pub(super) fn string_encoding_bytes(&mut self, data_arg: HeapCellValue, encoding: Atom) -> Vec { + let data = self.value_to_str_like(data_arg).unwrap(); match encoding { - "utf8" => data.into_bytes(), - "octet" => { - let mut buf = vec![]; - for c in data.chars() { - buf.push(c as u8); - } - buf - } + atom!("utf8") => data.as_str().bytes().collect(), + atom!("octet") => data.as_str().chars().map(|c| c as u8).collect(), _ => { unreachable!() } @@ -5699,43 +5421,53 @@ impl MachineState { &mut self, indices: &mut IndexStore, node: roxmltree::Node, - ) -> Addr { + ) -> HeapCellValue { if node.is_text() { - let string = String::from(node.text().unwrap()); - self.heap.put_complete_string(&string) + put_complete_string( + &mut self.heap, + node.text().unwrap(), + &mut self.atom_tbl, + ) } else { let mut avec = Vec::new(); - for attr in node.attributes() { - let chars = clause_name!(String::from(attr.name()), self.atom_tbl); - let name = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); - let value = self.heap.put_complete_string(&attr.value()); + for attr in node.attributes() { + let name = self.atom_tbl.build_with(attr.name()); + let value = put_complete_string( + &mut self.heap, + &attr.value(), + &mut self.atom_tbl, + ); - avec.push(HeapCellValue::Addr(Addr::HeapCell(self.heap.h()))); + avec.push(heap_loc_as_cell!(self.heap.len())); - self.heap - .push(HeapCellValue::NamedStr(2, clause_name!("="), None)); - self.heap.push(HeapCellValue::Addr(name)); - self.heap.push(HeapCellValue::Addr(value)); + self.heap.push(atom_as_cell!(atom!("="), 2)); + self.heap.push(atom_as_cell!(name)); + self.heap.push(value); } - let attrs = Addr::HeapCell(self.heap.to_list(avec.into_iter())); + + let attrs = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, avec.into_iter()) + ); let mut cvec = Vec::new(); + for child in node.children() { cvec.push(self.xml_node_to_term(indices, child)); } - let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter())); - let chars = clause_name!(String::from(node.tag_name().name()), self.atom_tbl); - let tag = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); + let children = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, cvec.into_iter()) + ); + + let tag = self.atom_tbl.build_with(node.tag_name().name()); - let result = Addr::HeapCell(self.heap.h()); + let result = heap_loc_as_cell!(self.heap.len()); - self.heap - .push(HeapCellValue::NamedStr(3, clause_name!("element"), None)); - self.heap.push(HeapCellValue::Addr(tag)); - self.heap.push(HeapCellValue::Addr(attrs)); - self.heap.push(HeapCellValue::Addr(children)); + self.heap.push(atom_as_cell!(atom!("element"), 3)); + self.heap.push(atom_as_cell!(tag)); + self.heap.push(attrs); + self.heap.push(children); result } @@ -5745,45 +5477,54 @@ impl MachineState { &mut self, indices: &mut IndexStore, node: select::node::Node, - ) -> Addr { + ) -> HeapCellValue { match node.name() { None => { - let string = String::from(node.text()); - self.heap.put_complete_string(&string) + put_complete_string( + &mut self.heap, + &node.text(), + &mut self.atom_tbl, + ) } Some(name) => { let mut avec = Vec::new(); - for attr in node.attrs() { - let chars = clause_name!(String::from(attr.0), self.atom_tbl); - let name = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); - let value = self.heap.put_complete_string(&String::from(attr.1)); + for attr in node.attrs() { + let name = self.atom_tbl.build_with(attr.0); + let value = put_complete_string( + &mut self.heap, + &attr.1, + &mut self.atom_tbl, + ); - avec.push(HeapCellValue::Addr(Addr::HeapCell(self.heap.h()))); + avec.push(heap_loc_as_cell!(self.heap.len())); - self.heap - .push(HeapCellValue::NamedStr(2, clause_name!("="), None)); - self.heap.push(HeapCellValue::Addr(name)); - self.heap.push(HeapCellValue::Addr(value)); + self.heap.push(atom_as_cell!(atom!("="), 2)); + self.heap.push(atom_as_cell!(name)); + self.heap.push(value); } - let attrs = Addr::HeapCell(self.heap.to_list(avec.into_iter())); + + let attrs = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, avec.into_iter()) + ); let mut cvec = Vec::new(); + for child in node.children() { cvec.push(self.html_node_to_term(indices, child)); } - let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter())); - let chars = clause_name!(String::from(name), self.atom_tbl); - let tag = self.heap.to_unifiable(HeapCellValue::Atom(chars, None)); + let children = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, cvec.into_iter()) + ); - let result = Addr::HeapCell(self.heap.h()); + let tag = self.atom_tbl.build_with(name); + let result = heap_loc_as_cell!(self.heap.len()); - self.heap - .push(HeapCellValue::NamedStr(3, clause_name!("element"), None)); - self.heap.push(HeapCellValue::Addr(tag)); - self.heap.push(HeapCellValue::Addr(attrs)); - self.heap.push(HeapCellValue::Addr(children)); + self.heap.push(atom_as_cell!(atom!("element"), 3)); + self.heap.push(atom_as_cell!(tag)); + self.heap.push(attrs); + self.heap.push(children); result } @@ -5808,3 +5549,4 @@ impl hkdf::KeyType for MyKey { self.0 } } + diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs index e55a5499..a1d38271 100644 --- a/src/machine/term_stream.rs +++ b/src/machine/term_stream.rs @@ -1,48 +1,53 @@ -use prolog_parser::ast::*; -use prolog_parser::parser::*; - -use crate::machine::machine_errors::CompilationError; +use crate::forms::*; use crate::machine::*; +use crate::machine::load_state::*; +use crate::machine::loader::*; +use crate::machine::machine_errors::*; +use crate::parser::ast::*; +use crate::parser::parser::*; + +use crate::predicate_queue; use indexmap::IndexSet; use std::collections::VecDeque; use std::fmt; -pub(crate) trait TermStream: Sized { - type Evacuable; +pub struct LoadStatePayload { + pub term_stream: TS, + pub(super) compilation_target: CompilationTarget, + pub(super) retraction_info: RetractionInfo, + pub(super) module_op_exports: ModuleOpExports, + pub(super) non_counted_bt_preds: IndexSet, + pub(super) predicates: PredicateQueue, + pub(super) clause_clauses: Vec<(Term, Term)>, +} +pub trait TermStream: Sized { fn next(&mut self, op_dir: &CompositeOpDir) -> Result; fn eof(&mut self) -> Result; fn listing_src(&self) -> &ListingSource; - fn evacuate<'a>(loader: Loader<'a, Self>) -> Result; } #[derive(Debug)] -pub(super) struct BootstrappingTermStream<'a> { +pub struct BootstrappingTermStream<'a> { listing_src: ListingSource, - parser: Parser<'a, Stream>, + pub(super) parser: Parser<'a, Stream>, } impl<'a> BootstrappingTermStream<'a> { #[inline] - pub(super) fn from_prolog_stream( - stream: &'a mut PrologStream, - atom_tbl: TabledData, - flags: MachineFlags, + pub(super) fn from_char_reader( + stream: Stream, + machine_st: &'a mut MachineState, listing_src: ListingSource, ) -> Self { - let parser = Parser::new(stream, atom_tbl, flags); - Self { - parser, - listing_src, - } + let parser = Parser::new(stream, machine_st); + Self { parser, listing_src } } } impl<'a> TermStream for BootstrappingTermStream<'a> { - type Evacuable = CompilationTarget; - #[inline] fn next(&mut self, op_dir: &CompositeOpDir) -> Result { self.parser.reset(); @@ -61,24 +66,9 @@ impl<'a> TermStream for BootstrappingTermStream<'a> { fn listing_src(&self) -> &ListingSource { &self.listing_src } - - fn evacuate(mut loader: Loader) -> Result { - if !loader.predicates.is_empty() { - loader.compile_and_submit()?; - } - - loader - .load_state - .retraction_info - .reset(loader.load_state.wam.code_repo.code.len()); - - loader.load_state.remove_module_op_exports(); - - Ok(loader.load_state.compilation_target.take()) - } } -pub(crate) struct LiveTermStream { +pub struct LiveTermStream { pub(super) term_queue: VecDeque, pub(super) listing_src: ListingSource, } @@ -93,28 +83,18 @@ impl LiveTermStream { } } -pub(crate) struct LoadStatePayload { - pub(super) term_stream: LiveTermStream, - pub(super) compilation_target: CompilationTarget, - pub(super) retraction_info: RetractionInfo, - pub(super) module_op_exports: Vec<(OpDecl, Option<(usize, Specifier)>)>, - pub(super) non_counted_bt_preds: IndexSet, - pub(super) predicates: PredicateQueue, - pub(super) clause_clauses: Vec<(Term, Term)>, -} - -impl fmt::Debug for LoadStatePayload { +impl fmt::Debug for LoadStatePayload { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "LoadStatePayload") } } -impl LoadStatePayload { - pub(super) fn new(wam: &Machine) -> Self { +impl LoadStatePayload { + pub(super) fn new(code_repo_len: usize, term_stream: TS) -> Self { Self { - term_stream: LiveTermStream::new(ListingSource::User), + term_stream, compilation_target: CompilationTarget::default(), - retraction_info: RetractionInfo::new(wam.code_repo.code.len()), + retraction_info: RetractionInfo::new(code_repo_len), module_op_exports: vec![], non_counted_bt_preds: IndexSet::new(), predicates: predicate_queue![], @@ -124,8 +104,6 @@ impl LoadStatePayload { } impl TermStream for LiveTermStream { - type Evacuable = LoadStatePayload; - #[inline] fn next(&mut self, _: &CompositeOpDir) -> Result { Ok(self.term_queue.pop_front().unwrap()) @@ -140,9 +118,4 @@ impl TermStream for LiveTermStream { fn listing_src(&self) -> &ListingSource { &self.listing_src } - - #[inline] - fn evacuate(loader: Loader) -> Result { - Ok(loader.to_load_state_payload()) - } } diff --git a/src/macros.rs b/src/macros.rs index b8b6d802..1b459928 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -13,53 +13,421 @@ macro_rules! count_tt { ($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 }; } -macro_rules! functor { - ($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({ - { - #[allow(unused_variables, unused_mut)] - let mut addendum = Heap::new(); - let arity = count_tt!($($dt) +); - let aux_lens = [$($aux.len()),*]; +macro_rules! char_as_cell { + ($c: expr) => { + HeapCellValue::build_with(HeapCellValueTag::Char, $c as u64) + }; +} - let mut result = - vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)), - $(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ]; +macro_rules! fixnum_as_cell { + ($n: expr) => { + HeapCellValue::from_bytes($n.into_bytes()) //HeapCellValueTag::Fixnum, $n.get_num() as u64) + }; +} - $( - result.extend($aux.into_iter()); - )* +macro_rules! cell_as_fixnum { + ($cell:expr) => { + Fixnum::from_bytes($cell.into_bytes()) + }; +} - result.extend(addendum.into_iter()); - result +macro_rules! integer_as_cell { + ($n: expr) => {{ + match $n { + Number::Float(_) => unreachable!(), + Number::Fixnum(n) => fixnum_as_cell!(n), + Number::Rational(r) => typed_arena_ptr_as_cell!(r), + Number::Integer(n) => typed_arena_ptr_as_cell!(n), } + }}; +} + +macro_rules! empty_list_as_cell { + () => { + // the empty list atom has the fixed index of 8 (8 >> 3 == 1 in the condensed atom representation). + atom_as_cell!(atom!("[]")) + }; +} + +macro_rules! atom_as_cell { + ($atom:expr) => { + HeapCellValue::from_bytes( + AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::Atom).into_bytes(), + ) + }; + ($atom:expr, $arity:expr) => { + HeapCellValue::from_bytes( + AtomCell::build_with($atom.flat_index(), $arity as u16, HeapCellValueTag::Atom) + .into_bytes(), + ) + }; +} + +macro_rules! cell_as_ossified_op_dir { + ($cell:expr) => {{ + let ptr_u64 = cell_as_untyped_arena_ptr!($cell); + TypedArenaPtr::new(ptr_u64.payload_offset() as *mut OssifiedOpDir) + }}; +} + +macro_rules! cell_as_string { + ($cell:expr) => { + PartialString::from(cell_as_atom!($cell)) + }; +} + +macro_rules! cell_as_atom { + ($cell:expr) => {{ + let cell = AtomCell::from_bytes($cell.into_bytes()); + let name = cell.get_index() << 3; + + Atom::from(name as usize) + }}; +} + +macro_rules! cell_as_atom_cell { + ($cell:expr) => { + AtomCell::from_bytes($cell.into_bytes()) + }; +} + +macro_rules! cell_as_f64_ptr { + ($cell:expr) => {{ + let ptr_u64 = ConsPtr::from_bytes($cell.into_bytes()); + F64Ptr(TypedArenaPtr::new( + ptr_u64.as_ptr() as *mut OrderedFloat + )) + }}; +} + +macro_rules! cell_as_untyped_arena_ptr { + ($cell:expr) => { + UntypedArenaPtr::from(u64::from($cell) as *const ArenaHeader) + }; +} + +macro_rules! pstr_as_cell { + ($atom:expr) => { + HeapCellValue::from_bytes( + AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::PStr).into_bytes(), + ) + }; +} + +macro_rules! pstr_loc_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::PStrLoc, $h as u64) + }; +} + +macro_rules! pstr_offset_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::PStrOffset, $h as u64) + }; +} + +macro_rules! list_loc_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::Lis, $h as u64) + }; +} + +macro_rules! str_loc_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::Str, $h as u64) + }; +} + +macro_rules! stack_loc { + (OrFrame, $b:expr, $idx:expr) => ({ + $b + prelude_size::() + $idx * std::mem::size_of::() }); - ($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+]) => ({ - { - #[allow(unused_variables, unused_mut)] - let mut addendum = Heap::new(); - let arity = count_tt!($($dt) +); + (AndFrame, $e:expr, $idx:expr) => ({ + $e + prelude_size::() + ($idx - 1) * std::mem::size_of::() + }); +} - let mut result = - vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)), - $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]; +macro_rules! stack_loc_as_cell { + (OrFrame, $b:expr, $idx:expr) => { + stack_loc_as_cell!(stack_loc!(OrFrame, $b, $idx)) + }; + (AndFrame, $b:expr, $idx:expr) => { + stack_loc_as_cell!(stack_loc!(AndFrame, $b, $idx)) + }; + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::StackVar, $h as u64) + }; +} - result.extend(addendum.into_iter()); - result +#[macro_export] +macro_rules! heap_loc_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::Var, $h as u64) + }; +} + +macro_rules! attr_var_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::AttrVar, $h as u64) + }; +} + +#[allow(unused)] +macro_rules! attr_var_loc_as_cell { + ($h:expr) => { + HeapCellValue::build_with(HeapCellValueTag::AttrVar, $h as u64) + }; +} + +macro_rules! typed_arena_ptr_as_cell { + ($ptr:expr) => { + untyped_arena_ptr_as_cell!($ptr.header_ptr()) + }; +} + +macro_rules! untyped_arena_ptr_as_cell { + ($ptr:expr) => { + HeapCellValue::from_bytes(unsafe { std::mem::transmute($ptr) }) + }; +} + +macro_rules! atom_as_cstr_cell { + ($atom:expr) => {{ + let offset = $atom.flat_index(); + + HeapCellValue::from_bytes( + AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(), + ) + }}; +} + +macro_rules! string_as_cstr_cell { + ($ptr:expr) => {{ + let atom: Atom = $ptr.into(); + let offset = atom.flat_index(); + + HeapCellValue::from_bytes( + AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(), + ) + }}; +} + +macro_rules! string_as_pstr_cell { + ($ptr:expr) => {{ + let atom: Atom = $ptr.into(); + let offset = atom.flat_index(); + + HeapCellValue::from_bytes( + AtomCell::build_with(offset as u64, 0, HeapCellValueTag::PStr).into_bytes(), + ) + }}; +} + +macro_rules! stream_as_cell { + ($ptr:expr) => { + untyped_arena_ptr_as_cell!($ptr.as_ptr()) + }; +} + +macro_rules! cell_as_stream { + ($cell:expr) => {{ + let ptr = cell_as_untyped_arena_ptr!($cell); + Stream::from_tag(ptr.get_tag(), ptr.payload_offset()) + }}; +} + +macro_rules! cell_as_load_state_payload { + ($cell:expr) => { unsafe { + let ptr = cell_as_untyped_arena_ptr!($cell); + let ptr = std::mem::transmute::<_, *mut LiveLoadState>(ptr.payload_offset()); + + TypedArenaPtr::new(ptr) + }}; +} + +macro_rules! match_untyped_arena_ptr_pat_body { + ($ptr:ident, Integer, $n:ident, $code:expr) => {{ + let payload_ptr = unsafe { std::mem::transmute::<_, *mut Integer>($ptr.payload_offset()) }; + let $n = TypedArenaPtr::new(payload_ptr); + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, F64, $n:ident, $code:expr) => {{ + let payload_ptr = + unsafe { std::mem::transmute::<_, *mut OrderedFloat>($ptr.payload_offset()) }; + let $n = TypedArenaPtr::new(payload_ptr); + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, Rational, $n:ident, $code:expr) => {{ + let payload_ptr = unsafe { std::mem::transmute::<_, *mut Rational>($ptr.payload_offset()) }; + let $n = TypedArenaPtr::new(payload_ptr); + #[allow(unused_braces)] + $code + }}; + ($cell:ident, OssifiedOpDir, $n:ident, $code:expr) => {{ + let $n = cell_as_ossified_op_dir!($cell); + #[allow(unused_braces)] + $code + }}; + ($cell:ident, LiveLoadState, $n:ident, $code:expr) => {{ + let $n = cell_as_load_state_payload!($cell); + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, Stream, $s:ident, $code:expr) => {{ + let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset()); + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, TcpListener, $listener:ident, $code:expr) => {{ + let payload_ptr = unsafe { std::mem::transmute::<_, *mut TcpListener>($ptr.payload_offset()) }; + #[allow(unused_mut)] + let mut $listener = TypedArenaPtr::new(payload_ptr); + #[allow(unused_braces)] + $code + }}; + ($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{ + let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset()); + #[allow(unused_braces)] + $code + }}; +} + +macro_rules! match_untyped_arena_ptr_pat { + (Stream) => { + ArenaHeaderTag::InputFileStream + | ArenaHeaderTag::OutputFileStream + | ArenaHeaderTag::NamedTcpStream + | ArenaHeaderTag::NamedTlsStream + | ArenaHeaderTag::ReadlineStream + | ArenaHeaderTag::StaticStringStream + | ArenaHeaderTag::ByteStream + | ArenaHeaderTag::NullStream + | ArenaHeaderTag::StandardOutputStream + | ArenaHeaderTag::StandardErrorStream + }; + ($tag:ident) => { + ArenaHeaderTag::$tag + }; +} + +macro_rules! match_untyped_arena_ptr { + ($ptr:expr, $( ($(ArenaHeaderTag::$tag:tt)|+, $n:ident) => $code:block $(,)?)+ $(_ => $misc_code:expr $(,)?)?) => ({ + let ptr_id = $ptr; + + match ptr_id.get_tag() { + $($(match_untyped_arena_ptr_pat!($tag) => { + match_untyped_arena_ptr_pat_body!(ptr_id, $tag, $n, $code) + })+)+ + $(_ => $misc_code)? + } + }); +} + +macro_rules! read_heap_cell_pat_body { + ($cell:ident, Cons, $n:ident, $code:expr) => ({ + let $n = cell_as_untyped_arena_ptr!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, F64, $n:ident, $code:expr) => ({ + let $n = cell_as_f64_ptr!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, Atom, ($name:ident, $arity:ident), $code:expr) => ({ + let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity(); + #[allow(unused_braces)] + $code + }); + ($cell:ident, PStr, $atom:ident, $code:expr) => ({ + let $atom = cell_as_atom!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, CStr, $atom:ident, $code:expr) => ({ + let $atom = cell_as_atom!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, CStr | PStr, $atom:ident, $code:expr) => ({ + let $atom = cell_as_atom!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, PStr | CStr, $atom:ident, $code:expr) => ({ + let $atom = cell_as_atom!($cell); + #[allow(unused_braces)] + $code + }); + ($cell:ident, Fixnum, $value:ident, $code:expr) => ({ + let $value = Fixnum::from_bytes($cell.into_bytes()); + #[allow(unused_braces)] + $code + }); + ($cell:ident, Char, $value:ident, $code:expr) => ({ + let $value = unsafe { char::from_u32_unchecked($cell.get_value() as u32) }; + #[allow(unused_braces)] + $code + }); + ($cell:ident, $($tags:tt)|+, $value:ident, $code:expr) => ({ + let $value = $cell.get_value() as usize; + #[allow(unused_braces)] + $code + }); +} + +macro_rules! read_heap_cell_pat { + (($(HeapCellValueTag::$tag:tt)|+, $n:tt)) => { + $(HeapCellValueTag::$tag)|+ + }; + (($(HeapCellValueTag::$tag:tt)|+)) => { + $(HeapCellValueTag::$tag)|+ + }; + (_) => { _ }; +} + +macro_rules! read_heap_cell_pat_expander { + ($cell_id:ident, ($(HeapCellValueTag::$tag:tt)|+, $n:tt), $code:block) => ({ + read_heap_cell_pat_body!($cell_id, $($tag)|+, $n, $code) + }); + ($cell_id:ident, ($(HeapCellValueTag::$tag:tt)|+), $code:block) => ({ + $code + }); + ($cell_id:ident, _, $code:block) => ({ + $code + }); +} + +macro_rules! read_heap_cell { + ($cell:expr, $($pat:tt $(if $guard_expr:expr)? => $code:block $(,)?)+) => ({ + let cell_id = $cell; + + match cell_id.get_tag() { + $(read_heap_cell_pat!($pat) $(if $guard_expr)? => { + read_heap_cell_pat_expander!(cell_id, $pat, $code) + })+ } }); +} + +macro_rules! functor { ($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({ { #[allow(unused_variables, unused_mut)] let mut addendum = Heap::new(); - let arity = count_tt!($($dt) +); - let aux_lens = [$($aux.len()),*]; + let arity: usize = count_tt!($($dt) +); + + #[allow(unused_variables)] + let aux_lens: [usize; count_tt!($($aux) *)] = [$($aux.len()),*]; let mut result = - vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None), + vec![ atom_as_cell!($name, arity as u16), $(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ]; $( - result.extend($aux.into_iter()); + result.extend($aux.iter()); )* result.extend(addendum.into_iter()); @@ -68,143 +436,126 @@ macro_rules! functor { }); ($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({ { - use crate::machine::heap::*; + let arity: usize = count_tt!($($dt) +); - let arity = count_tt!($($dt) +); #[allow(unused_variables, unused_mut)] let mut addendum = Heap::new(); let mut result = - vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None), + vec![ atom_as_cell!($name, arity as u16), $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ]; result.extend(addendum.into_iter()); result } }); - ($name:expr, $fixity:expr) => ( - vec![ HeapCellValue::Atom(clause_name!($name), Some($fixity)) ] - ); - (clause_name($name:expr)) => ( - vec![ HeapCellValue::Atom($name, None) ] - ); - ($name:expr) => ( - vec![ HeapCellValue::Atom(clause_name!($name), None) ] - ); + ($name:expr) => ({ + vec![ atom_as_cell!($name) ] + }); } macro_rules! functor_term { - (aux(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - HeapCellValue::Addr(Addr::HeapCell($arity + 1)) + (str(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + str_loc_as_cell!($arity + 1) }); - (aux($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + (str($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ let len: usize = $aux_lens[0 .. $e].iter().sum(); - HeapCellValue::Addr(Addr::HeapCell($arity + 1 + len)) + str_loc_as_cell!($arity + 1 + len) }); - (aux($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1)) + (str($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + str_loc_as_cell!($arity + $h + 1) }); - (aux($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ + (str($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ let len: usize = $aux_lens[0 .. $e].iter().sum(); - HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1 + len)) + str_loc_as_cell!($arity + $h + 1 + len) }); - (addr($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::Addr($e) + (literal($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + HeapCellValue::from($e) ); - (constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - from_constant!($e, $h, $arity, $aux_lens, $addendum) + (integer($e:expr, $arena:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + HeapCellValue::arena_from(Number::arena_from($e, $arena), $arena) ); - (constant($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - from_constant!($e, 0, $arity, $aux_lens, $addendum) - ); - (number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - $e.into() - ); - (integer($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::Integer(Rc::new(Integer::from($e))) + (fixnum($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + fixnum_as_cell!(Fixnum::build_with($e as i64)) ); (indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({ let stub = match $e { - IndexingCodePtr::DynamicExternal(o) => functor!("dynamic_external", [integer(o)]), - IndexingCodePtr::External(o) => functor!("external", [integer(o)]), - IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]), - IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)], + IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]), + IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]), + IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]), + IndexingCodePtr::Fail => { + vec![atom_as_cell!(atom!("fail"))] + }, }; let len: usize = $aux_lens.iter().sum(); - let h = len + $arity + 1 + $addendum.h() + $h; + let h = len + $arity + 1 + $addendum.len() + $h; $addendum.extend(stub.into_iter()); - HeapCellValue::Addr(Addr::HeapCell(h)) + str_loc_as_cell!(h) }); - (clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::Atom($e, None) + (number($arena:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( + HeapCellValue::from(($e, $arena)) ); (atom($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( - HeapCellValue::Atom(clause_name!($e), None) - ); - (value($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ( - $e + atom_as_cell!($e) ); (string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({ let len: usize = $aux_lens.iter().sum(); - let h = len + $arity + 1 + $addendum.h() + $h; + let h = len + $arity + 1 + $addendum.len() + $h; - $addendum.put_complete_string(&$e); + let cell = string_as_pstr_cell!($e); - HeapCellValue::Addr(Addr::PStrLocation(h, 0)) + $addendum.push(cell); + $addendum.push(empty_list_as_cell!()); + + heap_loc_as_cell!(h) }); (boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({ if $e { - functor_term!(atom("true"), $arity, $aux_lens, $addendum) + functor_term!(atom(atom!("true")), $arity, $aux_lens, $addendum) } else { - functor_term!(atom("false"), $arity, $aux_lens, $addendum) + functor_term!(atom(atom!("false")), $arity, $aux_lens, $addendum) } }); - ($e:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ( + (cell($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( $e ); } -macro_rules! from_constant { - ($e:expr, $over_h:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ({ - match $e { - &Constant::Atom(ref name, ref op) => { - HeapCellValue::Atom(name.clone(), op.clone()) - } - &Constant::Char(c) => { - HeapCellValue::Addr(Addr::Char(c)) - } - &Constant::Fixnum(n) => { - HeapCellValue::Addr(Addr::Fixnum(n)) - } - &Constant::Integer(ref n) => { - HeapCellValue::Integer(n.clone()) - } - &Constant::Rational(ref r) => { - HeapCellValue::Rational(r.clone()) - } - &Constant::Float(f) => { - HeapCellValue::Addr(Addr::Float(f)) - } - &Constant::String(ref s) => { - let len: usize = $aux_lens.iter().sum(); - let h = len + $arity + 1 + $addendum.h() + $over_h; +macro_rules! ar_reg { + ($r: expr) => { + ArithmeticTerm::Reg($r) + }; +} - $addendum.put_complete_string(&s); +macro_rules! unmark_cell_bits { + ($e:expr) => {{ + let mut result = $e; - HeapCellValue::Addr(Addr::PStrLocation(h, 0)) - } - &Constant::Usize(u) => { - HeapCellValue::Addr(Addr::Usize(u)) - } - &Constant::EmptyList => { - HeapCellValue::Addr(Addr::EmptyList) - } + result.set_mark_bit(false); + result.set_forwarding_bit(false); + + result + }}; +} + +macro_rules! index_store { + ($code_dir:expr, $op_dir:expr, $modules:expr) => { + IndexStore { + code_dir: $code_dir, + extensible_predicates: ExtensiblePredicates::new(), + local_extensible_predicates: LocalExtensiblePredicates::new(), + global_variables: GlobalVarDir::new(), + meta_predicates: MetaPredicateDir::new(), + modules: $modules, + op_dir: $op_dir, + streams: StreamDir::new(), + stream_aliases: StreamAliasDir::new(), } - }) + }; } macro_rules! is_atom { @@ -358,22 +709,6 @@ macro_rules! dir_entry { }; } -macro_rules! index_store { - ($code_dir:expr, $op_dir:expr, $modules:expr) => { - IndexStore { - code_dir: $code_dir, - extensible_predicates: ExtensiblePredicates::new(), - local_extensible_predicates: LocalExtensiblePredicates::new(), - global_variables: GlobalVarDir::new(), - meta_predicates: MetaPredicateDir::new(), - modules: $modules, - op_dir: $op_dir, - streams: StreamDir::new(), - stream_aliases: StreamAliasDir::new(), - } - }; -} - macro_rules! put_constant { ($lvl:expr, $cons:expr, $r:expr) => { QueryInstruction::PutConstant($lvl, $cons, $r) @@ -408,43 +743,58 @@ macro_rules! discard_result { }; } */ -macro_rules! ar_reg { - ($r: expr) => { - ArithmeticTerm::Reg($r) - }; -} -macro_rules! atom_from { - ($self:expr, $e:expr) => { +macro_rules! try_or_fail { + ($s:expr, $e:expr) => {{ match $e { - Addr::Con(h) if $self.heap.atom_at(h) => { - match &$self.heap[h] { - HeapCellValue::Atom(ref atom, _) => { - atom.clone() - } - _ => { - unreachable!() - } - } - } - Addr::Char(c) => { - clause_name!(c.to_string(), $self.atom_tbl) - } - _ => { - unreachable!() + Ok(val) => val, + Err(msg) => { + $s.throw_exception(msg); + return; } } - } + }}; } -macro_rules! try_or_fail { +macro_rules! try_or_fail_gen { ($s:expr, $e:expr) => {{ match $e { Ok(val) => val, - Err(msg) => { - $s.throw_exception(msg); + Err(msg_fn) => { + let e = msg_fn($s); + $s.throw_exception(e); return; } } }}; } + +macro_rules! unify { + ($machine_st:expr, $($value:expr),*) => {{ + $($machine_st.pdl.push($value);)* + $machine_st.unify() + }}; +} + +macro_rules! unify_fn { + ($machine_st:expr, $($value:expr),*) => {{ + $($machine_st.pdl.push($value);)* + ($machine_st.unify_fn)($machine_st) + }}; +} + +macro_rules! unify_with_occurs_check { + ($machine_st:expr, $($value:expr),*) => {{ + $($machine_st.pdl.push($value);)* + $machine_st.unify_with_occurs_check() + }}; +} + +macro_rules! compare_term_test { + ($machine_st:expr, $e1:expr, $e2:expr) => {{ + $machine_st.pdl.push($e2); + $machine_st.pdl.push($e1); + + $machine_st.compare_term_test() + }}; +} diff --git a/src/parser/ast.rs b/src/parser/ast.rs new file mode 100644 index 00000000..1bbde9c2 --- /dev/null +++ b/src/parser/ast.rs @@ -0,0 +1,631 @@ +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::char_reader::*; +use crate::types::HeapCellValueTag; + +use std::cell::Cell; +use std::fmt; +use std::hash::Hash; +use std::io::{Error as IOError}; +use std::ops::Neg; +use std::rc::Rc; +use std::vec::Vec; + +use rug::{Integer, Rational}; + +use indexmap::IndexMap; +use modular_bitfield::error::OutOfBounds; +use modular_bitfield::prelude::*; + +pub type Specifier = u32; + +pub const MAX_ARITY: usize = 1023; + +pub const XFX: u32 = 0x0001; +pub const XFY: u32 = 0x0002; +pub const YFX: u32 = 0x0004; +pub const XF: u32 = 0x0010; +pub const YF: u32 = 0x0020; +pub const FX: u32 = 0x0040; +pub const FY: u32 = 0x0080; +pub const DELIMITER: u32 = 0x0100; +pub const TERM: u32 = 0x1000; +pub const LTERM: u32 = 0x3000; + +pub const NEGATIVE_SIGN: u32 = 0x0200; + +#[macro_export] +macro_rules! fixnum { + ($wrapper:tt, $n:expr, $arena:expr) => { + Fixnum::build_with_checked($n) + .map(<$wrapper>::Fixnum) + .unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena))) + }; +} + +macro_rules! is_term { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::TERM) != 0 + }; +} + +macro_rules! is_lterm { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::LTERM) != 0 + }; +} + +macro_rules! is_op { + ($x:expr) => { + $x as u32 + & ($crate::parser::ast::XF + | $crate::parser::ast::YF + | $crate::parser::ast::FX + | $crate::parser::ast::FY + | $crate::parser::ast::XFX + | $crate::parser::ast::XFY + | $crate::parser::ast::YFX) + != 0 + }; +} + +macro_rules! is_negate { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::NEGATIVE_SIGN) != 0 + }; +} + +#[macro_export] +macro_rules! is_prefix { + ($x:expr) => { + $x as u32 & ($crate::parser::ast::FX | $crate::parser::ast::FY) != 0 + }; +} + +#[macro_export] +macro_rules! is_postfix { + ($x:expr) => { + $x as u32 & ($crate::parser::ast::XF | $crate::parser::ast::YF) != 0 + }; +} + +#[macro_export] +macro_rules! is_infix { + ($x:expr) => { + ($x as u32 + & ($crate::parser::ast::XFX | $crate::parser::ast::XFY | $crate::parser::ast::YFX)) + != 0 + }; +} + +#[macro_export] +macro_rules! is_xfx { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::XFX) != 0 + }; +} + +#[macro_export] +macro_rules! is_xfy { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::XFY) != 0 + }; +} + +#[macro_export] +macro_rules! is_yfx { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::YFX) != 0 + }; +} + +#[macro_export] +macro_rules! is_yf { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::YF) != 0 + }; +} + +#[macro_export] +macro_rules! is_xf { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::XF) != 0 + }; +} + +#[macro_export] +macro_rules! is_fx { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::FX) != 0 + }; +} + +#[macro_export] +macro_rules! is_fy { + ($x:expr) => { + ($x as u32 & $crate::parser::ast::FY) != 0 + }; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum RegType { + Perm(usize), + Temp(usize), +} + +impl Default for RegType { + fn default() -> Self { + RegType::Temp(0) + } +} + +impl RegType { + pub fn reg_num(self) -> usize { + match self { + RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num, + } + } + + pub fn is_perm(self) -> bool { + matches!(self, RegType::Perm(_)) + } +} + +impl fmt::Display for RegType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + RegType::Perm(val) => write!(f, "Y{}", val), + RegType::Temp(val) => write!(f, "X{}", val), + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum VarReg { + ArgAndNorm(RegType, usize), + Norm(RegType), +} + +impl VarReg { + pub fn norm(self) -> RegType { + match self { + VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg, + } + } +} + +impl fmt::Display for VarReg { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg), + VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg), + VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg), + VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg), + } + } +} + +impl Default for VarReg { + fn default() -> Self { + VarReg::Norm(RegType::default()) + } +} + +#[macro_export] +macro_rules! temp_v { + ($x:expr) => { + $crate::parser::ast::RegType::Temp($x) + }; +} + +#[macro_export] +macro_rules! perm_v { + ($x:expr) => { + $crate::parser::ast::RegType::Perm($x) + }; +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum GenContext { + Head, + Mid(usize), + Last(usize), // Mid & Last: chunk_num +} + +impl GenContext { + pub fn chunk_num(self) -> usize { + match self { + GenContext::Head => 0, + GenContext::Mid(cn) | GenContext::Last(cn) => cn, + } + } +} + +#[bitfield] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct OpDesc { + prec: B11, + spec: B8, + #[allow(unused)] padding: B13, +} + +impl OpDesc { + #[inline] + pub fn build_with(prec: u16, spec: u8) -> Self { + OpDesc::new().with_spec(spec).with_prec(prec) + } + + #[inline] + pub fn get(self) -> (u16, u8) { + (self.prec(), self.spec()) + } + + pub fn set(&mut self, prec: u16, spec: u8) { + self.set_prec(prec); + self.set_spec(spec); + } + + #[inline] + pub fn get_prec(self) -> u16 { + self.prec() + } + + #[inline] + pub fn get_spec(self) -> u8 { + self.spec() + } + + #[inline] + pub fn arity(self) -> usize { + if self.spec() as u32 & (XFX | XFY | YFX) == 0 { + 1 + } else { + 2 + } + } +} + +// name and fixity -> operator type and precedence. +pub type OpDir = IndexMap<(Atom, Fixity), OpDesc>; + +#[derive(Debug, Clone, Copy)] +pub struct MachineFlags { + pub double_quotes: DoubleQuotes, +} + +impl Default for MachineFlags { + fn default() -> Self { + MachineFlags { + double_quotes: DoubleQuotes::default(), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum DoubleQuotes { + Atom, + Chars, + Codes, +} + +impl DoubleQuotes { + pub fn is_chars(self) -> bool { + matches!(self, DoubleQuotes::Chars) + } + + pub fn is_atom(self) -> bool { + matches!(self, DoubleQuotes::Atom) + } + + pub fn is_codes(self) -> bool { + matches!(self, DoubleQuotes::Codes) + } +} + +impl Default for DoubleQuotes { + fn default() -> Self { + DoubleQuotes::Chars + } +} + +pub fn default_op_dir() -> OpDir { + let mut op_dir = OpDir::new(); + + op_dir.insert( + (atom!(":-"), Fixity::In), + OpDesc::build_with(1200, XFX as u8), + ); + op_dir.insert( + (atom!(":-"), Fixity::Pre), + OpDesc::build_with(1200, FX as u8), + ); + op_dir.insert( + (atom!("?-"), Fixity::Pre), + OpDesc::build_with(1200, FX as u8), + ); + op_dir.insert( + (atom!(","), Fixity::In), + OpDesc::build_with(1000, XFY as u8), + ); + + op_dir +} + +#[derive(Debug, Clone)] +pub enum ArithmeticError { + NonEvaluableFunctor(Literal, usize), + UninstantiatedVar, +} + +#[derive(Debug)] +pub enum ParserError { + BackQuotedString(usize, usize), + UnexpectedChar(char, usize, usize), + UnexpectedEOF, + IO(IOError), + IncompleteReduction(usize, usize), + InvalidSingleQuotedCharacter(char), + MissingQuote(usize, usize), + NonPrologChar(usize, usize), + ParseBigInt(usize, usize), + LexicalError(lexical::Error), + Utf8Error(usize, usize), +} + +impl ParserError { + pub fn line_and_col_num(&self) -> Option<(usize, usize)> { + match self { + &ParserError::BackQuotedString(line_num, col_num) + | &ParserError::UnexpectedChar(_, line_num, col_num) + | &ParserError::IncompleteReduction(line_num, col_num) + | &ParserError::MissingQuote(line_num, col_num) + | &ParserError::NonPrologChar(line_num, col_num) + | &ParserError::ParseBigInt(line_num, col_num) + | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)), + _ => None, + } + } + + pub fn as_atom(&self) -> Atom { + match self { + ParserError::BackQuotedString(..) => atom!("back_quoted_string"), + ParserError::UnexpectedChar(..) => atom!("unexpected_char"), + ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"), + ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"), + ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"), + ParserError::IO(_) => atom!("input_output_error"), + ParserError::LexicalError(_) => atom!("lexical_error"), // TODO: ? + ParserError::MissingQuote(..) => atom!("missing_quote"), + ParserError::NonPrologChar(..) => atom!("non_prolog_character"), + ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"), + ParserError::Utf8Error(..) => atom!("utf8_conversion_error"), + } + } +} + +impl From for ParserError { + fn from(e: lexical::Error) -> ParserError { + ParserError::LexicalError(e) + } +} + +impl From for ParserError { + fn from(e: IOError) -> ParserError { + ParserError::IO(e) + } +} + +impl From<&IOError> for ParserError { + fn from(error: &IOError) -> ParserError { + if error.get_ref().filter(|e| e.is::()).is_some() { + ParserError::Utf8Error(0, 0) + } else { + ParserError::IO(error.kind().into()) + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct CompositeOpDir<'a, 'b> { + pub primary_op_dir: Option<&'b OpDir>, + pub secondary_op_dir: &'a OpDir, +} + +impl<'a, 'b> CompositeOpDir<'a, 'b> { + #[inline] + pub fn new(secondary_op_dir: &'a OpDir, primary_op_dir: Option<&'b OpDir>) -> Self { + CompositeOpDir { + primary_op_dir, + secondary_op_dir, + } + } + + #[inline] + pub(crate) fn get(&self, name: Atom, fixity: Fixity) -> Option { + let entry = if let Some(ref primary_op_dir) = &self.primary_op_dir { + primary_op_dir.get(&(name, fixity)) + } else { + None + }; + + entry + .or_else(move || self.secondary_op_dir.get(&(name, fixity))) + .cloned() + } +} + +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub enum Fixity { + In, + Post, + Pre, +} + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Fixnum { + num: B57, + #[allow(unused)] m: bool, + #[allow(unused)] tag: B6, +} + +impl Fixnum { + #[inline] + pub fn build_with(num: i64) -> Self { + Fixnum::new() + .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1)) + .with_tag(HeapCellValueTag::Fixnum as u8) + .with_m(false) + //num as u64).with__m(false) + } + + #[inline] + pub fn build_with_checked(num: i64) -> Result { + const UPPER_BOUND: i64 = (1 << 56) - 1; + const LOWER_BOUND: i64 = -(1 << 56); + + if LOWER_BOUND <= num && num <= UPPER_BOUND { + Ok(Fixnum::new() + .with_m(false) + .with_tag(HeapCellValueTag::Fixnum as u8) + .with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))) //num as u64 & ((1 << 57) - 1))) + } else { + Err(OutOfBounds {}) + } + } + + #[inline] + pub fn get_num(self) -> i64 { + let n = self.num() as i64; + let (n, overflowed) = (n << 7).overflowing_shr(7); // sign-extend the 57-bit signed fixnum. + debug_assert_eq!(overflowed, false); + n + } +} + +impl Neg for Fixnum { + type Output = Self; + + #[inline] + fn neg(self) -> Self::Output { + Fixnum::build_with(-self.get_num()) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Literal { + Atom(Atom), + Char(char), + Fixnum(Fixnum), + Integer(TypedArenaPtr), + Rational(TypedArenaPtr), + Float(F64Ptr), + String(Atom), +} + +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Literal::Atom(ref atom) => { + // if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) { + // write!(f, "'{}'", atom) + // } else { + write!(f, "{}", atom.flat_index()) + // } + } + Literal::Char(c) => write!(f, "'{}'", *c as u32), + Literal::Fixnum(n) => write!(f, "{}", n.get_num()), + Literal::Integer(ref n) => write!(f, "{}", n), + Literal::Rational(ref n) => write!(f, "{}", n), + Literal::Float(ref n) => write!(f, "{}", *n), + Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()), + // Literal::Usize(integer) => write!(f, "u{}", integer), + } + } +} + +impl Literal { + pub fn to_atom(&self, atom_tbl: &mut AtomTable) -> Option { + match self { + Literal::Atom(atom) => Some(atom.defrock_brackets(atom_tbl)), + _ => None, + } + } +} + +#[derive(Debug, Clone)] +pub enum Term { + AnonVar, + Clause(Cell, Atom, Vec), + Cons(Cell, Box, Box), + Literal(Cell, Literal), + PartialString(Cell, Atom, Option>), + Var(Cell, Rc), +} + +impl Term { + pub fn into_literal(self) -> Option { + match self { + Term::Literal(_, c) => Some(c), + _ => None, + } + } + + pub fn first_arg(&self) -> Option<&Term> { + match self { + Term::Clause(_, _, ref terms) => terms.first(), + _ => None, + } + } + + pub fn set_name(&mut self, new_name: Atom) { + match self { + Term::Literal(_, Literal::Atom(ref mut atom)) | Term::Clause(_, ref mut atom, ..) => { + *atom = new_name; + } + _ => {} + } + } + + pub fn name(&self) -> Option { + match self { + &Term::Literal(_, Literal::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => { + Some(*atom) + } + _ => None, + } + } + + pub fn arity(&self) -> usize { + match self { + Term::Clause(_, _, ref child_terms, ..) => child_terms.len(), + _ => 0, + } + } +} + +fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> { + if let Term::Clause(_, ref name, ref mut subterms) = term { + if name == &s && subterms.len() == 2 { + let snd = subterms.pop().unwrap(); + let fst = subterms.pop().unwrap(); + + return Some((fst, snd)); + } + } + + None +} + +pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec { + let mut terms = vec![]; + + while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) { + terms.push(fst); + term = snd; + } + + terms.push(term); + terms +} diff --git a/src/parser/char_reader.rs b/src/parser/char_reader.rs new file mode 100644 index 00000000..9c23371e --- /dev/null +++ b/src/parser/char_reader.rs @@ -0,0 +1,747 @@ +/* + * CharReader is a not entirely redundant flattening/chimera of std's + * BufReader and unicode_reader's CodePoints, introduced to allow + * peekable buffered UTF-8 codepoints and access to the underlying + * reader. + * + * Unlike CodePoints, it doesn't make the reader inaccessible by + * wrapping it a Bytes struct. + * + * Unlike BufReader, its buffer is peekable as a char. + */ + +use smallvec::*; + +use std::error::Error; +use std::fmt; +use std::io; +use std::io::{ErrorKind, IoSliceMut, Read}; +use std::str; + +pub struct CharReader { + inner: R, + buf: SmallVec<[u8;4]>, + pos: usize, +} + +/// An error raised when parsing a UTF-8 byte stream fails. +#[derive(Debug)] +pub struct BadUtf8Error { + /// The bytes that could not be parsed as a code point. + pub bytes: Vec, +} + +impl Error for BadUtf8Error { + fn description(&self) -> &str { + "BadUtf8Error" + } +} + +impl fmt::Display for BadUtf8Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Bad UTF-8: {:?}", self.bytes) + } +} + +impl CharReader { + pub fn new(inner: R) -> CharReader { + Self { + inner, + buf: SmallVec::new(), + pos: 0, + } + } + + #[inline] + pub fn inner(&self) -> &R { + &self.inner + } + + #[inline] + pub fn inner_mut(&mut self) -> &mut R { + &mut self.inner + } +} + +pub trait CharRead { + fn read_char(&mut self) -> Option> { + match self.peek_char() { + Some(Ok(c)) => { + self.consume(c.len_utf8()); + Some(Ok(c)) + } + result => result + } + } + + fn peek_char(&mut self) -> Option>; + fn put_back_char(&mut self, c: char); + fn consume(&mut self, nread: usize); +} + +impl CharReader { + pub fn get_ref(&self) -> &R { + &self.inner + } + + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner + } + + pub fn buffer(&self) -> &[u8] { + &self.buf[self.pos..] + } + + pub fn into_inner(self) -> R { + self.inner + } + + fn reset_buffer(&mut self) { + self.buf.clear(); + self.pos = 0; + } +} + +impl CharReader { + fn refresh_buffer(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.buf.len() { + debug_assert!(self.pos == self.buf.len()); + + self.buf.clear(); + + let mut word = [0u8;4]; + let nread = self.inner.read(&mut word)?; + + self.buf.extend_from_slice(&word[..nread]); + self.pos = 0; + } + + Ok(&self.buf[self.pos..]) + } +} + +impl CharRead for CharReader { + fn peek_char(&mut self) -> Option> { + match self.refresh_buffer() { + Ok(_buf) => {} + Err(e) => return Some(Err(e)), + } + + loop { + let buf = &self.buf[self.pos..]; + + if !buf.is_empty() { + let e = match str::from_utf8(buf) { + Ok(s) => { + let mut chars = s.chars(); + let c = chars.next().unwrap(); + + return Some(Ok(c)); + } + Err(e) => { + e + } + }; + + if buf.len() - e.valid_up_to() >= 4 { + // If we have 4 bytes that still don't make up + // a valid code point, then we have garbage. + + // We have bad data in the buffer. Remove + // leading bytes until either the buffer is + // empty, or we have a valid code point. + + let mut split_point = 1; + let mut badbytes = vec![]; + + loop { + let (bad, rest) = buf.split_at(split_point); + + if rest.is_empty() || str::from_utf8(rest).is_ok() { + badbytes.extend_from_slice(bad); + break; + } + + split_point += 1; + } + + // Raise the error. If we still have data in + // the buffer, it will be returned on the next + // loop. + + return Some(Err(io::Error::new(io::ErrorKind::InvalidData, + BadUtf8Error { bytes: badbytes }))); + } else { + if self.pos >= self.buf.len() { + return None; + } else if self.buf.len() - self.pos >= 4 { + return match str::from_utf8(&self.buf[..e.valid_up_to()]) { + Ok(s) => { + let mut chars = s.chars(); + let c = chars.next().unwrap(); + + Some(Ok(c)) + } + Err(e) => { + let badbytes = self.buf[..e.valid_up_to()].to_vec(); + + Some(Err(io::Error::new(io::ErrorKind::InvalidData, + BadUtf8Error { bytes: badbytes }))) + } + }; + } else { + let buf_len = self.buf.len(); + + for (c, idx) in (self.pos..buf_len).enumerate() { + self.buf[c] = self.buf[idx]; + } + + self.buf.truncate(buf_len - self.pos); + + let buf_len = self.buf.len(); + + let mut word = [0u8;4]; + let word_slice = &mut word[buf_len..4]; + + match self.inner.read(word_slice) { + Err(e) => return Some(Err(e)), + Ok(nread) => { + self.buf.extend_from_slice(&word_slice[0..nread]); + } + } + + self.pos = 0; + } + } + } else { + return None; + } + } + } + + #[inline(always)] + fn put_back_char(&mut self, c: char) { + let src_len = self.buf.len() - self.pos; + debug_assert!(src_len <= 4); + + let c_len = c.len_utf8(); + let mut shifted_slice = [0u8; 4]; + + shifted_slice[0..src_len].copy_from_slice(&self.buf[self.pos .. self.buf.len()]); + + self.buf.resize(c_len, 0); + self.buf.extend_from_slice(&shifted_slice[0..src_len]); + self.pos = 0; + + c.encode_utf8(&mut self.buf[0..c_len]); + } + + #[inline(always)] + fn consume(&mut self, nread: usize) { + self.pos += nread; + } +} + +/* +impl BufReader { + /// Seeks relative to the current position. If the new position lies within the buffer, + /// the buffer will not be flushed, allowing for more efficient seeks. + /// This method does not return the location of the underlying reader, so the caller + /// must track this information themselves if it is required. + #[stable(feature = "bufreader_seek_relative", since = "1.53.0")] + pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { + let pos = self.pos as u64; + if offset < 0 { + if let Some(new_pos) = pos.checked_sub((-offset) as u64) { + self.pos = new_pos as usize; + return Ok(()); + } + } else { + if let Some(new_pos) = pos.checked_add(offset as u64) { + if new_pos <= self.cap as u64 { + self.pos = new_pos as usize; + return Ok(()); + } + } + } + self.seek(SeekFrom::Current(offset)).map(drop) + } +} +*/ + +impl Read for CharReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // // If we don't have any buffered data and we're doing a massive read + // // (larger than our internal buffer), bypass our internal buffer + // // entirely. + // if self.pos == self.cap && buf.len() >= self.buf.len() { + // self.discard_buffer(); + // return self.inner.read(buf); + // } + + let mut inner_buf = self.refresh_buffer()?; + let nread = inner_buf.read(buf)?; + + // let nread = { + // let mut rem = self.fill_buf()?; + // rem.read(buf)? + // }; + + self.consume(nread); + Ok(nread) + } + + // Small read_exacts from a BufReader are extremely common when used with a deserializer. + // The default implementation calls read in a loop, which results in surprisingly poor code + // generation for the common path where the buffer has enough bytes to fill the passed-in + // buffer. + fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> { + if self.buffer().len() >= buf.len() { + buf.copy_from_slice(&self.buffer()[..buf.len()]); + self.consume(buf.len()); + return Ok(()); + } + + while !buf.is_empty() { + match self.read(buf) { + Ok(0) => break, + Ok(n) => { + let tmp = buf; + buf = &mut tmp[n..]; + } + Err(e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + + if !buf.is_empty() { + Err(io::Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer")) + } else { + Ok(()) + } + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum::(); + + if self.pos == self.buf.len() && total_len >= self.buf.len() { + self.reset_buffer(); // self.discard_buffer(); + return self.inner.read_vectored(bufs); + } + + let nread = { + self.refresh_buffer()?; + (&self.buf[self.pos..]).read_vectored(bufs)? + }; + + self.consume(nread); + Ok(nread) + } +} + +/* +#[stable(feature = "rust1", since = "1.0.0")] +impl BufRead for BufReader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.cap { + debug_assert!(self.pos == self.cap); + self.cap = self.inner.read(&mut self.buf)?; + self.pos = 0; + } + Ok(&self.buf[self.pos..self.cap]) + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.cap); + } +} +*/ + +impl fmt::Debug for CharReader +where + R: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("CharReader") + .field("reader", &self.inner) + .field("buf", &format_args!("{}/{}", self.buf.capacity() - self.pos, self.buf.len())) + .finish() + } +} + +/* +#[stable(feature = "rust1", since = "1.0.0")] +impl Seek for BufReader { + /// Seek to an offset, in bytes, in the underlying reader. + /// + /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the + /// position the underlying reader would be at if the `BufReader` had no + /// internal buffer. + /// + /// Seeking always discards the internal buffer, even if the seek position + /// would otherwise fall within it. This guarantees that calling + /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader + /// at the same position. + /// + /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`]. + /// + /// See [`std::io::Seek`] for more details. + /// + /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` + /// where `n` minus the internal buffer length overflows an `i64`, two + /// seeks will be performed instead of one. If the second seek returns + /// [`Err`], the underlying reader will be left at the same position it would + /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. + /// + /// [`std::io::Seek`]: Seek + fn seek(&mut self, pos: SeekFrom) -> io::Result { + let result: u64; + if let SeekFrom::Current(n) = pos { + let remainder = (self.cap - self.pos) as i64; + // it should be safe to assume that remainder fits within an i64 as the alternative + // means we managed to allocate 8 exbibytes and that's absurd. + // But it's not out of the realm of possibility for some weird underlying reader to + // support seeking by i64::MIN so we need to handle underflow when subtracting + // remainder. + if let Some(offset) = n.checked_sub(remainder) { + result = self.inner.seek(SeekFrom::Current(offset))?; + } else { + // seek backwards by our remainder, and then by the offset + self.inner.seek(SeekFrom::Current(-remainder))?; + self.discard_buffer(); + result = self.inner.seek(SeekFrom::Current(n))?; + } + } else { + // Seeking with Start/End doesn't care about our buffer length. + result = self.inner.seek(pos)?; + } + self.discard_buffer(); + Ok(result) + } + + /// Returns the current seek position from the start of the stream. + /// + /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))` + /// but does not flush the internal buffer. Due to this optimization the + /// function does not guarantee that calling `.into_inner()` immediately + /// afterwards will yield the underlying reader at the same position. Use + /// [`BufReader::seek`] instead if you require that guarantee. + /// + /// # Panics + /// + /// This function will panic if the position of the inner reader is smaller + /// than the amount of buffered data. That can happen if the inner reader + /// has an incorrect implementation of [`Seek::stream_position`], or if the + /// position has gone out of sync due to calling [`Seek::seek`] directly on + /// the underlying reader. + /// + /// # Example + /// + /// ```no_run + /// use std::{ + /// io::{self, BufRead, BufReader, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = BufReader::new(File::open("foo.txt")?); + /// + /// let before = f.stream_position()?; + /// f.read_line(&mut String::new())?; + /// let after = f.stream_position()?; + /// + /// println!("The first line was {} bytes long", after - before); + /// Ok(()) + /// } + /// ``` + fn stream_position(&mut self) -> io::Result { + let remainder = (self.cap - self.pos) as u64; + self.inner.stream_position().map(|pos| { + pos.checked_sub(remainder).expect( + "overflow when subtracting remaining buffer size from inner stream position", + ) + }) + } +} +*/ +/* +impl SizeHint for CharReader { + fn lower_bound(&self) -> usize { + self.buffer().len() + } +} +*/ + +#[cfg(test)] +mod tests { + use crate::parser::char_reader::*; + use std::io::Cursor; + + #[test] + fn plain_string() { + let mut read_string = CharReader::new(Cursor::new("a string")); + + for c in "a string".chars() { + assert_eq!(read_string.peek_char().unwrap().ok(), Some(c)); + assert_eq!(read_string.read_char().unwrap().ok(), Some(c)); + } + + assert!(read_string.read_char().is_none()); + } + + #[test] + fn greek_string() { + let mut read_string = CharReader::new(Cursor::new("λέξη")); + + for c in "λέξη".chars() { + assert_eq!(read_string.peek_char().unwrap().ok(), Some(c)); + assert_eq!(read_string.read_char().unwrap().ok(), Some(c)); + } + + assert!(read_string.read_char().is_none()); + } + + #[test] + fn russian_string() { + let mut read_string = CharReader::new(Cursor::new("слово")); + + for c in "слово".chars() { + assert_eq!(read_string.peek_char().unwrap().ok(), Some(c)); + assert_eq!(read_string.read_char().unwrap().ok(), Some(c)); + } + + assert!(read_string.read_char().is_none()); + } + + #[test] + fn greek_lorem_ipsum() { + let lorem_ipsum = "Λορεμ ιπσθμ δολορ σιτ αμετ, οφφενδιτ + εφφιcιενδι σιτ ει, ηαρθμ λεγερε qθαερενδθμ ιθσ νε. Ηασ νο εροσ + σιγνιφερθμqθε, σεδ ετ μθτατ jθστο, ει cθμ ελιγενδι σcριπτορεμ + ρεπρεηενδθντ. Εοσ ατ αμετ μαλισ ελειφενδ. Ιν cθμ εριπθιτ + νομινατι. Θσθ ιν cετεροσ μαιορθμ, μθνερε ατομορθμ ινcιδεριντ θτ + ηασ. Αν ηασ λιβρισ πραεσεντ πατριοqθε, ηινc θτιναμ πριμισ νε + cθμ. Cθ μοδο ερρεμ σcριβεντθρ cθμ. Ει vισ δεcορε μαλορθμ + σεντεντιαε, σεδ νο λιβερ εvερτι μεντιτθμ. Προ φαcερ vολθτπατ + σαπιεντεμ ιν. Cθ εροσ περσεqθερισ πρι, εα ποσσιτ cετεροσ δθο. Πρι + εα μαλισ μθνερε. + + Qθισ jθστο μαλορθμ cθ qθο. Νεc ατ οδιο σολετ μαιεστατισ, νε + φορενσιβθσ σαδιπσcινγ ιθσ, αν qθι ειθσ βρθτε σαπιεντεμ. Cομμθνε + περcιπιτθρ ιθσ αδ, μθνερε δολορθμ ιμπεδιτ ηισ νε. Νεc ετιαμ + προπριαε vιτθπερατα ιν. Σονετ νεμορε ιθσ cθ, ιν αφφερτ ινερμισ + cοτιδιεqθε vισ. + + Ηασ ιδ νονθμυ δοcτθσ cοτιδιεqθε. Σινγθλισ πηιλοσοπηια εξ δθο. Εστ + νο ιραcθνδια cονσεqθθντθρ. Τε διcτασ επιcθρει εφφιcιαντθρ δθο, εοσ + νε νθλλα νομιναvι. Εθμ cθ ελιτρ λιβεραvισσε, σιτ περσεqθερισ + cομπλεcτιτθρ εξ, πονδερθμ σιμιλιqθε ηασ νο. + + Σολθμ ποσσιμ λαβιτθρ εξ ηισ, ει δομινγ εξπετενδισ vελ, διαμ μινιμ + σcριπσεριτ ει περ. Αθδιαμ οcθρρερετ προ εξ, δομινγ vολθπταρια ετ + qθο. Cονσθλ σανcτθσ αccθμσαν νο ιθσ, αδ εαμ αλβθcιθσ + ηονεστατισ. Ετ vιξ φαcιλισ qθαλισqθε ερροριβθσ, ηισ εθ πθρτο + ασσεντιορ. Ιθσ βονορθμ ηονεστατισ σcριπσεριτ ατ, ιν ναμ εσσε μοvετ + γραεcο. Αθγθε cονσεcτετθερ εστ ατ. + + Αδ ταλε σθασ μθνερε σεδ, vισ φεθγαιτ αντιοπαμ ιδ. Προ εθ ινερμισ + σαλθτατθσ, σαεπε qθαεστιο θρβανιτασ cθ περ. Ιν μαλορθμ σαλθτατθσ + δετερρθισσετ περ, νε παρτεμ vολθτπατ ινστρθcτιορ vιξ. Νο vισ + δεμοcριτθμ εφφιcιαντθρ, επιcθρει αδολεσcενσ εστ cθ, ιδ vιξ + λθcιλιθσ αδιπισcινγ. Σεα τε cλιτα ιραcθνδια. Σεα αν σιμθλ + εσσεντ. Vοcιβθσ ελειφενδ cονσεqθθντθρ περ αδ, αν ναμ πονδερθμ + vολθπταρια. + + Λιβερ ερθδιτι αccθσαμθσ θτ ναμ. Σιτ αντιοπαμ γθβεργρεν νε. Αμετ + ανcιλλαε ετ qθι, μεα σολθμ λαθδεμ εα. Εθ μελ παρτεμ οβλιqθε + πηαεδρθμ. Εξ μελ jθστο αccομμοδαρε, νε νολθισσε σινγθλισ σενσιβθσ + cθμ, vισ εθ τιμεαμ αδιπισcινγ. + + Τε νολθισσε vολθπτατθμ εστ. Ασσθμ νομιναvι πρι νε, ει νοστρθμ + επιcθρει μεα. Σεδ cθ ελιτ δεσερθντ, γραεcε ερροριβθσ προ θτ, περ + νε εθισμοδ vολθπταρια. Νο εθμ διcατ ποσσιμ, νεc πρινcιπεσ + cονcεπταμ νε. Εθ αππαρεατ ιντελλεγατ σεα. Μελ θτ ελιτ λαθδεμ, θσθ + δολορεμ cομπλεcτιτθρ ετ, νε μεα δολορεσ μολεστιαε. + + Θσθ λεγενδοσ vολθπτατιβθσ cθ. Qθο νε αδηθc ρεφερρεντθρ, αλια + μεδιοcρεμ δθο νε, σεδ ερρεμ δολορθμ αccομμοδαρε νε. Ετιαμ εqθιδεμ + δετερρθισσετ cθ μει, ετ εροσ cετεροσ σεα, εξ vιξ ενιμ cασε + δετραξιτ. Σεδ σολθτα λιβρισ ειρμοδ τε, νοvθμ ποπθλο νε εθμ. Σθμμο + αδμοδθμ δεσερθντ εστ εξ, εστ διcαμ εqθιδεμ cθ. + + Ιλλθμ cορπορα ινvιδθντ εαμ ετ. Σεδ μαλισ ταcιματεσ εvερτιτθρ εα, + μαζιμ νθλλαμ vοcιβθσ μεα ει. Μεα ορνατθσ λθπτατθμ αδιπισcινγ + αδ. Μεα αφφερτ νοστερ ατ, ναμ αν σολεατ ερροριβθσ. Εξ σεα αεqθε + μθνερε cετερο, εοσ ηινc ελειφενδ δεμοcριτθμ."; + + let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum)); + + for c in lorem_ipsum.chars() { + assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c)); + assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c)); + } + + assert!(lorem_ipsum_reader.read_char().is_none()); + } + + #[test] + fn armenian_lorem_ipsum() { + let lorem_ipsum = "լոռեմ իպսում դոլոռ սիթ ամեթ, նովում գռաեծո + սեա եա, աբհոռռեանթ դիսպութանդո եի քուի. իդ քուոդ ինդոծթում + եսթ, մեա թե ծոմմոդո ծոռպոռա. եթ ծոնսուլ ադիպիսծինգ ռեֆոռմիդանս + պեռ, ինեռմիս ֆեուգաիթ նո քուո, թալե սալե պռո եա. եթ նիբհ + աուգուե վոլումուս դուո, նե ծում եխեռծի սալութաթուս գլոռիաթուռ, + ծու թաթիոն պռաեսենթ մեդիոծռեմ վիս. + + վիխ եռոս ռեֆեռռենթուռ եու. պեռսիուս վիթուպեռաթոռիբուս ութ սեա, + վիդե ինվիդունթ պռոբաթուս նո քուո. մեի եռոս մելիուս նոմինավի + իդ, ութ պռո քուաս քուաեսթիո. եթ նաթում պեթենթիում սուավիթաթե + հիս. քուի ծոնսթիթութո մեդիոծռիթաթեմ թե. ծեթեռո դեթռածթո + ծոնծեպթամ սեա եթ. դիսսենթիեթ ելոքուենթիամ թհեոպհռասթուս նեծ + աթ, աթ ֆածեթե եռիպուիթ վիխ. + + ասսուեվեռիթ սծռիպսեռիթ եսթ եթ, վիդիթ դեբեթ եվեռթի եխ + եսթ. աութեմ լաուդեմ պոսիդոնիում մեի եի. ռեբում դիծամ ծեթեռոս + եում ծու. նիհիլ եխպեթենդա ասսուեվեռիթ ուսու ան. ւիսի թաթիոն + դելենիթ նո իուս, սեդ եխ իդքուե սիգնիֆեռումքուե, բռութե զռիլ + ալբուծիուս ան պռի. + + մովեթ իռիուռե սալութանդի պեռ նո, եի ոմնիս աֆֆեռթ պեռսեքուեռիս + իուս, եթ պռաեսենթ մալուիսսեթ եսթ. եսթ պռոբո գուբեռգռեն եթ, հաս + ին դիամ նումքուամ. ֆեուգաիթ ինվենիռե ռեպուդիանդաե աթ սեդ, + իուվառեթ ծոնսուլաթու եֆֆիծիանթուռ ուսու եի. ութ մեա ածծումսան + նոմինավի թինծիդունթ, մեի դիծթա ածծումսան ութ. վիմ ոմնիում + ելիգենդի սծռիպթոռեմ եու. + + իդ վիս եռռոռ ալիքուիպ ելոքուենթիամ, ադ դելենիթի պեռծիպիթ + դեֆինիթիոնես իուս. վիմ իուդիծո դեմոծռիթում ծոմպռեհենսամ թե, + ութ նիհիլ լոբոռթիս վոլուպթաթիբուս վել, դիծունթ մենթիթում + ֆածիլիսիս եի եում. եսսե սալե մինիմ եոս նե. ագամ ոմնեսքուե ծում + ին. + + իուվառեթ իուդիծաբիթ ծում աթ, ուսու նիբհ աթքուի դոմինգ եխ. եի + քուի սանծթուս սենսիբուս, նամ ուբիքուե ապպեթեռե պռոդեսսեթ + եու. ուսու եթ աուգուե ծոնվենիռե սծռիբենթուռ. ան ոմնիում վեռեառ + ութռոքուե դուո, եսթ եի լիբեռ մեդիոծռեմ եխպլիծառի, ոմնիս + աուդիռե թե պռի. վիմ մունեռե սոլեաթ ծու, եռոս ինվենիռե + դիսպութաթիոնի եի քուո, ան ալթեռա պութենթ լաբոռես պռո. անթիոպամ + դեմոծռիթում պեռ ին. + + նե քուի ծիբո ելիթռ. նեծ նե լիբեռ վոլուպթուա. նիսլ ծոմմունե + եխպեթենդիս նամ եխ, իուդիծո պլածեռաթ պեռծիպիթուռ մել նո, եթ + պառթեմ պութանթ քուի. վիմ թինծիդունթ ածծոմմոդառե աթ, նե նամ + վիդիթ իռիուռե, պռո եա ելիգենդի պոսթուլանթ ծոնսթիթութո. + + մել ութ ոդիո նուլլամ եխպլիծառի. պռոպռիաե թինծիդունթ + դելիծաթիսսիմի եամ ան, մոդո քուոդսի ապեռիռի եու եսթ, պեռ աթ + լաբոռես սենսեռիթ. վիմ ծոնգուե ռեպուդիանդաե եի, նեծ ագամ + դիծունթ դելիծաթիսսիմի աթ. պոսսիթ լիբեռավիսսե եոս եու. + + աթ ալիա դեբեթ ելաբոռառեթ քուո, ին ալիի ածծումսան ծոնսթիթուամ + հաս, մել թոթա ոմիթթանթուռ ինսթռուծթիոռ նո. պեռ նե ծաուսաե + սապիենթեմ, պաուլո ոմնեսքուե եի քուո, եխ ոռաթիո պհիլոսոպհիա + սիթ. իգնոթա ծաուսաե աթ ուսու, եխ քուո դիծթաս քուոդսի + ռեպուդիառե. ծոռպոռա պռոդեսսեթ ռեֆեռռենթուռ եոս եխ. + + եու եթիամ ելեիֆենդ մել, սալե սծռիպսեռիթ հիս եու. պոռռո + ադոլեսծենս մեի եա. ին մեա զռիլ պռոբաթուս սալութաթուս. եոս ադ + մինիմ թեմպոռիբուս. սեա նե եթիամ."; + + let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum)); + + for c in lorem_ipsum.chars() { + assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c)); + assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c)); + } + + assert!(lorem_ipsum_reader.read_char().is_none()); + } + + #[test] + fn russian_lorem_ipsum() { + let lorem_ipsum = "Лорем ипсум долор сит амет, атяуи дицам еи + сит, ид сеа фацилис елаборарет. Меа еу яуас алияуид, те яуи + саперет аппеллантур. Ех иус диам дицта волуптариа, еу пер + бруте омиттам аццусата. Хис сапиентем губергрен те, яуидам + луптатум персеяуерис ад ест. + + Ан алияуип перицулис нам, нец апериам цотидиеяуе волуптатибус + но. Солум тритани пер ех, меи не одио тритани рецусабо, цу при + веро мелиоре импердиет. Ин граеци индоцтум салутатус нец, диам + сцаевола пертинациа про те. Ут сеа дебитис лаборамус + диссентиас, еи цум яуот лобортис. + + Децоре сингулис вим не. Еос не риденс оффициис, еу нонумы + лабитур еррорибус хас, вел омнис цонституто посидониум но. Вел + персиус фастидии репрехендунт ид. Натум иллум ипсум сит ад, еа + еам новум латине. Еос нолуиссе патриояуе елояуентиам те. + + Стет малис яуаерендум хас ад, прима цотидиеяуе мел ан, + трацтатос десеруиссе нам ех. Ин малорум сусципиантур вим, ех + меа граецо тритани адолесценс. Промпта цонцлусионемяуе нам еи, + дуо ин лаборе алтерум цотидиеяуе. Но елитр промпта сплендиде + еум, аеяуе ассуеверит цонституам яуи ид. Ад тале еррор + интеллегебат хас, ерудити граецис хас не, пер ут лабитур + еуисмод. Те при суммо путант. Про утинам цоммуне урбанитас еа. + + Идяуе репрехендунт еи нам, алии толлит легере нам не, хис еа + виси адверсариум цонцлусионемяуе. Хас ассум омиттам луцилиус + ет, вих цонсул малорум фастидии не, сенсибус ассуеверит дуо + ут. Дуо алиа видит цетеро ат, еа аппареат пертинах вел. Пер + цонституто инцидеринт ин, убияуе риденс сенсерит цум цу. Про + ет цетерос темпорибус, те вел пурто суммо, дуо мунере вертерем + урбанитас ад. Сит оптион елецтрам форенсибус но. Еи татион + сапиентем ест, лаборе сцрипта сингулис но вим, усу еу елигенди + персецути. + + Иус ан елецтрам цонтентионес. Меи атяуи нонумес ут, вел амет + репрехендунт ан, вис еу яуаестио патриояуе. Про синт легере + детрацто ад. Постеа долорем евертитур при ет, вим номинави + принципес ирацундиа ех. Доцтус интеллегебат но нам. Фацете + оффициис нецесситатибус цу меа. + + Промпта симилияуе вис ин. Пер бонорум перицулис аргументум + ад. Еу дицат фацилис губергрен нам, еффициенди цомпрехенсам + хас еу. Инани нонумы усу но, ад цонцептам репудиандае + про. Тота нуллам делицата еа яуо, усу дуис дебет путент еи. + + Вис апериам доценди елояуентиам еа. Ех яуот детрацто + елояуентиам цум, ерос малис дицерет вис ин. Еа цум модус + еяуидем, дебет нуллам ан меи. Алтерум омиттам про ет. + + Яуи ех латине алияуам, ан меи одио нуллам. Ид хас омнис ребум + либрис. Ет убияуе путант дебитис про, ех хис медиоцрем + партиендо, но елит елецтрам дуо. Еу меа сонет номинави + цотидиеяуе. Нам фалли новум минимум еу, перфецто ратионибус + цонституто ад меа. + + Нобис детрацто еам ид, при еу ассум пертинах, те етиам + проприае салутанди яуо. Легимус сусципиантур ет хас, сед + поссит дефинитионес еа. Ест не патриояуе омиттантур + интеллегебат, еу яуо дебет цонцлудатуряуе. Еум ад мнесарчум + дефинитионем, елитр лаборамус перципитур про не, хас феугаит + фастидии луцилиус ид. Фастидии интеллегат ех."; + + let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum)); + + for c in lorem_ipsum.chars() { + assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c)); + assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c)); + + lorem_ipsum_reader.put_back_char(c); + + assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c)); + assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c)); + } + + assert!(lorem_ipsum_reader.read_char().is_none()); + } +} diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs new file mode 100644 index 00000000..d2487666 --- /dev/null +++ b/src/parser/lexer.rs @@ -0,0 +1,1059 @@ +use lexical::parse_lossy; +use ordered_float::*; + +use crate::atom_table::*; +pub use crate::machine::machine_state::*; +use crate::parser::ast::*; +use crate::parser::char_reader::*; +use crate::parser::rug::Integer; + +use std::convert::TryFrom; +use std::fmt; + +macro_rules! is_not_eof { + ($parser:expr, $c:expr) => { + match $c { + Ok('\u{0}') => { + $parser.consume('\u{0}'.len_utf8()); + return Ok(true); + } + Ok(c) => c, + Err($crate::parser::ast::ParserError::UnexpectedEOF) => return Ok(true), + Err(e) => return Err(e), + } + }; +} + +macro_rules! consume_chars_with { + ($token:expr, $e:expr) => { + loop { + match $e { + Ok(Some(c)) => $token.push(c), + Ok(None) => continue, + Err($crate::parser::ast::ParserError::UnexpectedChar(..)) => break, + Err(e) => return Err(e), + } + } + }; +} + +#[derive(Debug, PartialEq)] +pub enum Token { + Literal(Literal), + Var(String), + Open, // '(' + OpenCT, // '(' + Close, // ')' + OpenList, // '[' + CloseList, // ']' + OpenCurly, // '{' + CloseCurly, // '}' + HeadTailSeparator, // '|' + Comma, // ',' + End, +} + +impl Token { + #[inline] + pub(super) fn is_end(&self) -> bool { + if let Token::End = self { + true + } else { + false + } + } +} + +pub struct Lexer<'a, R> { + pub(crate) reader: R, + pub(crate) machine_st: &'a mut MachineState, + pub(crate) line_num: usize, + pub(crate) col_num: usize, +} + +impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Lexer") + .field("reader", &"&'a mut R") // Hacky solution. + .field("line_num", &self.line_num) + .field("col_num", &self.col_num) + .finish() + } +} + +impl<'a, R: CharRead> Lexer<'a, R> { + pub fn new(src: R, machine_st: &'a mut MachineState) -> Self { + Lexer { + reader: src, + machine_st, + line_num: 0, + col_num: 0, + } + } + + pub fn lookahead_char(&mut self) -> Result { + match self.reader.peek_char() { + Some(Ok(c)) => Ok(c), + _ => Err(ParserError::UnexpectedEOF) + } + } + + pub fn read_char(&mut self) -> Result { + match self.reader.read_char() { + Some(Ok(c)) => Ok(c), + _ => Err(ParserError::UnexpectedEOF) + } + } + + #[inline(always)] + fn return_char(&mut self, c: char) { + self.reader.put_back_char(c); + } + + fn skip_char(&mut self, c: char) { + self.reader.consume(c.len_utf8()); + + if new_line_char!(c) { + self.line_num += 1; + self.col_num = 0; + } else { + self.col_num += 1; + } + } + + pub fn eof(&mut self) -> Result { + if self.reader.peek_char().is_none() { + return Ok(true); + } + + let mut c = is_not_eof!(self.reader, self.lookahead_char()); + + while layout_char!(c) { + self.skip_char(c); + + if self.reader.peek_char().is_none() { + return Ok(true); + } + + c = is_not_eof!(self.reader, self.lookahead_char()); + } + + Ok(false) + } + + fn single_line_comment(&mut self) -> Result<(), ParserError> { + loop { + if self.reader.peek_char().is_none() { + break; + } + + let c = self.lookahead_char()?; + self.skip_char(c); + + if new_line_char!(c) { + break; + } + } + + Ok(()) + } + + fn bracketed_comment(&mut self) -> Result { + // we have already checked that the current lookahead_char is + // comment_1_char, just skip it + self.skip_char('/'); + + let c = self.lookahead_char()?; + + if comment_2_char!(c) { + self.skip_char(c); + + // Keep reading until we find characters '*' and '/' + // Deliberately skip checks for prolog_char to allow + // comments to contain any characters, including so-called + // "extended characters", without having to explicitly add + // them to a character class. + + let mut c = self.lookahead_char()?; + + loop { + while !comment_2_char!(c) { + self.skip_char(c); + c = self.lookahead_char()?; + } + + self.skip_char(c); + c = self.lookahead_char()?; + + if comment_1_char!(c) { + break; + } + } + + if prolog_char!(c) { + self.skip_char(c); + Ok(true) + } else { + Err(ParserError::NonPrologChar(self.line_num, self.col_num)) + } + } else { + self.return_char('/'); + Ok(false) + } + } + + fn get_back_quoted_char(&mut self) -> Result { + let c = self.lookahead_char()?; + + if back_quote_char!(c) { + self.skip_char(c); + let c2 = self.lookahead_char()?; + + if !back_quote_char!(c2) { + self.return_char(c); + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + } else { + self.skip_char(c2); + Ok(c2) + } + } else if single_quote_char!(c) { + self.skip_char(c); + self.read_char() + } else { + self.get_non_quote_char() + } + } + + fn get_back_quoted_item(&mut self) -> Result, ParserError> { + let c = self.lookahead_char()?; + + if backslash_char!(c) { + self.skip_char(c); + let c2 = self.lookahead_char()?; + + if new_line_char!(c2) { + self.skip_char(c2); + Ok(None) + } else { + self.return_char(c); + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + } + } else { + self.get_back_quoted_char().map(Some) + } + } + + fn get_back_quoted_string(&mut self) -> Result { + let c = self.lookahead_char()?; + + if back_quote_char!(c) { + self.skip_char(c); + + let mut token = String::with_capacity(16); + consume_chars_with!(token, self.get_back_quoted_item()); + + let c = self.lookahead_char()?; + + if back_quote_char!(c) { + self.skip_char(c); + Ok(token) + } else { + Err(ParserError::MissingQuote(self.line_num, self.col_num)) + } + } else { + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + } + } + + fn get_single_quoted_item(&mut self) -> Result, ParserError> { + let c = self.lookahead_char()?; + + if backslash_char!(c) { + self.skip_char(c); + let c2 = self.lookahead_char()?; + + if new_line_char!(c2) { + self.skip_char(c2); + return Ok(None); + } else { + self.return_char(c); + } + } + + self.get_single_quoted_char().map(Some) + } + + fn get_single_quoted_char(&mut self) -> Result { + let c = self.lookahead_char()?; + + if single_quote_char!(c) { + self.skip_char(c); + let c2 = self.lookahead_char()?; + + if !single_quote_char!(c2) { + self.return_char(c); + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + } else { + self.skip_char(c2); + Ok(c2) + } + } else if double_quote_char!(c) || back_quote_char!(c) { + self.skip_char(c); + Ok(c) + } else { + self.get_non_quote_char() + } + } + + fn get_double_quoted_item(&mut self) -> Result, ParserError> { + let c = self.lookahead_char()?; + + if backslash_char!(c) { + self.skip_char(c); + + let c2 = self.lookahead_char()?; + + if new_line_char!(c2) { + self.skip_char(c2); + return Ok(None); + } else { + self.return_char(c); + } + } + + self.get_double_quoted_char().map(Some) + } + + fn get_double_quoted_char(&mut self) -> Result { + let c = self.lookahead_char()?; + + if double_quote_char!(c) { + self.skip_char(c); + let c2 = self.lookahead_char()?; + + if !double_quote_char!(c2) { + self.return_char(c); + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + } else { + self.skip_char(c2); + Ok(c2) + } + } else if single_quote_char!(c) || back_quote_char!(c) { + self.skip_char(c); + Ok(c) + } else { + self.get_non_quote_char() + } + } + + fn get_control_escape_sequence(&mut self) -> Result { + let c = self.lookahead_char()?; + + let escaped = match c { + 'a' => '\u{07}', // UTF-8 alert + 'b' => '\u{08}', // UTF-8 backspace + 'v' => '\u{0b}', // UTF-8 vertical tab + 'f' => '\u{0c}', // UTF-8 form feed + 't' => '\t', + 'n' => '\n', + 'r' => '\r', + c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)), + }; + + self.skip_char(c); + Ok(escaped) + } + + fn get_octal_escape_sequence(&mut self) -> Result { + self.escape_sequence_to_char(|c| octal_digit_char!(c), 8) + } + + fn get_hexadecimal_escape_sequence(&mut self, start: char) -> Result { + self.skip_char(start); + let c = self.lookahead_char()?; + + if hexadecimal_digit_char!(c) { + self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16) + } else { + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + } + } + + fn escape_sequence_to_char( + &mut self, + accept_char: impl Fn(char) -> bool, + radix: u32, + ) -> Result { + let mut c = self.lookahead_char()?; + let mut token = String::with_capacity(16); + + loop { + token.push(c); + + self.skip_char(c); + c = self.lookahead_char()?; + + if !accept_char(c) { + break; + } + } + + if backslash_char!(c) { + self.skip_char(c); + u32::from_str_radix(&token, radix).map_or_else( + |_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)), + |n| { + char::try_from(n) + .map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num)) + }, + ) + } else { + // on failure, restore the token characters and backslash. + // self.reader.put_back_all(token.chars().map(Ok)); + // self.reader.put_back(Ok('\\')); + + Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)) + } + } + + fn get_non_quote_char(&mut self) -> Result { + let c = self.lookahead_char()?; + + if graphic_char!(c) || alpha_numeric_char!(c) || solo_char!(c) || space_char!(c) { + self.skip_char(c); + Ok(c) + } else { + if !backslash_char!(c) { + return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)); + } + + self.skip_char(c); + let c = self.lookahead_char()?; + + if meta_char!(c) { + self.skip_char(c); + Ok(c) + } else if octal_digit_char!(c) { + self.get_octal_escape_sequence() + } else if symbolic_hexadecimal_char!(c) { + self.get_hexadecimal_escape_sequence(c) + } else { + self.get_control_escape_sequence() + } + } + } + + fn char_code_list_token(&mut self, start: char) -> Result { + let mut token = String::with_capacity(16); + + self.skip_char(start); + consume_chars_with!(token, self.get_double_quoted_item()); + + let c = self.lookahead_char()?; + + if double_quote_char!(c) { + self.skip_char(c); + Ok(token) + } else { + Err(ParserError::MissingQuote(self.line_num, self.col_num)) + } + } + + fn hexadecimal_constant(&mut self, start: char) -> Result { + self.skip_char(start); + let mut c = self.lookahead_char()?; + + if hexadecimal_digit_char!(c) { + let mut token = String::with_capacity(16); + + loop { + if hexadecimal_digit_char!(c) { + self.skip_char(c); + token.push(c); + c = self.lookahead_char()?; + } else { + break; + } + } + + i64::from_str_radix(&token, 16) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + Integer::from_str_radix(&token, 16) + .map(|n| Token::Literal(Literal::Integer( + arena_alloc!(n, &mut self.machine_st.arena) + ))) + .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) + }) + } else { + self.return_char(start); + Err(ParserError::ParseBigInt(self.line_num, self.col_num)) + } + } + + fn octal_constant(&mut self, start: char) -> Result { + self.skip_char(start); + let mut c = self.lookahead_char()?; + + if octal_digit_char!(c) { + let mut token = String::with_capacity(16); + + loop { + if octal_digit_char!(c) { + self.skip_char(c); + token.push(c); + c = self.lookahead_char()?; + } else { + break; + } + } + + i64::from_str_radix(&token, 8) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + Integer::from_str_radix(&token, 8) + .map(|n| Token::Literal(Literal::Integer( + arena_alloc!(n, &mut self.machine_st.arena) + ))) + .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) + }) + } else { + self.return_char(start); + Err(ParserError::ParseBigInt(self.line_num, self.col_num)) + } + } + + fn binary_constant(&mut self, start: char) -> Result { + self.skip_char(start); + let mut c = self.lookahead_char()?; + + if binary_digit_char!(c) { + let mut token = String::with_capacity(16); + + loop { + if binary_digit_char!(c) { + self.skip_char(c); + token.push(c); + c = self.lookahead_char()?; + } else { + break; + } + } + + i64::from_str_radix(&token, 2) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + Integer::from_str_radix(&token, 2) + .map(|n| Token::Literal(Literal::Integer( + arena_alloc!(n, &mut self.machine_st.arena) + ))) + .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) + }) + } else { + self.return_char(start); + Err(ParserError::ParseBigInt(self.line_num, self.col_num)) + } + } + + fn variable_token(&mut self) -> Result { + let mut s = String::with_capacity(16); + s.push(self.read_char()?); + + loop { + let c = self.lookahead_char()?; + + if alpha_numeric_char!(c) { + self.skip_char(c); + s.push(c); + } else { + break; + } + } + + Ok(Token::Var(s)) + } + + fn name_token(&mut self, c: char) -> Result { + let mut token = String::with_capacity(16); + + if small_letter_char!(c) { + self.skip_char(c); + token.push(c); + + loop { + let c = self.lookahead_char()?; + + if alpha_numeric_char!(c) { + self.skip_char(c); + token.push(c); + } else { + break; + } + } + } else if graphic_token_char!(c) { + self.skip_char(c); + token.push(c); + + loop { + let c = self.lookahead_char()?; + + if graphic_token_char!(c) { + self.skip_char(c); + token.push(c); + } else { + break; + } + } + } else if cut_char!(c) { + self.skip_char(c); + token.push(c); + } else if semicolon_char!(c) { + self.skip_char(c); + token.push(c); + } else if single_quote_char!(c) { + self.skip_char(c); + consume_chars_with!(token, self.get_single_quoted_item()); + + let c = self.lookahead_char()?; + + if single_quote_char!(c) { + self.skip_char(c); + + if !token.is_empty() && token.chars().nth(1).is_none() { + if let Some(c) = token.chars().next() { + return Ok(Token::Literal(Literal::Char(c))); + } + } + } else { + return Err(ParserError::InvalidSingleQuotedCharacter(c)); + } + } else { + match self.get_back_quoted_string() { + Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)), + Err(e) => return Err(e), + } + } + + if token.as_str() == "[]" { + Ok(Token::Literal(Literal::Atom(atom!("[]")))) + } else { + Ok(Token::Literal(Literal::Atom( + self.machine_st.atom_tbl.build_with(&token), + ))) + } + } + + fn vacate_with_float(&mut self, mut token: String) -> Result { + self.return_char(token.pop().unwrap()); + + let result = OrderedFloat(parse_lossy::(token.as_bytes())?); + Ok(Token::Literal(Literal::Float(arena_alloc!( + result, + &mut self.machine_st.arena + )))) + } + + fn skip_underscore_in_number(&mut self) -> Result { + let mut c = self.lookahead_char()?; + + if c == '_' { + self.skip_char(c); + self.scan_for_layout()?; + c = self.lookahead_char()?; + + if decimal_digit_char!(c) { + Ok(c) + } else { + Err(ParserError::ParseBigInt(self.line_num, self.col_num)) + } + } else { + Ok(c) + } + } + + pub fn number_token(&mut self, leading_c: char) -> Result { + let mut token = String::with_capacity(16); + + self.skip_char(leading_c); + token.push(leading_c); + let mut c = self.skip_underscore_in_number()?; + + while decimal_digit_char!(c) { + token.push(c); + self.skip_char(c); + c = self.skip_underscore_in_number()?; + } + + if decimal_point_char!(c) { + self.skip_char(c); + + if self.reader.peek_char().is_none() { + self.return_char('.'); + + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + token + .parse::() + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena))) + }) + .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) + }) + } else if decimal_digit_char!(self.lookahead_char()?) { + token.push('.'); + token.push(self.read_char()?); + + let mut c = self.lookahead_char()?; + + while decimal_digit_char!(c) { + token.push(c); + self.skip_char(c); + c = self.lookahead_char()?; + } + + if exponent_char!(c) { + self.skip_char(c); + token.push(c); + + let c = match self.lookahead_char() { + Err(_) => return Ok(self.vacate_with_float(token)?), + Ok(c) => c, + }; + + if !sign_char!(c) && !decimal_digit_char!(c) { + return Ok(self.vacate_with_float(token)?); + } + + if sign_char!(c) { + self.skip_char(c); + token.push(c); + + let c = match self.lookahead_char() { + Err(_) => { + self.return_char(token.pop().unwrap()); + return Ok(self.vacate_with_float(token)?); + } + Ok(c) => c, + }; + + if !decimal_digit_char!(c) { + self.return_char(token.pop().unwrap()); + return Ok(self.vacate_with_float(token)?); + } + } + + let mut c = self.lookahead_char()?; + + if decimal_digit_char!(c) { + self.skip_char(c); + token.push(c); + + loop { + c = self.lookahead_char()?; + + if decimal_digit_char!(c) { + self.skip_char(c); + token.push(c); + } else { + break; + } + } + + let n = OrderedFloat(parse_lossy::(token.as_bytes())?); + Ok(Token::Literal(Literal::Float(arena_alloc!( + n, + &mut self.machine_st.arena + )))) + } else { + return Ok(self.vacate_with_float(token)?); + } + } else { + let n = OrderedFloat(parse_lossy::(token.as_bytes())?); + Ok(Token::Literal(Literal::Float(arena_alloc!( + n, + &mut self.machine_st.arena + )))) + } + } else { + self.return_char('.'); + + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + token + .parse::() + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena))) + }) + .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) + }) + } + } else { + if token.starts_with('0') && token.len() == 1 { + if c == 'x' { + self.hexadecimal_constant(c).or_else(|e| { + if let ParserError::ParseBigInt(..) = e { + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + token + .parse::() + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!( + n, + &mut self.machine_st.arena + ))) + }) + .map_err(|_| { + ParserError::ParseBigInt(self.line_num, self.col_num) + }) + }) + } else { + Err(e) + } + }) + } else if c == 'o' { + self.octal_constant(c).or_else(|e| { + if let ParserError::ParseBigInt(..) = e { + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + token + .parse::() + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!( + n, + &mut self.machine_st.arena + ))) + }) + .map_err(|_| { + ParserError::ParseBigInt(self.line_num, self.col_num) + }) + }) + } else { + Err(e) + } + }) + } else if c == 'b' { + self.binary_constant(c).or_else(|e| { + if let ParserError::ParseBigInt(..) = e { + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + token + .parse::() + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!( + n, + &mut self.machine_st.arena + ))) + }) + .map_err(|_| { + ParserError::ParseBigInt(self.line_num, self.col_num) + }) + }) + } else { + Err(e) + } + }) + } else if single_quote_char!(c) { + self.skip_char(c); + let c = self.lookahead_char()?; + + if backslash_char!(c) { + self.skip_char(c); + let c = self.lookahead_char()?; + + if new_line_char!(c) { + self.skip_char(c); + self.return_char('\''); + + return Ok(Token::Literal(Literal::Fixnum(Fixnum::build_with(0)))); + } else { + self.return_char('\\'); + } + } + + self.get_single_quoted_char() + .map(|c| Token::Literal(Literal::Fixnum(Fixnum::build_with(c as i64)))) + .or_else(|_| { + self.return_char(c); + + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + token + .parse::() + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!( + n, + &mut self.machine_st.arena + ))) + }) + .map_err(|_| { + ParserError::ParseBigInt(self.line_num, self.col_num) + }) + }) + }) + } else { + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + token + .parse::() + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!( + n, + &mut self.machine_st.arena + ))) + }) + .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) + }) + } + } else { + i64::from_str_radix(&token, 10) + .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .or_else(|_| { + token + .parse::() + .map(|n| { + Token::Literal(Literal::Integer(arena_alloc!(n, &mut self.machine_st.arena))) + }) + .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num)) + }) + } + } + } + + pub fn scan_for_layout(&mut self) -> Result { + let mut layout_inserted = false; + let mut more_layout = true; + + loop { + let cr = self.lookahead_char(); + + match cr { + Ok(c) if layout_char!(c) => { + self.skip_char(c); + layout_inserted = true; + } + Ok(c) if end_line_comment_char!(c) => { + self.single_line_comment()?; + layout_inserted = true; + } + Ok(c) if comment_1_char!(c) => { + if self.bracketed_comment()? { + layout_inserted = true; + } else { + more_layout = false; + } + } + _ => more_layout = false, + }; + + if !more_layout { + break; + } + } + + Ok(layout_inserted) + } + + pub fn next_token(&mut self) -> Result { + let layout_inserted = self.scan_for_layout()?; + let cr = self.lookahead_char(); + + match cr { + Ok(c) => { + if capital_letter_char!(c) || variable_indicator_char!(c) { + return self.variable_token(); + } + + if c == ',' { + self.skip_char(c); + return Ok(Token::Comma); + } + + if c == ')' { + self.skip_char(c); + return Ok(Token::Close); + } + + if c == '(' { + self.skip_char(c); + return Ok(if layout_inserted { + Token::Open + } else { + Token::OpenCT + }); + } + + if c == '.' { + self.skip_char(c); + + match self.lookahead_char() { + Ok(c) if layout_char!(c) || c == '%' => { + if new_line_char!(c) { + self.skip_char(c); + } + + return Ok(Token::End); + } + Err(ParserError::UnexpectedEOF) => { + return Ok(Token::End); + } + _ => { + self.return_char('.'); + } + }; + + return self.name_token(c); + } + + if decimal_digit_char!(c) { + return self.number_token(c); + } + + if c == ']' { + self.skip_char(c); + return Ok(Token::CloseList); + } + + if c == '[' { + self.skip_char(c); + return Ok(Token::OpenList); + } + + if c == '|' { + self.skip_char(c); + return Ok(Token::HeadTailSeparator); + } + + if c == '{' { + self.skip_char(c); + return Ok(Token::OpenCurly); + } + + if c == '}' { + self.skip_char(c); + return Ok(Token::CloseCurly); + } + + if c == '"' { + let s = self.char_code_list_token(c)?; + let atom = self.machine_st.atom_tbl.build_with(&s); + + return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes { + Ok(Token::Literal(Literal::Atom(atom))) + } else { + Ok(Token::Literal(Literal::String(atom))) + }; + } + + self.name_token(c) + } + Err(e) => Err(e), + } + } +} diff --git a/src/parser/macros.rs b/src/parser/macros.rs new file mode 100644 index 00000000..6e37f320 --- /dev/null +++ b/src/parser/macros.rs @@ -0,0 +1,253 @@ +#[macro_export] +macro_rules! char_class { + ($c: expr, [$head:expr]) => ($c == $head); + ($c: expr, [$head:expr $(, $cs:expr)+]) => ($c == $head || $crate::char_class!($c, [$($cs),*])); +} + +#[macro_export] +macro_rules! alpha_char { + ($c: expr) => { + match $c { + 'a'..='z' => true, + 'A'..='Z' => true, + '_' => true, + '\u{00A0}'..='\u{00BF}' => true, + '\u{00C0}'..='\u{00D6}' => true, + '\u{00D8}'..='\u{00F6}' => true, + '\u{00F8}'..='\u{00FF}' => true, + '\u{0100}'..='\u{017F}' => true, // Latin Extended-A + '\u{0180}'..='\u{024F}' => true, // Latin Extended-B + '\u{0250}'..='\u{02AF}' => true, // IPA Extensions + '\u{02B0}'..='\u{02FF}' => true, // Spacing Modifier Letters + '\u{0300}'..='\u{036F}' => true, // Combining Diacritical Marks + '\u{0370}'..='\u{03FF}' => true, // Greek/Coptic + '\u{0400}'..='\u{04FF}' => true, // Cyrillic + '\u{0500}'..='\u{052F}' => true, // Cyrillic Supplement + '\u{0530}'..='\u{058F}' => true, // Armenian + '\u{0590}'..='\u{05FF}' => true, // Hebrew + '\u{0600}'..='\u{06FF}' => true, // Arabic + '\u{0700}'..='\u{074F}' => true, // Syriac + _ => false, + } + }; +} + +#[macro_export] +macro_rules! alpha_numeric_char { + ($c: expr) => { + $crate::alpha_char!($c) || $crate::decimal_digit_char!($c) + }; +} + +#[macro_export] +macro_rules! backslash_char { + ($c: expr) => { + $c == '\\' + }; +} + +#[macro_export] +macro_rules! back_quote_char { + ($c: expr) => { + $c == '`' + }; +} + +#[macro_export] +macro_rules! octet_char { + ($c: expr) => { + ('\u{0000}'..='\u{00FF}').contains(&$c) + }; +} + +#[macro_export] +macro_rules! capital_letter_char { + ($c: expr) => { + ('A'..='Z').contains(&$c) + }; +} + +#[macro_export] +macro_rules! comment_1_char { + ($c: expr) => { + $c == '/' + }; +} + +#[macro_export] +macro_rules! comment_2_char { + ($c: expr) => { + $c == '*' + }; +} + +#[macro_export] +macro_rules! cut_char { + ($c: expr) => { + $c == '!' + }; +} + +#[macro_export] +macro_rules! decimal_digit_char { + ($c: expr) => { + ('0'..='9').contains(&$c) + }; +} + +#[macro_export] +macro_rules! decimal_point_char { + ($c: expr) => { + $c == '.' + }; +} + +#[macro_export] +macro_rules! double_quote_char { + ($c: expr) => { + $c == '"' + }; +} + +#[macro_export] +macro_rules! end_line_comment_char { + ($c: expr) => { + $c == '%' + }; +} + +#[macro_export] +macro_rules! exponent_char { + ($c: expr) => { + $c == 'e' || $c == 'E' + }; +} + +#[macro_export] +macro_rules! graphic_char { + ($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':', + '<', '=', '>', '?', '@', '^', '~'])) +} + +#[macro_export] +macro_rules! graphic_token_char { + ($c: expr) => { + $crate::graphic_char!($c) || $crate::backslash_char!($c) + }; +} + +#[macro_export] +macro_rules! hexadecimal_digit_char { + ($c: expr) => { + ('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c) + }; +} + +#[macro_export] +macro_rules! layout_char { + ($c: expr) => { + $crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}']) + }; +} + +#[macro_export] +macro_rules! meta_char { + ($c: expr) => { + $crate::char_class!($c, ['\\', '\'', '"', '`']) + }; +} + +#[macro_export] +macro_rules! new_line_char { + ($c: expr) => { + $c == '\n' + }; +} + +#[macro_export] +macro_rules! octal_digit_char { + ($c: expr) => { + ('0'..='7').contains(&$c) + }; +} + +#[macro_export] +macro_rules! binary_digit_char { + ($c: expr) => { + $c >= '0' && $c <= '1' + }; +} + +#[macro_export] +macro_rules! prolog_char { + ($c: expr) => { + $crate::graphic_char!($c) + || $crate::alpha_numeric_char!($c) + || $crate::solo_char!($c) + || $crate::layout_char!($c) + || $crate::meta_char!($c) + }; +} + +#[macro_export] +macro_rules! semicolon_char { + ($c: expr) => { + $c == ';' + }; +} + +#[macro_export] +macro_rules! sign_char { + ($c: expr) => { + $c == '-' || $c == '+' + }; +} + +#[macro_export] +macro_rules! single_quote_char { + ($c: expr) => { + $c == '\'' + }; +} + +#[macro_export] +macro_rules! small_letter_char { + ($c: expr) => { + ('a'..='z').contains(&$c) + }; +} + +#[macro_export] +macro_rules! solo_char { + ($c: expr) => { + $crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%']) + }; +} + +#[macro_export] +macro_rules! space_char { + ($c: expr) => { + $c == ' ' + }; +} + +#[macro_export] +macro_rules! symbolic_control_char { + ($c: expr) => { + $crate::char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0']) + }; +} + +#[macro_export] +macro_rules! symbolic_hexadecimal_char { + ($c: expr) => { + $c == 'x' + }; +} + +#[macro_export] +macro_rules! variable_indicator_char { + ($c: expr) => { + $c == '_' + }; +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs new file mode 100644 index 00000000..8835c9ef --- /dev/null +++ b/src/parser/mod.rs @@ -0,0 +1,17 @@ +#[cfg(feature = "num-rug-adapter")] +use num_rug_adapter as rug; +#[cfg(feature = "rug")] +pub use rug; + +// #[macro_use] +// extern crate lazy_static; +// #[macro_use] +// extern crate static_assertions; + +pub mod char_reader; +#[macro_use] +pub mod ast; +#[macro_use] +pub mod macros; +pub mod lexer; +pub mod parser; diff --git a/src/parser/parser.rs b/src/parser/parser.rs new file mode 100644 index 00000000..2d6334c0 --- /dev/null +++ b/src/parser/parser.rs @@ -0,0 +1,1080 @@ +use crate::arena::*; +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::parser::char_reader::*; +use crate::parser::lexer::*; + +use ordered_float::OrderedFloat; + +use rug::ops::NegAssign; + +use std::cell::Cell; +use std::mem; +use std::rc::Rc; + +#[derive(Debug, Clone, Copy, PartialEq)] +enum TokenType { + Term, + Open, + OpenCT, + OpenList, // '[' + OpenCurly, // '{' + HeadTailSeparator, // '|' + Comma, // ',' + Close, + CloseList, // ']' + CloseCurly, // '}' + End, +} + +impl TokenType { + fn is_sep(self) -> bool { + matches!( + self, + TokenType::HeadTailSeparator + | TokenType::OpenCT + | TokenType::Open + | TokenType::Close + | TokenType::OpenList + | TokenType::CloseList + | TokenType::OpenCurly + | TokenType::CloseCurly + | TokenType::Comma + ) + } +} + +#[derive(Debug, Clone, Copy)] +struct TokenDesc { + tt: TokenType, + priority: usize, + spec: u32, +} + +fn is_partial_string( + head: Term, + mut tail: Term, + atom_tbl: &mut AtomTable, +) -> Result<(Atom, Option>), Term> { + let mut string = match &head { + Term::Literal(_, Literal::Atom(atom)) => { + if let Some(c) = atom.as_char() { + c.to_string() + } else { + return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); + } + } + Term::Literal(_, Literal::Char(c)) => c.to_string(), + _ => { + return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail))); + } + }; + + let mut orig_tail = Box::new(tail); + let mut tail_ref = &mut orig_tail; + + loop { + match &mut **tail_ref { + Term::Cons(_, prev, succ) => { + match prev.as_ref() { + Term::Literal(_, Literal::Atom(atom)) => { + if let Some(c) = atom.as_char() { + string.push(c); + } else { + return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail)); + } + } + Term::Literal(_, Literal::Char(c)) => { + string.push(*c); + } + _ => { + return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail)); + } + } + + tail_ref = succ; + } + tail_ref => { + tail = mem::replace(tail_ref, Term::AnonVar); + break; + } + } + } + + match &tail { + Term::AnonVar | Term::Var(..) => { + let pstr_atom = atom_tbl.build_with(&string); + Ok((pstr_atom, Some(Box::new(tail)))) + } + Term::Literal(_, Literal::Atom(atom!("[]"))) => { + let pstr_atom = atom_tbl.build_with(&string); + Ok((pstr_atom, None)) + } + Term::Literal(_, Literal::String(tail)) => { + string += tail.as_str(); + let pstr_atom = atom_tbl.build_with(&string); + Ok((pstr_atom, None)) + } + _ => { + let pstr_atom = atom_tbl.build_with(&string); + Ok((pstr_atom, Some(Box::new(tail)))) + } + } +} + +pub fn get_op_desc( + name: Atom, + op_dir: &CompositeOpDir, +) -> Option { + let mut op_desc = CompositeOpDesc { + pre: 0, + inf: 0, + post: 0, + spec: 0, + }; + + if let Some(cell) = op_dir.get(name, Fixity::Pre) { + let (pri, spec) = cell.get(); + + if pri > 0 { + op_desc.pre = pri as usize; + op_desc.spec |= spec as u32; + } else if name == atom!("-") { + op_desc.spec |= NEGATIVE_SIGN; + } + } + + if let Some(cell) = op_dir.get(name, Fixity::Post) { + let (pri, spec) = cell.get(); + + if pri > 0 { + op_desc.post = pri as usize; + op_desc.spec |= spec as u32; + } + } + + if let Some(cell) = op_dir.get(name, Fixity::In) { + let (pri, spec) = cell.get(); + + if pri > 0 { + op_desc.inf = pri as usize; + op_desc.spec |= spec as u32; + } + } + + if op_desc.pre + op_desc.post + op_desc.inf == 0 && !is_negate!(op_desc.spec) { + None + } else { + Some(op_desc) + } +} + +pub fn get_clause_spec(name: Atom, arity: usize, op_dir: &CompositeOpDir) -> Option { + match arity { + 1 => { + /* This is a clause with an operator principal functor. Prefix operators + are supposed over post. + */ + if let Some(cell) = op_dir.get(name, Fixity::Pre) { + return Some(cell); + } + + if let Some(cell) = op_dir.get(name, Fixity::Post) { + return Some(cell); + } + } + 2 => { + if let Some(cell) = op_dir.get(name, Fixity::In) { + return Some(cell); + } + } + _ => {} + }; + + None +} + +fn affirm_xfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool { + d2.priority <= priority + && is_term!(d3.spec) + && is_term!(d1.spec) + && d3.priority < d2.priority + && d1.priority < d2.priority +} + +fn affirm_yfx(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool { + d2.priority <= priority + && ((is_term!(d3.spec) && d3.priority < d2.priority) + || (is_lterm!(d3.spec) && d3.priority == d2.priority)) + && is_term!(d1.spec) + && d1.priority < d2.priority +} + +fn affirm_xfy(priority: usize, d2: TokenDesc, d3: TokenDesc, d1: TokenDesc) -> bool { + d2.priority < priority + && is_term!(d3.spec) + && d3.priority < d2.priority + && is_term!(d1.spec) + && d1.priority <= d2.priority +} + +fn affirm_yf(d1: TokenDesc, d2: TokenDesc) -> bool { + let is_valid_lterm = is_lterm!(d2.spec) && d2.priority == d1.priority; + (is_term!(d2.spec) && d2.priority < d1.priority) || is_valid_lterm +} + +fn affirm_xf(d1: TokenDesc, d2: TokenDesc) -> bool { + is_term!(d2.spec) && d2.priority < d1.priority +} + +fn affirm_fy(priority: usize, d1: TokenDesc, d2: TokenDesc) -> bool { + d2.priority < priority && is_term!(d1.spec) && d1.priority <= d2.priority +} + +fn affirm_fx(priority: usize, d1: TokenDesc, d2: TokenDesc) -> bool { + d2.priority <= priority && is_term!(d1.spec) && d1.priority < d2.priority +} + +#[derive(Debug, Clone, Copy)] +pub struct CompositeOpDesc { + pub pre: usize, + pub inf: usize, + pub post: usize, + pub spec: Specifier, +} + +#[derive(Debug)] +pub struct Parser<'a, R> { + pub lexer: Lexer<'a, R>, + tokens: Vec, + stack: Vec, + terms: Vec, +} + +fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> { + let mut tokens = vec![]; + + loop { + match lexer.next_token() { + Ok(token) => { + let at_end = token.is_end(); + tokens.push(token); + + if at_end { + break; + } + } + Err(ParserError::UnexpectedEOF) if !tokens.is_empty() => { + return Err(ParserError::IncompleteReduction( + lexer.line_num, + lexer.col_num, + )); + } + Err(e) => { + return Err(e); + } + } + } + + tokens.reverse(); + + Ok(tokens) +} + +fn atomize_term(atom_tbl: &mut AtomTable, term: &Term) -> Option { + match term { + Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c), + _ => None, + } +} + +fn atomize_constant(atom_tbl: &mut AtomTable, c: Literal) -> Option { + match c { + Literal::Atom(ref name) => Some(*name), + Literal::Char(c) => Some(atom_tbl.build_with(&c.to_string())), + _ => None, + } +} + +impl<'a, R: CharRead> Parser<'a, R> { + pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self { + Parser { + lexer: Lexer::new(stream, machine_st), + tokens: vec![], + stack: Vec::new(), + terms: Vec::new(), + } + } + + fn sep_to_atom(&mut self, tt: TokenType) -> Option { + match tt { + TokenType::Open | TokenType::OpenCT => Some(atom!("(")), + TokenType::Close => Some(atom!(")")), + TokenType::OpenList => Some(atom!("[")), + TokenType::CloseList => Some(atom!("]")), + TokenType::OpenCurly => Some(atom!("{")), + TokenType::CloseCurly => Some(atom!("}")), + TokenType::HeadTailSeparator => Some(atom!("|")), + TokenType::Comma => Some(atom!(",")), + TokenType::End => Some(atom!(".")), + _ => None, + } + } + + #[inline] + pub fn line_num(&self) -> usize { + self.lexer.line_num + } + + #[inline] + pub fn col_num(&self) -> usize { + self.lexer.col_num + } + + fn get_term_name(&mut self, td: TokenDesc) -> Option { + match td.tt { + TokenType::HeadTailSeparator => Some(atom!("|")), + TokenType::Comma => Some(atom!(",")), + TokenType::Term => match self.terms.pop() { + Some(Term::Literal(_, Literal::Atom(atom))) => Some(atom), + Some(term) => { + self.terms.push(term); + None + } + _ => None, + }, + _ => None, + } + } + + fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) { + if let Some(arg2) = self.terms.pop() { + if let Some(name) = self.get_term_name(td) { + if let Some(arg1) = self.terms.pop() { + let term = Term::Clause(Cell::default(), name, vec![arg1, arg2]); + + self.terms.push(term); + self.stack.push(TokenDesc { + tt: TokenType::Term, + priority: td.priority, + spec, + }); + } + } + } + } + + fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: u32) { + if let Some(mut arg1) = self.terms.pop() { + if let Some(mut name) = self.terms.pop() { + if is_postfix!(assoc) { + mem::swap(&mut arg1, &mut name); + } + + if let Term::Literal(_, Literal::Atom(name)) = name { + let term = Term::Clause(Cell::default(), name, vec![arg1]); + + self.terms.push(term); + self.stack.push(TokenDesc { + tt: TokenType::Term, + priority: td.priority, + spec, + }); + } + } + } + } + + fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) { + self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom))); + self.stack.push(TokenDesc { + tt: TokenType::Term, + priority, + spec: assoc, + }); + } + + fn shift(&mut self, token: Token, priority: usize, spec: Specifier) { + let tt = match token { + Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_codes() => { + let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))); + + for c in s.as_str().chars().rev() { + list = Term::Cons( + Cell::default(), + Box::new(Term::Literal( + Cell::default(), + Literal::Fixnum(Fixnum::build_with(c as i64)), + )), + Box::new(list), + ); + } + + self.terms.push(list); + TokenType::Term + } + Token::Literal(Literal::String(s)) if self.lexer.machine_st.flags.double_quotes.is_chars() => { + self.terms.push(Term::PartialString(Cell::default(), s, None)); + TokenType::Term + } + Token::Literal(c) => { + self.terms.push(Term::Literal(Cell::default(), c)); + TokenType::Term + } + Token::Var(v) => { + if v.trim() == "_" { + self.terms.push(Term::AnonVar); + } else { + self.terms.push(Term::Var(Cell::default(), Rc::new(v))); + } + + TokenType::Term + } + Token::Comma => TokenType::Comma, + Token::Open => TokenType::Open, + Token::Close => TokenType::Close, + Token::OpenCT => TokenType::OpenCT, + Token::HeadTailSeparator => TokenType::HeadTailSeparator, + Token::OpenList => TokenType::OpenList, + Token::CloseList => TokenType::CloseList, + Token::OpenCurly => TokenType::OpenCurly, + Token::CloseCurly => TokenType::CloseCurly, + Token::End => TokenType::End, + }; + + self.stack.push(TokenDesc { tt, priority, spec }); + } + + fn reduce_op(&mut self, priority: usize) { + loop { + if let Some(desc1) = self.stack.pop() { + if let Some(desc2) = self.stack.pop() { + if let Some(desc3) = self.stack.pop() { + if is_xfx!(desc2.spec) && affirm_xfx(priority, desc2, desc3, desc1) { + self.push_binary_op(desc2, LTERM); + continue; + } else if is_yfx!(desc2.spec) && affirm_yfx(priority, desc2, desc3, desc1) { + self.push_binary_op(desc2, LTERM); + continue; + } else if is_xfy!(desc2.spec) && affirm_xfy(priority, desc2, desc3, desc1) { + self.push_binary_op(desc2, TERM); + continue; + } else { + self.stack.push(desc3); + } + } + + if is_yf!(desc1.spec) && affirm_yf(desc1, desc2) { + self.push_unary_op(desc1, LTERM, YF); + continue; + } else if is_xf!(desc1.spec) && affirm_xf(desc1, desc2) { + self.push_unary_op(desc1, LTERM, XF); + continue; + } else if is_fy!(desc2.spec) && affirm_fy(priority, desc1, desc2) { + self.push_unary_op(desc2, TERM, FY); + continue; + } else if is_fx!(desc2.spec) && affirm_fx(priority, desc1, desc2) { + self.push_unary_op(desc2, TERM, FX); + continue; + } else { + self.stack.push(desc2); + self.stack.push(desc1); + } + } else { + self.stack.push(desc1); + } + } + + break; + } + } + + fn compute_arity_in_brackets(&self) -> Option { + let mut arity = 0; + + for (i, desc) in self.stack.iter().rev().enumerate() { + if i % 2 == 0 { + // expect a term or non-comma operator. + if let TokenType::Comma = desc.tt { + return None; + } else if is_term!(desc.spec) || is_op!(desc.spec) || is_negate!(desc.spec) { + arity += 1; + } else { + return None; + } + } else { + if desc.tt == TokenType::OpenCT { + return Some(arity); + } + + if let TokenType::Comma = desc.tt { + continue; + } else { + return None; + } + } + } + + None + } + + fn reduce_term(&mut self) -> bool { + if self.stack.is_empty() { + return false; + } + + self.reduce_op(999); + + let arity = match self.compute_arity_in_brackets() { + Some(arity) => arity, + None => return false, + }; + + if self.stack.len() > 2 * arity { + let idx = self.stack.len() - 2 * arity - 1; + + if is_infix!(self.stack[idx].spec) && idx > 0 { + if !is_op!(self.stack[idx - 1].spec) && !self.stack[idx - 1].tt.is_sep() { + return false; + } + } + } else { + return false; + } + + if self.terms.len() < 1 + arity { + return false; + } + + let stack_len = self.stack.len() - 2 * arity - 1; + let idx = self.terms.len() - arity; + + if TokenType::Term == self.stack[stack_len].tt { + if atomize_term(&mut self.lexer.machine_st.atom_tbl, &self.terms[idx - 1]).is_some() { + self.stack.truncate(stack_len + 1); + + let mut subterms: Vec<_> = self.terms.drain(idx..).collect(); + + if let Some(name) = self + .terms + .pop() + .and_then(|t| atomize_term(&mut self.lexer.machine_st.atom_tbl, &t)) + { + // reduce the '.' functor to a cons cell if it applies. + if name == atom!(".") && subterms.len() == 2 { + let tail = subterms.pop().unwrap(); + let head = subterms.pop().unwrap(); + + self.terms.push( + match is_partial_string(head, tail, &mut self.lexer.machine_st.atom_tbl) { + Ok((string_buf, tail_opt)) => { + Term::PartialString(Cell::default(), string_buf, tail_opt) + } + Err(term) => term, + }, + ); + + /* + self.terms.push(Term::Cons( + Cell::default(), + Box::new(head), + Box::new(tail), + )); + */ + } else { + self.terms + .push(Term::Clause(Cell::default(), name, subterms)); + } + + if let Some(&mut TokenDesc { + ref mut priority, + ref mut spec, + ref mut tt, + }) = self.stack.last_mut() + { + *tt = TokenType::Term; + *priority = 0; + *spec = TERM; + } + + return true; + } + } + } + + false + } + + pub fn devour_whitespace(&mut self) -> Result<(), ParserError> { + self.lexer.scan_for_layout()?; + Ok(()) + } + + pub fn reset(&mut self) { + self.stack.clear() + } + + fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { + if let Some(term) = self.terms.pop() { + let op_desc = self.stack[index - 1]; + + if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority { + /* '|' is a head-tail separator here, not + * an operator, so expand the + * terms it compacted out again. */ + match (term.name(), term.arity()) { + (Some(name), 2) if name == atom!(",") => { + let terms = unfold_by_str(term, name); // notice: name == "," here. + let arity = terms.len() - 1; + + self.terms.extend(terms.into_iter()); + return arity; + } + _ => {} + } + } + + self.terms.push(term); + } + + 0 + } + + fn compute_arity_in_list(&self) -> Option { + let mut arity = 0; + + for (i, desc) in self.stack.iter().rev().enumerate() { + if i % 2 == 0 { + // expect a term or non-comma operator. + if let TokenType::Comma = desc.tt { + return None; + } else if is_term!(desc.spec) || is_op!(desc.spec) { + arity += 1; + } else { + return None; + } + } else { + if desc.tt == TokenType::HeadTailSeparator { + if arity == 1 { + continue; + } + + return None; + } else if desc.tt == TokenType::OpenList { + return Some(arity); + } else if desc.tt != TokenType::Comma { + return None; + } + } + } + + None + } + + fn reduce_list(&mut self) -> Result { + if self.stack.is_empty() { + return Ok(false); + } + + if let Some(ref mut td) = self.stack.last_mut() { + if td.tt == TokenType::OpenList { + td.spec = TERM; + td.tt = TokenType::Term; + td.priority = 0; + + self.terms.push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))); + return Ok(true); + } + } + + self.reduce_op(1000); + + let mut arity = match self.compute_arity_in_list() { + Some(arity) => arity, + None => return Ok(false), + }; + + // we know that self.stack.len() >= 2 by this point. + let idx = self.stack.len() - 2; + let list_len = self.stack.len() - 2 * arity; + + let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator { + Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))) + } else { + let term = match self.terms.pop() { + Some(term) => term, + _ => { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } + }; + + if self.stack[idx].priority > 1000 { + arity += self.expand_comma_compacted_terms(idx); + } + + arity -= 1; + + term + }; + + if arity > self.terms.len() { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num + )) + } + + let idx = self.terms.len() - arity; + + let list = self.terms.drain(idx..).rev().fold(end_term, |acc, t| { + Term::Cons(Cell::default(), Box::new(t), Box::new(acc)) + }); + + self.stack.truncate(list_len); + + self.stack.push(TokenDesc { + tt: TokenType::Term, + priority: 0, + spec: TERM, + }); + + self.terms.push(match list { + Term::Cons(_, head, tail) => { + match is_partial_string(*head, *tail, &mut self.lexer.machine_st.atom_tbl) { + Ok((string_buf, tail_opt)) => { + Term::PartialString(Cell::default(), string_buf, tail_opt) + } + Err(term) => term, + } + } + term => term, + }); + + Ok(true) + } + + fn reduce_curly(&mut self) -> Result { + if self.stack.is_empty() { + return Ok(false); + } + + if let Some(ref mut td) = self.stack.last_mut() { + if td.tt == TokenType::OpenCurly { + td.tt = TokenType::Term; + td.priority = 0; + td.spec = TERM; + + let term = Term::Literal( + Cell::default(), + Literal::Atom(atom!("{}")), + ); + + self.terms.push(term); + return Ok(true); + } + } + + self.reduce_op(1201); + + if self.stack.len() > 1 { + if let Some(td) = self.stack.pop() { + if let Some(ref mut oc) = self.stack.last_mut() { + if td.tt != TokenType::Term { + return Ok(false); + } + + if oc.tt == TokenType::OpenCurly { + oc.tt = TokenType::Term; + oc.priority = 0; + oc.spec = TERM; + + let term = match self.terms.pop() { + Some(term) => term, + _ => { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } + }; + + self.terms.push(Term::Clause( + Cell::default(), + atom!("{}"), + vec![term], + )); + + return Ok(true); + } + } + } + } + + Ok(false) + } + + fn reduce_brackets(&mut self) -> bool { + if self.stack.is_empty() { + return false; + } + + self.reduce_op(1400); + + if self.stack.len() == 1 { + return false; + } + + let idx = self.stack.len() - 2; + + let td = self.stack.remove(idx); + match td.tt { + TokenType::Open | TokenType::OpenCT => { + if self.stack[idx].tt == TokenType::Comma { + return false; + } + + if let Some(atom) = self.sep_to_atom(self.stack[idx].tt) { + self.terms + .push(Term::Literal(Cell::default(), Literal::Atom(atom))); + } + + self.stack[idx].spec = TERM; + self.stack[idx].tt = TokenType::Term; + self.stack[idx].priority = 0; + + true + } + _ => false, + } + } + + fn shift_op(&mut self, name: Atom, op_dir: &CompositeOpDir) -> Result { + if let Some(CompositeOpDesc { + pre, + inf, + post, + spec, + }) = get_op_desc(name, op_dir) + { + if (pre > 0 && inf + post > 0) || is_negate!(spec) { + match self.tokens.last().ok_or(ParserError::UnexpectedEOF)? { + // do this when layout hasn't been inserted, + // ie. why we don't match on Token::Open. + Token::OpenCT => { + // can't be prefix, so either inf == 0 + // or post == 0. + self.reduce_op(inf + post); + + // let fixity = if inf > 0 { Fixity::In } else { Fixity::Post }; + + self.promote_atom_op(name, inf + post, spec & (XFX | XFY | YFX | YF | XF)); + } + _ => { + self.reduce_op(inf + post); + + if let Some(TokenDesc { spec: pspec, .. }) = self.stack.last().cloned() { + // rterm.c: 412 + if is_term!(pspec) { + self.promote_atom_op( + name, + inf + post, + spec & (XFX | XFY | YFX | XF | YF), + ); + } else { + self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN)); + } + } else { + self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN)); + } + } + } + } else { + self.reduce_op(pre + inf + post); // only one non-zero priority among these. + self.promote_atom_op(name, pre + inf + post, spec); + } + + Ok(true) + } else { + // not an operator. + Ok(false) + } + } + + fn negate_number(&mut self, n: N, negator: Negator, constr: ToLiteral) + where + Negator: Fn(N) -> N, + ToLiteral: Fn(N, &mut Arena) -> Literal, + { + if let Some(desc) = self.stack.last().cloned() { + if let Some(term) = self.terms.last().cloned() { + match term { + Term::Literal(_, Literal::Atom(name)) + if name == atom!("-") && (is_prefix!(desc.spec) || is_negate!(desc.spec)) => + { + self.stack.pop(); + self.terms.pop(); + + let literal = constr(negator(n), &mut self.lexer.machine_st.arena); + self.shift(Token::Literal(literal), 0, TERM); + + return; + } + _ => {} + } + } + } + + let literal = constr(n, &mut self.lexer.machine_st.arena); + self.shift(Token::Literal(literal), 0, TERM); + } + + fn shift_token(&mut self, token: Token, op_dir: &CompositeOpDir) -> Result<(), ParserError> { + fn negate_rc(mut t: TypedArenaPtr) -> TypedArenaPtr { + (&mut t).neg_assign(); + t + } + + match token { + Token::Literal(Literal::Fixnum(n)) => { + self.negate_number(n, |n| -n, |n, _| Literal::Fixnum(n)) + } + Token::Literal(Literal::Integer(n)) => { + self.negate_number(n, negate_rc, |n, _| Literal::Integer(n)) + } + Token::Literal(Literal::Rational(n)) => { + self.negate_number(n, negate_rc, |r, _| Literal::Rational(r)) + } + Token::Literal(Literal::Float(n)) => self.negate_number( + **n, + |n| OrderedFloat(-n.into_inner()), + |n, arena| Literal::Float(arena_alloc!(n, arena)), + ), + Token::Literal(c) => { + if let Some(name) = atomize_constant(&mut self.lexer.machine_st.atom_tbl, c) { + if !self.shift_op(name, op_dir)? { + self.shift(Token::Literal(c), 0, TERM); + } + } else { + self.shift(Token::Literal(c), 0, TERM); + } + } + Token::Var(v) => self.shift(Token::Var(v), 0, TERM), + Token::Open => self.shift(Token::Open, 1300, DELIMITER), + Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER), + Token::Close => { + if !self.reduce_term() { + if !self.reduce_brackets() { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )); + } + } + } + Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER), + Token::CloseList => { + if !self.reduce_list()? { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )); + } + } + Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER), + Token::CloseCurly => { + if !self.reduce_curly()? { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )); + } + } + Token::HeadTailSeparator => { + /* '|' as an operator must have priority > 1000 and can only be infix. + * See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78 + */ + let bar_atom = atom!("|"); + + let (priority, spec) = get_op_desc(bar_atom, op_dir) + .map(|CompositeOpDesc { inf, spec, .. }| (inf, spec)) + .unwrap_or((1000, DELIMITER)); + + self.reduce_op(priority); + self.shift(Token::HeadTailSeparator, priority, spec); + } + Token::Comma => { + self.reduce_op(1000); + self.shift(Token::Comma, 1000, XFY); + } + Token::End => match self.stack.last().map(|t| t.tt) { + Some(TokenType::Open) + | Some(TokenType::OpenCT) + | Some(TokenType::OpenList) + | Some(TokenType::OpenCurly) + | Some(TokenType::HeadTailSeparator) + | Some(TokenType::Comma) => { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } + _ => {} + }, + } + + Ok(()) + } + + #[inline] + pub fn eof(&mut self) -> Result { + self.lexer.eof() + } + + #[inline] + pub fn add_lines_read(&mut self, lines_read: usize) { + self.lexer.line_num += lines_read; + } + + #[inline] + pub fn lines_read(&self) -> usize { + self.lexer.line_num + } + + // on success, returns the parsed term and the number of lines read. + pub fn read_term(&mut self, op_dir: &CompositeOpDir) -> Result { + self.tokens = read_tokens(&mut self.lexer)?; + + while let Some(token) = self.tokens.pop() { + self.shift_token(token, op_dir)?; + } + + self.reduce_op(1400); + + if self.terms.len() > 1 || self.stack.len() > 1 { + return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )); + } + + match self.terms.pop() { + Some(term) => { + if self.terms.is_empty() { + Ok(term) + } else { + Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) + } + } + _ => Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )), + } + } +} diff --git a/src/raw_block.rs b/src/raw_block.rs new file mode 100644 index 00000000..d39c65ca --- /dev/null +++ b/src/raw_block.rs @@ -0,0 +1,105 @@ +use core::marker::PhantomData; + +use std::alloc; +use std::ptr; + +pub trait RawBlockTraits { + fn init_size() -> usize; + fn align() -> usize; +} + +#[derive(Debug)] +pub struct RawBlock { + pub base: *const u8, + pub top: *const u8, + pub ptr: *mut u8, + _marker: PhantomData, +} + +impl RawBlock { + #[inline] + fn empty_block() -> Self { + RawBlock { + base: ptr::null(), + top: ptr::null(), + ptr: ptr::null_mut(), + _marker: PhantomData, + } + } + + pub fn new() -> Self { + let mut block = Self::empty_block(); + + unsafe { + block.grow(); + } + + block + } + + unsafe fn init_at_size(&mut self, cap: usize) { + let layout = alloc::Layout::from_size_align_unchecked(cap, T::align()); + + self.base = alloc::alloc(layout) as *const _; + self.top = (self.base as usize + cap) as *const _; + self.ptr = self.base as *mut _; + } + + pub unsafe fn grow(&mut self) { + if self.base.is_null() { + self.init_at_size(T::init_size()); + } else { + let size = self.size(); + let layout = alloc::Layout::from_size_align_unchecked(size, T::align()); + + self.base = alloc::realloc(self.base as *mut _, layout, size * 2) as *const _; + self.top = (self.base as usize + size * 2) as *const _; + self.ptr = (self.base as usize + size) as *mut _; + } + } + + /* + #[inline] + pub fn take(&mut self) -> Self { + mem::replace(self, Self::empty_block()) + } + */ + + #[inline] + pub fn size(&self) -> usize { + self.top as usize - self.base as usize + } + + #[inline(always)] + fn free_space(&self) -> usize { + debug_assert!( + self.ptr as *const _ >= self.base, + "self.ptr = {:?} < {:?} = self.base", + self.ptr, + self.base + ); + + self.top as usize - self.ptr as usize + } + + pub unsafe fn alloc(&mut self, size: usize) -> *mut u8 { + if self.free_space() >= size { + let ptr = self.ptr; + self.ptr = (self.ptr as usize + size) as *mut _; + ptr + } else { + ptr::null_mut() + } + } + + pub fn deallocate(&mut self) { + unsafe { + let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align()); + alloc::dealloc(self.base as *mut _, layout); + + self.top = ptr::null(); + self.base = ptr::null(); + self.ptr = ptr::null_mut(); + } + } +} diff --git a/src/read.rs b/src/read.rs index 366962cb..b4c4dbcc 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1,254 +1,261 @@ -use prolog_parser::ast::*; -use prolog_parser::parser::*; -use prolog_parser::tabled_rc::TabledData; +use crate::parser::ast::*; +use crate::parser::parser::*; +use crate::arena::*; +use crate::atom_table::*; use crate::forms::*; use crate::iterators::*; +use crate::machine::heap::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::MachineState; -use crate::machine::streams::Stream; +use crate::machine::streams::*; +use crate::parser::char_reader::*; +use crate::types::*; + +use rustyline::error::ReadlineError; +use rustyline::{Cmd, Config, Editor, KeyEvent}; use std::collections::VecDeque; +use std::io::{Cursor, Error, ErrorKind, Read}; type SubtermDeque = VecDeque<(usize, usize)>; -pub(crate) type PrologStream = ParsingStream; +// pub(crate) type PrologStream = ParsingStream; -pub mod readline { - use crate::machine::streams::Stream; - use rustyline::error::ReadlineError; - use rustyline::{Cmd, Config, Editor, KeyEvent}; - use std::io::{Cursor, Error, ErrorKind, Read}; +impl MachineState { + pub(crate) fn devour_whitespace( + &mut self, + mut inner: Stream, + ) -> Result { + let mut parser = Parser::new(inner, self); - static mut PROMPT: bool = false; + parser.devour_whitespace()?; + inner.add_lines_read(parser.lines_read()); - const HISTORY_FILE: &'static str = ".scryer_history"; + parser.eof() + } - pub(crate) fn set_prompt(value: bool) { - unsafe { - PROMPT = value; - } + pub(crate) fn read( + &mut self, + mut inner: Stream, + op_dir: &OpDir, + ) -> Result { + let (term, num_lines_read) = { + let prior_num_lines_read = inner.lines_read(); + let mut parser = Parser::new(inner, self); + + parser.add_lines_read(prior_num_lines_read); + + let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?; + (term, parser.lines_read() - prior_num_lines_read) + }; + + inner.add_lines_read(num_lines_read); + Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl)) } +} - #[inline] - fn get_prompt() -> &'static str { - unsafe { - if PROMPT { - "?- " - } else { - "" - } - } +static mut PROMPT: bool = false; + +const HISTORY_FILE: &'static str = ".scryer_history"; + +pub(crate) fn set_prompt(value: bool) { + unsafe { + PROMPT = value; } +} - #[derive(Debug)] - pub struct ReadlineStream { - rl: Editor<()>, - pending_input: Cursor, +#[inline] +fn get_prompt() -> &'static str { + unsafe { + if PROMPT { + "?- " + } else { + "" + } } +} - impl ReadlineStream { - #[inline] - pub(crate) fn new(pending_input: String) -> Self { - let config = Config::builder().check_cursor_position(true).build(); - - let mut rl = Editor::<()>::with_config(config); //Editor::<()>::new(); - if let Some(mut path) = dirs_next::home_dir() { - path.push(HISTORY_FILE); - if path.exists() { - if rl.load_history(&path).is_err() { - println!("Warning: loading history failed"); - } - } - } +#[inline] +pub fn input_stream(arena: &mut Arena) -> Stream { + let input_stream = ReadlineStream::new(""); + Stream::from_readline_stream(input_stream, arena) +} + +#[derive(Debug)] +pub struct ReadlineStream { + rl: Editor<()>, + pending_input: Cursor, +} - rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string())); - ReadlineStream { - rl, - pending_input: Cursor::new(pending_input), +impl ReadlineStream { + #[inline] + pub fn new(pending_input: &str) -> Self { + let config = Config::builder().check_cursor_position(true).build(); + let mut rl = Editor::<()>::with_config(config); + + if let Some(mut path) = dirs_next::home_dir() { + path.push(HISTORY_FILE); + if path.exists() && rl.load_history(&path).is_err() { + println!("Warning: loading history failed"); } } - #[inline] - pub(crate) fn input_stream(pending_input: String) -> Stream { - Stream::from(Self::new(pending_input)) + rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string())); + + ReadlineStream { + rl, + pending_input: Cursor::new(pending_input.to_owned()), } + } - fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result { - match self.rl.readline(get_prompt()) { - Ok(text) => { - *self.pending_input.get_mut() = text; - self.pending_input.set_position(0); - - unsafe { - if PROMPT { - self.rl.history_mut().add(self.pending_input.get_ref()); - self.save_history(); - PROMPT = false; - } + fn call_readline(&mut self) -> std::io::Result { + match self.rl.readline(get_prompt()) { + Ok(text) => { + *self.pending_input.get_mut() = text; + self.pending_input.set_position(0); + + unsafe { + if PROMPT { + self.rl.history_mut().add(self.pending_input.get_ref()); + self.save_history(); + PROMPT = false; } + } - if self.pending_input.get_ref().chars().last() != Some('\n') { - *self.pending_input.get_mut() += "\n"; - } + if self.pending_input.get_ref().chars().last() != Some('\n') { + *self.pending_input.get_mut() += "\n"; + } + + Ok(self.pending_input.get_ref().len()) + } + Err(ReadlineError::Eof) => Ok(0), + Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)), + } + } - self.pending_input.read(buf) + fn save_history(&mut self) { + if let Some(mut path) = dirs_next::home_dir() { + path.push(HISTORY_FILE); + if path.exists() { + if self.rl.append_history(&path).is_err() { + println!("Warning: couldn't append history (existing file)"); } - Err(ReadlineError::Eof) => Ok(0), - Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)), + } else if self.rl.save_history(&path).is_err() { + println!("Warning: couldn't save history (new file)"); } } + } - fn save_history(&mut self) { - if let Some(mut path) = dirs_next::home_dir() { - path.push(HISTORY_FILE); - if path.exists() { - if self.rl.append_history(&path).is_err() { - println!("Warning: couldn't append history (existing file)"); + pub(crate) fn peek_byte(&mut self) -> std::io::Result { + loop { + match self.pending_input.get_ref().bytes().next() { + Some(0) => { + return Ok(0); + } + Some(b) => { + return Ok(b); + } + None => match self.call_readline() { + Err(e) => { + return Err(e); } - } else { - if self.rl.save_history(&path).is_err() { - println!("Warning: couldn't save history (new file)"); + Ok(0) => { + self.pending_input.get_mut().push('\u{0}'); + return Ok(0); } - } + _ => { + set_prompt(false); + } + }, } } + } +} - pub(crate) fn peek_byte(&mut self) -> std::io::Result { - set_prompt(false); - - loop { - match self.pending_input.get_ref().bytes().next() { - Some(b) => { - return Ok(b); - } - None => match self.call_readline(&mut []) { - Err(e) => { - return Err(e); - } - Ok(0) => { - return Err(Error::new(ErrorKind::UnexpectedEof, "end of file")); - } - _ => {} - }, - } +impl Read for ReadlineStream { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + match self.pending_input.read(buf) { + Ok(0) => { + self.call_readline()?; + self.pending_input.read(buf) } + result => result } + } +} - pub(crate) fn peek_char(&mut self) -> std::io::Result { - set_prompt(false); +impl CharRead for ReadlineStream { + fn peek_char(&mut self) -> Option> { + loop { + let pos = self.pending_input.position() as usize; - loop { - match self.pending_input.get_ref().chars().next() { - Some(c) => { - return Ok(c); - } - None => match self.call_readline(&mut []) { + match self.pending_input.get_ref()[pos ..].chars().next() { + Some('\u{0}') => { + return Some(Ok('\u{0}')); + } + Some(c) => { + return Some(Ok(c)); + } + None => { + match self.call_readline() { Err(e) => { - return Err(e); + return Some(Err(e)); } Ok(0) => { - return Err(Error::new(ErrorKind::UnexpectedEof, "end of file")); + self.pending_input.get_mut().push('\u{0}'); + return Some(Ok('\u{0}')); } - _ => {} - }, + _ => { + set_prompt(false); + } + } } } } } - impl Read for ReadlineStream { - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - match self.pending_input.read(buf) { - Ok(0) => self.call_readline(buf), - result => result, - } - } + fn consume(&mut self, nread: usize) { + let offset = self.pending_input.position() as usize; + self.pending_input.set_position((offset + nread) as u64); } - #[inline] - pub fn input_stream() -> Stream { - let input_stream = ReadlineStream::input_stream(String::from("")); - Stream::from(input_stream) - } -} - -impl MachineState { - pub(crate) fn devour_whitespace( - &mut self, - mut inner: Stream, - atom_tbl: TabledData, - ) -> Result { - let mut stream = parsing_stream(inner.clone())?; - let mut parser = Parser::new(&mut stream, atom_tbl, self.flags); - - parser.devour_whitespace()?; - - inner.add_lines_read(parser.num_lines_read()); - - let result = parser.eof(); - let buf = stream.take_buf(); - - inner.pause_stream(buf)?; - - result - } - - pub(crate) fn read( - &mut self, - mut inner: Stream, - atom_tbl: TabledData, - op_dir: &OpDir, - ) -> Result { - let mut stream = parsing_stream(inner.clone())?; - - let (term, num_lines_read) = { - let prior_num_lines_read = inner.lines_read(); - let mut parser = Parser::new(&mut stream, atom_tbl, self.flags); - - parser.add_lines_read(prior_num_lines_read); - - let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?; - (term, parser.num_lines_read() - prior_num_lines_read) - }; - - inner.add_lines_read(num_lines_read); - - // 'pausing' the stream saves the pending top buffer - // created by the parsing stream, which was created in this - // scope and is about to be destroyed in it. - - let buf = stream.take_buf(); - inner.pause_stream(buf)?; - - Ok(write_term_to_heap(&term, self)) + fn put_back_char(&mut self, c: char) { + let offset = self.pending_input.position() as usize; + self.pending_input.set_position((offset - c.len_utf8()) as u64); } } #[inline] -pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult { - let term_writer = TermWriter::new(machine_st); +pub(crate) fn write_term_to_heap( + term: &Term, + heap: &mut Heap, + atom_tbl: &mut AtomTable, +) -> TermWriteResult { + let term_writer = TermWriter::new(heap, atom_tbl); term_writer.write_term_to_heap(term) } #[derive(Debug)] -struct TermWriter<'a> { - machine_st: &'a mut MachineState, +struct TermWriter<'a, 'b> { + heap: &'a mut Heap, + atom_tbl: &'b mut AtomTable, queue: SubtermDeque, var_dict: HeapVarDict, } #[derive(Debug)] -pub(crate) struct TermWriteResult { - pub(crate) heap_loc: usize, - pub(crate) var_dict: HeapVarDict, +pub struct TermWriteResult { + pub heap_loc: usize, + pub var_dict: HeapVarDict, } -impl<'a> TermWriter<'a> { +impl<'a, 'b> TermWriter<'a, 'b> { #[inline] - fn new(machine_st: &'a mut MachineState) -> Self { + fn new(heap: &'a mut Heap, atom_tbl: &'b mut AtomTable) -> Self { TermWriter { - machine_st, + heap, + atom_tbl, queue: SubtermDeque::new(), var_dict: HeapVarDict::new(), } @@ -257,7 +264,7 @@ impl<'a> TermWriter<'a> { #[inline] fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) { if let Some((arity, site_h)) = self.queue.pop_front() { - self.machine_st.heap[site_h] = HeapCellValue::Addr(self.term_as_addr(term, h)); + self.heap[site_h] = self.term_as_addr(term, h); if arity > 1 { self.queue.push_front((arity - 1, site_h + 1)); @@ -267,64 +274,82 @@ impl<'a> TermWriter<'a> { #[inline] fn push_stub_addr(&mut self) { - let h = self.machine_st.heap.h(); - self.machine_st - .heap - .push(HeapCellValue::Addr(Addr::HeapCell(h))); + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); } - fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> Addr { + fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> HeapCellValue { match term { - &TermRef::AnonVar(_) | &TermRef::Var(..) => Addr::HeapCell(h), - &TermRef::Cons(..) => Addr::HeapCell(h), - &TermRef::Constant(_, _, c) => self.machine_st.heap.put_constant(c.clone()), - &TermRef::Clause(..) => Addr::Str(h), - &TermRef::PartialString(..) => Addr::PStrLocation(h, 0), + &TermRef::Cons(..) => list_loc_as_cell!(h), + &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h), + &TermRef::PartialString(_, _, ref src, None) => + if src.as_str().is_empty() { + empty_list_as_cell!() + } else if self.heap[h].get_tag() == HeapCellValueTag::CStr { + heap_loc_as_cell!(h) + } else { + pstr_loc_as_cell!(h) + }, + &TermRef::PartialString(..) => pstr_loc_as_cell!(h), + &TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal), + &TermRef::Clause(..) => str_loc_as_cell!(h), } } fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult { - let heap_loc = self.machine_st.heap.h(); + let heap_loc = self.heap.len(); for term in breadth_first_iter(term, true) { - let h = self.machine_st.heap.h(); + let h = self.heap.len(); match &term { - &TermRef::Cons(lvl, ..) => { + &TermRef::Cons(Level::Root, ..) => { self.queue.push_back((2, h + 1)); - self.machine_st - .heap - .push(HeapCellValue::Addr(Addr::Lis(h + 1))); + self.heap.push(list_loc_as_cell!(h + 1)); self.push_stub_addr(); self.push_stub_addr(); - if let Level::Root = lvl { - continue; - } + continue; } - &TermRef::Clause(lvl, _, ref ct, subterms) => { - self.queue.push_back((subterms.len(), h + 1)); - let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec()); + &TermRef::Cons(..) => { + self.queue.push_back((2, h)); + + self.push_stub_addr(); + self.push_stub_addr(); + } + &TermRef::Clause(Level::Root, _, ref ct, subterms) => { + self.heap.push(str_loc_as_cell!(heap_loc + 1)); + + self.queue.push_back((subterms.len(), h + 2)); + let named = atom_as_cell!(ct.name(), subterms.len()); - self.machine_st.heap.push(named); + self.heap.push(named); for _ in 0..subterms.len() { self.push_stub_addr(); } - if let Level::Root = lvl { - continue; + continue; + } + &TermRef::Clause(_, _, ref ct, subterms) => { + self.queue.push_back((subterms.len(), h + 1)); + let named = atom_as_cell!(ct.name(), subterms.len()); + + self.heap.push(named); + + for _ in 0..subterms.len() { + self.push_stub_addr(); } } - &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => { + &TermRef::AnonVar(Level::Root) | &TermRef::Literal(Level::Root, ..) => { let addr = self.term_as_addr(&term, h); - self.machine_st.heap.push(HeapCellValue::Addr(addr)); + self.heap.push(addr); } &TermRef::Var(Level::Root, _, ref var) => { let addr = self.term_as_addr(&term, h); - self.var_dict.insert(var.clone(), Addr::HeapCell(h)); - self.machine_st.heap.push(HeapCellValue::Addr(addr)); + self.var_dict.insert(var.clone(), heap_loc_as_cell!(h)); + self.heap.push(addr); } &TermRef::AnonVar(_) => { if let Some((arity, site_h)) = self.queue.pop_front() { @@ -335,25 +360,28 @@ impl<'a> TermWriter<'a> { continue; } - &TermRef::PartialString(lvl, _, ref pstr, tail) => { + &TermRef::PartialString(lvl, _, ref src, tail) => { if tail.is_some() { - self.machine_st.heap.allocate_pstr(&pstr); + allocate_pstr(self.heap, src.as_str(), self.atom_tbl); } else { - self.machine_st.heap.put_complete_string(&pstr); + put_complete_string(self.heap, src.as_str(), self.atom_tbl); } - if let Level::Root = lvl { - } else if tail.is_some() { - let h = self.machine_st.heap.h(); + if tail.is_some() { + let h = self.heap.len(); self.queue.push_back((1, h - 1)); + + if let Level::Root = lvl { + continue; + } } } &TermRef::Var(_, _, ref var) => { if let Some((arity, site_h)) = self.queue.pop_front() { if let Some(addr) = self.var_dict.get(var).cloned() { - self.machine_st.heap[site_h] = HeapCellValue::Addr(addr); + self.heap[site_h] = addr; } else { - self.var_dict.insert(var.clone(), Addr::HeapCell(site_h)); + self.var_dict.insert(var.clone(), heap_loc_as_cell!(site_h)); } if arity > 1 { diff --git a/src/targets.rs b/src/targets.rs index 78e988e5..0d4ac6d6 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -1,37 +1,39 @@ -use prolog_parser::ast::*; +use crate::parser::ast::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::forms::*; use crate::instructions::*; use crate::iterators::*; +use crate::types::*; pub(crate) trait CompilationTarget<'a> { type Iterator: Iterator>; - fn iter(_: &'a Term) -> Self::Iterator; + fn iter(term: &'a Term) -> Self::Iterator; - fn to_constant(_: Level, _: Constant, _: RegType) -> Self; - fn to_list(_: Level, _: RegType) -> Self; - fn to_structure(_: ClauseType, _: usize, _: RegType) -> Self; + fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Self; + fn to_list(lvl: Level, r: RegType) -> Self; + fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self; - fn to_void(_: usize) -> Self; + fn to_void(num_subterms: usize) -> Self; fn is_void_instr(&self) -> bool; - fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self; + fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self; fn incr_void_instr(&mut self); - fn constant_subterm(_: Constant) -> Self; + fn constant_subterm(literal: Literal) -> Self; - fn argument_to_variable(_: RegType, _: usize) -> Self; - fn argument_to_value(_: RegType, _: usize) -> Self; + fn argument_to_variable(r: RegType, r: usize) -> Self; + fn argument_to_value(r: RegType, val: usize) -> Self; - fn move_to_register(_: RegType, _: usize) -> Self; + fn move_to_register(r: RegType, val: usize) -> Self; - fn subterm_to_variable(_: RegType) -> Self; - fn subterm_to_value(_: RegType) -> Self; + fn subterm_to_variable(r: RegType) -> Self; + fn subterm_to_value(r: RegType) -> Self; - fn clause_arg_to_instr(_: RegType) -> Self; + fn clause_arg_to_instr(r: RegType) -> Self; } impl<'a> CompilationTarget<'a> for FactInstruction { @@ -41,8 +43,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { breadth_first_iter(term, false) // do not iterate over the root clause if one exists. } - fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self { - FactInstruction::GetConstant(lvl, constant, reg) + fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Self { + FactInstruction::GetConstant(lvl, HeapCellValue::from(constant), reg) } fn to_structure(ct: ClauseType, arity: usize, reg: RegType) -> Self { @@ -53,8 +55,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { FactInstruction::GetList(lvl, reg) } - fn to_void(subterms: usize) -> Self { - FactInstruction::UnifyVoid(subterms) + fn to_void(num_subterms: usize) -> Self { + FactInstruction::UnifyVoid(num_subterms) } fn is_void_instr(&self) -> bool { @@ -64,7 +66,7 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } } - fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self { + fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self { FactInstruction::GetPartialString(lvl, string, r, has_tail) } @@ -75,8 +77,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } } - fn constant_subterm(constant: Constant) -> Self { - FactInstruction::UnifyConstant(constant) + fn constant_subterm(constant: Literal) -> Self { + FactInstruction::UnifyConstant(HeapCellValue::from(constant)) } fn argument_to_variable(arg: RegType, val: usize) -> Self { @@ -115,15 +117,15 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { QueryInstruction::PutStructure(ct, arity, r) } - fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self { - QueryInstruction::PutConstant(lvl, constant, reg) + fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Self { + QueryInstruction::PutConstant(lvl, HeapCellValue::from(constant), reg) } fn to_list(lvl: Level, reg: RegType) -> Self { QueryInstruction::PutList(lvl, reg) } - fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self { + fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self { QueryInstruction::PutPartialString(lvl, string, r, has_tail) } @@ -145,8 +147,8 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { } } - fn constant_subterm(constant: Constant) -> Self { - QueryInstruction::SetConstant(constant) + fn constant_subterm(constant: Literal) -> Self { + QueryInstruction::SetConstant(HeapCellValue::from(constant)) } fn argument_to_variable(arg: RegType, val: usize) -> Self { diff --git a/src/toplevel.pl b/src/toplevel.pl index fdc5c18f..441d470a 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -4,6 +4,7 @@ :- use_module(library(charsio)). :- use_module(library(files)). :- use_module(library(iso_ext)). +:- use_module(library(lambda)). :- use_module(library(lists)). :- use_module(library(si)). @@ -17,7 +18,7 @@ load_scryerrc :- append(HomeDir, "/.scryerrc", ScryerrcFile), ( file_exists(ScryerrcFile) -> atom_chars(ScryerrcFileAtom, ScryerrcFile), - catch(consult(ScryerrcFileAtom), E, print_exception(E)) + catch(use_module(ScryerrcFileAtom), E, print_exception(E)) ; true ) ; true @@ -166,7 +167,7 @@ instruction_match(Term, VarList) :- ; Term = end_of_file -> halt ; - submit_query_and_print_results(Term, VarList) + submit_query_and_print_results(Term, VarList) ). @@ -193,10 +194,10 @@ submit_query_and_print_results(Term0, VarList) :- needs_bracketing(Value, Op) :- catch((functor(Value, F, _), - current_op(EqPrec, EqSpec, Op), - current_op(FPrec, _, F)), - _, - false), + current_op(EqPrec, EqSpec, Op), + current_op(FPrec, _, F)), + _, + false), ( EqPrec < FPrec -> true ; FPrec > 0, F == Value, graphic_token_char(F) -> @@ -210,15 +211,15 @@ needs_bracketing(Value, Op) :- write_goal(G, VarList, MaxDepth) :- ( G = (Var = Value) -> ( var(Value) -> - select((Var = _), VarList, NewVarList) + select((Var = _), VarList, NewVarList) ; VarList = NewVarList ), write(Var), write(' = '), ( needs_bracketing(Value, (=)) -> - write('('), - write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), - write(')') + write('('), + write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), + write(')') ; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]) ) ; G == [] -> @@ -229,20 +230,20 @@ write_goal(G, VarList, MaxDepth) :- write_last_goal(G, VarList, MaxDepth) :- ( G = (Var = Value) -> ( var(Value) -> - select((Var = _), VarList, NewVarList) + select((Var = _), VarList, NewVarList) ; VarList = NewVarList ), write(Var), write(' = '), ( needs_bracketing(Value, (=)) -> - write('('), - write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), - write(')') + write('('), + write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), + write(')') ; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), - ( trailing_period_is_ambiguous(Value) -> - write(' ') - ; true - ) + ( trailing_period_is_ambiguous(Value) -> + write(' ') + ; true + ) ) ; G == [] -> write('true') @@ -272,8 +273,13 @@ trailing_period_is_ambiguous(Value) :- ValueChars \== ['.'], graphic_token_char(Char). +term_variables_under_max_depth(Term, MaxDepth, Vars) :- + '$term_variables_under_max_depth'(Term, MaxDepth, Vars). + write_eqs_and_read_input(B, VarList) :- - term_variables(VarList, Vars0), + gather_query_vars(VarList, OrigVars), + % one layer of depth added for (=/2) functor + '$term_variables_under_max_depth'(OrigVars, 22, Vars0), '$term_attributed_variables'(VarList, AttrVars), '$project_atts':project_attributes(Vars0, AttrVars), copy_term(AttrVars, AttrVars, AttrGoals), @@ -281,12 +287,13 @@ write_eqs_and_read_input(B, VarList) :- append([Vars0, AttrGoalVars, AttrVars], Vars), charsio:extend_var_list(Vars, VarList, NewVarList, fabricated), '$get_b_value'(B0), - gather_query_vars(VarList, OrigVars), gather_equations(NewVarList, OrigVars, Equations), append(Equations, AttrGoals, Goals), - term_variables(Equations, EquationVars), - append([AttrGoalVars, EquationVars], Vars1), - charsio:extend_var_list(Vars1, VarList, NewVarList0, fabricated), + % one layer of depth added for (=/2) functor + maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars), + append([AttrGoalVars | EquationVars], Vars1), + sort(Vars1, Vars2), + charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated), ( bb_get('$first_answer', true) -> write(' '), bb_put('$first_answer', false) @@ -294,11 +301,11 @@ write_eqs_and_read_input(B, VarList) :- ), ( B0 == B -> ( Goals == [] -> - write('true.'), nl + write('true.'), nl ; loader:thread_goals(Goals, ThreadedGoals, (',')), - write_eq(ThreadedGoals, NewVarList0, 20), - write('.'), - nl + write_eq(ThreadedGoals, NewVarList0, 20), + write('.'), + nl ) ; loader:thread_goals(Goals, ThreadedGoals, (',')), write_eq(ThreadedGoals, NewVarList0, 20), @@ -340,7 +347,7 @@ gather_query_vars([_ = Var | Vars], QueryVars) :- QueryVars = [Var | QueryVars0], gather_query_vars(Vars, QueryVars0) ; - gather_query_vars(Vars, QueryVars) + gather_query_vars(Vars, QueryVars) ). gather_query_vars([], []). @@ -358,8 +365,8 @@ select_all([OtherVar = OtherValue | Pairs], Var, Value, Vars, NewPairs) :- Vars = [OtherVar = OtherValue | Vars0], select_all(Pairs, Var, Value, Vars0, NewPairs) ; - NewPairs = [OtherVar = OtherValue | NewPairs0], - select_all(Pairs, Var, Value, Vars, NewPairs0) + NewPairs = [OtherVar = OtherValue | NewPairs0], + select_all(Pairs, Var, Value, Vars, NewPairs0) ). gather_equations([], _, []). @@ -370,11 +377,11 @@ gather_equations([Var = Value | Pairs], OrigVarList, Goals) :- append([Var = Value | VarEqs], Goals0, Goals), gather_equations(NewPairs, OrigVarList, Goals0) ; - gather_equations(Pairs, OrigVarList, Goals) + gather_equations(Pairs, OrigVarList, Goals) ) ; - Goals = [Var = Value | Goals0], - gather_equations(Pairs, OrigVarList, Goals0) + Goals = [Var = Value | Goals0], + gather_equations(Pairs, OrigVarList, Goals0) ). print_exception(E) :- diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 00000000..57c999eb --- /dev/null +++ b/src/types.rs @@ -0,0 +1,739 @@ +use crate::arena::*; +use crate::atom_table::*; +use crate::forms::*; +use crate::machine::machine_indices::*; +use crate::machine::partial_string::PartialString; +use crate::parser::ast::Fixnum; + +use modular_bitfield::prelude::*; + +use std::cmp::Ordering; +use std::convert::TryFrom; +use std::fmt; +use std::mem; +use std::ops::{Add, Sub, SubAssign}; + +#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[bits = 6] +pub enum HeapCellValueTag { + // non-constants / tags with adjoining forwarding bits. + Cons = 0b00, + F64 = 0b01, + Str = 0b000010, + Lis = 0b000011, + Var = 0b000110, + StackVar = 0b000111, + AttrVar = 0b010011, + PStrLoc = 0b111111, + PStrOffset = 0b001110, + // constants. + Fixnum = 0b010010, + Char = 0b011011, + Atom = 0b001010, + PStr = 0b001011, + CStr = 0b010110, // a complete string. +} + +#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[bits = 6] +pub enum HeapCellValueView { + // non-constants / tags with adjoining forwarding bits. + Cons = 0b00, + F64 = 0b01, + Str = 0b000010, + Lis = 0b000011, + Var = 0b000110, + StackVar = 0b000111, + AttrVar = 0b010011, + PStrLoc = 0b111111, + PStrOffset = 0b001110, + // constants. + Fixnum = 0b010010, + Char = 0b011011, + Atom = 0b001010, + PStr = 0b001011, + CStr = 0b010110, + // trail elements. + TrailedHeapVar = 0b011110, + TrailedStackVar = 0b011111, + TrailedAttrVarHeapLink = 0b101110, + TrailedAttrVarListLink = 0b100010, + TrailedAttachedValue = 0b101010, + TrailedBlackboardEntry = 0b100110, + TrailedBlackboardOffset = 0b100111, +} + +#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[bits = 2] +pub enum ConsPtrMaskTag { + Cons = 0b00, + F64 = 0b01, +} + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug)] +pub struct ConsPtr { + ptr: B61, + m: bool, + tag: ConsPtrMaskTag, +} + +impl ConsPtr { + #[inline(always)] + pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self { + ConsPtr::new() + .with_ptr(ptr as *const u8 as u64) + .with_m(false) + .with_tag(tag) + } + + #[inline] + pub fn as_ptr(self) -> *mut u8 { + self.ptr() as *mut _ + } +} + +#[derive(BitfieldSpecifier, Copy, Clone, Debug)] +#[bits = 6] +pub(crate) enum RefTag { + HeapCell = 0b0110, + StackCell = 0b111, + AttrVar = 0b10011, +} + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Ref { + val: B56, + #[allow(unused)] m: bool, + #[allow(unused)] f: bool, + tag: RefTag, +} + +impl Ord for Ref { + fn cmp(&self, rhs: &Ref) -> Ordering { + match self.get_tag() { + RefTag::HeapCell | RefTag::AttrVar => { + match rhs.get_tag() { + RefTag::StackCell => Ordering::Less, + _ => self.get_value().cmp(&rhs.get_value()), + } + } + RefTag::StackCell => { + match rhs.get_tag() { + RefTag::StackCell => + self.get_value().cmp(&rhs.get_value()), + _ => + Ordering::Greater, + } + } + } + } +} + +impl PartialOrd for Ref { + fn partial_cmp(&self, rhs: &Self) -> Option { + Some(self.cmp(rhs)) + } +} + +impl Ref { + #[inline(always)] + pub(crate) fn build_with(tag: RefTag, value: u64) -> Self { + Ref::new().with_tag(tag).with_val(value) + } + + #[inline(always)] + pub(crate) fn get_tag(self) -> RefTag { + self.tag() + } + + #[inline(always)] + pub(crate) fn get_value(self) -> u64 { + self.val() + } + + #[inline(always)] + pub(crate) fn as_heap_cell_value(self) -> HeapCellValue { + HeapCellValue::from_bytes(self.into_bytes()) + } + + #[inline(always)] + pub(crate) fn heap_cell(h: usize) -> Self { + Ref::build_with(RefTag::HeapCell, h as u64) + } + + #[inline(always)] + pub(crate) fn stack_cell(h: usize) -> Self { + Ref::build_with(RefTag::StackCell, h as u64) + } + + #[inline(always)] + pub(crate) fn attr_var(h: usize) -> Self { + Ref::build_with(RefTag::AttrVar, h as u64) + } +} + +#[derive(Debug, Clone, Copy)] +pub enum TrailRef { + Ref(Ref), + AttrVarHeapLink(usize), + AttrVarListLink(usize, usize), + BlackboardEntry(Atom), + BlackboardOffset(Atom, HeapCellValue), // key atom, key value +} + +#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[bits = 6] +pub(crate) enum TrailEntryTag { + TrailedHeapVar = 0b011110, + TrailedStackVar = 0b011111, + TrailedAttrVar = 0b101110, + TrailedAttrVarHeapLink = 0b100010, + TrailedAttrVarListLink = 0b100011, + TrailedAttachedValue = 0b101010, + TrailedBlackboardEntry = 0b100110, + TrailedBlackboardOffset = 0b100111, +} + +#[bitfield] +#[derive(Copy, Clone, Debug)] +#[repr(u64)] +pub(crate) struct TrailEntry { + val: B56, + #[allow(unused)] f: bool, + #[allow(unused)] m: bool, + #[allow(unused)] tag: TrailEntryTag, +} + +impl TrailEntry { + #[inline(always)] + pub(crate) fn build_with(tag: TrailEntryTag, value: u64) -> Self { + TrailEntry::new() + .with_tag(tag) + .with_m(false) + .with_f(false) + .with_val(value) + } + + #[inline(always)] + pub(crate) fn get_tag(self) -> TrailEntryTag { + match self.tag_or_err() { + Ok(tag) => tag, + Err(_) => TrailEntryTag::TrailedAttachedValue, + } + } + + #[inline] + pub(crate) fn get_value(self) -> u64 { + self.val() + } +} + +#[repr(u64)] +#[bitfield] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub struct HeapCellValue { + val: B56, + f: bool, + m: bool, + tag: HeapCellValueTag, +} + +impl fmt::Debug for HeapCellValue { + fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result { + match self.get_tag() { + tag @ (HeapCellValueTag::Cons | HeapCellValueTag::F64) => { + let cons_ptr = ConsPtr::from_bytes(self.into_bytes()); + + f.debug_struct("HeapCellValue") + .field("tag", &tag) + .field("ptr", &cons_ptr.ptr()) + .field("m", &cons_ptr.m()) + .finish() + } + HeapCellValueTag::Atom => { + let (name, arity) = cell_as_atom_cell!(self) + .get_name_and_arity(); + + f.debug_struct("HeapCellValue") + .field("tag", &HeapCellValueTag::Atom) + .field("name", &name.as_str()) + .field("arity", &arity) + .field("m", &self.m()) + .field("f", &self.f()) + .finish() + } + HeapCellValueTag::PStr => { + let (name, _) = cell_as_atom_cell!(self) + .get_name_and_arity(); + + f.debug_struct("HeapCellValue") + .field("tag", &HeapCellValueTag::PStr) + .field("contents", &name.as_str()) + .field("m", &self.m()) + .field("f", &self.f()) + .finish() + } + tag => { + f.debug_struct("HeapCellValue") + .field("tag", &tag) + .field("value", &self.get_value()) + .field("m", &self.get_mark_bit()) + .field("f", &self.get_forwarding_bit()) + .finish() + } + } + } +} + +impl From> for HeapCellValue { + #[inline] + fn from(arena_ptr: TypedArenaPtr) -> HeapCellValue { + HeapCellValue::from(arena_ptr.header_ptr() as u64) + } +} + +impl From for HeapCellValue { + #[inline] + fn from(f64_ptr: F64Ptr) -> HeapCellValue { + HeapCellValue::from_bytes( + ConsPtr::from(f64_ptr.as_ptr() as u64) + .with_tag(ConsPtrMaskTag::F64) + .with_m(false) + .into_bytes(), + ) + } +} + +impl From for HeapCellValue { + #[inline(always)] + fn from(cons_ptr: ConsPtr) -> HeapCellValue { + HeapCellValue::from_bytes( + ConsPtr::from(cons_ptr.as_ptr() as u64) + .with_tag(ConsPtrMaskTag::Cons) + .with_m(false) + .into_bytes(), + ) + } +} + +impl<'a> From<(Number, &mut Arena)> for HeapCellValue { + #[inline(always)] + fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue { + match n { + Number::Float(n) => HeapCellValue::from(arena_alloc!(n, arena)), + Number::Integer(n) => HeapCellValue::from(n), + Number::Rational(n) => HeapCellValue::from(n), + Number::Fixnum(n) => fixnum_as_cell!(n), + } + } +} + +impl HeapCellValue { + #[inline(always)] + pub fn build_with(tag: HeapCellValueTag, value: u64) -> Self { + HeapCellValue::new() + .with_tag(tag) + .with_val(value) + .with_m(false) + .with_f(false) + } + + #[inline] + pub fn is_string_terminator(self, heap: &[HeapCellValue]) -> bool { + read_heap_cell!(self, + (HeapCellValueTag::Atom, (name, arity)) => { + name == atom!("[]") && arity == 0 + } + (HeapCellValueTag::CStr) => { + true + } + (HeapCellValueTag::PStrOffset, pstr_offset) => { + heap[pstr_offset].get_tag() == HeapCellValueTag::CStr + } + _ => { + false + } + ) + } + + #[inline(always)] + pub fn is_forwarded(self) -> bool { + self.get_forwarding_bit().unwrap_or(false) + } + + #[inline] + pub fn is_ref(self) -> bool { + match self.get_tag() { + HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::Var | + HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc | + HeapCellValueTag::PStrOffset => true, + _ => false, + } + } + + #[inline] + pub fn as_char(self) -> Option { + read_heap_cell!(self, + (HeapCellValueTag::Char, c) => { + Some(c) + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity > 0 { + return None; + } + + name.as_char() + } + _ => { + None + } + ) + } + + #[inline] + pub fn is_constant(self) -> bool { + match self.get_tag() { + HeapCellValueTag::Cons | HeapCellValueTag::F64 | HeapCellValueTag::Fixnum | + HeapCellValueTag::Char | HeapCellValueTag::CStr => { + true + } + HeapCellValueTag::Atom => { + cell_as_atom_cell!(self).get_arity() == 0 + } + _ => { + false + } + } + } + + #[inline(always)] + pub fn is_stack_var(self) -> bool { + self.get_tag() == HeapCellValueTag::StackVar + } + + #[inline] + pub fn is_compound(self) -> bool { + match self.get_tag() { + HeapCellValueTag::Str + | HeapCellValueTag::Lis + | HeapCellValueTag::CStr + | HeapCellValueTag::PStr + | HeapCellValueTag::PStrLoc + | HeapCellValueTag::PStrOffset => { + true + } + HeapCellValueTag::Atom => { + cell_as_atom_cell!(self).get_arity() > 0 + } + _ => { false } + } + } + + #[inline] + pub fn is_var(self) -> bool { + read_heap_cell!(self, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + true + } + _ => { + false + } + ) + } + + #[inline] + pub(crate) fn as_var(self) -> Option { + read_heap_cell!(self, + (HeapCellValueTag::Var, h) => { + Some(Ref::heap_cell(h)) + } + (HeapCellValueTag::AttrVar, h) => { + Some(Ref::attr_var(h)) + } + (HeapCellValueTag::StackVar, s) => { + Some(Ref::stack_cell(s)) + } + _ => { + None + } + ) + } + + #[inline] + pub fn get_value(self) -> usize { + self.val() as usize + } + + #[inline] + pub fn set_value(&mut self, val: usize) { + self.set_val(val as u64); + } + + #[inline] + pub fn get_tag(self) -> HeapCellValueTag { + match self.tag_or_err() { + Ok(tag) => tag, + Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() { + ConsPtrMaskTag::Cons => HeapCellValueTag::Cons, + ConsPtrMaskTag::F64 => HeapCellValueTag::F64, + }, + } + } + + #[inline] + pub fn to_atom(self) -> Option { + match self.tag() { + HeapCellValueTag::Atom => Some(Atom::from((self.val() << 3) as usize)), + _ => None, + } + } + + #[inline] + pub fn to_pstr(self) -> Option { + match self.tag() { + HeapCellValueTag::PStr => { + Some(PartialString::from(Atom::from((self.val() as usize) << 3))) + } + _ => None, + } + } + + #[inline] + pub fn to_fixnum(self) -> Option { + match self.get_tag() { + HeapCellValueTag::Fixnum => Some(Fixnum::from_bytes(self.into_bytes())), + _ => None, + } + } + + #[inline] + pub fn to_untyped_arena_ptr(self) -> Option { + match self.tag() { + HeapCellValueTag::Cons => Some(UntypedArenaPtr::from_bytes(self.into_bytes())), + _ => None, + } + } + + #[inline] + pub fn get_forwarding_bit(self) -> Option { + match self.get_tag() { + HeapCellValueTag::Cons // the list of non-forwardable cell tags. + | HeapCellValueTag::F64 + // | HeapCellValueTag::Atom + // | HeapCellValueTag::PStr + | HeapCellValueTag::Fixnum + | HeapCellValueTag::Char => None, + _ => Some(self.f()), + } + } + + #[inline] + pub fn set_forwarding_bit(&mut self, f: bool) { + match self.get_tag() { + HeapCellValueTag::Cons // the list of non-forwardable cell tags. + | HeapCellValueTag::F64 + // | HeapCellValueTag::Atom + // | HeapCellValueTag::PStr + | HeapCellValueTag::Fixnum + | HeapCellValueTag::Char => {} + _ => self.set_f(f), + } + } + + #[inline] + pub fn get_mark_bit(self) -> bool { + match self.get_tag() { + HeapCellValueTag::Cons | HeapCellValueTag::F64 => { + ConsPtr::from_bytes(self.into_bytes()).m() + } + _ => self.m(), + } + } + + #[inline] + pub fn set_mark_bit(&mut self, m: bool) { + match self.get_tag() { + HeapCellValueTag::Cons | HeapCellValueTag::F64 => { + let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m); + *self = HeapCellValue::from_bytes(value.into_bytes()); + } + _ => self.set_m(m), + } + } + + pub fn order_category(self) -> Option { + match Number::try_from(self).ok() { + Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => { + Some(TermOrderCategory::Integer) + } + Some(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint), + None => match self.get_tag() { + HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => { + Some(TermOrderCategory::Variable) + } + HeapCellValueTag::Char => Some(TermOrderCategory::Atom), + HeapCellValueTag::Atom => { + Some(if cell_as_atom_cell!(self).get_arity() > 0 { + TermOrderCategory::Compound + } else { + TermOrderCategory::Atom + }) + } + HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | + HeapCellValueTag::CStr | HeapCellValueTag::Str => { + Some(TermOrderCategory::Compound) + } + _ => { + None + } + }, + } + } + + #[inline(always)] + pub fn is_protected(self, e: usize) -> bool { + read_heap_cell!(self, + (HeapCellValueTag::StackVar, s) => { + s < e + } + _ => { + true + } + ) + } +} + +const_assert!(mem::size_of::() == 8); + +#[bitfield] +#[repr(u64)] +#[derive(Copy, Clone, Debug)] +pub struct UntypedArenaPtr { + ptr: B61, + m: bool, + #[allow(unused)] padding: B2, +} + +const_assert!(mem::size_of::() == 8); + +impl From<*const ArenaHeader> for UntypedArenaPtr { + #[inline] + fn from(ptr: *const ArenaHeader) -> UntypedArenaPtr { + unsafe { mem::transmute(ptr) } + } +} + +impl From for *const ArenaHeader { + #[inline] + fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader { + unsafe { mem::transmute(ptr) } + } +} + +impl UntypedArenaPtr { + #[inline] + pub fn set_mark_bit(&mut self, m: bool) { + self.set_m(m); + } + + #[inline] + pub fn get_ptr(self) -> *const u8 { + self.ptr() as *const u8 + } + + #[inline] + pub fn get_tag(self) -> ArenaHeaderTag { + unsafe { + let header = *(self.ptr() as *const ArenaHeader); + header.get_tag() + } + } + + #[inline] + pub fn payload_offset(self) -> *const u8 { + unsafe { + self.get_ptr() + .offset(mem::size_of::() as isize) + } + } + + #[inline] + pub fn get_mark_bit(self) -> bool { + self.m() + } +} + +impl Add for HeapCellValue { + type Output = HeapCellValue; + + fn add(self, rhs: usize) -> Self::Output { + match self.get_tag() { + tag @ HeapCellValueTag::Str | + tag @ HeapCellValueTag::Lis | + tag @ HeapCellValueTag::PStrOffset | + tag @ HeapCellValueTag::PStrLoc | + tag @ HeapCellValueTag::Var | + tag @ HeapCellValueTag::AttrVar => { + HeapCellValue::build_with(tag, (self.get_value() + rhs) as u64) + } + _ => { + self + } + } + } +} + +impl Sub for HeapCellValue { + type Output = HeapCellValue; + + fn sub(self, rhs: usize) -> Self::Output { + match self.get_tag() { + tag @ HeapCellValueTag::Str | + tag @ HeapCellValueTag::Lis | + tag @ HeapCellValueTag::PStrOffset | + tag @ HeapCellValueTag::PStrLoc | + tag @ HeapCellValueTag::Var | + tag @ HeapCellValueTag::AttrVar => { + HeapCellValue::build_with(tag, (self.get_value() - rhs) as u64) + } + _ => { + self + } + } + } +} + +impl SubAssign for HeapCellValue { + #[inline(always)] + fn sub_assign(&mut self, rhs: usize) { + *self = *self - rhs; + } +} + +impl Sub for HeapCellValue { + type Output = HeapCellValue; + + fn sub(self, rhs: i64) -> Self::Output { + if rhs < 0 { + match self.get_tag() { + tag @ HeapCellValueTag::Str | + tag @ HeapCellValueTag::Lis | + tag @ HeapCellValueTag::PStrOffset | + tag @ HeapCellValueTag::Var | + tag @ HeapCellValueTag::AttrVar => { + HeapCellValue::build_with(tag, (self.get_value() + rhs.abs() as usize) as u64) + } + _ => { + self + } + } + } else { + self.sub(rhs as usize) + } + } +} + diff --git a/src/write.rs b/src/write.rs index 1c1fc3dc..49e8c10b 100644 --- a/src/write.rs +++ b/src/write.rs @@ -1,10 +1,17 @@ +use crate::arena::*; +use crate::atom_table::*; use crate::clause_types::*; use crate::forms::*; -use crate::indexing::IndexingCodePtr; use crate::instructions::*; use crate::machine::loader::CompilationTarget; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; +use crate::machine::partial_string::*; +use crate::machine::streams::*; +use crate::parser::rug::{Integer, Rational}; +use crate::types::*; + +use ordered_float::OrderedFloat; use std::fmt; @@ -13,7 +20,9 @@ impl fmt::Display for LocalCodePtr { match self { LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p), LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"), - LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i), + LocalCodePtr::IndexingBuf(p, o, i) => { + write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i) + } } } } @@ -21,74 +30,50 @@ impl fmt::Display for LocalCodePtr { impl fmt::Display for REPLCodePtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - REPLCodePtr::AddDiscontiguousPredicate => - write!(f, "REPLCodePtr::AddDiscontiguousPredicate"), - REPLCodePtr::AddDynamicPredicate => - write!(f, "REPLCodePtr::AddDynamicPredicate"), - REPLCodePtr::AddMultifilePredicate => - write!(f, "REPLCodePtr::AddMultifilePredicate"), - REPLCodePtr::AddGoalExpansionClause => - write!(f, "REPLCodePtr::AddGoalExpansionClause"), - REPLCodePtr::AddTermExpansionClause => - write!(f, "REPLCodePtr::AddTermExpansionClause"), - REPLCodePtr::AddInSituFilenameModule => - write!(f, "REPLCodePtr::AddInSituFilenameModule"), - REPLCodePtr::AbolishClause => - write!(f, "REPLCodePtr::AbolishClause"), - REPLCodePtr::Assertz => - write!(f, "REPLCodePtr::Assertz"), - REPLCodePtr::Asserta => - write!(f, "REPLCodePtr::Asserta"), - REPLCodePtr::Retract => - write!(f, "REPLCodePtr::Retract"), - REPLCodePtr::ClauseToEvacuable => - write!(f, "REPLCodePtr::ClauseToEvacuable"), - REPLCodePtr::ScopedClauseToEvacuable => - write!(f, "REPLCodePtr::ScopedClauseToEvacuable"), - REPLCodePtr::ConcludeLoad => - write!(f, "REPLCodePtr::ConcludeLoad"), - REPLCodePtr::DeclareModule => - write!(f, "REPLCodePtr::DeclareModule"), - REPLCodePtr::LoadCompiledLibrary => - write!(f, "REPLCodePtr::LoadCompiledLibrary"), - REPLCodePtr::LoadContextSource => - write!(f, "REPLCodePtr::LoadContextSource"), - REPLCodePtr::LoadContextFile => - write!(f, "REPLCodePtr::LoadContextFile"), - REPLCodePtr::LoadContextDirectory => - write!(f, "REPLCodePtr::LoadContextDirectory"), - REPLCodePtr::LoadContextModule => - write!(f, "REPLCodePtr::LoadContextModule"), - REPLCodePtr::LoadContextStream => - write!(f, "REPLCodePtr::LoadContextStream"), - REPLCodePtr::PopLoadContext => - write!(f, "REPLCodePtr::PopLoadContext"), - REPLCodePtr::PopLoadStatePayload => - write!(f, "REPLCodePtr::PopLoadStatePayload"), - REPLCodePtr::PushLoadContext => - write!(f, "REPLCodePtr::PushLoadContext"), - REPLCodePtr::PushLoadStatePayload => - write!(f, "REPLCodePtr::PushLoadStatePayload"), - REPLCodePtr::UseModule => - write!(f, "REPLCodePtr::UseModule"), - REPLCodePtr::MetaPredicateProperty => - write!(f, "REPLCodePtr::MetaPredicateProperty"), - REPLCodePtr::BuiltInProperty => - write!(f, "REPLCodePtr::BuiltInProperty"), - REPLCodePtr::DynamicProperty => - write!(f, "REPLCodePtr::DynamicProperty"), - REPLCodePtr::MultifileProperty => - write!(f, "REPLCodePtr::MultifileProperty"), - REPLCodePtr::DiscontiguousProperty => - write!(f, "REPLCodePtr::DiscontiguousProperty"), - REPLCodePtr::IsConsistentWithTermQueue => - write!(f, "REPLCodePtr::IsConsistentWithTermQueue"), - REPLCodePtr::FlushTermQueue => - write!(f, "REPLCodePtr::FlushTermQueue"), - REPLCodePtr::RemoveModuleExports => - write!(f, "REPLCodePtr::RemoveModuleExports"), - REPLCodePtr::AddNonCountedBacktracking => - write!(f, "REPLCodePtr::AddNonCountedBacktracking"), + REPLCodePtr::AddDiscontiguousPredicate => { + write!(f, "REPLCodePtr::AddDiscontiguousPredicate") + } + REPLCodePtr::AddDynamicPredicate => write!(f, "REPLCodePtr::AddDynamicPredicate"), + REPLCodePtr::AddMultifilePredicate => write!(f, "REPLCodePtr::AddMultifilePredicate"), + REPLCodePtr::AddGoalExpansionClause => write!(f, "REPLCodePtr::AddGoalExpansionClause"), + REPLCodePtr::AddTermExpansionClause => write!(f, "REPLCodePtr::AddTermExpansionClause"), + REPLCodePtr::AddInSituFilenameModule => { + write!(f, "REPLCodePtr::AddInSituFilenameModule") + } + REPLCodePtr::AbolishClause => write!(f, "REPLCodePtr::AbolishClause"), + REPLCodePtr::Assertz => write!(f, "REPLCodePtr::Assertz"), + REPLCodePtr::Asserta => write!(f, "REPLCodePtr::Asserta"), + REPLCodePtr::Retract => write!(f, "REPLCodePtr::Retract"), + REPLCodePtr::ClauseToEvacuable => write!(f, "REPLCodePtr::ClauseToEvacuable"), + REPLCodePtr::ScopedClauseToEvacuable => { + write!(f, "REPLCodePtr::ScopedClauseToEvacuable") + } + REPLCodePtr::ConcludeLoad => write!(f, "REPLCodePtr::ConcludeLoad"), + REPLCodePtr::DeclareModule => write!(f, "REPLCodePtr::DeclareModule"), + REPLCodePtr::LoadCompiledLibrary => write!(f, "REPLCodePtr::LoadCompiledLibrary"), + REPLCodePtr::LoadContextSource => write!(f, "REPLCodePtr::LoadContextSource"), + REPLCodePtr::LoadContextFile => write!(f, "REPLCodePtr::LoadContextFile"), + REPLCodePtr::LoadContextDirectory => write!(f, "REPLCodePtr::LoadContextDirectory"), + REPLCodePtr::LoadContextModule => write!(f, "REPLCodePtr::LoadContextModule"), + REPLCodePtr::LoadContextStream => write!(f, "REPLCodePtr::LoadContextStream"), + REPLCodePtr::PopLoadContext => write!(f, "REPLCodePtr::PopLoadContext"), + REPLCodePtr::PopLoadStatePayload => write!(f, "REPLCodePtr::PopLoadStatePayload"), + REPLCodePtr::PushLoadContext => write!(f, "REPLCodePtr::PushLoadContext"), + REPLCodePtr::PushLoadStatePayload => write!(f, "REPLCodePtr::PushLoadStatePayload"), + REPLCodePtr::UseModule => write!(f, "REPLCodePtr::UseModule"), + REPLCodePtr::MetaPredicateProperty => write!(f, "REPLCodePtr::MetaPredicateProperty"), + REPLCodePtr::BuiltInProperty => write!(f, "REPLCodePtr::BuiltInProperty"), + REPLCodePtr::DynamicProperty => write!(f, "REPLCodePtr::DynamicProperty"), + REPLCodePtr::MultifileProperty => write!(f, "REPLCodePtr::MultifileProperty"), + REPLCodePtr::DiscontiguousProperty => write!(f, "REPLCodePtr::DiscontiguousProperty"), + REPLCodePtr::IsConsistentWithTermQueue => { + write!(f, "REPLCodePtr::IsConsistentWithTermQueue") + } + REPLCodePtr::FlushTermQueue => write!(f, "REPLCodePtr::FlushTermQueue"), + REPLCodePtr::RemoveModuleExports => write!(f, "REPLCodePtr::RemoveModuleExports"), + REPLCodePtr::AddNonCountedBacktracking => { + write!(f, "REPLCodePtr::AddNonCountedBacktracking") + } } } } @@ -107,7 +92,7 @@ impl fmt::Display for CompilationTarget { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { CompilationTarget::User => write!(f, "user"), - CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name), + CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name.as_str()), } } } @@ -122,11 +107,17 @@ impl fmt::Display for FactInstruction { write!(f, "get_list {}{}", lvl, r.reg_num()) } &FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => { - write!(f, "get_partial_string({}, {}, {}, {})", - lvl, s, r, has_tail) + write!( + f, + "get_partial_string({}, {}, {}, {})", + lvl, + s.as_str(), + r, + has_tail + ) } &FactInstruction::GetStructure(ref ct, ref arity, ref r) => { - write!(f, "get_structure {}/{}, {}", ct.name(), arity, r) + write!(f, "get_structure {}/{}, {}", ct.name().as_str(), arity, r) } &FactInstruction::GetValue(ref x, ref a) => { write!(f, "get_value {}, A{}", x, a) @@ -166,11 +157,17 @@ impl fmt::Display for QueryInstruction { write!(f, "put_list {}{}", lvl, r.reg_num()) } &QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => { - write!(f, "put_partial_string({}, {}, {}, {})", - lvl, s, r, has_tail) + write!( + f, + "put_partial_string({}, {}, {}, {})", + lvl, + s.as_str(), + r, + has_tail + ) } &QueryInstruction::PutStructure(ref ct, ref arity, ref r) => { - write!(f, "put_structure {}/{}, {}", ct.name(), arity, r) + write!(f, "put_structure {}/{}, {}", ct.name().as_str(), arity, r) } &QueryInstruction::PutUnsafeValue(y, a) => write!(f, "put_unsafe_value Y{}, A{}", y, a), &QueryInstruction::PutValue(ref x, ref a) => write!(f, "put_value {}, A{}", x, a), @@ -214,12 +211,12 @@ impl fmt::Display for ClauseType { &ClauseType::System(SystemClauseType::SetCutPoint(r)) => { write!(f, "$set_cp({})", r) } - &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { + &ClauseType::Named(ref name, _, ref idx) => { let idx = idx.0.get(); - write!(f, "{}/{}", name, idx) + write!(f, "{}/{}", name.as_str(), idx) } ref ct => { - write!(f, "{}", ct.name()) + write!(f, "{}", ct.name().as_str()) } } } @@ -227,6 +224,52 @@ impl fmt::Display for ClauseType { impl fmt::Display for HeapCellValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + read_heap_cell!(*self, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + write!(f, "{}", name.as_str()) + } else { + write!( + f, + "{}/{}", + name.as_str(), + arity + ) + } + } + (HeapCellValueTag::PStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + + write!( + f, + "pstr ( \"{}\", )", + pstr.as_str_from(0) + ) + } + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::Integer, n) => { + write!(f, "{}", n) + } + (ArenaHeaderTag::Rational, r) => { + write!(f, "{}", r) + } + (ArenaHeaderTag::F64, fl) => { + write!(f, "{}", fl) + } + (ArenaHeaderTag::Stream, stream) => { + write!(f, "$stream({})", stream.as_ptr() as usize) + } + _ => { + write!(f, "") + } + ) + } + _ => { + unreachable!() + } + ) + /* match self { &HeapCellValue::Addr(ref addr) => write!(f, "{}", addr), &HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()), @@ -260,9 +303,11 @@ impl fmt::Display for HeapCellValue { write!(f, "$tcp_listener({})", tcp_listener.local_addr().unwrap()) } } + */ } } +/* impl fmt::Display for DBRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -273,7 +318,9 @@ impl fmt::Display for DBRef { } } } +*/ +/* impl fmt::Display for Addr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -296,6 +343,7 @@ impl fmt::Display for Addr { } } } +*/ impl fmt::Display for ControlInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -353,29 +401,45 @@ impl fmt::Display for ChoiceInstruction { &ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => { write!(f, "dynamic_else {}, {}, fail({})", offset, d, i) } - &ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Next(i)) => { + &ChoiceInstruction::DynamicInternalElse( + offset, + Death::Infinity, + NextOrFail::Next(i), + ) => { write!(f, "dynamic_internal_else {}, {}, {}", offset, "inf", i) } - &ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Fail(i)) => { - write!(f, "dynamic_internal_else {}, {}, fail({})", offset, "inf", i) + &ChoiceInstruction::DynamicInternalElse( + offset, + Death::Infinity, + NextOrFail::Fail(i), + ) => { + write!( + f, + "dynamic_internal_else {}, {}, fail({})", + offset, "inf", i + ) } - &ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Next(i)) => { + &ChoiceInstruction::DynamicInternalElse( + offset, + Death::Finite(d), + NextOrFail::Next(i), + ) => { write!(f, "dynamic_internal_else {}, {}, {}", offset, d, i) } - &ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => { + &ChoiceInstruction::DynamicInternalElse( + offset, + Death::Finite(d), + NextOrFail::Fail(i), + ) => { write!(f, "dynamic_internal_else {}, {}, fail({})", offset, d, i) } - &ChoiceInstruction::TryMeElse(offset) => - write!(f, "try_me_else {}", offset), + &ChoiceInstruction::TryMeElse(offset) => write!(f, "try_me_else {}", offset), &ChoiceInstruction::DefaultRetryMeElse(offset) => { write!(f, "retry_me_else_by_default {}", offset) } - &ChoiceInstruction::RetryMeElse(offset) => - write!(f, "retry_me_else {}", offset), - &ChoiceInstruction::DefaultTrustMe(_) => - write!(f, "trust_me_by_default"), - &ChoiceInstruction::TrustMe(_) => - write!(f, "trust_me"), + &ChoiceInstruction::RetryMeElse(offset) => write!(f, "retry_me_else {}", offset), + &ChoiceInstruction::DefaultTrustMe(_) => write!(f, "trust_me_by_default"), + &ChoiceInstruction::TrustMe(_) => write!(f, "trust_me"), } } } @@ -434,8 +498,8 @@ impl fmt::Display for SessionError { write!( f, "module {} does not contain claimed export {}/{}", - module, - key.0, + module.as_str(), + key.0.as_str(), key.1, ) } @@ -452,12 +516,23 @@ impl fmt::Display for SessionError { write!(f, "queries cannot be defined as facts.") } &SessionError::ModuleCannotImportSelf(ref module_name) => { - write!(f, "modules ({}, in this case) cannot import themselves.", - module_name) + write!( + f, + "modules ({}, in this case) cannot import themselves.", + module_name.as_str() + ) } - &SessionError::PredicateNotMultifileOrDiscontiguous(ref compilation_target, ref key) => { - write!(f, "module {} does not define {}/{} as multifile or discontiguous.", - compilation_target.module_name(), key.0, key.1) + &SessionError::PredicateNotMultifileOrDiscontiguous( + ref compilation_target, + ref key, + ) => { + write!( + f, + "module {} does not define {}/{} as multifile or discontiguous.", + compilation_target.module_name().as_str(), + key.0.as_str(), + key.1 + ) } } } @@ -466,14 +541,19 @@ impl fmt::Display for SessionError { impl fmt::Display for ExistenceError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &ExistenceError::Module(ref module_name) => { - write!(f, "the module {} does not exist", module_name) + &ExistenceError::Module(module_name) => { + write!(f, "the module {} does not exist", module_name.as_str()) } &ExistenceError::ModuleSource(ref module_source) => { write!(f, "the source/sink {} does not exist", module_source) } - &ExistenceError::Procedure(ref name, arity) => { - write!(f, "the procedure {}/{} does not exist", name, arity) + &ExistenceError::Procedure(name, arity) => { + write!( + f, + "the procedure {}/{} does not exist", + name.as_str(), + arity + ) } &ExistenceError::SourceSink(ref addr) => { write!(f, "the source/sink {} does not exist", addr) @@ -489,10 +569,10 @@ impl fmt::Display for ModuleSource { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &ModuleSource::File(ref file) => { - write!(f, "at the file {}", file) + write!(f, "at the file {}", file.as_str()) } &ModuleSource::Library(ref library) => { - write!(f, "at library({})", library) + write!(f, "at library({})", library.as_str()) } } } @@ -538,7 +618,9 @@ impl fmt::Display for Line { Ok(()) } &Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr), - &Line::DynamicIndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr), + &Line::DynamicIndexedChoice(ref indexed_choice_instr) => { + write!(f, "{}", indexed_choice_instr) + } &Line::Query(ref query_instr) => write!(f, "{}", query_instr), } } @@ -547,10 +629,10 @@ impl fmt::Display for Line { impl fmt::Display for Number { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &Number::Fixnum(n) => write!(f, "{}", n), - &Number::Float(fl) => write!(f, "{}", fl), - &Number::Integer(ref bi) => write!(f, "{}", bi), - &Number::Rational(ref r) => write!(f, "{}", r), + Number::Float(fl) => write!(f, "{}", fl), + Number::Integer(n) => write!(f, "{}", n), + Number::Rational(r) => write!(f, "{}", r), + Number::Fixnum(n) => write!(f, "{}", n.get_num()), } } } diff --git a/tests/scryer/helper.rs b/tests/scryer/helper.rs index baa057d0..93e7b7ca 100644 --- a/tests/scryer/helper.rs +++ b/tests/scryer/helper.rs @@ -31,21 +31,23 @@ impl Expectable for &[u8] { pub(crate) fn load_module_test(file: &str, expected: T) { use scryer_prolog::*; - let input = machine::Stream::from(""); - let output = machine::Stream::from(String::new()); - let error = machine::Stream::from(String::new()); + // let input = machine::Stream::from(""); + // let output = machine::Stream::from(String::new()); + // let error = machine::Stream::from(String::new()); - let mut wam = machine::Machine::new(input, output.clone(), error); + let mut wam = machine::Machine::new(); // input, output.clone(), error); + expected.assert_eq(wam.test_load_file(file).as_slice()); - wam.load_file( - file.into(), - machine::Stream::from( - std::fs::read_to_string(AsRef::::as_ref(file)).unwrap(), - ), - ); - - let output = output.bytes().unwrap(); - expected.assert_eq(output.as_slice()); + // wam.load_file( + // file.into(), + // machine::Stream::from_owned_string( + // std::fs::read_to_string(AsRef::::as_ref(file)).unwrap(), + // &mut wam.machine_st.arena, + // ), + // ); + // + // let output = output.bytes().unwrap(); + // expected.assert_eq(output.as_slice()); } pub const SCRYER_PROLOG: &str = "scryer-prolog"; -- cgit v1.2.3-70-g09d2 From ffd1b7069f0ddcc0c1c14c03560bbddc57abc8ce Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 15 Nov 2021 21:27:42 -0700 Subject: greatly reduce the number of goal expansions done in callable if/then/else --- src/clause_types.rs | 3 + src/lib/builtins.pl | 215 +++++++++++++++++--------------------- src/loader.pl | 5 +- src/machine/machine_state_impl.rs | 58 +++++----- src/machine/system_calls.rs | 48 +++++++++ 5 files changed, 177 insertions(+), 152 deletions(-) diff --git a/src/clause_types.rs b/src/clause_types.rs index e7c2c853..d3ba917c 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -284,6 +284,7 @@ pub enum SystemClauseType { GetBall, GetCurrentBlock, GetCutPoint, + GetStaggeredCutPoint, GetDoubleQuotes, InstallNewBlock, Maybe, @@ -525,6 +526,7 @@ impl SystemClauseType { &SystemClauseType::Fail => atom!("$fail"), &SystemClauseType::GetBall => atom!("$get_ball"), &SystemClauseType::GetCutPoint => atom!("$get_cp"), + &SystemClauseType::GetStaggeredCutPoint => atom!("$get_staggered_cp"), &SystemClauseType::GetCurrentBlock => atom!("$get_current_block"), &SystemClauseType::InstallNewBlock => atom!("$install_new_block"), &SystemClauseType::NextEP => atom!("$nextEP"), @@ -705,6 +707,7 @@ impl SystemClauseType { (atom!("$get_cont_chunk"), 3) => Some(SystemClauseType::GetContinuationChunk), (atom!("$get_current_block"), 1) => Some(SystemClauseType::GetCurrentBlock), (atom!("$get_cp"), 1) => Some(SystemClauseType::GetCutPoint), + (atom!("$get_staggered_cp"), 1) => Some(SystemClauseType::GetStaggeredCutPoint), (atom!("$install_new_block"), 1) => Some(SystemClauseType::InstallNewBlock), (atom!("$quoted_token"), 1) => Some(SystemClauseType::QuotedToken), (atom!("$nextEP"), 3) => Some(SystemClauseType::NextEP), diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 0c9d33f9..534edb06 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1,4 +1,4 @@ -:- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2, +:- module(builtins, [(=)/2, (\=)/2, (\+)/1, !/0, (',')/2, (->)/2, (;)/2, (=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6, (:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12, abolish/1, asserta/1, assertz/1, @@ -61,10 +61,8 @@ call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H). Module : Predicate :- - ( atom(Module) -> - '$module_call'(Module, Predicate) - ; - throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). @@ -205,142 +203,115 @@ repeat. repeat :- repeat. +:- meta_predicate ','(0,0). -:- meta_predicate ','(0, 0). - -:- meta_predicate ','(0, +, +). - -:- meta_predicate ;(0, 0). - -:- meta_predicate ;(0, 0, +). - -:- meta_predicate ->(0, 0). - -:- meta_predicate ->(0, 0, +). - - -','(G1, G2) :- - '$get_b_value'(B), - ( '$call_with_default_policy'(var(G1)) -> - throw(error(instantiation_error, (',')/2)) - ; '$call_with_default_policy'(','(G1, G2, B)) - ). - - -';'(G1, G2) :- - '$get_b_value'(B), - ( '$call_with_default_policy'(var(G1)) -> - throw(error(instantiation_error, (';')/2)) - ; '$call_with_default_policy'(';'(G1, G2, B)) - ). - - -G1 -> G2 :- - '$get_b_value'(B), - ( '$call_with_default_policy'(var(G1)) -> - throw(error(instantiation_error, (->)/2)) - ; '$call_with_default_policy'(->(G1, G2, B)) - ). - - -:-non_counted_backtracking call_or_cut/3. - -call_or_cut(G, B, ErrorPI) :- - ( '$call_with_default_policy'(var(G)) -> - throw(error(instantiation_error, ErrorPI)) - ; '$call_with_default_policy'(call_or_cut(G, B)) - ). - - -:- non_counted_backtracking control_functor/1. - -control_functor(_:G) :- nonvar(G), control_functor(G). -control_functor(call(_:C)) :- C == !. -control_functor(!). -control_functor((_,_)). -control_functor((_;_)). -control_functor((_->_)). - - -:- non_counted_backtracking call_or_cut/2. +:- meta_predicate ;(0,0). -call_or_cut(G, B) :- - ( nonvar(G), - '$call_with_default_policy'(control_functor(G)) -> - '$call_with_default_policy'(call_or_cut_interp(G, B)) - ; call(G) - ). +:- meta_predicate ->(0,0). +% '!' is for internal use as a callable no-op within if/then/else. +% Where it shouldn't be a no-op, it's interpreted under the expected +% semantics by comma_dispatch/3. -:- non_counted_backtracking call_or_cut_interp/2. +! :- '$get_staggered_cp'(B), '$set_cp'(B). -call_or_cut_interp(_ : G, B) :- - call_or_cut_interp(G, B). -call_or_cut_interp(call(_ : !), B) :- - !. % '$set_cp'(B). -call_or_cut_interp(!, B) :- - '$set_cp'(B). -call_or_cut_interp((G1, G2), B) :- - '$call_with_default_policy'(','(G1, G2, B)). -call_or_cut_interp((G1 ; G2), B) :- - '$call_with_default_policy'(';'(G1, G2, B)). -call_or_cut_interp((G1 -> G2), B) :- - '$call_with_default_policy'(->(G1, G2, B)). +G1 -> G2 :- '$get_staggered_cp'(B), call('$call'(G1)), '$set_cp'(B), call('$call'(G2)). +G ; _ :- call('$call'(G)). +_ ; G :- call('$call'(G)). -:- non_counted_backtracking (',')/3. +','(G1, G2) :- '$get_staggered_cp'(B), comma_dispatch(G1,G2,B). -','(G1, G2, B) :- - ( nonvar(G1), - '$call_with_default_policy'(control_functor(G1)) -> - '$call_with_default_policy'(call_or_cut_interp(G1, B)), - '$call_with_default_policy'(call_or_cut(G2, B, (',')/2)) - ; call(G1), - '$call_with_default_policy'(call_or_cut(G2, B, (',')/2)) - ). +set_cp(B) :- '$set_cp'(B). -:- non_counted_backtracking (;)/3. +:- non_counted_backtracking comma_dispatch_prep/3. -';'(G1, G2, B) :- - ( nonvar(G1), - '$call_with_default_policy'(control_functor(G1)) -> - '$call_with_default_policy'(';-interp'(G1, G2, B)) - ; call(G1) - ; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2)) +comma_dispatch_prep(Gs, B, [Cont|Conts]) :- + ( callable(Gs) -> + ( functor(Gs, ',', 2) -> + arg(1, Gs, G1), + arg(2, Gs, G2), + ( G1 == ! -> + Cont = builtins:set_cp(B) + ; callable(G1) -> + Cont = G1 + ; Cont = throw(error(type_error(callable, G1), call/1)) + ), + comma_dispatch_prep(G2, B, Conts) + ; Cont = Gs, + Conts = [] + ) + ; Gs == ! -> + Cont = builtins:set_cp(B), + Conts = [] + ; Cont = throw(error(type_error(callable, Gs), call/1)), + Conts = [] ). -:- non_counted_backtracking ';-interp'/3. +:- non_counted_backtracking comma_dispatch_call_list/1. -';-interp'((G1 -> G2), G3, B) :- +comma_dispatch_call_list([]). +comma_dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :- !, - ( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) -> - '$call_with_default_policy'(call_or_cut(G2, B, (->)/2)) - ; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2)) - ). -';-interp'(_:(G1 -> G2), G3, B) :- + '$call'(G1), + '$call'(G2), + '$call'(G3), + '$call'(G4), + '$call'(G5), + '$call'(G6), + '$call'(G7), + '$call'(G8), + comma_dispatch_call_list(Gs). +comma_dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :- !, - ( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) -> - '$call_with_default_policy'(call_or_cut(G2, B, (->)/2)) - ; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2)) - ). -';-interp'(G1, G2, B) :- - ( '$call_with_default_policy'(call_or_cut_interp(G1, B)) - ; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2)) - ). + '$call'(G1), + '$call'(G2), + '$call'(G3), + '$call'(G4), + '$call'(G5), + '$call'(G6), + '$call'(G7). +comma_dispatch_call_list([G1,G2,G3,G4,G5,G6]) :- + !, + '$call'(G1), + '$call'(G2), + '$call'(G3), + '$call'(G4), + '$call'(G5), + '$call'(G6). +comma_dispatch_call_list([G1,G2,G3,G4,G5]) :- + !, + '$call'(G1), + '$call'(G2), + '$call'(G3), + '$call'(G4), + '$call'(G5). +comma_dispatch_call_list([G1,G2,G3,G4]) :- + !, + '$call'(G1), + '$call'(G2), + '$call'(G3), + '$call'(G4). +comma_dispatch_call_list([G1,G2,G3]) :- + !, + '$call'(G1), + '$call'(G2), + '$call'(G3). +comma_dispatch_call_list([G1,G2]) :- + !, + '$call'(G1), + '$call'(G2). +comma_dispatch_call_list([G1]) :- + '$call'(G1). -:- non_counted_backtracking (->)/3. +:- non_counted_backtracking comma_dispatch/3. + +comma_dispatch(G1, G2, B) :- + comma_dispatch_prep((G1, G2), B, Conts), + comma_dispatch_call_list(Conts). -->(G1, G2, B) :- - ( nonvar(G1), - '$call_with_default_policy'(control_functor(G1)) -> - ( '$call_with_default_policy'(call_or_cut_interp(G1, B)) -> - '$call_with_default_policy'(call_or_cut(G2, B, (->)/2)) - ) - ; call(G1) -> - '$call_with_default_policy'(call_or_cut(G2, B, (->)/2)) - ). % univ. diff --git a/src/loader.pl b/src/loader.pl index 722d413a..87d758be 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -629,6 +629,8 @@ expand_module_name(ESG0, M, ESG) :- ESG = M:ESG0 ; ESG0 = _:_ -> ESG = ESG0 + ; predicate_property(ESG0, built_in) -> + ESG = ESG0 ; ESG = M:ESG0 ). @@ -656,7 +658,8 @@ expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :- ( GoalFunctor == (:), SubGoals = [M, SubGoal] -> expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars), - ExpandedGoals = M:ExpandedSubGoal + expand_module_name(ExpandedSubGoal, M, ExpandedGoals) + % ExpandedGoals = M:ExpandedSubGoal ; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars), ExpandedGoals =.. [GoalFunctor | ExpandedGoalList] ). diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 8f4dc44d..89dd4269 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -202,9 +202,9 @@ impl MachineState { RefTag::HeapCell => { self.heap[r1.get_value() as usize] = t2; } - RefTag::AttrVar => { - self.bind_attr_var(r1.get_value() as usize, t2); - } + RefTag::AttrVar => { + self.bind_attr_var(r1.get_value() as usize, t2); + } }; self.trail(TrailRef::Ref(r1)); @@ -1457,7 +1457,7 @@ impl MachineState { let order_cat_v2 = v2.order_category(); if order_cat_v1 != order_cat_v2 { - self.pdl.clear(); + self.pdl.clear(); return Some(order_cat_v1.cmp(&order_cat_v2)); } @@ -1467,7 +1467,7 @@ impl MachineState { let v2 = v2.as_var().unwrap(); if v1 != v2 { - self.pdl.clear(); + self.pdl.clear(); return Some(v1.cmp(&v2)); } } @@ -1476,7 +1476,7 @@ impl MachineState { let v2 = cell_as_f64_ptr!(v2); if v1 != v2 { - self.pdl.clear(); + self.pdl.clear(); return Some(v1.cmp(&v2)); } } @@ -1485,7 +1485,7 @@ impl MachineState { let v2 = Number::try_from(v2).unwrap(); if v1 != v2 { - self.pdl.clear(); + self.pdl.clear(); return Some(v1.cmp(&v2)); } } @@ -1495,18 +1495,18 @@ impl MachineState { read_heap_cell!(v2, (HeapCellValueTag::Atom, (n2, _a2)) => { if n1 != n2 { - self.pdl.clear(); + self.pdl.clear(); return Some(n1.cmp(&n2)); } } (HeapCellValueTag::Char, c2) => { if let Some(c1) = n1.as_char() { if c1 != c2 { - self.pdl.clear(); + self.pdl.clear(); return Some(c1.cmp(&c2)); } } else { - self.pdl.clear(); + self.pdl.clear(); return Some(Ordering::Greater); } } @@ -1520,17 +1520,17 @@ impl MachineState { (HeapCellValueTag::Atom, (n2, _a2)) => { if let Some(c2) = n2.as_char() { if c1 != c2 { - self.pdl.clear(); + self.pdl.clear(); return Some(c1.cmp(&c2)); } } else { - self.pdl.clear(); + self.pdl.clear(); return Some(Ordering::Less); } } (HeapCellValueTag::Char, c2) => { if c1 != c2 { - self.pdl.clear(); + self.pdl.clear(); return Some(c1.cmp(&c2)); } } @@ -1634,7 +1634,7 @@ impl MachineState { self.heap.pop(); self.heap.pop(); - self.pdl.clear(); + self.pdl.clear(); return Some(ordering); } @@ -1675,7 +1675,7 @@ impl MachineState { self.pdl.push(self.heap[l1]); } ordering => { - self.pdl.clear(); + self.pdl.clear(); return Some(ordering); } } @@ -1698,7 +1698,7 @@ impl MachineState { self.heap.pop(); self.heap.pop(); - self.pdl.clear(); + self.pdl.clear(); return Some(ordering); } @@ -1730,7 +1730,7 @@ impl MachineState { } } ordering => { - self.pdl.clear(); + self.pdl.clear(); return Some(ordering); } } @@ -1754,7 +1754,7 @@ impl MachineState { self.pdl.push(self.heap[s1+2]); } ordering => { - self.pdl.clear(); + self.pdl.clear(); return Some(ordering); } } @@ -1772,7 +1772,7 @@ impl MachineState { self.heap.pop(); self.heap.pop(); - self.pdl.clear(); + self.pdl.clear(); return Some(ordering); } @@ -1793,7 +1793,7 @@ impl MachineState { } None => { if v1 != v2 { - self.pdl.clear(); + self.pdl.clear(); return None; } } @@ -1873,8 +1873,8 @@ impl MachineState { None => unreachable!(), } } - TrailEntryTag::TrailedAttachedValue => { - } + TrailEntryTag::TrailedAttachedValue => { + } } } } @@ -3307,11 +3307,11 @@ impl MachineState { self.heap.push(atom_as_cell!(name, arity)); for i in 0..arity { - self.heap.push(heap_loc_as_cell!(h + i + 1)); - } + self.heap.push(heap_loc_as_cell!(h + i + 1)); + } str_loc_as_cell!(h) - }; + }; (self.bind_fn)(self, r, f_a); } @@ -3441,10 +3441,10 @@ impl MachineState { Err(self.error_form(err, stub_gen())) } } - (HeapCellValueTag::CStr, cstr_atom) => { - let cstr = cstr_atom.as_str(); - Ok(cstr.chars().map(|c| char_as_cell!(c)).collect()) - } + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = cstr_atom.as_str(); + Ok(cstr.chars().map(|c| char_as_cell!(c)).collect()) + } _ => { let err = self.type_error(ValidType::List, store_v); Err(self.error_form(err, stub_gen())) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 9f3dd089..7b85f2c4 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3580,6 +3580,54 @@ impl MachineState { let n = Fixnum::build_with(i64::try_from(self.b0).unwrap()); self.unify_fixnum(n, self.registers[1]); } + &SystemClauseType::GetStaggeredCutPoint => { + use std::sync::Once; + + let b = self.store(self.deref(self.registers[1])); + + static mut SEMICOLON_SECOND_BRANCH_LOC: usize = 0; + static LOC_INIT: Once = Once::new(); + + let semicolon_second_clause_p = unsafe { + LOC_INIT.call_once(|| { + match indices.code_dir.get(&(atom!(";"), 2)).map(|cell| cell.get()) { + Some(IndexPtr::Index(p)) => { + match code_repo.code[p] { + Line::Choice(ChoiceInstruction::TryMeElse(o)) => { + SEMICOLON_SECOND_BRANCH_LOC = p + o; + } + _ => { + unreachable!(); + } + } + } + _ => { + unreachable!(); + } + } + }); + + LocalCodePtr::DirEntry(SEMICOLON_SECOND_BRANCH_LOC) + }; + + let staggered_b0 = if self.b > 0 { + let or_frame = self.stack.index_or_frame(self.b); + + if or_frame.prelude.bp == semicolon_second_clause_p { + or_frame.prelude.b0 + } else { + self.b0 + } + } else { + self.b0 + }; + + let staggered_b0 = integer_as_cell!( + Number::arena_from(staggered_b0, &mut self.arena) + ); + + self.bind(b.as_var().unwrap(), staggered_b0); + } &SystemClauseType::InstallNewBlock => { self.install_new_block(self.registers[1]); } -- cgit v1.2.3-70-g09d2 From b24e7cce38991a79f517f87f923c42495a1a3b79 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 17 Nov 2021 23:29:23 -0700 Subject: support comparison and unification of cyclic partial strings --- src/machine/machine_state_impl.rs | 39 ++++++-- src/machine/partial_string.rs | 193 ++++++++++++++++++-------------------- src/machine/system_calls.rs | 15 ++- 3 files changed, 134 insertions(+), 113 deletions(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 89dd4269..1caa8a96 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -343,6 +343,13 @@ impl MachineState { (HeapCellValueTag::CStr, cstr_atom) => { self.fail = atom != cstr_atom; } + (HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { + self.unify_partial_string(atom_as_cstr_cell!(atom), value); + + if !self.pdl.is_empty() { + self.unify(); + } + } _ => { self.fail = true; } @@ -367,12 +374,20 @@ impl MachineState { match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { PStrCmpResult::Ordered(Ordering::Equal) => {} PStrCmpResult::Ordered(Ordering::Less) => { - self.pdl.push(empty_list_as_cell!()); - self.pdl.push(pstr_iter2.focus); + if pstr_iter2.focus.as_var().is_none() { + self.fail = true; + } else { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter2.focus); + } } PStrCmpResult::Ordered(Ordering::Greater) => { - self.pdl.push(empty_list_as_cell!()); - self.pdl.push(pstr_iter1.focus); + if pstr_iter1.focus.as_var().is_none() { + self.fail = true; + } else { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter1.focus); + } } continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { @@ -1014,12 +1029,20 @@ impl MachineState { match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) { PStrCmpResult::Ordered(Ordering::Equal) => {} PStrCmpResult::Ordered(Ordering::Less) => { - self.pdl.push(empty_list_as_cell!()); - self.pdl.push(pstr_iter2.focus); + if pstr_iter2.focus.as_var().is_none() { + self.fail = true; + } else { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter2.focus); + } } PStrCmpResult::Ordered(Ordering::Greater) => { - self.pdl.push(empty_list_as_cell!()); - self.pdl.push(pstr_iter1.focus); + if pstr_iter1.focus.as_var().is_none() { + self.fail = true; + } else { + self.pdl.push(empty_list_as_cell!()); + self.pdl.push(pstr_iter1.focus); + } } continuable @ PStrCmpResult::FirstIterContinuable(iteratee) | continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => { diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index da32db4f..87256d04 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -539,18 +539,33 @@ pub fn compare_pstr_prefixes<'a>( i2: &mut HeapPStrIter<'a>, ) -> PStrCmpResult { #[inline(always)] - fn consolidate_step(iter: &mut HeapPStrIter, step: &PStrIterStep) -> bool { - iter.focus = iter.heap[step.next_hare]; + fn step(iter: &mut HeapPStrIter, hare: usize) -> Option { + let result = iter.step(hare); + + iter.focus = iter.heap[hare]; if iter.focus.is_string_terminator(iter.heap) { iter.focus = empty_list_as_cell!(); } - !iter.brent_st.step(step.next_hare).is_some() + result + } + + #[inline(always)] + fn cycle_detection_step(i1: &mut HeapPStrIter, i2: &HeapPStrIter, step: &PStrIterStep) -> bool { + if i1.cycle_detected() { + i1.brent_st.hare = step.next_hare; + i2.cycle_detected() + } else if i1.brent_st.step(step.next_hare).is_some() { + i1.stepper = HeapPStrIter::post_cycle_discovery_stepper; + i2.cycle_detected() + } else { + false + } } - let mut r1 = i1.step(i1.brent_st.hare); - let mut r2 = i2.step(i2.brent_st.hare); + let mut r1 = step(i1, i1.brent_st.hare); + let mut r2 = step(i2, i2.brent_st.hare); loop { if let Some(step_1) = r1.as_mut() { @@ -561,21 +576,14 @@ pub fn compare_pstr_prefixes<'a>( return PStrCmpResult::Ordered(c1.cmp(&c2)); } - let c1_result = consolidate_step(i1, &step_1); - let c2_result = consolidate_step(i2, &step_2); + cycle_detection_step(i1, i2, &step_1); + let both_cyclic = cycle_detection_step(i2, i1, &step_2); - if c1_result { - r1 = i1.step(i1.brent_st.hare); - } - - if c2_result { - r2 = i2.step(i2.brent_st.hare); - } + r1 = step(i1, i1.brent_st.hare); + r2 = step(i2, i2.brent_st.hare); - if c1_result && c2_result { + if !both_cyclic { continue; - } else { - break; } } (PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => { @@ -591,36 +599,29 @@ pub fn compare_pstr_prefixes<'a>( if n1 < pstr_atom.len() { step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1); - if consolidate_step(i1, &step_1) { - r1 = i1.step(step_1.next_hare); + let c1_result = cycle_detection_step(i1, i2, &step_1); + r1 = step(i1, i1.brent_st.hare); + + if !c1_result { continue; - } else { - break; } } else { - let c1_result = consolidate_step(i1, &step_1); - let c2_result = consolidate_step(i2, &step_2); - - if c1_result { - r1 = i1.step(i1.brent_st.hare); - } + cycle_detection_step(i1, i2, &step_1); + let both_cyclic = cycle_detection_step(i2, i1, &step_2); - if c2_result { - r2 = i2.step(i2.brent_st.hare); - } + r1 = step(i1, i1.brent_st.hare); + r2 = step(i2, i2.brent_st.hare); - if c1_result && c2_result { + if !both_cyclic { continue; - } else { - break; } } } else { - if consolidate_step(i2, &step_2) { - r2 = i2.step(step_2.next_hare); + let c2_result = cycle_detection_step(i2, i1, &step_2); + r2 = step(i2, i2.brent_st.hare); + + if !c2_result { continue; - } else { - break; } } } @@ -637,54 +638,42 @@ pub fn compare_pstr_prefixes<'a>( if n1 < pstr_atom.len() { step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1); - if consolidate_step(i2, &step_2) { - r2 = i2.step(step_2.next_hare); + let c2_result = cycle_detection_step(i2, i1, &step_2); + r2 = step(i2, step_2.next_hare); + + if !c2_result { continue; - } else { - break; } } else { - let c1_result = consolidate_step(i1, &step_1); - let c2_result = consolidate_step(i2, &step_2); - - if c1_result { - r1 = i1.step(i1.brent_st.hare); - } + cycle_detection_step(i1, i2, &step_1); + let both_cyclic = cycle_detection_step(i2, i1, &step_2); - if c2_result { - r2 = i2.step(i2.brent_st.hare); - } + r1 = step(i1, i1.brent_st.hare); + r2 = step(i2, i2.brent_st.hare); - if c1_result && c2_result { + if !both_cyclic { continue; - } else { - break; } } } else { - if consolidate_step(i1, &step_1) { - r1 = i1.step(step_1.next_hare); + let c1_result = cycle_detection_step(i1, i2, &step_1); + r1 = step(i1, i1.brent_st.hare); + + if !c1_result { continue; - } else { - break; } } } (PStrIteratee::PStrSegment(f1, pstr1_atom, n1), PStrIteratee::PStrSegment(f2, pstr2_atom, n2)) => { if pstr1_atom == pstr2_atom && n1 == n2 { - let c_result1 = consolidate_step(i1, &step_1); - let c_result2 = consolidate_step(i2, &step_2); - - if c_result1 { - r1 = i1.step(step_1.next_hare); - } + cycle_detection_step(i1, i2, &step_1); + let both_cyclic = cycle_detection_step(i2, i1, &step_2); - if c_result2 { - r2 = i2.step(step_2.next_hare); - } + r1 = step(i1, i1.brent_st.hare); + r2 = step(i2, i2.brent_st.hare); - if c_result1 && c_result2 { + if !both_cyclic { continue; } @@ -699,41 +688,32 @@ pub fn compare_pstr_prefixes<'a>( match str1.len().cmp(&str2.len()) { Ordering::Equal if str1 == str2 => { - let c_result1 = consolidate_step(i1, &step_1); - let c_result2 = consolidate_step(i2, &step_2); + cycle_detection_step(i1, i2, &step_1); + let both_cyclic = cycle_detection_step(i2, i1, &step_2); - if c_result1 { - r1 = i1.step(step_1.next_hare); - } - - if c_result2 { - r2 = i2.step(step_2.next_hare); - } + r1 = step(i1, i1.brent_st.hare); + r2 = step(i2, i2.brent_st.hare); - if c_result1 && c_result2 { + if !both_cyclic { continue; } - - break; } Ordering::Less if str2.starts_with(str1) => { step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len()); + let c1_result = cycle_detection_step(i1, i2, &step_1); + r1 = step(i1, i1.brent_st.hare); - if consolidate_step(i1, &step_1) { - r1 = i1.step(step_1.next_hare); + if !c1_result { continue; - } else { - break; } } Ordering::Greater if str1.starts_with(str2) => { step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len()); + let c2_result = cycle_detection_step(i2, i1, &step_2); + r2 = step(i2, i2.brent_st.hare); - if consolidate_step(i2, &step_2) { - r2 = i2.step(step_2.next_hare); + if !c2_result { continue; - } else { - break; } } _ => { @@ -757,22 +737,33 @@ pub fn compare_pstr_prefixes<'a>( // and thus matched by the compare_pstr_prefixes loop previously, // so here it suffices to check if they are both continuable. - if i1.focus == i2.focus { - PStrCmpResult::Ordered(Ordering::Equal) - } else if i1.focus == empty_list_as_cell!() { - PStrCmpResult::Ordered(Ordering::Less) - } else if i2.focus == empty_list_as_cell!() { - PStrCmpResult::Ordered(Ordering::Greater) - } else if i1.is_continuable() { - if i2.is_continuable() { - return PStrCmpResult::Ordered(Ordering::Equal); - } + let r1_at_end = r1.is_none(); + let r2_at_end = r2.is_none(); - PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee) - } else if i2.is_continuable() { - PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee) + if r1_at_end && r2_at_end { + if i1.focus == i2.focus { + PStrCmpResult::Ordered(Ordering::Equal) + } else { + PStrCmpResult::Unordered + } + } else if r1_at_end { + if i1.focus == empty_list_as_cell!() { + PStrCmpResult::Ordered(Ordering::Less) + } else { + PStrCmpResult::SecondIterContinuable(r2.unwrap().iteratee) + } + } else if r2_at_end { + if i2.focus == empty_list_as_cell!() { + PStrCmpResult::Ordered(Ordering::Greater) + } else { + PStrCmpResult::FirstIterContinuable(r1.unwrap().iteratee) + } } else { - PStrCmpResult::Unordered + if i1.is_continuable() && i2.is_continuable() { + PStrCmpResult::Ordered(Ordering::Equal) + } else { + PStrCmpResult::Unordered + } } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 7b85f2c4..dd385801 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -113,6 +113,15 @@ impl BrentAlgState { } } + #[inline(always)] + pub fn teleport_tortoise(&mut self) { + if self.lam == self.power { + self.tortoise = self.hare; + self.power <<= 1; + self.lam = 0; + } + } + #[inline(always)] pub fn step(&mut self, hare: usize) -> Option { self.hare = hare; @@ -120,10 +129,8 @@ impl BrentAlgState { if self.tortoise == self.hare { return Some(CycleSearchResult::NotList); - } else if self.lam == self.power { - self.tortoise = self.hare; - self.power <<= 1; - self.lam = 0; + } else { + self.teleport_tortoise(); } None -- cgit v1.2.3-70-g09d2 From a0a86d0f6266503f6de14bcfde2e6a894301f7ac Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 18 Nov 2021 09:35:00 -0700 Subject: unmark cell bits in occurs check --- src/machine/machine_state_impl.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 1caa8a96..47019772 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -882,6 +882,8 @@ impl MachineState { if !value.is_constant() { for addr in stackful_preorder_iter(&mut self.heap, value) { + let addr = unmark_cell_bits!(addr); + if let Some(inner_r) = addr.as_var() { if r == inner_r { occurs_triggered = true; -- cgit v1.2.3-70-g09d2 From addc817ccacf0c3364fb5f0fea17cbd92d8dd22e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 18 Nov 2021 23:41:58 -0700 Subject: break from get_char loop after successful char unification --- src/machine/system_calls.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index dd385801..b5fb568e 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2213,6 +2213,8 @@ impl MachineState { if self.fail { return Ok(()); } + + break; } _ => { self.eof_action( -- cgit v1.2.3-70-g09d2 From 0e2db4a23e269dd59d0d15858f76a650e4f6bc6a Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 19 Nov 2021 23:00:56 -0700 Subject: tag DCG constructs with module names for proper resolution --- src/clause_types.rs | 4 +- src/lib/builtins.pl | 44 ++++++------- src/lib/dcgs.pl | 120 +++++++++++++++++++++++------------- src/loader.pl | 33 ++++++---- src/machine/attributed_variables.rs | 18 +++--- 5 files changed, 131 insertions(+), 88 deletions(-) diff --git a/src/clause_types.rs b/src/clause_types.rs index d3ba917c..540bf779 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -638,8 +638,8 @@ impl SystemClauseType { (atom!("$flush_output"), 1) => Some(SystemClauseType::FlushOutput), (atom!("$del_attr_non_head"), 1) => Some(SystemClauseType::DeleteAttribute), (atom!("$del_attr_head"), 1) => Some(SystemClauseType::DeleteHeadAttribute), - (atom!("$get_next_db_ref"), 2) => Some(SystemClauseType::GetNextDBRef), - (atom!("$get_next_op_db_ref"), 2) => Some(SystemClauseType::GetNextOpDBRef), + (atom!("$get_next_db_ref"), 4) => Some(SystemClauseType::GetNextDBRef), + (atom!("$get_next_op_db_ref"), 7) => Some(SystemClauseType::GetNextOpDBRef), (atom!("$module_call"), _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)), (atom!("$enqueue_attr_var"), 1) => Some(SystemClauseType::EnqueueAttributedVar), (atom!("$partial_string_tail"), 2) => Some(SystemClauseType::PartialStringTail), diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 534edb06..ef9f555e 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -61,61 +61,61 @@ call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H). Module : Predicate :- - ( atom(Module) -> '$module_call'(Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). % dynamic module resolution. :(Module, Predicate, A1) :- - ( atom(Module) -> '$module_call'(A1, Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(A1, Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). :(Module, Predicate, A1, A2) :- - ( atom(Module) -> '$module_call'(A1, A2, Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(A1, A2, Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). :(Module, Predicate, A1, A2, A3) :- - ( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). :(Module, Predicate, A1, A2, A3, A4) :- - ( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). :(Module, Predicate, A1, A2, A3, A4, A5) :- - ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). :(Module, Predicate, A1, A2, A3, A4, A5, A6) :- - ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). :(Module, Predicate, A1, A2, A3, A4, A5, A6, A7) :- - ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). :(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8) :- - ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). :(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9) :- - ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). :(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) :- - ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate) + ; throw(error(type_error(atom, Module), (:)/2)) ). % flags. diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl index f4cee25c..35a0f27d 100644 --- a/src/lib/dcgs.pl +++ b/src/lib/dcgs.pl @@ -1,16 +1,25 @@ :- module(dcgs, [op(1105, xfy, '|'), - phrase/2, - phrase/3, - seq//1, - seqq//1, - ... //0 - ]). + phrase/2, + phrase/3, + seq//1, + seqq//1, + ... //0 + ]). :- use_module(library(error)). -:- use_module(library(lists), [append/3]). +:- use_module(library(lists), [append/3, member/2]). :- use_module(library(loader), [strip_module/3]). +load_context(GRBody, Module, GRBody0) :- + strip_module(GRBody, Module, GRBody0), + ( nonvar(Module) -> + true + ; prolog_load_context(module, Module) -> + true + ; true + ). + :- meta_predicate phrase(2, ?). :- meta_predicate phrase(2, ?, ?). @@ -18,77 +27,78 @@ phrase(GRBody, S0) :- phrase(GRBody, S0, []). - phrase(GRBody, S0, S) :- ( var(GRBody) -> throw(error(instantiation_error, phrase/3)) - ; strip_module(GRBody, Module, GRBody0), + ; load_context(GRBody, Module, GRBody0), dcg_constr(GRBody0) -> ( var(Module) -> phrase_(GRBody0, S0, S) - ; phrase_(Module:GRBody0, S0, S) + ; phrase_(GRBody0, S0, S, Module) ) ; functor(GRBody, _, _) -> call(GRBody, S0, S) ; throw(error(type_error(callable, GRBody), phrase/3)) ). +phrase_([], S, S, _). +phrase_(!, S, S, _). +phrase_((A, B), S0, S, M) :- + phrase(M:A, S0, S1), + phrase(M:B, S1, S). +phrase_((A -> B ; C), S0, S, M) :- + ( phrase(M:A, S0, S1) -> + phrase(M:B, S1, S) + ; phrase(M:C, S0, S) + ). +phrase_((A ; B), S0, S, M) :- + ( phrase(M:A, S0, S) + ; phrase(M:B, S0, S) + ). +phrase_((A | B), S0, S, M) :- + ( phrase(M:A, S0, S) + ; phrase(M:B, S0, S) + ). +phrase_({G}, S, S, M) :- + call(M:G). +phrase_(call(G), S0, S, M) :- + call(M:G, S0, S). +phrase_((A -> B), S0, S, M) :- + ( phrase(M:A, S0, S1) -> + phrase(M:B, S1, S) + ; fail + ). +phrase_(phrase(NonTerminal), S0, S, M) :- + phrase(NonTerminal, S0, S, M). +phrase_([T|Ts], S0, S, _) :- + append([T|Ts], S, S0). + phrase_([], S, S). phrase_(!, S, S). -phrase_(_:[], S, S) :- !. -phrase_(_:!, S, S) :- !. +phrase_(M:G, S0, S) :- + phrase_(G, S0, S, M). phrase_((A, B), S0, S) :- - phrase(A, S0, S1), phrase(B, S1, S). -phrase_(M:(A, B), S0, S) :- - !, - phrase(M:A, S0, S1), phrase(M:B, S1, S). + phrase(A, S0, S1), + phrase(B, S1, S). phrase_((A -> B ; C), S0, S) :- - !, ( phrase(A, S0, S1) -> phrase(B, S1, S) ; phrase(C, S0, S) ). -phrase_(M:(A -> B ; C), S0, S) :- - !, - ( phrase(M:A, S0, S1) -> - phrase(M:B, S1, S) - ; phrase(M:C, S0, S) - ). phrase_((A ; B), S0, S) :- ( phrase(A, S0, S) ; phrase(B, S0, S) ). -phrase_(M:(A ; B), S0, S) :- - !, - ( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ). phrase_((A | B), S0, S) :- ( phrase(A, S0, S) ; phrase(B, S0, S) ). -phrase_(M:(A | B), S0, S) :- - !, - ( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ). phrase_({G}, S0, S) :- ( call(G), S0 = S ). -phrase_(M:{G}, S0, S) :- - !, - ( call(M:G), S0 = S ). phrase_(call(G), S0, S) :- call(G, S0, S). -phrase_(M:call(G), S0, S) :- - !, - call(M:G, S0, S). phrase_((A -> B), S0, S) :- phrase((A -> B ; fail), S0, S). -phrase_(M:(A -> B), S0, S) :- - !, - phrase((M:A -> M:B ; fail), S0, S). phrase_(phrase(NonTerminal), S0, S) :- phrase(NonTerminal, S0, S). -phrase_(M:phrase(NonTerminal), S0, S) :- - !, - phrase(M:NonTerminal, S0, S). phrase_([T|Ts], S0, S) :- append([T|Ts], S, S0). -phrase_(_:[T|Ts], S0, S) :- - append([T|Ts], S, S0). - % The same version of the below two dcg_rule clauses, but with module scoping. dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :- @@ -193,3 +203,25 @@ seqq([Es|Ess]) --> seq(Es), seqq(Ess). % Describes an arbitrary number of elements ... --> [] | [_], ... . + +user:goal_expansion(phrase(GRBody, S, S0), phrase(GRBody1, S, S0)) :- + strip_module(GRBody, M, GRBody0), + var(M), + prolog_load_context(module, M), + ( nonvar(GRBody0) -> + GRBody0 \== [], + dcg_constr(GRBody0), + predicate_property(GRBody0, meta_predicate(_)) + ), + GRBody1 = M:GRBody0. + +user:goal_expansion(phrase(GRBody, S), phrase(GRBody1, S, [])) :- + strip_module(GRBody, M, GRBody0), + var(M), + prolog_load_context(module, M), + ( nonvar(GRBody0) -> + GRBody0 \== [], + dcg_constr(GRBody0), + predicate_property(GRBody0, meta_predicate(_)) + ), + GRBody1 = M:GRBody0. diff --git a/src/loader.pl b/src/loader.pl index 87d758be..fb5d8ab1 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -315,6 +315,7 @@ compile_dispatch(user:goal_expansion(Term, Terms), Evacuable) :- compile_dispatch((user:goal_expansion(Term, Terms) :- Body), Evacuable) :- '$add_goal_expansion_clause'(user, (goal_expansion(Term, Terms) :- Body), Evacuable). + remove_module(Module, Evacuable) :- ( nonvar(Module), Module = library(ModuleName), @@ -708,17 +709,13 @@ expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :- ) ). -thread_goals(Goals0, Goals1, Functor) :- - ( var(Goals0) -> - Goals0 = Goals1 - ; ( Goals0 = [G | Gs] -> - ( Gs = [] -> - Goals1 = G - ; Goals1 =.. [Functor, G, Goals2], - thread_goals(Gs, Goals2, Functor) - ) - ; Goals1 = Goals0 - ) +thread_goals([SG|SGs], G, F) :- + ( SGs \== [], functor(G, F, 2) -> + arg(1, G, SG), + arg(2, G, Gs1), + thread_goals(SGs, Gs1, F) + ; SG = G, + SGs = [] ). thread_goals(Goals0, Goals1, Hole, Functor) :- @@ -734,6 +731,20 @@ thread_goals(Goals0, Goals1, Hole, Functor) :- ) ). +/* +thread_goals(Goals0, Goals1, Functor) :- + ( var(Goals0) -> + Goals0 = Goals1 + ; ( Goals0 = [G | Gs] -> + ( Gs = [] -> + Goals1 = G + ; Goals1 =.. [Functor, G, Goals2], + thread_goals(Gs, Goals2, Functor) + ) + ; Goals1 = Goals0 + ) + ). +*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 34cdd12e..48c5ec8b 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -86,21 +86,21 @@ impl MachineState { .iter() .filter_map(|h| { read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))), //Addr::HeapCell(*h))) { - (HeapCellValueTag::AttrVar, h) => { - Some(attr_var_as_cell!(h)) - } - _ => { - None - } + (HeapCellValueTag::AttrVar, h) => { + Some(attr_var_as_cell!(h)) + } + _ => { + None + } ) }) .collect(); attr_vars.sort_unstable_by(|a1, a2| { - compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less) - }); + compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less) + }); - attr_vars.dedup(); + attr_vars.dedup(); attr_vars.into_iter() } -- cgit v1.2.3-70-g09d2 From 3355b4972493ddce70019717534f20c10dc9ef11 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 21 Nov 2021 11:30:15 -0700 Subject: add bounds check for attributed variables slice --- src/machine/attributed_variables.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 48c5ec8b..30ec9a8c 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -82,19 +82,23 @@ impl MachineState { } pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter { - let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..] - .iter() - .filter_map(|h| { - read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))), //Addr::HeapCell(*h))) { - (HeapCellValueTag::AttrVar, h) => { - Some(attr_var_as_cell!(h)) - } - _ => { - None - } - ) - }) - .collect(); + let mut attr_vars: Vec<_> = if b >= self.attr_var_init.attr_var_queue.len() { + vec![] + } else { + self.attr_var_init.attr_var_queue[b..] + .iter() + .filter_map(|h| { + read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))), + (HeapCellValueTag::AttrVar, h) => { + Some(attr_var_as_cell!(h)) + } + _ => { + None + } + ) + }) + .collect() + }; attr_vars.sort_unstable_by(|a1, a2| { compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less) -- cgit v1.2.3-70-g09d2 From 073f281f1e2d22b8de4be1051a24cead776eec56 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 21 Nov 2021 13:25:24 -0700 Subject: fix arg/3 bug --- src/lib/builtins.pl | 4 ---- src/machine/machine_state_impl.rs | 2 +- src/machine/system_calls.rs | 6 +++--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index ef9f555e..730b97bd 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -209,10 +209,6 @@ repeat :- repeat. :- meta_predicate ->(0,0). -% '!' is for internal use as a callable no-op within if/then/else. -% Where it shouldn't be a no-op, it's interpreted under the expected -% semantics by comma_dispatch/3. - ! :- '$get_staggered_cp'(B), '$set_cp'(B). G1 -> G2 :- '$get_staggered_cp'(B), call('$call'(G1)), '$set_cp'(B), call('$call'(G2)). diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 47019772..00556078 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -2974,7 +2974,7 @@ impl MachineState { // arg(+N, +Term, ?Arg) pub fn try_arg(&mut self) -> CallResult { let stub_gen = || functor_stub(atom!("arg"), 3); - let n = self.registers[1]; //self.store(self.deref(self.registers[1])); // TODO: necessary? + let n = self.store(self.deref(self.registers[1])); read_heap_cell!(n, (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index b5fb568e..5bc6a915 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3795,12 +3795,12 @@ impl MachineState { self.reset_block(addr); } &SystemClauseType::ResetContinuationMarker => { - self.registers[3] = atom_as_cell!(atom!("none")); - let h = self.heap.len(); - self.heap.push(heap_loc_as_cell!(h)); + self.registers[3] = atom_as_cell!(atom!("none")); self.registers[4] = heap_loc_as_cell!(h); + + self.heap.push(heap_loc_as_cell!(h)); } &SystemClauseType::SetBall => { self.set_ball(); -- cgit v1.2.3-70-g09d2 From 7507e8840616a817fa8a523149f2ff135ca51fdb Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 21 Nov 2021 23:09:39 -0700 Subject: detect module resolved cut in interpreted (,) --- src/arena.rs | 2 -- src/lib/builtins.pl | 27 ++++++++++++--------------- src/loader.pl | 6 +++++- src/toplevel.pl | 2 +- tests/scryer/helper.rs | 2 +- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/arena.rs b/src/arena.rs index 2ba73d27..0d6ad6a0 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -37,11 +37,9 @@ pub enum ArenaHeaderTag { OutputFileStream = 0b10100, NamedTcpStream = 0b011100, NamedTlsStream = 0b100000, - // PausedPrologStream = 0b101100, ReadlineStream = 0b110000, StaticStringStream = 0b110100, ByteStream = 0b111000, - // StandardInputStream = 0b100, StandardOutputStream = 0b1100, StandardErrorStream = 0b11000, NullStream = 0b111100, diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 730b97bd..d0f7245e 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -220,6 +220,12 @@ _ ; G :- call('$call'(G)). set_cp(B) :- '$set_cp'(B). +:- non_counted_backtracking comma_dispatch/3. + +comma_dispatch(G1, G2, B) :- + comma_dispatch_prep((G1, G2), B, Conts), + comma_dispatch_call_list(Conts). + :- non_counted_backtracking comma_dispatch_prep/3. comma_dispatch_prep(Gs, B, [Cont|Conts]) :- @@ -227,20 +233,18 @@ comma_dispatch_prep(Gs, B, [Cont|Conts]) :- ( functor(Gs, ',', 2) -> arg(1, Gs, G1), arg(2, Gs, G2), - ( G1 == ! -> + ( nonvar(G1), ( G1 = ! ; G1 = _:! ) -> Cont = builtins:set_cp(B) - ; callable(G1) -> - Cont = G1 - ; Cont = throw(error(type_error(callable, G1), call/1)) + ; Cont = G1 ), comma_dispatch_prep(G2, B, Conts) + ; ( Gs = ! ; Gs = _:! ) -> + Cont = builtins:set_cp(B), + Conts = [] ; Cont = Gs, Conts = [] ) - ; Gs == ! -> - Cont = builtins:set_cp(B), - Conts = [] - ; Cont = throw(error(type_error(callable, Gs), call/1)), + ; Cont = Gs, Conts = [] ). @@ -302,13 +306,6 @@ comma_dispatch_call_list([G1]) :- '$call'(G1). -:- non_counted_backtracking comma_dispatch/3. - -comma_dispatch(G1, G2, B) :- - comma_dispatch_prep((G1, G2), B, Conts), - comma_dispatch_call_list(Conts). - - % univ. :- non_counted_backtracking univ_errors/3. diff --git a/src/loader.pl b/src/loader.pl index fb5d8ab1..21489e46 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -691,10 +691,14 @@ expand_goal_cases((\+ Goals0), Module, ExpandedGoals, HeadVars) :- expand_goal_cases((Module:Goals0), _, ExpandedGoals, HeadVars) :- expand_goal(Goals0, Module, Goals1, HeadVars), ExpandedGoals = (Module:Goals1). +expand_goal_cases(call(Goals0), _, ExpandedGoals, HeadVars) :- + expand_goal(Goals0, Module, Goals1, HeadVars), + ExpandedGoals = call(Goals1). expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :- ( var(UnexpandedGoals) -> - expand_module_names(call(UnexpandedGoals), [0], Module, ExpandedGoals, HeadVars) + UnexpandedGoals = ExpandedGoals + % expand_module_names(call(UnexpandedGoals), [0], Module, ExpandedGoals, HeadVars) ; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1), ( Module \== user -> goal_expansion(UnexpandedGoals1, user, Goals) diff --git a/src/toplevel.pl b/src/toplevel.pl index 441d470a..492fef83 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -185,7 +185,7 @@ submit_query_and_print_results(Term0, VarList) :- ( functor(Term0, call, _) -> Term = Term0 % prevent pre-mature expansion of incomplete goal % in the first argument, which is done by call/N - ; expand_goal(call(Term0), user, call(Term)) + ; expand_goal(Term0, user, Term) ), setup_call_cleanup(bb_put('$first_answer', true), submit_query_and_print_results_(Term, VarList), diff --git a/tests/scryer/helper.rs b/tests/scryer/helper.rs index 93e7b7ca..3dec7e3e 100644 --- a/tests/scryer/helper.rs +++ b/tests/scryer/helper.rs @@ -45,7 +45,7 @@ pub(crate) fn load_module_test(file: &str, expected: T) { // &mut wam.machine_st.arena, // ), // ); - // + // // let output = output.bytes().unwrap(); // expected.assert_eq(output.as_slice()); } -- cgit v1.2.3-70-g09d2 From bc613eeff92959a752c8b55cb65fd8c1add65866 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 22 Nov 2021 00:17:45 -0700 Subject: fix number not recognizing floats --- src/machine/machine_state_impl.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 00556078..b0416b1d 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -3250,6 +3250,9 @@ impl MachineState { self.fail = true; } } + Ok(Number::Float(_)) => { + self.p += 1; + } _ => { self.fail = true; } -- cgit v1.2.3-70-g09d2 From 4af57b0dd3cfd2b955f8d40fbab490e4835a071b Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 22 Nov 2021 23:06:02 -0700 Subject: fix HeapPStrIter bug not recognizing nil focus if PStrLoc points to PStrOffset to CStr --- src/loader.pl | 6 +----- src/machine/machine_indices.rs | 24 ++++-------------------- src/types.rs | 36 +++++++++++++++++++++--------------- 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/src/loader.pl b/src/loader.pl index 21489e46..fb5d8ab1 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -691,14 +691,10 @@ expand_goal_cases((\+ Goals0), Module, ExpandedGoals, HeadVars) :- expand_goal_cases((Module:Goals0), _, ExpandedGoals, HeadVars) :- expand_goal(Goals0, Module, Goals1, HeadVars), ExpandedGoals = (Module:Goals1). -expand_goal_cases(call(Goals0), _, ExpandedGoals, HeadVars) :- - expand_goal(Goals0, Module, Goals1, HeadVars), - ExpandedGoals = call(Goals1). expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :- ( var(UnexpandedGoals) -> - UnexpandedGoals = ExpandedGoals - % expand_module_names(call(UnexpandedGoals), [0], Module, ExpandedGoals, HeadVars) + expand_module_names(call(UnexpandedGoals), [0], Module, ExpandedGoals, HeadVars) ; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1), ( Module \== user -> goal_expansion(UnexpandedGoals1, user, Goals) diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 6d5be8c1..361b084e 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -45,25 +45,6 @@ pub enum TermOrderCategory { Compound, } -// the position-dependent heap template: - -/* - read_heap_cell!( - (HeapCellValueTag::AttrVar, n) => { - } - (HeapCellValueTag::Lis, n) => { - } - (HeapCellValueTag::Var, n) => { - } - (HeapCellValueTag::Str, n) => { - } - (HeapCellValueTag::PStrOffset, n) => { - } - _ => { - } - ) -*/ - impl PartialEq for HeapCellValue { fn eq(&self, r: &Ref) -> bool { self.as_var() == Some(*r) @@ -82,7 +63,10 @@ impl PartialOrd for HeapCellValue { _ => Some(Ordering::Greater), } } - (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h1) => { + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => { + // _ if self.is_ref() => { + // let h1 = self.get_value(); + match r.get_tag() { RefTag::StackCell => Some(Ordering::Less), _ => { diff --git a/src/types.rs b/src/types.rs index 57c999eb..57a6c5a3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -343,21 +343,27 @@ impl HeapCellValue { } #[inline] - pub fn is_string_terminator(self, heap: &[HeapCellValue]) -> bool { - read_heap_cell!(self, - (HeapCellValueTag::Atom, (name, arity)) => { - name == atom!("[]") && arity == 0 - } - (HeapCellValueTag::CStr) => { - true - } - (HeapCellValueTag::PStrOffset, pstr_offset) => { - heap[pstr_offset].get_tag() == HeapCellValueTag::CStr - } - _ => { - false - } - ) + pub fn is_string_terminator(mut self, heap: &[HeapCellValue]) -> bool { + loop { + return read_heap_cell!(self, + (HeapCellValueTag::Atom, (name, arity)) => { + name == atom!("[]") && arity == 0 + } + (HeapCellValueTag::CStr) => { + true + } + (HeapCellValueTag::PStrLoc, h) => { + self = heap[h]; + continue; + } + (HeapCellValueTag::PStrOffset, pstr_offset) => { + heap[pstr_offset].get_tag() == HeapCellValueTag::CStr + } + _ => { + false + } + ); + } } #[inline(always)] -- cgit v1.2.3-70-g09d2 From 10bb6ab3bbea5eec67a4fe053620081a818cff54 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 23 Nov 2021 19:59:35 -0700 Subject: restore old thread_goals to fix top-level solutions printing bug --- src/loader.pl | 11 --------- src/machine/loader.rs | 16 ------------- src/machine/system_calls.rs | 18 +++++++-------- src/toplevel.pl | 56 ++++++++++++++++++++++----------------------- 4 files changed, 37 insertions(+), 64 deletions(-) diff --git a/src/loader.pl b/src/loader.pl index fb5d8ab1..720e534a 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -709,15 +709,6 @@ expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :- ) ). -thread_goals([SG|SGs], G, F) :- - ( SGs \== [], functor(G, F, 2) -> - arg(1, G, SG), - arg(2, G, Gs1), - thread_goals(SGs, Gs1, F) - ; SG = G, - SGs = [] - ). - thread_goals(Goals0, Goals1, Hole, Functor) :- ( var(Goals0) -> Goals1 =.. [Functor, Goals0, Hole] @@ -731,7 +722,6 @@ thread_goals(Goals0, Goals1, Hole, Functor) :- ) ). -/* thread_goals(Goals0, Goals1, Functor) :- ( var(Goals0) -> Goals0 = Goals1 @@ -744,7 +734,6 @@ thread_goals(Goals0, Goals1, Functor) :- ; Goals1 = Goals0 ) ). -*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % diff --git a/src/machine/loader.rs b/src/machine/loader.rs index b2f43e54..d7ed073e 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -380,13 +380,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { LS::evacuate(self) } - /* - #[inline(always)] - pub(crate) fn load_state(&mut self) -> &mut LoadStatePayload<>::TS> { - self.payload.as_mut() - } - */ - fn dequeue_terms(&mut self) -> Result, SessionError> { while !self.payload.term_stream.eof()? { let load_state = &mut self.payload; @@ -395,7 +388,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let term = load_state.term_stream.next(&composite_op_dir)?; - // if is_consistent is false, self.predicates is not empty. if !term.is_consistent(&load_state.predicates) { self.compile_and_submit()?; } @@ -450,14 +442,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let machine_st = LS::machine_st(&mut self.payload); let term_addr = machine_st[heap_term_loc]; - /* - if let Ok(lit) = Literal::try_from(term_addr) { - return Ok(Term::Literal(Cell::default(), lit)); - } else if machine_st.is_cyclic_term(term_addr) { - return Err(SessionError::from(CompilationError::CannotParseCyclicTerm)); - } - */ - let mut term_stack = vec![]; let mut iter = stackful_post_order_iter(&mut machine_st.heap, term_addr); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 5bc6a915..eedb127b 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2495,17 +2495,17 @@ impl MachineState { &SystemClauseType::HeadIsDynamic => { let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); - let (name, arity) = read_heap_cell!(self.store(self.deref(self.registers[2])), - (HeapCellValueTag::Str, s) => { - cell_as_atom_cell!(self.heap[s]).get_name_and_arity() - } + let (name, arity) = read_heap_cell!(self.store(self.deref(self.registers[2])), + (HeapCellValueTag::Str, s) => { + cell_as_atom_cell!(self.heap[s]).get_name_and_arity() + } (HeapCellValueTag::Atom, (name, _arity)) => { - (name, 0) - } + (name, 0) + } _ => { - unreachable!() - } - ); + unreachable!() + } + ); self.fail = !indices.is_dynamic_predicate(module_name, (name, arity)); } diff --git a/src/toplevel.pl b/src/toplevel.pl index 492fef83..18a6f3e8 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -155,14 +155,14 @@ instruction_match(Term, VarList) :- ; Term = [Item] -> !, ( atom(Item) -> - ( Item == user -> - catch(load(user_input), E, print_exception_with_check(E)) - ; - submit_query_and_print_results(consult(Item), []) - ) + ( Item == user -> + catch(load(user_input), E, print_exception_with_check(E)) + ; + submit_query_and_print_results(consult(Item), []) + ) ; catch(type_error(atom, Item, repl/0), - E, - print_exception_with_check(E)) + E, + print_exception_with_check(E)) ) ; Term = end_of_file -> halt @@ -184,7 +184,7 @@ submit_query_and_print_results_(_, _) :- submit_query_and_print_results(Term0, VarList) :- ( functor(Term0, call, _) -> Term = Term0 % prevent pre-mature expansion of incomplete goal - % in the first argument, which is done by call/N + % in the first argument, which is done by call/N ; expand_goal(Term0, user, Term) ), setup_call_cleanup(bb_put('$first_answer', true), @@ -194,10 +194,10 @@ submit_query_and_print_results(Term0, VarList) :- needs_bracketing(Value, Op) :- catch((functor(Value, F, _), - current_op(EqPrec, EqSpec, Op), - current_op(FPrec, _, F)), - _, - false), + current_op(EqPrec, EqSpec, Op), + current_op(FPrec, _, F)), + _, + false), ( EqPrec < FPrec -> true ; FPrec > 0, F == Value, graphic_token_char(F) -> @@ -211,15 +211,15 @@ needs_bracketing(Value, Op) :- write_goal(G, VarList, MaxDepth) :- ( G = (Var = Value) -> ( var(Value) -> - select((Var = _), VarList, NewVarList) + select((Var = _), VarList, NewVarList) ; VarList = NewVarList ), write(Var), write(' = '), ( needs_bracketing(Value, (=)) -> - write('('), - write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), - write(')') + write('('), + write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), + write(')') ; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]) ) ; G == [] -> @@ -230,20 +230,20 @@ write_goal(G, VarList, MaxDepth) :- write_last_goal(G, VarList, MaxDepth) :- ( G = (Var = Value) -> ( var(Value) -> - select((Var = _), VarList, NewVarList) + select((Var = _), VarList, NewVarList) ; VarList = NewVarList ), write(Var), write(' = '), ( needs_bracketing(Value, (=)) -> - write('('), - write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), - write(')') + write('('), + write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), + write(')') ; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]), - ( trailing_period_is_ambiguous(Value) -> - write(' ') - ; true - ) + ( trailing_period_is_ambiguous(Value) -> + write(' ') + ; true + ) ) ; G == [] -> write('true') @@ -301,11 +301,11 @@ write_eqs_and_read_input(B, VarList) :- ), ( B0 == B -> ( Goals == [] -> - write('true.'), nl + write('true.'), nl ; loader:thread_goals(Goals, ThreadedGoals, (',')), - write_eq(ThreadedGoals, NewVarList0, 20), - write('.'), - nl + write_eq(ThreadedGoals, NewVarList0, 20), + write('.'), + nl ) ; loader:thread_goals(Goals, ThreadedGoals, (',')), write_eq(ThreadedGoals, NewVarList0, 20), -- cgit v1.2.3-70-g09d2 From b551ef315faf304c1010dbb342f89041fa3ac56f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 24 Nov 2021 19:00:52 -0700 Subject: use strip module in retract/1, a meta-predicate --- src/lib/builtins.pl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index d0f7245e..2f3066f3 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -964,13 +964,14 @@ retract_clause(Head, Body) :- :- meta_predicate retract(0). retract(Clause0) :- - strip_module(Clause0, Module, Clause), - ( Clause = (Head :- Body) -> - true - ; Head = Clause, - Body = true - ), - retract_clause(Module:Head, Body). + loader:strip_module(Clause0, Module, Clause), + ( Clause \= (_ :- _) -> + Head = Clause, + Body = true, + retract_module_clause(Head, Body, Module) + ; Clause = (Head :- Body) -> + retract_module_clause(Head, Body, Module) + ). :- meta_predicate retractall(0). -- cgit v1.2.3-70-g09d2 From 1b3f290037f8864d58059d5dee85f4562a71fb0e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 24 Nov 2021 19:11:14 -0700 Subject: throw instantiation error if Arity is a variable in abolish/1 --- src/lib/builtins.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 2f3066f3..41215a80 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1003,6 +1003,7 @@ module_abolish(Pred, Module) :- ; throw(error(permission_error(modify, static_procedure, Pred), abolish/1)) ) ) + ; var(Arity) -> throw(error(instantiation_error, abolish/1)) ; throw(error(type_error(integer, Arity), abolish/1)) ) ; throw(error(type_error(predicate_indicator, Module:Pred), abolish/1)) -- cgit v1.2.3-70-g09d2 From f340f9ac9415154de913cc03f50079a4ac07f013 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 24 Nov 2021 23:13:14 -0700 Subject: break from loop in get_code upon successful character read --- src/lib/builtins.pl | 5 +++-- src/machine/system_calls.rs | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 41215a80..86d5841f 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -988,8 +988,10 @@ module_abolish(Pred, Module) :- ; Pred = Name/Arity -> ( var(Name) -> throw(error(instantiation_error, abolish/1)) + ; var(Arity) -> + throw(error(instantiation_error, abolish/1)) ; integer(Arity) -> - ( \+ atom(Name) -> + (\+ atom(Name) -> throw(error(type_error(atom, Name), abolish/1)) ; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), abolish/1)) @@ -1003,7 +1005,6 @@ module_abolish(Pred, Module) :- ; throw(error(permission_error(modify, static_procedure, Pred), abolish/1)) ) ) - ; var(Arity) -> throw(error(instantiation_error, abolish/1)) ; throw(error(type_error(integer, Arity), abolish/1)) ) ; throw(error(type_error(predicate_indicator, Module:Pred), abolish/1)) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index eedb127b..a35a65e8 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2369,6 +2369,8 @@ impl MachineState { if self.fail { return Ok(()); } + + break; } _ => { self.eof_action( -- cgit v1.2.3-70-g09d2 From d02b9d848cfd47b40d20b9834b2fcfc96738bb98 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 25 Nov 2021 23:08:02 -0700 Subject: break from loop upon successful peek in peek_char/1 and peek_code/1 --- src/machine/system_calls.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index a35a65e8..3d33d921 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1512,6 +1512,7 @@ impl MachineState { match stream.peek_char().map(|result| result.map_err(|e| e.kind())) { Some(Ok(d)) => { self.unify_char(d, a2); + break; } Some(Err(ErrorKind::PermissionDenied)) => { self.fail = true; @@ -1614,6 +1615,7 @@ impl MachineState { match result.map(|result| result.map_err(|e| e.kind())) { Some(Ok(c)) => { self.unify_fixnum(Fixnum::build_with(c as i64), addr); + break; } Some(Err(ErrorKind::PermissionDenied)) => { self.fail = true; -- cgit v1.2.3-70-g09d2 From 975c1ca62cecd82ec1b115bb5f464b95719edde9 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 26 Nov 2021 22:13:52 -0700 Subject: fix stream errors --- src/clause_types.rs | 2 +- src/machine/machine_state.rs | 3 +-- src/machine/streams.rs | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/clause_types.rs b/src/clause_types.rs index 540bf779..2e298dff 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -157,7 +157,7 @@ pub fn clause_type_form(name: Atom, arity: usize) -> Option { ))), (atom!("keysort"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::KeySort)), (atom!("\\=="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::NotEq)), - (atom!("read"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::Read)), + (atom!("read"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Read)), (atom!("sort"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Sort)), _ => None, } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 8d39edcd..32665ad7 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -1,7 +1,6 @@ use crate::arena::*; use crate::atom_table::*; use crate::parser::ast::*; -use crate::temp_v; use crate::clause_types::*; use crate::forms::*; @@ -490,7 +489,7 @@ pub trait CallPolicy: Any + fmt::Debug { } &BuiltInClauseType::Read => { let stream = machine_st.get_stream_or_alias( - machine_st[temp_v!(1)], + machine_st.registers[1], stream_aliases, atom!("read"), 2, diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 064d9fa8..4aeba63e 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1369,9 +1369,7 @@ impl MachineState { arity: usize, ) -> MachineStub { let stub = functor_stub(caller, arity); - let payload = vec![stream_as_cell!(stream)]; - - let err = self.permission_error(perm, err_atom, payload); + let err = self.permission_error(perm, err_atom, stream_as_cell!(stream)); return self.error_form(err, stub); } -- cgit v1.2.3-70-g09d2 From a87236fea27922cfa4fc07784e6d64c55cbde920 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 28 Nov 2021 10:21:07 -0700 Subject: keep cursor position after writing to byte stream --- src/machine/streams.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 4aeba63e..8e2e2c13 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -110,7 +110,13 @@ impl Read for ByteStream { impl Write for ByteStream { #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.0.write(buf) + let pos = self.0.position(); + + self.0.seek(SeekFrom::End(0))?; + let result = self.0.write(buf); + self.0.seek(SeekFrom::Start(pos))?; + + result } #[inline] -- cgit v1.2.3-70-g09d2 From 529c401eee00cf267a36bf9abf3967973da0fd07 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 28 Nov 2021 14:53:39 -0700 Subject: don't allow [] as a stream alias, restore domain error on source sink for open/{3,4} --- src/machine/streams.rs | 7 ++++++- src/machine/system_calls.rs | 12 ++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 8e2e2c13..047f9112 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1231,7 +1231,12 @@ impl MachineState { let alias = read_heap_cell!(self.store(MachineState::deref(self, alias)), (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); - Some(name) + + if name != atom!("[]") { + Some(name) + } else { + None + } } _ => { None diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 3d33d921..2d699a06 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2977,8 +2977,16 @@ impl MachineState { let options = self.to_stream_options(alias, eof_action, reposition, stream_type); let src_sink = self.store(self.deref(self.registers[1])); - if let Some(atom_or_string) = self.value_to_str_like(src_sink) { - let file_spec = self.atom_tbl.build_with(atom_or_string.as_str()); + if let Some(str_like) = self.value_to_str_like(src_sink) { + let file_spec = match str_like { + AtomOrString::Atom(atom) => { + atom + } + AtomOrString::String(string) => { + self.atom_tbl.build_with(&string) + } + }; + let mut stream = self.stream_from_file_spec(file_spec, indices, &options)?; *stream.options_mut() = options; -- cgit v1.2.3-70-g09d2 From 1a86ad5cec263839c037a2858de78fe672df1b55 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 28 Nov 2021 20:36:09 -0700 Subject: upgrade rustyline --- Cargo.lock | 149 ++++++++++++++++++++++++++++++++++++++++++------- Cargo.toml | 2 +- src/arena.rs | 37 +++++------- src/machine/streams.rs | 79 -------------------------- 4 files changed, 144 insertions(+), 123 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d5b4dc14..2de5d75c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,9 +63,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "1.3.2" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "blake2" @@ -160,6 +160,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "clipboard-win" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8340083d28acb43451166543b98c838299b7e0863621be53a338adceea0ed" +dependencies = [ + "error-code", + "str-buf", + "winapi 0.3.9", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -299,6 +310,33 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "error-code" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff" +dependencies = [ + "libc", + "str-buf", +] + +[[package]] +name = "fd-lock" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc110fe50727d46a428eed832df40affe9bf74d077cac1bf3f2718e823f14c5" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "windows-sys", +] + [[package]] name = "foreign-types" version = "0.3.2" @@ -314,16 +352,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi 0.3.9", -] - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -607,6 +635,15 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg 1.0.1", +] + [[package]] name = "mio" version = "0.6.23" @@ -692,6 +729,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + [[package]] name = "nix" version = "0.15.0" @@ -707,14 +753,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.19.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2" +checksum = "d3bb9a13fa32bc5aeb64150cd3f32d6cf4c748f8f8a417cce5d2eb976a8370ba" dependencies = [ "bitflags", "cc", "cfg-if 1.0.0", "libc", + "memoffset", ] [[package]] @@ -1027,6 +1074,16 @@ dependencies = [ "proc-macro2 1.0.32", ] +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + [[package]] name = "rand" version = "0.6.5" @@ -1276,19 +1333,22 @@ dependencies = [ [[package]] name = "rustyline" -version = "7.1.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8227301bfc717136f0ecbd3d064ba8199e44497a0bdd46bb01ede4387cfd2cec" +checksum = "790487c3881a63489ae77126f57048b42d62d3b2bafbf37453ea19eedb6340d6" dependencies = [ "bitflags", "cfg-if 1.0.0", + "clipboard-win", "dirs-next", - "fs2", + "fd-lock", "libc", "log", "memchr", - "nix 0.19.1", + "nix 0.22.2", + "radix_trie", "scopeguard", + "smallvec", "unicode-segmentation", "unicode-width", "utf8parse", @@ -1371,9 +1431,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.4.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" +checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" dependencies = [ "bitflags", "core-foundation", @@ -1539,6 +1599,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "str-buf" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" + [[package]] name = "string_cache" version = "0.7.5" @@ -1835,6 +1901,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2" + +[[package]] +name = "windows_i686_gnu" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a" + +[[package]] +name = "windows_i686_msvc" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f" + [[package]] name = "ws2_32-sys" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index ee785cb4..6d27688a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ ordered-float = "2.1.1" phf = { version = "0.9", features = ["macros"] } ref_thread_local = "0.0.0" rug = { version = "1.12.0", optional = true } -rustyline = "7.0.0" +rustyline = "9.0.0" ring = "0.16.13" ripemd160 = "0.8.0" sha3 = "0.8.2" diff --git a/src/arena.rs b/src/arena.rs index 0d6ad6a0..7fafccb1 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -373,51 +373,42 @@ impl Arena { unsafe fn drop_slab_in_place(value: &mut AllocSlab) { match value.header.tag() { ArenaHeaderTag::Integer => { - ptr::drop_in_place(value.payload_offset() as *mut Integer); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::Rational => { - ptr::drop_in_place(value.payload_offset() as *mut Rational); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::InputFileStream => { - ptr::drop_in_place(value.payload_offset() as *mut InputFileStream); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::OutputFileStream => { - ptr::drop_in_place(value.payload_offset() as *mut OutputFileStream); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::NamedTcpStream => { - ptr::drop_in_place(value.payload_offset() as *mut NamedTcpStream); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::NamedTlsStream => { - ptr::drop_in_place(value.payload_offset() as *mut NamedTlsStream); + ptr::drop_in_place(value.payload_offset::()); } - // ArenaHeaderTag::PausedPrologStream => { - // // idea: PausedPrologStream with only the buffer of unread characters. - // // no stream to be wrapped, no nuttin'. - // ptr::drop_in_place(value.payload_offset() as *mut PausedPrologStream); - // } ArenaHeaderTag::ReadlineStream => { - ptr::drop_in_place(value.payload_offset() as *mut ReadlineStream); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::StaticStringStream => { - ptr::drop_in_place(value.payload_offset() as *mut StaticStringStream); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::ByteStream => { - ptr::drop_in_place(value.payload_offset() as *mut ByteStream); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::OssifiedOpDir => { - ptr::drop_in_place( - mem::transmute::<_, *mut OssifiedOpDir>(value.payload_offset()) - ); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => { - ptr::drop_in_place( - mem::transmute::<_, *mut LiveLoadState>(value.payload_offset()) - ); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::Dropped => { } ArenaHeaderTag::TcpListener => { - ptr::drop_in_place(value.payload_offset() as *mut TcpListener); + ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::F64 | ArenaHeaderTag::StandardOutputStream | ArenaHeaderTag::StandardErrorStream | ArenaHeaderTag::NullStream => { @@ -458,10 +449,10 @@ impl AllocSlab { self.header.size() as usize + mem::size_of::() } - fn payload_offset(&self) -> *const u8 { + fn payload_offset(&self) -> *mut T { let mut ptr = (self as *const AllocSlab) as usize; ptr += mem::size_of::(); - ptr as *const u8 + ptr as *mut T } } diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 047f9112..1b512e51 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -237,11 +237,6 @@ impl Write for NamedTlsStream { } } -/* -#[derive(Debug)] -pub struct NullStream {} -*/ - #[derive(Debug)] pub struct StandardOutputStream {} @@ -375,65 +370,6 @@ macro_rules! arena_allocated_impl_for_stream { }; } -/* -pub mod testing { - use super::PausedPrologStream; - - impl PausedPrologStream { - #[allow(dead_code)] - pub fn write_test_input(&mut self, string: &str) { - self.bytes.extend(string.as_bytes().iter().rev()); - } - } -} -*/ -/* -impl ArenaAllocated for PausedPrologStream { - type PtrToAllocated = TypedArenaPtr; - - #[inline] - fn tag() -> ArenaHeaderTag { - ArenaHeaderTag::PausedPrologStream - } - - #[inline] - fn size(&self) -> usize { - mem::size_of::() - } - - #[inline] - fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated { - unsafe { - ptr::write(dst, self); - TypedArenaPtr::new(dst as *mut Self) - } - } -} - -#[derive(Debug)] -pub struct PausedPrologStream { - bytes: Vec, - paused_stream: Stream, -} - -impl PausedPrologStream { - #[inline] - pub fn new() -> Self { - PausedPrologStream { - bytes: vec![], - paused_stream: Stream::Null(StreamOptions::default()), - } - } -} - -impl Read for PausedPrologStream { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - self.paused_stream.read(buf) - } -} -*/ - arena_allocated_impl_for_stream!(CharReader, ByteStream); arena_allocated_impl_for_stream!(CharReader, InputFileStream); arena_allocated_impl_for_stream!(OutputFileStream, OutputFileStream); @@ -593,21 +529,6 @@ impl Stream { } } - /* - fn unpause_stream(&mut self) { - let stream_inst = match self { - Stream::PausedProlog(paused) if paused.bytes.is_empty() => { - mem::replace(&mut paused.paused_stream, Stream::Null(StreamOptions::default())) - } - _ => { - return; - } - }; - - *self = stream_inst; - } - */ - #[inline] pub(crate) fn add_lines_read(&mut self, incr_num_lines_read: usize) { match self { -- cgit v1.2.3-70-g09d2 From ef3a97cedd91e49663a7502c60502c4a5316f7c3 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 29 Nov 2021 19:22:26 -0700 Subject: detect attributed variables by properly detecting them in copy_term/2 --- src/machine/attributed_variables.rs | 2 ++ src/machine/copier.rs | 51 +++---------------------------------- src/types.rs | 6 ++--- 3 files changed, 8 insertions(+), 51 deletions(-) diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 30ec9a8c..568978d8 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -143,6 +143,8 @@ impl MachineState { continue; } + let value = unmark_cell_bits!(value); + seen_vars.push(value); seen_set.insert(h); diff --git a/src/machine/copier.rs b/src/machine/copier.rs index bab1d110..f5417e53 100644 --- a/src/machine/copier.rs +++ b/src/machine/copier.rs @@ -166,8 +166,7 @@ impl CopyTermState { self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h))); if let AttrVarPolicy::DeepCopy = self.attr_var_policy { - self.target - .push(attr_var_as_cell!(threshold)); + self.target.push(attr_var_as_cell!(threshold)); let list_val = self.target[h + 1]; self.target.push(list_val); @@ -195,58 +194,14 @@ impl CopyTermState { _ => {} ); - if addr == ra { - self.reinstantiate_var(addr, self.scan); + if rd == ra { + self.reinstantiate_var(ra, self.scan); self.scan += 1; } else { *self.value_at_scan() = ra; - // self.copy_compound(rd, ra); } } - /* - fn copy_compound(&mut self, rd: HeapCellValue, ra: HeapCellValue) { - let h = rd.get_value(); - let trail_item = self.target[h]; - let threshold = self.target.threshold(); - - self.trail.push((Ref::heap_cell(h), trail_item)); - self.target[self.scan].set_value(threshold); - - read_heap_cell!(ra, - (HeapCellValueTag::Atom, (_name, arity)) => { - self.target.push(ra); - - for i in 0..arity { - self.target.push(self.target[h + 1 + i]); - } - - self.target[h] = str_loc_as_cell!(self.scan + 1); - } - (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { - self.target.push(ra); - self.target.push(self.target[h + 1]); - - self.target[h] = pstr_loc_as_cell!(self.scan + 1); - } - (HeapCellValueTag::CStr, cstr_atom) => { - self.target[h] = atom_as_cstr_cell!(cstr_atom); - } - (HeapCellValueTag::Str, s) => { - self.copy_structure(s); - return; - } - _ => { - *self.value_at_scan() = rd; - self.trail.pop(); - return; - } - ); - - self.scan += 1; - } - */ - fn copy_structure(&mut self, addr: usize) { read_heap_cell!(self.target[addr], (HeapCellValueTag::Atom, (name, arity)) => { diff --git a/src/types.rs b/src/types.rs index 57a6c5a3..b0339a1a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -221,9 +221,9 @@ impl TrailEntry { #[inline(always)] pub(crate) fn get_tag(self) -> TrailEntryTag { match self.tag_or_err() { - Ok(tag) => tag, - Err(_) => TrailEntryTag::TrailedAttachedValue, - } + Ok(tag) => tag, + Err(_) => TrailEntryTag::TrailedAttachedValue, + } } #[inline] -- cgit v1.2.3-70-g09d2 From fb4e627e6281bae6176b61fef27e021decbdb92a Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 30 Nov 2021 22:35:38 -0700 Subject: fix various partial string bugs (copying using them in arg/3) --- src/lib/tabling/trie.pl | 2 ++ src/machine/copier.rs | 67 +++++++++++++++++++++++++++------------ src/machine/machine_state_impl.rs | 49 +++++++++++++++++++++++++--- src/types.rs | 1 + 4 files changed, 95 insertions(+), 24 deletions(-) diff --git a/src/lib/tabling/trie.pl b/src/lib/tabling/trie.pl index cd855b92..2460f70f 100644 --- a/src/lib/tabling/trie.pl +++ b/src/lib/tabling/trie.pl @@ -41,6 +41,8 @@ trie_get_all_values/2 % +Trie, -Value ]). +:- use_module(library(format)). + :- use_module(library(assoc)). :- use_module(library(atts)). :- use_module(library(lists)). diff --git a/src/machine/copier.rs b/src/machine/copier.rs index f5417e53..fd016fd6 100644 --- a/src/machine/copier.rs +++ b/src/machine/copier.rs @@ -107,36 +107,63 @@ impl CopyTermState { fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) { read_heap_cell!(self.target[pstr_loc], (HeapCellValueTag::PStrLoc, h) => { - if h >= self.old_h { - *self.value_at_scan() = match scan_tag { - HeapCellValueTag::PStrLoc => { - pstr_loc_as_cell!(h) - } - tag => { - debug_assert!(tag == HeapCellValueTag::PStrOffset); - pstr_offset_as_cell!(h) - } - }; + debug_assert!(h >= self.old_h); - self.scan += 1; - return; - } + *self.value_at_scan() = match scan_tag { + HeapCellValueTag::PStrLoc => { + pstr_loc_as_cell!(h) + } + tag => { + debug_assert_eq!(tag, HeapCellValueTag::PStrOffset); + pstr_offset_as_cell!(h) + } + }; + + self.scan += 1; + return; + } + (HeapCellValueTag::Var, h) => { + debug_assert!(h >= self.old_h); + debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset); + + *self.value_at_scan() = pstr_offset_as_cell!(h); + self.scan += 1; + + return; } _ => {} ); let threshold = self.target.threshold(); - *self.value_at_scan() = pstr_loc_as_cell!(threshold); - self.scan += 1; + let replacement = read_heap_cell!(self.target[pstr_loc], + (HeapCellValueTag::CStr) => { + debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset); - self.target.push(self.target[pstr_loc]); + *self.value_at_scan() = pstr_offset_as_cell!(threshold); + self.target.push(self.target[pstr_loc]); - let replacement = pstr_loc_as_cell!(threshold); - let trail_item = mem::replace(&mut self.target[pstr_loc], replacement); + heap_loc_as_cell!(threshold) + } + _ => { + *self.value_at_scan() = if scan_tag == HeapCellValueTag::PStrLoc { + pstr_loc_as_cell!(threshold) + } else { + debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset); + pstr_offset_as_cell!(threshold) + }; + + self.target.push(self.target[pstr_loc]); + self.target.push(self.target[pstr_loc + 1]); + pstr_loc_as_cell!(threshold) + } + ); + + self.scan += 1; + + let trail_item = mem::replace(&mut self.target[pstr_loc], replacement); self.trail.push((Ref::heap_cell(pstr_loc), trail_item)); - self.target.push(self.target[pstr_loc + 1]); } fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) { @@ -185,7 +212,7 @@ impl CopyTermState { read_heap_cell!(ra, (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if h >= self.old_h { - *self.value_at_scan() = rd; + *self.value_at_scan() = ra; self.scan += 1; return; diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index b0416b1d..dbf44bed 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -3046,11 +3046,26 @@ impl MachineState { } else { let offset = (offset + c.len_utf8()) as i64; let h_len = self.heap.len(); + let pstr_atom: Atom = pstr.into(); - self.heap.push(pstr_offset_as_cell!(h_len)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); + if pstr_atom.len() > offset as usize { + self.heap.push(pstr_offset_as_cell!(h)); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); - unify_fn!(self, pstr_loc_as_cell!(h_len), a3); + unify_fn!(self, pstr_loc_as_cell!(h_len), a3); + } else { + match self.heap[h].get_tag() { + HeapCellValueTag::CStr => { + self.unify_atom(atom!("[]"), self.store(self.deref(a3))); + } + HeapCellValueTag::PStr => { + unify_fn!(self, self.heap[h+1], a3); + } + _ => { + unreachable!(); + } + } + } } } else { unreachable!() @@ -3059,6 +3074,32 @@ impl MachineState { self.fail = true; } } + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = PartialString::from(cstr_atom); + + if let Some(c) = cstr.as_str_from(0).chars().next() { + if n == 1 { + self.unify_char(c, self.store(self.deref(self.registers[3]))); + } else if n == 2 { + let offset = c.len_utf8() as i64; + let h_len = self.heap.len(); + + if cstr_atom.len() > offset as usize { + self.heap.push(atom_as_cstr_cell!(cstr_atom)); + self.heap.push(pstr_offset_as_cell!(h_len)); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); + + unify_fn!(self, pstr_loc_as_cell!(h_len+1), self.registers[3]); + } else { + self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[3]))); + } + } else { + self.fail = true; + } + } else { + unreachable!() + } + } _ => { // 8.5.2.3 d) let err = self.type_error(ValidType::Compound, term); @@ -3361,7 +3402,7 @@ impl MachineState { let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); self.try_functor_compound_case(name, arity); } - (HeapCellValueTag::Lis | HeapCellValueTag::PStrOffset) => { + (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { self.try_functor_compound_case(atom!("."), 2); } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { diff --git a/src/types.rs b/src/types.rs index b0339a1a..16805981 100644 --- a/src/types.rs +++ b/src/types.rs @@ -729,6 +729,7 @@ impl Sub for HeapCellValue { tag @ HeapCellValueTag::Str | tag @ HeapCellValueTag::Lis | tag @ HeapCellValueTag::PStrOffset | + tag @ HeapCellValueTag::PStrLoc | tag @ HeapCellValueTag::Var | tag @ HeapCellValueTag::AttrVar => { HeapCellValue::build_with(tag, (self.get_value() + rhs.abs() as usize) as u64) -- cgit v1.2.3-70-g09d2 From 4cde8cd5015057e01901be241ddf802100327df1 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 3 Dec 2021 21:18:13 -0700 Subject: fix bug in error_form --- src/machine/machine_errors.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index d62e5b5b..cae977e5 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -503,22 +503,29 @@ impl MachineState { } pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub { - let location = err.location; - let err_len = err.len(); - let h = self.heap.len(); + let location = err.location; + let stub_addition_len = if err.len() == 1 { + 0 // if err contains 1 cell, it can be inlined at stub[1]. + } else { + err.len() + }; let mut stub = vec![ atom_as_cell!(atom!("error"), 2), str_loc_as_cell!(h + 3), - str_loc_as_cell!(h + 3 + err_len), + str_loc_as_cell!(h + 3 + stub_addition_len), ]; - stub.extend(err.into_iter(3)); + if stub_addition_len > 0 { + stub.extend(err.into_iter(3)); + } else { + stub[1] = err.stub[0]; + } if let Some((line_num, _)) = location { stub.push(atom_as_cell!(atom!(":"), 2)); - stub.push(str_loc_as_cell!(h + 6 + err_len)); + stub.push(str_loc_as_cell!(h + 6 + stub_addition_len)); stub.push(integer_as_cell!(Number::arena_from( line_num, &mut self.arena -- cgit v1.2.3-70-g09d2 From d7bf04d2c0f0791628ab1f1470ce5f18fef30484 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 4 Dec 2021 16:24:06 -0700 Subject: fix off by one bug in system_calls --- src/machine/system_calls.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 2d699a06..dd1f7eab 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -354,7 +354,7 @@ impl MachineState { let cstr = PartialString::from(cstr_atom); let pstr_chars = cstr.as_str_from(0).chars().count(); - if pstr_chars < max_steps { + if pstr_chars <= max_steps { CycleSearchResult::ProperList(pstr_chars) } else { CycleSearchResult::UntouchedCStr(cstr_atom, max_steps) @@ -734,7 +734,7 @@ impl MachineState { // avoid allocating a String if possible ... Some(AtomOrString::Atom(cstr_atom)) } - (HeapCellValueTag::Atom, (atom, arity)) => { + (HeapCellValueTag::Atom, (atom, arity)) => { // TODO: Char?? if arity == 0 { // ... likewise. Some(AtomOrString::Atom(atom)) @@ -2698,13 +2698,13 @@ impl MachineState { &SystemClauseType::EnqueueAttributedVar => { let addr = self.store(self.deref(self.registers[1])); - read_heap_cell!(addr, - (HeapCellValueTag::AttrVar, h) => { - self.attr_var_init.attr_var_queue.push(h); - } - _ => { - } - ); + read_heap_cell!(addr, + (HeapCellValueTag::AttrVar, h) => { + self.attr_var_init.attr_var_queue.push(h); + } + _ => { + } + ); } &SystemClauseType::GetNextDBRef => { let a1 = self.store(self.deref(self.registers[1])); @@ -4424,11 +4424,6 @@ impl MachineState { &SystemClauseType::UnwindStack => { self.unwind_stack(); } - /* - &SystemClauseType::Variant => { - self.fail = self.structural_eq_test(); - } - */ &SystemClauseType::WAMInstructions => { let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); -- cgit v1.2.3-70-g09d2 From 2b3e43f1600c6544620c7510d0ac8e7295c3155a Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 4 Dec 2021 16:24:34 -0700 Subject: start to retune testing infrastructure --- src/machine/mock_wam.rs | 99 +++++++++++++++++++++++++++++++++++++++++++++---- tests/scryer/helper.rs | 19 +--------- tests/scryer/main.rs | 3 +- 3 files changed, 95 insertions(+), 26 deletions(-) diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 540db78f..0cbae419 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -2,7 +2,7 @@ pub use crate::arena::*; pub use crate::atom_table::*; use crate::heap_print::*; pub use crate::machine::heap::*; -pub use crate::machine::Machine; +pub use crate::machine::*; pub use crate::machine::machine_state::*; pub use crate::machine::stack::*; pub use crate::machine::streams::*; @@ -215,14 +215,100 @@ pub(crate) fn parse_and_write_parsed_term_to_heap( } impl Machine { + pub fn with_test_streams() -> Self { + use ref_thread_local::RefThreadLocal; + + let mut machine_st = MachineState::new(); + + let user_input = Stream::Null(StreamOptions::default()); + let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena); + let user_error = Stream::stderr(&mut machine_st.arena); + + let mut wam = Machine { + machine_st, + inner_heap: Heap::new(), + policies: MachinePolicies::new(), + indices: IndexStore::new(), + code_repo: CodeRepo::new(), + user_input, + user_output, + user_error, + load_contexts: vec![], + }; + + let mut lib_path = current_dir(); + + lib_path.pop(); + lib_path.push("lib"); + + bootstrapping_compile( + Stream::from_static_string( + LIBRARIES.borrow()["ops_and_meta_predicates"], + &mut wam.machine_st.arena, + ), + &mut wam, + ListingSource::from_file_and_path( + atom!("ops_and_meta_predicates.pl"), + lib_path.clone(), + ), + ) + .unwrap(); + + bootstrapping_compile( + Stream::from_static_string( + LIBRARIES.borrow()["builtins"], + &mut wam.machine_st.arena, + ), + &mut wam, + ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()), + ) + .unwrap(); + + if let Some(builtins) = wam.indices.modules.get(&atom!("builtins")) { + load_module( + &mut wam.indices.code_dir, + &mut wam.indices.op_dir, + &mut wam.indices.meta_predicates, + &CompilationTarget::User, + builtins, + ); + } else { + unreachable!() + } + + lib_path.pop(); // remove the "lib" at the end + + bootstrapping_compile( + Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena), + &mut wam, + ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()), + ) + .unwrap(); + + wam.configure_modules(); + + if let Some(loader) = wam.indices.modules.get(&atom!("loader")) { + load_module( + &mut wam.indices.code_dir, + &mut wam.indices.op_dir, + &mut wam.indices.meta_predicates, + &CompilationTarget::User, + loader, + ); + } else { + unreachable!() + } + + wam.load_special_forms(); + wam.load_top_level(); + wam.configure_streams(); + + wam + } + pub fn test_load_file(&mut self, file: &str) -> Vec { use std::io::Read; - let old_output = std::mem::replace( - &mut self.user_output, - Stream::from_owned_string("".to_owned(), &mut self.machine_st.arena), - ); - let stream = Stream::from_owned_string( std::fs::read_to_string(AsRef::::as_ref(file)).unwrap(), &mut self.machine_st.arena, @@ -231,7 +317,6 @@ impl Machine { self.load_file(file.into(), stream); let output = self.user_output.bytes().map(|b| b.unwrap()).collect(); - self.user_output = old_output; output } } diff --git a/tests/scryer/helper.rs b/tests/scryer/helper.rs index 3dec7e3e..9cb2f0a3 100644 --- a/tests/scryer/helper.rs +++ b/tests/scryer/helper.rs @@ -29,25 +29,10 @@ impl Expectable for &[u8] { /// Tests whether the file can be successfully loaded /// and produces the expected output during it pub(crate) fn load_module_test(file: &str, expected: T) { - use scryer_prolog::*; + use scryer_prolog::machine::mock_wam::*; - // let input = machine::Stream::from(""); - // let output = machine::Stream::from(String::new()); - // let error = machine::Stream::from(String::new()); - - let mut wam = machine::Machine::new(); // input, output.clone(), error); + let mut wam = Machine::with_test_streams(); expected.assert_eq(wam.test_load_file(file).as_slice()); - - // wam.load_file( - // file.into(), - // machine::Stream::from_owned_string( - // std::fs::read_to_string(AsRef::::as_ref(file)).unwrap(), - // &mut wam.machine_st.arena, - // ), - // ); - // - // let output = output.bytes().unwrap(); - // expected.assert_eq(output.as_slice()); } pub const SCRYER_PROLOG: &str = "scryer-prolog"; diff --git a/tests/scryer/main.rs b/tests/scryer/main.rs index 1b3ada5f..08072d36 100644 --- a/tests/scryer/main.rs +++ b/tests/scryer/main.rs @@ -1,4 +1,3 @@ mod helper; - -mod issues; +// mod issues; mod src_tests; -- cgit v1.2.3-70-g09d2 From cd129e32a7af4d160e3ce8120f07cd1dedac26e5 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 4 Dec 2021 23:46:31 -0700 Subject: fix bugs revealed by src/tests/builtins.pl --- src/codegen.rs | 8 +++++--- src/heap_iter.rs | 3 --- src/machine/heap.rs | 4 ++++ src/machine/loader.rs | 5 +++-- src/machine/machine_state.rs | 3 +-- src/machine/machine_state_impl.rs | 23 +++++++++++++++-------- src/machine/mock_wam.rs | 2 +- src/tests/builtins.pl | 8 -------- tests/scryer/main.rs | 2 +- 9 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/codegen.rs b/src/codegen.rs index 243974aa..ca344558 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -538,6 +538,9 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) => { code.push(fail!()); } + &Term::Literal(_, Literal::String(_)) => { + code.push(fail!()); + } &Term::Literal(..) => { code.push(succeed!()); } @@ -548,7 +551,8 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } }, &InlinedClauseType::IsCompound(..) => match &terms[0] { - &Term::Clause(..) | &Term::Cons(..) => { + &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) | + &Term::Literal(_, Literal::String(..)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -591,7 +595,6 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { | &Term::Literal(_, Literal::Rational(_)) | &Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => { - // | &Term::Literal(_, Literal::Usize(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { @@ -618,7 +621,6 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { }, &InlinedClauseType::IsInteger(..) => match &terms[0] { &Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => { - // | &Term::Literal(_, Literal::Usize(_)) => { code.push(succeed!()); } &Term::Var(ref vr, ref name) => { diff --git a/src/heap_iter.rs b/src/heap_iter.rs index b5c83a22..df211339 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -204,9 +204,6 @@ impl<'a> StackfulPreOrderHeapIter<'a> { return Some(self.heap[h]); } - // (HeapCellValueTag::StackVar) => { - // unreachable!() // TODO: here, crashing. - // } _ => { return Some(*cell); } diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 462aacbc..cb166b69 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -67,6 +67,10 @@ impl TryFrom for Literal { (ArenaHeaderTag::Rational, n) => { Ok(Literal::Rational(n)) } + (ArenaHeaderTag::F64, f) => { + // remove this redundancy. + Ok(Literal::Float(F64Ptr(f))) + } _ => { Err(()) } diff --git a/src/machine/loader.rs b/src/machine/loader.rs index d7ed073e..ba1a5cea 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -446,6 +446,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let mut iter = stackful_post_order_iter(&mut machine_st.heap, term_addr); while let Some(addr) = iter.next() { + let addr = unmark_cell_bits!(addr); + read_heap_cell!(addr, (HeapCellValueTag::Lis) => { let tail = term_stack.pop().unwrap(); @@ -459,7 +461,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } (HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum | HeapCellValueTag::Char | HeapCellValueTag::F64) => { - let addr = unmark_cell_bits!(addr); term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap())); } (HeapCellValueTag::Atom, (name, arity)) => { @@ -490,7 +491,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { )); } } - (HeapCellValueTag::PStrOffset, h) => { + (HeapCellValueTag::PStrLoc, h) => { let string = cell_as_atom_cell!(iter.heap[h]).get_name(); let tail = term_stack.pop().unwrap(); diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 32665ad7..1ca0a784 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -966,9 +966,8 @@ impl MachineState { loop { match self.read(stream, &indices.op_dir) { Ok(term_write_result) => { - let term = self.registers[2]; + let term = self.store(self.deref(self.registers[2])); unify_fn!(self, heap_loc_as_cell!(term_write_result.heap_loc), term); - let term = self.store(self.deref(term)); if self.fail { return Ok(()); diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index dbf44bed..dfaa502e 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -2847,15 +2847,15 @@ impl MachineState { } &QueryInstruction::SetLocalValue(reg) => { let addr = self.deref(self[reg]); - let h = self.heap.len(); + let stored_v = self.store(addr); - if addr < Ref::heap_cell(h) { - self.heap.push(addr); - return; + if stored_v.is_stack_var() { + let h = self.heap.len(); + self.heap.push(heap_loc_as_cell!(h)); + (self.bind_fn)(self, Ref::heap_cell(h), stored_v); + } else { + self.heap.push(stored_v); } - - self.heap.push(heap_loc_as_cell!(h)); - (self.bind_fn)(self, Ref::heap_cell(h), addr); } &QueryInstruction::SetVariable(reg) => { let h = self.heap.len(); @@ -2956,6 +2956,7 @@ impl MachineState { return false; } + let addr = self.store(self.deref(addr)); let mut iter = stackful_preorder_iter(&mut self.heap, addr); while let Some(value) = iter.next() { @@ -3624,9 +3625,15 @@ impl MachineState { return false; } - let value = self.registers[1]; + let value = self.store(self.deref(self.registers[1])); + + if value.is_stack_var() { + return true; + } for v in stackful_preorder_iter(&mut self.heap, value) { + let v = unmark_cell_bits!(v); + if v.is_var() { return true; } diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 0cbae419..42d3f600 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -846,6 +846,6 @@ mod tests { wam.heap.push(pstr_as_cell!(atom!("a string"))); wam.heap.push(empty_list_as_cell!()); - assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0))); + assert!(!wam.is_cyclic_term(pstr_loc_as_cell!(0))); } } diff --git a/src/tests/builtins.pl b/src/tests/builtins.pl index 96b5e4c0..a87fc22a 100644 --- a/src/tests/builtins.pl +++ b/src/tests/builtins.pl @@ -115,14 +115,6 @@ test_queries_on_builtins :- 1.1 @< 1, 1.0 @=< 1, \+ 1 @=< 1.0, - \+ \+ (variant(X, Y)), - \+ (variant(f(X), f(x))), - \+ \+ (variant(X, X)), - \+ \+ (variant(f(x), f(x))), - \+ (variant([X,Y,Z], [V,W,V])), - \+ \+ (variant([X,Y,Z], [V,W,Z])), - \+ \+ (variant([X,Y,X], [V,W,V])), - \+ \+ (g(B) = B, g(A) = A, variant(A, B)), keysort([1-1,1-1],[1-1,1-1]), \+ \+ findall(Sorted, keysort([2-99,1-a,3-f(_),1-z,1-a,2-44],Sorted), [[1-a,1-z,1-a,2-99,2-44,3-f(_)]]), \+ \+ findall(X, keysort([X-1,1-1],[2-1,1-1]), [2]). diff --git a/tests/scryer/main.rs b/tests/scryer/main.rs index 08072d36..7865c0b3 100644 --- a/tests/scryer/main.rs +++ b/tests/scryer/main.rs @@ -1,3 +1,3 @@ mod helper; -// mod issues; +mod issues; mod src_tests; -- cgit v1.2.3-70-g09d2 From 8ba61a1da14540f07c125d4155bf8fbd7cbd761c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 6 Dec 2021 18:08:38 -0700 Subject: defer installation of inference counter for call_with_inference_limit til after goals expanded --- src/clause_types.rs | 1 - src/lib/builtins.pl | 28 +++++++------ src/lib/iso_ext.pl | 23 +++++++---- src/loader.pl | 4 +- src/machine/system_calls.rs | 72 +++++++++++++++++----------------- src/tests/call_with_inference_limit.pl | 25 ++++++------ 6 files changed, 82 insertions(+), 71 deletions(-) diff --git a/src/clause_types.rs b/src/clause_types.rs index 2e298dff..e11e84b1 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -481,7 +481,6 @@ impl SystemClauseType { &SystemClauseType::Maybe => atom!("maybe"), &SystemClauseType::CpuNow => atom!("$cpu_now"), &SystemClauseType::CurrentTime => atom!("$current_time"), - // &SystemClauseType::ModuleHeadIsDynamic => atom!("$module_head_is_dynamic"), &SystemClauseType::ModuleExists => atom!("$module_exists"), &SystemClauseType::NextStream => atom!("$next_stream"), &SystemClauseType::NoSuchPredicate => atom!("$no_such_predicate"), diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 86d5841f..e27a1f43 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -69,7 +69,8 @@ Module : Predicate :- % dynamic module resolution. :(Module, Predicate, A1) :- - ( atom(Module) -> '$module_call'(A1, Module, Predicate) + ( atom(Module) -> + '$module_call'(A1, Module, Predicate) ; throw(error(type_error(atom, Module), (:)/2)) ). @@ -262,7 +263,7 @@ comma_dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :- '$call'(G6), '$call'(G7), '$call'(G8), - comma_dispatch_call_list(Gs). + '$call_with_default_policy'(comma_dispatch_call_list(Gs)). comma_dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :- !, '$call'(G1), @@ -585,7 +586,9 @@ throw(Ball) :- ), '$unwind_stack'. + :- non_counted_backtracking '$iterate_find_all'/4. + '$iterate_find_all'(Template, Goal, _, LhOffset) :- call(Goal), '$copy_to_lh'(LhOffset, Template), @@ -601,7 +604,7 @@ truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength). :- meta_predicate findall(?, 0, ?). findall(Template, Goal, Solutions) :- - error:can_be(list, Solutions), + '$call_with_default_policy'(error:can_be(list, Solutions)), '$lh_length'(LhLength), '$call_with_default_policy'( catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength), @@ -609,7 +612,6 @@ findall(Template, Goal, Solutions) :- ( builtins:truncate_lh_to(LhLength), builtins:throw(Error) )) ). - :- non_counted_backtracking '$iterate_find_all_diff'/5. '$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :- @@ -624,8 +626,8 @@ findall(Template, Goal, Solutions) :- :- meta_predicate findall(?, 0, ?, ?). findall(Template, Goal, Solutions0, Solutions1) :- - error:can_be(list, Solutions0), - error:can_be(list, Solutions1), + '$call_with_default_policy'(error:can_be(list, Solutions0)), + '$call_with_default_policy'(error:can_be(list, Solutions1)), '$lh_length'(LhLength), '$call_with_default_policy'( catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0, @@ -819,13 +821,14 @@ asserta_clause(Head, Body) :- :- meta_predicate asserta(0). -asserta(Clause) :- +asserta(Clause0) :- + loader:strip_module(Clause0, Module, Clause), ( Clause \= (_ :- _) -> Head = Clause, Body = true, - asserta_clause(Head, Body) + module_asserta_clause(Head, Body, Module) ; Clause = (Head :- Body) -> - asserta_clause(Head, Body) + module_asserta_clause(Head, Body, Module) ). module_assertz_clause(Head, Body, Module) :- @@ -874,13 +877,14 @@ assertz_clause(Head, Body) :- :- meta_predicate assertz(0). -assertz(Clause) :- +assertz(Clause0) :- + loader:strip_module(Clause0, Module, Clause), ( Clause \= (_ :- _) -> Head = Clause, Body = true, - assertz_clause(Head, Body) + module_assertz_clause(Head, Body, Module) ; Clause = (Head :- Body) -> - assertz_clause(Head, Body) + module_assertz_clause(Head, Body, Module) ). diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index f48af1d2..2127ca8a 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -24,10 +24,6 @@ :- use_module(library(lists), [maplist/3]). -:- meta_predicate(call_cleanup(0, 0)). - -:- meta_predicate(setup_call_cleanup(0, 0, 0)). - :- meta_predicate(forall(0, 0)). forall(Generate, Test) :- @@ -56,14 +52,17 @@ bb_get(Key, Value) :- ). -call_cleanup(G, C) :- setup_call_cleanup(true, G, C). +% setup_call_cleanup. +:- meta_predicate(call_cleanup(0, 0)). -% setup_call_cleanup. +call_cleanup(G, C) :- setup_call_cleanup(true, G, C). + +:- meta_predicate(setup_call_cleanup(0, 0, 0)). setup_call_cleanup(S, G, C) :- '$get_b_value'(B), - call(S), + '$call'(S), '$set_cp_by_default'(B), '$get_current_block'(Bb), ( C = _:CC, @@ -72,6 +71,8 @@ setup_call_cleanup(S, G, C) :- ; '$call_with_default_policy'(scc_helper(C, G, Bb)) ). +:- meta_predicate(scc_helper(?,0,?)). + :- non_counted_backtracking scc_helper/3. scc_helper(C, G, Bb) :- '$get_cp'(Cp), @@ -140,11 +141,17 @@ call_with_inference_limit(G, L, R) :- '$call_with_default_policy'(call_with_inference_limit(G, L, R, Bb, B)), '$remove_call_policy_check'(B). +install_inference_counter(B, L, Count0) :- + '$install_inference_counter'(B, L, Count0). + +:- meta_predicate(call_with_inference_limit(0,?,?,?,?)). + :- non_counted_backtracking call_with_inference_limit/5. + call_with_inference_limit(G, L, R, Bb, B) :- '$install_new_block'(NBb), '$install_inference_counter'(B, L, Count0), - call(G), + '$call'(G), '$inference_level'(R, B), '$remove_inference_counter'(B, Count1), '$call_with_default_policy'(is(Diff, L - (Count1 - Count0))), diff --git a/src/loader.pl b/src/loader.pl index 720e534a..d1e86b1a 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -257,8 +257,8 @@ expand_term_goals(Terms0, Terms) :- Terms = (Module:Head2 :- Body1) ; type_error(atom, Module, load/1) ) - ; prolog_load_context(module, Target), - module_expanded_head_variables(Head1, HeadVars), + ; module_expanded_head_variables(Head1, HeadVars), + prolog_load_context(module, Target), expand_goal(Body0, Target, Body1, HeadVars), Terms = (Head1 :- Body1) ) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index dd1f7eab..81bdccfe 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -407,29 +407,29 @@ impl MachineState { } fn term_variables_under_max_depth( - &mut self, - term: HeapCellValue, - max_depth: usize, - list_of_vars: HeapCellValue, + &mut self, + term: HeapCellValue, + max_depth: usize, + list_of_vars: HeapCellValue, ) { - let mut seen_set = IndexSet::new(); + let mut seen_set = IndexSet::new(); - { - let mut iter = stackful_post_order_iter(&mut self.heap, term); + { + let mut iter = stackful_post_order_iter(&mut self.heap, term); while let Some(value) = iter.next() { - if iter.parent_stack_len() >= max_depth { - iter.pop_stack(); - continue; - } + if iter.parent_stack_len() >= max_depth { + iter.pop_stack(); + continue; + } - let value = unmark_cell_bits!(value); + let value = unmark_cell_bits!(value); - if value.is_var() && !seen_set.contains(&value) { - seen_set.insert(value); - } + if value.is_var() && !seen_set.contains(&value) { + seen_set.insert(value); + } } - } + } let outcome = heap_loc_as_cell!( iter_to_heap_list( @@ -2499,17 +2499,17 @@ impl MachineState { &SystemClauseType::HeadIsDynamic => { let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); - let (name, arity) = read_heap_cell!(self.store(self.deref(self.registers[2])), + let (name, arity) = read_heap_cell!(self.store(self.deref(self.registers[2])), (HeapCellValueTag::Str, s) => { - cell_as_atom_cell!(self.heap[s]).get_name_and_arity() - } + cell_as_atom_cell!(self.heap[s]).get_name_and_arity() + } (HeapCellValueTag::Atom, (name, _arity)) => { - (name, 0) - } + (name, 0) + } _ => { - unreachable!() - } - ); + unreachable!() + } + ); self.fail = !indices.is_dynamic_predicate(module_name, (name, arity)); } @@ -2698,13 +2698,13 @@ impl MachineState { &SystemClauseType::EnqueueAttributedVar => { let addr = self.store(self.deref(self.registers[1])); - read_heap_cell!(addr, - (HeapCellValueTag::AttrVar, h) => { - self.attr_var_init.attr_var_queue.push(h); - } - _ => { - } - ); + read_heap_cell!(addr, + (HeapCellValueTag::AttrVar, h) => { + self.attr_var_init.attr_var_queue.push(h); + } + _ => { + } + ); } &SystemClauseType::GetNextDBRef => { let a1 = self.store(self.deref(self.registers[1])); @@ -4384,12 +4384,12 @@ impl MachineState { unify_fn!(self, a2, outcome); } &SystemClauseType::TermVariablesUnderMaxDepth => { - // Term, MaxDepth, VarList - let max_depth = cell_as_fixnum!( - self.store(self.deref(self.registers[2])) - ).get_num() as usize; + // Term, MaxDepth, VarList + let max_depth = cell_as_fixnum!( + self.store(self.deref(self.registers[2])) + ).get_num() as usize; - self.term_variables_under_max_depth(self.registers[1], max_depth, self.registers[3]); + self.term_variables_under_max_depth(self.registers[1], max_depth, self.registers[3]); } &SystemClauseType::TruncateLiftedHeapTo => { let a1 = self.store(self.deref(self.registers[1])); diff --git a/src/tests/call_with_inference_limit.pl b/src/tests/call_with_inference_limit.pl index a1cf2a4e..18fda2dd 100644 --- a/src/tests/call_with_inference_limit.pl +++ b/src/tests/call_with_inference_limit.pl @@ -16,39 +16,40 @@ test_queries_on_call_with_inference_limit :- \+ call_with_inference_limit(g(X), 5, R), maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]), findall([R,X], - call_with_inference_limit(g(X), 10, R), + call_with_inference_limit(g(X), 11, R), [[true, 1], [true, 2], [true, 3], [true, 4], [!, 5]]), findall([R,X], - (call_with_inference_limit(g(X), 10, R), call(true)), + (call_with_inference_limit(g(X), 11, R), call(true)), [[true, 1], [true, 2], [true, 3], [true, 4], [!, 5]]), findall([R,X], - (call_with_inference_limit(g(X), 4, R), call(true)), + (call_with_inference_limit(g(X), 5, R), call(true)), [[true, 1], [true, 2], [inference_limit_exceeded, _]]), findall([X,R1,R2], - (call_with_inference_limit(g(X), 4, R1), - call_with_inference_limit(g(X), 5, R2)), + (call_with_inference_limit(g(X), 5, R1), + call_with_inference_limit(g(X), 6, R2)), [[1,true,!], [2,true,!], [3,true,!], [4,true,!], [5,!,!]]), - \+ \+ assertz((f(X) :- call_with_inference_limit(g(X), 8, _))), + \+ \+ assertz((f(X) :- call_with_inference_limit(tests_on_call_with_inference_limit:g(X), 11, _))), findall([R,X], - call_with_inference_limit(f(X), 12, R), - [[true,1], - [true,2], - [true,3], - [true,4], - [!,5]]). + call_with_inference_limit(f(X), 14, R), + Solutions), + Solutions == [[true,1], + [true,2], + [true,3], + [true,4], + [!,5]]. :- initialization(test_queries_on_call_with_inference_limit). -- cgit v1.2.3-70-g09d2 From 48c1d05151ff9354ef2dd8dedce605371899b100 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 7 Dec 2021 22:26:46 -0700 Subject: use heap_loc to refer to 0-arity atom instead of str_loc --- src/lib/builtins.pl | 2 +- src/machine/machine_state_impl.rs | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index e27a1f43..79b94a51 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -590,7 +590,7 @@ throw(Ball) :- :- non_counted_backtracking '$iterate_find_all'/4. '$iterate_find_all'(Template, Goal, _, LhOffset) :- - call(Goal), + '$call'(Goal), '$copy_to_lh'(LhOffset, Template), '$fail'. '$iterate_find_all'(_, _, Solutions, LhOffset) :- diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index dfaa502e..e408a6e9 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1,7 +1,6 @@ use crate::arena::*; use crate::atom_table::*; use crate::types::*; - use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; @@ -3377,11 +3376,15 @@ impl MachineState { self.heap.push(atom_as_cell!(name, arity)); for i in 0..arity { - self.heap.push(heap_loc_as_cell!(h + i + 1)); - } + self.heap.push(heap_loc_as_cell!(h + i + 1)); + } - str_loc_as_cell!(h) - }; + if arity == 0 { + heap_loc_as_cell!(h) + } else { + str_loc_as_cell!(h) + } + }; (self.bind_fn)(self, r, f_a); } -- cgit v1.2.3-70-g09d2 From 520121b2b2cc21b0fc805a7ea6b5a94fdfc5900f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 8 Dec 2021 23:20:08 -0700 Subject: remove skeletons from replaced modules --- src/lib/builtins.pl | 11 +++++------ src/loader.pl | 2 ++ src/machine/load_state.rs | 39 +++++++++++++++++++++++---------------- src/machine/loader.rs | 15 +++++++++++---- src/machine/system_calls.rs | 2 +- 5 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 79b94a51..f1b2f2d9 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -746,11 +746,11 @@ setof(Template, Goal, Solution) :- ( var(H) -> throw(error(instantiation_error, clause/2)) ; callable(H), functor(H, Name, Arity) -> - ( '$head_is_dynamic'(Module, H) -> + ( '$no_such_predicate'(Module, H) -> + '$fail' + ; '$head_is_dynamic'(Module, H) -> '$clause_body_is_valid'(B), Module:'$clause'(H, B) - ; '$no_such_predicate'(Module, H) -> - '$fail' ; throw(error(permission_error(access, private_procedure, Name/Arity), clause/2)) ) @@ -767,12 +767,11 @@ clause(H, B) :- arg(1, H, Module), arg(2, H, F), '$module_clause'(F, B, Module) + ; '$no_such_predicate'(user, H) -> + '$fail' ; '$head_is_dynamic'(user, H) -> '$clause_body_is_valid'(B), '$clause'(H, B) - ; '$no_such_predicate'(user, H) -> %% '$no_such_predicate' fails if - %% H is not callable. - '$fail' ; throw(error(permission_error(access, private_procedure, Name/Arity), clause/2)) ) diff --git a/src/loader.pl b/src/loader.pl index d1e86b1a..20933268 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -89,6 +89,8 @@ unload_evacuable(Evacuable) :- run_initialization_goals(Module) :- ( predicate_property(Module:'$initialization_goals'(_), dynamic) -> + % FIXME: failing here. also, see add_module. + '$debug_hook', findall(Module:Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals), abolish(Module:'$initialization_goals'/1), ( maplist(Module:call, Goals) -> diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 2b8c0fb5..036c31d7 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -459,7 +459,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } pub(super) fn remove_replaced_in_situ_module(&mut self, module_name: Atom) { - let removed_module = match self.wam_prelude.indices.modules.remove(&module_name) { + let mut removed_module = match self.wam_prelude.indices.modules.remove(&module_name) { Some(module) => module, None => return, }; @@ -467,22 +467,29 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { for (key, code_index) in &removed_module.code_dir { match removed_module .local_extensible_predicates - .get(&(CompilationTarget::User, key.clone())) + .get(&(CompilationTarget::User, *key)) { Some(skeleton) if skeleton.is_multifile => continue, _ => {} } - if code_index.get() != IndexPtr::Undefined { - let old_index_ptr = code_index.replace(IndexPtr::Undefined); + let old_index_ptr = code_index.replace(IndexPtr::Undefined); - self.payload.retraction_info - .push_record(RetractionRecord::ReplacedModulePredicate( - module_name.clone(), - key.clone(), - old_index_ptr, - )); - } + self.payload.retraction_info + .push_record(RetractionRecord::ReplacedModulePredicate( + module_name, + *key, + old_index_ptr, + )); + } + + for (key, skeleton) in removed_module.extensible_predicates.drain(..) { + self.payload.retraction_info + .push_record(RetractionRecord::RemovedSkeleton( + CompilationTarget::Module(module_name), + key, + skeleton, + )); } self.wam_prelude.indices.modules.insert(module_name, removed_module); @@ -861,7 +868,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let mut module = Module::new(module_decl, listing_src); self.import_builtins_in_module( - module_name.clone(), + module_name, &mut module.code_dir, &mut module.op_dir, &mut module.meta_predicates, @@ -904,10 +911,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { module_decl: ModuleDecl, listing_src: &ListingSource, ) { - let module_name = module_decl.name.clone(); + let module_name = module_decl.name; - self.remove_module_exports(module_name.clone()); - self.remove_replaced_in_situ_module(module_name.clone()); + self.remove_module_exports(module_name); + self.remove_replaced_in_situ_module(module_name); match self.wam_prelude.indices.modules.get_mut(&module_name) { Some(module) => { @@ -970,7 +977,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { None => { self.payload .retraction_info - .push_record(RetractionRecord::AddedModule(module_name.clone())); + .push_record(RetractionRecord::AddedModule(module_name)); Module::new(module_decl, listing_src) } diff --git a/src/machine/loader.rs b/src/machine/loader.rs index ba1a5cea..061452ab 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1974,13 +1974,21 @@ impl Machine { loader .wam_prelude .indices - .get_predicate_skeleton_mut(&compilation_target, &key) - .map(|skeleton| skeleton.reset()); + .remove_predicate_skeleton(&compilation_target, &key); let code_index = loader .get_or_insert_code_index(key, compilation_target); - code_index.set(IndexPtr::DynamicUndefined); + code_index.set(IndexPtr::Undefined); + + /* + loader + .wam_prelude + .indices + .get_predicate_skeleton_mut(&compilation_target, &key) + .map(|skeleton| skeleton.reset()); + + */ loader.payload.compilation_target = clause_clause_compilation_target; @@ -2269,7 +2277,6 @@ impl Machine { ClauseType::Named(name, arity, _) => { if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) { self.machine_st.fail = !module.code_dir.contains_key(&(name, arity)); - return; } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 81bdccfe..0720c265 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3365,7 +3365,7 @@ impl MachineState { .unwrap_or(IndexPtr::DynamicUndefined); match index { - IndexPtr::DynamicUndefined => false, + IndexPtr::DynamicUndefined | IndexPtr::Undefined => false, _ => true, } } -- cgit v1.2.3-70-g09d2 From 6c66c236fba768c6b3443a0acb56c49f9312230e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 9 Dec 2021 18:15:52 -0700 Subject: fix printing of CStr's --- src/forms.rs | 7 ------- src/heap_print.rs | 17 +++++++++-------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/forms.rs b/src/forms.rs index 4cda0237..b8042820 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -833,13 +833,6 @@ impl PredicateSkeleton { } } - #[inline] - pub(crate) fn reset(&mut self) { - self.core.clause_clause_locs.clear(); - self.core.clause_assert_margin = 0; - self.clauses.clear(); - } - pub(crate) fn target_pos_of_clause_clause_loc( &self, clause_clause_loc: usize, diff --git a/src/heap_print.rs b/src/heap_print.rs index 7a0c2c5d..9e7e2206 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1125,8 +1125,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { return self.push_list(max_depth); } + // let end_h = heap_pstr_iter.focus(); + // let end_cell = self.iter.heap[end_h]; + let end_h = heap_pstr_iter.focus(); - let end_cell = self.iter.heap[end_h]; + let end_cell = heap_pstr_iter.focus; self.remove_list_children(focus); @@ -1142,8 +1145,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } if self.ignore_ops { - if !self.print_string_as_functor(end_h, max_depth) { - if end_cell.get_tag() == HeapCellValueTag::CStr { + if !self.print_string_as_functor(focus, max_depth) { + if end_cell == empty_list_as_cell!() { // end_cell.get_tag() == HeapCellValueTag::CStr { append_str!(self, "[]"); } else { if self.outputter.ends_with(",") { @@ -1182,21 +1185,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if self.max_depth > 0 && iter.next().is_some() { self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } else { if iter.cycle_detected() { self.iter.heap[end_h].set_forwarding_bit(true); } - if end_cell.get_tag() == HeapCellValueTag::CStr { - self.state_stack.push(TokenOrRedirect::Atom(atom!("[]"))); - } else { + if end_cell != empty_list_as_cell!() { self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.state_stack.push(TokenOrRedirect::HeadTailSeparator); self.iter.push_stack(end_h); } } - self.state_stack.push(TokenOrRedirect::HeadTailSeparator); - if self.outputter.ends_with(",") { self.outputter.truncate(self.outputter.len() - ','.len_utf8()); } -- cgit v1.2.3-70-g09d2 From bcd33dc8e34cd1190a0325a9f6f803743d323eed Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 9 Dec 2021 23:23:03 -0700 Subject: get test suite working --- Cargo.lock | 23 +++++++++++++++++++++++ Cargo.toml | 3 ++- src/arena.rs | 25 ++++++++++++++++--------- src/machine/mock_wam.rs | 4 +--- src/macros.rs | 1 - tests-pl/issue839-op3.pl | 2 +- tests/scryer/issues.rs | 36 ++++++++++++++++++++++++------------ tests/scryer/src_tests.rs | 19 +++++++++++++------ 8 files changed, 80 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2de5d75c..e706052a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1421,6 +1421,7 @@ dependencies = [ "rug", "rustyline", "select", + "serial_test", "sha3", "slice-deque", "smallvec", @@ -1490,6 +1491,28 @@ dependencies = [ "serde", ] +[[package]] +name = "serial_test" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d" +dependencies = [ + "lazy_static", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5" +dependencies = [ + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", +] + [[package]] name = "sha3" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 6d27688a..000c117e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,4 +64,5 @@ slice-deque = "0.3.0" [dev-dependencies] assert_cmd = "1.0.3" -predicates-core = "1.0.2" \ No newline at end of file +predicates-core = "1.0.2" +serial_test = "0.5.1" diff --git a/src/arena.rs b/src/arena.rs index 7fafccb1..d0244fae 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -371,6 +371,8 @@ impl Arena { } unsafe fn drop_slab_in_place(value: &mut AllocSlab) { + use crate::parser::char_reader::CharReader; + match value.header.tag() { ArenaHeaderTag::Integer => { ptr::drop_in_place(value.payload_offset::()); @@ -379,25 +381,25 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) { ptr::drop_in_place(value.payload_offset::()); } ArenaHeaderTag::InputFileStream => { - ptr::drop_in_place(value.payload_offset::()); + ptr::drop_in_place(value.payload_offset::>>()); } ArenaHeaderTag::OutputFileStream => { - ptr::drop_in_place(value.payload_offset::()); + ptr::drop_in_place(value.payload_offset::>()); } ArenaHeaderTag::NamedTcpStream => { - ptr::drop_in_place(value.payload_offset::()); + ptr::drop_in_place(value.payload_offset::>>()); } ArenaHeaderTag::NamedTlsStream => { - ptr::drop_in_place(value.payload_offset::()); + ptr::drop_in_place(value.payload_offset::>>()); } ArenaHeaderTag::ReadlineStream => { - ptr::drop_in_place(value.payload_offset::()); + ptr::drop_in_place(value.payload_offset::>()); } ArenaHeaderTag::StaticStringStream => { - ptr::drop_in_place(value.payload_offset::()); + ptr::drop_in_place(value.payload_offset::>()); } ArenaHeaderTag::ByteStream => { - ptr::drop_in_place(value.payload_offset::()); + ptr::drop_in_place(value.payload_offset::>>()); } ArenaHeaderTag::OssifiedOpDir => { ptr::drop_in_place(value.payload_offset::()); @@ -410,8 +412,13 @@ unsafe fn drop_slab_in_place(value: &mut AllocSlab) { ArenaHeaderTag::TcpListener => { ptr::drop_in_place(value.payload_offset::()); } - ArenaHeaderTag::F64 | ArenaHeaderTag::StandardOutputStream | - ArenaHeaderTag::StandardErrorStream | ArenaHeaderTag::NullStream => { + ArenaHeaderTag::StandardOutputStream => { + ptr::drop_in_place(value.payload_offset::>()); + } + ArenaHeaderTag::StandardErrorStream => { + ptr::drop_in_place(value.payload_offset::>()); + } + ArenaHeaderTag::F64 | ArenaHeaderTag::NullStream => { } } } diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 42d3f600..9524d138 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -315,9 +315,7 @@ impl Machine { ); self.load_file(file.into(), stream); - - let output = self.user_output.bytes().map(|b| b.unwrap()).collect(); - output + self.user_output.bytes().map(|b| b.unwrap()).collect() } } diff --git a/src/macros.rs b/src/macros.rs index 1b459928..b248080d 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -303,7 +303,6 @@ macro_rules! match_untyped_arena_ptr_pat { | ArenaHeaderTag::ReadlineStream | ArenaHeaderTag::StaticStringStream | ArenaHeaderTag::ByteStream - | ArenaHeaderTag::NullStream | ArenaHeaderTag::StandardOutputStream | ArenaHeaderTag::StandardErrorStream }; diff --git a/tests-pl/issue839-op3.pl b/tests-pl/issue839-op3.pl index 3f362cf6..52d36f95 100644 --- a/tests-pl/issue839-op3.pl +++ b/tests-pl/issue839-op3.pl @@ -1 +1 @@ -:- op(900, fy, [$,@]). \ No newline at end of file +:- op(900, fy, [$,@]). diff --git a/tests/scryer/issues.rs b/tests/scryer/issues.rs index 54deae58..9932786c 100644 --- a/tests/scryer/issues.rs +++ b/tests/scryer/issues.rs @@ -8,7 +8,8 @@ fn display_constraints() { X = 1.\n\ use_module(library(dif)).\n\ X = 1.\n\ - dif(X,1).\n", + dif(X,1).\n + halt.\n", " \ X = 1.\n \ true.\n \ @@ -23,9 +24,10 @@ fn display_constraints() { fn do_not_duplicate_path_components() { run_top_level_test_no_args( "\ - ['tests-pl/issue852-throw_e.pl'].\n\ - ['tests-pl/issue852-throw_e.pl'].\n\ - ", + ['tests-pl/issue852-throw_e.pl'].\n\ + ['tests-pl/issue852-throw_e.pl'].\n\ + halt.\n\ + ", "\ caught: e\n\ false.\n\ @@ -50,6 +52,7 @@ fn handle_residual_goal() { set_prolog_flag(occurs_check, true).\n\ -X\\=X.\n\ dif(-X,X).\n\ + halt.\n\ ", " \ true.\n \ @@ -72,8 +75,9 @@ fn occurs_check_flag() { run_top_level_test_with_args( &["tests-pl/issue841-occurs-check.pl"], "\ - f(X, X).\n\ - ", + f(X, X).\n\ + halt.\n\ + ", "false.\n", ) } @@ -86,7 +90,8 @@ fn occurs_check_flag2() { X = -X.\n\ asserta(f(X,g(X))).\n\ f(X,X).\n\ - X-X = X-g(X). + X-X = X-g(X).\n\ + halt.\n\ ", " \ true.\n\ @@ -101,7 +106,7 @@ fn occurs_check_flag2() { // issue #839 #[test] fn op3() { - run_top_level_test_with_args(&["tests-pl/issue839-op3.pl"], "", "") + run_top_level_test_with_args(&["tests-pl/issue839-op3.pl", "-g", "halt"], "", "") } // issue #820 @@ -127,27 +132,34 @@ fn compound_goal() { // issue #815 #[test] fn no_stutter() { - run_top_level_test_no_args("write(a), write(b), false.\n", "abfalse.\n") + run_top_level_test_no_args("write(a), write(b), false.\n\ + halt.\n\ + ", + "abfalse.\n") } +/* // issue #812 #[test] // FIXME: the line number is of by one (should be 4), empty line not accounted for or starting to count at line 0? fn singleton_warning() { run_top_level_test_no_args( - "['tests-pl/issue812-singleton-warning.pl'].", + "['tests-pl/issue812-singleton-warning.pl'].\ + halt.\n", "\ Warning: singleton variables X at line 3 of issue812-singleton-warning.pl\n \ true.\n\ ", ); } + */ // issue #807 #[test] fn ignored_constraint() { run_top_level_test_no_args( - "use_module(library(freeze)), freeze(X,false), X \\=a.", - " freeze:freeze(X,user:false).\n", + "use_module(library(freeze)), freeze(X,false), X \\=a.\n\ + halt.", + " freeze:freeze(X,false).\n", ); } diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index 51caf4a8..1730f0cd 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -1,25 +1,31 @@ use crate::helper::{load_module_test, run_top_level_test_with_args}; +use serial_test::serial; +#[serial] #[test] fn builtins() { load_module_test("src/tests/builtins.pl", ""); } +#[serial] #[test] fn call_with_inference_limit() { load_module_test("src/tests/call_with_inference_limit.pl", ""); } +#[serial] #[test] fn facts() { load_module_test("src/tests/facts.pl", ""); } +#[serial] #[test] fn hello_world() { load_module_test("src/tests/hello_world.pl", "Hello World!\n"); } +#[serial] #[test] fn syntax_error() { load_module_test( @@ -28,36 +34,37 @@ fn syntax_error() { ); } +#[serial] #[test] -#[ignore] // fails to halt fn predicates() { load_module_test("src/tests/predicates.pl", ""); } +#[serial] #[test] fn rules() { load_module_test("src/tests/rules.pl", ""); } +#[serial] #[test] -#[ignore] fn setup_call_cleanup_load() { load_module_test( "src/tests/setup_call_cleanup.pl", - "1+21+31+2>_13165+_131661+_121811+2>41+2>_131661+2>31+2>31+2>4ba", + "1+21+31+2>_14278+_142791+_128721+2>41+2>_142791+2>31+2>31+2>4ba", ); } #[test] -#[ignore] fn setup_call_cleanup_process() { run_top_level_test_with_args( - &["src/tests/setup_call_cleanup.pl"], + &["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"], "", - "1+21+31+2>_14108+_141091+_131241+2>41+2>_141091+2>31+2>31+2>4ba", + "1+21+31+2>_15677+_156781+_142711+2>41+2>_156781+2>31+2>31+2>4ba", ); } +#[serial] #[test] fn clpz_load() { load_module_test("src/tests/clpz/test_clpz.pl", ""); -- cgit v1.2.3-70-g09d2 From b24df6e195a6c21f99485842aa6d0a3d5f1d96c0 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 10 Dec 2021 10:10:00 -0700 Subject: properly iterate over read terms in MachineState::read_term --- src/machine/machine_state.rs | 3 ++- tests/scryer/issues.rs | 4 ++-- tests/scryer/src_tests.rs | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 1ca0a784..b09d0503 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -966,8 +966,9 @@ impl MachineState { loop { match self.read(stream, &indices.op_dir) { Ok(term_write_result) => { - let term = self.store(self.deref(self.registers[2])); + let term = self.registers[2]; unify_fn!(self, heap_loc_as_cell!(term_write_result.heap_loc), term); + let term = heap_loc_as_cell!(term_write_result.heap_loc); if self.fail { return Ok(()); diff --git a/tests/scryer/issues.rs b/tests/scryer/issues.rs index 9932786c..bae95d73 100644 --- a/tests/scryer/issues.rs +++ b/tests/scryer/issues.rs @@ -143,7 +143,7 @@ fn no_stutter() { #[test] // FIXME: the line number is of by one (should be 4), empty line not accounted for or starting to count at line 0? fn singleton_warning() { run_top_level_test_no_args( - "['tests-pl/issue812-singleton-warning.pl'].\ + "['tests-pl/issue812-singleton-warning.pl'].\n\ halt.\n", "\ Warning: singleton variables X at line 3 of issue812-singleton-warning.pl\n \ @@ -151,7 +151,7 @@ fn singleton_warning() { ", ); } - */ +*/ // issue #807 #[test] diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index 1730f0cd..883d787a 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -51,7 +51,7 @@ fn rules() { fn setup_call_cleanup_load() { load_module_test( "src/tests/setup_call_cleanup.pl", - "1+21+31+2>_14278+_142791+_128721+2>41+2>_142791+2>31+2>31+2>4ba", + "1+21+31+2>_14304+_143051+_128981+2>41+2>_143051+2>31+2>31+2>4ba", ); } @@ -60,7 +60,7 @@ fn setup_call_cleanup_process() { run_top_level_test_with_args( &["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"], "", - "1+21+31+2>_15677+_156781+_142711+2>41+2>_156781+2>31+2>31+2>4ba", + "1+21+31+2>_15703+_157041+_142971+2>41+2>_157041+2>31+2>31+2>4ba", ); } -- cgit v1.2.3-70-g09d2 From 3974b6e6cd3c38e108b8ce8678828622fc7c44c4 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 10 Dec 2021 17:16:15 -0700 Subject: dereference variables when looking for string terminators --- src/types.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/types.rs b/src/types.rs index 16805981..b4278f41 100644 --- a/src/types.rs +++ b/src/types.rs @@ -344,6 +344,8 @@ impl HeapCellValue { #[inline] pub fn is_string_terminator(mut self, heap: &[HeapCellValue]) -> bool { + use crate::machine::heap::*; + loop { return read_heap_cell!(self, (HeapCellValueTag::Atom, (name, arity)) => { @@ -356,6 +358,16 @@ impl HeapCellValue { self = heap[h]; continue; } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[h])); + + if cell.is_var() { + return false; + } + + self = cell; + continue; + } (HeapCellValueTag::PStrOffset, pstr_offset) => { heap[pstr_offset].get_tag() == HeapCellValueTag::CStr } -- cgit v1.2.3-70-g09d2 From 4211151fe6560ea3979d038fdf41ee97707f4425 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 11 Dec 2021 16:29:26 -0700 Subject: fix unify_float --- src/machine/machine_state_impl.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index e408a6e9..4f42756e 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -667,9 +667,17 @@ impl MachineState { read_heap_cell!(value, (HeapCellValueTag::F64, f2) => { - if *f1 != *f2 { - self.fail = true; - } + self.fail = **f1 != **f2; + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::F64, f2) => { + self.fail = **f1 != **F64Ptr(f2); + } + _ => { + self.fail = true; + } + ); } _ => { self.fail = true; -- cgit v1.2.3-70-g09d2 From 39efc12dc86502bfa0563c605e5dcaf0936b6d68 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 11 Dec 2021 21:51:45 -0700 Subject: generate heap_loc cells to refer to 0-arity atoms in read.rs --- src/read.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/read.rs b/src/read.rs index b4c4dbcc..eced1d72 100644 --- a/src/read.rs +++ b/src/read.rs @@ -292,6 +292,7 @@ impl<'a, 'b> TermWriter<'a, 'b> { }, &TermRef::PartialString(..) => pstr_loc_as_cell!(h), &TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal), + &TermRef::Clause(_,_,_,subterms) if subterms.len() == 0 => heap_loc_as_cell!(h), &TermRef::Clause(..) => str_loc_as_cell!(h), } } @@ -319,7 +320,11 @@ impl<'a, 'b> TermWriter<'a, 'b> { self.push_stub_addr(); } &TermRef::Clause(Level::Root, _, ref ct, subterms) => { - self.heap.push(str_loc_as_cell!(heap_loc + 1)); + self.heap.push(if subterms.len() == 0 { + heap_loc_as_cell!(heap_loc + 1) + } else { + str_loc_as_cell!(heap_loc + 1) + }); self.queue.push_back((subterms.len(), h + 2)); let named = atom_as_cell!(ct.name(), subterms.len()); -- cgit v1.2.3-70-g09d2 From 708c3bc3ce6d2498d0f2797bfd3f9c0412123d44 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 11 Dec 2021 23:36:19 -0700 Subject: dereference first argument of (is)/2 --- src/machine/machine_state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index b09d0503..58336338 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -597,7 +597,7 @@ pub trait CallPolicy: Any + fmt::Debug { return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Is(r, ref at) => { - let n1 = machine_st[r]; + let n1 = machine_st.store(machine_st.deref(machine_st[r])); let n2 = machine_st.get_number(at)?; match n2 { -- cgit v1.2.3-70-g09d2 From b056d40eba4ee1458c54f4d3bb2ca726e0b3e2cb Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 12 Dec 2021 10:58:42 -0700 Subject: module-qualify incomplete goals in expand_goal/3 --- src/examples/least_time.pl | 6 ------ src/heap_iter.rs | 2 +- src/heap_print.rs | 5 +---- src/loader.pl | 1 + 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/examples/least_time.pl b/src/examples/least_time.pl index b93f0b5e..06eccd31 100644 --- a/src/examples/least_time.pl +++ b/src/examples/least_time.pl @@ -20,12 +20,6 @@ :- use_module(library(reif)). -permutation([], []). -permutation([X|Xs], Ys) :- - permutation(Xs, Yss), - select(X, Ys, Yss). - - valid_time([H1,H2,M1,M2], T) :- memberd_t(H1, [0,1,2], TH1), memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2), diff --git a/src/heap_iter.rs b/src/heap_iter.rs index df211339..c88ad721 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -439,7 +439,7 @@ mod tests { ] )); - for _ in 0..2 { //00000 { + for _ in 0..200000 { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, heap_loc_as_cell!(0)); assert_eq!( diff --git a/src/heap_print.rs b/src/heap_print.rs index 9e7e2206..6f320839 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1125,9 +1125,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { return self.push_list(max_depth); } - // let end_h = heap_pstr_iter.focus(); - // let end_cell = self.iter.heap[end_h]; - let end_h = heap_pstr_iter.focus(); let end_cell = heap_pstr_iter.focus; @@ -1146,7 +1143,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if self.ignore_ops { if !self.print_string_as_functor(focus, max_depth) { - if end_cell == empty_list_as_cell!() { // end_cell.get_tag() == HeapCellValueTag::CStr { + if end_cell == empty_list_as_cell!() { append_str!(self, "[]"); } else { if self.outputter.ends_with(",") { diff --git a/src/loader.pl b/src/loader.pl index 20933268..a9e8f8d7 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -643,6 +643,7 @@ expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars MS >= 0 ) -> ( var(SG), + MS =:= 0, pairs:same_key(SG, HeadVars, [_|_], _) -> expand_subgoal(SG, MS, M, ESG, HeadVars) ; expand_subgoal(SG, MS, M, ESG0, HeadVars), -- cgit v1.2.3-70-g09d2 From 6f9b6a29c487fa1095a418f2501c5e1733f49c02 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 15 Dec 2021 23:41:00 -0700 Subject: remove LocalCodePtr::IndexingBuf --- src/machine/code_repo.rs | 117 ++++++++++++++---------------- src/machine/machine_indices.rs | 56 +++++++------- src/machine/machine_state.rs | 149 ++++++++++++++++++-------------------- src/machine/machine_state_impl.rs | 100 ++++++++++++++++--------- src/machine/mod.rs | 17 +++-- src/machine/stack.rs | 2 + src/machine/system_calls.rs | 6 +- src/write.rs | 6 +- 8 files changed, 235 insertions(+), 218 deletions(-) diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs index 54db570f..ba046228 100644 --- a/src/machine/code_repo.rs +++ b/src/machine/code_repo.rs @@ -1,53 +1,19 @@ use crate::clause_types::*; use crate::instructions::*; +use crate::machine::MachineState; use crate::machine::machine_indices::*; +// TODO: remove this, replace with just 'Code'. #[derive(Debug)] pub struct CodeRepo { pub(super) code: Code, } impl CodeRepo { - #[inline] - pub(super) fn new() -> Self { - CodeRepo { code: Code::new() } - } - - #[inline] - pub(super) fn lookup_local_instr<'a>(&'a self, p: LocalCodePtr) -> RefOrOwned<'a, Line> { - match p { - LocalCodePtr::Halt => { - // exit with the interrupt exit code. - std::process::exit(1); - } - LocalCodePtr::DirEntry(p) => RefOrOwned::Borrowed(&self.code[p as usize]), - LocalCodePtr::IndexingBuf(p, o, i) => match &self.code[p] { - &Line::IndexingCode(ref indexing_lines) => match &indexing_lines[o] { - &IndexingLine::IndexedChoice(ref indexed_choice_instrs) => { - RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[i])) - } - &IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => { - RefOrOwned::Owned(Line::DynamicIndexedChoice(indexed_choice_instrs[i])) - } - _ => { - unreachable!() - } - }, - _ => { - unreachable!() - } - }, - } - } - - pub(super) fn lookup_instr<'a>( - &'a self, - last_call: bool, - p: &CodePtr, - ) -> Option> { + pub(super) fn lookup_instr<'a>(&'a self, machine_st: &MachineState, p: &CodePtr) -> Option> { match p { &CodePtr::Local(local) => { - return Some(self.lookup_local_instr(local)); + return Some(self.lookup_local_instr(machine_st, local)); } &CodePtr::REPL(..) => None, &CodePtr::BuiltInClause(ref built_in, _) => { @@ -55,33 +21,56 @@ impl CodeRepo { ClauseType::BuiltIn(built_in.clone()), built_in.arity(), 0, - last_call + machine_st.last_call ); Some(RefOrOwned::Owned(call_clause)) } &CodePtr::CallN(arity, _, last_call) => { let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call); - Some(RefOrOwned::Owned(call_clause)) } &CodePtr::VerifyAttrInterrupt(p) => Some(RefOrOwned::Borrowed(&self.code[p])), } } - pub(super) fn find_living_dynamic_else( - &self, - mut p: usize, - cc: usize, - ) -> Option<(usize, usize)> { + #[inline] + pub(super) fn lookup_local_instr<'a>(&'a self, machine_st: &MachineState, p: LocalCodePtr) -> RefOrOwned<'a, Line> { + match p { + LocalCodePtr::Halt => { + // exit with the interrupt exit code. + std::process::exit(1); + } + LocalCodePtr::DirEntry(p) => match &self.code[p] { + &Line::IndexingCode(ref indexing_lines) => { + match &indexing_lines[machine_st.oip as usize] { + &IndexingLine::IndexedChoice(ref indexed_choice_instrs) => { + RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[machine_st.iip as usize])) + } + &IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => { + RefOrOwned::Owned(Line::DynamicIndexedChoice(indexed_choice_instrs[machine_st.iip as usize])) + } + _ => { + RefOrOwned::Borrowed(&self.code[p as usize]) + } + } + } + _ => RefOrOwned::Borrowed(&self.code[p as usize]), + } + } + } +} + +impl MachineState { + pub(super) fn find_living_dynamic_else(&self, code: &Code, mut p: usize) -> Option<(usize, usize)> { loop { - match &self.code[p] { + match &code[p] { &Line::Choice(ChoiceInstruction::DynamicElse( birth, death, NextOrFail::Next(i), )) => { - if birth < cc && Death::Finite(cc) <= death { + if birth < self.cc && Death::Finite(self.cc) <= death { return Some((p, i)); } else if i > 0 { p += i; @@ -94,7 +83,7 @@ impl CodeRepo { death, NextOrFail::Fail(_), )) => { - if birth < cc && Death::Finite(cc) <= death { + if birth < self.cc && Death::Finite(self.cc) <= death { return Some((p, 0)); } else { return None; @@ -105,7 +94,7 @@ impl CodeRepo { death, NextOrFail::Next(i), )) => { - if birth < cc && Death::Finite(cc) <= death { + if birth < self.cc && Death::Finite(self.cc) <= death { return Some((p, i)); } else if i > 0 { p += i; @@ -118,7 +107,7 @@ impl CodeRepo { death, NextOrFail::Fail(_), )) => { - if birth < cc && Death::Finite(cc) <= death { + if birth < self.cc && Death::Finite(self.cc) <= death { return Some((p, 0)); } else { return None; @@ -134,18 +123,11 @@ impl CodeRepo { } } - pub(super) fn find_living_dynamic( - &self, - p: LocalCodePtr, - cc: usize, - ) -> Option<(usize, usize, usize, bool)> { - let (p, oi, mut ii) = match p { - LocalCodePtr::IndexingBuf(p, oi, ii) => (p, oi, ii), - _ => unreachable!(), - }; + pub(super) fn find_living_dynamic(&self, code: &Code, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> { + let p = self.p.local().abs_loc(); - let indexed_choice_instrs = match &self.code[p] { - Line::IndexingCode(ref indexing_code) => match &indexing_code[oi] { + let indexed_choice_instrs = match &code[p] { + Line::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] { IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => { indexed_choice_instrs } @@ -155,14 +137,14 @@ impl CodeRepo { }; loop { - match &indexed_choice_instrs.get(ii) { - Some(&offset) => match &self.code[p + offset - 1] { + match &indexed_choice_instrs.get(ii as usize) { + Some(&offset) => match &code[p + offset - 1] { &Line::Choice(ChoiceInstruction::DynamicInternalElse( birth, death, next_or_fail, )) => { - if birth < cc && Death::Finite(cc) <= death { + if birth < self.cc && Death::Finite(self.cc) <= death { return Some((offset, oi, ii, next_or_fail.is_next())); } else { ii += 1; @@ -175,3 +157,10 @@ impl CodeRepo { } } } + +impl CodeRepo { + #[inline] + pub(super) fn new() -> Self { + CodeRepo { code: Code::new() } + } +} diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 361b084e..e7cda22d 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -322,8 +322,26 @@ impl CodePtr { pub enum LocalCodePtr { DirEntry(usize), // offset Halt, - IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset - // TopLevel(usize, usize), // chunk_num, offset + // IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset + // TopLevel(usize, usize), // chunk_num, offset +} + +impl MachineState { + pub(crate) fn is_reset_cont_marker(&self, code_repo: &CodeRepo, p: LocalCodePtr) -> bool { + match code_repo.lookup_instr(self, &CodePtr::Local(p)) { + Some(line) => match line.as_ref() { + Line::Control(ControlInstruction::CallClause(ref ct, ..)) => { + if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct { + return true; + } + } + _ => {} + }, + None => {} + } + + false + } } impl LocalCodePtr { @@ -338,27 +356,11 @@ impl LocalCodePtr { pub fn abs_loc(&self) -> usize { match self { LocalCodePtr::DirEntry(ref p) => *p, - LocalCodePtr::IndexingBuf(ref p, ..) => *p, + // LocalCodePtr::IndexingBuf(ref p, ..) => *p, LocalCodePtr::Halt => unreachable!(), } } - pub(crate) fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool { - match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) { - Some(line) => match line.as_ref() { - Line::Control(ControlInstruction::CallClause(ref ct, ..)) => { - if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct { - return true; - } - } - _ => {} - }, - None => {} - } - - false - } - pub(crate) fn as_functor(&self) -> MachineStub { match self { LocalCodePtr::DirEntry(p) => { @@ -367,12 +369,14 @@ impl LocalCodePtr { LocalCodePtr::Halt => { functor!(atom!("halt")) } + /* LocalCodePtr::IndexingBuf(p, o, i) => { functor!( atom!("indexed_buf"), [fixnum(*p), fixnum(*o), fixnum(*i)] ) } + */ } } } @@ -399,7 +403,7 @@ impl Add for LocalCodePtr { match self { LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs), LocalCodePtr::Halt => unreachable!(), - LocalCodePtr::IndexingBuf(p, o, i) => LocalCodePtr::IndexingBuf(p, o, i + rhs), + // LocalCodePtr::IndexingBuf(p, o, i) => LocalCodePtr::IndexingBuf(p, o, i + rhs), } } } @@ -412,9 +416,9 @@ impl Sub for LocalCodePtr { match self { LocalCodePtr::DirEntry(p) => p.checked_sub(rhs).map(LocalCodePtr::DirEntry), LocalCodePtr::Halt => unreachable!(), - LocalCodePtr::IndexingBuf(p, o, i) => i - .checked_sub(rhs) - .map(|r| LocalCodePtr::IndexingBuf(p, o, r)), + // LocalCodePtr::IndexingBuf(p, o, i) => i + // .checked_sub(rhs) + // .map(|r| LocalCodePtr::IndexingBuf(p, o, r)), } } } @@ -424,7 +428,7 @@ impl SubAssign for LocalCodePtr { fn sub_assign(&mut self, rhs: usize) { match self { LocalCodePtr::DirEntry(ref mut p) => *p -= rhs, - LocalCodePtr::Halt | LocalCodePtr::IndexingBuf(..) => unreachable!(), + LocalCodePtr::Halt => unreachable!() // | LocalCodePtr::IndexingBuf(..) => unreachable!(), } } } @@ -433,8 +437,8 @@ impl AddAssign for LocalCodePtr { #[inline] fn add_assign(&mut self, rhs: usize) { match self { - &mut LocalCodePtr::DirEntry(ref mut i) - | &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs, + &mut LocalCodePtr::DirEntry(ref mut i) => *i += rhs, + // | &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs, &mut LocalCodePtr::Halt => unreachable!(), } } diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 58336338..68330be7 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -63,6 +63,8 @@ pub struct MachineState { pub(super) pdl: Vec, pub(super) s: HeapPtr, pub(super) p: CodePtr, + pub(super) oip: u32, // first internal code ptr + pub(super) iip : u32, // second internal code ptr pub(super) b: usize, pub(super) b0: usize, pub(super) e: usize, @@ -81,7 +83,7 @@ pub struct MachineState { pub(super) ball: Ball, pub(super) lifted_heap: Heap, pub(super) interms: Vec, // intermediate numbers. - pub(super) last_call: bool, + pub(super) last_call: bool, // TODO: REMOVE THIS. pub(crate) flags: MachineFlags, pub(crate) cc: usize, pub(crate) global_clock: usize, @@ -191,38 +193,34 @@ pub trait CallPolicy: Any + fmt::Debug { global_variables: &mut GlobalVarDir, ) -> CallResult { let b = machine_st.b; - let n = machine_st - .stack - .index_or_frame(b) - .prelude - .univ_prelude - .num_cells; - - for i in 1..n + 1 { - machine_st.registers[i] = machine_st.stack[stack_loc!(OrFrame, b, i - 1)]; + let or_frame = machine_st.stack.index_or_frame_mut(b); + let n = or_frame.prelude.univ_prelude.num_cells; + + for i in 0..n { + machine_st.registers[i + 1] = or_frame[i]; } machine_st.num_of_args = n; - machine_st.e = machine_st.stack.index_or_frame(b).prelude.e; - machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp; + machine_st.e = or_frame.prelude.e; + machine_st.cp = or_frame.prelude.cp; - machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + offset; + or_frame.prelude.bp = machine_st.p.local() + offset; - let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; + let old_tr = or_frame.prelude.tr; let curr_tr = machine_st.tr; + let target_h = or_frame.prelude.h; - machine_st.unwind_trail(old_tr, curr_tr, global_variables); - machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; - - machine_st.trail.truncate(machine_st.tr); - machine_st - .heap - .truncate(machine_st.stack.index_or_frame(b).prelude.h); + machine_st.tr = or_frame.prelude.tr; machine_st.attr_var_init.reset(); machine_st.hb = machine_st.heap.len(); machine_st.p += 1; + machine_st.unwind_trail(old_tr, curr_tr, global_variables); + + machine_st.trail.truncate(machine_st.tr); + machine_st.heap.truncate(target_h); + Ok(()) } @@ -233,38 +231,38 @@ pub trait CallPolicy: Any + fmt::Debug { global_variables: &mut GlobalVarDir, ) -> CallResult { let b = machine_st.b; - let n = machine_st - .stack - .index_or_frame(b) - .prelude - .univ_prelude - .num_cells; - - for i in 1..n + 1 { - machine_st.registers[i] = machine_st.stack.index_or_frame(b)[i - 1]; + let or_frame = machine_st.stack.index_or_frame_mut(b); + let n = or_frame.prelude.univ_prelude.num_cells; + + for i in 0..n { + machine_st.registers[i+1] = or_frame[i]; } machine_st.num_of_args = n; - machine_st.e = machine_st.stack.index_or_frame(b).prelude.e; - machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp; + machine_st.e = or_frame.prelude.e; + machine_st.cp = or_frame.prelude.cp; - machine_st.stack.index_or_frame_mut(b).prelude.bp = machine_st.p.local() + 1; + // WAS: or_frame.prelude.bp = machine_st.p.local() + 1; + or_frame.prelude.biip += 1; - let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; + let old_tr = or_frame.prelude.tr; let curr_tr = machine_st.tr; + let target_h = or_frame.prelude.h; + + machine_st.tr = or_frame.prelude.tr; + machine_st.attr_var_init.reset(); machine_st.unwind_trail(old_tr, curr_tr, global_variables); - machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; machine_st.trail.truncate(machine_st.tr); - machine_st - .heap - .truncate(machine_st.stack.index_or_frame(b).prelude.h); + machine_st.heap.truncate(target_h); - machine_st.attr_var_init.reset(); machine_st.hb = machine_st.heap.len(); machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); + machine_st.oip = 0; + machine_st.iip = 0; + Ok(()) } @@ -275,39 +273,38 @@ pub trait CallPolicy: Any + fmt::Debug { global_variables: &mut GlobalVarDir, ) -> CallResult { let b = machine_st.b; - let n = machine_st - .stack - .index_or_frame(b) - .prelude - .univ_prelude - .num_cells; - - for i in 1..n + 1 { - machine_st.registers[i] = machine_st.stack[stack_loc!(OrFrame, b, i - 1)]; + let or_frame = machine_st.stack.index_or_frame(b); + let n = or_frame.prelude.univ_prelude.num_cells; + + for i in 0..n { + machine_st.registers[i+1] = or_frame[i]; } machine_st.num_of_args = n; - machine_st.e = machine_st.stack.index_or_frame(b).prelude.e; - machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp; + machine_st.e = or_frame.prelude.e; + machine_st.cp = or_frame.prelude.cp; - let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; + let old_tr = or_frame.prelude.tr; let curr_tr = machine_st.tr; + let target_h = or_frame.prelude.h; + + machine_st.tr = or_frame.prelude.tr; + + machine_st.attr_var_init.reset(); + machine_st.b = or_frame.prelude.b; machine_st.unwind_trail(old_tr, curr_tr, global_variables); - machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; machine_st.trail.truncate(machine_st.tr); - machine_st - .heap - .truncate(machine_st.stack.index_or_frame(b).prelude.h); - - machine_st.attr_var_init.reset(); - machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.stack.truncate(b); + machine_st.heap.truncate(target_h); machine_st.hb = machine_st.heap.len(); machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); + machine_st.oip = 0; + machine_st.iip = 0; + Ok(()) } @@ -317,35 +314,31 @@ pub trait CallPolicy: Any + fmt::Debug { global_variables: &mut GlobalVarDir, ) -> CallResult { let b = machine_st.b; - let n = machine_st - .stack - .index_or_frame(b) - .prelude - .univ_prelude - .num_cells; - - for i in 1..n + 1 { - machine_st.registers[i] = machine_st.stack[stack_loc!(OrFrame, b, i - 1)]; + let or_frame = machine_st.stack.index_or_frame(b); + let n = or_frame.prelude.univ_prelude.num_cells; + + for i in 0..n { + machine_st.registers[i+1] = or_frame[i]; } machine_st.num_of_args = n; - machine_st.e = machine_st.stack.index_or_frame(b).prelude.e; - machine_st.cp = machine_st.stack.index_or_frame(b).prelude.cp; + machine_st.e = or_frame.prelude.e; + machine_st.cp = or_frame.prelude.cp; - let old_tr = machine_st.stack.index_or_frame(b).prelude.tr; + let old_tr = or_frame.prelude.tr; let curr_tr = machine_st.tr; + let target_h = or_frame.prelude.h; + + machine_st.tr = or_frame.prelude.tr; + + machine_st.attr_var_init.reset(); + machine_st.b = or_frame.prelude.b; machine_st.unwind_trail(old_tr, curr_tr, global_variables); - machine_st.tr = machine_st.stack.index_or_frame(b).prelude.tr; machine_st.trail.truncate(machine_st.tr); - machine_st - .heap - .truncate(machine_st.stack.index_or_frame(b).prelude.h); - - machine_st.attr_var_init.reset(); - machine_st.b = machine_st.stack.index_or_frame(b).prelude.b; machine_st.stack.truncate(b); + machine_st.heap.truncate(target_h); machine_st.hb = machine_st.heap.len(); machine_st.p += 1; @@ -754,7 +747,6 @@ impl<'a> IndexMut for CopyTerm<'a> { } } -// the ordinary, heap term copier, used by duplicate_term. impl<'a> CopierTarget for CopyTerm<'a> { #[inline(always)] fn threshold(&self) -> usize { @@ -827,7 +819,6 @@ impl<'a> IndexMut for CopyBallTerm<'a> { } } -// the ordinary, heap term copier, used by duplicate_term. impl<'a> CopierTarget for CopyBallTerm<'a> { fn threshold(&self) -> usize { self.heap_boundary + self.stub.len() diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 4f42756e..1c6922d5 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -37,6 +37,8 @@ impl MachineState { pdl: Vec::with_capacity(1024), s: HeapPtr::default(), p: CodePtr::default(), + oip: 0, + iip: 0, b: 0, b0: 0, e: 0, @@ -1905,8 +1907,8 @@ impl MachineState { None => unreachable!(), } } - TrailEntryTag::TrailedAttachedValue => { - } + TrailEntryTag::TrailedAttachedValue => { + } } } } @@ -2758,7 +2760,9 @@ impl MachineState { } &IndexingLine::IndexedChoice(_) => { if let LocalCodePtr::DirEntry(p) = self.p.local() { - self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0)); + self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + self.oip = index as u32; + self.iip = 0; } else { unreachable!() } @@ -2769,7 +2773,9 @@ impl MachineState { self.dynamic_mode = FirstOrNext::First; if let LocalCodePtr::DirEntry(p) = self.p.local() { - self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0)); + self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + self.oip = index as u32; + self.iip = 0; } else { unreachable!() } @@ -3886,9 +3892,11 @@ impl MachineState { ) { let p = self.p.local(); - match code_repo.find_living_dynamic(p, self.cc) { + match self.find_living_dynamic(&code_repo.code, self.oip, self.iip) { Some((offset, oi, ii, is_next_clause)) => { - self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii)); + self.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc())); + self.oip = oi; + self.iip = ii; match self.dynamic_mode { FirstOrNext::First if !is_next_clause => { @@ -3898,14 +3906,15 @@ impl MachineState { // there's a leading DynamicElse that sets self.cc. // self.cc = self.global_clock; - match code_repo.find_living_dynamic( - LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii + 1), - self.cc, - ) { + // see that there is a following dynamic_else + // clause so we avoid generating a choice + // point in case there isn't. + match self.find_living_dynamic(&code_repo.code, oi, ii + 1) { Some(_) => { self.registers[self.num_of_args + 1] = fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); - self.num_of_args += 1; + + self.num_of_args += 2; self.execute_indexed_choice_instr( &IndexedChoiceInstruction::Try(offset), @@ -3913,39 +3922,39 @@ impl MachineState { global_variables, ); - self.num_of_args -= 1; + self.num_of_args -= 2; } None => { - self.p = - CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset)); + self.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset)); + self.oip = 0; + self.iip = 0; } } } FirstOrNext::Next => { + let b = self.b; let n = self .stack - .index_or_frame(self.b) + .index_or_frame(b) .prelude .univ_prelude .num_cells; - self.cc = cell_as_fixnum!(self.stack[n - 1]).get_num() as usize; + self.cc = cell_as_fixnum!(self.stack[stack_loc!(OrFrame, b, n-2)]) + .get_num() as usize; if is_next_clause { - match code_repo.find_living_dynamic( - LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii + 1), - self.cc, - ) { + match self.find_living_dynamic(&code_repo.code, self.oip, self.iip) { Some(_) => { try_or_fail!( self, - call_policy.retry(self, offset, global_variables,) - ) + call_policy.retry(self, offset, global_variables) + ); } None => { try_or_fail!( self, - call_policy.trust(self, offset, global_variables,) + call_policy.trust(self, offset, global_variables) ) } } @@ -3979,19 +3988,36 @@ impl MachineState { or_frame.prelude.e = self.e; or_frame.prelude.cp = self.cp; or_frame.prelude.b = self.b; - or_frame.prelude.bp = self.p.local() + 1; + or_frame.prelude.bp = self.p.local(); // + 1; in self.iip now! + or_frame.prelude.boip = self.oip; + or_frame.prelude.biip = self.iip + 1; or_frame.prelude.tr = self.tr; or_frame.prelude.h = self.heap.len(); or_frame.prelude.b0 = self.b0; self.b = b; - for i in 1..n + 1 { - self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i]; + for i in 0..n { + or_frame[i] = self.registers[i+1]; } + /* + self.iip += 1; + + let oip_b = self.oip.to_ne_bytes(); + let iip_b = self.iip.to_ne_bytes(); + + or_frame[n] = HeapCellValue::from_bytes( + [oip_b[0], oip_b[1], oip_b[2], oip_b[3], + iip_b[0], iip_b[1], iip_b[2], iip_b[3]], + ); + */ + self.hb = self.heap.len(); self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset)); + + self.oip = 0; + self.iip = 0; } &IndexedChoiceInstruction::Retry(l) => { try_or_fail!(self, call_policy.retry(self, l, global_variables)); @@ -4017,7 +4043,7 @@ impl MachineState { let p = self.p.local().abs_loc(); - match code_repo.find_living_dynamic_else(p, self.cc) { + match self.find_living_dynamic_else(&code_repo.code, p) { Some((p, next_i)) => { self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); @@ -4028,7 +4054,7 @@ impl MachineState { FirstOrNext::First => { self.cc = self.global_clock; - match code_repo.find_living_dynamic_else(p + next_i, self.cc) { + match self.find_living_dynamic_else(&code_repo.code, p + next_i) { Some(_) => { self.registers[self.num_of_args + 1] = fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); @@ -4056,11 +4082,11 @@ impl MachineState { .univ_prelude .num_cells; - self.cc = cell_as_fixnum!(self.stack.index_or_frame(self.b)[n - 1]) + self.cc = cell_as_fixnum!(self.stack[stack_loc!(OrFrame, self.b, n-1)]) .get_num() as usize; if next_i > 0 { - match code_repo.find_living_dynamic_else(p + next_i, self.cc) { + match self.find_living_dynamic_else(&code_repo.code, p + next_i) { Some(_) => { try_or_fail!( self, @@ -4094,7 +4120,7 @@ impl MachineState { &ChoiceInstruction::DynamicInternalElse(..) => { let p = self.p.local().abs_loc(); - match code_repo.find_living_dynamic_else(p, self.cc) { + match self.find_living_dynamic_else(&code_repo.code, p) { Some((p, next_i)) => { self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); @@ -4103,7 +4129,7 @@ impl MachineState { self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1)); } FirstOrNext::First => { - match code_repo.find_living_dynamic_else(p + next_i, self.cc) { + match self.find_living_dynamic_else(&code_repo.code, p + next_i) { Some(_) => { self.registers[self.num_of_args + 1] = fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); @@ -4131,11 +4157,11 @@ impl MachineState { .univ_prelude .num_cells; - self.cc = cell_as_fixnum!(self.stack.index_or_frame(self.b)[n - 1]) + self.cc = cell_as_fixnum!(self.stack[stack_loc!(OrFrame, self.b, n-1)]) .get_num() as usize; if next_i > 0 { - match code_repo.find_living_dynamic_else(p + next_i, self.cc) { + match self.find_living_dynamic_else(&code_repo.code, p + next_i) { Some(_) => { try_or_fail!( self, @@ -4149,14 +4175,14 @@ impl MachineState { None => { try_or_fail!( self, - call_policy.trust_me(self, global_variables,) + call_policy.trust_me(self, global_variables) ) } } } else { try_or_fail!( self, - call_policy.trust_me(self, global_variables,) + call_policy.trust_me(self, global_variables) ) } } @@ -4179,6 +4205,8 @@ impl MachineState { or_frame.prelude.cp = self.cp; or_frame.prelude.b = self.b; or_frame.prelude.bp = self.p.local() + offset; + or_frame.prelude.boip = 0; + or_frame.prelude.biip = 0; or_frame.prelude.tr = self.tr; or_frame.prelude.h = self.heap.len(); or_frame.prelude.b0 = self.b0; diff --git a/src/machine/mod.rs b/src/machine/mod.rs index ccb952cd..7a73ac30 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -612,7 +612,7 @@ impl MachineState { user_input: &mut Stream, user_output: &mut Stream, ) { - let instr = match code_repo.lookup_instr(self.last_call, &self.p) { + let instr = match code_repo.lookup_instr(self, &self.p) { Some(instr) => instr, None => return, }; @@ -629,9 +629,13 @@ impl MachineState { fn backtrack(&mut self) { let b = self.b; + let or_frame = self.stack.index_or_frame(b); - self.b0 = self.stack.index_or_frame(b).prelude.b0; - self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp); + self.b0 = or_frame.prelude.b0; + self.p = CodePtr::Local(or_frame.prelude.bp); + + self.oip = or_frame.prelude.boip; + self.iip = or_frame.prelude.biip; self.pdl.clear(); self.fail = false; @@ -639,8 +643,7 @@ impl MachineState { fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool { match self.p { - CodePtr::Local(LocalCodePtr::DirEntry(p)) | - CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..)) + CodePtr::Local(LocalCodePtr::DirEntry(p)) if p < code_repo.code.len() => {} CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => { return false; @@ -661,7 +664,7 @@ impl MachineState { user_output: &mut Stream, ) -> bool { loop { - let instr = match code_repo.lookup_instr(self.last_call, &self.p) { + let instr = match code_repo.lookup_instr(self, &self.p) { Some(instr) => { if instr.as_ref().is_head_instr() { instr @@ -721,7 +724,7 @@ impl MachineState { let instigating_p = CodePtr::Local(self.attr_var_init.instigating_p); let instigating_instr = code_repo - .lookup_instr(false, &instigating_p) + .lookup_instr(self, &instigating_p) .unwrap(); if !instigating_instr.as_ref().is_head_instr() { diff --git a/src/machine/stack.rs b/src/machine/stack.rs index 1ab988cd..b175917b 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -121,6 +121,8 @@ pub(crate) struct OrFramePrelude { pub(crate) cp: LocalCodePtr, pub(crate) b: usize, pub(crate) bp: LocalCodePtr, + pub(crate) boip: u32, + pub(crate) biip: u32, pub(crate) tr: usize, pub(crate) h: usize, pub(crate) b0: usize, diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 0720c265..15217cec 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3145,7 +3145,7 @@ impl MachineState { let p_functor = self.store(self.deref(self.registers[2])); let p = to_local_code_ptr(&self.heap, p_functor).unwrap(); - let num_cells = match code_repo.lookup_instr(self.last_call, &CodePtr::Local(p)) { + let num_cells = match code_repo.lookup_instr(self, &CodePtr::Local(p)) { Some(line) => { let perm_vars = match line.as_ref() { Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(), @@ -3720,7 +3720,7 @@ impl MachineState { } }; - if p.is_reset_cont_marker(code_repo, self.last_call) { + if self.is_reset_cont_marker(&code_repo, p) { return return_from_clause!(self.last_call, self); } @@ -4408,7 +4408,7 @@ impl MachineState { let mut cp = self.cp; while e > 0 { - if cp.is_reset_cont_marker(code_repo, self.last_call) { + if self.is_reset_cont_marker(code_repo, cp) { self.e = e; self.p = CodePtr::Local(cp + 1); // skip the reset marker. diff --git a/src/write.rs b/src/write.rs index 49e8c10b..455cc72b 100644 --- a/src/write.rs +++ b/src/write.rs @@ -20,9 +20,9 @@ impl fmt::Display for LocalCodePtr { match self { LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p), LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"), - LocalCodePtr::IndexingBuf(p, o, i) => { - write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i) - } + // LocalCodePtr::IndexingBuf(p, o, i) => { + // write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i) + // } } } } -- cgit v1.2.3-70-g09d2 From 3db86f1e2565b81a7f159fa9c75694611e636f22 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 17 Dec 2021 22:02:20 -0700 Subject: relocate most instruction routines from MachineState to Machine --- Cargo.lock | 7 - Cargo.toml | 4 +- src/clause_types.rs | 3 + src/heap_print.rs | 7 +- src/instructions.rs | 2 +- src/lib/iso_ext.pl | 3 +- src/machine/code_repo.rs | 75 +- src/machine/compile.rs | 10 +- src/machine/dispatch.rs | 1279 +++++++++++++++++++ src/machine/machine_indices.rs | 180 +-- src/machine/machine_state.rs | 885 ++------------ src/machine/machine_state_impl.rs | 1897 +++-------------------------- src/machine/mock_wam.rs | 2 - src/machine/mod.rs | 1044 +++++++++++++--- src/machine/preprocessor.rs | 4 +- src/machine/system_calls.rs | 2437 ++++++++++++++++++------------------- src/macros.rs | 2 +- 17 files changed, 3698 insertions(+), 4143 deletions(-) create mode 100644 src/machine/dispatch.rs diff --git a/Cargo.lock b/Cargo.lock index e706052a..7818a0a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -289,12 +289,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" -[[package]] -name = "downcast" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d" - [[package]] name = "ed25519" version = "1.2.0" @@ -1398,7 +1392,6 @@ dependencies = [ "crossterm", "dirs-next", "divrem", - "downcast", "git-version", "hostname", "indexmap", diff --git a/Cargo.toml b/Cargo.toml index 000c117e..d0a332fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,6 @@ cpu-time = "1.0.0" crossterm = "0.16.0" dirs-next = "2.0.0" divrem = "0.1.0" -downcast = "0.10.0" git-version = "0.3.4" hostname = "0.3.1" indexmap = "1.0.2" @@ -66,3 +65,6 @@ slice-deque = "0.3.0" assert_cmd = "1.0.3" predicates-core = "1.0.2" serial_test = "0.5.1" + +[profile.release] +debug = true \ No newline at end of file diff --git a/src/clause_types.rs b/src/clause_types.rs index e11e84b1..8083775a 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -799,11 +799,13 @@ impl SystemClauseType { (atom!("$ed25519_new_keypair"), 1) => Some(SystemClauseType::Ed25519NewKeyPair), (atom!("$ed25519_keypair_public_key"), 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey), (atom!("$curve25519_scalar_mult"), 3) => Some(SystemClauseType::Curve25519ScalarMult), + (atom!("$first_non_octet"), 2) => Some(SystemClauseType::FirstNonOctet), (atom!("$load_html"), 3) => Some(SystemClauseType::LoadHTML), (atom!("$load_xml"), 3) => Some(SystemClauseType::LoadXML), (atom!("$getenv"), 2) => Some(SystemClauseType::GetEnv), (atom!("$setenv"), 2) => Some(SystemClauseType::SetEnv), (atom!("$unsetenv"), 1) => Some(SystemClauseType::UnsetEnv), + (atom!("$shell"), 2) => Some(SystemClauseType::Shell), (atom!("$pid"), 1) => Some(SystemClauseType::PID), (atom!("$chars_base64"), 4) => Some(SystemClauseType::CharsBase64), (atom!("$load_library_as_stream"), 3) => Some(SystemClauseType::LoadLibraryAsStream), @@ -847,6 +849,7 @@ impl SystemClauseType { (atom!("$set_sto_with_error_as_unify"), 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify), (atom!("$home_directory"), 1) => Some(SystemClauseType::HomeDirectory), (atom!("$debug_hook"), 0) => Some(SystemClauseType::DebugHook), + (atom!("$popcount"), 2) => Some(SystemClauseType::PopCount), _ => None, } } diff --git a/src/heap_print.rs b/src/heap_print.rs index 6f320839..f9421788 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -19,7 +19,7 @@ use crate::types::*; use ordered_float::OrderedFloat; -use indexmap::{IndexMap, IndexSet}; +use indexmap::IndexMap; use std::cell::Cell; use std::convert::TryFrom; @@ -490,11 +490,7 @@ pub struct HCPrinter<'a, Outputter> { op_dir: &'a OpDir, state_stack: Vec, toplevel_spec: Option, - // heap_locs: ReverseHeapVarDict, - printed_vars: IndexSet, last_item_idx: usize, - // cyclic_terms: IndexMap, - // non_cyclic_terms: IndexSet, pub var_names: IndexMap>, pub numbervars_offset: Integer, pub numbervars: bool, @@ -530,7 +526,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { op_dir, state_stack: vec![], toplevel_spec: None, - printed_vars: IndexSet::new(), last_item_idx: 0, numbervars: false, numbervars_offset: Integer::from(0), diff --git a/src/instructions.rs b/src/instructions.rs index 76c9c76c..efaf4d5a 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -339,7 +339,7 @@ pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec> { } } -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] pub enum ArithmeticInstruction { Add(ArithmeticTerm, ArithmeticTerm, usize), Sub(ArithmeticTerm, ArithmeticTerm, usize), diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index 2127ca8a..37044a40 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -98,7 +98,8 @@ scc_helper(_, _, _) :- :- non_counted_backtracking run_cleaners_with_handling/0. run_cleaners_with_handling :- - '$get_scc_cleaner'(C), '$get_level'(B), + '$get_scc_cleaner'(C), + '$get_level'(B), '$call_with_default_policy'(catch(C, _, true)), '$set_cp_by_default'(B), '$call_with_default_policy'(run_cleaners_with_handling). diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs index ba046228..f6fb6aa0 100644 --- a/src/machine/code_repo.rs +++ b/src/machine/code_repo.rs @@ -1,8 +1,35 @@ use crate::clause_types::*; use crate::instructions::*; -use crate::machine::MachineState; +use crate::machine::{Machine, MachineState}; use crate::machine::machine_indices::*; +use std::fmt; + +pub(crate) enum OwnedOrIndexed { + Indexed(usize), + Owned(Line), +} + +impl fmt::Debug for OwnedOrIndexed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &OwnedOrIndexed::Indexed(ref index) => write!(f, "Indexed({:?})", index), + &OwnedOrIndexed::Owned(ref owned) => write!(f, "Owned({:?})", owned), + } + } +} + +impl OwnedOrIndexed { + #[inline(always)] + pub(crate) fn as_ref<'a>(&'a self, code: &'a Code) -> &'a Line { + match self { + &OwnedOrIndexed::Indexed(p) => &code[p], + &OwnedOrIndexed::Owned(ref r) => r, + } + } +} + + // TODO: remove this, replace with just 'Code'. #[derive(Debug)] pub struct CodeRepo { @@ -10,7 +37,7 @@ pub struct CodeRepo { } impl CodeRepo { - pub(super) fn lookup_instr<'a>(&'a self, machine_st: &MachineState, p: &CodePtr) -> Option> { + pub(super) fn lookup_instr(&self, machine_st: &MachineState, p: &CodePtr) -> Option { match p { &CodePtr::Local(local) => { return Some(self.lookup_local_instr(machine_st, local)); @@ -24,18 +51,18 @@ impl CodeRepo { machine_st.last_call ); - Some(RefOrOwned::Owned(call_clause)) + Some(OwnedOrIndexed::Owned(call_clause)) } &CodePtr::CallN(arity, _, last_call) => { let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call); - Some(RefOrOwned::Owned(call_clause)) + Some(OwnedOrIndexed::Owned(call_clause)) } - &CodePtr::VerifyAttrInterrupt(p) => Some(RefOrOwned::Borrowed(&self.code[p])), + &CodePtr::VerifyAttrInterrupt(p) => Some(OwnedOrIndexed::Indexed(p)), } } #[inline] - pub(super) fn lookup_local_instr<'a>(&'a self, machine_st: &MachineState, p: LocalCodePtr) -> RefOrOwned<'a, Line> { + pub(super) fn lookup_local_instr(&self, machine_st: &MachineState, p: LocalCodePtr) -> OwnedOrIndexed { match p { LocalCodePtr::Halt => { // exit with the interrupt exit code. @@ -45,32 +72,36 @@ impl CodeRepo { &Line::IndexingCode(ref indexing_lines) => { match &indexing_lines[machine_st.oip as usize] { &IndexingLine::IndexedChoice(ref indexed_choice_instrs) => { - RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[machine_st.iip as usize])) + OwnedOrIndexed::Owned( + Line::IndexedChoice(indexed_choice_instrs[machine_st.iip as usize]) + ) } &IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => { - RefOrOwned::Owned(Line::DynamicIndexedChoice(indexed_choice_instrs[machine_st.iip as usize])) + OwnedOrIndexed::Owned( + Line::DynamicIndexedChoice(indexed_choice_instrs[machine_st.iip as usize]) + ) } _ => { - RefOrOwned::Borrowed(&self.code[p as usize]) + OwnedOrIndexed::Indexed(p) } } } - _ => RefOrOwned::Borrowed(&self.code[p as usize]), + _ => OwnedOrIndexed::Indexed(p) } } } } -impl MachineState { - pub(super) fn find_living_dynamic_else(&self, code: &Code, mut p: usize) -> Option<(usize, usize)> { +impl Machine { + pub(super) fn find_living_dynamic_else(&self, mut p: usize) -> Option<(usize, usize)> { loop { - match &code[p] { + match &self.code_repo.code[p] { &Line::Choice(ChoiceInstruction::DynamicElse( birth, death, NextOrFail::Next(i), )) => { - if birth < self.cc && Death::Finite(self.cc) <= death { + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { return Some((p, i)); } else if i > 0 { p += i; @@ -83,7 +114,7 @@ impl MachineState { death, NextOrFail::Fail(_), )) => { - if birth < self.cc && Death::Finite(self.cc) <= death { + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { return Some((p, 0)); } else { return None; @@ -94,7 +125,7 @@ impl MachineState { death, NextOrFail::Next(i), )) => { - if birth < self.cc && Death::Finite(self.cc) <= death { + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { return Some((p, i)); } else if i > 0 { p += i; @@ -107,7 +138,7 @@ impl MachineState { death, NextOrFail::Fail(_), )) => { - if birth < self.cc && Death::Finite(self.cc) <= death { + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { return Some((p, 0)); } else { return None; @@ -123,10 +154,10 @@ impl MachineState { } } - pub(super) fn find_living_dynamic(&self, code: &Code, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> { - let p = self.p.local().abs_loc(); + pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> { + let p = self.machine_st.p.local().abs_loc(); - let indexed_choice_instrs = match &code[p] { + let indexed_choice_instrs = match &self.code_repo.code[p] { Line::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] { IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => { indexed_choice_instrs @@ -138,13 +169,13 @@ impl MachineState { loop { match &indexed_choice_instrs.get(ii as usize) { - Some(&offset) => match &code[p + offset - 1] { + Some(&offset) => match &self.code_repo.code[p + offset - 1] { &Line::Choice(ChoiceInstruction::DynamicInternalElse( birth, death, next_or_fail, )) => { - if birth < self.cc && Death::Finite(self.cc) <= death { + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { return Some((offset, oi, ii, next_or_fail.is_next())); } else { ii += 1; diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 72ec57c4..8b69ced8 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1371,12 +1371,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { term: Term, settings: CodeGenSettings, ) -> Result { - let mut preprocessor = Preprocessor::new(LS::machine_st(&mut self.payload).flags); + let mut preprocessor = Preprocessor::new(); let clause = self.try_term_to_tl(term, &mut preprocessor)?; let queue = preprocessor.parse_queue(self)?; - let mut cg = CodeGenerator::::new(&mut LS::machine_st(&mut self.payload).atom_tbl, settings); + let mut cg = CodeGenerator::::new( + &mut LS::machine_st(&mut self.payload).atom_tbl, + settings, + ); + let mut clause_code = cg.compile_predicate(&vec![clause])?; compile_appendix( @@ -1405,7 +1409,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let mut code_ptr = code_len; let mut clauses = vec![]; - let mut preprocessor = Preprocessor::new(LS::machine_st(&mut self.payload).flags); + let mut preprocessor = Preprocessor::new(); for term in predicates.predicates.drain(0..) { clauses.push(self.try_term_to_tl(term, &mut preprocessor)?); diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs new file mode 100644 index 00000000..9b02d191 --- /dev/null +++ b/src/machine/dispatch.rs @@ -0,0 +1,1279 @@ +use crate::arena::*; +use crate::atom_table::*; +use crate::instructions::*; +use crate::machine::*; +use crate::machine::arithmetic_ops::*; +use crate::machine::code_repo::*; +use crate::machine::machine_errors::*; +use crate::machine::machine_state::*; +use crate::types::*; + +use crate::try_numeric_result; + +impl Machine { + #[inline(always)] + pub(super) fn dispatch_instr(&mut self, instr: OwnedOrIndexed) { + match instr.as_ref(&self.code_repo.code) { + &Line::Arithmetic(ref arith_instr) => { + let stub_gen = || functor_stub(atom!("is"), 2); + + match arith_instr { + &ArithmeticInstruction::Add(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + try_numeric_result!(add(n1, n2, &mut self.machine_st.arena), stub_gen) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Sub(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Mul(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + try_numeric_result!(mul(n1, n2, &mut self.machine_st.arena), stub_gen) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Max(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + max(n1, n2) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Min(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + min(n1, n2) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::IntPow(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + int_pow(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + gcd(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Pow(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + pow(n1, n2, atom!("**")) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => { + let stub_gen = || functor_stub(atom!("(rdiv)"), 2); + + let r1 = try_or_fail!(self.machine_st, self.machine_st.get_rational(a1, stub_gen)); + let r2 = try_or_fail!(self.machine_st, self.machine_st.get_rational(a2, stub_gen)); + + self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!( + try_or_fail_gen!(&mut self.machine_st, rdiv(r1, r2)), + self.machine_st.arena + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + int_floor_div(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + idiv(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Abs(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = abs(n1, &mut self.machine_st.arena); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Sign(ref a1, t) => { + let n = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = sign(n); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Neg(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = neg(n1, &mut self.machine_st.arena); + self.machine_st.p += 1; + } + &ArithmeticInstruction::BitwiseComplement(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + bitwise_complement(n1, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Div(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + div(n1, n2) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Shr(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + shr(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Shl(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + shl(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Xor(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + xor(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::And(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + and(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Or(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + or(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Mod(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + modulus(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Rem(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_fail_gen!( + &mut self.machine_st, + remainder(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Cos(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, cos(n1)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Sin(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, sin(n1)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Tan(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, tan(n1)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Sqrt(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, sqrt(n1)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Log(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, log(n1)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Exp(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, exp(n1)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::ACos(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, acos(n1)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::ASin(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, asin(n1)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::ATan(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, atan(n1)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::ATan2(ref a1, ref a2, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, atan2(n1, n2)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Float(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_fail_gen!(&mut self.machine_st, float(n1)) + )); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Truncate(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = truncate(n1, &mut self.machine_st.arena); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Round(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = + try_or_fail_gen!(&mut self.machine_st, round(n1, &mut self.machine_st.arena)); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Ceiling(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = ceiling(n1, &mut self.machine_st.arena); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Floor(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = floor(n1, &mut self.machine_st.arena); + self.machine_st.p += 1; + } + &ArithmeticInstruction::Plus(ref a1, t) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = n1; + self.machine_st.p += 1; + } + } + } + &Line::Choice(ref choice_instr) => { + match choice_instr { + &ChoiceInstruction::DynamicElse(..) => { + if let FirstOrNext::First = self.machine_st.dynamic_mode { + self.machine_st.cc = self.machine_st.global_clock; + } + + let p = self.machine_st.p.local().abs_loc(); + + match self.find_living_dynamic_else(p) { + Some((p, next_i)) => { + self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + + match self.machine_st.dynamic_mode { + FirstOrNext::First if next_i == 0 => { + self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1)); + } + FirstOrNext::First => { + self.machine_st.cc = self.machine_st.global_clock; + + match self.find_living_dynamic_else(p + next_i) { + Some(_) => { + self.machine_st.registers[self.machine_st.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); + + self.machine_st.num_of_args += 1; + self.machine_st.try_me_else(next_i); + self.machine_st.num_of_args -= 1; + } + None => { + self.machine_st.p += 1; + } + } + } + FirstOrNext::Next => { + let n = self.machine_st + .stack + .index_or_frame(self.machine_st.b) + .prelude + .univ_prelude + .num_cells; + + self.machine_st.cc = cell_as_fixnum!( + self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)] + ).get_num() as usize; + + if next_i > 0 { + match self.find_living_dynamic_else(p + next_i) { + Some(_) => { + self.retry_me_else(next_i); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + None => { + self.trust_me(); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } else { + self.trust_me(); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } + } + None => { + self.machine_st.fail = true; + } + } + + self.machine_st.dynamic_mode = FirstOrNext::Next; + } + &ChoiceInstruction::DynamicInternalElse(..) => { + let p = self.machine_st.p.local().abs_loc(); + + match self.find_living_dynamic_else(p) { + Some((p, next_i)) => { + self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + + match self.machine_st.dynamic_mode { + FirstOrNext::First if next_i == 0 => { + self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1)); + } + FirstOrNext::First => { + match self.find_living_dynamic_else(p + next_i) { + Some(_) => { + self.machine_st.registers[self.machine_st.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); + + self.machine_st.num_of_args += 1; + self.machine_st.try_me_else(next_i); + self.machine_st.num_of_args -= 1; + } + None => { + self.machine_st.p += 1; + } + } + } + FirstOrNext::Next => { + let n = self.machine_st + .stack + .index_or_frame(self.machine_st.b) + .prelude + .univ_prelude + .num_cells; + + self.machine_st.cc = cell_as_fixnum!( + self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)] + ).get_num() as usize; + + if next_i > 0 { + match self.find_living_dynamic_else(p + next_i) { + Some(_) => { + self.retry_me_else(next_i); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + None => { + self.trust_me(); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } else { + self.trust_me(); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } + } + None => { + self.machine_st.fail = true; + } + } + + self.machine_st.dynamic_mode = FirstOrNext::Next; + } + &ChoiceInstruction::TryMeElse(offset) => { + self.machine_st.try_me_else(offset); + } + &ChoiceInstruction::DefaultRetryMeElse(offset) => { + self.retry_me_else(offset); + } + &ChoiceInstruction::DefaultTrustMe(_) => { + self.trust_me(); + } + &ChoiceInstruction::RetryMeElse(offset) => { + self.retry_me_else(offset); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + &ChoiceInstruction::TrustMe(_) => { + self.trust_me(); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } + &Line::Cut(ref cut_instr) => { + match cut_instr { + &CutInstruction::NeckCut => { + let b = self.machine_st.b; + let b0 = self.machine_st.b0; + + if b > b0 { + self.machine_st.b = b0; + + if b > self.machine_st.e { + self.machine_st.stack.truncate(b); + } + } + + self.machine_st.p += 1; + } + &CutInstruction::GetLevel(r) => { + let b0 = self.machine_st.b0; + + self.machine_st[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64)); + self.machine_st.p += 1; + } + &CutInstruction::GetLevelAndUnify(r) => { + let b0 = self.machine_st[perm_v!(1)]; + let a = self.machine_st[r]; + + unify_fn!(&mut self.machine_st, a, b0); + self.machine_st.p += 1; + } + &CutInstruction::Cut(r) => { + let value = self.machine_st[r]; + self.machine_st.cut_body(value); + + if !self.machine_st.fail && !(self.machine_st.run_cleaners_fn)(self) { + self.machine_st.p += 1; + } + } + } + } + &Line::Control(ref ctrl_instr) => { + match ctrl_instr { + &ControlInstruction::Allocate(num_cells) => + self.machine_st.allocate(num_cells), + &ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) => { + let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); + + match INTERRUPT.compare_exchange( + interrupted, + false, + std::sync::atomic::Ordering::Relaxed, + std::sync::atomic::Ordering::Relaxed, + ) { + Ok(interruption) => { + if interruption { + self.machine_st.throw_interrupt_exception(); + return; + } + } + Err(_) => unreachable!(), + } + + self.machine_st.last_call = lco; + + match ct { + &ClauseType::BuiltIn(ref ct) => { + let ct = ct.clone(); + + try_or_fail!( + self.machine_st, + self.call_builtin(&ct) + ); + + if !use_default_cp { + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + &ClauseType::CallN => { + try_or_fail!( + self.machine_st, + self.call_n(atom!("user"), arity) + ); + + if !use_default_cp { + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + &ClauseType::Inlined(ref ct) => { + let ct = ct.clone(); + self.execute_inlined(&ct); + + if lco { + self.machine_st.p = CodePtr::Local(self.machine_st.cp); + } + } + &ClauseType::Named(name, _, ref idx) => { + let idx = idx.clone(); + + try_or_fail!( + self.machine_st, + self.context_call(name, arity, idx) // TODO: change to idx.get() ??? + ); + + if !use_default_cp { + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + &ClauseType::System(ref ct) => { + let ct = ct.clone(); + + try_or_fail!( + self.machine_st, + self.system_call(&ct) + ); + } + }; + + self.machine_st.last_call = false; + } + &ControlInstruction::Deallocate => + self.machine_st.deallocate(), + &ControlInstruction::JmpBy(arity, offset, _, lco) => { + if !lco { + self.machine_st.cp.assign_if_local(self.machine_st.p.clone() + 1); + } + + self.machine_st.num_of_args = arity; + self.machine_st.b0 = self.machine_st.b; + self.machine_st.p += offset; + } + &ControlInstruction::RevJmpBy(offset) => { + self.machine_st.p -= offset; + } + &ControlInstruction::Proceed => { + self.machine_st.p = CodePtr::Local(self.machine_st.cp); + } + } + } + &Line::Fact(ref fact_instr) => { + match fact_instr { + &FactInstruction::GetConstant(_, c, reg) => { + let value = self.machine_st.deref(self.machine_st[reg]); + self.machine_st.write_literal_to_var(value, c); + } + &FactInstruction::GetList(_, reg) => { + let deref_v = self.machine_st.deref(self.machine_st[reg]); + let store_v = self.machine_st.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::PStrLoc, h) => { + let (h, n) = pstr_loc_and_offset(&self.machine_st.heap, h); + + self.machine_st.s = HeapPtr::PStrChar(h, n.get_num() as usize); + self.machine_st.mode = MachineMode::Read; + } + (HeapCellValueTag::CStr) => { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(store_v); + + self.machine_st.s = HeapPtr::PStrChar(h, 0); + self.machine_st.mode = MachineMode::Read; + } + (HeapCellValueTag::Lis, l) => { + self.machine_st.s = HeapPtr::HeapCell(l); + self.machine_st.mode = MachineMode::Read; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(list_loc_as_cell!(h+1)); + self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); + + self.machine_st.mode = MachineMode::Write; + } + _ => { + self.machine_st.fail = true; + } + ); + } + &FactInstruction::GetPartialString(_, string, reg, has_tail) => { + let deref_v = self.machine_st.deref(self.machine_st[reg]); + let store_v = self.machine_st.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::Str | HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar | + HeapCellValueTag::StackVar | HeapCellValueTag::Var | + HeapCellValueTag::CStr) => { + self.machine_st.match_partial_string(store_v, string, has_tail); + } + _ => { + self.machine_st.fail = true; + } + ); + } + &FactInstruction::GetStructure(ref ct, arity, reg) => { + let deref_v = self.machine_st.deref(self.machine_st[reg]); + let store_v = self.machine_st.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::Str, a) => { + let result = self.machine_st.heap[a]; + + read_heap_cell!(result, + (HeapCellValueTag::Atom, (name, narity)) => { + if narity == arity && ct.name() == name { + self.machine_st.s = HeapPtr::HeapCell(a + 1); + self.machine_st.mode = MachineMode::Read; + } else { + self.machine_st.fail = true; + } + } + _ => { + unreachable!(); + } + ); + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(str_loc_as_cell!(h+1)); + self.machine_st.heap.push(atom_as_cell!(ct.name(), arity)); + + self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); + + self.machine_st.mode = MachineMode::Write; + } + _ => { + self.machine_st.fail = true; + } + ); + } + &FactInstruction::GetVariable(norm, arg) => { + self.machine_st[norm] = self.machine_st.registers[arg]; + } + &FactInstruction::GetValue(norm, arg) => { + let norm_addr = self.machine_st[norm]; + let reg_addr = self.machine_st.registers[arg]; + + unify_fn!(&mut self.machine_st, norm_addr, reg_addr); + } + &FactInstruction::UnifyConstant(v) => { + match self.machine_st.mode { + MachineMode::Read => { + let addr = self.machine_st.read_s(); + + self.machine_st.write_literal_to_var(addr, v); + self.machine_st.increment_s_ptr(1); + } + MachineMode::Write => { + self.machine_st.heap.push(v); + } + }; + } + &FactInstruction::UnifyVariable(reg) => { + match self.machine_st.mode { + MachineMode::Read => { + self.machine_st[reg] = self.machine_st.read_s(); + self.machine_st.increment_s_ptr(1); + } + MachineMode::Write => { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(heap_loc_as_cell!(h)); + self.machine_st[reg] = heap_loc_as_cell!(h); + } + }; + } + &FactInstruction::UnifyLocalValue(reg) => { + match self.machine_st.mode { + MachineMode::Read => { + let reg_addr = self.machine_st[reg]; + let value = self.machine_st.read_s(); + + unify_fn!(&mut self.machine_st, reg_addr, value); + self.machine_st.increment_s_ptr(1); + } + MachineMode::Write => { + let value = self.machine_st.store(self.machine_st.deref(self.machine_st[reg])); + let h = self.machine_st.heap.len(); + + read_heap_cell!(value, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => { + let value = self.machine_st.heap[hc]; + + self.machine_st.heap.push(value); + self.machine_st.increment_s_ptr(1); + } + _ => { + self.machine_st.heap.push(heap_loc_as_cell!(h)); + (self.machine_st.bind_fn)( + &mut self.machine_st, + Ref::heap_cell(h), + value, + ); + } + ); + } + }; + } + &FactInstruction::UnifyValue(reg) => { + match self.machine_st.mode { + MachineMode::Read => { + let reg_addr = self.machine_st[reg]; + let value = self.machine_st.read_s(); + + unify_fn!(&mut self.machine_st, reg_addr, value); + self.machine_st.increment_s_ptr(1); + } + MachineMode::Write => { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(heap_loc_as_cell!(h)); + + let addr = self.machine_st.store(self.machine_st[reg]); + (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr); + + // the former code of this match arm was: + + // let addr = self.machine_st.store(self.machine_st[reg]); + // self.machine_st.heap.push(HeapCellValue::Addr(addr)); + + // the old code didn't perform the occurs + // check when enabled and so it was changed to + // the above, which is only slightly less + // efficient when the occurs_check is disabled. + } + }; + } + &FactInstruction::UnifyVoid(n) => { + match self.machine_st.mode { + MachineMode::Read => { + self.machine_st.increment_s_ptr(n); + } + MachineMode::Write => { + let h = self.machine_st.heap.len(); + + for i in h..h + n { + self.machine_st.heap.push(heap_loc_as_cell!(i)); + } + } + }; + } + } + self.machine_st.p += 1; + } + &Line::IndexingCode(ref indexing_lines) => { + #[inline(always)] + fn dynamic_external_of_clause_is_valid(machine: &mut Machine, p: usize) -> bool { + match &machine.code_repo.code[p] { + Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => { + machine.machine_st.dynamic_mode = FirstOrNext::First; + return true; + } + _ => {} + } + + match &machine.code_repo.code[p - 1] { + &Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => { + if birth < machine.machine_st.cc && Death::Finite(machine.machine_st.cc) <= death { + return true; + } else { + return false; + } + } + _ => {} + } + + true + } + + let mut index = 0; + let addr = match &indexing_lines[0] { + &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => { + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[arg])) + } + _ => { + unreachable!() + } + }; + + loop { + match &indexing_lines[index] { + &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => { + let offset = read_heap_cell!(addr, + (HeapCellValueTag::Var | + HeapCellValueTag::StackVar | + HeapCellValueTag::AttrVar) => { + v + } + (HeapCellValueTag::PStrLoc | + HeapCellValueTag::Lis | + HeapCellValueTag::CStr) => { + l + } + (HeapCellValueTag::Fixnum | + HeapCellValueTag::Char | + HeapCellValueTag::F64) => { + c + } + (HeapCellValueTag::Atom, (_name, arity)) => { + // if arity == 0 { c } else { s } + debug_assert!(arity == 0); + c + } + (HeapCellValueTag::Str) => { + s + } + (HeapCellValueTag::Cons, ptr) => { + match ptr.get_tag() { + ArenaHeaderTag::Rational | ArenaHeaderTag::Integer | + ArenaHeaderTag::F64 => { + c + } + _ => { + IndexingCodePtr::Fail + } + } + } + _ => { + unreachable!(); + } + ); + + match offset { + IndexingCodePtr::Fail => { + self.machine_st.fail = true; + break; + } + IndexingCodePtr::DynamicExternal(o) => { + // either points directly to a + // DynamicInternalElse, or just ahead of + // one. Or neither! + let p = self.machine_st.p.local().abs_loc(); + + if !dynamic_external_of_clause_is_valid(self, p + o) { + self.machine_st.fail = true; + } else { + self.machine_st.p += o; + } + + break; + } + IndexingCodePtr::External(o) => { + self.machine_st.p += o; + break; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + } + } + &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => { + let lit = read_heap_cell!(addr, + (HeapCellValueTag::Char, c) => { + Literal::Char(c) + } + (HeapCellValueTag::Fixnum, n) => { + Literal::Fixnum(n) + } + (HeapCellValueTag::F64, f) => { + Literal::Float(f) + } + (HeapCellValueTag::Atom, (atom, arity)) => { + debug_assert_eq!(arity, 0); + Literal::Atom(atom) + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Rational, r) => { + Literal::Rational(r) + } + (ArenaHeaderTag::F64, f) => { + Literal::Float(F64Ptr(f)) + } + (ArenaHeaderTag::Integer, n) => { + Literal::Integer(n) + } + _ => { + unreachable!() + } + ) + } + _ => { + unreachable!() + } + ); + + let offset = match hm.get(&lit) { + Some(offset) => *offset, + _ => IndexingCodePtr::Fail, + }; + + match offset { + IndexingCodePtr::Fail => { + self.machine_st.fail = true; + break; + } + IndexingCodePtr::DynamicExternal(o) => { + // either points directly to a + // DynamicInternalElse, or just ahead of + // one. Or neither! + let p = self.machine_st.p.local().abs_loc(); + + if !dynamic_external_of_clause_is_valid(self, p + o) { + self.machine_st.fail = true; + } else { + self.machine_st.p += o; + } + + break; + } + IndexingCodePtr::External(o) => { + self.machine_st.p += o; + break; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + } + } + &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => { + let offset = read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, arity)) => { + match hm.get(&(name, arity)) { + Some(offset) => *offset, + None => IndexingCodePtr::Fail, + } + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) + .get_name_and_arity(); + + match hm.get(&(name, arity)) { + Some(offset) => *offset, + None => IndexingCodePtr::Fail, + } + } + _ => { + IndexingCodePtr::Fail + } + ); + + match offset { + IndexingCodePtr::Fail => { + self.machine_st.fail = true; + break; + } + IndexingCodePtr::DynamicExternal(o) => { + let p = self.machine_st.p.local().abs_loc(); + + if !dynamic_external_of_clause_is_valid(self, p + o) { + self.machine_st.fail = true; + } else { + self.machine_st.p += o; + } + + break; + } + IndexingCodePtr::External(o) => { + self.machine_st.p += o; + break; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + } + } + &IndexingLine::IndexedChoice(_) => { + if let LocalCodePtr::DirEntry(p) = self.machine_st.p.local() { + self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + self.machine_st.oip = index as u32; + self.machine_st.iip = 0; + } else { + unreachable!() + } + + break; + } + &IndexingLine::DynamicIndexedChoice(_) => { + self.machine_st.dynamic_mode = FirstOrNext::First; + + if let LocalCodePtr::DirEntry(p) = self.machine_st.p.local() { + self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + self.machine_st.oip = index as u32; + self.machine_st.iip = 0; + } else { + unreachable!() + } + + break; + } + } + } + } + &Line::IndexedChoice(ref choice_instr) => { + match choice_instr { + &IndexedChoiceInstruction::Try(offset) => { + self.machine_st.indexed_try(offset); + } + &IndexedChoiceInstruction::Retry(l) => { + self.retry(l); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + &IndexedChoiceInstruction::Trust(l) => { + self.trust(l); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } + &Line::DynamicIndexedChoice(_) => self.execute_dynamic_indexed_choice_instr(), + &Line::Query(ref query_instr) => { + match query_instr { + &QueryInstruction::GetVariable(norm, arg) => { + self.machine_st[norm] = self.machine_st.registers[arg]; + } + &QueryInstruction::PutConstant(_, c, reg) => { + self.machine_st[reg] = c; + } + &QueryInstruction::PutList(_, reg) => { + self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.len()); + } + &QueryInstruction::PutPartialString(_, string, reg, has_tail) => { + let pstr_addr = if has_tail { + if string != atom!("") { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(string_as_pstr_cell!(string)); + + // the tail will be pushed by the next + // instruction, so don't push one here. + + pstr_loc_as_cell!(h) + } else { + empty_list_as_cell!() + } + } else { + string_as_cstr_cell!(string) + }; + + self.machine_st[reg] = pstr_addr; + } + &QueryInstruction::PutStructure(ref ct, arity, reg) => { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(atom_as_cell!(ct.name(), arity)); + self.machine_st[reg] = str_loc_as_cell!(h); + } + &QueryInstruction::PutUnsafeValue(n, arg) => { + let s = stack_loc!(AndFrame, self.machine_st.e, n); + let addr = self.machine_st.store(self.machine_st.deref(stack_loc_as_cell!(s))); + + if addr.is_protected(self.machine_st.e) { + self.machine_st.registers[arg] = addr; + } else { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(heap_loc_as_cell!(h)); + (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr); + + self.machine_st.registers[arg] = heap_loc_as_cell!(h); + } + } + &QueryInstruction::PutValue(norm, arg) => { + self.machine_st.registers[arg] = self.machine_st[norm]; + } + &QueryInstruction::PutVariable(norm, arg) => { + match norm { + RegType::Perm(n) => { + self.machine_st[norm] = stack_loc_as_cell!(AndFrame, self.machine_st.e, n); + self.machine_st.registers[arg] = self.machine_st[norm]; + } + RegType::Temp(_) => { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(heap_loc_as_cell!(h)); + + self.machine_st[norm] = heap_loc_as_cell!(h); + self.machine_st.registers[arg] = heap_loc_as_cell!(h); + } + }; + } + &QueryInstruction::SetConstant(c) => { + self.machine_st.heap.push(c); + } + &QueryInstruction::SetLocalValue(reg) => { + let addr = self.machine_st.deref(self.machine_st[reg]); + let stored_v = self.machine_st.store(addr); + + if stored_v.is_stack_var() { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(heap_loc_as_cell!(h)); + (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), stored_v); + } else { + self.machine_st.heap.push(stored_v); + } + } + &QueryInstruction::SetVariable(reg) => { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(heap_loc_as_cell!(h)); + self.machine_st[reg] = heap_loc_as_cell!(h); + } + &QueryInstruction::SetValue(reg) => { + let heap_val = self.machine_st.store(self.machine_st[reg]); + self.machine_st.heap.push(heap_val); + } + &QueryInstruction::SetVoid(n) => { + let h = self.machine_st.heap.len(); + + for i in h..h + n { + self.machine_st.heap.push(heap_loc_as_cell!(i)); + } + } + } + + self.machine_st.p += 1; + } + } + } +} diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index e7cda22d..3f8d47e8 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -6,8 +6,7 @@ use crate::clause_types::*; use crate::fixtures::*; use crate::forms::*; use crate::instructions::*; - -use crate::machine::code_repo::CodeRepo; +use crate::machine::*; use crate::machine::heap::*; use crate::machine::loader::*; use crate::machine::machine_errors::MachineStub; @@ -19,10 +18,14 @@ use indexmap::IndexMap; use std::cell::Cell; use std::cmp::Ordering; use std::collections::BTreeSet; -use std::fmt; use std::ops::{Add, AddAssign, Deref, Sub, SubAssign}; use std::rc::Rc; +// these statics store the locations of one-off control instructions +// in the code vector. + +pub static HALT_CODE: usize = 0; + use crate::types::*; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity); @@ -81,126 +84,7 @@ impl PartialOrd for HeapCellValue { ) } } -/* -impl HeapCellValue { - #[inline] - pub fn as_constant_index(self, machine_st: &MachineState) -> Option { - read_heap_cell!(self, - (HeapCellValueTag::Char, c) => Some(Literal::Char(c)), - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - Some(Literal::Atom(name)) - } else { - None - } - } - (HeapCellValueTag::Fixnum, n) => { - Some(Literal::Fixnum(n)) - } - (HeapCellValueTag::F64, f) => { - Some(Literal::Float(f)) - } - (HeapCellValueTag::Cons, ptr) => { - match_untyped_arena_ptr!(ptr, - (ArenaHeaderTag::Integer, n) => { - Some(Literal::Integer(n)) - } - (ArenaHeaderTag::Rational, r) => { - Some(Literal::Rational(r)) - } - _ => { - None - } - ) - } - ) - } -} -*/ -/* -impl Ord for Ref { - fn cmp(&self, other: &Ref) -> Ordering { - match (self, other) { - (Ref::AttrVar(h1), Ref::AttrVar(h2)) - | (Ref::HeapCell(h1), Ref::HeapCell(h2)) - | (Ref::HeapCell(h1), Ref::AttrVar(h2)) - | (Ref::AttrVar(h1), Ref::HeapCell(h2)) => h1.cmp(&h2), - (Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => { - fr1.cmp(&fr2).then_with(|| sc1.cmp(&sc2)) - } - (Ref::StackCell(..), _) => Ordering::Greater, - (_, Ref::StackCell(..)) => Ordering::Less, - } - } -} - -impl PartialEq for Addr { - fn eq(&self, r: &Ref) -> bool { - self.as_var() == Some(*r) - } -} - -impl Addr { - #[inline] - pub(crate) fn is_heap_bound(&self) -> bool { - match self { - Addr::Char(_) - | Addr::EmptyList - | Addr::CutPoint(_) - | Addr::Usize(_) - | Addr::Fixnum(_) - | Addr::Float(_) => false, - _ => true, - } - } - #[inline] - pub(crate) fn is_ref(&self) -> bool { - match self { - Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => true, - _ => false, - } - } - - #[inline] - pub(crate) fn as_var(&self) -> Option { - match self { - &Addr::AttrVar(h) => Some(Ref::AttrVar(h)), - &Addr::HeapCell(h) => Some(Ref::HeapCell(h)), - &Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)), - _ => None, - } - } - - pub(crate) fn is_protected(&self, e: usize) -> bool { - match self { - &Addr::StackCell(addr, _) if addr >= e => false, - _ => true, - } - } -} - -impl SubAssign for Addr { - fn sub_assign(&mut self, rhs: usize) { - *self = self.clone() - rhs; - } -} - -#[derive(Debug, Clone, Copy)] -pub(crate) enum TrailRef { - Ref(Ref), - AttrVarHeapLink(usize), - AttrVarListLink(usize, usize), - BlackboardEntry(usize), - BlackboardOffset(usize, usize), // key atom heap location, key value heap location -} - -impl From for TrailRef { - fn from(r: Ref) -> Self { - TrailRef::Ref(r) - } -} -*/ #[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum IndexPtr { DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. @@ -326,10 +210,10 @@ pub enum LocalCodePtr { // TopLevel(usize, usize), // chunk_num, offset } -impl MachineState { - pub(crate) fn is_reset_cont_marker(&self, code_repo: &CodeRepo, p: LocalCodePtr) -> bool { - match code_repo.lookup_instr(self, &CodePtr::Local(p)) { - Some(line) => match line.as_ref() { +impl Machine { + pub(crate) fn is_reset_cont_marker(&self, p: LocalCodePtr) -> bool { + match self.code_repo.lookup_instr(&self.machine_st, &CodePtr::Local(p)) { + Some(line) => match line.as_ref(&self.code_repo.code) { Line::Control(ControlInstruction::CallClause(ref ct, ..)) => { if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct { return true; @@ -679,50 +563,6 @@ impl IndexStore { pub(super) fn new() -> Self { index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new()) } - - pub(super) fn get_cleaner_sites(&self) -> (usize, usize) { - let r_w_h = atom!("run_cleaners_with_handling"); - let r_wo_h = atom!("run_cleaners_without_handling"); - let iso_ext = atom!("iso_ext"); - - let r_w_h = self - .get_predicate_code_index(r_w_h, 0, iso_ext) - .and_then(|item| item.local()); - let r_wo_h = self - .get_predicate_code_index(r_wo_h, 1, iso_ext) - .and_then(|item| item.local()); - - if let Some(r_w_h) = r_w_h { - if let Some(r_wo_h) = r_wo_h { - return (r_w_h, r_wo_h); - } - } - - return (0, 0); - } } pub(crate) type CodeDir = IndexMap; - -pub(crate) enum RefOrOwned<'a, T: 'a> { - Borrowed(&'a T), - Owned(T), -} - -impl<'a, T: 'a + fmt::Debug> fmt::Debug for RefOrOwned<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &RefOrOwned::Borrowed(ref borrowed) => write!(f, "Borrowed({:?})", borrowed), - &RefOrOwned::Owned(ref owned) => write!(f, "Owned({:?})", owned), - } - } -} - -impl<'a, T> RefOrOwned<'a, T> { - pub(crate) fn as_ref(&'a self) -> &'a T { - match self { - &RefOrOwned::Borrowed(r) => r, - &RefOrOwned::Owned(ref r) => r, - } - } -} diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 68330be7..6bd29da2 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -1,11 +1,9 @@ use crate::arena::*; use crate::atom_table::*; -use crate::parser::ast::*; - -use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; use crate::heap_print::*; +use crate::machine::Machine; use crate::machine::attributed_variables::*; use crate::machine::copier::*; use crate::machine::heap::*; @@ -13,20 +11,15 @@ use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::stack::*; use crate::machine::streams::*; +use crate::parser::ast::*; use crate::types::*; use crate::parser::rug::Integer; -use downcast::{ - downcast, downcast_methods, downcast_methods_core, downcast_methods_std, impl_downcast, Any, -}; - use indexmap::IndexMap; -use std::cmp::Ordering; use std::convert::TryFrom; use std::fmt; -use std::mem; use std::ops::{Index, IndexMut}; use std::rc::Rc; @@ -83,6 +76,9 @@ pub struct MachineState { pub(super) ball: Ball, pub(super) lifted_heap: Heap, pub(super) interms: Vec, // intermediate numbers. + // locations of cleaners, cut points, the previous block. for setup_call_cleanup. + pub(super) cont_pts: Vec<(HeapCellValue, usize, usize)>, + pub(super) cwil: CWIL, pub(super) last_call: bool, // TODO: REMOVE THIS. pub(crate) flags: MachineFlags, pub(crate) cc: usize, @@ -90,6 +86,8 @@ pub struct MachineState { pub(crate) dynamic_mode: FirstOrNext, pub(crate) unify_fn: fn(&mut MachineState), pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue), + pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool, + pub(crate) increment_call_count_fn: fn(&mut MachineState) -> CallResult, } impl fmt::Debug for MachineState { @@ -178,505 +176,6 @@ impl IndexMut for MachineState { pub type CallResult = Result<(), Vec>; -pub trait CutPolicy: Any + fmt::Debug { - // returns true iff we fail or cut redirected the MachineState's p itself - fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool; -} - -downcast!(dyn CutPolicy); - -pub trait CallPolicy: Any + fmt::Debug { - fn retry_me_else( - &mut self, - machine_st: &mut MachineState, - offset: usize, - global_variables: &mut GlobalVarDir, - ) -> CallResult { - let b = machine_st.b; - let or_frame = machine_st.stack.index_or_frame_mut(b); - let n = or_frame.prelude.univ_prelude.num_cells; - - for i in 0..n { - machine_st.registers[i + 1] = or_frame[i]; - } - - machine_st.num_of_args = n; - machine_st.e = or_frame.prelude.e; - machine_st.cp = or_frame.prelude.cp; - - or_frame.prelude.bp = machine_st.p.local() + offset; - - let old_tr = or_frame.prelude.tr; - let curr_tr = machine_st.tr; - let target_h = or_frame.prelude.h; - - machine_st.tr = or_frame.prelude.tr; - - machine_st.attr_var_init.reset(); - machine_st.hb = machine_st.heap.len(); - machine_st.p += 1; - - machine_st.unwind_trail(old_tr, curr_tr, global_variables); - - machine_st.trail.truncate(machine_st.tr); - machine_st.heap.truncate(target_h); - - Ok(()) - } - - fn retry( - &mut self, - machine_st: &mut MachineState, - offset: usize, - global_variables: &mut GlobalVarDir, - ) -> CallResult { - let b = machine_st.b; - let or_frame = machine_st.stack.index_or_frame_mut(b); - let n = or_frame.prelude.univ_prelude.num_cells; - - for i in 0..n { - machine_st.registers[i+1] = or_frame[i]; - } - - machine_st.num_of_args = n; - machine_st.e = or_frame.prelude.e; - machine_st.cp = or_frame.prelude.cp; - - // WAS: or_frame.prelude.bp = machine_st.p.local() + 1; - or_frame.prelude.biip += 1; - - let old_tr = or_frame.prelude.tr; - let curr_tr = machine_st.tr; - let target_h = or_frame.prelude.h; - - machine_st.tr = or_frame.prelude.tr; - machine_st.attr_var_init.reset(); - - machine_st.unwind_trail(old_tr, curr_tr, global_variables); - - machine_st.trail.truncate(machine_st.tr); - machine_st.heap.truncate(target_h); - - machine_st.hb = machine_st.heap.len(); - machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); - - machine_st.oip = 0; - machine_st.iip = 0; - - Ok(()) - } - - fn trust( - &mut self, - machine_st: &mut MachineState, - offset: usize, - global_variables: &mut GlobalVarDir, - ) -> CallResult { - let b = machine_st.b; - let or_frame = machine_st.stack.index_or_frame(b); - let n = or_frame.prelude.univ_prelude.num_cells; - - for i in 0..n { - machine_st.registers[i+1] = or_frame[i]; - } - - machine_st.num_of_args = n; - machine_st.e = or_frame.prelude.e; - machine_st.cp = or_frame.prelude.cp; - - let old_tr = or_frame.prelude.tr; - let curr_tr = machine_st.tr; - let target_h = or_frame.prelude.h; - - machine_st.tr = or_frame.prelude.tr; - - machine_st.attr_var_init.reset(); - machine_st.b = or_frame.prelude.b; - - machine_st.unwind_trail(old_tr, curr_tr, global_variables); - - machine_st.trail.truncate(machine_st.tr); - machine_st.stack.truncate(b); - machine_st.heap.truncate(target_h); - - machine_st.hb = machine_st.heap.len(); - machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); - - machine_st.oip = 0; - machine_st.iip = 0; - - Ok(()) - } - - fn trust_me( - &mut self, - machine_st: &mut MachineState, - global_variables: &mut GlobalVarDir, - ) -> CallResult { - let b = machine_st.b; - let or_frame = machine_st.stack.index_or_frame(b); - let n = or_frame.prelude.univ_prelude.num_cells; - - for i in 0..n { - machine_st.registers[i+1] = or_frame[i]; - } - - machine_st.num_of_args = n; - machine_st.e = or_frame.prelude.e; - machine_st.cp = or_frame.prelude.cp; - - let old_tr = or_frame.prelude.tr; - let curr_tr = machine_st.tr; - let target_h = or_frame.prelude.h; - - machine_st.tr = or_frame.prelude.tr; - - machine_st.attr_var_init.reset(); - machine_st.b = or_frame.prelude.b; - - machine_st.unwind_trail(old_tr, curr_tr, global_variables); - - machine_st.trail.truncate(machine_st.tr); - machine_st.stack.truncate(b); - machine_st.heap.truncate(target_h); - - machine_st.hb = machine_st.heap.len(); - machine_st.p += 1; - - Ok(()) - } - - fn context_call( - &mut self, - machine_st: &mut MachineState, - name: Atom, - arity: usize, - idx: &CodeIndex, - ) -> CallResult { - if machine_st.last_call { - self.try_execute(machine_st, name, arity, idx) - } else { - self.try_call(machine_st, name, arity, idx) - } - } - - fn try_call( - &mut self, - machine_st: &mut MachineState, - name: Atom, - arity: usize, - idx: &CodeIndex, - ) -> CallResult { - match idx.get() { - IndexPtr::DynamicUndefined => { - machine_st.fail = true; - return Ok(()); - } - IndexPtr::Undefined => { - return Err(machine_st.throw_undefined_error(name, arity)); - } - IndexPtr::DynamicIndex(compiled_tl_index) => { - machine_st.dynamic_mode = FirstOrNext::First; - machine_st.call_at_index(arity, dir_entry!(compiled_tl_index)); - } - IndexPtr::Index(compiled_tl_index) => { - machine_st.call_at_index(arity, dir_entry!(compiled_tl_index)); - } - } - - Ok(()) - } - - fn try_execute( - &mut self, - machine_st: &mut MachineState, - name: Atom, - arity: usize, - idx: &CodeIndex, - ) -> CallResult { - match idx.get() { - IndexPtr::DynamicUndefined => { - machine_st.fail = true; - return Ok(()); - } - IndexPtr::Undefined => { - return Err(machine_st.throw_undefined_error(name, arity)); - } - IndexPtr::DynamicIndex(compiled_tl_index) => { - machine_st.dynamic_mode = FirstOrNext::First; - machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index)); - } - IndexPtr::Index(compiled_tl_index) => { - machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index)) - } - } - - Ok(()) - } - - fn call_builtin( - &mut self, - machine_st: &mut MachineState, - ct: &BuiltInClauseType, - _code_dir: &CodeDir, - op_dir: &OpDir, - stream_aliases: &StreamAliasDir, - ) -> CallResult { - match ct { - &BuiltInClauseType::AcyclicTerm => { - let addr = machine_st.registers[1]; - machine_st.fail = machine_st.is_cyclic_term(addr); - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::Arg => { - machine_st.try_arg()?; - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::Compare => { - let stub_gen = || functor_stub(atom!("compare"), 3); - - let a1 = machine_st.store(machine_st.deref(machine_st.registers[1])); - let a2 = machine_st.registers[2]; - let a3 = machine_st.registers[3]; - - read_heap_cell!(a1, - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(machine_st.heap[s]) - .get_name_and_arity(); - - match name { - atom!(">") | atom!("<") | atom!("=") if arity == 2 => { - } - _ => { - let err = machine_st.domain_error(DomainErrorType::Order, a1); - return Err(machine_st.error_form(err, stub_gen())); - } - } - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - } - _ => { - let err = machine_st.type_error(ValidType::Atom, a1); - return Err(machine_st.error_form(err, stub_gen())); - } - ); - - let atom = match compare_term_test!(machine_st, a2, a3) { - Some(Ordering::Greater) => { - atom!(">") - } - Some(Ordering::Equal) => { - atom!("=") - } - None | Some(Ordering::Less) => { - atom!("<") - } - }; - - machine_st.unify_atom(atom, a1); - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::CompareTerm(qt) => { - machine_st.compare_term(qt); - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::Read => { - let stream = machine_st.get_stream_or_alias( - machine_st.registers[1], - stream_aliases, - atom!("read"), - 2, - )?; - - match machine_st.read(stream, op_dir) { - Ok(offset) => { - let value = machine_st.registers[2]; - unify_fn!(machine_st, value, heap_loc_as_cell!(offset.heap_loc)); - } - Err(ParserError::UnexpectedEOF) => { - let value = machine_st.registers[2]; - machine_st.unify_atom(atom!("end_of_file"), value); - } - Err(e) => { - let stub = functor_stub(atom!("read"), 2); - let err = machine_st.syntax_error(e); - - return Err(machine_st.error_form(err, stub)); - } - }; - - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::CopyTerm => { - machine_st.copy_term(AttrVarPolicy::DeepCopy); - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::Eq => { - let a1 = machine_st.registers[1]; - let a2 = machine_st.registers[2]; - - machine_st.fail = machine_st.eq_test(a1, a2); - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::Ground => { - machine_st.fail = machine_st.ground_test(); - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::Functor => { - machine_st.try_functor()?; - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::NotEq => { - let a1 = machine_st.registers[1]; - let a2 = machine_st.registers[2]; - - machine_st.fail = - if let Some(Ordering::Equal) = compare_term_test!(machine_st, a1, a2) { - true - } else { - false - }; - - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::Sort => { - machine_st.check_sort_errors()?; - - let stub_gen = || functor_stub(atom!("sort"), 2); - let mut list = machine_st.try_from_list(machine_st.registers[1], stub_gen)?; - - list.sort_unstable_by(|v1, v2| { - compare_term_test!(machine_st, *v1, *v2).unwrap_or(Ordering::Less) - }); - - list.dedup_by(|v1, v2| { - compare_term_test!(machine_st, *v1, *v2) == Some(Ordering::Equal) - }); - - let heap_addr = heap_loc_as_cell!( - iter_to_heap_list(&mut machine_st.heap, list.into_iter()) - ); - - let r2 = machine_st.registers[2]; - unify_fn!(machine_st, r2, heap_addr); - - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::KeySort => { - machine_st.check_keysort_errors()?; - - let stub_gen = || functor_stub(atom!("keysort"), 2); - let list = machine_st.try_from_list(machine_st.registers[1], stub_gen)?; - - let mut key_pairs = Vec::with_capacity(list.len()); - - for val in list { - let key = machine_st.project_onto_key(val)?; - key_pairs.push((key, val)); - } - - key_pairs.sort_by(|a1, a2| { - compare_term_test!(machine_st, a1.0, a2.0).unwrap_or(Ordering::Less) - }); - - let key_pairs = key_pairs.into_iter().map(|kp| kp.1); - let heap_addr = heap_loc_as_cell!( - iter_to_heap_list(&mut machine_st.heap, key_pairs) - ); - - let r2 = machine_st.registers[2]; - unify_fn!(machine_st, r2, heap_addr); - - return_from_clause!(machine_st.last_call, machine_st) - } - &BuiltInClauseType::Is(r, ref at) => { - let n1 = machine_st.store(machine_st.deref(machine_st[r])); - let n2 = machine_st.get_number(at)?; - - match n2 { - Number::Fixnum(n) => machine_st.unify_fixnum(n, n1), - Number::Float(n) => { - // TODO: argghh.. deal with it. - let n = arena_alloc!(n, &mut machine_st.arena); - machine_st.unify_f64(n, n1) - } - Number::Integer(n) => machine_st.unify_big_int(n, n1), - Number::Rational(n) => machine_st.unify_rational(n, n1), - } - - return_from_clause!(machine_st.last_call, machine_st) - } - } - } - - fn call_clause_type( - &mut self, - machine_st: &mut MachineState, - key: PredicateKey, - code_dir: &CodeDir, - op_dir: &OpDir, - stream_aliases: &StreamAliasDir, - ) -> CallResult { - let (name, arity) = key; - - match ClauseType::from(name, arity) { - ClauseType::BuiltIn(built_in) => { - machine_st.setup_built_in_call(built_in); - self.call_builtin(machine_st, &built_in, code_dir, op_dir, stream_aliases)?; - } - ClauseType::CallN => { - machine_st.handle_internal_call_n(arity); - - if machine_st.fail { - return Ok(()); - } - - machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call); - } - ClauseType::Inlined(inlined) => { - machine_st.execute_inlined(&inlined); - - if machine_st.last_call { - machine_st.p = CodePtr::Local(machine_st.cp); - } - } - ClauseType::Named(..) => { - if let Some(idx) = code_dir.get(&(name, arity)) { - self.context_call(machine_st, name, arity, idx)?; - } else { - return Err(machine_st.throw_undefined_error(name, arity)); - } - } - ClauseType::System(_) => { - let (name, arity) = key; - let name = functor!(name); - - let stub = functor_stub(atom!("call"), arity + 1); - let err = machine_st.type_error(ValidType::Callable, name); - - return Err(machine_st.error_form(err, stub)); - } - } - - Ok(()) - } - - fn call_n( - &mut self, - machine_st: &mut MachineState, - arity: usize, - code_dir: &CodeDir, - op_dir: &OpDir, - stream_aliases: &StreamAliasDir, - ) -> CallResult { - if let Some(key) = machine_st.setup_call_n(arity) { - self.call_clause_type(machine_st, key, code_dir, op_dir, stream_aliases)?; - } - - Ok(()) - } -} - #[inline(always)] pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) { read_heap_cell!(heap[index], @@ -866,6 +365,26 @@ impl<'a> CopierTarget for CopyBallTerm<'a> { } impl MachineState { + pub(crate) fn increment_call_count(&mut self) -> CallResult { + if self.cwil.inference_limit_exceeded || self.ball.stub.len() > 0 { + return Ok(()); + } + + if let Some(&(ref limit, bp)) = self.cwil.limits.last() { + if self.cwil.count == *limit { + self.cwil.inference_limit_exceeded = true; + + return Err( + functor!(atom!("inference_limit_exceeded"), [fixnum(bp)]) + ); + } else { + self.cwil.count += 1; + } + } + + Ok(()) + } + #[allow(dead_code)] pub(super) fn try_char_list(&mut self, addrs: Vec) -> Result { let mut chars = String::new(); @@ -958,7 +477,7 @@ impl MachineState { match self.read(stream, &indices.op_dir) { Ok(term_write_result) => { let term = self.registers[2]; - unify_fn!(self, heap_loc_as_cell!(term_write_result.heap_loc), term); + unify_fn!(*self, heap_loc_as_cell!(term_write_result.heap_loc), term); let term = heap_loc_as_cell!(term_write_result.heap_loc); if self.fail { @@ -1004,7 +523,7 @@ impl MachineState { iter_to_heap_list(&mut self.heap, singleton_var_list.into_iter()) ); - unify_fn!(self, singletons_offset, singleton_addr); + unify_fn!(*self, singletons_offset, singleton_addr); if self.fail { return Ok(()); @@ -1015,7 +534,7 @@ impl MachineState { iter_to_heap_list(&mut self.heap, var_list.into_iter()) ); - unify_fn!(self, vars_offset, vars_addr); + unify_fn!(*self, vars_offset, vars_addr); if self.fail { return Ok(()); @@ -1026,7 +545,7 @@ impl MachineState { iter_to_heap_list(&mut self.heap, list_of_var_eqs.into_iter()) ); - return Ok(unify_fn!(self, var_names_offset, var_names_addr)); + return Ok(unify_fn!(*self, var_names_offset, var_names_addr)); } Err(err) => { if let ParserError::UnexpectedEOF = err { @@ -1163,83 +682,96 @@ impl MachineState { (name, usize::try_from(arity.get_num()).unwrap()) } - pub(super) fn module_lookup( - &mut self, - indices: &IndexStore, - call_policy: &mut Box, - key: PredicateKey, - module_name: Atom, - _last_call: bool, - stream_aliases: &StreamAliasDir, - ) -> CallResult { - if module_name == atom!("user") { - return call_policy.call_clause_type( - self, - key, - &indices.code_dir, - &indices.op_dir, - stream_aliases, - ); - } else if let Some(module) = indices.modules.get(&module_name) { - return call_policy.call_clause_type( - self, - key, - &module.code_dir, - &module.op_dir, - stream_aliases, - ); + #[inline(always)] + pub(super) fn cut_body(&mut self, value: HeapCellValue) { + let b = self.b; + + read_heap_cell!(value, + (HeapCellValueTag::Fixnum, b0) => { + let b0 = b0.get_num() as usize; + + if b > b0 { + self.b = b0; + } + } + _ => { + self.fail = true; + } + ); + } + + #[inline(always)] + pub(super) fn try_me_else(&mut self, offset: usize) { + let n = self.num_of_args; + let b = self.stack.allocate_or_frame(n); + let or_frame = self.stack.index_or_frame_mut(b); + + or_frame.prelude.univ_prelude.num_cells = n; + or_frame.prelude.e = self.e; + or_frame.prelude.cp = self.cp; + or_frame.prelude.b = self.b; + or_frame.prelude.bp = self.p.local() + offset; + or_frame.prelude.boip = 0; + or_frame.prelude.biip = 0; + or_frame.prelude.tr = self.tr; + or_frame.prelude.h = self.heap.len(); + or_frame.prelude.b0 = self.b0; + + self.b = b; + + for i in 0..n { + self.stack[stack_loc!(OrFrame, b, i)] = self.registers[i+1]; } - let (name, arity) = key; + self.hb = self.heap.len(); + self.p += 1; + } - let stub = functor_stub(name, arity); - let err = self.module_resolution_error(module_name, name, arity); + #[inline(always)] + pub(super) fn indexed_try(&mut self, offset: usize) { + let n = self.num_of_args; + let b = self.stack.allocate_or_frame(n); + let or_frame = self.stack.index_or_frame_mut(b); + + or_frame.prelude.univ_prelude.num_cells = n; + or_frame.prelude.e = self.e; + or_frame.prelude.cp = self.cp; + or_frame.prelude.b = self.b; + or_frame.prelude.bp = self.p.local(); // + 1; in self.iip now! + or_frame.prelude.boip = self.oip; + or_frame.prelude.biip = self.iip + 1; + or_frame.prelude.tr = self.tr; + or_frame.prelude.h = self.heap.len(); + or_frame.prelude.b0 = self.b0; + + self.b = b; - return Err(self.error_form(err, stub)); + for i in 0..n { + or_frame[i] = self.registers[i+1]; + } + + self.hb = self.heap.len(); + self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset)); + + self.oip = 0; + self.iip = 0; } } #[derive(Debug)] -pub(crate) struct CWILCallPolicy { - pub(crate) prev_policy: Box, +pub(crate) struct CWIL { count: Integer, limits: Vec<(Integer, usize)>, inference_limit_exceeded: bool, } -impl CWILCallPolicy { - pub(crate) fn new_in_place(policy: &mut Box) { - let mut prev_policy: Box = Box::new(DefaultCallPolicy {}); - mem::swap(&mut prev_policy, policy); - - let new_policy = CWILCallPolicy { - prev_policy, +impl CWIL { + pub(crate) fn new() -> Self { + CWIL { count: Integer::from(0), limits: vec![], inference_limit_exceeded: false, - }; - - *policy = Box::new(new_policy); - } - - fn increment(&mut self, machine_st: &MachineState) -> CallResult { - if self.inference_limit_exceeded || machine_st.ball.stub.len() > 0 { - return Ok(()); } - - if let Some(&(ref limit, bp)) = self.limits.last() { - if self.count == *limit { - self.inference_limit_exceeded = true; - - return Err( - functor!(atom!("inference_limit_exceeded"), [fixnum(bp)]) - ); - } else { - self.count += 1; - } - } - - Ok(()) } pub(crate) fn add_limit(&mut self, limit: usize, b: usize) -> &Integer { @@ -1254,6 +786,7 @@ impl CWILCallPolicy { &self.count } + #[inline(always)] pub(crate) fn remove_limit(&mut self, b: usize) -> &Integer { if let Some((_, bp)) = self.limits.last() { if bp == &b { @@ -1264,207 +797,15 @@ impl CWILCallPolicy { &self.count } - pub(crate) fn is_empty(&self) -> bool { - self.limits.is_empty() - } - - pub(crate) fn into_inner(&mut self) -> Box { - let mut new_inner: Box = Box::new(DefaultCallPolicy {}); - mem::swap(&mut self.prev_policy, &mut new_inner); - new_inner - } -} - -impl CallPolicy for CWILCallPolicy { - fn context_call( - &mut self, - machine_st: &mut MachineState, - name: Atom, - arity: usize, - idx: &CodeIndex, - ) -> CallResult { - self.prev_policy.context_call(machine_st, name, arity, idx)?; - self.increment(machine_st) - } - - fn retry_me_else( - &mut self, - machine_st: &mut MachineState, - offset: usize, - global_variables: &mut GlobalVarDir, - ) -> CallResult { - self.prev_policy.retry_me_else(machine_st, offset, global_variables)?; - self.increment(machine_st) - } - - fn retry( - &mut self, - machine_st: &mut MachineState, - offset: usize, - global_variables: &mut GlobalVarDir, - ) -> CallResult { - self.prev_policy.retry(machine_st, offset, global_variables)?; - self.increment(machine_st) - } - - fn trust_me( - &mut self, - machine_st: &mut MachineState, - global_variables: &mut GlobalVarDir, - ) -> CallResult { - self.prev_policy.trust_me(machine_st, global_variables)?; - self.increment(machine_st) - } - - fn trust( - &mut self, - machine_st: &mut MachineState, - offset: usize, - global_variables: &mut GlobalVarDir, - ) -> CallResult { - self.prev_policy.trust(machine_st, offset, global_variables)?; - self.increment(machine_st) - } - - fn call_builtin( - &mut self, - machine_st: &mut MachineState, - ct: &BuiltInClauseType, - code_dir: &CodeDir, - op_dir: &OpDir, - stream_aliases: &StreamAliasDir, - ) -> CallResult { - self.prev_policy.call_builtin(machine_st, ct, code_dir, op_dir, stream_aliases)?; - self.increment(machine_st) - } - - fn call_n( - &mut self, - machine_st: &mut MachineState, - arity: usize, - code_dir: &CodeDir, - op_dir: &OpDir, - stream_aliases: &StreamAliasDir, - ) -> CallResult { - self.prev_policy.call_n(machine_st, arity, code_dir, op_dir, stream_aliases)?; - self.increment(machine_st) - } -} - -downcast!(dyn CallPolicy); - -#[derive(Debug)] -pub(crate) struct DefaultCallPolicy {} - -impl CallPolicy for DefaultCallPolicy {} - -fn cut_body(machine_st: &mut MachineState, addr: HeapCellValue) -> bool { - let b = machine_st.b; - - read_heap_cell!(addr, - (HeapCellValueTag::Fixnum, b0) => { - let b0 = b0.get_num() as usize; - - if b > b0 { - machine_st.b = b0; - } - } - _ => { - machine_st.fail = true; - return true; - } - ); - - false -} - -#[derive(Debug)] -pub(crate) struct DefaultCutPolicy {} - -pub(super) fn deref_cut(machine_st: &mut MachineState, r: RegType) { - let addr = machine_st.store(machine_st.deref(machine_st[r])); - cut_body(machine_st, addr); -} - -impl CutPolicy for DefaultCutPolicy { - fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool { - let addr = machine_st[r]; - cut_body(machine_st, addr) - } -} - -#[derive(Debug)] -pub(crate) struct SCCCutPolicy { - // locations of cleaners, cut points, the previous block - cont_pts: Vec<(HeapCellValue, usize, usize)>, - r_c_w_h: usize, - r_c_wo_h: usize, -} - -impl SCCCutPolicy { - pub(crate) fn new(r_c_w_h: usize, r_c_wo_h: usize) -> Self { - SCCCutPolicy { - cont_pts: vec![], - r_c_w_h, - r_c_wo_h, - } - } - - pub(crate) fn out_of_cont_pts(&self) -> bool { - self.cont_pts.is_empty() - } - - pub(crate) fn push_cont_pt(&mut self, addr: HeapCellValue, b: usize, prev_b: usize) { - self.cont_pts.push((addr, b, prev_b)); - } - - pub(crate) fn pop_cont_pt(&mut self) -> Option<(HeapCellValue, usize, usize)> { - self.cont_pts.pop() - } - - fn run_cleaners(&self, machine_st: &mut MachineState) -> bool { - if let Some(&(_, b_cutoff, prev_block)) = self.cont_pts.last() { - if machine_st.b < b_cutoff { - let (idx, arity) = if machine_st.block > prev_block { - (dir_entry!(self.r_c_w_h), 0) - } else { - machine_st.registers[1] = fixnum_as_cell!(Fixnum::build_with(b_cutoff as i64)); - (dir_entry!(self.r_c_wo_h), 1) - }; - - if machine_st.last_call { - machine_st.execute_at_index(arity, idx); - } else { - machine_st.call_at_index(arity, idx); - } - - return true; - } - } - - false + #[inline(always)] + pub(crate) fn reset(&mut self) { + self.count = Integer::from(0); + self.limits.clear(); + self.inference_limit_exceeded = false; } -} - -impl CutPolicy for SCCCutPolicy { - fn cut(&mut self, machine_st: &mut MachineState, r: RegType) -> bool { - let b = machine_st.b; - read_heap_cell!(machine_st[r], - (HeapCellValueTag::Fixnum, b0) => { - let b0 = b0.get_num() as usize; - - if b > b0 { - machine_st.b = b0; - } - } - _ => { - machine_st.fail = true; - return true; - } - ); - - self.run_cleaners(machine_st) + #[inline(always)] + pub(crate) fn is_empty(&self) -> bool { + self.limits.is_empty() } } - diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 1c6922d5..ee04d645 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -4,24 +4,18 @@ use crate::types::*; use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; -use crate::instructions::*; -use crate::machine::arithmetic_ops::*; use crate::machine::attributed_variables::*; -use crate::machine::code_repo::CodeRepo; use crate::machine::copier::*; use crate::machine::heap::*; +use crate::machine::Machine; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; use crate::machine::partial_string::*; use crate::machine::stack::*; -use crate::machine::streams::*; -use crate::machine::INTERRUPT; use crate::parser::ast::*; use crate::parser::rug::{Integer, Rational}; -use crate::try_numeric_result; - use ordered_float::*; use indexmap::IndexSet; @@ -29,6 +23,11 @@ use indexmap::IndexSet; use std::cmp::Ordering; use std::convert::TryFrom; +// TODO: move this block to.. a place. +impl Machine { + +} + impl MachineState { pub(crate) fn new() -> Self { MachineState { @@ -56,7 +55,9 @@ impl MachineState { block: 0, ball: Ball::new(), lifted_heap: Heap::new(), - interms: vec![Number::default(); 256], + interms: vec![Number::default();256], + cont_pts: Vec::with_capacity(256), + cwil: CWIL::new(), last_call: false, flags: MachineFlags::default(), cc: 0, @@ -64,6 +65,8 @@ impl MachineState { dynamic_mode: FirstOrNext::First, unify_fn: MachineState::unify, bind_fn: MachineState::bind, + run_cleaners_fn: |_| { false }, + increment_call_count_fn: |_| { Ok(()) }, } } @@ -869,7 +872,7 @@ impl MachineState { copy_term(CopyTerm::new(self), a1, attr_var_policy); - unify_fn!(self, heap_loc_as_cell!(old_h), a2); + unify_fn!(*self, heap_loc_as_cell!(old_h), a2); } pub(super) fn unwind_stack(&mut self) { @@ -1405,7 +1408,7 @@ impl MachineState { } } - fn read_s(&mut self) -> HeapCellValue { + pub(crate) fn read_s(&mut self) -> HeapCellValue { match &self.s { &HeapPtr::HeapCell(h) => self.deref(self.heap[h]), &HeapPtr::PStrChar(h, n) => { @@ -1837,7 +1840,7 @@ impl MachineState { Some(Ordering::Equal) } - fn increment_s_ptr(&mut self, rhs: usize) { + pub(crate) fn increment_s_ptr(&mut self, rhs: usize) { match &mut self.s { HeapPtr::HeapCell(ref mut h) => { *h += rhs; @@ -1861,58 +1864,6 @@ impl MachineState { } } - pub(super) fn unwind_trail( - &mut self, - a1: usize, - a2: usize, - global_variables: &mut GlobalVarDir, - ) { - // the sequence is reversed to respect the chronology of trail - // additions, now that deleted attributes can be undeleted by - // backtracking. - for i in (a1..a2).rev() { - let h = self.trail[i].get_value() as usize; - - match self.trail[i].get_tag() { - TrailEntryTag::TrailedHeapVar => { - self.heap[h] = heap_loc_as_cell!(h); - } - TrailEntryTag::TrailedStackVar => { - self.stack[h] = stack_loc_as_cell!(h); - } - TrailEntryTag::TrailedAttrVar => { - self.heap[h] = attr_var_as_cell!(h); - } - TrailEntryTag::TrailedAttrVarHeapLink => { - self.heap[h] = heap_loc_as_cell!(h); - } - TrailEntryTag::TrailedAttrVarListLink => { - let l = self.trail[i + 1].get_value(); - self.heap[h] = list_loc_as_cell!(l); - } - TrailEntryTag::TrailedBlackboardEntry => { - let key = Atom::from(h); - - match global_variables.get_mut(&key) { - Some((_, ref mut loc)) => *loc = None, - None => unreachable!(), - } - } - TrailEntryTag::TrailedBlackboardOffset => { - let key = Atom::from(h); - let value_cell = HeapCellValue::from(u64::from(self.trail[i + 1])); - - match global_variables.get_mut(&key) { - Some((_, ref mut loc)) => *loc = Some(value_cell), - None => unreachable!(), - } - } - TrailEntryTag::TrailedAttachedValue => { - } - } - } - } - pub fn match_partial_string(&mut self, value: HeapCellValue, string: Atom, has_tail: bool) { let h = self.heap.len(); self.heap.push(value); @@ -2045,1035 +1996,191 @@ impl MachineState { ) } - pub fn execute_arith_instr(&mut self, instr: &ArithmeticInstruction) { - let stub_gen = || functor_stub(atom!("is"), 2); - - match instr { - &ArithmeticInstruction::Add(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!( - self, - try_numeric_result!(add(n1, n2, &mut self.arena), stub_gen) - ); - self.p += 1; - } - &ArithmeticInstruction::Sub(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!( - self, - try_numeric_result!(sub(n1, n2, &mut self.arena), stub_gen) - ); - self.p += 1; - } - &ArithmeticInstruction::Mul(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!( - self, - try_numeric_result!(mul(n1, n2, &mut self.arena), stub_gen) - ); - self.p += 1; - } - &ArithmeticInstruction::Max(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!(self, max(n1, n2)); - self.p += 1; - } - &ArithmeticInstruction::Min(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!(self, min(n1, n2)); - self.p += 1; - } - &ArithmeticInstruction::IntPow(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!(self, int_pow(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!(self, gcd(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Pow(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!(self, pow(n1, n2, atom!("**"))); - self.p += 1; - } - &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => { - let stub_gen = || functor_stub(atom!("(rdiv)"), 2); - - let r1 = try_or_fail!(self, self.get_rational(a1, stub_gen)); - let r2 = try_or_fail!(self, self.get_rational(a2, stub_gen)); - - self.interms[t - 1] = Number::Rational(arena_alloc!( - try_or_fail_gen!(self, rdiv(r1, r2)), - self.arena - )); - self.p += 1; - } - &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = - try_or_fail_gen!(self, int_floor_div(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!(self, idiv(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Abs(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - - self.interms[t - 1] = abs(n1, &mut self.arena); - self.p += 1; - } - &ArithmeticInstruction::Sign(ref a1, t) => { - let n = try_or_fail!(self, self.get_number(a1)); - - self.interms[t - 1] = sign(n); - self.p += 1; - } - &ArithmeticInstruction::Neg(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - - self.interms[t - 1] = neg(n1, &mut self.arena); - self.p += 1; - } - &ArithmeticInstruction::BitwiseComplement(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - - self.interms[t - 1] = - try_or_fail_gen!(self, bitwise_complement(n1, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Div(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!(self, div(n1, n2)); - self.p += 1; - } - &ArithmeticInstruction::Shr(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!(self, shr(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Shl(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!(self, shl(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Xor(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); - - self.interms[t - 1] = try_or_fail_gen!(self, xor(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::And(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); + pub(super) fn handle_internal_call_n(&mut self, arity: usize) { + let arity = arity + 1; + let pred = self.registers[1]; - self.interms[t - 1] = try_or_fail_gen!(self, and(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Or(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); + for i in 2..arity { + self.registers[i - 1] = self.registers[i]; + } - self.interms[t - 1] = try_or_fail_gen!(self, or(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Mod(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); + if arity > 1 { + self.registers[arity - 1] = pred; + return; + } - self.interms[t - 1] = try_or_fail_gen!(self, modulus(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Rem(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); + self.fail = true; + } - self.interms[t - 1] = try_or_fail_gen!(self, remainder(n1, n2, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Cos(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + pub(super) fn setup_call_n(&mut self, arity: usize) -> Option { + let addr = self.store(self.deref(self.registers[arity])); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, cos(n1)))); - self.p += 1; - } - &ArithmeticInstruction::Sin(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + let (name, narity) = read_heap_cell!(addr, + (HeapCellValueTag::Str, s) => { + let (name, narity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, sin(n1)))); - self.p += 1; - } - &ArithmeticInstruction::Tan(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + if narity + arity > MAX_ARITY { + let stub = functor_stub(atom!("call"), arity + 1); + let err = self.representation_error(RepFlag::MaxArity); + let representation_error = self.error_form(err, stub); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, tan(n1)))); - self.p += 1; - } - &ArithmeticInstruction::Sqrt(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + self.throw_exception(representation_error); + return None; + } - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, sqrt(n1)))); - self.p += 1; - } - &ArithmeticInstruction::Log(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + for i in (1..arity).rev() { + self.registers[i + narity] = self.registers[i]; + } - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, log(n1)))); - self.p += 1; - } - &ArithmeticInstruction::Exp(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + for i in 1..narity + 1 { + self.registers[i] = self.heap[s + i]; + } - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, exp(n1)))); - self.p += 1; + (name, narity) } - &ArithmeticInstruction::ACos(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, acos(n1)))); - self.p += 1; + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + (name, 0) + } else { + self.fail = true; + return None; + } } - &ArithmeticInstruction::ASin(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, asin(n1)))); - self.p += 1; + (HeapCellValueTag::Char, c) => { + (self.atom_tbl.build_with(&c.to_string()), 0) } - &ArithmeticInstruction::ATan(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, _h) => { + let stub = functor_stub(atom!("call"), arity + 1); + let err = self.instantiation_error(); + let instantiation_error = self.error_form(err, stub); - self.interms[t - 1] = Number::Float(OrderedFloat(try_or_fail_gen!(self, atan(n1)))); - self.p += 1; + self.throw_exception(instantiation_error); + return None; } - &ArithmeticInstruction::ATan2(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); - let n2 = try_or_fail!(self, self.get_number(a2)); + _ => { + let stub = functor_stub(atom!("call"), arity + 1); + let err = self.type_error(ValidType::Callable, addr); + let type_error = self.error_form(err, stub); - self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail_gen!(self, atan2(n1, n2)))); - self.p += 1; + self.throw_exception(type_error); + return None; } - &ArithmeticInstruction::Float(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + ); - self.interms[t - 1] = - Number::Float(OrderedFloat(try_or_fail_gen!(self, float(n1)))); - self.p += 1; - } - &ArithmeticInstruction::Truncate(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + Some((name, arity + narity - 1)) + } - self.interms[t - 1] = truncate(n1, &mut self.arena); - self.p += 1; - } - &ArithmeticInstruction::Round(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + #[inline] + pub fn is_cyclic_term(&mut self, addr: HeapCellValue) -> bool { + if addr.is_constant() { + return false; + } - self.interms[t - 1] = try_or_fail_gen!(self, round(n1, &mut self.arena)); - self.p += 1; - } - &ArithmeticInstruction::Ceiling(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + let addr = self.store(self.deref(addr)); + let mut iter = stackful_preorder_iter(&mut self.heap, addr); - self.interms[t - 1] = ceiling(n1, &mut self.arena); - self.p += 1; - } - &ArithmeticInstruction::Floor(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + while let Some(value) = iter.next() { + if value.is_forwarded() { + let value = heap_bound_store(iter.heap, heap_bound_deref(iter.heap, value)); - self.interms[t - 1] = floor(n1, &mut self.arena); - self.p += 1; + if value.is_compound() { + return true; + } } - &ArithmeticInstruction::Plus(ref a1, t) => { - let n1 = try_or_fail!(self, self.get_number(a1)); + } - self.interms[t - 1] = n1; - self.p += 1; - } - }; + false } - pub fn execute_fact_instr(&mut self, instr: &FactInstruction) { - match instr { - &FactInstruction::GetConstant(_, c, reg) => { - let value = self.deref(self[reg]); - self.write_literal_to_var(value, c); - } - &FactInstruction::GetList(_, reg) => { - let deref_v = self.deref(self[reg]); - let store_v = self.store(deref_v); - - read_heap_cell!(store_v, - (HeapCellValueTag::PStrLoc, h) => { - let (h, n) = pstr_loc_and_offset(&self.heap, h); - - self.s = HeapPtr::PStrChar(h, n.get_num() as usize); - self.mode = MachineMode::Read; - } - (HeapCellValueTag::CStr) => { - let h = self.heap.len(); - self.heap.push(store_v); - - self.s = HeapPtr::PStrChar(h, 0); - self.mode = MachineMode::Read; - } - (HeapCellValueTag::Lis, l) => { - self.s = HeapPtr::HeapCell(l); - self.mode = MachineMode::Read; - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - let h = self.heap.len(); - - self.heap.push(list_loc_as_cell!(h+1)); - self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); + // arg(+N, +Term, ?Arg) + pub fn try_arg(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("arg"), 3); + let n = self.store(self.deref(self.registers[1])); - self.mode = MachineMode::Write; - } - _ => { - self.fail = true; - } - ); + read_heap_cell!(n, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + // 8.5.2.3 a) + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); } - &FactInstruction::GetPartialString(_, string, reg, has_tail) => { - let deref_v = self.deref(self[reg]); - let store_v = self.store(deref_v); - - read_heap_cell!(store_v, - (HeapCellValueTag::Str | HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar | - HeapCellValueTag::StackVar | HeapCellValueTag::Var | - HeapCellValueTag::CStr) => { - self.match_partial_string(store_v, string, has_tail); - } + _ => { + let n = match Number::try_from(n) { + Ok(Number::Fixnum(n)) => Number::Fixnum(n), + Ok(Number::Integer(n)) => Number::Integer(n), _ => { - self.fail = true; - } - ); - } - &FactInstruction::GetStructure(ref ct, arity, reg) => { - let deref_v = self.deref(self[reg]); - let store_v = self.store(deref_v); - - read_heap_cell!(store_v, - (HeapCellValueTag::Str, a) => { - let result = self.heap[a]; - - read_heap_cell!(result, - (HeapCellValueTag::Atom, (name, narity)) => { - if narity == arity && ct.name() == name { - self.s = HeapPtr::HeapCell(a + 1); - self.mode = MachineMode::Read; - } else { - self.fail = true; - } - } - _ => { - unreachable!(); - } - ); + let err = self.type_error(ValidType::Integer, n); + return Err(self.error_form(err, stub_gen())); } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - let h = self.heap.len(); - - self.heap.push(str_loc_as_cell!(h+1)); - self.heap.push(atom_as_cell!(ct.name(), arity)); + }; - self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); + if n < 0 { + // 8.5.2.3 e) + let err = self.domain_error(DomainErrorType::NotLessThanZero, n); + return Err(self.error_form(err, stub_gen())); + } - self.mode = MachineMode::Write; - } + let n = match n { + Number::Fixnum(n) => n.get_num() as usize, + Number::Integer(n) => n.to_usize().unwrap(), _ => { self.fail = true; + return Ok(()); } - ); - } - &FactInstruction::GetVariable(norm, arg) => { - self[norm] = self.registers[arg]; - } - &FactInstruction::GetValue(norm, arg) => { - let norm_addr = self[norm]; - let reg_addr = self.registers[arg]; + }; - unify_fn!(self, norm_addr, reg_addr); - } - &FactInstruction::UnifyConstant(v) => { - match self.mode { - MachineMode::Read => { - let addr = self.read_s(); + let term = self.deref(self.registers[2]); - self.write_literal_to_var(addr, v); - self.increment_s_ptr(1); - } - MachineMode::Write => { - self.heap.push(v); - } - }; - } - &FactInstruction::UnifyVariable(reg) => { - match self.mode { - MachineMode::Read => { - self[reg] = self.read_s(); - self.increment_s_ptr(1); + read_heap_cell!(self.store(term), + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let err = self.instantiation_error(); + return Err(self.error_form(err, stub_gen())); } - MachineMode::Write => { - let h = self.heap.len(); + (HeapCellValueTag::Str, o) => { + let arity = cell_as_atom_cell!(self.heap[o]).get_arity(); - self.heap.push(heap_loc_as_cell!(h)); - self[reg] = heap_loc_as_cell!(h); + if 1 <= n && n <= arity { + let a3 = self.registers[3]; + unify_fn!(*self, a3, heap_loc_as_cell!(o + n)); + } else { + self.fail = true; + } } - }; - } - &FactInstruction::UnifyLocalValue(reg) => { - match self.mode { - MachineMode::Read => { - let reg_addr = self[reg]; - let value = self.read_s(); - - unify_fn!(self, reg_addr, value); - self.increment_s_ptr(1); + (HeapCellValueTag::Lis, l) => { + if n == 1 || n == 2 { + let a3 = self.registers[3]; + unify_fn!(*self, a3, heap_loc_as_cell!(l + n - 1)); + } else { + self.fail = true; + } } - MachineMode::Write => { - let value = self.store(self.deref(self[reg])); - let h = self.heap.len(); - - read_heap_cell!(value, - (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => { - let value = self.heap[hc]; + (HeapCellValueTag::PStrLoc, pstr_loc) => { + if n == 1 || n == 2 { + let a3 = self.registers[3]; + let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc); - self.heap.push(value); - self.increment_s_ptr(1); + let pstr = cell_as_string!(self.heap[h]); + let offset = offset.get_num() as usize; - return; - } - _ => { - } - ); - - self.heap.push(heap_loc_as_cell!(h)); - (self.bind_fn)(self, Ref::heap_cell(h), value); - } - }; - } - &FactInstruction::UnifyValue(reg) => { - match self.mode { - MachineMode::Read => { - let reg_addr = self[reg]; - let value = self.read_s(); - - unify_fn!(self, reg_addr, value); - self.increment_s_ptr(1); - } - MachineMode::Write => { - let h = self.heap.len(); - self.heap.push(heap_loc_as_cell!(h)); - - let addr = self.store(self[reg]); - (self.bind_fn)(self, Ref::heap_cell(h), addr); - - // the former code of this match arm was: - - // let addr = self.store(self[reg]); - // self.heap.push(HeapCellValue::Addr(addr)); - - // the old code didn't perform the occurs - // check when enabled and so it was changed to - // the above, which is only slightly less - // efficient when the occurs_check is disabled. - } - }; - } - &FactInstruction::UnifyVoid(n) => { - match self.mode { - MachineMode::Read => { - self.increment_s_ptr(n); - } - MachineMode::Write => { - let h = self.heap.len(); - - for i in h..h + n { - self.heap.push(heap_loc_as_cell!(i)); - } - } - }; - } - }; - } - - pub(super) fn execute_indexing_instr( - &mut self, - indexing_lines: &Vec, - code_repo: &CodeRepo, - ) { - fn dynamic_external_of_clause_is_valid( - machine_st: &mut MachineState, - code: &Code, - p: usize, - ) -> bool { - match &code[p] { - Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => { - machine_st.dynamic_mode = FirstOrNext::First; - return true; - } - _ => {} - } - - match &code[p - 1] { - &Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => { - if birth < machine_st.cc && Death::Finite(machine_st.cc) <= death { - return true; - } else { - return false; - } - } - _ => {} - } - - true - } - - let mut index = 0; - let addr = match &indexing_lines[0] { - &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => { - self.store(self.deref(self[temp_v!(arg)])) - } - _ => { - unreachable!() - } - }; - - loop { - match &indexing_lines[index] { - &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => { - let offset = read_heap_cell!(addr, - (HeapCellValueTag::Var - | HeapCellValueTag::StackVar - | HeapCellValueTag::AttrVar) => { - v - } - (HeapCellValueTag::PStrLoc - | HeapCellValueTag::Lis - | HeapCellValueTag::CStr) => { - l - } - (HeapCellValueTag::Fixnum - | HeapCellValueTag::Char - | HeapCellValueTag::F64) => { - c - } - (HeapCellValueTag::Atom, (_name, arity)) => { - // if arity == 0 { c } else { s } - debug_assert!(arity == 0); - c - } - (HeapCellValueTag::Str) => { - s - } - (HeapCellValueTag::Cons, ptr) => { - match ptr.get_tag() { - ArenaHeaderTag::Rational | ArenaHeaderTag::Integer | - ArenaHeaderTag::F64 => { - c - } - _ => { - IndexingCodePtr::Fail - } - } - } - _ => { - unreachable!(); - } - ); - - match offset { - IndexingCodePtr::Fail => { - self.fail = true; - break; - } - IndexingCodePtr::DynamicExternal(o) => { - // either points directly to a - // DynamicInternalElse, or just ahead of - // one. Or neither! - let p = self.p.local().abs_loc(); - - if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) { - self.fail = true; - } else { - self.p += o; - } - - break; - } - IndexingCodePtr::External(o) => { - self.p += o; - break; - } - IndexingCodePtr::Internal(o) => { - index += o; - } - } - } - &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => { - let lit = read_heap_cell!(addr, - (HeapCellValueTag::Char, c) => { - Literal::Char(c) - } - (HeapCellValueTag::Fixnum, n) => { - Literal::Fixnum(n) - } - (HeapCellValueTag::F64, f) => { - Literal::Float(f) - } - (HeapCellValueTag::Atom, (atom, arity)) => { - debug_assert_eq!(arity, 0); - Literal::Atom(atom) - } - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::Rational, r) => { - Literal::Rational(r) - } - (ArenaHeaderTag::F64, f) => { - Literal::Float(F64Ptr(f)) - } - (ArenaHeaderTag::Integer, n) => { - Literal::Integer(n) - } - _ => { - unreachable!() - } - ) - } - _ => { - unreachable!() - } - ); - - let offset = match hm.get(&lit) { - Some(offset) => *offset, - _ => IndexingCodePtr::Fail, - }; - - match offset { - IndexingCodePtr::Fail => { - self.fail = true; - break; - } - IndexingCodePtr::DynamicExternal(o) => { - // either points directly to a - // DynamicInternalElse, or just ahead of - // one. Or neither! - let p = self.p.local().abs_loc(); - - if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) { - self.fail = true; - } else { - self.p += o; - } - - break; - } - IndexingCodePtr::External(o) => { - self.p += o; - break; - } - IndexingCodePtr::Internal(o) => { - index += o; - } - } - } - &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => { - let offset = read_heap_cell!(addr, - (HeapCellValueTag::Atom, (name, arity)) => { - match hm.get(&(name, arity)) { - Some(offset) => *offset, - None => IndexingCodePtr::Fail, - } - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); - - match hm.get(&(name, arity)) { - Some(offset) => *offset, - None => IndexingCodePtr::Fail, - } - } - _ => { - IndexingCodePtr::Fail - } - ); - - match offset { - IndexingCodePtr::Fail => { - self.fail = true; - break; - } - IndexingCodePtr::DynamicExternal(o) => { - let p = self.p.local().abs_loc(); - - if !dynamic_external_of_clause_is_valid(self, &code_repo.code, p + o) { - self.fail = true; - } else { - self.p += o; - } - - break; - } - IndexingCodePtr::External(o) => { - self.p += o; - break; - } - IndexingCodePtr::Internal(o) => { - index += o; - } - } - } - &IndexingLine::IndexedChoice(_) => { - if let LocalCodePtr::DirEntry(p) = self.p.local() { - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); - self.oip = index as u32; - self.iip = 0; - } else { - unreachable!() - } - - break; - } - &IndexingLine::DynamicIndexedChoice(_) => { - self.dynamic_mode = FirstOrNext::First; - - if let LocalCodePtr::DirEntry(p) = self.p.local() { - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); - self.oip = index as u32; - self.iip = 0; - } else { - unreachable!() - } - - break; - } - } - } - } - - pub(super) fn execute_query_instr(&mut self, instr: &QueryInstruction) { - match instr { - &QueryInstruction::GetVariable(norm, arg) => { - self[norm] = self.registers[arg]; - } - &QueryInstruction::PutConstant(_, c, reg) => { - self[reg] = c; - } - &QueryInstruction::PutList(_, reg) => { - self[reg] = list_loc_as_cell!(self.heap.len()); - } - &QueryInstruction::PutPartialString(_, string, reg, has_tail) => { - let pstr_addr = if has_tail { - if string != atom!("") { - let h = self.heap.len(); - self.heap.push(string_as_pstr_cell!(string)); - - // the tail will be pushed by the next - // instruction, so don't push one here. - - pstr_loc_as_cell!(h) - } else { - empty_list_as_cell!() - } - } else { - string_as_cstr_cell!(string) - }; - - self[reg] = pstr_addr; - } - &QueryInstruction::PutStructure(ref ct, arity, reg) => { - let h = self.heap.len(); - - self.heap.push(atom_as_cell!(ct.name(), arity)); - self[reg] = str_loc_as_cell!(h); - } - &QueryInstruction::PutUnsafeValue(n, arg) => { - let s = stack_loc!(AndFrame, self.e, n); - let addr = self.store(self.deref(stack_loc_as_cell!(s))); - - if addr.is_protected(self.e) { - self.registers[arg] = addr; - } else { - let h = self.heap.len(); - - self.heap.push(heap_loc_as_cell!(h)); - (self.bind_fn)(self, Ref::heap_cell(h), addr); - - self.registers[arg] = heap_loc_as_cell!(h); - } - } - &QueryInstruction::PutValue(norm, arg) => { - self.registers[arg] = self[norm]; - } - &QueryInstruction::PutVariable(norm, arg) => { - match norm { - RegType::Perm(n) => { - self[norm] = stack_loc_as_cell!(AndFrame, self.e, n); - self.registers[arg] = self[norm]; - } - RegType::Temp(_) => { - let h = self.heap.len(); - self.heap.push(heap_loc_as_cell!(h)); - - self[norm] = heap_loc_as_cell!(h); - self.registers[arg] = heap_loc_as_cell!(h); - } - }; - } - &QueryInstruction::SetConstant(c) => { - self.heap.push(c); - } - &QueryInstruction::SetLocalValue(reg) => { - let addr = self.deref(self[reg]); - let stored_v = self.store(addr); - - if stored_v.is_stack_var() { - let h = self.heap.len(); - self.heap.push(heap_loc_as_cell!(h)); - (self.bind_fn)(self, Ref::heap_cell(h), stored_v); - } else { - self.heap.push(stored_v); - } - } - &QueryInstruction::SetVariable(reg) => { - let h = self.heap.len(); - self.heap.push(heap_loc_as_cell!(h)); - self[reg] = heap_loc_as_cell!(h); - } - &QueryInstruction::SetValue(reg) => { - let heap_val = self.store(self[reg]); - self.heap.push(heap_val); - } - &QueryInstruction::SetVoid(n) => { - let h = self.heap.len(); - - for i in h..h + n { - self.heap.push(heap_loc_as_cell!(i)); - } - } - } - } - - pub(super) fn handle_internal_call_n(&mut self, arity: usize) { - let arity = arity + 1; - let pred = self.registers[1]; - - for i in 2..arity { - self.registers[i - 1] = self.registers[i]; - } - - if arity > 1 { - self.registers[arity - 1] = pred; - return; - } - - self.fail = true; - } - - pub(super) fn setup_call_n(&mut self, arity: usize) -> Option { - let addr = self.store(self.deref(self.registers[arity])); - - let (name, narity) = read_heap_cell!(addr, - (HeapCellValueTag::Str, s) => { - let (name, narity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); - - if narity + arity > MAX_ARITY { - let stub = functor_stub(atom!("call"), arity + 1); - let err = self.representation_error(RepFlag::MaxArity); - let representation_error = self.error_form(err, stub); - - self.throw_exception(representation_error); - return None; - } - - for i in (1..arity).rev() { - self.registers[i + narity] = self.registers[i]; - } - - for i in 1..narity + 1 { - self.registers[i] = self.heap[s + i]; - } - - (name, narity) - } - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - (name, 0) - } else { - self.fail = true; - return None; - } - } - (HeapCellValueTag::Char, c) => { - (self.atom_tbl.build_with(&c.to_string()), 0) - } - (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, _h) => { - let stub = functor_stub(atom!("call"), arity + 1); - let err = self.instantiation_error(); - let instantiation_error = self.error_form(err, stub); - - self.throw_exception(instantiation_error); - return None; - } - _ => { - let stub = functor_stub(atom!("call"), arity + 1); - let err = self.type_error(ValidType::Callable, addr); - let type_error = self.error_form(err, stub); - - self.throw_exception(type_error); - return None; - } - ); - - Some((name, arity + narity - 1)) - } - - #[inline] - pub fn is_cyclic_term(&mut self, addr: HeapCellValue) -> bool { - if addr.is_constant() { - return false; - } - - let addr = self.store(self.deref(addr)); - let mut iter = stackful_preorder_iter(&mut self.heap, addr); - - while let Some(value) = iter.next() { - if value.is_forwarded() { - let value = heap_bound_store(iter.heap, heap_bound_deref(iter.heap, value)); - - if value.is_compound() { - return true; - } - } - } - - false - } - - // arg(+N, +Term, ?Arg) - pub fn try_arg(&mut self) -> CallResult { - let stub_gen = || functor_stub(atom!("arg"), 3); - let n = self.store(self.deref(self.registers[1])); - - read_heap_cell!(n, - (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { - // 8.5.2.3 a) - let err = self.instantiation_error(); - return Err(self.error_form(err, stub_gen())); - } - _ => { - let n = match Number::try_from(n) { - Ok(Number::Fixnum(n)) => Number::Fixnum(n), - Ok(Number::Integer(n)) => Number::Integer(n), - _ => { - let err = self.type_error(ValidType::Integer, n); - return Err(self.error_form(err, stub_gen())); - } - }; - - if n < 0 { - // 8.5.2.3 e) - let err = self.domain_error(DomainErrorType::NotLessThanZero, n); - return Err(self.error_form(err, stub_gen())); - } - - let n = match n { - Number::Fixnum(n) => n.get_num() as usize, - Number::Integer(n) => n.to_usize().unwrap(), - _ => { - self.fail = true; - return Ok(()); - } - }; - - let term = self.deref(self.registers[2]); - - read_heap_cell!(self.store(term), - (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { - let err = self.instantiation_error(); - return Err(self.error_form(err, stub_gen())); - } - (HeapCellValueTag::Str, o) => { - let arity = cell_as_atom_cell!(self.heap[o]).get_arity(); - - if 1 <= n && n <= arity { - let a3 = self.registers[3]; - unify_fn!(self, a3, heap_loc_as_cell!(o + n)); - } else { - self.fail = true; - } - } - (HeapCellValueTag::Lis, l) => { - if n == 1 || n == 2 { - let a3 = self.registers[3]; - unify_fn!(self, a3, heap_loc_as_cell!(l + n - 1)); - } else { - self.fail = true; - } - } - (HeapCellValueTag::PStrLoc, pstr_loc) => { - if n == 1 || n == 2 { - let a3 = self.registers[3]; - let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc); - - let pstr = cell_as_string!(self.heap[h]); - let offset = offset.get_num() as usize; - - if let Some(c) = pstr.as_str_from(offset).chars().next() { - if n == 1 { - self.unify_char(c, a3); - } else { - let offset = (offset + c.len_utf8()) as i64; - let h_len = self.heap.len(); - let pstr_atom: Atom = pstr.into(); + if let Some(c) = pstr.as_str_from(offset).chars().next() { + if n == 1 { + self.unify_char(c, a3); + } else { + let offset = (offset + c.len_utf8()) as i64; + let h_len = self.heap.len(); + let pstr_atom: Atom = pstr.into(); if pstr_atom.len() > offset as usize { self.heap.push(pstr_offset_as_cell!(h)); self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); - unify_fn!(self, pstr_loc_as_cell!(h_len), a3); + unify_fn!(*self, pstr_loc_as_cell!(h_len), a3); } else { match self.heap[h].get_tag() { HeapCellValueTag::CStr => { self.unify_atom(atom!("[]"), self.store(self.deref(a3))); } HeapCellValueTag::PStr => { - unify_fn!(self, self.heap[h+1], a3); + unify_fn!(*self, self.heap[h+1], a3); } _ => { unreachable!(); @@ -3103,7 +2210,7 @@ impl MachineState { self.heap.push(pstr_offset_as_cell!(h_len)); self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); - unify_fn!(self, pstr_loc_as_cell!(h_len+1), self.registers[3]); + unify_fn!(*self, pstr_loc_as_cell!(h_len+1), self.registers[3]); } else { self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[3]))); } @@ -3187,182 +2294,6 @@ impl MachineState { ) } - pub fn execute_inlined(&mut self, inlined: &InlinedClauseType) { - match inlined { - &InlinedClauseType::CompareNumber(cmp, ref at_1, ref at_2) => { - let n1 = try_or_fail!(self, self.get_number(at_1)); - let n2 = try_or_fail!(self, self.get_number(at_2)); - - self.compare_numbers(cmp, n1, n2); - } - &InlinedClauseType::IsAtom(r1) => { - let d = self.store(self.deref(self[r1])); - - read_heap_cell!(d, - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity == 0 { - self.p += 1; - } else { - self.fail = true; - } - } - (HeapCellValueTag::Char) => { - self.p += 1; - } - _ => { - self.fail = true; - } - ); - } - &InlinedClauseType::IsAtomic(r1) => { - let d = self.store(self.deref(self[r1])); - - read_heap_cell!(d, - (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | - HeapCellValueTag::Cons) => { - self.p += 1; - } - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity == 0 { - self.p += 1; - } else { - self.fail = true; - } - } - _ => { - self.fail = true; - } - ); - } - &InlinedClauseType::IsInteger(r1) => { - let d = self.store(self.deref(self[r1])); - - match Number::try_from(d) { - Ok(Number::Fixnum(_)) => { - self.p += 1; - } - Ok(Number::Integer(_)) => { - self.p += 1; - } - Ok(Number::Rational(n)) => { - if n.denom() == &1 { - self.p += 1; - } else { - self.fail = true; - } - } - _ => { - self.fail = true; - } - } - } - &InlinedClauseType::IsCompound(r1) => { - let d = self.store(self.deref(self[r1])); - - read_heap_cell!(d, - (HeapCellValueTag::Str | HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { - self.p += 1; - } - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity > 0 { - self.p += 1; - } else { - self.fail = true; - } - } - _ => { - self.fail = true; - } - ); - } - &InlinedClauseType::IsFloat(r1) => { - let d = self.store(self.deref(self[r1])); - - match Number::try_from(d) { - Ok(Number::Float(_)) => { - self.p += 1; - } - _ => { - self.fail = true; - } - } - } - &InlinedClauseType::IsNumber(r1) => { - let d = self.store(self.deref(self[r1])); - - match Number::try_from(d) { - Ok(Number::Fixnum(_)) => { - self.p += 1; - } - Ok(Number::Integer(_)) => { - self.p += 1; - } - Ok(Number::Rational(n)) => { - if n.denom() == &1 { - self.p += 1; - } else { - self.fail = true; - } - } - Ok(Number::Float(_)) => { - self.p += 1; - } - _ => { - self.fail = true; - } - } - } - &InlinedClauseType::IsRational(r1) => { - let d = self.store(self.deref(self[r1])); - - read_heap_cell!(d, - (HeapCellValueTag::Cons, ptr) => { - match_untyped_arena_ptr!(ptr, - (ArenaHeaderTag::Rational, _r) => { - self.p += 1; - } - _ => { - self.fail = true; - } - ); - } - _ => { - self.fail = true; - } - ); - } - &InlinedClauseType::IsNonVar(r1) => { - let d = self.store(self.deref(self[r1])); - - match d.get_tag() { - HeapCellValueTag::AttrVar - | HeapCellValueTag::Var - | HeapCellValueTag::StackVar => { - self.fail = true; - } - _ => { - self.p += 1; - } - } - } - &InlinedClauseType::IsVar(r1) => { - let d = self.store(self.deref(self[r1])); - - match d.get_tag() { - HeapCellValueTag::AttrVar - | HeapCellValueTag::Var - | HeapCellValueTag::StackVar => { - self.p += 1; - } - _ => { - self.fail = true; - } - } - } - } - } - #[inline(always)] fn try_functor_compound_case(&mut self, name: Atom, arity: usize) { self.try_functor_unify_components(atom_as_cell!(name), arity); @@ -3742,545 +2673,11 @@ impl MachineState { self.p += 1; } - fn throw_interrupt_exception(&mut self) { + pub fn throw_interrupt_exception(&mut self) { let err = self.interrupt_error(); let src = functor_stub(atom!("repl"), 0); let err = self.error_form(err, src); self.throw_exception(err); } - - fn handle_call_clause( - &mut self, - indices: &mut IndexStore, - code_repo: &CodeRepo, - call_policy: &mut Box, - cut_policy: &mut Box, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, - ct: &ClauseType, - arity: usize, - lco: bool, - use_default_cp: bool, - ) { - let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); - - match INTERRUPT.compare_exchange( - interrupted, - false, - std::sync::atomic::Ordering::Relaxed, - std::sync::atomic::Ordering::Relaxed, - ) { - Ok(interruption) => { - if interruption { - self.throw_interrupt_exception(); - return; - } - } - Err(_) => unreachable!(), - } - - let mut default_call_policy: Box = Box::new(DefaultCallPolicy {}); - - let call_policy = if use_default_cp { - &mut default_call_policy - } else { - call_policy - }; - - self.last_call = lco; - - match ct { - &ClauseType::BuiltIn(ref ct) => try_or_fail!( - self, - call_policy.call_builtin( - self, - ct, - &indices.code_dir, - &indices.op_dir, - &indices.stream_aliases, - ) - ), - &ClauseType::CallN => try_or_fail!( - self, - call_policy.call_n( - self, - arity, - &indices.code_dir, - &indices.op_dir, - &indices.stream_aliases, - ) - ), - &ClauseType::Inlined(ref ct) => { - self.execute_inlined(ct); - - if lco { - self.p = CodePtr::Local(self.cp); - } - } - &ClauseType::Named(ref name, _, ref idx) => { - try_or_fail!(self, call_policy.context_call(self, *name, arity, idx)) - } - &ClauseType::System(ref ct) => try_or_fail!( - self, - self.system_call( - ct, - code_repo, - indices, - call_policy, - cut_policy, - current_input_stream, - current_output_stream, - ) - ), - }; - - self.last_call = false; - } - - pub fn execute_ctrl_instr( - &mut self, - indices: &mut IndexStore, - code_repo: &CodeRepo, - call_policy: &mut Box, - cut_policy: &mut Box, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, - instr: &ControlInstruction, - ) { - match instr { - &ControlInstruction::Allocate(num_cells) => { - self.allocate(num_cells); - } - &ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) => self - .handle_call_clause( - indices, - code_repo, - call_policy, - cut_policy, - current_input_stream, - current_output_stream, - ct, - arity, - lco, - use_default_cp, - ), - &ControlInstruction::Deallocate => self.deallocate(), - &ControlInstruction::JmpBy(arity, offset, _, lco) => { - if !lco { - self.cp.assign_if_local(self.p.clone() + 1); - } - - self.num_of_args = arity; - self.b0 = self.b; - self.p += offset; - } - &ControlInstruction::RevJmpBy(offset) => { - self.p -= offset; - } - &ControlInstruction::Proceed => { - self.p = CodePtr::Local(self.cp); - } - }; - } - - pub(super) fn execute_dynamic_indexed_choice_instr( - &mut self, - code_repo: &CodeRepo, - call_policy: &mut Box, - global_variables: &mut GlobalVarDir, - ) { - let p = self.p.local(); - - match self.find_living_dynamic(&code_repo.code, self.oip, self.iip) { - Some((offset, oi, ii, is_next_clause)) => { - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc())); - self.oip = oi; - self.iip = ii; - - match self.dynamic_mode { - FirstOrNext::First if !is_next_clause => { - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset)); - } - FirstOrNext::First => { - // there's a leading DynamicElse that sets self.cc. - // self.cc = self.global_clock; - - // see that there is a following dynamic_else - // clause so we avoid generating a choice - // point in case there isn't. - match self.find_living_dynamic(&code_repo.code, oi, ii + 1) { - Some(_) => { - self.registers[self.num_of_args + 1] = - fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); - - self.num_of_args += 2; - - self.execute_indexed_choice_instr( - &IndexedChoiceInstruction::Try(offset), - call_policy, - global_variables, - ); - - self.num_of_args -= 2; - } - None => { - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset)); - self.oip = 0; - self.iip = 0; - } - } - } - FirstOrNext::Next => { - let b = self.b; - let n = self - .stack - .index_or_frame(b) - .prelude - .univ_prelude - .num_cells; - - self.cc = cell_as_fixnum!(self.stack[stack_loc!(OrFrame, b, n-2)]) - .get_num() as usize; - - if is_next_clause { - match self.find_living_dynamic(&code_repo.code, self.oip, self.iip) { - Some(_) => { - try_or_fail!( - self, - call_policy.retry(self, offset, global_variables) - ); - } - None => { - try_or_fail!( - self, - call_policy.trust(self, offset, global_variables) - ) - } - } - } else { - try_or_fail!(self, call_policy.trust(self, offset, global_variables)) - } - } - } - } - None => { - self.fail = true; - } - } - - self.dynamic_mode = FirstOrNext::Next; - } - - pub(super) fn execute_indexed_choice_instr( - &mut self, - instr: &IndexedChoiceInstruction, - call_policy: &mut Box, - global_variables: &mut GlobalVarDir, - ) { - match instr { - &IndexedChoiceInstruction::Try(offset) => { - let n = self.num_of_args; - let b = self.stack.allocate_or_frame(n); - let or_frame = self.stack.index_or_frame_mut(b); - - or_frame.prelude.univ_prelude.num_cells = n; - or_frame.prelude.e = self.e; - or_frame.prelude.cp = self.cp; - or_frame.prelude.b = self.b; - or_frame.prelude.bp = self.p.local(); // + 1; in self.iip now! - or_frame.prelude.boip = self.oip; - or_frame.prelude.biip = self.iip + 1; - or_frame.prelude.tr = self.tr; - or_frame.prelude.h = self.heap.len(); - or_frame.prelude.b0 = self.b0; - - self.b = b; - - for i in 0..n { - or_frame[i] = self.registers[i+1]; - } - - /* - self.iip += 1; - - let oip_b = self.oip.to_ne_bytes(); - let iip_b = self.iip.to_ne_bytes(); - - or_frame[n] = HeapCellValue::from_bytes( - [oip_b[0], oip_b[1], oip_b[2], oip_b[3], - iip_b[0], iip_b[1], iip_b[2], iip_b[3]], - ); - */ - - self.hb = self.heap.len(); - self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset)); - - self.oip = 0; - self.iip = 0; - } - &IndexedChoiceInstruction::Retry(l) => { - try_or_fail!(self, call_policy.retry(self, l, global_variables)); - } - &IndexedChoiceInstruction::Trust(l) => { - try_or_fail!(self, call_policy.trust(self, l, global_variables)); - } - }; - } - - pub(super) fn execute_choice_instr( - &mut self, - instr: &ChoiceInstruction, - code_repo: &CodeRepo, - call_policy: &mut Box, - global_variables: &mut GlobalVarDir, - ) { - match instr { - &ChoiceInstruction::DynamicElse(..) => { - if let FirstOrNext::First = self.dynamic_mode { - self.cc = self.global_clock; - } - - let p = self.p.local().abs_loc(); - - match self.find_living_dynamic_else(&code_repo.code, p) { - Some((p, next_i)) => { - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); - - match self.dynamic_mode { - FirstOrNext::First if next_i == 0 => { - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1)); - } - FirstOrNext::First => { - self.cc = self.global_clock; - - match self.find_living_dynamic_else(&code_repo.code, p + next_i) { - Some(_) => { - self.registers[self.num_of_args + 1] = - fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); - self.num_of_args += 1; - - self.execute_choice_instr( - &ChoiceInstruction::TryMeElse(next_i), - code_repo, - call_policy, - global_variables, - ); - - self.num_of_args -= 1; - } - None => { - self.p += 1; - } - } - } - FirstOrNext::Next => { - let n = self - .stack - .index_or_frame(self.b) - .prelude - .univ_prelude - .num_cells; - - self.cc = cell_as_fixnum!(self.stack[stack_loc!(OrFrame, self.b, n-1)]) - .get_num() as usize; - - if next_i > 0 { - match self.find_living_dynamic_else(&code_repo.code, p + next_i) { - Some(_) => { - try_or_fail!( - self, - call_policy.retry_me_else( - self, - next_i, - global_variables, - ) - ) - } - None => { - try_or_fail!( - self, - call_policy.trust_me(self, global_variables) - ) - } - } - } else { - try_or_fail!(self, call_policy.trust_me(self, global_variables)) - } - } - } - } - None => { - self.fail = true; - } - } - - self.dynamic_mode = FirstOrNext::Next; - } - &ChoiceInstruction::DynamicInternalElse(..) => { - let p = self.p.local().abs_loc(); - - match self.find_living_dynamic_else(&code_repo.code, p) { - Some((p, next_i)) => { - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); - - match self.dynamic_mode { - FirstOrNext::First if next_i == 0 => { - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1)); - } - FirstOrNext::First => { - match self.find_living_dynamic_else(&code_repo.code, p + next_i) { - Some(_) => { - self.registers[self.num_of_args + 1] = - fixnum_as_cell!(Fixnum::build_with(self.cc as i64)); - self.num_of_args += 1; - - self.execute_choice_instr( - &ChoiceInstruction::TryMeElse(next_i), - code_repo, - call_policy, - global_variables, - ); - - self.num_of_args -= 1; - } - None => { - self.p += 1; - } - } - } - FirstOrNext::Next => { - let n = self - .stack - .index_or_frame(self.b) - .prelude - .univ_prelude - .num_cells; - - self.cc = cell_as_fixnum!(self.stack[stack_loc!(OrFrame, self.b, n-1)]) - .get_num() as usize; - - if next_i > 0 { - match self.find_living_dynamic_else(&code_repo.code, p + next_i) { - Some(_) => { - try_or_fail!( - self, - call_policy.retry_me_else( - self, - next_i, - global_variables, - ) - ) - } - None => { - try_or_fail!( - self, - call_policy.trust_me(self, global_variables) - ) - } - } - } else { - try_or_fail!( - self, - call_policy.trust_me(self, global_variables) - ) - } - } - } - } - None => { - self.fail = true; - } - } - - self.dynamic_mode = FirstOrNext::Next; - } - &ChoiceInstruction::TryMeElse(offset) => { - let n = self.num_of_args; - let b = self.stack.allocate_or_frame(n); - let or_frame = self.stack.index_or_frame_mut(b); - - or_frame.prelude.univ_prelude.num_cells = n; - or_frame.prelude.e = self.e; - or_frame.prelude.cp = self.cp; - or_frame.prelude.b = self.b; - or_frame.prelude.bp = self.p.local() + offset; - or_frame.prelude.boip = 0; - or_frame.prelude.biip = 0; - or_frame.prelude.tr = self.tr; - or_frame.prelude.h = self.heap.len(); - or_frame.prelude.b0 = self.b0; - - self.b = b; - - for i in 1..n + 1 { - self.stack.index_or_frame_mut(b)[i - 1] = self.registers[i]; - } - - self.hb = self.heap.len(); - self.p += 1; - } - &ChoiceInstruction::DefaultRetryMeElse(offset) => { - let mut call_policy = DefaultCallPolicy {}; - try_or_fail!( - self, - call_policy.retry_me_else(self, offset, global_variables) - ) - } - &ChoiceInstruction::DefaultTrustMe(_) => { - let mut call_policy = DefaultCallPolicy {}; - try_or_fail!(self, call_policy.trust_me(self, global_variables)) - } - &ChoiceInstruction::RetryMeElse(offset) => { - try_or_fail!( - self, - call_policy.retry_me_else(self, offset, global_variables) - ) - } - &ChoiceInstruction::TrustMe(_) => { - try_or_fail!(self, call_policy.trust_me(self, global_variables)) - } - } - } - - pub(super) fn execute_cut_instr( - &mut self, - instr: &CutInstruction, - cut_policy: &mut Box, - ) { - match instr { - &CutInstruction::NeckCut => { - let b = self.b; - let b0 = self.b0; - - if b > b0 { - self.b = b0; - - if b > self.e { - self.stack.truncate(b); - } - } - - self.p += 1; - } - &CutInstruction::GetLevel(r) => { - let b0 = self.b0; - - self[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64)); - self.p += 1; - } - &CutInstruction::GetLevelAndUnify(r) => { - let b0 = self[perm_v!(1)]; - let a = self[r]; - - unify_fn!(self, a, b0); - self.p += 1; - } - &CutInstruction::Cut(r) => { - if !cut_policy.cut(self, r) { - self.p += 1; - } - } - } - } } diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 9524d138..7f73755a 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -226,8 +226,6 @@ impl Machine { let mut wam = Machine { machine_st, - inner_heap: Heap::new(), - policies: MachinePolicies::new(), indices: IndexStore::new(), code_repo: CodeRepo::new(), user_input, diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 7a73ac30..b33df9d4 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -6,6 +6,7 @@ pub mod code_walker; pub mod loader; pub mod compile; pub mod copier; +pub mod dispatch; pub mod gc; pub mod heap; pub mod load_state; @@ -21,23 +22,29 @@ pub mod streams; pub mod system_calls; pub mod term_stream; +use crate::arena::*; use crate::atom_table::*; +use crate::clause_types::*; use crate::forms::*; -use crate::instructions::*; use crate::machine::code_repo::*; use crate::machine::compile::*; +use crate::machine::copier::*; use crate::machine::heap::*; use crate::machine::loader::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; +use crate::machine::stack::*; use crate::machine::streams::*; +use crate::parser::ast::*; +use crate::parser::rug::{Integer, Rational}; use crate::types::*; use indexmap::IndexMap; - use lazy_static::lazy_static; +use ordered_float::OrderedFloat; +use std::cmp::Ordering; use std::env; use std::path::PathBuf; use std::sync::atomic::AtomicBool; @@ -49,8 +56,6 @@ lazy_static! { #[derive(Debug)] pub struct Machine { pub(super) machine_st: MachineState, - pub(super) inner_heap: Heap, - pub(super) policies: MachinePolicies, pub(super) indices: IndexStore, pub(super) code_repo: CodeRepo, pub(super) user_input: Stream, @@ -59,29 +64,6 @@ pub struct Machine { pub(super) load_contexts: Vec, } -#[derive(Debug)] -pub(crate) struct MachinePolicies { - call_policy: Box, - cut_policy: Box, -} - -impl MachinePolicies { - #[inline] - fn new() -> Self { - MachinePolicies { - call_policy: Box::new(DefaultCallPolicy {}), - cut_policy: Box::new(DefaultCutPolicy {}), - } - } -} - -impl Default for MachinePolicies { - #[inline] - fn default() -> Self { - MachinePolicies::new() - } -} - #[derive(Debug)] pub struct LoadContext { pub(super) path: PathBuf, @@ -142,9 +124,7 @@ impl Machine { self.machine_st.throw_exception(err); return; } -} -impl Machine { fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) { if let Some(module) = self.indices.modules.get(&module_name) { if let Some(ref code_index) = module.code_dir.get(&key) { @@ -317,8 +297,6 @@ impl Machine { let mut wam = Machine { machine_st, - inner_heap: Heap::new(), - policies: MachinePolicies::new(), indices: IndexStore::new(), code_repo: CodeRepo::new(), user_input, @@ -413,6 +391,12 @@ impl Machine { .insert(atom!("user_output"), self.user_output); self.indices.streams.insert(self.user_output); + + self.indices + .stream_aliases + .insert(atom!("user_error"), self.user_error); + + self.indices.streams.insert(self.user_error); } fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) { @@ -526,20 +510,14 @@ impl Machine { pub(crate) fn run_query(&mut self) { while !self.machine_st.p.is_halt() { - self.machine_st.query_stepper( - &mut self.indices, - &mut self.policies, - &mut self.code_repo, - &mut self.user_input, - &mut self.user_output, - ); + self.query_stepper(); match self.machine_st.p { CodePtr::REPL(code_ptr, p) => { self.handle_toplevel_command(code_ptr, p); if self.machine_st.fail { - self.machine_st.backtrack(); + self.backtrack(); } } _ => { @@ -548,103 +526,34 @@ impl Machine { }; } } -} - -impl MachineState { - fn dispatch_instr( - &mut self, - instr: &Line, - indices: &mut IndexStore, - policies: &mut MachinePolicies, - code_repo: &CodeRepo, - user_input: &mut Stream, - user_output: &mut Stream, - ) { - match instr { - &Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr), - &Line::Choice(ref choice_instr) => self.execute_choice_instr( - choice_instr, - code_repo, - &mut policies.call_policy, - &mut indices.global_variables, - ), - &Line::Cut(ref cut_instr) => { - self.execute_cut_instr(cut_instr, &mut policies.cut_policy) - } - &Line::Control(ref control_instr) => self.execute_ctrl_instr( - indices, - code_repo, - &mut policies.call_policy, - &mut policies.cut_policy, - user_input, - user_output, - control_instr, - ), - &Line::Fact(ref fact_instr) => { - self.execute_fact_instr(&fact_instr); - self.p += 1; - } - &Line::IndexingCode(ref indexing_lines) => { - self.execute_indexing_instr(indexing_lines, code_repo) - } - &Line::IndexedChoice(ref choice_instr) => self.execute_indexed_choice_instr( - choice_instr, - &mut policies.call_policy, - &mut indices.global_variables, - ), - &Line::DynamicIndexedChoice(_) => self.execute_dynamic_indexed_choice_instr( - code_repo, - &mut policies.call_policy, - &mut indices.global_variables, - ), - &Line::Query(ref query_instr) => { - self.execute_query_instr(&query_instr); - self.p += 1; - } - } - } - fn execute_instr( - &mut self, - indices: &mut IndexStore, - policies: &mut MachinePolicies, - code_repo: &CodeRepo, - user_input: &mut Stream, - user_output: &mut Stream, - ) { - let instr = match code_repo.lookup_instr(self, &self.p) { + fn execute_instr(&mut self) { + let instr = match self.code_repo.lookup_instr(&self.machine_st, &self.machine_st.p) { Some(instr) => instr, None => return, }; - self.dispatch_instr( - instr.as_ref(), - indices, - policies, - code_repo, - user_input, - user_output, - ); + self.dispatch_instr(instr); } fn backtrack(&mut self) { - let b = self.b; - let or_frame = self.stack.index_or_frame(b); + let b = self.machine_st.b; + let or_frame = self.machine_st.stack.index_or_frame(b); - self.b0 = or_frame.prelude.b0; - self.p = CodePtr::Local(or_frame.prelude.bp); + self.machine_st.b0 = or_frame.prelude.b0; + self.machine_st.p = CodePtr::Local(or_frame.prelude.bp); - self.oip = or_frame.prelude.boip; - self.iip = or_frame.prelude.biip; + self.machine_st.oip = or_frame.prelude.boip; + self.machine_st.iip = or_frame.prelude.biip; - self.pdl.clear(); - self.fail = false; + self.machine_st.pdl.clear(); + self.machine_st.fail = false; } - fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool { - match self.p { + fn check_machine_index(&mut self) -> bool { + match self.machine_st.p { CodePtr::Local(LocalCodePtr::DirEntry(p)) - if p < code_repo.code.len() => {} + if p < self.code_repo.code.len() => {} CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => { return false; } @@ -655,21 +564,14 @@ impl MachineState { } // return true iff verify_attr_interrupt is called. - fn verify_attr_stepper( - &mut self, - indices: &mut IndexStore, - policies: &mut MachinePolicies, - code_repo: &mut CodeRepo, - user_input: &mut Stream, - user_output: &mut Stream, - ) -> bool { + fn verify_attr_stepper(&mut self) -> bool { loop { - let instr = match code_repo.lookup_instr(self, &self.p) { + let instr = match self.code_repo.lookup_instr(&self.machine_st, &self.machine_st.p) { Some(instr) => { - if instr.as_ref().is_head_instr() { + if instr.as_ref(&self.code_repo.code).is_head_instr() { instr } else { - let cp = self.p.local(); + let cp = self.machine_st.p.local(); self.run_verify_attr_interrupt(cp); return true; } @@ -677,80 +579,876 @@ impl MachineState { None => return false, }; - self.dispatch_instr( - instr.as_ref(), - indices, - policies, - code_repo, - user_input, - user_output, - ); + self.dispatch_instr(instr); - if self.fail { + if self.machine_st.fail { self.backtrack(); } - if !self.check_machine_index(code_repo) { + if !self.check_machine_index() { return false; } } } fn run_verify_attr_interrupt(&mut self, cp: LocalCodePtr) { - let p = self.attr_var_init.verify_attrs_loc; + let p = self.machine_st.attr_var_init.verify_attrs_loc; - self.attr_var_init.cp = cp; - self.verify_attr_interrupt(p); + self.machine_st.attr_var_init.cp = cp; + self.machine_st.verify_attr_interrupt(p); } - fn query_stepper( - &mut self, - indices: &mut IndexStore, - policies: &mut MachinePolicies, - code_repo: &mut CodeRepo, - user_input: &mut Stream, - user_output: &mut Stream, - ) { + fn query_stepper(&mut self) { loop { - self.execute_instr(indices, policies, code_repo, user_input, user_output); + self.execute_instr(); - if self.fail { + if self.machine_st.fail { self.backtrack(); } - match self.p { + match self.machine_st.p { CodePtr::VerifyAttrInterrupt(_) => { - self.p = CodePtr::Local(self.attr_var_init.cp); + self.machine_st.p = CodePtr::Local(self.machine_st.attr_var_init.cp); - let instigating_p = CodePtr::Local(self.attr_var_init.instigating_p); - let instigating_instr = code_repo - .lookup_instr(self, &instigating_p) + let instigating_p = CodePtr::Local(self.machine_st.attr_var_init.instigating_p); + let instigating_instr = self.code_repo + .lookup_instr(&self.machine_st, &instigating_p) .unwrap(); - if !instigating_instr.as_ref().is_head_instr() { - let cp = self.p.local(); + if !instigating_instr.as_ref(&self.code_repo.code).is_head_instr() { + let cp = self.machine_st.p.local(); self.run_verify_attr_interrupt(cp); - } else if !self.verify_attr_stepper( - indices, - policies, - code_repo, - user_input, - user_output, - ) { - if self.fail { + } else if !self.verify_attr_stepper() { + if self.machine_st.fail { break; } - let cp = self.p.local(); + let cp = self.machine_st.p.local(); self.run_verify_attr_interrupt(cp); } } _ => { - if !self.check_machine_index(code_repo) { + if !self.check_machine_index() { break; } } } } } + + pub fn execute_inlined(&mut self, inlined: &InlinedClauseType) { + match inlined { + &InlinedClauseType::CompareNumber(cmp, ref at_1, ref at_2) => { + let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(at_2)); + + self.machine_st.compare_numbers(cmp, n1, n2); + } + &InlinedClauseType::IsAtom(r1) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); + + read_heap_cell!(d, + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + self.machine_st.p += 1; + } else { + self.machine_st.fail = true; + } + } + (HeapCellValueTag::Char) => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.fail = true; + } + ); + } + &InlinedClauseType::IsAtomic(r1) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); + + read_heap_cell!(d, + (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + HeapCellValueTag::Cons) => { + self.machine_st.p += 1; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + self.machine_st.p += 1; + } else { + self.machine_st.fail = true; + } + } + _ => { + self.machine_st.fail = true; + } + ); + } + &InlinedClauseType::IsInteger(r1) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); + + match Number::try_from(d) { + Ok(Number::Fixnum(_)) => { + self.machine_st.p += 1; + } + Ok(Number::Integer(_)) => { + self.machine_st.p += 1; + } + Ok(Number::Rational(n)) => { + if n.denom() == &1 { + self.machine_st.p += 1; + } else { + self.machine_st.fail = true; + } + } + _ => { + self.machine_st.fail = true; + } + } + } + &InlinedClauseType::IsCompound(r1) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); + + read_heap_cell!(d, + (HeapCellValueTag::Str | HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { + self.machine_st.p += 1; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity > 0 { + self.machine_st.p += 1; + } else { + self.machine_st.fail = true; + } + } + _ => { + self.machine_st.fail = true; + } + ); + } + &InlinedClauseType::IsFloat(r1) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); + + match Number::try_from(d) { + Ok(Number::Float(_)) => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.fail = true; + } + } + } + &InlinedClauseType::IsNumber(r1) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); + + match Number::try_from(d) { + Ok(Number::Fixnum(_)) => { + self.machine_st.p += 1; + } + Ok(Number::Integer(_)) => { + self.machine_st.p += 1; + } + Ok(Number::Rational(n)) => { + if n.denom() == &1 { + self.machine_st.p += 1; + } else { + self.machine_st.fail = true; + } + } + Ok(Number::Float(_)) => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.fail = true; + } + } + } + &InlinedClauseType::IsRational(r1) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); + + read_heap_cell!(d, + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Rational, _r) => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.fail = true; + } + ); + } + _ => { + self.machine_st.fail = true; + } + ); + } + &InlinedClauseType::IsNonVar(r1) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); + + match d.get_tag() { + HeapCellValueTag::AttrVar + | HeapCellValueTag::Var + | HeapCellValueTag::StackVar => { + self.machine_st.fail = true; + } + _ => { + self.machine_st.p += 1; + } + } + } + &InlinedClauseType::IsVar(r1) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); + + match d.get_tag() { + HeapCellValueTag::AttrVar | + HeapCellValueTag::Var | + HeapCellValueTag::StackVar => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.fail = true; + } + } + } + } + } + + #[inline(always)] + pub(super) fn execute_dynamic_indexed_choice_instr(&mut self) { + let p = self.machine_st.p.local(); + + match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { + Some((offset, oi, ii, is_next_clause)) => { + self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc())); + self.machine_st.oip = oi; + self.machine_st.iip = ii; + + match self.machine_st.dynamic_mode { + FirstOrNext::First if !is_next_clause => { + self.machine_st.p = + CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset)); + } + FirstOrNext::First => { + // there's a leading DynamicElse that sets self.machine_st.cc. + // self.machine_st.cc = self.machine_st.global_clock; + + // see that there is a following dynamic_else + // clause so we avoid generating a choice + // point in case there isn't. + match self.find_living_dynamic(oi, ii + 1) { + Some(_) => { + self.machine_st.registers[self.machine_st.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); + + self.machine_st.num_of_args += 2; + self.machine_st.indexed_try(offset); + self.machine_st.num_of_args -= 2; + } + None => { + self.machine_st.p = + CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset)); + self.machine_st.oip = 0; + self.machine_st.iip = 0; + } + } + } + FirstOrNext::Next => { + let b = self.machine_st.b; + let n = self.machine_st + .stack + .index_or_frame(b) + .prelude + .univ_prelude + .num_cells; + + self.machine_st.cc = cell_as_fixnum!( + self.machine_st.stack[stack_loc!(OrFrame, b, n-2)] + ).get_num() as usize; + + if is_next_clause { + match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { + Some(_) => { + self.retry(offset); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + None => { + self.trust(offset); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } else { + self.trust(offset); + + try_or_fail!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } + } + None => { + self.machine_st.fail = true; + } + } + + self.machine_st.dynamic_mode = FirstOrNext::Next; + } + + #[inline(always)] + fn retry_me_else(&mut self, offset: usize) { + let b = self.machine_st.b; + let or_frame = self.machine_st.stack.index_or_frame_mut(b); + let n = or_frame.prelude.univ_prelude.num_cells; + + for i in 0..n { + self.machine_st.registers[i + 1] = or_frame[i]; + } + + self.machine_st.num_of_args = n; + self.machine_st.e = or_frame.prelude.e; + self.machine_st.cp = or_frame.prelude.cp; + + or_frame.prelude.bp = self.machine_st.p.local() + offset; + + let old_tr = or_frame.prelude.tr; + let curr_tr = self.machine_st.tr; + let target_h = or_frame.prelude.h; + + self.machine_st.tr = or_frame.prelude.tr; + + self.machine_st.attr_var_init.reset(); + self.machine_st.hb = self.machine_st.heap.len(); + self.machine_st.p += 1; + + self.unwind_trail(old_tr, curr_tr); + + self.machine_st.trail.truncate(self.machine_st.tr); + self.machine_st.heap.truncate(target_h); + } + + #[inline(always)] + fn retry(&mut self, offset: usize) { + let b = self.machine_st.b; + let or_frame = self.machine_st.stack.index_or_frame_mut(b); + let n = or_frame.prelude.univ_prelude.num_cells; + + for i in 0..n { + self.machine_st.registers[i+1] = or_frame[i]; + } + + self.machine_st.num_of_args = n; + self.machine_st.e = or_frame.prelude.e; + self.machine_st.cp = or_frame.prelude.cp; + + // WAS: or_frame.prelude.bp = self.machine_st.p.local() + 1; + or_frame.prelude.biip += 1; + + let old_tr = or_frame.prelude.tr; + let curr_tr = self.machine_st.tr; + let target_h = or_frame.prelude.h; + + self.machine_st.tr = or_frame.prelude.tr; + self.machine_st.attr_var_init.reset(); + + self.unwind_trail(old_tr, curr_tr); + + self.machine_st.trail.truncate(self.machine_st.tr); + self.machine_st.heap.truncate(target_h); + + self.machine_st.hb = self.machine_st.heap.len(); + self.machine_st.p = CodePtr::Local(dir_entry!(self.machine_st.p.local().abs_loc() + offset)); + + self.machine_st.oip = 0; + self.machine_st.iip = 0; + } + + #[inline(always)] + fn trust(&mut self, offset: usize) { + let b = self.machine_st.b; + let or_frame = self.machine_st.stack.index_or_frame(b); + let n = or_frame.prelude.univ_prelude.num_cells; + + for i in 0..n { + self.machine_st.registers[i+1] = or_frame[i]; + } + + self.machine_st.num_of_args = n; + self.machine_st.e = or_frame.prelude.e; + self.machine_st.cp = or_frame.prelude.cp; + + let old_tr = or_frame.prelude.tr; + let curr_tr = self.machine_st.tr; + let target_h = or_frame.prelude.h; + + self.machine_st.tr = or_frame.prelude.tr; + + self.machine_st.attr_var_init.reset(); + self.machine_st.b = or_frame.prelude.b; + + self.unwind_trail(old_tr, curr_tr); + + self.machine_st.trail.truncate(self.machine_st.tr); + self.machine_st.stack.truncate(b); + self.machine_st.heap.truncate(target_h); + + self.machine_st.hb = self.machine_st.heap.len(); + self.machine_st.p = CodePtr::Local(dir_entry!(self.machine_st.p.local().abs_loc() + offset)); + + self.machine_st.oip = 0; + self.machine_st.iip = 0; + } + + #[inline(always)] + fn trust_me(&mut self) { + let b = self.machine_st.b; + let or_frame = self.machine_st.stack.index_or_frame(b); + let n = or_frame.prelude.univ_prelude.num_cells; + + for i in 0..n { + self.machine_st.registers[i+1] = or_frame[i]; + } + + self.machine_st.num_of_args = n; + self.machine_st.e = or_frame.prelude.e; + self.machine_st.cp = or_frame.prelude.cp; + + let old_tr = or_frame.prelude.tr; + let curr_tr = self.machine_st.tr; + let target_h = or_frame.prelude.h; + + self.machine_st.tr = or_frame.prelude.tr; + + self.machine_st.attr_var_init.reset(); + self.machine_st.b = or_frame.prelude.b; + + self.unwind_trail(old_tr, curr_tr); + + self.machine_st.trail.truncate(self.machine_st.tr); + self.machine_st.stack.truncate(b); + self.machine_st.heap.truncate(target_h); + + self.machine_st.hb = self.machine_st.heap.len(); + self.machine_st.p += 1; + } + + #[inline(always)] + fn context_call(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult { + if self.machine_st.last_call { + self.try_execute(name, arity, idx) + } else { + self.try_call(name, arity, idx) + } + } + + #[inline(always)] + fn try_call(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult { + match idx.get() { + IndexPtr::DynamicUndefined => { + self.machine_st.fail = true; + return Ok(()); + } + IndexPtr::Undefined => { + return Err(self.machine_st.throw_undefined_error(name, arity)); + } + IndexPtr::DynamicIndex(compiled_tl_index) => { + self.machine_st.dynamic_mode = FirstOrNext::First; + self.machine_st.call_at_index(arity, dir_entry!(compiled_tl_index)); + } + IndexPtr::Index(compiled_tl_index) => { + self.machine_st.call_at_index(arity, dir_entry!(compiled_tl_index)); + } + } + + Ok(()) + } + + #[inline(always)] + fn try_execute(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult { + match idx.get() { + IndexPtr::DynamicUndefined => { + self.machine_st.fail = true; + return Ok(()); + } + IndexPtr::Undefined => { + return Err(self.machine_st.throw_undefined_error(name, arity)); + } + IndexPtr::DynamicIndex(compiled_tl_index) => { + self.machine_st.dynamic_mode = FirstOrNext::First; + self.machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index)); + } + IndexPtr::Index(compiled_tl_index) => { + self.machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index)) + } + } + + Ok(()) + } + + #[inline(always)] + fn call_builtin(&mut self, ct: &BuiltInClauseType) -> CallResult { + match ct { + &BuiltInClauseType::AcyclicTerm => { + let addr = self.machine_st.registers[1]; + self.machine_st.fail = self.machine_st.is_cyclic_term(addr); + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::Arg => { + self.machine_st.try_arg()?; + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::Compare => { + let stub_gen = || functor_stub(atom!("compare"), 3); + + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let a2 = self.machine_st.registers[2]; + let a3 = self.machine_st.registers[3]; + + read_heap_cell!(a1, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) + .get_name_and_arity(); + + match name { + atom!(">") | atom!("<") | atom!("=") if arity == 2 => { + } + _ => { + let err = self.machine_st.domain_error(DomainErrorType::Order, a1); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + } + _ => { + let err = self.machine_st.type_error(ValidType::Atom, a1); + return Err(self.machine_st.error_form(err, stub_gen())); + } + ); + + let atom = match compare_term_test!(self.machine_st, a2, a3) { + Some(Ordering::Greater) => { + atom!(">") + } + Some(Ordering::Equal) => { + atom!("=") + } + None | Some(Ordering::Less) => { + atom!("<") + } + }; + + self.machine_st.unify_atom(atom, a1); + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::CompareTerm(qt) => { + self.machine_st.compare_term(qt); + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::Read => { + let stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("read"), + 2, + )?; + + match self.machine_st.read(stream, &self.indices.op_dir) { + Ok(offset) => { + let value = self.machine_st.registers[2]; + unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc)); + } + Err(ParserError::UnexpectedEOF) => { + let value = self.machine_st.registers[2]; + self.machine_st.unify_atom(atom!("end_of_file"), value); + } + Err(e) => { + let stub = functor_stub(atom!("read"), 2); + let err = self.machine_st.syntax_error(e); + + return Err(self.machine_st.error_form(err, stub)); + } + }; + + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::CopyTerm => { + self.machine_st.copy_term(AttrVarPolicy::DeepCopy); + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::Eq => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + self.machine_st.fail = self.machine_st.eq_test(a1, a2); + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::Ground => { + self.machine_st.fail = self.machine_st.ground_test(); + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::Functor => { + self.machine_st.try_functor()?; + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::NotEq => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + self.machine_st.fail = + if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { + true + } else { + false + }; + + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::Sort => { + self.machine_st.check_sort_errors()?; + + let stub_gen = || functor_stub(atom!("sort"), 2); + let mut list = self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen)?; + + list.sort_unstable_by(|v1, v2| { + compare_term_test!(self.machine_st, *v1, *v2).unwrap_or(Ordering::Less) + }); + + list.dedup_by(|v1, v2| { + compare_term_test!(self.machine_st, *v1, *v2) == Some(Ordering::Equal) + }); + + let heap_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut self.machine_st.heap, list.into_iter()) + ); + + let r2 = self.machine_st.registers[2]; + unify_fn!(&mut self.machine_st, r2, heap_addr); + + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::KeySort => { + self.machine_st.check_keysort_errors()?; + + let stub_gen = || functor_stub(atom!("keysort"), 2); + let list = self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen)?; + + let mut key_pairs = Vec::with_capacity(list.len()); + + for val in list { + let key = self.machine_st.project_onto_key(val)?; + key_pairs.push((key, val)); + } + + key_pairs.sort_by(|a1, a2| { + compare_term_test!(self.machine_st, a1.0, a2.0).unwrap_or(Ordering::Less) + }); + + let key_pairs = key_pairs.into_iter().map(|kp| kp.1); + let heap_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut self.machine_st.heap, key_pairs) + ); + + let r2 = self.machine_st.registers[2]; + unify_fn!(&mut self.machine_st, r2, heap_addr); + + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + &BuiltInClauseType::Is(r, ref at) => { + let n1 = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + let n2 = self.machine_st.get_number(at)?; + + match n2 { + Number::Fixnum(n) => self.machine_st.unify_fixnum(n, n1), + Number::Float(n) => { + // TODO: argghh.. deal with it. + let n = arena_alloc!(n, &mut self.machine_st.arena); + self.machine_st.unify_f64(n, n1) + } + Number::Integer(n) => self.machine_st.unify_big_int(n, n1), + Number::Rational(n) => self.machine_st.unify_rational(n, n1), + } + + return_from_clause!(self.machine_st.last_call, self.machine_st) + } + } + } + + #[inline(always)] + fn call_clause_type(&mut self, module_name: Atom, key: PredicateKey) -> CallResult { + let (name, arity) = key; + + match ClauseType::from(name, arity) { + ClauseType::BuiltIn(built_in) => { + self.machine_st.setup_built_in_call(built_in); + self.call_builtin(&built_in)?; + } + ClauseType::CallN => { + self.machine_st.handle_internal_call_n(arity); + + if self.machine_st.fail { + return Ok(()); + } + + self.machine_st.p = CodePtr::CallN( + arity, + self.machine_st.p.local(), + self.machine_st.last_call, + ); + } + ClauseType::Inlined(inlined) => { + self.execute_inlined(&inlined); + + if self.machine_st.last_call { + self.machine_st.p = CodePtr::Local(self.machine_st.cp); + } + } + ClauseType::Named(..) if module_name == atom!("user") => { + return if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { + self.context_call(name, arity, idx) + } else { + Err(self.machine_st.throw_undefined_error(name, arity)) + }; + } + ClauseType::Named(..) => { + return if let Some(module) = self.indices.modules.get(&module_name) { + if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() { + self.context_call(name, arity, idx) + } else { + Err(self.machine_st.throw_undefined_error(name, arity)) + } + } else { + let stub = functor_stub(name, arity); + let err = self.machine_st.module_resolution_error(module_name, name, arity); + + Err(self.machine_st.error_form(err, stub)) + }; + } + ClauseType::System(_) => { + let (name, arity) = key; + let name = functor!(name); + + let stub = functor_stub(atom!("call"), arity + 1); + let err = self.machine_st.type_error(ValidType::Callable, name); + + return Err(self.machine_st.error_form(err, stub)); + } + } + + Ok(()) + } + + #[inline(always)] + fn call_n(&mut self, module_name: Atom, arity: usize) -> CallResult { + if let Some(key) = self.machine_st.setup_call_n(arity) { + self.call_clause_type(module_name, key)?; + } + + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + } + + #[inline(always)] + fn run_cleaners(&mut self) -> bool { + use std::sync::Once; + + static CLEANER_INIT: Once = Once::new(); + + static mut RCWH: usize = 0; + static mut RCWOH: usize = 0; + + let (r_c_w_h, r_c_wo_h) = unsafe { + CLEANER_INIT.call_once(|| { + let r_c_w_h_atom = atom!("run_cleaners_with_handling"); + let r_c_wo_h_atom = atom!("run_cleaners_without_handling"); + let iso_ext = atom!("iso_ext"); + + RCWH = self.indices.get_predicate_code_index(r_c_w_h_atom, 0, iso_ext) + .and_then(|item| item.local()) + .unwrap(); + RCWOH = self.indices.get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext) + .and_then(|item| item.local()) + .unwrap(); + }); + + (RCWH, RCWOH) + }; + + if let Some(&(_, b_cutoff, prev_block)) = self.machine_st.cont_pts.last() { + if self.machine_st.b < b_cutoff { + let (idx, arity) = if self.machine_st.block > prev_block { + (dir_entry!(r_c_w_h), 0) + } else { + self.machine_st.registers[1] = fixnum_as_cell!( + Fixnum::build_with(b_cutoff as i64) + ); + + (dir_entry!(r_c_wo_h), 1) + }; + + if self.machine_st.last_call { + self.machine_st.execute_at_index(arity, idx); + } else { + self.machine_st.call_at_index(arity, idx); + } + + return true; + } + } + + false + } + + pub(super) fn unwind_trail(&mut self, a1: usize, a2: usize) { + // the sequence is reversed to respect the chronology of trail + // additions, now that deleted attributes can be undeleted by + // backtracking. + for i in (a1..a2).rev() { + let h = self.machine_st.trail[i].get_value() as usize; + + match self.machine_st.trail[i].get_tag() { + TrailEntryTag::TrailedHeapVar => { + self.machine_st.heap[h] = heap_loc_as_cell!(h); + } + TrailEntryTag::TrailedStackVar => { + self.machine_st.stack[h] = stack_loc_as_cell!(h); + } + TrailEntryTag::TrailedAttrVar => { + self.machine_st.heap[h] = attr_var_as_cell!(h); + } + TrailEntryTag::TrailedAttrVarHeapLink => { + self.machine_st.heap[h] = heap_loc_as_cell!(h); + } + TrailEntryTag::TrailedAttrVarListLink => { + let l = self.machine_st.trail[i + 1].get_value(); + self.machine_st.heap[h] = list_loc_as_cell!(l); + } + TrailEntryTag::TrailedBlackboardEntry => { + let key = Atom::from(h); + + match self.indices.global_variables.get_mut(&key) { + Some((_, ref mut loc)) => *loc = None, + None => unreachable!(), + } + } + TrailEntryTag::TrailedBlackboardOffset => { + let key = Atom::from(h); + let value_cell = HeapCellValue::from(u64::from(self.machine_st.trail[i + 1])); + + match self.indices.global_variables.get_mut(&key) { + Some((_, ref mut loc)) => *loc = Some(value_cell), + None => unreachable!(), + } + } + TrailEntryTag::TrailedAttachedValue => { + } + } + } + } } diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index e2c74be1..c3711db0 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -542,14 +542,12 @@ fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( #[derive(Debug)] pub(crate) struct Preprocessor { - flags: MachineFlags, queue: VecDeque>, } impl Preprocessor { - pub(super) fn new(flags: MachineFlags) -> Self { + pub(super) fn new() -> Self { Preprocessor { - flags, queue: VecDeque::new(), } } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 15217cec..d84c2ea9 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -11,7 +11,7 @@ use crate::heap_iter::*; use crate::heap_print::*; use crate::instructions::*; use crate::machine; -use crate::machine::code_repo::CodeRepo; +use crate::machine::Machine; use crate::machine::code_walker::*; use crate::machine::copier::*; use crate::machine::heap::*; @@ -438,7 +438,7 @@ impl MachineState { ) ); - unify_fn!(self, list_of_vars, outcome); + unify_fn!(*self, list_of_vars, outcome); } fn finalize_skip_max_list(&mut self, n: usize, value: HeapCellValue) { @@ -806,20 +806,13 @@ impl MachineState { Ok(string) } +} - pub(super) fn system_call( - &mut self, - ct: &SystemClauseType, - code_repo: &CodeRepo, - indices: &mut IndexStore, - call_policy: &mut Box, - cut_policy: &mut Box, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, - ) -> CallResult { +impl Machine { + pub(super) fn system_call(&mut self, ct: &SystemClauseType) -> CallResult { match ct { &SystemClauseType::BindFromRegister => { - let reg = self.store(self.deref(self.registers[2])); + let reg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let n = match Number::try_from(reg) { Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), Ok(Number::Integer(n)) => n.to_usize(), @@ -830,97 +823,101 @@ impl MachineState { if let Some(n) = n { if n <= MAX_ARITY { - let target = self.registers[n]; - let addr = self.registers[1]; + let target = self.machine_st.registers[n]; + let addr = self.machine_st.registers[1]; - unify_fn!(self, addr, target); - return return_from_clause!(self.last_call, self); + unify_fn!(self.machine_st, addr, target); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } - self.fail = true; + self.machine_st.fail = true; } &SystemClauseType::CurrentHostname => { match hostname::get().ok() { Some(host) => match host.to_str() { Some(host) => { - let hostname = self.atom_tbl.build_with(host); + let hostname = self.machine_st.atom_tbl.build_with(host); + + self.machine_st.unify_atom( + hostname, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) + ); - self.unify_atom(hostname, self.store(self.deref(self.registers[1]))); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } None => {} }, None => {} } - self.fail = true; + self.machine_st.fail = true; return Ok(()); } &SystemClauseType::CurrentInput => { - let addr = self.store(self.deref(self.registers[1])); - let stream = *current_input_stream; + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let stream = self.user_input; if let Some(var) = addr.as_var() { - self.bind(var, stream_as_cell!(stream)); - return return_from_clause!(self.last_call, self); + self.machine_st.bind(var, stream_as_cell!(stream)); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } read_heap_cell!(addr, (HeapCellValueTag::Cons, cons_ptr) => { match_untyped_arena_ptr!(cons_ptr, (ArenaHeaderTag::Stream, other_stream) => { - self.fail = stream != other_stream; + self.machine_st.fail = stream != other_stream; } _ => { let stub = functor_stub(atom!("current_input"), 1); - let err = self.domain_error(DomainErrorType::Stream, addr); + let err = self.machine_st.domain_error(DomainErrorType::Stream, addr); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } ); } _ => { let stub = functor_stub(atom!("current_input"), 1); - let err = self.domain_error(DomainErrorType::Stream, addr); + let err = self.machine_st.domain_error(DomainErrorType::Stream, addr); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } ); } &SystemClauseType::CurrentOutput => { - let addr = self.store(self.deref(self.registers[1])); - let stream = *current_output_stream; + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let stream = self.user_output; if let Some(var) = addr.as_var() { - self.bind(var, stream_as_cell!(stream)); - return return_from_clause!(self.last_call, self); + self.machine_st.bind(var, stream_as_cell!(stream)); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } read_heap_cell!(addr, (HeapCellValueTag::Cons, cons_ptr) => { match_untyped_arena_ptr!(cons_ptr, (ArenaHeaderTag::Stream, other_stream) => { - self.fail = stream != other_stream; + self.machine_st.fail = stream != other_stream; } _ => { let stub = functor_stub(atom!("current_output"), 1); - let err = self.domain_error(DomainErrorType::Stream, addr); + let err = self.machine_st.domain_error(DomainErrorType::Stream, addr); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } ); } _ => { let stub = functor_stub(atom!("current_output"), 1); - let err = self.domain_error(DomainErrorType::Stream, addr); + let err = self.machine_st.domain_error(DomainErrorType::Stream, addr); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } ); } &SystemClauseType::DirectoryFiles => { - if let Some(dir) = self.value_to_str_like(self.registers[1]) { + if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { let path = std::path::Path::new(dir.as_str()); let mut files = Vec::new(); @@ -928,7 +925,7 @@ impl MachineState { for entry in entries { if let Ok(entry) = entry { if let Some(name) = entry.file_name().to_str() { - let name = self.atom_tbl.build_with(name); + let name = self.machine_st.atom_tbl.build_with(name); files.push(atom_as_cstr_cell!(name)); continue; @@ -936,122 +933,122 @@ impl MachineState { } let stub = functor_stub(atom!("directory_files"), 2); - let err = self.representation_error(RepFlag::Character); - let err = self.error_form(err, stub); + let err = self.machine_st.representation_error(RepFlag::Character); + let err = self.machine_st.error_form(err, stub); return Err(err); } let files_list = heap_loc_as_cell!( - iter_to_heap_list(&mut self.heap, files.into_iter()) + iter_to_heap_list(&mut self.machine_st.heap, files.into_iter()) ); - unify!(self, self.registers[2], files_list); - return return_from_clause!(self.last_call, self); + unify!(self.machine_st, self.machine_st.registers[2], files_list); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } - self.fail = true; + self.machine_st.fail = true; } &SystemClauseType::FileSize => { - if let Some(file) = self.value_to_str_like(self.registers[1]) { + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { let len = Number::arena_from( fs::metadata(file.as_str()).unwrap().len(), - &mut self.arena, + &mut self.machine_st.arena, ); match len { - Number::Fixnum(n) => self.unify_fixnum(n, self.registers[2]), - Number::Integer(n) => self.unify_big_int(n, self.registers[2]), + Number::Fixnum(n) => self.machine_st.unify_fixnum(n, self.machine_st.registers[2]), + Number::Integer(n) => self.machine_st.unify_big_int(n, self.machine_st.registers[2]), _ => unreachable!(), } } else { - self.fail = true; + self.machine_st.fail = true; } } &SystemClauseType::FileExists => { - if let Some(file) = self.value_to_str_like(self.registers[1]) { + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { let file_str = file.as_str(); if !std::path::Path::new(file_str).exists() || !fs::metadata(file_str).unwrap().is_file() { - self.fail = true; + self.machine_st.fail = true; } } else { - self.fail = true; + self.machine_st.fail = true; } } &SystemClauseType::DirectoryExists => { - if let Some(dir) = self.value_to_str_like(self.registers[1]) { + if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { let dir_str = dir.as_str(); if !std::path::Path::new(dir_str).exists() || !fs::metadata(dir_str).unwrap().is_dir() { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } else { - self.fail = true; + self.machine_st.fail = true; } } &SystemClauseType::DirectorySeparator => { - self.unify_char(std::path::MAIN_SEPARATOR, self.registers[1]); + self.machine_st.unify_char(std::path::MAIN_SEPARATOR, self.machine_st.registers[1]); } &SystemClauseType::MakeDirectory => { - if let Some(dir) = self.value_to_str_like(self.registers[1]) { + if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { match fs::create_dir(dir.as_str()) { Ok(_) => {} _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } else { - self.fail = true; + self.machine_st.fail = true; } } &SystemClauseType::MakeDirectoryPath => { - if let Some(dir) = self.value_to_str_like(self.registers[1]) { + if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { match fs::create_dir_all(dir.as_str()) { Ok(_) => {} _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } else { - self.fail = true; + self.machine_st.fail = true; } } &SystemClauseType::DeleteFile => { - if let Some(file) = self.value_to_str_like(self.registers[1]) { + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { match fs::remove_file(file.as_str()) { Ok(_) => {} _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } } &SystemClauseType::RenameFile => { - if let Some(file) = self.value_to_str_like(self.registers[1]) { - if let Some(renamed) = self.value_to_str_like(self.registers[2]) { + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + if let Some(renamed) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { if fs::rename(file.as_str(), renamed.as_str()).is_ok() { - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } } - self.fail = true; + self.machine_st.fail = true; } &SystemClauseType::DeleteDirectory => { - if let Some(dir) = self.value_to_str_like(self.registers[1]) { + if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { match fs::remove_dir(dir.as_str()) { Ok(_) => {} _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } @@ -1063,67 +1060,67 @@ impl MachineState { Some(d) => d, _ => { let stub = functor_stub(atom!("working_directory"), 2); - let err = self.representation_error(RepFlag::Character); - let err = self.error_form(err, stub); + let err = self.machine_st.representation_error(RepFlag::Character); + let err = self.machine_st.error_form(err, stub); return Err(err); } }; - let current_atom = self.atom_tbl.build_with(¤t); + let current_atom = self.machine_st.atom_tbl.build_with(¤t); - self.unify_complete_string( + self.machine_st.unify_complete_string( current_atom, - self.store(self.deref(self.registers[1])), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])), ); - if self.fail { + if self.machine_st.fail { return Ok(()); } - if let Some(next) = self.value_to_str_like(self.registers[2]) { + if let Some(next) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { if env::set_current_dir(std::path::Path::new(next.as_str())).is_ok() { - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } } - self.fail = true; + self.machine_st.fail = true; } &SystemClauseType::PathCanonical => { - if let Some(path) = self.value_to_str_like(self.registers[1]) { + if let Some(path) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { match fs::canonicalize(path.as_str()) { Ok(canonical) => { let cs = match canonical.to_str() { Some(s) => s, _ => { let stub = functor_stub(atom!("path_canonical"), 2); - let err = self.representation_error(RepFlag::Character); - let err = self.error_form(err, stub); + let err = self.machine_st.representation_error(RepFlag::Character); + let err = self.machine_st.error_form(err, stub); return Err(err); } }; - let canonical_atom = self.atom_tbl.build_with(cs); + let canonical_atom = self.machine_st.atom_tbl.build_with(cs); - self.unify_complete_string( + self.machine_st.unify_complete_string( canonical_atom, - self.store(self.deref(self.registers[2])), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), ); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } _ => { } } } - self.fail = true; + self.machine_st.fail = true; } &SystemClauseType::FileTime => { - if let Some(file) = self.value_to_str_like(self.registers[1]) { - let which = cell_as_atom!(self.store(self.deref(self.registers[2]))); + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + let which = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); if let Ok(md) = fs::metadata(file.as_str()) { if let Ok(time) = match which { @@ -1136,58 +1133,58 @@ impl MachineState { } { let chars_atom = self.systemtime_to_timestamp(time); - self.unify_complete_string( + self.machine_st.unify_complete_string( chars_atom, - self.registers[3], + self.machine_st.registers[3], ); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } } - self.fail = true; + self.machine_st.fail = true; } &SystemClauseType::AtomChars => { - let a1 = self.store(self.deref(self.registers[1])); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); read_heap_cell!(a1, (HeapCellValueTag::Char) => { - let h = self.heap.len(); + let h = self.machine_st.heap.len(); - self.heap.push(a1); - self.heap.push(empty_list_as_cell!()); + self.machine_st.heap.push(a1); + self.machine_st.heap.push(empty_list_as_cell!()); - unify!(self, self.registers[2], list_loc_as_cell!(h)); + unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h)); } (HeapCellValueTag::Atom, (name, arity)) => { if arity == 0 { - self.unify_complete_string( + self.machine_st.unify_complete_string( name, - self.store(self.deref(self.registers[2])), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), ); } else { - self.fail = true; + self.machine_st.fail = true; } } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { - let a2 = self.store(self.deref(self.registers[2])); + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - if let Some(str_like) = self.value_to_str_like(a2) { + if let Some(str_like) = self.machine_st.value_to_str_like(a2) { let atom = match str_like { AtomOrString::Atom(atom) => { atom } AtomOrString::String(string) => { - self.atom_tbl.build_with(&string) + self.machine_st.atom_tbl.build_with(&string) } }; - self.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); - return return_from_clause!(self.last_call, self); + self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } - self.fail = true; + self.machine_st.fail = true; } _ => { unreachable!(); @@ -1195,37 +1192,37 @@ impl MachineState { ); } &SystemClauseType::AtomCodes => { - let a1 = self.store(self.deref(self.registers[1])); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); read_heap_cell!(a1, (HeapCellValueTag::Char, c) => { - let h = self.heap.len(); + let h = self.machine_st.heap.len(); - self.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64))); - self.heap.push(empty_list_as_cell!()); + self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64))); + self.machine_st.heap.push(empty_list_as_cell!()); - unify!(self, list_loc_as_cell!(h), self.registers[2]); + unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]); } (HeapCellValueTag::Atom, (name, arity)) => { if arity == 0 { let iter = name.chars() .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); - let h = iter_to_heap_list(&mut self.heap, iter); - unify!(self, heap_loc_as_cell!(h), self.registers[2]); + let h = iter_to_heap_list(&mut self.machine_st.heap, iter); + unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]); } else { - self.fail = true; + self.machine_st.fail = true; } } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { let stub_gen = || functor_stub(atom!("atom_codes"), 2); - match self.try_from_list(self.registers[2], stub_gen) { + match self.machine_st.try_from_list(self.machine_st.registers[2], stub_gen) { Ok(addrs) => { - let string = self.codes_to_string(addrs.into_iter(), stub_gen)?; - let atom = self.atom_tbl.build_with(&string); + let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?; + let atom = self.machine_st.atom_tbl.build_with(&string); - self.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); + self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); } Err(e) => { return Err(e); @@ -1238,14 +1235,14 @@ impl MachineState { ); } &SystemClauseType::AtomLength => { - let a1 = self.store(self.deref(self.registers[1])); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let len: i64 = read_heap_cell!(a1, (HeapCellValueTag::Atom, (name, arity)) => { if arity == 0 { name.chars().count() as i64 } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } @@ -1257,28 +1254,28 @@ impl MachineState { } ); - self.unify_fixnum( + self.machine_st.unify_fixnum( Fixnum::build_with(len), - self.store(self.deref(self.registers[2])), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), ); } &SystemClauseType::CallContinuation => { let stub_gen = || functor_stub(atom!("call_continuation"), 1); - let a1 = self.store(self.deref(self.registers[1])); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - match self.try_from_list(a1, stub_gen) { + match self.machine_st.try_from_list(a1, stub_gen) { Err(e) => return Err(e), Ok(cont_chunks) => { - let mut return_p = if self.last_call { - self.cp + let mut return_p = if self.machine_st.last_call { + self.machine_st.cp } else { - self.p.local() + 1 + self.machine_st.p.local() + 1 }; - self.p = CodePtr::Local(return_p); + self.machine_st.p = CodePtr::Local(return_p); for chunk in cont_chunks.into_iter().rev() { - return_p = self.call_continuation_chunk(chunk, return_p); + return_p = self.machine_st.call_continuation_chunk(chunk, return_p); } } } @@ -1287,98 +1284,118 @@ impl MachineState { } &SystemClauseType::CharsToNumber => { let stub_gen = || functor_stub(atom!("number_chars"), 2); - let a1 = self.store(self.deref(self.registers[1])); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - if let Some(atom_or_string) = self.value_to_str_like(a1) { - self.parse_number_from_string(atom_or_string.to_string(), indices, stub_gen)?; + if let Some(atom_or_string) = self.machine_st.value_to_str_like(a1) { + self.machine_st.parse_number_from_string( + atom_or_string.to_string(), + &self.indices, + stub_gen, + )?; } else { // a1 is a ground list at the call site within // number_chars/2, so failure of value_to_str_like // means the list contains a non-character. - let err = self.type_error(ValidType::Character, a1); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::Character, a1); + return Err(self.machine_st.error_form(err, stub_gen())); } } &SystemClauseType::CreatePartialString => { - let atom = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let atom = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) + ); if atom == atom!("") { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } - let pstr_h = self.heap.len(); + let pstr_h = self.machine_st.heap.len(); - self.heap.push(pstr_as_cell!(atom)); - self.heap.push(heap_loc_as_cell!(pstr_h+1)); + self.machine_st.heap.push(pstr_as_cell!(atom)); + self.machine_st.heap.push(heap_loc_as_cell!(pstr_h+1)); - unify!(self, self.registers[2], pstr_loc_as_cell!(pstr_h)); + unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_as_cell!(pstr_h)); - if !self.fail { - self.bind(Ref::heap_cell(pstr_h+1), self.registers[3]); + if !self.machine_st.fail { + self.machine_st.bind(Ref::heap_cell(pstr_h+1), self.machine_st.registers[3]); } } &SystemClauseType::IsPartialString => { - let value = self.store(self.deref(self.registers[1])); + let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let h = self.heap.len(); - self.heap.push(value); + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(value); - let mut iter = HeapPStrIter::new(&self.heap, h); + let mut iter = HeapPStrIter::new(&self.machine_st.heap, h); while let Some(_) = iter.next() {} let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator(); - self.fail = !at_end_of_pstr; + self.machine_st.fail = !at_end_of_pstr; - self.heap.pop(); + self.machine_st.heap.pop(); } &SystemClauseType::PartialStringTail => { - let pstr = self.store(self.deref(self.registers[1])); + let pstr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); read_heap_cell!(pstr, (HeapCellValueTag::PStrLoc, h) => { - let (h, _) = pstr_loc_and_offset(&self.heap, h); + let (h, _) = pstr_loc_and_offset(&self.machine_st.heap, h); - if HeapCellValueTag::CStr == self.heap[h].get_tag() { - self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2]))); + if HeapCellValueTag::CStr == self.machine_st.heap[h].get_tag() { + self.machine_st.unify_atom( + atom!("[]"), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) + ); } else { - unify_fn!(self, heap_loc_as_cell!(h+1), self.registers[2]); + unify_fn!( + self.machine_st, + heap_loc_as_cell!(h+1), + self.machine_st.registers[2] + ); } } (HeapCellValueTag::CStr) => { - self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2]))); + self.machine_st.unify_atom( + atom!("[]"), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) + ); } (HeapCellValueTag::Lis, h) => { - unify_fn!(self, heap_loc_as_cell!(h+1), self.registers[2]); + unify_fn!( + self.machine_st, + heap_loc_as_cell!(h+1), + self.machine_st.registers[2] + ); } _ => { - self.fail = true; + self.machine_st.fail = true; } ); } &SystemClauseType::PeekByte => { let stub_gen = || functor_stub(atom!("peek_byte"), 2); - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("peek_byte"), 2, )?; - self.check_stream_properties( + self.machine_st.check_stream_properties( stream, StreamType::Binary, - Some(self.registers[2]), + Some(self.machine_st.registers[2]), atom!("peek_byte"), 2, )?; if stream.past_end_of_stream() { if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } @@ -1386,36 +1403,36 @@ impl MachineState { if stream.at_end_of_stream() { stream.set_past_end_of_stream(true); - self.unify_fixnum( + self.machine_st.unify_fixnum( Fixnum::build_with(-1), - self.store(self.deref(self.registers[2])), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), ); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } - let addr = match self.store(self.deref(self.registers[2])) { + let addr = match self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) { addr if addr.is_var() => addr, addr => match Number::try_from(addr) { Ok(Number::Integer(n)) => { if let Some(nb) = n.to_u8() { fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - let err = self.type_error(ValidType::InByte, addr); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); } } Ok(Number::Fixnum(n)) => { if let Ok(nb) = u8::try_from(n.get_num()) { fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - let err = self.type_error(ValidType::InByte, addr); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); } } _ => { - let err = self.type_error(ValidType::InByte, addr); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); } }, }; @@ -1423,23 +1440,23 @@ impl MachineState { loop { match stream.peek_byte().map_err(|e| e.kind()) { Ok(b) => { - self.unify_fixnum(Fixnum::build_with(b as i64), addr); + self.machine_st.unify_fixnum(Fixnum::build_with(b as i64), addr); } Err(ErrorKind::PermissionDenied) => { - self.fail = true; + self.machine_st.fail = true; break; } _ => { - self.eof_action( - self.registers[2], + self.machine_st.eof_action( + self.machine_st.registers[2], stream, atom!("peek_byte"), 2, )?; if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } @@ -1449,25 +1466,25 @@ impl MachineState { &SystemClauseType::PeekChar => { let stub_gen = || functor_stub(atom!("peek_char"), 2); - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("peek_char"), 2, )?; - self.check_stream_properties( + self.machine_st.check_stream_properties( stream, StreamType::Text, - Some(self.registers[2]), + Some(self.machine_st.registers[2]), atom!("peek_char"), 2, )?; if stream.past_end_of_stream() { if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } @@ -1476,11 +1493,11 @@ impl MachineState { let end_of_file = atom!("end_of_file"); stream.set_past_end_of_stream(true); - self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); - return return_from_clause!(self.last_call, self); + self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } - let a2 = self.store(self.deref(self.registers[2])); + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let a2 = read_heap_cell!(a2, (HeapCellValueTag::Char) => { @@ -1491,44 +1508,44 @@ impl MachineState { if let Some(c) = name.as_char() { char_as_cell!(c) } else { - let err = self.type_error(ValidType::InCharacter, a2); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::InCharacter, a2); + return Err(self.machine_st.error_form(err, stub_gen())); } } else { - let err = self.type_error(ValidType::InCharacter, a2); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::InCharacter, a2); + return Err(self.machine_st.error_form(err, stub_gen())); } } (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { a2 } _ => { - let err = self.type_error(ValidType::InCharacter, a2); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::InCharacter, a2); + return Err(self.machine_st.error_form(err, stub_gen())); } ); loop { match stream.peek_char().map(|result| result.map_err(|e| e.kind())) { Some(Ok(d)) => { - self.unify_char(d, a2); + self.machine_st.unify_char(d, a2); break; } Some(Err(ErrorKind::PermissionDenied)) => { - self.fail = true; + self.machine_st.fail = true; break; } _ => { - self.eof_action( - self.registers[2], + self.machine_st.eof_action( + self.machine_st.registers[2], stream, atom!("peek_char"), 2, )?; if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } @@ -1538,25 +1555,25 @@ impl MachineState { &SystemClauseType::PeekCode => { let stub_gen = || functor_stub(atom!("peek_code"), 2); - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("peek_code"), 2, )?; - self.check_stream_properties( + self.machine_st.check_stream_properties( stream, StreamType::Text, - Some(self.registers[2]), + Some(self.machine_st.registers[2]), atom!("peek_code"), 2, )?; if stream.past_end_of_stream() { if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } @@ -1565,11 +1582,11 @@ impl MachineState { let end_of_file = atom!("end_of_file"); stream.set_past_end_of_stream(true); - self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); - return return_from_clause!(self.last_call, self); + self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } - let a2 = self.store(self.deref(self.registers[2])); + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let addr = read_heap_cell!(a2, (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { @@ -1585,8 +1602,8 @@ impl MachineState { if let Some(n) = n { fixnum_as_cell!(Fixnum::build_with(n as i64)) } else { - let err = self.representation_error(RepFlag::InCharacterCode); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.representation_error(RepFlag::InCharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); } } Ok(Number::Fixnum(n)) => { @@ -1597,13 +1614,13 @@ impl MachineState { if let Some(n) = n { fixnum_as_cell!(Fixnum::build_with(n as i64)) } else { - let err = self.representation_error(RepFlag::InCharacterCode); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.representation_error(RepFlag::InCharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); } } _ => { - let err = self.type_error(ValidType::Integer, self.registers[2]); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]); + return Err(self.machine_st.error_form(err, stub_gen())); } } } @@ -1614,24 +1631,24 @@ impl MachineState { match result.map(|result| result.map_err(|e| e.kind())) { Some(Ok(c)) => { - self.unify_fixnum(Fixnum::build_with(c as i64), addr); + self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr); break; } Some(Err(ErrorKind::PermissionDenied)) => { - self.fail = true; + self.machine_st.fail = true; break; } _ => { - self.eof_action( - self.registers[2], + self.machine_st.eof_action( + self.machine_st.registers[2], stream, atom!("peek_code"), 2, )?; if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } @@ -1639,10 +1656,10 @@ impl MachineState { } } &SystemClauseType::NumberToChars => { - let n = self.registers[1]; - let chs = self.registers[2]; + let n = self.machine_st.registers[1]; + let chs = self.machine_st.registers[2]; - let n = self.store(self.deref(n)); + let n = self.machine_st.store(self.machine_st.deref(n)); let string = match Number::try_from(n) { Ok(Number::Float(OrderedFloat(n))) => { @@ -1661,12 +1678,12 @@ impl MachineState { } }; - let chars_atom = self.atom_tbl.build_with(&string.trim()); - self.unify_complete_string(chars_atom, self.store(self.deref(chs))); + let chars_atom = self.machine_st.atom_tbl.build_with(&string.trim()); + self.machine_st.unify_complete_string(chars_atom, self.machine_st.store(self.machine_st.deref(chs))); } &SystemClauseType::NumberToCodes => { - let n = self.store(self.deref(self.registers[1])); - let chs = self.registers[2]; + let n = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let chs = self.machine_st.registers[2]; let string = match Number::try_from(n) { Ok(Number::Float(OrderedFloat(n))) => { @@ -1689,31 +1706,31 @@ impl MachineState { fixnum_as_cell!(Fixnum::build_with(c as i64)) }); - let h = iter_to_heap_list(&mut self.heap, codes); - unify!(self, heap_loc_as_cell!(h), chs); + let h = iter_to_heap_list(&mut self.machine_st.heap, codes); + unify!(self.machine_st, heap_loc_as_cell!(h), chs); } &SystemClauseType::CodesToNumber => { let stub_gen = || functor_stub(atom!("number_codes"), 2); - match self.try_from_list(self.registers[1], stub_gen) { + match self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen) { Err(e) => { return Err(e); } Ok(addrs) => { - let string = self.codes_to_string(addrs.into_iter(), stub_gen)?; - self.parse_number_from_string(string, indices, stub_gen)?; + let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?; + self.machine_st.parse_number_from_string(string, &self.indices, stub_gen)?; } } } &SystemClauseType::LiftedHeapLength => { - let a1 = self.registers[1]; - let lh_len = Fixnum::build_with(self.lifted_heap.len() as i64); + let a1 = self.machine_st.registers[1]; + let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.len() as i64); - self.unify_fixnum(lh_len, a1); + self.machine_st.unify_fixnum(lh_len, a1); } &SystemClauseType::CharCode => { let stub_gen = || functor_stub(atom!("char_code"), 2); - let a1 = self.store(self.deref(self.registers[1])); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let c = read_heap_cell!(a1, (HeapCellValueTag::Atom, (name, _arity)) => { @@ -1723,51 +1740,51 @@ impl MachineState { c } _ => { - let a2 = self.store(self.deref(self.registers[2])); + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); match Number::try_from(a2) { Ok(Number::Integer(n)) => { let c = match n.to_u32().and_then(std::char::from_u32) { Some(c) => c, _ => { - let err = self.representation_error(RepFlag::CharacterCode); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.representation_error(RepFlag::CharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); } }; - self.unify_char(c, a2); - return return_from_clause!(self.last_call, self); + self.machine_st.unify_char(c, a2); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } Ok(Number::Fixnum(n)) => { match u32::try_from(n.get_num()) { Ok(n) => { if let Some(c) = std::char::from_u32(n) { - self.unify_char(c, a1); - return return_from_clause!(self.last_call, self); + self.machine_st.unify_char(c, a1); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } _ => {} } - let err = self.representation_error(RepFlag::CharacterCode); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.representation_error(RepFlag::CharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); } _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } ); - self.unify_fixnum( + self.machine_st.unify_fixnum( Fixnum::build_with(c as i64), - self.store(self.deref(self.registers[2])), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), ); } &SystemClauseType::CharType => { - let a1 = self.store(self.deref(self.registers[1])); - let a2 = self.store(self.deref(self.registers[2])); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let c = read_heap_cell!(a1, (HeapCellValueTag::Char, c) => { @@ -1782,13 +1799,13 @@ impl MachineState { ); let chars = cell_as_atom!(a2); - self.fail = true; // This predicate fails by default. + self.machine_st.fail = true; // This predicate fails by default. macro_rules! macro_check { ($id:ident, $name:expr) => { if $id!(c) && chars == $name { - self.fail = false; - return return_from_clause!(self.last_call, self); + self.machine_st.fail = false; + return return_from_clause!(self.machine_st.last_call, self.machine_st); } }; } @@ -1796,8 +1813,8 @@ impl MachineState { macro_rules! method_check { ($id:ident, $name:expr) => { if c.$id() && chars == $name { - self.fail = false; - return return_from_clause!(self.last_call, self); + self.machine_st.fail = false; + return return_from_clause!(self.machine_st.last_call, self.machine_st); } }; } @@ -1845,55 +1862,55 @@ impl MachineState { method_check!(is_whitespace, atom!("whitespace")); } &SystemClauseType::CheckCutPoint => { - let addr = self.store(self.deref(self.registers[1])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let old_b = cell_as_fixnum!(addr).get_num() as usize; - let prev_b = self.stack.index_or_frame(self.b).prelude.b; - let prev_b = self.stack.index_or_frame(prev_b).prelude.b; + let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b; + let prev_b = self.machine_st.stack.index_or_frame(prev_b).prelude.b; if prev_b > old_b { - self.fail = true; + self.machine_st.fail = true; } } &SystemClauseType::CopyTermWithoutAttrVars => { - self.copy_term(AttrVarPolicy::StripAttributes); + self.machine_st.copy_term(AttrVarPolicy::StripAttributes); } &SystemClauseType::FetchGlobalVar => { - let key = cell_as_atom!(self.store(self.deref(self.registers[1]))); - let addr = self.registers[2]; + let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); + let addr = self.machine_st.registers[2]; - match indices.global_variables.get_mut(&key) { + match self.indices.global_variables.get_mut(&key) { Some((ref ball, ref mut loc)) => match loc { Some(value_loc) => { - unify_fn!(self, addr, *value_loc); + unify_fn!(self.machine_st, addr, *value_loc); } None if !ball.stub.is_empty() => { - let h = self.heap.len(); + let h = self.machine_st.heap.len(); let stub = ball.copy_and_align(h); - self.heap.extend(stub.into_iter()); + self.machine_st.heap.extend(stub.into_iter()); - unify_fn!(self, addr, heap_loc_as_cell!(h)); + unify_fn!(self.machine_st, addr, heap_loc_as_cell!(h)); - if !self.fail { + if !self.machine_st.fail { *loc = Some(heap_loc_as_cell!(h)); - self.trail(TrailRef::BlackboardEntry(key)); + self.machine_st.trail(TrailRef::BlackboardEntry(key)); } } - _ => self.fail = true, + _ => self.machine_st.fail = true, }, - None => self.fail = true, + None => self.machine_st.fail = true, }; } &SystemClauseType::PutCode => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("put_code"), 2, )?; - self.check_stream_properties( + self.machine_st.check_stream_properties( stream, StreamType::Text, None, @@ -1903,17 +1920,17 @@ impl MachineState { let stub_gen = || functor_stub(atom!("put_code"), 2); - let addr = self.store(self.deref(self.registers[2])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); if addr.is_var() { - let err = self.instantiation_error(); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.instantiation_error(); + return Err(self.machine_st.error_form(err, stub_gen())); } else { match Number::try_from(addr) { Ok(Number::Integer(n)) => { if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) { write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } Ok(Number::Fixnum(n)) => { @@ -1921,28 +1938,28 @@ impl MachineState { if let Some(c) = u32::try_from(n).ok().and_then(|c| char::from_u32(c)) { write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } _ => { - let err = self.type_error(ValidType::Integer, addr); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::Integer, addr); + return Err(self.machine_st.error_form(err, stub_gen())); } } - let err = self.representation_error(RepFlag::CharacterCode); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.representation_error(RepFlag::CharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); } } &SystemClauseType::PutChar => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("put_char"), 2, )?; - self.check_stream_properties( + self.machine_st.check_stream_properties( stream, StreamType::Text, None, @@ -1951,34 +1968,34 @@ impl MachineState { )?; let stub_gen = || functor_stub(atom!("put_char"), 2); - let addr = self.store(self.deref(self.registers[2])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); if addr.is_var() { - let err = self.instantiation_error(); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.instantiation_error(); + return Err(self.machine_st.error_form(err, stub_gen())); } else { read_heap_cell!(addr, (HeapCellValueTag::Atom, (name, _arity)) => { let c = name.as_char().unwrap(); write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } (HeapCellValueTag::Char, c) => { write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } _ => { } ); - let err = self.type_error(ValidType::Character, addr); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::Character, addr); + return Err(self.machine_st.error_form(err, stub_gen())); } } &SystemClauseType::PutChars => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("$put_chars"), 2, )?; @@ -1986,12 +2003,12 @@ impl MachineState { let mut bytes = Vec::new(); let stub_gen = || functor_stub(atom!("$put_chars"), 2); - if let Some(string) = self.value_to_str_like(self.registers[2]) { + if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { if stream.options().stream_type() == StreamType::Binary { for c in string.as_str().chars() { if c as u32 > 255 { - let err = self.type_error(ValidType::Byte, char_as_cell!(c)); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::Byte, char_as_cell!(c)); + return Err(self.machine_st.error_form(err, stub_gen())); } bytes.push(c as u8); @@ -2002,28 +2019,28 @@ impl MachineState { match stream.write_all(&bytes) { Ok(_) => { - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } _ => { let addr = stream_as_cell!(stream); - let err = self.existence_error(ExistenceError::Stream(addr)); + let err = self.machine_st.existence_error(ExistenceError::Stream(addr)); - return Err(self.error_form(err, stub_gen())); + return Err(self.machine_st.error_form(err, stub_gen())); } } } else { - self.fail = true; + self.machine_st.fail = true; } } &SystemClauseType::PutByte => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("put_byte"), 2, )?; - self.check_stream_properties( + self.machine_st.check_stream_properties( stream, StreamType::Binary, None, @@ -2032,25 +2049,25 @@ impl MachineState { )?; let stub_gen = || functor_stub(atom!("put_byte"), 2); - let addr = self.store(self.deref(self.registers[2])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); if addr.is_var() { - let err = self.instantiation_error(); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.instantiation_error(); + return Err(self.machine_st.error_form(err, stub_gen())); } else { match Number::try_from(addr) { Ok(Number::Integer(n)) => { if let Some(nb) = n.to_u8() { match stream.write(&mut [nb]) { Ok(1) => { - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } _ => { - let err = self.existence_error( + let err = self.machine_st.existence_error( ExistenceError::Stream(stream_as_cell!(stream)) ); - return Err(self.error_form(err, stub_gen())); + return Err(self.machine_st.error_form(err, stub_gen())); } } } @@ -2059,14 +2076,14 @@ impl MachineState { if let Ok(nb) = u8::try_from(n.get_num()) { match stream.write(&mut [nb]) { Ok(1) => { - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } _ => { - let err = self.existence_error( + let err = self.machine_st.existence_error( ExistenceError::Stream(stream_as_cell!(stream)) ); - return Err(self.error_form(err, stub_gen())); + return Err(self.machine_st.error_form(err, stub_gen())); } } } @@ -2076,37 +2093,37 @@ impl MachineState { } } - let err = self.type_error(ValidType::Byte, self.registers[2]); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::Byte, self.machine_st.registers[2]); + return Err(self.machine_st.error_form(err, stub_gen())); } &SystemClauseType::GetByte => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("get_byte"), 2, )?; - self.check_stream_properties( + self.machine_st.check_stream_properties( stream, StreamType::Binary, - Some(self.registers[2]), + Some(self.machine_st.registers[2]), atom!("get_byte"), 2, )?; if stream.past_end_of_stream() { - self.eof_action(self.registers[2], stream, atom!("get_byte"), 2)?; + self.machine_st.eof_action(self.machine_st.registers[2], stream, atom!("get_byte"), 2)?; if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } let stub_gen = || functor_stub(atom!("get_byte"), 2); - let addr = self.store(self.deref(self.registers[2])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let addr = if addr.is_var() { addr @@ -2116,21 +2133,21 @@ impl MachineState { if let Some(nb) = n.to_u8() { fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - let err = self.type_error(ValidType::InByte, addr); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); } } Ok(Number::Fixnum(n)) => { if let Ok(nb) = u8::try_from(n.get_num()) { fixnum_as_cell!(Fixnum::build_with(nb as i64)) } else { - let err = self.type_error(ValidType::InByte, addr); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); } } _ => { - let err = self.type_error(ValidType::InByte, addr); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); } } }; @@ -2140,37 +2157,37 @@ impl MachineState { match stream.read(&mut b) { Ok(1) => { - self.unify_fixnum(Fixnum::build_with(b[0] as i64), addr); + self.machine_st.unify_fixnum(Fixnum::build_with(b[0] as i64), addr); break; } _ => { stream.set_past_end_of_stream(true); - self.unify_fixnum(Fixnum::build_with(-1), self.registers[2]); - return return_from_clause!(self.last_call, self); + self.machine_st.unify_fixnum(Fixnum::build_with(-1), self.machine_st.registers[2]); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } } } &SystemClauseType::GetChar => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("get_char"), 2, )?; - self.check_stream_properties( + self.machine_st.check_stream_properties( stream, StreamType::Text, - Some(self.registers[2]), + Some(self.machine_st.registers[2]), atom!("get_char"), 2, )?; if stream.past_end_of_stream() { if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } @@ -2179,14 +2196,14 @@ impl MachineState { let end_of_file = atom!("end_of_file"); stream.set_past_end_of_stream(true); - self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); - return return_from_clause!(self.last_call, self); + self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } let stub_gen = || functor_stub(atom!("get_char"), 2); - let mut iter = self.open_parsing_stream(stream, atom!("get_char"), 2)?; + let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_char"), 2)?; - let addr = self.store(self.deref(self.registers[2])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let addr = if addr.is_var() { addr @@ -2199,8 +2216,8 @@ impl MachineState { addr } _ => { - let err = self.type_error(ValidType::InCharacter, addr); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::InCharacter, addr); + return Err(self.machine_st.error_form(err, stub_gen())); } ) }; @@ -2210,25 +2227,25 @@ impl MachineState { match result { Some(Ok(c)) => { - self.unify_char(c, addr); + self.machine_st.unify_char(c, addr); - if self.fail { + if self.machine_st.fail { return Ok(()); } break; } _ => { - self.eof_action( - self.registers[2], + self.machine_st.eof_action( + self.machine_st.registers[2], stream, atom!("get_char"), 2, )?; if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } @@ -2236,19 +2253,19 @@ impl MachineState { } } &SystemClauseType::GetNChars => { - let stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("get_n_chars"), 3, )?; - let num = match Number::try_from(self.store(self.deref(self.registers[2]))) { + let num = match Number::try_from(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))) { Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match n.to_usize() { Some(u) => u, _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }, @@ -2269,7 +2286,7 @@ impl MachineState { string.push(c as char); } } else { - let mut iter = self.open_parsing_stream(stream, atom!("get_n_chars"), 2)?; + let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_n_chars"), 2)?; for _ in 0..num { let result = iter.read_char(); @@ -2285,29 +2302,29 @@ impl MachineState { } }; - let atom = self.atom_tbl.build_with(&string); - self.unify_complete_string(atom, self.store(self.deref(self.registers[3]))); + let atom = self.machine_st.atom_tbl.build_with(&string); + self.machine_st.unify_complete_string(atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]))); } &SystemClauseType::GetCode => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("get_code"), 2, )?; - self.check_stream_properties( + self.machine_st.check_stream_properties( stream, StreamType::Text, - Some(self.registers[2]), + Some(self.machine_st.registers[2]), atom!("get_code"), 2, )?; if stream.past_end_of_stream() { if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } @@ -2317,12 +2334,12 @@ impl MachineState { stream.set_past_end_of_stream(true); - self.unify_atom(end_of_file, self.store(self.deref(self.registers[2]))); - return return_from_clause!(self.last_call, self); + self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } let stub_gen = || functor_stub(atom!("get_code"), 2); - let addr = self.store(self.deref(self.registers[2])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let addr = if addr.is_var() { addr @@ -2336,8 +2353,8 @@ impl MachineState { if let Some(n) = n { fixnum_as_cell!(Fixnum::build_with(n as i64)) } else { - let err = self.representation_error(RepFlag::InCharacterCode); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.representation_error(RepFlag::InCharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); } } Ok(Number::Fixnum(n)) => { @@ -2348,43 +2365,43 @@ impl MachineState { if nf.is_some() { fixnum_as_cell!(n) } else { - let err = self.representation_error(RepFlag::InCharacterCode); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.representation_error(RepFlag::InCharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); } } _ => { - let err = self.type_error(ValidType::Integer, self.registers[2]); - return Err(self.error_form(err, stub_gen())); + let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]); + return Err(self.machine_st.error_form(err, stub_gen())); } } }; - let mut iter = self.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?; + let mut iter = self.machine_st.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?; loop { let result = iter.read_char(); match result { Some(Ok(c)) => { - self.unify_fixnum(Fixnum::build_with(c as i64), addr); + self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr); - if self.fail { + if self.machine_st.fail { return Ok(()); } break; } _ => { - self.eof_action( - self.registers[2], + self.machine_st.eof_action( + self.machine_st.registers[2], stream, atom!("get_code"), 2, )?; if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); - } else if self.fail { + return return_from_clause!(self.machine_st.last_call, self.machine_st); + } else if self.machine_st.fail { return Ok(()); } } @@ -2395,7 +2412,7 @@ impl MachineState { let mut first_stream = None; let mut null_streams = BTreeSet::new(); - for stream in indices.streams.iter().cloned() { + for stream in self.indices.streams.iter().cloned() { if !stream.is_null_stream() { first_stream = Some(stream); break; @@ -2404,25 +2421,30 @@ impl MachineState { } } - indices.streams = indices.streams.sub(&null_streams); + self.indices.streams = self.indices.streams.sub(&null_streams); if let Some(first_stream) = first_stream { let stream = stream_as_cell!(first_stream); - let var = self.store(self.deref(self.registers[1])).as_var().unwrap(); - self.bind(var, stream); + let var = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1] + )).as_var().unwrap(); + + self.machine_st.bind(var, stream); } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } &SystemClauseType::NextStream => { - let prev_stream = cell_as_stream!(self.store(self.deref(self.registers[1]))); + let prev_stream = cell_as_stream!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1] + ))); let mut next_stream = None; let mut null_streams = BTreeSet::new(); - for stream in indices + for stream in self.indices .streams .range(prev_stream..) .skip(1) @@ -2436,22 +2458,25 @@ impl MachineState { } } - indices.streams = indices.streams.sub(&null_streams); + self.indices.streams = self.indices.streams.sub(&null_streams); if let Some(next_stream) = next_stream { - let var = self.store(self.deref(self.registers[2])).as_var().unwrap(); + let var = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2] + )).as_var().unwrap(); + let next_stream = stream_as_cell!(next_stream); - self.bind(var, next_stream); + self.machine_st.bind(var, next_stream); } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } &SystemClauseType::FlushOutput => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("flush_output"), 1, )?; @@ -2460,13 +2485,13 @@ impl MachineState { let stub = functor_stub(atom!("flush_output"), 1); let addr = stream_as_cell!(stream); // vec![HeapCellValue::Stream(stream)]; - let err = self.permission_error( + let err = self.machine_st.permission_error( Permission::OutputStream, atom!("stream"), addr, ); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } stream.flush().unwrap(); @@ -2481,8 +2506,8 @@ impl MachineState { if key == ctrl_c { let stub = functor_stub(atom!("get_single_char"), 1); - let err = self.interrupt_error(); - let err = self.error_form(err, stub); + let err = self.machine_st.interrupt_error(); + let err = self.machine_st.error_form(err, stub); return Err(err); } @@ -2494,14 +2519,14 @@ impl MachineState { _ => unreachable!(), }; - self.unify_char(c, self.store(self.deref(self.registers[1]))); + self.machine_st.unify_char(c, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); } &SystemClauseType::HeadIsDynamic => { - let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); - let (name, arity) = read_heap_cell!(self.store(self.deref(self.registers[2])), + let (name, arity) = read_heap_cell!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), (HeapCellValueTag::Str, s) => { - cell_as_atom_cell!(self.heap[s]).get_name_and_arity() + cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity() } (HeapCellValueTag::Atom, (name, _arity)) => { (name, 0) @@ -2511,12 +2536,12 @@ impl MachineState { } ); - self.fail = !indices.is_dynamic_predicate(module_name, (name, arity)); + self.machine_st.fail = !self.indices.is_dynamic_predicate(module_name, (name, arity)); } &SystemClauseType::Close => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("close"), 2, )?; @@ -2525,69 +2550,69 @@ impl MachineState { stream.flush().unwrap(); // 8.11.6.1b) } - indices.streams.remove(&stream); + self.indices.streams.remove(&stream); - if stream == *current_input_stream { - *current_input_stream = indices + if stream == self.user_input { + self.user_input = self.indices .stream_aliases .get(&atom!("user_input")) .cloned() .unwrap(); - indices.streams.insert(*current_input_stream); - } else if stream == *current_output_stream { - *current_output_stream = indices + self.indices.streams.insert(self.user_input); + } else if stream == self.user_output { + self.user_output = self.indices .stream_aliases .get(&atom!("user_output")) .cloned() .unwrap(); - indices.streams.insert(*current_output_stream); + self.indices.streams.insert(self.user_output); } if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() { let close_result = stream.close(); if let Some(alias) = stream.options().get_alias() { - indices.stream_aliases.remove(&alias); + self.indices.stream_aliases.remove(&alias); } if let Err(_) = close_result { let stub = functor_stub(atom!("close"), 1); let addr = stream_as_cell!(stream); - let err = self.existence_error(ExistenceError::Stream(addr)); + let err = self.machine_st.existence_error(ExistenceError::Stream(addr)); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } } } &SystemClauseType::CopyToLiftedHeap => { let lh_offset = cell_as_fixnum!( - self.store(self.deref(self.registers[1])) + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ).get_num() as usize; - let copy_target = self.registers[2]; + let copy_target = self.machine_st.registers[2]; - let old_threshold = self.copy_findall_solution(lh_offset, copy_target); - let new_threshold = self.lifted_heap.len() - lh_offset; + let old_threshold = self.machine_st.copy_findall_solution(lh_offset, copy_target); + let new_threshold = self.machine_st.lifted_heap.len() - lh_offset; - self.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold); + self.machine_st.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold); - for addr in self.lifted_heap[old_threshold + 1 ..].iter_mut() { - *addr -= self.heap.len() + lh_offset; + for addr in self.machine_st.lifted_heap[old_threshold + 1 ..].iter_mut() { + *addr -= self.machine_st.heap.len() + lh_offset; } }, &SystemClauseType::DeleteAttribute => { - let ls0 = self.store(self.deref(self.registers[1])); + let ls0 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); if let HeapCellValueTag::Lis = ls0.get_tag() { let l1 = ls0.get_value(); - let ls1 = self.store(self.deref(heap_loc_as_cell!(l1 + 1))); + let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1))); if let HeapCellValueTag::Lis = ls1.get_tag() { let l2 = ls1.get_value(); - let old_addr = self.heap[l1+1]; - let tail = self.store(self.deref(heap_loc_as_cell!(l2 + 1))); + let old_addr = self.machine_st.heap[l1+1]; + let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1))); let tail = if tail.is_var() { heap_loc_as_cell!(l1 + 1) @@ -2607,158 +2632,139 @@ impl MachineState { } ); - self.heap[l1 + 1] = tail; - self.trail(trail_ref); + self.machine_st.heap[l1 + 1] = tail; + self.machine_st.trail(trail_ref); } } } &SystemClauseType::DeleteHeadAttribute => { - let addr = self.store(self.deref(self.registers[1])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar); let h = addr.get_value(); - let addr = self.store(self.deref(self.heap[h + 1])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1])); debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis); let l = addr.get_value(); - let tail = self.store(self.deref(heap_loc_as_cell!(l + 1))); + let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l + 1))); let tail = if tail.is_var() { - self.heap[h] = heap_loc_as_cell!(h); - self.trail(TrailRef::Ref(Ref::attr_var(h))); + self.machine_st.heap[h] = heap_loc_as_cell!(h); + self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h))); heap_loc_as_cell!(h + 1) } else { tail }; - self.heap[h + 1] = tail; - self.trail(TrailRef::AttrVarListLink(h + 1, l)); + self.machine_st.heap[h + 1] = tail; + self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l)); } &SystemClauseType::DynamicModuleResolution(narity) => { - let module_name = self.store(self.deref(self.registers[1 + narity])); - let module_name = cell_as_atom!(module_name); + let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1 + narity] + ))); - let addr = self.store(self.deref(self.registers[2 + narity])); + let addr = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2 + narity] + )); read_heap_cell!(addr, (HeapCellValueTag::Str, a) => { - let (name, arity) = cell_as_atom_cell!(self.heap[a]) + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[a]) .get_name_and_arity(); for i in (arity + 1..arity + narity + 1).rev() { - self.registers[i] = self.registers[i - arity]; + self.machine_st.registers[i] = self.machine_st.registers[i - arity]; } for i in 1..arity + 1 { - self.registers[i] = self.heap[a + i]; + self.machine_st.registers[i] = self.machine_st.heap[a + i]; } - return self.module_lookup( - indices, - call_policy, - (name, arity + narity), - module_name, - true, - &indices.stream_aliases, - ); + return self.call_clause_type(module_name, (name, arity + narity)); } (HeapCellValueTag::Atom, (name, _arity)) => { - return self.module_lookup( - indices, - call_policy, - (name, narity), - module_name, - true, - &indices.stream_aliases, - ); + return self.call_clause_type(module_name, (name, narity)); } (HeapCellValueTag::Char, c) => { - let key = (self.atom_tbl.build_with(&c.to_string()), narity); - - return self.module_lookup( - indices, - call_policy, - key, - module_name, - true, - &indices.stream_aliases, - ); + let key = (self.machine_st.atom_tbl.build_with(&c.to_string()), narity); + return self.call_clause_type(module_name, key); } _ => { let stub = functor_stub(atom!("(:)"), 2); - let err = self.type_error(ValidType::Callable, addr); + let err = self.machine_st.type_error(ValidType::Callable, addr); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } ); } &SystemClauseType::EnqueueAttributedVar => { - let addr = self.store(self.deref(self.registers[1])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); read_heap_cell!(addr, (HeapCellValueTag::AttrVar, h) => { - self.attr_var_init.attr_var_queue.push(h); + self.machine_st.attr_var_init.attr_var_queue.push(h); } _ => { } ); } &SystemClauseType::GetNextDBRef => { - let a1 = self.store(self.deref(self.registers[1])); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); if let Some(name_var) = a1.as_var() { - let mut iter = indices.code_dir.iter(); + let mut iter = self.indices.code_dir.iter(); while let Some(((name, arity), _)) = iter.next() { if SystemClauseType::from(*name, *arity).is_some() { continue; } - let arity_var = self.deref(self.registers[2]) + let arity_var = self.machine_st.deref(self.machine_st.registers[2]) .as_var().unwrap(); - self.bind(name_var, atom_as_cell!(name)); - self.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64))); + self.machine_st.bind(name_var, atom_as_cell!(name)); + self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64))); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } - self.fail = true; + self.machine_st.fail = true; } else if a1.get_tag() == HeapCellValueTag::Atom { let name = cell_as_atom!(a1); - let arity = cell_as_fixnum!(self.store(self.deref(self.registers[2]))) + let arity = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))) .get_num() as usize; - match self.get_next_db_ref(indices, &DBRef::NamedPred(name, arity)) { + match self.machine_st.get_next_db_ref(&self.indices, &DBRef::NamedPred(name, arity)) { Some(DBRef::NamedPred(name, arity)) => { - let atom_var = self.deref(self.registers[3]) + let atom_var = self.machine_st.deref(self.machine_st.registers[3]) .as_var().unwrap(); - let arity_var = self.deref(self.registers[4]) + let arity_var = self.machine_st.deref(self.machine_st.registers[4]) .as_var().unwrap(); - self.bind(atom_var, atom_as_cell!(name)); - self.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64))); + self.machine_st.bind(atom_var, atom_as_cell!(name)); + self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64))); } Some(DBRef::Op(..)) | None => { - self.fail = true; + self.machine_st.fail = true; } } } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } &SystemClauseType::GetNextOpDBRef => { - let prec = self.store(self.deref(self.registers[1])); + let prec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); if let Some(prec_var) = prec.as_var() { - let spec = self.store(self.deref(self.registers[2])); - let op = self.store(self.deref(self.registers[3])); - let orig_op = self.store(self.deref(self.registers[7])); + let spec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + let op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + let orig_op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[7])); let spec_num = if spec.get_tag() == HeapCellValueTag::Atom { (match cell_as_atom!(spec) { @@ -2778,9 +2784,9 @@ impl MachineState { let orig_op = cell_as_atom!(orig_op); let op_descs = [ - indices.op_dir.get_key_value(&(orig_op, Fixity::In)), - indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)), - indices.op_dir.get_key_value(&(orig_op, Fixity::Post)), + self.indices.op_dir.get_key_value(&(orig_op, Fixity::In)), + self.indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)), + self.indices.op_dir.get_key_value(&(orig_op, Fixity::Post)), ]; let number_of_keys = op_descs[0].is_some() as usize + @@ -2789,7 +2795,7 @@ impl MachineState { match number_of_keys { 0 => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } 1 => { @@ -2811,12 +2817,12 @@ impl MachineState { let op_prec = Fixnum::build_with(op_prec as i64); - self.unify_fixnum(op_prec, prec); - self.unify_atom(op_spec, spec); + self.machine_st.unify_fixnum(op_prec, prec); + self.machine_st.unify_atom(op_spec, spec); } } - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } _ => { let mut unossified_op_dir = OssifiedOpDir::new(); @@ -2834,7 +2840,7 @@ impl MachineState { } else { let mut unossified_op_dir = OssifiedOpDir::new(); - unossified_op_dir.extend(indices.op_dir.iter().filter_map( + unossified_op_dir.extend(self.indices.op_dir.iter().filter_map( |(key, op_desc)| { let (other_prec, other_spec) = (op_desc.get_prec(), op_desc.get_spec()); let name = key.0; @@ -2855,11 +2861,11 @@ impl MachineState { unossified_op_dir }; - let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.arena); + let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.machine_st.arena); match ossified_op_dir.iter().next() { Some(((op_atom, _), (op_prec, op_spec))) => { - let ossified_op_dir_var = self.store(self.deref(self.registers[4])) + let ossified_op_dir_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4])) .as_var().unwrap(); let spec_atom = match *op_spec { @@ -2871,7 +2877,7 @@ impl MachineState { XFY => atom!("xfy"), YFX => atom!("yfx"), _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; @@ -2879,23 +2885,23 @@ impl MachineState { let spec_var = spec.as_var().unwrap(); let op_var = op.as_var().unwrap(); - self.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64))); - self.bind(spec_var, atom_as_cell!(spec_atom)); - self.bind(op_var, atom_as_cell!(op_atom)); - self.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir)); + self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64))); + self.machine_st.bind(spec_var, atom_as_cell!(spec_atom)); + self.machine_st.bind(op_var, atom_as_cell!(op_atom)); + self.machine_st.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir)); } None => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } else { - let spec = cell_as_atom!(self.store(self.deref(self.registers[2]))); - let op_atom = cell_as_atom!(self.store(self.deref(self.registers[3]))); - let ossified_op_dir_cell = self.store(self.deref(self.registers[4])); + let spec = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); + let op_atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]))); + let ossified_op_dir_cell = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4])); if ossified_op_dir_cell.is_var() { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } @@ -2908,22 +2914,25 @@ impl MachineState { atom!("xf") | atom!("yf") => Fixity::Post, atom!("fx") | atom!("fy") => Fixity::Pre, _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; - match self.get_next_db_ref(indices, &DBRef::Op(op_atom, fixity, ossified_op_dir)) { + match self.machine_st.get_next_db_ref( + &self.indices, + &DBRef::Op(op_atom, fixity, ossified_op_dir), + ) { Some(DBRef::Op(op_atom, fixity, ossified_op_dir)) => { let (prec, spec) = ossified_op_dir.get(&(op_atom, fixity)).unwrap(); - let prec_var = self.deref(self.registers[5]) + let prec_var = self.machine_st.deref(self.machine_st.registers[5]) .as_var().unwrap(); - let spec_var = self.deref(self.registers[6]) + let spec_var = self.machine_st.deref(self.machine_st.registers[6]) .as_var().unwrap(); - let op_var = self.deref(self.registers[7]) + let op_var = self.machine_st.deref(self.machine_st.registers[7]) .as_var().unwrap(); let spec_atom = match *spec { @@ -2935,17 +2944,17 @@ impl MachineState { XFY => atom!("xfy"), YFX => atom!("yfx"), _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; - self.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64))); - self.bind(spec_var, atom_as_cell!(spec_atom)); - self.bind(op_var, atom_as_cell!(op_atom)); + self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64))); + self.machine_st.bind(spec_var, atom_as_cell!(spec_atom)); + self.machine_st.bind(op_var, atom_as_cell!(op_atom)); } Some(DBRef::NamedPred(..)) | None => { - self.fail = true; + self.machine_st.fail = true; } } } @@ -2956,61 +2965,65 @@ impl MachineState { rand.bits(1) == 0 }; - self.fail = result; + self.machine_st.fail = result; } &SystemClauseType::CpuNow => { let secs = ProcessTime::now().as_duration().as_secs_f64(); - let secs = arena_alloc!(OrderedFloat(secs), &mut self.arena); + let secs = arena_alloc!(OrderedFloat(secs), &mut self.machine_st.arena); - self.unify_f64(secs, self.registers[1]); + self.machine_st.unify_f64(secs, self.machine_st.registers[1]); } &SystemClauseType::CurrentTime => { let timestamp = self.systemtime_to_timestamp(SystemTime::now()); - self.unify_atom(timestamp, self.registers[1]); + self.machine_st.unify_atom(timestamp, self.machine_st.registers[1]); } &SystemClauseType::Open => { - let alias = self.registers[4]; - let eof_action = self.registers[5]; - let reposition = self.registers[6]; - let stream_type = self.registers[7]; + let alias = self.machine_st.registers[4]; + let eof_action = self.machine_st.registers[5]; + let reposition = self.machine_st.registers[6]; + let stream_type = self.machine_st.registers[7]; - let options = self.to_stream_options(alias, eof_action, reposition, stream_type); - let src_sink = self.store(self.deref(self.registers[1])); + let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); + let src_sink = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - if let Some(str_like) = self.value_to_str_like(src_sink) { + if let Some(str_like) = self.machine_st.value_to_str_like(src_sink) { let file_spec = match str_like { AtomOrString::Atom(atom) => { atom } AtomOrString::String(string) => { - self.atom_tbl.build_with(&string) + self.machine_st.atom_tbl.build_with(&string) } }; - let mut stream = self.stream_from_file_spec(file_spec, indices, &options)?; + let mut stream = self.machine_st.stream_from_file_spec( + file_spec, + &mut self.indices, + &options, + )?; *stream.options_mut() = options; - indices.streams.insert(stream); + self.indices.streams.insert(stream); if let Some(alias) = stream.options().get_alias() { - indices.stream_aliases.insert(alias, stream); + self.indices.stream_aliases.insert(alias, stream); } - let stream_var = self.store(self.deref(self.registers[3])); - self.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream)); + let stream_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + self.machine_st.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream)); } else { - let err = self.domain_error(DomainErrorType::SourceSink, src_sink); + let err = self.machine_st.domain_error(DomainErrorType::SourceSink, src_sink); let stub = functor_stub(atom!("open"), 4); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } } &SystemClauseType::OpDeclaration => { - let priority = self.registers[1]; - let specifier = self.registers[2]; - let op = self.registers[3]; + let priority = self.machine_st.registers[1]; + let specifier = self.machine_st.registers[2]; + let op = self.machine_st.registers[3]; - let priority = self.store(self.deref(priority)); + let priority = self.machine_st.store(self.machine_st.deref(priority)); let priority = match Number::try_from(priority) { Ok(Number::Integer(n)) => n.to_u16().unwrap(), @@ -3020,12 +3033,12 @@ impl MachineState { } }; - let specifier = cell_as_atom_cell!(self.store(self.deref(specifier))) + let specifier = cell_as_atom_cell!(self.machine_st.store(self.machine_st.deref(specifier))) .get_name(); - let op = read_heap_cell!(self.store(self.deref(op)), + let op = read_heap_cell!(self.machine_st.store(self.machine_st.deref(op)), (HeapCellValueTag::Char) => { - self.atom_tbl.build_with(&op.to_string()) + self.machine_st.atom_tbl.build_with(&op.to_string()) } (HeapCellValueTag::Atom, (name, _arity)) => { name @@ -3039,14 +3052,14 @@ impl MachineState { .map_err(SessionError::from) .and_then(|mut op_decl| { if op_decl.op_desc.get_prec() == 0 { - Ok(op_decl.remove(&mut indices.op_dir)) + Ok(op_decl.remove(&mut self.indices.op_dir)) } else { let spec = get_op_desc( op_decl.name, - &CompositeOpDir::new(&indices.op_dir, None), + &CompositeOpDir::new(&self.indices.op_dir, None), ); - op_decl.submit(spec, &mut indices.op_dir) + op_decl.submit(spec, &mut self.indices.op_dir) } }); @@ -3054,100 +3067,102 @@ impl MachineState { Ok(()) => {} Err(e) => { // 8.14.3.3 l) - let err = self.session_error(e); + let err = self.machine_st.session_error(e); let stub = functor_stub(atom!("op"), 3); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } } } &SystemClauseType::SetStreamOptions => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("open"), 4, )?; - let alias = self.registers[2]; - let eof_action = self.registers[3]; - let reposition = self.registers[4]; - let stream_type = self.registers[5]; + let alias = self.machine_st.registers[2]; + let eof_action = self.machine_st.registers[3]; + let reposition = self.machine_st.registers[4]; + let stream_type = self.machine_st.registers[5]; - let options = self.to_stream_options(alias, eof_action, reposition, stream_type); + let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); *stream.options_mut() = options; } &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => { - self.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h)) + self.machine_st.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h)) } &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { - self.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!()) + self.machine_st.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!()) } &SystemClauseType::GetAttributedVariableList => { - let attr_var = self.store(self.deref(self.registers[1])); + let attr_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let attr_var_list = read_heap_cell!(attr_var, (HeapCellValueTag::AttrVar, h) => { h + 1 } (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { // create an AttrVar in the heap. - let h = self.heap.len(); + let h = self.machine_st.heap.len(); - self.heap.push(attr_var_as_cell!(h)); - self.heap.push(heap_loc_as_cell!(h+1)); + self.machine_st.heap.push(attr_var_as_cell!(h)); + self.machine_st.heap.push(heap_loc_as_cell!(h+1)); - self.bind(Ref::attr_var(h), attr_var); + self.machine_st.bind(Ref::attr_var(h), attr_var); h + 1 } _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } ); - let list_addr = self.store(self.deref(self.registers[2])); - self.bind(Ref::heap_cell(attr_var_list), list_addr); + let list_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + self.machine_st.bind(Ref::heap_cell(attr_var_list), list_addr); } &SystemClauseType::GetAttrVarQueueDelimiter => { - let addr = self.registers[1]; - let value = Fixnum::build_with(self.attr_var_init.attr_var_queue.len() as i64); + let addr = self.machine_st.registers[1]; + let value = Fixnum::build_with(self.machine_st.attr_var_init.attr_var_queue.len() as i64); - self.unify_fixnum(value, self.store(self.deref(addr))); + self.machine_st.unify_fixnum(value, self.machine_st.store(self.machine_st.deref(addr))); } &SystemClauseType::GetAttrVarQueueBeyond => { - let addr = self.registers[1]; - let addr = self.store(self.deref(addr)); + let addr = self.machine_st.registers[1]; + let addr = self.machine_st.store(self.machine_st.deref(addr)); let b = match Number::try_from(addr) { Ok(Number::Integer(n)) => n.to_usize(), Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; if let Some(b) = b { - let iter = self.gather_attr_vars_created_since(b); + let iter = self.machine_st.gather_attr_vars_created_since(b); let var_list_addr = heap_loc_as_cell!( - iter_to_heap_list(&mut self.heap, iter) + iter_to_heap_list(&mut self.machine_st.heap, iter) ); - let list_addr = self.registers[2]; - unify!(self, var_list_addr, list_addr); + let list_addr = self.machine_st.registers[2]; + unify!(self.machine_st, var_list_addr, list_addr); } } &SystemClauseType::GetContinuationChunk => { - let e = self.store(self.deref(self.registers[1])); + let e = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let e = cell_as_fixnum!(e).get_num() as usize; - let p_functor = self.store(self.deref(self.registers[2])); - let p = to_local_code_ptr(&self.heap, p_functor).unwrap(); + let p_functor = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2] + )); + let p = to_local_code_ptr(&self.machine_st.heap, p_functor).unwrap(); - let num_cells = match code_repo.lookup_instr(self, &CodePtr::Local(p)) { + let num_cells = match self.code_repo.lookup_instr(&self.machine_st, &CodePtr::Local(p)) { Some(line) => { - let perm_vars = match line.as_ref() { + let perm_vars = match line.as_ref(&self.code_repo.code) { Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(), _ => None, }; @@ -3160,71 +3175,71 @@ impl MachineState { let mut addrs = vec![]; for idx in 1..num_cells + 1 { - addrs.push(self.stack[stack_loc!(AndFrame, e, idx)]); + addrs.push(self.machine_st.stack[stack_loc!(AndFrame, e, idx)]); } - let chunk = str_loc_as_cell!(self.heap.len()); + let chunk = str_loc_as_cell!(self.machine_st.heap.len()); - self.heap.push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); - self.heap.push(p_functor); - self.heap.extend(addrs); + self.machine_st.heap.push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); + self.machine_st.heap.push(p_functor); + self.machine_st.heap.extend(addrs); - unify!(self, self.registers[3], chunk); + unify!(self.machine_st, self.machine_st.registers[3], chunk); } &SystemClauseType::GetLiftedHeapFromOffsetDiff => { - let lh_offset = self.registers[1]; - let lh_offset = cell_as_fixnum!(self.store(self.deref(lh_offset))).get_num() as usize; + let lh_offset = self.machine_st.registers[1]; + let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))).get_num() as usize; - if lh_offset >= self.lifted_heap.len() { - let solutions = self.registers[2]; - let diff = self.registers[3]; + if lh_offset >= self.machine_st.lifted_heap.len() { + let solutions = self.machine_st.registers[2]; + let diff = self.machine_st.registers[3]; - unify_fn!(self, solutions, diff); + unify_fn!(self.machine_st, solutions, diff); } else { - let h = self.heap.len(); + let h = self.machine_st.heap.len(); let mut last_index = h; - for value in self.lifted_heap[lh_offset ..].iter().cloned() { - last_index = self.heap.len(); - self.heap.push(value + h); + for value in self.machine_st.lifted_heap[lh_offset ..].iter().cloned() { + last_index = self.machine_st.heap.len(); + self.machine_st.heap.push(value + h); } - if last_index < self.heap.len() { - let diff = self.registers[3]; - unify_fn!(self, diff, self.heap[last_index]); + if last_index < self.machine_st.heap.len() { + let diff = self.machine_st.registers[3]; + unify_fn!(self.machine_st, diff, self.machine_st.heap[last_index]); } - self.lifted_heap.truncate(lh_offset); + self.machine_st.lifted_heap.truncate(lh_offset); - let solutions = self.registers[2]; - unify_fn!(self, heap_loc_as_cell!(h), solutions); + let solutions = self.machine_st.registers[2]; + unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions); } } &SystemClauseType::GetLiftedHeapFromOffset => { - let lh_offset = self.registers[1]; - let lh_offset = cell_as_fixnum!(self.store(self.deref(lh_offset))).get_num() as usize; + let lh_offset = self.machine_st.registers[1]; + let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))).get_num() as usize; - if lh_offset >= self.lifted_heap.len() { - let solutions = self.registers[2]; - unify_fn!(self, solutions, empty_list_as_cell!()); + if lh_offset >= self.machine_st.lifted_heap.len() { + let solutions = self.machine_st.registers[2]; + unify_fn!(self.machine_st, solutions, empty_list_as_cell!()); } else { - let h = self.heap.len(); + let h = self.machine_st.heap.len(); - for addr in self.lifted_heap[lh_offset..].iter().cloned() { - self.heap.push(addr + h); + for addr in self.machine_st.lifted_heap[lh_offset..].iter().cloned() { + self.machine_st.heap.push(addr + h); } - self.lifted_heap.truncate(lh_offset); + self.machine_st.lifted_heap.truncate(lh_offset); - let solutions = self.registers[2]; - unify_fn!(self, heap_loc_as_cell!(h), solutions); + let solutions = self.machine_st.registers[2]; + unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions); } } &SystemClauseType::GetDoubleQuotes => { - let a1 = self.store(self.deref(self.registers[1])); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - self.unify_atom( - match self.flags.double_quotes { + self.machine_st.unify_atom( + match self.machine_st.flags.double_quotes { DoubleQuotes::Chars => atom!("chars"), DoubleQuotes::Atom => atom!("atom"), DoubleQuotes::Codes => atom!("codes"), @@ -3233,32 +3248,27 @@ impl MachineState { ); } &SystemClauseType::GetSCCCleaner => { - let dest = self.registers[1]; + let dest = self.machine_st.registers[1]; - match cut_policy.downcast_mut::().ok() { - Some(sgc_policy) => { - if let Some((addr, b_cutoff, prev_b)) = sgc_policy.pop_cont_pt() { - let b = self.stack.index_or_frame(self.b).prelude.b; + if let Some((addr, b_cutoff, prev_b)) = self.machine_st.cont_pts.pop() { + let b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b; - if b <= b_cutoff { - self.block = prev_b; + if b <= b_cutoff { + self.machine_st.block = prev_b; - if let Some(r) = dest.as_var() { - self.bind(r, addr); - return return_from_clause!(self.last_call, self); - } - } else { - sgc_policy.push_cont_pt(addr, b_cutoff, prev_b); - } + if let Some(r) = dest.as_var() { + self.machine_st.bind(r, addr); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } + } else { + self.machine_st.cont_pts.push((addr, b_cutoff, prev_b)); } - None => {} } - self.fail = true; + self.machine_st.fail = true; } &SystemClauseType::Halt => { - let code = self.store(self.deref(self.registers[1])); + let code = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let code = match Number::try_from(code) { Ok(Number::Fixnum(n)) => i32::try_from(n.get_num()).unwrap(), @@ -3277,34 +3287,19 @@ impl MachineState { std::process::exit(code); } &SystemClauseType::InstallSCCCleaner => { - let addr = self.registers[1]; - let b = self.b; - let prev_block = self.block; + let addr = self.machine_st.registers[1]; + let b = self.machine_st.b; + let prev_block = self.machine_st.block; - if cut_policy.downcast_ref::().is_err() { - let (r_c_w_h, r_c_wo_h) = indices.get_cleaner_sites(); - *cut_policy = Box::new(SCCCutPolicy::new(r_c_w_h, r_c_wo_h)); - } + self.machine_st.run_cleaners_fn = Machine::run_cleaners; - match cut_policy.downcast_mut::().ok() { - Some(cut_policy) => { - self.install_new_block(self.registers[2]); - cut_policy.push_cont_pt(addr, b, prev_block); - } - None => panic!( - "install_cleaner: should have installed \\ - SCCCutPolicy." - ), - }; + self.machine_st.install_new_block(self.machine_st.registers[2]); + self.machine_st.cont_pts.push((addr, b, prev_block)); } &SystemClauseType::InstallInferenceCounter => { // A1 = B, A2 = L - let a1 = self.store(self.deref(self.registers[1])); - let a2 = self.store(self.deref(self.registers[2])); - - if call_policy.downcast_ref::().is_err() { - CWILCallPolicy::new_in_place(call_policy); - } + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let n = match Number::try_from(a2) { Ok(Number::Fixnum(bp)) => bp.get_num() as usize, @@ -3315,48 +3310,39 @@ impl MachineState { 3, ); - let err = self.type_error(ValidType::Integer, a2); - return Err(self.error_form(err, stub)); + let err = self.machine_st.type_error(ValidType::Integer, a2); + return Err(self.machine_st.error_form(err, stub)); } }; let bp = cell_as_fixnum!(a1).get_num() as usize; + let count = self.machine_st.cwil.add_limit(n, bp); + let count = arena_alloc!(count.clone(), &mut self.machine_st.arena); - match call_policy.downcast_mut::().ok() { - Some(call_policy) => { - let count = call_policy.add_limit(n, bp); - let count = arena_alloc!(count.clone(), &mut self.arena); + self.machine_st.increment_call_count_fn = MachineState::increment_call_count; - let a3 = self.store(self.deref(self.registers[3])); - self.unify_big_int(count, a3); - } - None => { - panic!( - "install_inference_counter: should have installed \\ - CWILCallPolicy." - ) - } - } + let a3 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + self.machine_st.unify_big_int(count, a3); } &SystemClauseType::ModuleExists => { - let module = self.store(self.deref(self.registers[1])); + let module = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let module_name = cell_as_atom!(module); - self.fail = !indices.modules.contains_key(&module_name); + self.machine_st.fail = !self.indices.modules.contains_key(&module_name); } &SystemClauseType::NoSuchPredicate => { - let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); - let head = self.store(self.deref(self.registers[2])); + let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); + let head = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - self.fail = read_heap_cell!(head, + self.machine_st.fail = read_heap_cell!(head, (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.heap[s]) + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) .get_name_and_arity(); if clause_type_form(name, arity).is_some() { true } else { - let index = indices.get_predicate_code_index( + let index = self.indices.get_predicate_code_index( name, arity, module_name, @@ -3376,7 +3362,7 @@ impl MachineState { if clause_type_form(name, 0).is_some() { true } else { - let index = indices.get_predicate_code_index( + let index = self.indices.get_predicate_code_index( name, 0, module_name, @@ -3391,229 +3377,217 @@ impl MachineState { } } _ => { - let err = self.type_error(ValidType::Callable, head); + let err = self.machine_st.type_error(ValidType::Callable, head); let stub = functor_stub(atom!("clause"), 2); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } ); } &SystemClauseType::RedoAttrVarBinding => { - let var = self.store(self.deref(self.registers[1])); - let value = self.store(self.deref(self.registers[2])); + let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); debug_assert_eq!(HeapCellValueTag::AttrVar, var.get_tag()); - self.heap[var.get_value()] = value; + self.machine_st.heap[var.get_value()] = value; } &SystemClauseType::ResetAttrVarState => { - self.attr_var_init.reset(); + self.machine_st.attr_var_init.reset(); } &SystemClauseType::RemoveCallPolicyCheck => { - let restore_default = match call_policy.downcast_mut::().ok() { - Some(call_policy) => { - let a1 = self.store(self.deref(self.registers[1])); - let bp = cell_as_fixnum!(a1).get_num() as usize; + let bp = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1] + ))).get_num() as usize; - if call_policy.is_empty() && bp == self.b { - Some(call_policy.into_inner()) - } else { - None - } - } - None => panic!( - "remove_call_policy_check: requires \\ - CWILCallPolicy." - ), - }; - - if let Some(new_policy) = restore_default { - *call_policy = new_policy; + if bp == self.machine_st.b && self.machine_st.cwil.is_empty() { + self.machine_st.cwil.reset(); + self.machine_st.increment_call_count_fn = |_| { Ok(()) }; } } &SystemClauseType::RemoveInferenceCounter => { - match call_policy.downcast_mut::().ok() { - Some(call_policy) => { - let a1 = self.store(self.deref(self.registers[1])); - let bp = cell_as_fixnum!(a1).get_num() as usize; + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let bp = cell_as_fixnum!(a1).get_num() as usize; - let count = call_policy.remove_limit(bp).clone(); - let count = arena_alloc!(count.clone(), &mut self.arena); + let count = self.machine_st.cwil.remove_limit(bp).clone(); + let count = arena_alloc!(count.clone(), &mut self.machine_st.arena); - let a2 = self.store(self.deref(self.registers[2])); + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - self.unify_big_int(count, a2); - } - None => panic!( - "remove_inference_counter: requires \\ - CWILCallPolicy." - ), - } + self.machine_st.unify_big_int(count, a2); } &SystemClauseType::REPL(repl_code_ptr) => { - return self.repl_redirect(repl_code_ptr); + return self.machine_st.repl_redirect(repl_code_ptr); } &SystemClauseType::ReturnFromVerifyAttr => { - let e = self.e; - let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells; + let e = self.machine_st.e; + let frame_len = self.machine_st.stack.index_and_frame(e).prelude.univ_prelude.num_cells; for i in 1..frame_len - 1 { - self.registers[i] = self.stack[stack_loc!(AndFrame, e, i)]; + self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)]; } - self.b0 = cell_as_fixnum!(self.stack[stack_loc!(AndFrame, e, frame_len - 1)]) + self.machine_st.b0 = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)]) .get_num() as usize; - self.num_of_args = cell_as_fixnum!(self.stack[stack_loc!(AndFrame, e, frame_len)]) + self.machine_st.num_of_args = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)]) .get_num() as usize; - self.deallocate(); - self.p = CodePtr::Local(self.stack.index_and_frame(e).prelude.interrupt_cp); + self.machine_st.deallocate(); + self.machine_st.p = CodePtr::Local(self.machine_st.stack.index_and_frame(e).prelude.interrupt_cp); return Ok(()); } &SystemClauseType::RestoreCutPolicy => { - let restore_default = - if let Ok(cut_policy) = cut_policy.downcast_ref::() { - cut_policy.out_of_cont_pts() - } else { - false - }; - - if restore_default { - *cut_policy = Box::new(DefaultCutPolicy {}); + if self.machine_st.cont_pts.is_empty() { + self.machine_st.run_cleaners_fn = |_| { false }; } } &SystemClauseType::SetCutPoint(r) => { - if cut_policy.cut(self, r) { + let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + self.machine_st.cut_body(cp); + + if (self.machine_st.run_cleaners_fn)(self) { return Ok(()); } } - &SystemClauseType::SetCutPointByDefault(r) => deref_cut(self, r), + &SystemClauseType::SetCutPointByDefault(r) => { + let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + self.machine_st.cut_body(cp); + } &SystemClauseType::SetInput => { - let addr = self.store(self.deref(self.registers[1])); - let stream = - self.get_stream_or_alias(addr, &indices.stream_aliases, atom!("set_input"), 1)?; + let addr = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1] + )); + let stream = self.machine_st.get_stream_or_alias( + addr, + &self.indices.stream_aliases, + atom!("set_input"), + 1, + )?; if !stream.is_input_stream() { let stub = functor_stub(atom!("set_input"), 1); - let user_alias = atom_as_cell!(atom!("user")); - let err = self.permission_error( + let err = self.machine_st.permission_error( Permission::InputStream, atom!("stream"), user_alias, ); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } - *current_input_stream = stream; + self.user_input = stream; } &SystemClauseType::SetOutput => { - let addr = self.store(self.deref(self.registers[1])); - let stream = - self.get_stream_or_alias(addr, &indices.stream_aliases, atom!("set_output"), 1)?; + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let stream = self.machine_st.get_stream_or_alias( + addr, + &self.indices.stream_aliases, + atom!("set_output"), + 1, + )?; if !stream.is_output_stream() { let stub = functor_stub(atom!("set_input"), 1); let user_alias = atom_as_cell!(atom!("user")); - let err = self.permission_error( + let err = self.machine_st.permission_error( Permission::OutputStream, atom!("stream"), user_alias, ); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } - *current_output_stream = stream; + self.user_output = stream; } &SystemClauseType::SetDoubleQuotes => { - let atom = cell_as_atom!(self.registers[1]); + let atom = cell_as_atom!(self.machine_st.registers[1]); - self.flags.double_quotes = match atom { + self.machine_st.flags.double_quotes = match atom { atom!("atom") => DoubleQuotes::Atom, atom!("chars") => DoubleQuotes::Chars, atom!("codes") => DoubleQuotes::Codes, _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; } &SystemClauseType::InferenceLevel => { - let a1 = self.registers[1]; - let a2 = self.store(self.deref(self.registers[2])); + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let bp = cell_as_fixnum!(a2).get_num() as usize; - let prev_b = self.stack.index_or_frame(self.b).prelude.b; + let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b; if prev_b <= bp { - self.unify_atom(atom!("!"), a1) + self.machine_st.unify_atom(atom!("!"), a1) } else { - self.unify_atom(atom!("true"), a1); + self.machine_st.unify_atom(atom!("true"), a1); } } &SystemClauseType::CleanUpBlock => { - let nb = self.store(self.deref(self.registers[1])); + let nb = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let nb = cell_as_fixnum!(nb).get_num() as usize; - let b = self.b; + let b = self.machine_st.b; - if nb > 0 && self.stack.index_or_frame(b).prelude.b == nb { - self.b = self.stack.index_or_frame(nb).prelude.b; + if nb > 0 && self.machine_st.stack.index_or_frame(b).prelude.b == nb { + self.machine_st.b = self.machine_st.stack.index_or_frame(nb).prelude.b; } } &SystemClauseType::EraseBall => { - self.ball.reset(); + self.machine_st.ball.reset(); } &SystemClauseType::Fail => { - self.fail = true; + self.machine_st.fail = true; } &SystemClauseType::GetBall => { - let addr = self.store(self.deref(self.registers[1])); - let h = self.heap.len(); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let h = self.machine_st.heap.len(); - if self.ball.stub.len() > 0 { - let stub = self.ball.copy_and_align(h); - self.heap.extend(stub.into_iter()); + if self.machine_st.ball.stub.len() > 0 { + let stub = self.machine_st.ball.copy_and_align(h); + self.machine_st.heap.extend(stub.into_iter()); } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } match addr.as_var() { - Some(r) => self.bind(r, self.heap[h]), - _ => self.fail = true, + Some(r) => self.machine_st.bind(r, self.machine_st.heap[h]), + _ => self.machine_st.fail = true, }; } &SystemClauseType::GetCurrentBlock => { - let n = Fixnum::build_with(i64::try_from(self.block).unwrap()); - self.unify_fixnum(n, self.registers[1]); + let n = Fixnum::build_with(i64::try_from(self.machine_st.block).unwrap()); + self.machine_st.unify_fixnum(n, self.machine_st.registers[1]); } &SystemClauseType::GetBValue => { - let n = Fixnum::build_with(i64::try_from(self.b).unwrap()); - self.unify_fixnum(n, self.registers[1]); + let n = Fixnum::build_with(i64::try_from(self.machine_st.b).unwrap()); + self.machine_st.unify_fixnum(n, self.machine_st.registers[1]); } &SystemClauseType::GetCutPoint => { - let n = Fixnum::build_with(i64::try_from(self.b0).unwrap()); - self.unify_fixnum(n, self.registers[1]); + let n = Fixnum::build_with(i64::try_from(self.machine_st.b0).unwrap()); + self.machine_st.unify_fixnum(n, self.machine_st.registers[1]); } &SystemClauseType::GetStaggeredCutPoint => { use std::sync::Once; - let b = self.store(self.deref(self.registers[1])); + let b = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); static mut SEMICOLON_SECOND_BRANCH_LOC: usize = 0; static LOC_INIT: Once = Once::new(); let semicolon_second_clause_p = unsafe { LOC_INIT.call_once(|| { - match indices.code_dir.get(&(atom!(";"), 2)).map(|cell| cell.get()) { + match self.indices.code_dir.get(&(atom!(";"), 2)).map(|cell| cell.get()) { Some(IndexPtr::Index(p)) => { - match code_repo.code[p] { + match self.code_repo.code[p] { Line::Choice(ChoiceInstruction::TryMeElse(o)) => { SEMICOLON_SECOND_BRANCH_LOC = p + o; } @@ -3631,77 +3605,77 @@ impl MachineState { LocalCodePtr::DirEntry(SEMICOLON_SECOND_BRANCH_LOC) }; - let staggered_b0 = if self.b > 0 { - let or_frame = self.stack.index_or_frame(self.b); + let staggered_b0 = if self.machine_st.b > 0 { + let or_frame = self.machine_st.stack.index_or_frame(self.machine_st.b); if or_frame.prelude.bp == semicolon_second_clause_p { or_frame.prelude.b0 } else { - self.b0 + self.machine_st.b0 } } else { - self.b0 + self.machine_st.b0 }; let staggered_b0 = integer_as_cell!( - Number::arena_from(staggered_b0, &mut self.arena) + Number::arena_from(staggered_b0, &mut self.machine_st.arena) ); - self.bind(b.as_var().unwrap(), staggered_b0); + self.machine_st.bind(b.as_var().unwrap(), staggered_b0); } &SystemClauseType::InstallNewBlock => { - self.install_new_block(self.registers[1]); + self.machine_st.install_new_block(self.machine_st.registers[1]); } &SystemClauseType::NextEP => { - let first_arg = self.store(self.deref(self.registers[1])); + let first_arg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); read_heap_cell!(first_arg, (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(name, atom!("first")); debug_assert_eq!(arity, 0); - if self.e == 0 { - self.fail = true; + if self.machine_st.e == 0 { + self.machine_st.fail = true; return Ok(()); } - let and_frame = self.stack.index_and_frame(self.e); + let and_frame = self.machine_st.stack.index_and_frame(self.machine_st.e); let cp = (and_frame.prelude.cp - 1).unwrap(); let e = and_frame.prelude.e; let e = Fixnum::build_with(i64::try_from(e).unwrap()); - let p = str_loc_as_cell!(self.heap.len()); + let p = str_loc_as_cell!(self.machine_st.heap.len()); - self.heap.extend(cp.as_functor()); - self.unify_fixnum(e, self.registers[2]); + self.machine_st.heap.extend(cp.as_functor()); + self.machine_st.unify_fixnum(e, self.machine_st.registers[2]); - if !self.fail { - unify!(self, p, self.registers[3]); + if !self.machine_st.fail { + unify!(self.machine_st, p, self.machine_st.registers[3]); } } (HeapCellValueTag::Fixnum, n) => { let e = n.get_num() as usize; if e == 0 { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } // get the call site so that the number of // active permanent variables can be read from // it later. - let and_frame = self.stack.index_and_frame(e); + let and_frame = self.machine_st.stack.index_and_frame(e); let cp = (and_frame.prelude.cp - 1).unwrap(); - let p = str_loc_as_cell!(self.heap.len()); - self.heap.extend(cp.as_functor()); + let p = str_loc_as_cell!(self.machine_st.heap.len()); + self.machine_st.heap.extend(cp.as_functor()); let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap()); - self.unify_fixnum(e, self.registers[2]); + self.machine_st.unify_fixnum(e, self.machine_st.registers[2]); - if !self.fail { - unify!(self, p, self.registers[3]); + if !self.machine_st.fail { + unify!(self.machine_st, p, self.machine_st.registers[3]); } } _ => { @@ -3710,59 +3684,59 @@ impl MachineState { ); } &SystemClauseType::PointsToContinuationResetMarker => { - let addr = self.store(self.deref(self.registers[1])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let p = match to_local_code_ptr(&self.heap, addr) { + let p = match to_local_code_ptr(&self.machine_st.heap, addr) { Some(p) => p + 1, None => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; - if self.is_reset_cont_marker(&code_repo, p) { - return return_from_clause!(self.last_call, self); + if self.is_reset_cont_marker(p) { + return return_from_clause!(self.machine_st.last_call, self.machine_st); } - self.fail = true; + self.machine_st.fail = true; return Ok(()); } &SystemClauseType::QuotedToken => { - let addr = self.store(self.deref(self.registers[1])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); read_heap_cell!(addr, (HeapCellValueTag::Fixnum, n) => { let n = u32::try_from(n.get_num()).ok(); let n = n.and_then(std::char::from_u32); - self.fail = match n { + self.machine_st.fail = match n { Some(c) => non_quoted_token(once(c)), None => true, }; } (HeapCellValueTag::Char, c) => { - self.fail = non_quoted_token(once(c)); + self.machine_st.fail = non_quoted_token(once(c)); } (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); - self.fail = non_quoted_token(name.as_str().chars()); + self.machine_st.fail = non_quoted_token(name.as_str().chars()); } _ => { - self.fail = true; + self.machine_st.fail = true; } ); } &SystemClauseType::ReadQueryTerm => { - current_input_stream.reset(); + self.user_input.reset(); set_prompt(true); - let result = self.read_term(*current_input_stream, indices); + let result = self.machine_st.read_term(self.user_input, &mut self.indices); set_prompt(false); match result { Ok(()) => {} Err(e) => { - *current_input_stream = input_stream(&mut self.arena); + self.user_input = input_stream(&mut self.machine_st.arena); return Err(e); } } @@ -3770,55 +3744,55 @@ impl MachineState { &SystemClauseType::ReadTerm => { set_prompt(false); - let stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("read_term"), 3, )?; - self.read_term(stream, indices)?; + self.machine_st.read_term(stream, &mut self.indices)?; } &SystemClauseType::ReadTermFromChars => { - if let Some(atom_or_string) = self.value_to_str_like(self.registers[1]) { + if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { let chars = atom_or_string.to_string(); - let stream = Stream::from_owned_string(chars, &mut self.arena); + let stream = Stream::from_owned_string(chars, &mut self.machine_st.arena); - let term_write_result = match self.read(stream, &indices.op_dir) { + let term_write_result = match self.machine_st.read(stream, &self.indices.op_dir) { Ok(term_write_result) => term_write_result, Err(e) => { let stub = functor_stub(atom!("read_term_from_chars"), 2); - let e = self.session_error(SessionError::from(e)); + let e = self.machine_st.session_error(SessionError::from(e)); - return Err(self.error_form(e, stub)); + return Err(self.machine_st.error_form(e, stub)); } }; let result = heap_loc_as_cell!(term_write_result.heap_loc); - let var = self.store(self.deref(self.registers[2])).as_var().unwrap(); + let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])).as_var().unwrap(); - self.bind(var, result); + self.machine_st.bind(var, result); } else { unreachable!() } } &SystemClauseType::ResetBlock => { - let addr = self.deref(self.registers[1]); - self.reset_block(addr); + let addr = self.machine_st.deref(self.machine_st.registers[1]); + self.machine_st.reset_block(addr); } &SystemClauseType::ResetContinuationMarker => { - let h = self.heap.len(); + let h = self.machine_st.heap.len(); - self.registers[3] = atom_as_cell!(atom!("none")); - self.registers[4] = heap_loc_as_cell!(h); + self.machine_st.registers[3] = atom_as_cell!(atom!("none")); + self.machine_st.registers[4] = heap_loc_as_cell!(h); - self.heap.push(heap_loc_as_cell!(h)); + self.machine_st.heap.push(heap_loc_as_cell!(h)); } &SystemClauseType::SetBall => { - self.set_ball(); + self.machine_st.set_ball(); } &SystemClauseType::SetSeed => { - let seed = self.store(self.deref(self.registers[1])); + let seed = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let mut rand = RANDOM_STATE.borrow_mut(); match Number::try_from(seed) { @@ -3826,18 +3800,18 @@ impl MachineState { Ok(Number::Integer(n)) => rand.seed(&*n), Ok(Number::Rational(n)) if n.denom() == &1 => rand.seed(n.numer()), _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } &SystemClauseType::SkipMaxList => { - if let Err(err) = self.skip_max_list() { + if let Err(err) = self.machine_st.skip_max_list() { return Err(err); } } &SystemClauseType::Sleep => { - let time = self.store(self.deref(self.registers[1])); + let time = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let time = match Number::try_from(time) { Ok(Number::Float(n)) => n.into_inner(), @@ -3854,8 +3828,8 @@ impl MachineState { std::thread::sleep(duration); } &SystemClauseType::SocketClientOpen => { - let addr = self.store(self.deref(self.registers[1])); - let port = self.store(self.deref(self.registers[2])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let socket_atom = cell_as_atom!(addr); @@ -3865,7 +3839,7 @@ impl MachineState { name } _ => { - self.atom_tbl.build_with(&match Number::try_from(port) { + self.machine_st.atom_tbl.build_with(&match Number::try_from(port) { Ok(Number::Fixnum(n)) => n.get_num().to_string(), Ok(Number::Integer(n)) => n.to_string(), _ => { @@ -3881,20 +3855,20 @@ impl MachineState { socket_atom }; - let alias = self.registers[4]; - let eof_action = self.registers[5]; - let reposition = self.registers[6]; - let stream_type = self.registers[7]; + let alias = self.machine_st.registers[4]; + let eof_action = self.machine_st.registers[5]; + let reposition = self.machine_st.registers[6]; + let stream_type = self.machine_st.registers[7]; - let options = self.to_stream_options(alias, eof_action, reposition, stream_type); + let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); if options.reposition() { - return Err(self.reposition_error(atom!("socket_client_open"), 3)); + return Err(self.machine_st.reposition_error(atom!("socket_client_open"), 3)); } if let Some(alias) = options.get_alias() { - if indices.stream_aliases.contains_key(&alias) { - return Err(self.occupied_alias_permission_error( + if self.indices.stream_aliases.contains_key(&alias) { + return Err(self.machine_st.occupied_alias_permission_error( alias, atom!("socket_client_open"), 3, @@ -3909,36 +3883,36 @@ impl MachineState { *stream.options_mut() = options; if let Some(alias) = stream.options().get_alias() { - indices.stream_aliases.insert(alias, stream); + self.indices.stream_aliases.insert(alias, stream); } - indices.streams.insert(stream); + self.indices.streams.insert(stream); stream_as_cell!(stream) } Err(ErrorKind::PermissionDenied) => { - return Err(self.open_permission_error(addr, atom!("socket_client_open"), 3)); + return Err(self.machine_st.open_permission_error(addr, atom!("socket_client_open"), 3)); } Err(ErrorKind::NotFound) => { let stub = functor_stub(atom!("socket_client_open"), 3); - let err = self.existence_error( + let err = self.machine_st.existence_error( ExistenceError::SourceSink(addr), ); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } Err(_) => { // for now, just fail. expand to meaningful error messages later. - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; - let stream_addr = self.store(self.deref(self.registers[3])); - self.bind(stream_addr.as_var().unwrap(), stream); + let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + self.machine_st.bind(stream_addr.as_var().unwrap(), stream); } &SystemClauseType::SocketServerOpen => { - let addr = self.store(self.deref(self.registers[1])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let socket_atom = cell_as_atom_cell!(addr).get_name(); let socket_atom = if socket_atom == atom!("[]") { @@ -3947,7 +3921,7 @@ impl MachineState { socket_atom }; - let port = self.store(self.deref(self.registers[2])); + let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let port = if port.is_var() { String::from("0") @@ -3975,43 +3949,43 @@ impl MachineState { let port = tcp_listener.local_addr().map(|addr| addr.port()).ok(); if let Some(port) = port { - (arena_alloc!(tcp_listener, &mut self.arena), port as usize) + (arena_alloc!(tcp_listener, &mut self.machine_st.arena), port as usize) } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } Err(ErrorKind::PermissionDenied) => { - return Err(self.open_permission_error(addr, atom!("socket_server_open"), 2)); + return Err(self.machine_st.open_permission_error(addr, atom!("socket_server_open"), 2)); } _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; - let addr = self.store(self.deref(self.registers[3])); - self.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener)); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + self.machine_st.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener)); if had_zero_port { - self.unify_fixnum(Fixnum::build_with(port as i64), self.registers[2]); + self.machine_st.unify_fixnum(Fixnum::build_with(port as i64), self.machine_st.registers[2]); } } &SystemClauseType::SocketServerAccept => { - let alias = self.registers[4]; - let eof_action = self.registers[5]; - let reposition = self.registers[6]; - let stream_type = self.registers[7]; + let alias = self.machine_st.registers[4]; + let eof_action = self.machine_st.registers[5]; + let reposition = self.machine_st.registers[6]; + let stream_type = self.machine_st.registers[7]; - let options = self.to_stream_options(alias, eof_action, reposition, stream_type); + let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); if options.reposition() { - return Err(self.reposition_error(atom!("socket_server_accept"), 4)); + return Err(self.machine_st.reposition_error(atom!("socket_server_accept"), 4)); } if let Some(alias) = options.get_alias() { - if indices.stream_aliases.contains_key(&alias) { - return Err(self.occupied_alias_permission_error( + if self.indices.stream_aliases.contains_key(&alias) { + return Err(self.machine_st.occupied_alias_permission_error( alias, atom!("socket_server_accept"), 4, @@ -4019,7 +3993,7 @@ impl MachineState { } } - let culprit = self.store(self.deref(self.registers[1])); + let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); read_heap_cell!(culprit, (HeapCellValueTag::Cons, cons_ptr) => { @@ -4027,35 +4001,39 @@ impl MachineState { (ArenaHeaderTag::TcpListener, tcp_listener) => { match tcp_listener.accept().ok() { Some((tcp_stream, socket_addr)) => { - let client = self.atom_tbl.build_with(&socket_addr.to_string()); + let client = self.machine_st.atom_tbl.build_with(&socket_addr.to_string()); let mut tcp_stream = Stream::from_tcp_stream( client, tcp_stream, - &mut self.arena, + &mut self.machine_st.arena, ); *tcp_stream.options_mut() = options; if let Some(alias) = &tcp_stream.options().get_alias() { - indices.stream_aliases.insert(*alias, tcp_stream); + self.indices.stream_aliases.insert(*alias, tcp_stream); } - indices.streams.insert(tcp_stream); + self.indices.streams.insert(tcp_stream); let tcp_stream = stream_as_cell!(tcp_stream); let client = atom_as_cell!(client); - let client_addr = self.store(self.deref(self.registers[2])); - let stream_addr = self.store(self.deref(self.registers[3])); + let client_addr = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2], + )); + let stream_addr = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[3], + )); - self.bind(client_addr.as_var().unwrap(), client); - self.bind(stream_addr.as_var().unwrap(), tcp_stream); + self.machine_st.bind(client_addr.as_var().unwrap(), client); + self.machine_st.bind(stream_addr.as_var().unwrap(), tcp_stream); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } None => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } @@ -4102,24 +4080,24 @@ impl MachineState { } } &SystemClauseType::TLSAcceptClient => { - let pkcs12 = self.string_encoding_bytes(self.registers[1], atom!("octet")); + let pkcs12 = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); - if let Some(password) = self.value_to_str_like(self.registers[2]) { + if let Some(password) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { let identity = match Identity::from_pkcs12(&pkcs12, password.as_str()) { Ok(identity) => identity, Err(_) => { - return Err(self.open_permission_error( - self.registers[1], + return Err(self.machine_st.open_permission_error( + self.machine_st.registers[1], atom!("tls_server_negotiate"), 3, )); } }; - let stream0 = self.get_stream_or_alias( - self.registers[3], - &indices.stream_aliases, + let stream0 = self.machine_st.get_stream_or_alias( + self.machine_st.registers[3], + &self.indices.stream_aliases, atom!("tls_server_negotiate"), 3, )?; @@ -4130,25 +4108,25 @@ impl MachineState { match acceptor.accept(stream0) { Ok(tls_stream) => tls_stream, Err(_) => { - return Err(self.open_permission_error( - self.registers[3], + return Err(self.machine_st.open_permission_error( + self.machine_st.registers[3], atom!("tls_server_negotiate"), 3, )); } }; - let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.arena); - indices.streams.insert(stream); + let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.machine_st.arena); + self.indices.streams.insert(stream); - let stream_addr = self.store(self.deref(self.registers[4])); - self.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); + let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4])); + self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); } else { unreachable!(); } } &SystemClauseType::SocketServerClose => { - let culprit = self.store(self.deref(self.registers[1])); + let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); read_heap_cell!(culprit, (HeapCellValueTag::Cons, cons_ptr) => { @@ -4160,7 +4138,7 @@ impl MachineState { } tcp_listener.set_tag(ArenaHeaderTag::Dropped); - return return_from_clause!(self.last_call, self); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } _ => { } @@ -4170,15 +4148,15 @@ impl MachineState { } ); - let err = self.type_error(ValidType::TcpListener, culprit); + let err = self.machine_st.type_error(ValidType::TcpListener, culprit); let stub = functor_stub(atom!("socket_server_close"), 1); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } &SystemClauseType::SetStreamPosition => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("set_stream_position"), 2, )?; @@ -4186,16 +4164,16 @@ impl MachineState { if !stream.options().reposition() { let stub = functor_stub(atom!("set_stream_position"), 2); - let err = self.permission_error( + let err = self.machine_st.permission_error( Permission::Reposition, atom!("stream"), vec![stream_as_cell!(stream)], ); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } - let position = self.store(self.deref(self.registers[2])); + let position = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let position = match Number::try_from(position) { Ok(Number::Fixnum(n)) => n.get_num() as u64, @@ -4203,7 +4181,7 @@ impl MachineState { if let Some(n) = n.to_u64() { n } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } @@ -4215,21 +4193,21 @@ impl MachineState { stream.set_position(position); } &SystemClauseType::StreamProperty => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("stream_property"), 2, )?; - let atom = cell_as_atom!(self.store(self.deref(self.registers[2]))); + let atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); let property = match atom { atom!("file_name") => { atom_as_cell!(if let Some(file_name) = stream.file_name() { file_name } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); }) } @@ -4246,24 +4224,24 @@ impl MachineState { atom_as_cell!(if let Some(alias) = stream.options().get_alias() { alias } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); }) } atom!("position") => { if let Some((position, lines_read)) = stream.position() { - let h = self.heap.len(); + let h = self.machine_st.heap.len(); let position_term = functor!( atom!("position_and_lines_read"), - [integer(position, &mut self.arena), - integer(lines_read, &mut self.arena)] + [integer(position, &mut self.machine_st.arena), + integer(lines_read, &mut self.machine_st.arena)] ); - self.heap.extend(position_term.into_iter()); + self.machine_st.heap.extend(position_term.into_iter()); str_loc_as_cell!(h) } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } @@ -4288,76 +4266,76 @@ impl MachineState { } }; - unify!(self, property, self.registers[3]); + unify!(self.machine_st, property, self.machine_st.registers[3]); } &SystemClauseType::StoreGlobalVar => { - let key = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); - let value = self.registers[2]; + let value = self.machine_st.registers[2]; let mut ball = Ball::new(); - ball.boundary = self.heap.len(); + ball.boundary = self.machine_st.heap.len(); copy_term( - CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut ball.stub), + CopyBallTerm::new(&mut self.machine_st.stack, &mut self.machine_st.heap, &mut ball.stub), value, AttrVarPolicy::DeepCopy, ); - indices.global_variables.insert(key, (ball, None)); + self.indices.global_variables.insert(key, (ball, None)); } &SystemClauseType::StoreBacktrackableGlobalVar => { - let key = cell_as_atom!(self.store(self.deref(self.registers[1]))); - let new_value = self.store(self.deref(self.registers[2])); + let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); + let new_value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - match indices.global_variables.get_mut(&key) { + match self.indices.global_variables.get_mut(&key) { Some((_, ref mut loc)) => match loc { Some(ref mut value) => { - self.trail(TrailRef::BlackboardOffset(key, *value)); + self.machine_st.trail(TrailRef::BlackboardOffset(key, *value)); *value = new_value; } loc @ None => { - self.trail(TrailRef::BlackboardEntry(key)); + self.machine_st.trail(TrailRef::BlackboardEntry(key)); *loc = Some(new_value); } }, None => { - self.trail(TrailRef::BlackboardEntry(key)); - indices + self.machine_st.trail(TrailRef::BlackboardEntry(key)); + self.indices .global_variables .insert(key, (Ball::new(), Some(new_value))); } } } &SystemClauseType::TermAttributedVariables => { - if self.registers[1].is_constant() { - self.unify_atom(atom!("[]"), self.store(self.deref(self.registers[2]))); - return return_from_clause!(self.last_call, self); + if self.machine_st.registers[1].is_constant() { + self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } - let seen_vars = self.attr_vars_of_term(self.registers[1]); + let seen_vars = self.machine_st.attr_vars_of_term(self.machine_st.registers[1]); let outcome = heap_loc_as_cell!( - iter_to_heap_list(&mut self.heap, seen_vars.into_iter()) + iter_to_heap_list(&mut self.machine_st.heap, seen_vars.into_iter()) ); - unify_fn!(self, self.registers[2], outcome); + unify_fn!(self.machine_st, self.machine_st.registers[2], outcome); } &SystemClauseType::Succeed => {} &SystemClauseType::TermVariables => { - let a1 = self.registers[1]; - let a2 = self.registers[2]; + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; - let stored_v = self.store(self.deref(a1)); + let stored_v = self.machine_st.store(self.machine_st.deref(a1)); if stored_v.is_constant() { - self.unify_atom(atom!("[]"), self.store(self.deref(a2))); - return return_from_clause!(self.last_call, self); + self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(a2))); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } let mut seen_set = IndexSet::new(); { - let mut iter = stackless_preorder_iter(&mut self.heap, stored_v); + let mut iter = stackless_preorder_iter(&mut self.machine_st.heap, stored_v); while let Some(addr) = iter.next() { let addr = unmark_cell_bits!(addr); @@ -4370,7 +4348,7 @@ impl MachineState { let outcome = heap_loc_as_cell!( filtered_iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, seen_set.into_iter().rev(), |heap, value| { heap_bound_store( @@ -4381,57 +4359,63 @@ impl MachineState { ) ); - unify_fn!(self, a2, outcome); + unify_fn!(self.machine_st, a2, outcome); } &SystemClauseType::TermVariablesUnderMaxDepth => { // Term, MaxDepth, VarList let max_depth = cell_as_fixnum!( - self.store(self.deref(self.registers[2])) + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) ).get_num() as usize; - self.term_variables_under_max_depth(self.registers[1], max_depth, self.registers[3]); + self.machine_st.term_variables_under_max_depth( + self.machine_st.registers[1], + max_depth, + self.machine_st.registers[3], + ); } &SystemClauseType::TruncateLiftedHeapTo => { - let a1 = self.store(self.deref(self.registers[1])); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let lh_offset = cell_as_fixnum!(a1).get_num() as usize; - self.lifted_heap.truncate(lh_offset); + self.machine_st.lifted_heap.truncate(lh_offset); } &SystemClauseType::UnifyWithOccursCheck => { - let a1 = self.registers[1]; - let a2 = self.registers[2]; + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; - unify_with_occurs_check!(self, a1, a2); + unify_with_occurs_check!(&mut self.machine_st, a1, a2); } &SystemClauseType::UnwindEnvironments => { - let mut e = self.e; - let mut cp = self.cp; + let mut e = self.machine_st.e; + let mut cp = self.machine_st.cp; while e > 0 { - if self.is_reset_cont_marker(code_repo, cp) { - self.e = e; - self.p = CodePtr::Local(cp + 1); // skip the reset marker. + if self.is_reset_cont_marker(cp) { + self.machine_st.e = e; + self.machine_st.p = CodePtr::Local(cp + 1); // skip the reset marker. return Ok(()); } - let and_frame = self.stack.index_and_frame(e); + let and_frame = self.machine_st.stack.index_and_frame(e); cp = and_frame.prelude.cp; e = and_frame.prelude.e; } } &SystemClauseType::UnwindStack => { - self.unwind_stack(); + self.machine_st.unwind_stack(); } &SystemClauseType::WAMInstructions => { - let module_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1]) + )); - let name = self.registers[2]; - let arity = self.registers[3]; + let name = self.machine_st.registers[2]; + let arity = self.machine_st.registers[3]; - let name = cell_as_atom!(self.store(self.deref(name))); - let arity = self.store(self.deref(arity)); + let name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(name))); + let arity = self.machine_st.store(self.machine_st.deref(arity)); let arity = match Number::try_from(arity) { Ok(Number::Fixnum(n)) => n.get_num() as usize, @@ -4444,18 +4428,18 @@ impl MachineState { let key = (name, arity); let first_idx = match module_name { - atom!("user") => indices.code_dir.get(&key), - _ => match indices.modules.get(&module_name) { + atom!("user") => self.indices.code_dir.get(&key), + _ => match self.indices.modules.get(&module_name) { Some(module) => module.code_dir.get(&key), None => { let stub = functor_stub(key.0, key.1); - let err = self.session_error( + let err = self.machine_st.session_error( SessionError::from(CompilationError::InvalidModuleResolution( module_name, )), ); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } }, }; @@ -4470,22 +4454,22 @@ impl MachineState { } _ => { let stub = functor_stub(name, arity); - let err = self.existence_error( + let err = self.machine_st.existence_error( ExistenceError::Procedure(name, arity), ); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } }; - let mut h = self.heap.len(); + let mut h = self.machine_st.heap.len(); let mut functors = vec![]; let mut functor_list = vec![]; - walk_code(&code_repo.code, first_idx, |instr| { + walk_code(&self.code_repo.code, first_idx, |instr| { let old_len = functors.len(); - instr.enqueue_functors(h, &mut self.arena, &mut functors); + instr.enqueue_functors(h, &mut self.machine_st.arena, &mut functors); let new_len = functors.len(); for index in old_len..new_len { @@ -4506,26 +4490,26 @@ impl MachineState { }); for functor in functors { - self.heap.extend(functor.into_iter()); + self.machine_st.heap.extend(functor.into_iter()); } let listing = heap_loc_as_cell!( - iter_to_heap_list(&mut self.heap, functor_list.into_iter()) + iter_to_heap_list(&mut self.machine_st.heap, functor_list.into_iter()) ); - let listing_var = self.registers[4]; + let listing_var = self.machine_st.registers[4]; - unify!(self, listing, listing_var); + unify!(self.machine_st, listing, listing_var); } &SystemClauseType::WriteTerm => { - let mut stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("write_term"), 3, )?; - self.check_stream_properties( + self.machine_st.check_stream_properties( stream, StreamType::Text, None, // input @@ -4542,7 +4526,7 @@ impl MachineState { }; if let Some(err_atom) = opt_err { - return Err(self.stream_permission_error( + return Err(self.machine_st.stream_permission_error( Permission::OutputStream, err_atom, stream, @@ -4551,7 +4535,7 @@ impl MachineState { )); } - let printer = match self.write_term(&indices.op_dir)? { + let printer = match self.machine_st.write_term(&self.indices.op_dir)? { Some(printer) => printer, None => { // this next line is executed by @@ -4559,7 +4543,7 @@ impl MachineState { // commented here because rustc can't prove // that it's no longer borrowed. - // self.fail = true; + // self.machine_st.fail = true; return Ok(()); } }; @@ -4570,37 +4554,37 @@ impl MachineState { Ok(_) => {} Err(_) => { let stub = functor_stub(atom!("open"), 4); - let err = self.existence_error( - ExistenceError::Stream(self.registers[1]), + let err = self.machine_st.existence_error( + ExistenceError::Stream(self.machine_st.registers[1]), ); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } } stream.flush().unwrap(); } &SystemClauseType::WriteTermToChars => { - let printer = match self.write_term(&indices.op_dir)? { + let printer = match self.machine_st.write_term(&self.indices.op_dir)? { None => { // this next line is executed by // MachineState::write_term in this case. it's // commented here because rustc can't prove // that it's no longer borrowed. - // self.fail = true; + // self.machine_st.fail = true; return Ok(()); } Some(printer) => printer, }; let result = printer.print().result(); - let chars = put_complete_string(&mut self.heap, &result, &mut self.atom_tbl); + let chars = put_complete_string(&mut self.machine_st.heap, &result, &mut self.machine_st.atom_tbl); - let result_addr = self.store(self.deref(self.registers[1])); + let result_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); if let Some(var) = result_addr.as_var() { - self.bind(var, chars); + self.machine_st.bind(var, chars); } else { unreachable!() } @@ -4609,12 +4593,12 @@ impl MachineState { use git_version::git_version; let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); - let buffer_atom = self.atom_tbl.build_with(buffer); + let buffer_atom = self.machine_st.atom_tbl.build_with(buffer); - self.unify_complete_string(buffer_atom, self.store(self.deref(self.registers[1]))); + self.machine_st.unify_complete_string(buffer_atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); } &SystemClauseType::CryptoRandomByte => { - let arg = self.registers[1]; + let arg = self.machine_st.registers[1]; let mut bytes: [u8; 1] = [0]; match rng().fill(&mut bytes) { @@ -4623,19 +4607,19 @@ impl MachineState { // the error payload here is of type 'Unspecified', // which contains no information whatsoever. So, for now, // just fail. - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } let byte = Fixnum::build_with(bytes[0] as i64); - self.unify_fixnum(byte, arg); + self.machine_st.unify_fixnum(byte, arg); } &SystemClauseType::CryptoDataHash => { - let encoding = cell_as_atom!(self.registers[2]); - let bytes = self.string_encoding_bytes(self.registers[1], encoding); + let encoding = cell_as_atom!(self.machine_st.registers[2]); + let bytes = self.string_encoding_bytes(self.machine_st.registers[1], encoding); - let algorithm = cell_as_atom!(self.registers[4]); + let algorithm = cell_as_atom!(self.machine_st.registers[4]); let ints_list = match algorithm { atom!("sha3_224") => { @@ -4644,7 +4628,7 @@ impl MachineState { heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, context .result() .as_ref() @@ -4658,7 +4642,7 @@ impl MachineState { context.input(&bytes); heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, context .result() .as_ref() @@ -4673,7 +4657,7 @@ impl MachineState { heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, context .result() .as_ref() @@ -4688,7 +4672,7 @@ impl MachineState { heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, context .result() .as_ref() @@ -4703,7 +4687,7 @@ impl MachineState { heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, context .result() .as_ref() @@ -4718,7 +4702,7 @@ impl MachineState { heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, context .result() .as_ref() @@ -4733,7 +4717,7 @@ impl MachineState { heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, context .result() .as_ref() @@ -4758,7 +4742,7 @@ impl MachineState { heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, ints.as_ref() .iter() .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), @@ -4767,28 +4751,28 @@ impl MachineState { } }; - unify!(self, self.registers[3], ints_list); + unify!(self.machine_st, self.machine_st.registers[3], ints_list); } &SystemClauseType::CryptoDataHKDF => { - let encoding = cell_as_atom!(self.registers[2]); - let data = self.string_encoding_bytes(self.registers[1], encoding); + let encoding = cell_as_atom!(self.machine_st.registers[2]); + let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding); let stub1_gen = || functor_stub(atom!("crypto_data_hkdf"), 4); - let salt = self.integers_to_bytevec(self.registers[3], stub1_gen); + let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen); let stub2_gen = || functor_stub(atom!("crypto_data_hkdf"), 4); - let info = self.integers_to_bytevec(self.registers[4], stub2_gen); + let info = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen); - let algorithm = cell_as_atom!(self.registers[5]); + let algorithm = cell_as_atom!(self.machine_st.registers[5]); - let length = self.store(self.deref(self.registers[6])); + let length = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[6])); let length = match Number::try_from(length) { Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match n.to_usize() { Some(u) => u, _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }, @@ -4803,7 +4787,7 @@ impl MachineState { atom!("sha384") => hkdf::HKDF_SHA384, atom!("sha512") => hkdf::HKDF_SHA512, _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; @@ -4818,14 +4802,14 @@ impl MachineState { r.fill(&mut bytes).unwrap(); } _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, bytes .iter() .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), @@ -4833,22 +4817,22 @@ impl MachineState { ) }; - unify!(self, self.registers[7], ints_list); + unify!(self.machine_st, self.machine_st.registers[7], ints_list); } &SystemClauseType::CryptoPasswordHash => { let stub1_gen = || functor_stub(atom!("crypto_password_hash"), 3); - let data = self.integers_to_bytevec(self.registers[1], stub1_gen); + let data = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen); let stub2_gen = || functor_stub(atom!("crypto_password_hash"), 3); - let salt = self.integers_to_bytevec(self.registers[2], stub2_gen); + let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen); - let iterations = self.store(self.deref(self.registers[3])); + let iterations = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); let iterations = match Number::try_from(iterations) { Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(), Ok(Number::Integer(n)) => match n.to_u64() { Some(i) => i, None => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }, @@ -4870,7 +4854,7 @@ impl MachineState { heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, bytes .iter() .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), @@ -4878,19 +4862,19 @@ impl MachineState { ) }; - unify!(self, self.registers[4], ints_list); + unify!(self.machine_st, self.machine_st.registers[4], ints_list); } &SystemClauseType::CryptoDataEncrypt => { - let encoding = cell_as_atom!(self.registers[3]); + let encoding = cell_as_atom!(self.machine_st.registers[3]); - let data = self.string_encoding_bytes(self.registers[1], encoding); - let aad = self.string_encoding_bytes(self.registers[2], encoding); + let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding); + let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding); let stub2_gen = || functor_stub(atom!("crypto_data_encrypt"), 7); - let key = self.integers_to_bytevec(self.registers[4], stub2_gen); + let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen); let stub3_gen = || functor_stub(atom!("crypto_data_encrypt"), 7); - let iv = self.integers_to_bytevec(self.registers[5], stub3_gen); + let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[5], stub3_gen); let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap(); @@ -4905,14 +4889,14 @@ impl MachineState { ) { Ok(d) => d, _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; let tag_list = heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, tag.as_ref() .iter() .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), @@ -4921,22 +4905,22 @@ impl MachineState { let complete_string = { let buffer = String::from_iter(in_out.iter().map(|b| *b as char)); - put_complete_string(&mut self.heap, &buffer, &mut self.atom_tbl) + put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl) }; - unify!(self, self.registers[6], tag_list); - unify!(self, self.registers[7], complete_string); + unify!(self.machine_st, self.machine_st.registers[6], tag_list); + unify!(self.machine_st, self.machine_st.registers[7], complete_string); } &SystemClauseType::CryptoDataDecrypt => { - let data = self.string_encoding_bytes(self.registers[1], atom!("octet")); - let encoding = cell_as_atom!(self.registers[5]); + let data = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.machine_st.registers[5]); - let aad = self.string_encoding_bytes(self.registers[2], encoding); + let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding); let stub1_gen = || functor_stub(atom!("crypto_data_decrypt"), 7); - let key = self.integers_to_bytevec(self.registers[3], stub1_gen); + let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen); let stub2_gen = || functor_stub(atom!("crypto_data_decrypt"), 7); - let iv = self.integers_to_bytevec(self.registers[4], stub2_gen); + let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen); let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap(); @@ -4949,7 +4933,7 @@ impl MachineState { match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) { Ok(d) => d, _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; @@ -4959,7 +4943,7 @@ impl MachineState { atom!("utf8") => match String::from_utf8(decrypted_data.to_vec()) { Ok(str) => str, _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }, @@ -4968,13 +4952,13 @@ impl MachineState { } }; - put_complete_string(&mut self.heap, &buffer, &mut self.atom_tbl) + put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl) }; - unify!(self, self.registers[6], complete_string); + unify!(self.machine_st, self.machine_st.registers[6], complete_string); } &SystemClauseType::CryptoCurveScalarMult => { - let curve = cell_as_atom!(self.registers[1]); + let curve = cell_as_atom!(self.machine_st.registers[1]); let curve_id = match curve { atom!("secp112r1") => Nid::SECP112R1, @@ -4984,7 +4968,7 @@ impl MachineState { } }; - let scalar = self.store(self.deref(self.registers[2])); + let scalar = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); let scalar = match Number::try_from(scalar) { Ok(Number::Fixnum(n)) => Integer::from(n.get_num()), @@ -4995,7 +4979,7 @@ impl MachineState { }; let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 5); - let qbytes = self.integers_to_bytevec(self.registers[3], stub_gen); + let qbytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub_gen); let mut bnctx = BigNumContext::new().unwrap(); let group = EcGroup::from_curve_name(curve_id).unwrap(); @@ -5013,40 +4997,40 @@ impl MachineState { .ok(); let sx = put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, &rx.to_dec_str().unwrap(), - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ); let sy = put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, &ry.to_dec_str().unwrap(), - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ); - unify!(self, self.registers[4], sx); - unify!(self, self.registers[5], sy); + unify!(self.machine_st, self.machine_st.registers[4], sx); + unify!(self.machine_st, self.machine_st.registers[5], sy); } &SystemClauseType::Ed25519NewKeyPair => { let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap(); let complete_string = { let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char)); put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, &buffer, - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ) }; - unify!(self, self.registers[1], complete_string) + unify!(self.machine_st, self.machine_st.registers[1], complete_string) } &SystemClauseType::Ed25519KeyPairPublicKey => { - let bytes = self.string_encoding_bytes(self.registers[1], atom!("octet")); + let bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) { Ok(kp) => kp, _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; @@ -5057,23 +5041,23 @@ impl MachineState { ); put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, &buffer, - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ) }; - unify!(self, self.registers[2], complete_string); + unify!(self.machine_st, self.machine_st.registers[2], complete_string); } &SystemClauseType::Ed25519Sign => { - let key = self.string_encoding_bytes(self.registers[1], atom!("octet")); - let encoding = cell_as_atom!(self.registers[3]); - let data = self.string_encoding_bytes(self.registers[2], encoding); + let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.machine_st.registers[3]); + let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding); let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) { Ok(kp) => kp, _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; @@ -5082,134 +5066,133 @@ impl MachineState { let sig_list = heap_loc_as_cell!( iter_to_heap_list( - &mut self.heap, + &mut self.machine_st.heap, sig.as_ref() .iter() .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), ) ); - unify!(self, self.registers[4], sig_list); + unify!(self.machine_st, self.machine_st.registers[4], sig_list); } &SystemClauseType::Ed25519Verify => { - let key = self.string_encoding_bytes(self.registers[1], atom!("octet")); - let encoding = cell_as_atom!(self.registers[3]); - let data = self.string_encoding_bytes(self.registers[2], encoding); + let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.machine_st.registers[3]); + let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding); let stub_gen = || functor_stub(atom!("ed25519_verify"), 5); - let signature = self.integers_to_bytevec(self.registers[4], stub_gen); + let signature = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub_gen); let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key); match peer_public_key.verify(&data, &signature) { Ok(_) => {} _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } &SystemClauseType::Curve25519ScalarMult => { let stub1_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3); - let scalar_bytes = self.integers_to_bytevec(self.registers[1], stub1_gen); + let scalar_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen); let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap()); let stub2_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3); - let point_bytes = self.integers_to_bytevec(self.registers[2], stub2_gen); + let point_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen); let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap()); let result = scalarmult(&scalar, &point).unwrap(); let string = String::from_iter(result[..].iter().map(|b| *b as char)); - let cstr = put_complete_string(&mut self.heap, &string, &mut self.atom_tbl); + let cstr = put_complete_string(&mut self.machine_st.heap, &string, &mut self.machine_st.atom_tbl); - unify!(self, self.registers[3], cstr); + unify!(self.machine_st, self.machine_st.registers[3], cstr); } &SystemClauseType::FirstNonOctet => { - let addr = self.store(self.deref(self.registers[1])); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - if let Some(string) = self.value_to_str_like(addr) { + if let Some(string) = self.machine_st.value_to_str_like(addr) { for c in string.as_str().chars() { if c as u32 > 255 { - let non_octet = self.atom_tbl.build_with(&c.to_string()); - self.unify_atom(non_octet, self.registers[2]); - return return_from_clause!(self.last_call, self); + let non_octet = self.machine_st.atom_tbl.build_with(&c.to_string()); + self.machine_st.unify_atom(non_octet, self.machine_st.registers[2]); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } } - self.fail = true; + self.machine_st.fail = true; return Ok(()); } &SystemClauseType::LoadHTML => { - if let Some(string) = self.value_to_str_like(self.registers[1]) { - let doc = select::document::Document::from_read(string.as_str().as_bytes()) - .unwrap(); + if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + let doc = select::document::Document::from_read(string.as_str().as_bytes()).unwrap(); + let result = self.html_node_to_term(doc.nth(0).unwrap()); - let result = self.html_node_to_term(indices, doc.nth(0).unwrap()); - unify!(self, self.registers[2], result); + unify!(self.machine_st, self.machine_st.registers[2], result); } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } &SystemClauseType::LoadXML => { - if let Some(string) = self.value_to_str_like(self.registers[1]) { + if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { match roxmltree::Document::parse(string.as_str()) { Ok(doc) => { - let result = self.xml_node_to_term(indices, doc.root_element()); - unify!(self, self.registers[2], result); + let result = self.xml_node_to_term(doc.root_element()); + unify!(self.machine_st, self.machine_st.registers[2], result); } _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } &SystemClauseType::GetEnv => { - if let Some(key) = self.value_to_str_like(self.registers[1]) { + if let Some(key) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { match env::var(key.as_str()) { Ok(value) => { let cstr = put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, &value, - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ); - unify!(self, self.registers[2], cstr); + unify!(self.machine_st, self.machine_st.registers[2], cstr); } _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } else { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } &SystemClauseType::SetEnv => { - let key = self.value_to_str_like(self.registers[1]).unwrap(); - let value = self.value_to_str_like(self.registers[2]).unwrap(); + let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap(); + let value = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap(); env::set_var(key.as_str(), value.as_str()); } &SystemClauseType::UnsetEnv => { - let key = self.value_to_str_like(self.registers[1]).unwrap(); + let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap(); env::remove_var(key.as_str()); } &SystemClauseType::PID => { let pid = process::id(); - match fixnum!(Number, pid as i64, &mut self.arena) { + match fixnum!(Number, pid as i64, &mut self.machine_st.arena) { Number::Fixnum(pid) => { - self.unify_fixnum(pid, self.registers[1]); + self.machine_st.unify_fixnum(pid, self.machine_st.registers[1]); } Number::Integer(pid) => { - self.unify_big_int(pid, self.registers[1]); + self.machine_st.unify_big_int(pid, self.machine_st.registers[1]); } _ => { unreachable!(); @@ -5241,7 +5224,7 @@ impl MachineState { } } - let command = self.value_to_str_like(self.store(self.deref(self.registers[1]))).unwrap(); + let command = self.machine_st.value_to_str_like(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))).unwrap(); match env::var("SHELL") { Ok(value) => { @@ -5249,7 +5232,7 @@ impl MachineState { .arg("-c") .arg(command.as_str()) .status(); - command_result(self, command); + command_result(&mut self.machine_st, command); } _ => { match env::var("COMSPEC") { @@ -5258,18 +5241,18 @@ impl MachineState { .arg("/C") .arg(command.as_str()) .status(); - command_result(self, command); + command_result(&mut self.machine_st, command); } _ => { - self.fail = true; + self.machine_st.fail = true; } } } }; } &SystemClauseType::CharsBase64 => { - let padding = cell_as_atom!(self.registers[3]); - let charset = cell_as_atom!(self.registers[4]); + let padding = cell_as_atom!(self.machine_st.registers[3]); + let charset = cell_as_atom!(self.machine_st.registers[4]); let config = if padding == atom!("true") { if charset == atom!("standard") { @@ -5285,38 +5268,38 @@ impl MachineState { } }; - if self.store(self.deref(self.registers[1])).is_var() { - let b64 = self.value_to_str_like(self.registers[2]).unwrap(); + if self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])).is_var() { + let b64 = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap(); let bytes = base64::decode_config(b64.as_str(), config); match bytes { Ok(bs) => { let string = String::from_iter(bs.iter().map(|b| *b as char)); let cstr = put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, &string, - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ); - unify!(self, self.registers[1], cstr); + unify!(self.machine_st, self.machine_st.registers[1], cstr); } _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } else { let mut bytes = vec![]; - for c in self.value_to_str_like(self.registers[1]).unwrap().as_str().chars() { + for c in self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap().as_str().chars() { if c as u32 > 255 { let stub = functor_stub(atom!("chars_base64"), 3); - let err = self.type_error( + let err = self.machine_st.type_error( ValidType::Byte, char_as_cell!(c), ); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } bytes.push(c as u8); @@ -5324,23 +5307,23 @@ impl MachineState { let b64 = base64::encode_config(bytes, config); let cstr = put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, &b64, - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ); - unify!(self, self.registers[2], cstr); + unify!(self.machine_st, self.machine_st.registers[2], cstr); } } &SystemClauseType::LoadLibraryAsStream => { - let library_name = cell_as_atom!(self.store(self.deref(self.registers[1]))); + let library_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); use crate::machine::LIBRARIES; match LIBRARIES.borrow().get(library_name.as_str()) { Some(library) => { - let lib_stream = Stream::from_static_string(library, &mut self.arena); - unify!(self, stream_as_cell!(lib_stream), self.registers[2]); + let lib_stream = Stream::from_static_string(library, &mut self.machine_st.arena); + unify!(self.machine_st, stream_as_cell!(lib_stream), self.machine_st.registers[2]); let mut path_buf = machine::current_dir(); @@ -5348,65 +5331,65 @@ impl MachineState { path_buf.push(library_name.as_str()); let library_path_str = path_buf.to_str().unwrap(); - let library_path = self.atom_tbl.build_with(library_path_str); + let library_path = self.machine_st.atom_tbl.build_with(library_path_str); - self.unify_atom(library_path, self.registers[3]); + self.machine_st.unify_atom(library_path, self.machine_st.registers[3]); } None => { let stub = functor_stub(atom!("load"), 1); - let err = self.existence_error( + let err = self.machine_st.existence_error( ExistenceError::ModuleSource(ModuleSource::Library(library_name)) ); - return Err(self.error_form(err, stub)); + return Err(self.machine_st.error_form(err, stub)); } } } &SystemClauseType::DevourWhitespace => { - let stream = self.get_stream_or_alias( - self.registers[1], - &indices.stream_aliases, + let stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, atom!("$devour_whitespace"), 1, )?; - match self.devour_whitespace(stream) { + match self.machine_st.devour_whitespace(stream) { Ok(false) => { // not at EOF. } _ => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } } } &SystemClauseType::IsSTOEnabled => { - if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize { - self.unify_atom(atom!("true"), self.registers[1]); - } else if self.unify_fn as usize + if self.machine_st.unify_fn as usize == MachineState::unify_with_occurs_check as usize { + self.machine_st.unify_atom(atom!("true"), self.machine_st.registers[1]); + } else if self.machine_st.unify_fn as usize == MachineState::unify_with_occurs_check_with_error as usize { - self.unify_atom(atom!("error"), self.registers[1]); + self.machine_st.unify_atom(atom!("error"), self.machine_st.registers[1]); } else { - self.unify_atom(atom!("false"), self.registers[1]); + self.machine_st.unify_atom(atom!("false"), self.machine_st.registers[1]); } } &SystemClauseType::SetSTOAsUnify => { - self.unify_fn = MachineState::unify_with_occurs_check; - self.bind_fn = MachineState::bind_with_occurs_check_wrapper; + self.machine_st.unify_fn = MachineState::unify_with_occurs_check; + self.machine_st.bind_fn = MachineState::bind_with_occurs_check_wrapper; } &SystemClauseType::SetNSTOAsUnify => { - self.unify_fn = MachineState::unify; - self.bind_fn = MachineState::bind; + self.machine_st.unify_fn = MachineState::unify; + self.machine_st.bind_fn = MachineState::bind; } &SystemClauseType::SetSTOWithErrorAsUnify => { - self.unify_fn = MachineState::unify_with_occurs_check_with_error; - self.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper; + self.machine_st.unify_fn = MachineState::unify_with_occurs_check_with_error; + self.machine_st.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper; } &SystemClauseType::HomeDirectory => { let path = match dirs_next::home_dir() { Some(path) => path, None => { - self.fail = true; + self.machine_st.fail = true; return Ok(()); } }; @@ -5414,40 +5397,40 @@ impl MachineState { if path.is_dir() { if let Some(path) = path.to_str() { let path_string = put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, path, - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ); - unify!(self, self.registers[1], path_string); - return return_from_clause!(self.last_call, self); + unify!(self.machine_st, self.machine_st.registers[1], path_string); + return return_from_clause!(self.machine_st.last_call, self.machine_st); } } - self.fail = true; + self.machine_st.fail = true; } &SystemClauseType::DebugHook => { - self.fail = false; + self.machine_st.fail = false; } &SystemClauseType::PopCount => { - let number = self.store(self.deref(self.registers[1])); + let number = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); let pop_count = integer_as_cell!(match Number::try_from(number) { Ok(Number::Fixnum(n)) => { Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64)) } Ok(Number::Integer(n)) => { - Number::arena_from(n.count_ones().unwrap(), &mut self.arena) + Number::arena_from(n.count_ones().unwrap(), &mut self.machine_st.arena) } _ => { unreachable!() } }); - unify!(self, self.registers[2], pop_count); + unify!(self.machine_st, self.machine_st.registers[2], pop_count); } }; - return_from_clause!(self.last_call, self) + return_from_clause!(self.machine_st.last_call, self.machine_st) } pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Atom { @@ -5466,11 +5449,11 @@ impl MachineState { fstr.push_str("finis]."); let s = datetime.format(&fstr).to_string(); - self.atom_tbl.build_with(&s) + self.machine_st.atom_tbl.build_with(&s) } pub(super) fn string_encoding_bytes(&mut self, data_arg: HeapCellValue, encoding: Atom) -> Vec { - let data = self.value_to_str_like(data_arg).unwrap(); + let data = self.machine_st.value_to_str_like(data_arg).unwrap(); match encoding { atom!("utf8") => data.as_str().bytes().collect(), @@ -5481,114 +5464,106 @@ impl MachineState { } } - pub(super) fn xml_node_to_term( - &mut self, - indices: &mut IndexStore, - node: roxmltree::Node, - ) -> HeapCellValue { + pub(super) fn xml_node_to_term(&mut self, node: roxmltree::Node) -> HeapCellValue { if node.is_text() { put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, node.text().unwrap(), - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ) } else { let mut avec = Vec::new(); for attr in node.attributes() { - let name = self.atom_tbl.build_with(attr.name()); + let name = self.machine_st.atom_tbl.build_with(attr.name()); let value = put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, &attr.value(), - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ); - avec.push(heap_loc_as_cell!(self.heap.len())); + avec.push(heap_loc_as_cell!(self.machine_st.heap.len())); - self.heap.push(atom_as_cell!(atom!("="), 2)); - self.heap.push(atom_as_cell!(name)); - self.heap.push(value); + self.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); + self.machine_st.heap.push(atom_as_cell!(name)); + self.machine_st.heap.push(value); } let attrs = heap_loc_as_cell!( - iter_to_heap_list(&mut self.heap, avec.into_iter()) + iter_to_heap_list(&mut self.machine_st.heap, avec.into_iter()) ); let mut cvec = Vec::new(); for child in node.children() { - cvec.push(self.xml_node_to_term(indices, child)); + cvec.push(self.xml_node_to_term(child)); } let children = heap_loc_as_cell!( - iter_to_heap_list(&mut self.heap, cvec.into_iter()) + iter_to_heap_list(&mut self.machine_st.heap, cvec.into_iter()) ); - let tag = self.atom_tbl.build_with(node.tag_name().name()); + let tag = self.machine_st.atom_tbl.build_with(node.tag_name().name()); - let result = heap_loc_as_cell!(self.heap.len()); + let result = heap_loc_as_cell!(self.machine_st.heap.len()); - self.heap.push(atom_as_cell!(atom!("element"), 3)); - self.heap.push(atom_as_cell!(tag)); - self.heap.push(attrs); - self.heap.push(children); + self.machine_st.heap.push(atom_as_cell!(atom!("element"), 3)); + self.machine_st.heap.push(atom_as_cell!(tag)); + self.machine_st.heap.push(attrs); + self.machine_st.heap.push(children); result } } - pub(super) fn html_node_to_term( - &mut self, - indices: &mut IndexStore, - node: select::node::Node, - ) -> HeapCellValue { + pub(super) fn html_node_to_term(&mut self, node: select::node::Node) -> HeapCellValue { match node.name() { None => { put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, &node.text(), - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ) } Some(name) => { let mut avec = Vec::new(); for attr in node.attrs() { - let name = self.atom_tbl.build_with(attr.0); + let name = self.machine_st.atom_tbl.build_with(attr.0); let value = put_complete_string( - &mut self.heap, + &mut self.machine_st.heap, &attr.1, - &mut self.atom_tbl, + &mut self.machine_st.atom_tbl, ); - avec.push(heap_loc_as_cell!(self.heap.len())); + avec.push(heap_loc_as_cell!(self.machine_st.heap.len())); - self.heap.push(atom_as_cell!(atom!("="), 2)); - self.heap.push(atom_as_cell!(name)); - self.heap.push(value); + self.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); + self.machine_st.heap.push(atom_as_cell!(name)); + self.machine_st.heap.push(value); } let attrs = heap_loc_as_cell!( - iter_to_heap_list(&mut self.heap, avec.into_iter()) + iter_to_heap_list(&mut self.machine_st.heap, avec.into_iter()) ); let mut cvec = Vec::new(); for child in node.children() { - cvec.push(self.html_node_to_term(indices, child)); + cvec.push(self.html_node_to_term(child)); } let children = heap_loc_as_cell!( - iter_to_heap_list(&mut self.heap, cvec.into_iter()) + iter_to_heap_list(&mut self.machine_st.heap, cvec.into_iter()) ); - let tag = self.atom_tbl.build_with(name); - let result = heap_loc_as_cell!(self.heap.len()); + let tag = self.machine_st.atom_tbl.build_with(name); + let result = heap_loc_as_cell!(self.machine_st.heap.len()); - self.heap.push(atom_as_cell!(atom!("element"), 3)); - self.heap.push(atom_as_cell!(tag)); - self.heap.push(attrs); - self.heap.push(children); + self.machine_st.heap.push(atom_as_cell!(atom!("element"), 3)); + self.machine_st.heap.push(atom_as_cell!(tag)); + self.machine_st.heap.push(attrs); + self.machine_st.heap.push(children); result } diff --git a/src/macros.rs b/src/macros.rs index b248080d..90fed110 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -778,7 +778,7 @@ macro_rules! unify { macro_rules! unify_fn { ($machine_st:expr, $($value:expr),*) => {{ $($machine_st.pdl.push($value);)* - ($machine_st.unify_fn)($machine_st) + ($machine_st.unify_fn)(&mut $machine_st) }}; } -- cgit v1.2.3-70-g09d2 From 955e1799c8e8b58d3fcce9cf4d1a61741e57e8e8 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 19 Dec 2021 18:57:57 -0700 Subject: flatten the instruction dispatch loop --- Cargo.lock | 76 + Cargo.toml | 9 +- build.rs | 15 + crates/instructions-template/Cargo.lock | 129 + crates/instructions-template/Cargo.toml | 14 + crates/instructions-template/src/lib.rs | 3286 ++++++++++++ crates/prolog_parser/Cargo.toml | 26 - crates/static-string-indexing/Cargo.toml | 2 +- crates/to-syn-value/Cargo.toml | 10 + crates/to-syn-value/src/lib.rs | 3 + crates/to-syn-value_derive/Cargo.toml | 14 + crates/to-syn-value_derive/src/lib.rs | 20 + src/allocator.rs | 9 +- src/arithmetic.rs | 112 +- src/clause_types.rs | 952 ---- src/codegen.rs | 319 +- src/debray_allocator.rs | 54 +- src/fixtures.rs | 22 +- src/forms.rs | 61 +- src/heap_print.rs | 2 +- src/instructions.rs | 919 ---- src/iterators.rs | 15 +- src/lib.rs | 6 +- src/lib/between.pl | 14 +- src/lib/builtins.pl | 4 +- src/lib/lists.pl | 9 +- src/loader.pl | 11 +- src/machine/arithmetic_ops.rs | 3 +- src/machine/attributed_variables.rs | 38 +- src/machine/code_repo.rs | 197 - src/machine/code_walker.rs | 26 +- src/machine/compile.rs | 315 +- src/machine/dispatch.rs | 5853 +++++++++++++++++---- src/machine/gc.rs | 1 - src/machine/heap.rs | 184 +- src/machine/load_state.rs | 20 +- src/machine/loader.rs | 210 +- src/machine/machine_errors.rs | 7 +- src/machine/machine_indices.rs | 207 +- src/machine/machine_state.rs | 42 +- src/machine/machine_state_impl.rs | 114 +- src/machine/mock_wam.rs | 8 +- src/machine/mod.rs | 975 +--- src/machine/preprocessor.rs | 32 +- src/machine/stack.rs | 11 +- src/machine/system_calls.rs | 8269 ++++++++++++++++-------------- src/macros.rs | 256 +- src/parser/ast.rs | 5 +- src/read.rs | 4 +- src/targets.rs | 152 +- src/toplevel.pl | 4 +- src/write.rs | 110 +- 52 files changed, 13691 insertions(+), 9465 deletions(-) create mode 100644 crates/instructions-template/Cargo.lock create mode 100644 crates/instructions-template/Cargo.toml create mode 100644 crates/instructions-template/src/lib.rs delete mode 100644 crates/prolog_parser/Cargo.toml create mode 100644 crates/to-syn-value/Cargo.toml create mode 100644 crates/to-syn-value/src/lib.rs create mode 100644 crates/to-syn-value_derive/Cargo.toml create mode 100644 crates/to-syn-value_derive/src/lib.rs delete mode 100644 src/clause_types.rs delete mode 100644 src/instructions.rs delete mode 100644 src/machine/code_repo.rs diff --git a/Cargo.lock b/Cargo.lock index 7818a0a4..4d699f11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -378,6 +378,15 @@ dependencies = [ "new_debug_unreachable", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.12.4" @@ -436,6 +445,15 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hostname" version = "0.3.1" @@ -471,6 +489,20 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instructions-template" +version = "0.1.0" +dependencies = [ + "indexmap", + "proc-macro2 1.0.32", + "quote 1.0.10", + "strum", + "strum_macros", + "syn 1.0.81", + "to-syn-value", + "to-syn-value_derive", +] + [[package]] name = "iovec" version = "0.1.4" @@ -1325,6 +1357,12 @@ dependencies = [ "libc", ] +[[package]] +name = "rustversion" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" + [[package]] name = "rustyline" version = "9.0.0" @@ -1392,9 +1430,11 @@ dependencies = [ "crossterm", "dirs-next", "divrem", + "fxhash", "git-version", "hostname", "indexmap", + "instructions-template", "lazy_static", "lexical", "libc", @@ -1655,6 +1695,25 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" +[[package]] +name = "strum" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" + +[[package]] +name = "strum_macros" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38" +dependencies = [ + "heck", + "proc-macro2 1.0.32", + "quote 1.0.10", + "rustversion", + "syn 1.0.81", +] + [[package]] name = "subtle" version = "1.0.0" @@ -1724,6 +1783,23 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "to-syn-value" +version = "0.1.0" +dependencies = [ + "syn 1.0.81", + "to-syn-value_derive", +] + +[[package]] +name = "to-syn-value_derive" +version = "0.1.0" +dependencies = [ + "proc-macro2 1.0.32", + "quote 1.0.10", + "syn 1.0.81", +] + [[package]] name = "typenum" version = "1.14.0" diff --git a/Cargo.toml b/Cargo.toml index d0a332fb..8e81a947 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,11 @@ categories = ["command-line-utilities"] build = "build.rs" [workspace] -members = ["crates/num-rug-adapter", "crates/static-string-indexing"] +members = ["crates/num-rug-adapter", + "crates/static-string-indexing", + "crates/instructions-template", + "crates/to-syn-value", + "crates/to-syn-value_derive"] [features] num = ["num-rug-adapter"] @@ -24,6 +28,7 @@ default = ["rug"] [build-dependencies] indexmap = "1.0.2" static-string-indexing = { path = "./crates/static-string-indexing" } +instructions-template = { path = "./crates/instructions-template" } proc-macro2 = "*" [dependencies] @@ -31,13 +36,13 @@ cpu-time = "1.0.0" crossterm = "0.16.0" dirs-next = "2.0.0" divrem = "0.1.0" +fxhash = "0.2.1" git-version = "0.3.4" hostname = "0.3.1" indexmap = "1.0.2" lazy_static = "1.4.0" lexical = "5.2.2" libc = "0.2.62" -# temporary to remove unnecessary braces warnings. modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } # modular-bitfield = "0.11.2" nix = "0.15.0" num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" } diff --git a/build.rs b/build.rs index 88267cdc..6c315769 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,5 @@ use static_string_indexing::index_static_strings; +use instructions_template::generate_instructions_rs; use std::env; use std::fs; @@ -55,6 +56,20 @@ fn main() { find_prolog_files(&mut libraries, "", &lib_path); libraries.write_all(b"\n m\n };\n}\n").unwrap(); + let instructions_path = Path::new("src/instructions.rs"); + let mut instructions_file = File::create(&instructions_path).unwrap(); + + let quoted_output = generate_instructions_rs(); + + instructions_file + .write_all(quoted_output.to_string().as_bytes()) + .unwrap(); + + Command::new("rustfmt") + .arg(instructions_path.as_os_str()) + .spawn().unwrap() + .wait().unwrap(); + let static_atoms_path = Path::new("src/static_atoms.rs"); let mut static_atoms_file = File::create(&static_atoms_path).unwrap(); diff --git a/crates/instructions-template/Cargo.lock b/crates/instructions-template/Cargo.lock new file mode 100644 index 00000000..08be8ba3 --- /dev/null +++ b/crates/instructions-template/Cargo.lock @@ -0,0 +1,129 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instructions-template" +version = "0.1.0" +dependencies = [ + "indexmap", + "proc-macro2", + "quote", + "strum", + "strum_macros", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "392a54546fda6b7cc663379d0e6ce8b324cf88aecc5a499838e1be9781bdce2e" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" + +[[package]] +name = "strum" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" + +[[package]] +name = "strum_macros" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "to-syn-value" +version = "0.1.0" +dependencies = [ + "syn", + "to-syn-value_derive", +] + +[[package]] +name = "to-syn-value_derive" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/crates/instructions-template/Cargo.toml b/crates/instructions-template/Cargo.toml new file mode 100644 index 00000000..92f130ed --- /dev/null +++ b/crates/instructions-template/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "instructions-template" +version = "0.1.0" +edition = "2021" + +[dependencies] +indexmap = "*" +proc-macro2 = "*" +quote = "*" +strum = "0.23" +strum_macros = "0.23" +syn = { version = "*", features = ['full', 'visit', 'extra-traits'] } +to-syn-value = { path = "../to-syn-value" } +to-syn-value_derive = { path = "../to-syn-value_derive" } \ No newline at end of file diff --git a/crates/instructions-template/src/lib.rs b/crates/instructions-template/src/lib.rs new file mode 100644 index 00000000..386bafd5 --- /dev/null +++ b/crates/instructions-template/src/lib.rs @@ -0,0 +1,3286 @@ +// use crate::atom_table::*; +// use crate::machine::machine_indices::*; +// use crate::types::*; +// + +use proc_macro2::TokenStream; +use quote::{format_ident, quote, ToTokens, TokenStreamExt}; +use strum_macros::{EnumDiscriminants, EnumProperty, EnumString}; +use syn::*; +use to_syn_value_derive::ToDeriveInput; + +/* + * This crate exists to generate the Instruction enum in + * src/instructions.rs and its adjoining impl functions. The types + * defined in it are empty and serve only as schema for the generation + * of Instruction. They mimick most of the structure of the previous + * Line instruction type. The strum crate is used to provide reflection + * on each of the node types to the tree walker. + */ + +use std::any::*; +use std::str::FromStr; + +struct ArithmeticTerm; +struct Atom; +struct CodeIndex; +struct Death; +struct HeapCellValue; +struct IndexingLine; +struct Level; +struct NextOrFail; +struct RegType; + +#[allow(dead_code)] +#[derive(ToDeriveInput, EnumDiscriminants)] +#[strum_discriminants(derive(EnumProperty, EnumString))] +enum CompareNumber { + #[strum_discriminants(strum(props(Arity = "2", Name = ">")))] + NumberGreaterThan(ArithmeticTerm, ArithmeticTerm), + #[strum_discriminants(strum(props(Arity = "2", Name = "<")))] + NumberLessThan(ArithmeticTerm, ArithmeticTerm), + #[strum_discriminants(strum(props(Arity = "2", Name = ">=")))] + NumberGreaterThanOrEqual(ArithmeticTerm, ArithmeticTerm), + #[strum_discriminants(strum(props(Arity = "2", Name = "=<")))] + NumberLessThanOrEqual(ArithmeticTerm, ArithmeticTerm), + #[strum_discriminants(strum(props(Arity = "2", Name = "=\\=")))] + NumberNotEqual(ArithmeticTerm, ArithmeticTerm), + #[strum_discriminants(strum(props(Arity = "2", Name = "=:=")))] + NumberEqual(ArithmeticTerm, ArithmeticTerm), +} + +#[allow(dead_code)] +#[derive(ToDeriveInput, EnumDiscriminants)] +#[strum_discriminants(derive(EnumProperty, EnumString))] +enum CompareTerm { + #[strum_discriminants(strum(props(Arity = "2", Name = "@<")))] + TermLessThan, + #[strum_discriminants(strum(props(Arity = "2", Name = "@=<")))] + TermLessThanOrEqual, + #[strum_discriminants(strum(props(Arity = "2", Name = "@>=")))] + TermGreaterThanOrEqual, + #[strum_discriminants(strum(props(Arity = "2", Name = "@>")))] + TermGreaterThan, + #[strum_discriminants(strum(props(Arity = "2", Name = "==")))] + TermEqual, + #[strum_discriminants(strum(props(Arity = "2", Name = "\\==")))] + TermNotEqual, +} + +#[allow(dead_code)] +#[derive(ToDeriveInput, EnumDiscriminants)] +#[strum_discriminants(derive(EnumProperty, EnumString))] +enum ClauseType { + BuiltIn(BuiltInClauseType), + #[strum_discriminants(strum(props(Arity = "arity", Name = "$call")))] + CallN(usize), + Inlined(InlinedClauseType), + #[strum_discriminants(strum(props(Arity = "arity", Name = "call_named")))] + Named(usize, Atom, CodeIndex), // name, arity, index. + System(SystemClauseType), +} + +#[allow(dead_code)] +#[derive(ToDeriveInput, EnumDiscriminants)] +#[strum_discriminants(derive(EnumProperty, EnumString))] +enum BuiltInClauseType { + #[strum_discriminants(strum(props(Arity = "1", Name = "acyclic_term")))] + AcyclicTerm, + #[strum_discriminants(strum(props(Arity = "3", Name = "arg")))] + Arg, + #[strum_discriminants(strum(props(Arity = "3", Name = "compare")))] + Compare, + CompareTerm(CompareTerm), + #[strum_discriminants(strum(props(Arity = "2", Name = "copy_term")))] + CopyTerm, + #[strum_discriminants(strum(props(Arity = "3", Name = "functor")))] + Functor, + #[strum_discriminants(strum(props(Arity = "1", Name = "ground")))] + Ground, + #[strum_discriminants(strum(props(Arity = "2", Name = "is")))] + Is(RegType, ArithmeticTerm), + #[strum_discriminants(strum(props(Arity = "2", Name = "keysort")))] + KeySort, + #[strum_discriminants(strum(props(Arity = "1", Name = "read")))] + Read, + #[strum_discriminants(strum(props(Arity = "2", Name = "sort")))] + Sort, +} + +#[allow(dead_code)] +#[derive(ToDeriveInput, EnumDiscriminants)] +#[strum_discriminants(derive(EnumProperty, EnumString))] +enum InlinedClauseType { + CompareNumber(CompareNumber), + #[strum_discriminants(strum(props(Arity = "1", Name = "atom")))] + IsAtom(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "atomic")))] + IsAtomic(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "compound")))] + IsCompound(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "integer")))] + IsInteger(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "number")))] + IsNumber(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "rational")))] + IsRational(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "float")))] + IsFloat(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "nonvar")))] + IsNonVar(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "var")))] + IsVar(RegType), +} + +#[allow(dead_code)] +#[derive(ToDeriveInput, EnumDiscriminants)] +#[strum_discriminants(derive(EnumProperty, EnumString))] +enum REPLCodePtr { + #[strum_discriminants(strum(props(Arity = "4", Name = "$add_discontiguous_predicate")))] + AddDiscontiguousPredicate, + #[strum_discriminants(strum(props(Arity = "4", Name = "$add_dynamic_predicate")))] + AddDynamicPredicate, + #[strum_discriminants(strum(props(Arity = "4", Name = "$add_multifile_predicate")))] + AddMultifilePredicate, + #[strum_discriminants(strum(props(Arity = "3", Name = "$add_goal_expansion_clause")))] + AddGoalExpansionClause, + #[strum_discriminants(strum(props(Arity = "2", Name = "$add_term_expansion_clause")))] + AddTermExpansionClause, + #[strum_discriminants(strum(props(Arity = "1", Name = "$add_in_situ_filename_module")))] + AddInSituFilenameModule, + #[strum_discriminants(strum(props(Arity = "2", Name = "$clause_to_evacuable")))] + ClauseToEvacuable, + #[strum_discriminants(strum(props(Arity = "3", Name = "$scoped_clause_to_evacuable")))] + ScopedClauseToEvacuable, + #[strum_discriminants(strum(props(Arity = "1", Name = "$conclude_load")))] + ConcludeLoad, + #[strum_discriminants(strum(props(Arity = "3", Name = "$declare_module")))] + DeclareModule, + #[strum_discriminants(strum(props(Arity = "3", Name = "$load_compiled_library")))] + LoadCompiledLibrary, + #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_source")))] + LoadContextSource, + #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_file")))] + LoadContextFile, + #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_dir")))] + LoadContextDirectory, + #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_module")))] + LoadContextModule, + #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_stream")))] + LoadContextStream, + #[strum_discriminants(strum(props(Arity = "0", Name = "$pop_load_context")))] + PopLoadContext, + #[strum_discriminants(strum(props(Arity = "1", Name = "$pop_load_state_payload")))] + PopLoadStatePayload, + #[strum_discriminants(strum(props(Arity = "1", Name = "$push_load_state_payload")))] + PushLoadStatePayload, + #[strum_discriminants(strum(props(Arity = "2", Name = "$push_load_context")))] + PushLoadContext, + #[strum_discriminants(strum(props(Arity = "3", Name = "$use_module")))] + UseModule, + #[strum_discriminants(strum(props(Arity = "2", Name = "$built_in_property")))] + BuiltInProperty, + #[strum_discriminants(strum(props(Arity = "4", Name = "$meta_predicate_property")))] + MetaPredicateProperty, + #[strum_discriminants(strum(props(Arity = "3", Name = "$multifile_property")))] + MultifileProperty, + #[strum_discriminants(strum(props(Arity = "3", Name = "$discontiguous_property")))] + DiscontiguousProperty, + #[strum_discriminants(strum(props(Arity = "3", Name = "$dynamic_property")))] + DynamicProperty, + #[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))] + AbolishClause, + #[strum_discriminants(strum(props(Arity = "5", Name = "$asserta")))] + Asserta, + #[strum_discriminants(strum(props(Arity = "5", Name = "$assertz")))] + Assertz, + #[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))] + Retract, + #[strum_discriminants(strum(props(Arity = "4", Name = "$is_consistent_with_term_queue")))] + IsConsistentWithTermQueue, + #[strum_discriminants(strum(props(Arity = "1", Name = "$flush_term_queue")))] + FlushTermQueue, + #[strum_discriminants(strum(props(Arity = "2", Name = "$remove_module_exports")))] + RemoveModuleExports, + #[strum_discriminants(strum(props(Arity = "3", Name = "$add_non_counted_backtracking")))] + AddNonCountedBacktracking, +} + +#[allow(dead_code)] +#[derive(ToDeriveInput, EnumDiscriminants)] +#[strum_discriminants(derive(EnumProperty, EnumString))] +enum SystemClauseType { + #[strum_discriminants(strum(props(Arity = "2", Name = "$atom_chars")))] + AtomChars, + #[strum_discriminants(strum(props(Arity = "2", Name = "$atom_codes")))] + AtomCodes, + #[strum_discriminants(strum(props(Arity = "2", Name = "$atom_length")))] + AtomLength, + #[strum_discriminants(strum(props(Arity = "2", Name = "$bind_from_register")))] + BindFromRegister, + #[strum_discriminants(strum(props(Arity = "1", Name = "$call_continuation")))] + CallContinuation, + #[strum_discriminants(strum(props(Arity = "2", Name = "$char_code")))] + CharCode, + #[strum_discriminants(strum(props(Arity = "2", Name = "$char_type")))] + CharType, + #[strum_discriminants(strum(props(Arity = "2", Name = "$chars_to_number")))] + CharsToNumber, + #[strum_discriminants(strum(props(Arity = "2", Name = "$codes_to_number")))] + CodesToNumber, + #[strum_discriminants(strum(props(Arity = "2", Name = "$copy_term_without_attr_vars")))] + CopyTermWithoutAttrVars, + #[strum_discriminants(strum(props(Arity = "1", Name = "$check_cp")))] + CheckCutPoint, + #[strum_discriminants(strum(props(Arity = "2", Name = "$close")))] + Close, + #[strum_discriminants(strum(props(Arity = "2", Name = "$copy_to_lh")))] + CopyToLiftedHeap, + #[strum_discriminants(strum(props(Arity = "3", Name = "$create_partial_string")))] + CreatePartialString, + #[strum_discriminants(strum(props(Arity = "1", Name = "$current_hostname")))] + CurrentHostname, + #[strum_discriminants(strum(props(Arity = "1", Name = "$current_input")))] + CurrentInput, + #[strum_discriminants(strum(props(Arity = "1", Name = "$current_output")))] + CurrentOutput, + #[strum_discriminants(strum(props(Arity = "2", Name = "$directory_files")))] + DirectoryFiles, + #[strum_discriminants(strum(props(Arity = "2", Name = "$file_size")))] + FileSize, + #[strum_discriminants(strum(props(Arity = "1", Name = "$file_exists")))] + FileExists, + #[strum_discriminants(strum(props(Arity = "1", Name = "$directory_exists")))] + DirectoryExists, + #[strum_discriminants(strum(props(Arity = "1", Name = "$directory_separator")))] + DirectorySeparator, + #[strum_discriminants(strum(props(Arity = "1", Name = "$make_directory")))] + MakeDirectory, + #[strum_discriminants(strum(props(Arity = "1", Name = "$make_directory_path")))] + MakeDirectoryPath, + #[strum_discriminants(strum(props(Arity = "1", Name = "$delete_file")))] + DeleteFile, + #[strum_discriminants(strum(props(Arity = "2", Name = "$rename_file")))] + RenameFile, + #[strum_discriminants(strum(props(Arity = "2", Name = "working_directory")))] + WorkingDirectory, + #[strum_discriminants(strum(props(Arity = "1", Name = "$delete_directory")))] + DeleteDirectory, + #[strum_discriminants(strum(props(Arity = "2", Name = "$path_canonical")))] + PathCanonical, + #[strum_discriminants(strum(props(Arity = "3", Name = "$file_time")))] + FileTime, + #[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_non_head")))] + DeleteAttribute, + #[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_head")))] + DeleteHeadAttribute, + #[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))] + DynamicModuleResolution(usize), + #[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))] + EnqueueAttributedVar, + #[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))] + FetchGlobalVar, + #[strum_discriminants(strum(props(Arity = "1", Name = "$first_stream")))] + FirstStream, + #[strum_discriminants(strum(props(Arity = "1", Name = "$flush_output")))] + FlushOutput, + #[strum_discriminants(strum(props(Arity = "2", Name = "$get_byte")))] + GetByte, + #[strum_discriminants(strum(props(Arity = "2", Name = "$get_char")))] + GetChar, + #[strum_discriminants(strum(props(Arity = "3", Name = "$get_n_chars")))] + GetNChars, + #[strum_discriminants(strum(props(Arity = "2", Name = "$get_code")))] + GetCode, + #[strum_discriminants(strum(props(Arity = "1", Name = "$get_single_char")))] + GetSingleChar, + #[strum_discriminants(strum(props(Arity = "0", Name = "$reset_attr_var_state")))] + ResetAttrVarState, + #[strum_discriminants(strum(props(Arity = "2", Name = "$truncate_if_no_lh_growth_diff")))] + TruncateIfNoLiftedHeapGrowthDiff, + #[strum_discriminants(strum(props(Arity = "1", Name = "$truncate_if_no_lh_growth")))] + TruncateIfNoLiftedHeapGrowth, + #[strum_discriminants(strum(props(Arity = "2", Name = "$get_attr_list")))] + GetAttributedVariableList, + #[strum_discriminants(strum(props(Arity = "1", Name = "$get_attr_var_queue_delim")))] + GetAttrVarQueueDelimiter, + #[strum_discriminants(strum(props(Arity = "2", Name = "$get_attr_var_queue_beyond")))] + GetAttrVarQueueBeyond, + #[strum_discriminants(strum(props(Arity = "1", Name = "$get_b_value")))] + GetBValue, + #[strum_discriminants(strum(props(Arity = "3", Name = "$get_cont_chunk")))] + GetContinuationChunk, + #[strum_discriminants(strum(props(Arity = "4", Name = "$get_next_db_ref")))] + GetNextDBRef, + #[strum_discriminants(strum(props(Arity = "7", Name = "$get_next_op_db_ref")))] + GetNextOpDBRef, + #[strum_discriminants(strum(props(Arity = "1", Name = "$is_partial_string")))] + IsPartialString, + #[strum_discriminants(strum(props(Arity = "1", Name = "$halt")))] + Halt, + #[strum_discriminants(strum(props(Arity = "2", Name = "$get_lh_from_offset")))] + GetLiftedHeapFromOffset, + #[strum_discriminants(strum(props(Arity = "3", Name = "$get_lh_from_offset_diff")))] + GetLiftedHeapFromOffsetDiff, + #[strum_discriminants(strum(props(Arity = "1", Name = "$get_scc_cleaner")))] + GetSCCCleaner, + #[strum_discriminants(strum(props(Arity = "2", Name = "$head_is_dynamic")))] + HeadIsDynamic, + #[strum_discriminants(strum(props(Arity = "2", Name = "$install_scc_cleaner")))] + InstallSCCCleaner, + #[strum_discriminants(strum(props(Arity = "3", Name = "$install_inference_counter")))] + InstallInferenceCounter, + #[strum_discriminants(strum(props(Arity = "1", Name = "$lh_length")))] + LiftedHeapLength, + #[strum_discriminants(strum(props(Arity = "3", Name = "$load_library_as_stream")))] + LoadLibraryAsStream, + #[strum_discriminants(strum(props(Arity = "1", Name = "$module_exists")))] + ModuleExists, + #[strum_discriminants(strum(props(Arity = "3", Name = "$nextEP")))] + NextEP, + #[strum_discriminants(strum(props(Arity = "2", Name = "$no_such_predicate")))] + NoSuchPredicate, + #[strum_discriminants(strum(props(Arity = "2", Name = "$number_to_chars")))] + NumberToChars, + #[strum_discriminants(strum(props(Arity = "2", Name = "$number_to_codes")))] + NumberToCodes, + #[strum_discriminants(strum(props(Arity = "3", Name = "$op")))] + OpDeclaration, + #[strum_discriminants(strum(props(Arity = "7", Name = "$open")))] + Open, + #[strum_discriminants(strum(props(Arity = "5", Name = "$set_stream_options")))] + SetStreamOptions, + #[strum_discriminants(strum(props(Arity = "2", Name = "$next_stream")))] + NextStream, + #[strum_discriminants(strum(props(Arity = "2", Name = "$partial_string_tail")))] + PartialStringTail, + #[strum_discriminants(strum(props(Arity = "2", Name = "$peek_byte")))] + PeekByte, + #[strum_discriminants(strum(props(Arity = "2", Name = "$peek_char")))] + PeekChar, + #[strum_discriminants(strum(props(Arity = "2", Name = "$peek_code")))] + PeekCode, + #[strum_discriminants(strum(props(Arity = "1", Name = "$points_to_cont_reset_marker")))] + PointsToContinuationResetMarker, + #[strum_discriminants(strum(props(Arity = "2", Name = "$put_byte")))] + PutByte, + #[strum_discriminants(strum(props(Arity = "2", Name = "$put_char")))] + PutChar, + #[strum_discriminants(strum(props(Arity = "2", Name = "$put_chars")))] + PutChars, + #[strum_discriminants(strum(props(Arity = "2", Name = "$put_code")))] + PutCode, + #[strum_discriminants(strum(props(Arity = "5", Name = "$read_query_term")))] + ReadQueryTerm, + #[strum_discriminants(strum(props(Arity = "5", Name = "$read_term")))] + ReadTerm, + #[strum_discriminants(strum(props(Arity = "2", Name = "$redo_attr_var_binding")))] + RedoAttrVarBinding, + #[strum_discriminants(strum(props(Arity = "1", Name = "$remove_call_policy_check")))] + RemoveCallPolicyCheck, + #[strum_discriminants(strum(props(Arity = "2", Name = "$remove_inference_counter")))] + RemoveInferenceCounter, + #[strum_discriminants(strum(props(Arity = "0", Name = "$reset_cont_marker")))] + ResetContinuationMarker, + #[strum_discriminants(strum(props(Arity = "0", Name = "$restore_cut_policy")))] + RestoreCutPolicy, + #[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp")))] + SetCutPoint(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "$set_input")))] + SetInput, + #[strum_discriminants(strum(props(Arity = "1", Name = "$set_output")))] + SetOutput, + #[strum_discriminants(strum(props(Arity = "2", Name = "$store_backtrackable_global_var")))] + StoreBacktrackableGlobalVar, + #[strum_discriminants(strum(props(Arity = "2", Name = "$store_global_var")))] + StoreGlobalVar, + #[strum_discriminants(strum(props(Arity = "3", Name = "$stream_property")))] + StreamProperty, + #[strum_discriminants(strum(props(Arity = "2", Name = "$set_stream_position")))] + SetStreamPosition, + #[strum_discriminants(strum(props(Arity = "2", Name = "$inference_level")))] + InferenceLevel, + #[strum_discriminants(strum(props(Arity = "1", Name = "$clean_up_block")))] + CleanUpBlock, + #[strum_discriminants(strum(props(Arity = "0", Name = "$erase_ball")))] + EraseBall, + #[strum_discriminants(strum(props(Arity = "0", Name = "$fail")))] + Fail, + #[strum_discriminants(strum(props(Arity = "1", Name = "$get_ball")))] + GetBall, + #[strum_discriminants(strum(props(Arity = "1", Name = "$get_current_block")))] + GetCurrentBlock, + #[strum_discriminants(strum(props(Arity = "1", Name = "$get_cp")))] + GetCutPoint, + #[strum_discriminants(strum(props(Arity = "1", Name = "$get_staggered_cp")))] + GetStaggeredCutPoint, + #[strum_discriminants(strum(props(Arity = "1", Name = "$get_double_quotes")))] + GetDoubleQuotes, + #[strum_discriminants(strum(props(Arity = "1", Name = "$install_new_block")))] + InstallNewBlock, + #[strum_discriminants(strum(props(Arity = "0", Name = "$maybe")))] + Maybe, + #[strum_discriminants(strum(props(Arity = "1", Name = "$current_time")))] + CurrentTime, + #[strum_discriminants(strum(props(Arity = "1", Name = "$quoted_token")))] + QuotedToken, + #[strum_discriminants(strum(props(Arity = "2", Name = "$read_term_from_chars")))] + ReadTermFromChars, + #[strum_discriminants(strum(props(Arity = "1", Name = "$reset_block")))] + ResetBlock, + #[strum_discriminants(strum(props(Arity = "0", Name = "$return_from_verify_attr")))] + ReturnFromVerifyAttr, + #[strum_discriminants(strum(props(Arity = "1", Name = "$set_ball")))] + SetBall, + #[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp_by_default")))] + SetCutPointByDefault(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "$set_double_quotes")))] + SetDoubleQuotes, + #[strum_discriminants(strum(props(Arity = "1", Name = "$set_seed")))] + SetSeed, + #[strum_discriminants(strum(props(Arity = "4", Name = "$skip_max_list")))] + SkipMaxList, + #[strum_discriminants(strum(props(Arity = "1", Name = "$sleep")))] + Sleep, + #[strum_discriminants(strum(props(Arity = "8", Name = "$socket_client_open")))] + SocketClientOpen, + #[strum_discriminants(strum(props(Arity = "3", Name = "$socket_server_open")))] + SocketServerOpen, + #[strum_discriminants(strum(props(Arity = "7", Name = "$socket_server_accept")))] + SocketServerAccept, + #[strum_discriminants(strum(props(Arity = "1", Name = "$socket_server_close")))] + SocketServerClose, + #[strum_discriminants(strum(props(Arity = "4", Name = "$tls_accept_client")))] + TLSAcceptClient, + #[strum_discriminants(strum(props(Arity = "3", Name = "$tls_client_connect")))] + TLSClientConnect, + #[strum_discriminants(strum(props(Arity = "0", Name = "$succeed")))] + Succeed, + #[strum_discriminants(strum(props(Arity = "2", Name = "$term_attributed_variables")))] + TermAttributedVariables, + #[strum_discriminants(strum(props(Arity = "2", Name = "$term_variables")))] + TermVariables, + #[strum_discriminants(strum(props(Arity = "3", Name = "$term_variables_under_max_depth")))] + TermVariablesUnderMaxDepth, + #[strum_discriminants(strum(props(Arity = "1", Name = "$truncate_lh_to")))] + TruncateLiftedHeapTo, + #[strum_discriminants(strum(props(Arity = "2", Name = "$unify_with_occurs_check")))] + UnifyWithOccursCheck, + #[strum_discriminants(strum(props(Arity = "0", Name = "$unwind_environments")))] + UnwindEnvironments, + #[strum_discriminants(strum(props(Arity = "0", Name = "$unwind_stack")))] + UnwindStack, + #[strum_discriminants(strum(props(Arity = "4", Name = "$wam_instructions")))] + WAMInstructions, + #[strum_discriminants(strum(props(Arity = "7", Name = "$write_term")))] + WriteTerm, + #[strum_discriminants(strum(props(Arity = "7", Name = "$write_term_to_chars")))] + WriteTermToChars, + #[strum_discriminants(strum(props(Arity = "1", Name = "$scryer_prolog_version")))] + ScryerPrologVersion, + #[strum_discriminants(strum(props(Arity = "1", Name = "$crypto_random_byte")))] + CryptoRandomByte, + #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_data_hash")))] + CryptoDataHash, + #[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_hkdf")))] + CryptoDataHKDF, + #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_password_hash")))] + CryptoPasswordHash, + #[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_encrypt")))] + CryptoDataEncrypt, + #[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))] + CryptoDataDecrypt, + #[strum_discriminants(strum(props(Arity = "5", Name = "$crypto_curve_scalar_mult")))] + CryptoCurveScalarMult, + #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))] + Ed25519Sign, + #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify")))] + Ed25519Verify, + #[strum_discriminants(strum(props(Arity = "1", Name = "$ed25519_new_keypair")))] + Ed25519NewKeyPair, + #[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_keypair_public_key")))] + Ed25519KeyPairPublicKey, + #[strum_discriminants(strum(props(Arity = "3", Name = "$curve25519_scalar_mult")))] + Curve25519ScalarMult, + #[strum_discriminants(strum(props(Arity = "2", Name = "$first_non_octet")))] + FirstNonOctet, + #[strum_discriminants(strum(props(Arity = "3", Name = "$load_html")))] + LoadHTML, + #[strum_discriminants(strum(props(Arity = "3", Name = "$load_xml")))] + LoadXML, + #[strum_discriminants(strum(props(Arity = "2", Name = "$getenv")))] + GetEnv, + #[strum_discriminants(strum(props(Arity = "2", Name = "$setenv")))] + SetEnv, + #[strum_discriminants(strum(props(Arity = "1", Name = "$unsetenv")))] + UnsetEnv, + #[strum_discriminants(strum(props(Arity = "2", Name = "$shell")))] + Shell, + #[strum_discriminants(strum(props(Arity = "1", Name = "$pid")))] + PID, + #[strum_discriminants(strum(props(Arity = "4", Name = "$chars_base64")))] + CharsBase64, + #[strum_discriminants(strum(props(Arity = "1", Name = "$devour_whitespace")))] + DevourWhitespace, + #[strum_discriminants(strum(props(Arity = "1", Name = "$is_sto_enabled")))] + IsSTOEnabled, + #[strum_discriminants(strum(props(Arity = "0", Name = "$set_sto_as_unify")))] + SetSTOAsUnify, + #[strum_discriminants(strum(props(Arity = "0", Name = "$set_nsto_as_unify")))] + SetNSTOAsUnify, + #[strum_discriminants(strum(props(Arity = "0", Name = "$set_sto_with_error_as_unify")))] + SetSTOWithErrorAsUnify, + #[strum_discriminants(strum(props(Arity = "1", Name = "$home_directory")))] + HomeDirectory, + #[strum_discriminants(strum(props(Arity = "0", Name = "$debug_hook")))] + DebugHook, + #[strum_discriminants(strum(props(Arity = "2", Name = "$popcount")))] + PopCount, + #[strum_discriminants(strum(props(Arity = "1", Name = "$cpu_now")))] + CpuNow, + REPL(REPLCodePtr), +} + +#[allow(dead_code)] +#[derive(ToDeriveInput, EnumDiscriminants)] +#[strum_discriminants(derive(EnumProperty, EnumString))] +enum InstructionTemplate { + #[strum_discriminants(strum(props(Arity = "3", Name = "get_constant")))] + GetConstant(Level, HeapCellValue, RegType), + #[strum_discriminants(strum(props(Arity = "2", Name = "get_list")))] + GetList(Level, RegType), + #[strum_discriminants(strum(props(Arity = "4", Name = "get_partial_string")))] + GetPartialString(Level, Atom, RegType, bool), + #[strum_discriminants(strum(props(Arity = "3", Name = "get_structure")))] + GetStructure(Atom, usize, RegType), + #[strum_discriminants(strum(props(Arity = "2", Name = "get_variable")))] + GetVariable(RegType, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "get_value")))] + GetValue(RegType, usize), + #[strum_discriminants(strum(props(Arity = "1", Name = "unify_constant")))] + UnifyConstant(HeapCellValue), + #[strum_discriminants(strum(props(Arity = "1", Name = "unify_local_value")))] + UnifyLocalValue(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "unify_variable")))] + UnifyVariable(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "unify_value")))] + UnifyValue(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "unify_void")))] + UnifyVoid(usize), + // query instruction + #[strum_discriminants(strum(props(Arity = "3", Name = "put_constant")))] + PutConstant(Level, HeapCellValue, RegType), + #[strum_discriminants(strum(props(Arity = "2", Name = "put_list")))] + PutList(Level, RegType), + #[strum_discriminants(strum(props(Arity = "4", Name = "put_partial_string")))] + PutPartialString(Level, Atom, RegType, bool), + #[strum_discriminants(strum(props(Arity = "3", Name = "put_structure")))] + PutStructure(Atom, usize, RegType), + #[strum_discriminants(strum(props(Arity = "2", Name = "put_unsafe_value")))] + PutUnsafeValue(usize, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "put_value")))] + PutValue(RegType, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "put_variable")))] + PutVariable(RegType, usize), + #[strum_discriminants(strum(props(Arity = "1", Name = "set_constant")))] + SetConstant(HeapCellValue), + #[strum_discriminants(strum(props(Arity = "1", Name = "set_local_value")))] + SetLocalValue(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "set_variable")))] + SetVariable(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "set_value")))] + SetValue(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "set_void")))] + SetVoid(usize), + // cut instruction + #[strum_discriminants(strum(props(Arity = "1", Name = "cut")))] + Cut(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "get_level")))] + GetLevel(RegType), + #[strum_discriminants(strum(props(Arity = "1", Name = "get_level_and_unify")))] + GetLevelAndUnify(RegType), + #[strum_discriminants(strum(props(Arity = "0", Name = "neck_cut")))] + NeckCut, + // choice instruction + #[strum_discriminants(strum(props(Arity = "3", Name = "dynamic_else")))] + DynamicElse(usize, Death, NextOrFail), + #[strum_discriminants(strum(props(Arity = "3", Name = "dynamic_internal_else")))] + DynamicInternalElse(usize, Death, NextOrFail), + #[strum_discriminants(strum(props(Arity = "1", Name = "default_retry_me_else")))] + DefaultRetryMeElse(usize), + #[strum_discriminants(strum(props(Arity = "1", Name = "default_trust_me")))] + DefaultTrustMe(usize), + #[strum_discriminants(strum(props(Arity = "1", Name = "retry_me_else")))] + RetryMeElse(usize), + #[strum_discriminants(strum(props(Arity = "1", Name = "trust_me")))] + TrustMe(usize), + #[strum_discriminants(strum(props(Arity = "1", Name = "default_trust_me")))] + TryMeElse(usize), + // arithmetic instruction + #[strum_discriminants(strum(props(Arity = "3", Name = "add")))] + Add(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "sub")))] + Sub(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "mul")))] + Mul(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "pow")))] + Pow(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "int_pow")))] + IntPow(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "i_div")))] + IDiv(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "max")))] + Max(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "min")))] + Min(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "int_floor_div")))] + IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "r_div")))] + RDiv(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "div")))] + Div(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "shl")))] + Shl(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "shr")))] + Shr(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "xor")))] + Xor(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "and")))] + And(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "or")))] + Or(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "mod")))] + Mod(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "rem")))] + Rem(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "gcd")))] + Gcd(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "sign")))] + Sign(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "cos")))] + Cos(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "sin")))] + Sin(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "tan")))] + Tan(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "log")))] + Log(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "exp")))] + Exp(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "acos")))] + ACos(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "asin")))] + ASin(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "atan")))] + ATan(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "3", Name = "atan2")))] + ATan2(ArithmeticTerm, ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "sqrt")))] + Sqrt(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "abs")))] + Abs(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "float")))] + Float(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "truncate")))] + Truncate(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "round")))] + Round(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "ceiling")))] + Ceiling(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "floor")))] + Floor(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "neg")))] + Neg(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "plus")))] + Plus(ArithmeticTerm, usize), + #[strum_discriminants(strum(props(Arity = "2", Name = "bitwise_complement")))] + BitwiseComplement(ArithmeticTerm, usize), + // control instructions + #[strum_discriminants(strum(props(Arity = "1", Name = "allocate")))] + Allocate(usize), // num_frames. + #[strum_discriminants(strum(props(Arity = "0", Name = "deallocate")))] + Deallocate, + #[strum_discriminants(strum(props(Arity = "3", Name = "jmp_by_call")))] + JmpByCall(usize, usize), // arity, relative offset. + #[strum_discriminants(strum(props(Arity = "3", Name = "jmp_by_execute")))] + JmpByExecute(usize, usize), // arity, relative offset. + #[strum_discriminants(strum(props(Arity = "1", Name = "rev_jmp_by")))] + RevJmpBy(usize), + #[strum_discriminants(strum(props(Arity = "0", Name = "proceed")))] + Proceed, + // indexing. + #[strum_discriminants(strum(props(Arity = "1", Name = "indexing_code")))] + IndexingCode(Vec), + // break from loop instruction. + #[strum_discriminants(strum(props(Arity = "0", Name = "break_from_dispatch")))] + BreakFromDispatchLoop, + // swap the verify attr interrupt instruction with the next control instruction. + #[strum_discriminants(strum(props(Arity = "0", Name = "install_verify_attr")))] + InstallVerifyAttr, + // call verify_attrs. + #[strum_discriminants(strum(props(Arity = "0", Name = "verify_attr_interrupt")))] + VerifyAttrInterrupt, + // procedures + CallClause(ClauseType, usize, usize, bool, bool), // ClauseType, + // arity, + // perm_vars, + // last_call, + // use_default_call_policy. +} + +fn derive_input(ty: &Type) -> Option { + let clause_type: Type = parse_quote!{ ClauseType }; + let built_in_clause_type: Type = parse_quote! { BuiltInClauseType }; + let inlined_clause_type: Type = parse_quote! { InlinedClauseType }; + let system_clause_type: Type = parse_quote! { SystemClauseType }; + let compare_term_type: Type = parse_quote! { CompareTerm }; + let compare_number_type: Type = parse_quote! { CompareNumber }; + let repl_code_ptr_type: Type = parse_quote! { REPLCodePtr }; + + if ty == &clause_type { + Some(ClauseType::to_derive_input()) + } else if ty == &built_in_clause_type { + Some(BuiltInClauseType::to_derive_input()) + } else if ty == &inlined_clause_type { + Some(InlinedClauseType::to_derive_input()) + } else if ty == &system_clause_type { + Some(SystemClauseType::to_derive_input()) + } else if ty == &compare_number_type { + Some(CompareNumber::to_derive_input()) + } else if ty == &compare_term_type { + Some(CompareTerm::to_derive_input()) + } else if ty == &repl_code_ptr_type { + Some(REPLCodePtr::to_derive_input()) + } else { + None + } +} + +impl ToTokens for Arity { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Arity::Static(arity) => { + arity.to_tokens(tokens); + } + Arity::Ident(arity) => { + let ident = format_ident!("{}", arity); + tokens.append(ident); + } + } + } +} + +fn add_discriminant_data( + variant: &Variant, + prefix: &'static str, + variant_data: &mut Vec<(&'static str, Arity, Variant)>, +) -> (&'static str, Arity) + where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug +{ + let name = prop_from_ident::(&variant.ident, "Name"); + let arity = Arity::from(prop_from_ident::(&variant.ident, "Arity")); + + if prefix == "Call" { + let mut variant = variant.clone(); + variant.attrs.clear(); + + variant_data.push((name, arity, variant)); + } + + (name, arity) +} + +fn generate_instruction_preface() -> TokenStream { + quote! { + use crate::arena::*; + use crate::arithmetic::*; + use crate::atom_table::*; + use crate::forms::*; + use crate::machine::heap::*; + use crate::machine::machine_errors::MachineStub; + use crate::machine::machine_indices::CodeIndex; + use crate::parser::ast::*; + use crate::types::*; + + use indexmap::IndexMap; + use slice_deque::SliceDeque; + + fn reg_type_into_functor(r: RegType) -> MachineStub { + match r { + RegType::Temp(r) => functor!(atom!("x"), [fixnum(r)]), + RegType::Perm(r) => functor!(atom!("y"), [fixnum(r)]), + } + } + + impl Level { + fn into_functor(self) -> MachineStub { + match self { + Level::Root => functor!(atom!("level"), [atom(atom!("root"))]), + Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]), + Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]), + } + } + } + + impl ArithmeticTerm { + fn into_functor(&self, arena: &mut Arena) -> MachineStub { + match self { + &ArithmeticTerm::Reg(r) => reg_type_into_functor(r), + &ArithmeticTerm::Interm(i) => { + functor!(atom!("intermediate"), [fixnum(i)]) + } + &ArithmeticTerm::Number(n) => { + vec![HeapCellValue::from((n, arena))] + } + } + } + } + + #[derive(Debug, Clone, Copy)] + pub enum NextOrFail { + Next(usize), + Fail(usize), + } + + impl Default for NextOrFail { + fn default() -> Self { + NextOrFail::Fail(0) + } + } + + impl NextOrFail { + #[inline] + pub fn is_next(&self) -> bool { + if let NextOrFail::Next(_) = self { + true + } else { + false + } + } + } + + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + pub enum Death { + Finite(usize), + Infinity, + } + + impl Default for Death { + fn default() -> Self { + Death::Infinity + } + } + + #[derive(Clone, Copy, Debug)] + pub enum IndexedChoiceInstruction { + Retry(usize), + Trust(usize), + Try(usize), + } + + impl IndexedChoiceInstruction { + pub(crate) fn offset(&self) -> usize { + match self { + &IndexedChoiceInstruction::Retry(offset) => offset, + &IndexedChoiceInstruction::Trust(offset) => offset, + &IndexedChoiceInstruction::Try(offset) => offset, + } + } + + pub(crate) fn to_functor(&self) -> MachineStub { + match self { + &IndexedChoiceInstruction::Try(offset) => { + functor!(atom!("try"), [fixnum(offset)]) + } + &IndexedChoiceInstruction::Trust(offset) => { + functor!(atom!("trust"), [fixnum(offset)]) + } + &IndexedChoiceInstruction::Retry(offset) => { + functor!(atom!("retry"), [fixnum(offset)]) + } + } + } + } + + /// `IndexingInstruction` cf. page 110 of wambook. + #[derive(Clone, Debug)] + pub enum IndexingInstruction { + // The first index is the optimal argument being indexed. + SwitchOnTerm( + usize, + IndexingCodePtr, + IndexingCodePtr, + IndexingCodePtr, + IndexingCodePtr, + ), + SwitchOnConstant(IndexMap), + SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>), + } + + #[derive(Debug, Clone, Copy)] + pub enum IndexingCodePtr { + External(usize), // the index points past the indexing instruction prelude. + DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction. + Fail, + Internal(usize), // the index points into the indexing instruction prelude. + } + + impl IndexingCodePtr { + #[allow(dead_code)] + pub fn to_functor(self) -> MachineStub { + match self { + IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]), + IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]), + IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]), + IndexingCodePtr::Fail => { + vec![atom_as_cell!(atom!("fail"))] + }, + } + } + } + + impl IndexingInstruction { + pub fn to_functor(&self, mut h: usize) -> MachineStub { + match self { + &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => { + functor!( + atom!("switch_on_term"), + [ + fixnum(arg), + indexing_code_ptr(h, vars), + indexing_code_ptr(h, constants), + indexing_code_ptr(h, lists), + indexing_code_ptr(h, structures) + ] + ) + } + &IndexingInstruction::SwitchOnConstant(ref constants) => { + let mut key_value_list_stub = vec![]; + let orig_h = h; + + h += 2; // skip the 2-cell "switch_on_constant" functor. + + for (c, ptr) in constants.iter() { + let key_value_pair = functor!( + atom!(":"), + [literal(*c), indexing_code_ptr(h + 3, *ptr)] + ); + + key_value_list_stub.push(list_loc_as_cell!(h + 1)); + key_value_list_stub.push(str_loc_as_cell!(h + 3)); + key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len())); + + h += key_value_pair.len() + 3; + key_value_list_stub.extend(key_value_pair.into_iter()); + } + + key_value_list_stub.push(empty_list_as_cell!()); + + functor!( + atom!("switch_on_constant"), + [str(orig_h, 0)], + [key_value_list_stub] + ) + } + &IndexingInstruction::SwitchOnStructure(ref structures) => { + let mut key_value_list_stub = vec![]; + let orig_h = h; + + h += 2; // skip the 2-cell "switch_on_constant" functor. + + for ((name, arity), ptr) in structures.iter() { + let predicate_indicator_stub = functor!( + atom!("/"), + [atom(name), fixnum(*arity)] + ); + + let key_value_pair = functor!( + atom!(":"), + [str(h + 3, 0), indexing_code_ptr(h + 3, *ptr)], + [predicate_indicator_stub] + ); + + key_value_list_stub.push(list_loc_as_cell!(h + 1)); + key_value_list_stub.push(str_loc_as_cell!(h + 3)); + key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len())); + + h += key_value_pair.len() + 3; + key_value_list_stub.extend(key_value_pair.into_iter()); + } + + key_value_list_stub.push(empty_list_as_cell!()); + + functor!( + atom!("switch_on_structure"), + [str(orig_h, 0)], + [key_value_list_stub] + ) + } + } + } + } + + /// A `Line` is an instruction (cf. page 98 of wambook). + #[derive(Clone, Debug)] + pub enum IndexingLine { + Indexing(IndexingInstruction), + IndexedChoice(SliceDeque), + DynamicIndexedChoice(SliceDeque), + } + + impl From for IndexingLine { + #[inline] + fn from(instr: IndexingInstruction) -> Self { + IndexingLine::Indexing(instr) + } + } + + impl From> for IndexingLine { + #[inline] + fn from(instrs: SliceDeque) -> Self { + IndexingLine::IndexedChoice(instrs) + } + } + + fn arith_instr_unary_functor( + h: usize, + name: Atom, + arena: &mut Arena, + at: &ArithmeticTerm, + t: usize, + ) -> MachineStub { + let at_stub = at.into_functor(arena); + functor!(name, [str(h, 0), fixnum(t)], [at_stub]) + } + + fn arith_instr_bin_functor( + h: usize, + name: Atom, + arena: &mut Arena, + at_1: &ArithmeticTerm, + at_2: &ArithmeticTerm, + t: usize, + ) -> MachineStub { + let at_1_stub = at_1.into_functor(arena); + let at_2_stub = at_2.into_functor(arena); + + functor!( + name, + [str(h, 0), str(h, 1), fixnum(t)], + [at_1_stub, at_2_stub] + ) + } + + pub type Code = Vec; + + impl Instruction { + #[inline] + pub fn to_indexing_line_mut(&mut self) -> Option<&mut Vec> { + match self { + Instruction::IndexingCode(ref mut indexing_code) => Some(indexing_code), + _ => None, + } + } + + #[inline] + pub fn to_indexing_line(&self) -> Option<&Vec> { + match self { + Instruction::IndexingCode(ref indexing_code) => Some(indexing_code), + _ => None, + } + } + + #[inline] + pub fn is_head_instr(&self) -> bool { + match self { + Instruction::GetConstant(..) | + Instruction::GetList(..) | + Instruction::GetPartialString(..) | + Instruction::GetStructure(..) | + Instruction::GetValue(..) | + Instruction::UnifyConstant(..) | + Instruction::UnifyLocalValue(..) | + Instruction::UnifyVariable(..) | + Instruction::UnifyValue(..) | + Instruction::UnifyVoid(..) | + Instruction::GetVariable(..) | + Instruction::PutConstant(..) | + Instruction::PutList(..) | + Instruction::PutPartialString(..) | + Instruction::PutStructure(..) | + Instruction::PutUnsafeValue(..) | + Instruction::PutValue(..) | + Instruction::PutVariable(..) | + Instruction::SetConstant(..) | + Instruction::SetLocalValue(..) | + Instruction::SetVariable(..) | + Instruction::SetValue(..) | + Instruction::SetVoid(..) => true, + _ => false, + } + } + + pub fn enqueue_functors( + &self, + mut h: usize, + arena: &mut Arena, + functors: &mut Vec, + ) { + match self { + &Instruction::IndexingCode(ref indexing_instrs) => { + for indexing_instr in indexing_instrs { + match indexing_instr { + IndexingLine::Indexing(indexing_instr) => { + let section = indexing_instr.to_functor(h); + h += section.len(); + functors.push(section); + } + IndexingLine::IndexedChoice(indexed_choice_instrs) => { + for indexed_choice_instr in indexed_choice_instrs { + let section = indexed_choice_instr.to_functor(); + h += section.len(); + functors.push(section); + } + } + IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => { + for indexed_choice_instr in indexed_choice_instrs { + let section = functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)]); + + h += section.len(); + functors.push(section); + } + } + } + } + } + instr => functors.push(instr.to_functor(h, arena)), + } + } + + fn to_functor(&self, h: usize, arena: &mut Arena) -> MachineStub { + match self { + &Instruction::InstallVerifyAttr => { + functor!(atom!("install_verify_attr")) + } + &Instruction::VerifyAttrInterrupt => { + functor!(atom!("verify_attr_interrupt")) + } + &Instruction::DynamicElse(birth, death, next_or_fail) => { + match (death, next_or_fail) { + (Death::Infinity, NextOrFail::Next(i)) => { + functor!( + atom!("dynamic_else"), + [fixnum(birth), atom(atom!("inf")), fixnum(i)] + ) + } + (Death::Infinity, NextOrFail::Fail(i)) => { + let next_functor = functor!(atom!("fail"), [fixnum(i)]); + + functor!( + atom!("dynamic_else"), + [fixnum(birth), atom(atom!("inf")), str(h, 0)], + [next_functor] + ) + } + (Death::Finite(d), NextOrFail::Fail(i)) => { + let next_functor = functor!(atom!("fail"), [fixnum(i)]); + + functor!( + atom!("dynamic_else"), + [fixnum(birth), fixnum(d), str(h, 0)], + [next_functor] + ) + } + (Death::Finite(d), NextOrFail::Next(i)) => { + functor!(atom!("dynamic_else"), [fixnum(birth), fixnum(d), fixnum(i)]) + } + } + } + &Instruction::DynamicInternalElse(birth, death, next_or_fail) => { + match (death, next_or_fail) { + (Death::Infinity, NextOrFail::Next(i)) => { + functor!( + atom!("dynamic_internal_else"), + [fixnum(birth), atom(atom!("inf")), fixnum(i)] + ) + } + (Death::Infinity, NextOrFail::Fail(i)) => { + let next_functor = functor!(atom!("fail"), [fixnum(i)]); + + functor!( + atom!("dynamic_internal_else"), + [fixnum(birth), atom(atom!("inf")), str(h, 0)], + [next_functor] + ) + } + (Death::Finite(d), NextOrFail::Fail(i)) => { + let next_functor = functor!(atom!("fail"), [fixnum(i)]); + + functor!( + atom!("dynamic_internal_else"), + [fixnum(birth), fixnum(d), str(h, 0)], + [next_functor] + ) + } + (Death::Finite(d), NextOrFail::Next(i)) => { + functor!( + atom!("dynamic_internal_else"), + [fixnum(birth), fixnum(d), fixnum(i)] + ) + } + } + } + &Instruction::TryMeElse(offset) => { + functor!(atom!("try_me_else"), [fixnum(offset)]) + } + &Instruction::RetryMeElse(offset) => { + functor!(atom!("retry_me_else"), [fixnum(offset)]) + } + &Instruction::TrustMe(offset) => { + functor!(atom!("trust_me"), [fixnum(offset)]) + } + &Instruction::DefaultRetryMeElse(offset) => { + functor!(atom!("default_retry_me_else"), [fixnum(offset)]) + } + &Instruction::DefaultTrustMe(offset) => { + functor!(atom!("default_trust_me"), [fixnum(offset)]) + } + &Instruction::Cut(r) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("cut"), [str(h, 0)], [rt_stub]) + } + &Instruction::GetLevel(r) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("get_level"), [str(h, 0)], [rt_stub]) + } + &Instruction::GetLevelAndUnify(r) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("get_level_and_unify"), [str(h, 0)], [rt_stub]) + } + &Instruction::NeckCut => { + functor!(atom!("neck_cut")) + } + &Instruction::Add(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("add"), arena, at_1, at_2, t) + } + &Instruction::Sub(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("sub"), arena, at_1, at_2, t) + } + &Instruction::Mul(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("mul"), arena, at_1, at_2, t) + } + &Instruction::IntPow(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("int_pow"), arena, at_1, at_2, t) + } + &Instruction::Pow(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("pow"), arena, at_1, at_2, t) + } + &Instruction::IDiv(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("idiv"), arena, at_1, at_2, t) + } + &Instruction::Max(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("max"), arena, at_1, at_2, t) + } + &Instruction::Min(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("min"), arena, at_1, at_2, t) + } + &Instruction::IntFloorDiv(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("int_floor_div"), arena, at_1, at_2, t) + } + &Instruction::RDiv(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("rdiv"), arena, at_1, at_2, t) + } + &Instruction::Div(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("div"), arena, at_1, at_2, t) + } + &Instruction::Shl(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("shl"), arena, at_1, at_2, t) + } + &Instruction::Shr(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("shr"), arena, at_1, at_2, t) + } + &Instruction::Xor(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("xor"), arena, at_1, at_2, t) + } + &Instruction::And(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("and"), arena, at_1, at_2, t) + } + &Instruction::Or(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("or"), arena, at_1, at_2, t) + } + &Instruction::Mod(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("mod"), arena, at_1, at_2, t) + } + &Instruction::Rem(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t) + } + &Instruction::ATan2(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t) + } + &Instruction::Gcd(ref at_1, ref at_2, t) => { + arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t) + } + &Instruction::Sign(ref at, t) => { + arith_instr_unary_functor(h, atom!("sign"), arena, at, t) + } + &Instruction::Cos(ref at, t) => { + arith_instr_unary_functor(h, atom!("cos"), arena, at, t) + } + &Instruction::Sin(ref at, t) => { + arith_instr_unary_functor(h, atom!("sin"), arena, at, t) + } + &Instruction::Tan(ref at, t) => { + arith_instr_unary_functor(h, atom!("tan"), arena, at, t) + } + &Instruction::Log(ref at, t) => { + arith_instr_unary_functor(h, atom!("log"), arena, at, t) + } + &Instruction::Exp(ref at, t) => { + arith_instr_unary_functor(h, atom!("exp"), arena, at, t) + } + &Instruction::ACos(ref at, t) => { + arith_instr_unary_functor(h, atom!("acos"), arena, at, t) + } + &Instruction::ASin(ref at, t) => { + arith_instr_unary_functor(h, atom!("asin"), arena, at, t) + } + &Instruction::ATan(ref at, t) => { + arith_instr_unary_functor(h, atom!("atan"), arena, at, t) + } + &Instruction::Sqrt(ref at, t) => { + arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t) + } + &Instruction::Abs(ref at, t) => { + arith_instr_unary_functor(h, atom!("abs"), arena, at, t) + } + &Instruction::Float(ref at, t) => { + arith_instr_unary_functor(h, atom!("float"), arena, at, t) + } + &Instruction::Truncate(ref at, t) => { + arith_instr_unary_functor(h, atom!("truncate"), arena, at, t) + } + &Instruction::Round(ref at, t) => { + arith_instr_unary_functor(h, atom!("round"), arena, at, t) + } + &Instruction::Ceiling(ref at, t) => { + arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t) + } + &Instruction::Floor(ref at, t) => { + arith_instr_unary_functor(h, atom!("floor"), arena, at, t) + } + &Instruction::Neg(ref at, t) => arith_instr_unary_functor( + h, + atom!("-"), + arena, + at, + t, + ), + &Instruction::Plus(ref at, t) => arith_instr_unary_functor( + h, + atom!("+"), + arena, + at, + t, + ), + &Instruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor( + h, + atom!("\\"), + arena, + at, + t, + ), + &Instruction::IndexingCode(_) => { + // this case is covered in enqueue_functors, which + // should be called instead (to_functor is a private + // function for this reason). + vec![] + } + &Instruction::Allocate(num_frames) => { + functor!(atom!("allocate"), [fixnum(num_frames)]) + } + &Instruction::CallNamed(arity, name, ..) => { + functor!(atom!("call"), [atom(name), fixnum(arity)]) + } + &Instruction::ExecuteNamed(arity, name, ..) => { + functor!(atom!("execute"), [atom(name), fixnum(arity)]) + } + &Instruction::DefaultCallNamed(arity, name, ..) => { + functor!(atom!("call_default"), [atom(name), fixnum(arity)]) + } + &Instruction::DefaultExecuteNamed(arity, name, ..) => { + functor!(atom!("execute_default"), [atom(name), fixnum(arity)]) + } + &Instruction::CallN(arity, _) => { + functor!(atom!("call_n"), [fixnum(arity)]) + } + &Instruction::ExecuteN(arity, _) => { + functor!(atom!("execute_n"), [fixnum(arity)]) + } + &Instruction::DefaultCallN(arity, _) => { + functor!(atom!("call_default_n"), [fixnum(arity)]) + } + &Instruction::DefaultExecuteN(arity, _) => { + functor!(atom!("execute_default_n"), [fixnum(arity)]) + } + &Instruction::CallTermGreaterThan(_) | + &Instruction::CallTermLessThan(_) | + &Instruction::CallTermGreaterThanOrEqual(_) | + &Instruction::CallTermLessThanOrEqual(_) | + &Instruction::CallTermEqual(_) | + &Instruction::CallTermNotEqual(_) | + &Instruction::CallNumberGreaterThan(..) | + &Instruction::CallNumberLessThan(..) | + &Instruction::CallNumberGreaterThanOrEqual(..) | + &Instruction::CallNumberLessThanOrEqual(..) | + &Instruction::CallNumberEqual(..) | + &Instruction::CallNumberNotEqual(..) | + &Instruction::CallIs(..) | + &Instruction::CallAcyclicTerm(_) | + &Instruction::CallArg(_) | + &Instruction::CallCompare(_) | + &Instruction::CallCopyTerm(_) | + &Instruction::CallFunctor(_) | + &Instruction::CallGround(_) | + &Instruction::CallKeySort(_) | + &Instruction::CallRead(_) | + &Instruction::CallSort(_) => { + let (name, arity) = self.to_name_and_arity(); + functor!(atom!("call"), [atom(name), fixnum(arity)]) + } + // + &Instruction::ExecuteTermGreaterThan(_) | + &Instruction::ExecuteTermLessThan(_) | + &Instruction::ExecuteTermGreaterThanOrEqual(_) | + &Instruction::ExecuteTermLessThanOrEqual(_) | + &Instruction::ExecuteTermEqual(_) | + &Instruction::ExecuteTermNotEqual(_) | + &Instruction::ExecuteNumberGreaterThan(..) | + &Instruction::ExecuteNumberLessThan(..) | + &Instruction::ExecuteNumberGreaterThanOrEqual(..) | + &Instruction::ExecuteNumberLessThanOrEqual(..) | + &Instruction::ExecuteNumberEqual(..) | + &Instruction::ExecuteNumberNotEqual(..) | + &Instruction::ExecuteAcyclicTerm(_) | + &Instruction::ExecuteArg(_) | + &Instruction::ExecuteCompare(_) | + &Instruction::ExecuteCopyTerm(_) | + &Instruction::ExecuteFunctor(_) | + &Instruction::ExecuteGround(_) | + &Instruction::ExecuteIs(..) | + &Instruction::ExecuteKeySort(_) | + &Instruction::ExecuteRead(_) | + &Instruction::ExecuteSort(_) => { + let (name, arity) = self.to_name_and_arity(); + functor!(atom!("execute"), [atom(name), fixnum(arity)]) + } + // + &Instruction::DefaultCallTermGreaterThan(_) | + &Instruction::DefaultCallTermLessThan(_) | + &Instruction::DefaultCallTermGreaterThanOrEqual(_) | + &Instruction::DefaultCallTermLessThanOrEqual(_) | + &Instruction::DefaultCallTermEqual(_) | + &Instruction::DefaultCallTermNotEqual(_) | + &Instruction::DefaultCallNumberGreaterThan(..) | + &Instruction::DefaultCallNumberLessThan(..) | + &Instruction::DefaultCallNumberGreaterThanOrEqual(..) | + &Instruction::DefaultCallNumberLessThanOrEqual(..) | + &Instruction::DefaultCallNumberEqual(..) | + &Instruction::DefaultCallNumberNotEqual(..) | + &Instruction::DefaultCallAcyclicTerm(_) | + &Instruction::DefaultCallArg(_) | + &Instruction::DefaultCallCompare(_) | + &Instruction::DefaultCallCopyTerm(_) | + &Instruction::DefaultCallFunctor(_) | + &Instruction::DefaultCallGround(_) | + &Instruction::DefaultCallIs(..) | + &Instruction::DefaultCallKeySort(_) | + &Instruction::DefaultCallRead(_) | + &Instruction::DefaultCallSort(_) => { + let (name, arity) = self.to_name_and_arity(); + functor!(atom!("call_default"), [atom(name), fixnum(arity)]) + } + // + &Instruction::DefaultExecuteTermGreaterThan(_) | + &Instruction::DefaultExecuteTermLessThan(_) | + &Instruction::DefaultExecuteTermGreaterThanOrEqual(_) | + &Instruction::DefaultExecuteTermLessThanOrEqual(_) | + &Instruction::DefaultExecuteTermEqual(_) | + &Instruction::DefaultExecuteTermNotEqual(_) | + &Instruction::DefaultExecuteNumberGreaterThan(..) | + &Instruction::DefaultExecuteNumberLessThan(..) | + &Instruction::DefaultExecuteNumberGreaterThanOrEqual(..) | + &Instruction::DefaultExecuteNumberLessThanOrEqual(..) | + &Instruction::DefaultExecuteNumberEqual(..) | + &Instruction::DefaultExecuteNumberNotEqual(..) | + &Instruction::DefaultExecuteAcyclicTerm(_) | + &Instruction::DefaultExecuteArg(_) | + &Instruction::DefaultExecuteCompare(_) | + &Instruction::DefaultExecuteCopyTerm(_) | + &Instruction::DefaultExecuteFunctor(_) | + &Instruction::DefaultExecuteGround(_) | + &Instruction::DefaultExecuteIs(..) | + &Instruction::DefaultExecuteKeySort(_) | + &Instruction::DefaultExecuteRead(_) | + &Instruction::DefaultExecuteSort(_) => { + let (name, arity) = self.to_name_and_arity(); + functor!(atom!("execute_default"), [atom(name), fixnum(arity)]) + } + &Instruction::CallIsAtom(_, _) | + &Instruction::CallIsAtomic(_, _) | + &Instruction::CallIsCompound(_, _) | + &Instruction::CallIsInteger(_, _) | + &Instruction::CallIsNumber(_, _) | + &Instruction::CallIsRational(_, _) | + &Instruction::CallIsFloat(_, _) | + &Instruction::CallIsNonVar(_, _) | + &Instruction::CallIsVar(_, _) => { + let (name, arity) = self.to_name_and_arity(); + functor!(atom!("call"), [atom(name), fixnum(arity)]) + } + &Instruction::ExecuteIsAtom(_, _) | + &Instruction::ExecuteIsAtomic(_, _) | + &Instruction::ExecuteIsCompound(_, _) | + &Instruction::ExecuteIsInteger(_, _) | + &Instruction::ExecuteIsNumber(_, _) | + &Instruction::ExecuteIsRational(_, _) | + &Instruction::ExecuteIsFloat(_, _) | + &Instruction::ExecuteIsNonVar(_, _) | + &Instruction::ExecuteIsVar(_, _) => { + let (name, arity) = self.to_name_and_arity(); + functor!(atom!("execute"), [atom(name), fixnum(arity)]) + } + // + &Instruction::CallAtomChars(_) | + &Instruction::CallAtomCodes(_) | + &Instruction::CallAtomLength(_) | + &Instruction::CallBindFromRegister(_) | + &Instruction::CallContinuation(_) | + &Instruction::CallCharCode(_) | + &Instruction::CallCharType(_) | + &Instruction::CallCharsToNumber(_) | + &Instruction::CallCodesToNumber(_) | + &Instruction::CallCopyTermWithoutAttrVars(_) | + &Instruction::CallCheckCutPoint(_) | + &Instruction::CallClose(_) | + &Instruction::CallCopyToLiftedHeap(_) | + &Instruction::CallCreatePartialString(_) | + &Instruction::CallCurrentHostname(_) | + &Instruction::CallCurrentInput(_) | + &Instruction::CallCurrentOutput(_) | + &Instruction::CallDirectoryFiles(_) | + &Instruction::CallFileSize(_) | + &Instruction::CallFileExists(_) | + &Instruction::CallDirectoryExists(_) | + &Instruction::CallDirectorySeparator(_) | + &Instruction::CallMakeDirectory(_) | + &Instruction::CallMakeDirectoryPath(_) | + &Instruction::CallDeleteFile(_) | + &Instruction::CallRenameFile(_) | + &Instruction::CallWorkingDirectory(_) | + &Instruction::CallDeleteDirectory(_) | + &Instruction::CallPathCanonical(_) | + &Instruction::CallFileTime(_) | + &Instruction::CallDeleteAttribute(_) | + &Instruction::CallDeleteHeadAttribute(_) | + &Instruction::CallDynamicModuleResolution(..) | + &Instruction::CallEnqueueAttributedVar(_) | + &Instruction::CallFetchGlobalVar(_) | + &Instruction::CallFirstStream(_) | + &Instruction::CallFlushOutput(_) | + &Instruction::CallGetByte(_) | + &Instruction::CallGetChar(_) | + &Instruction::CallGetNChars(_) | + &Instruction::CallGetCode(_) | + &Instruction::CallGetSingleChar(_) | + &Instruction::CallResetAttrVarState(_) | + &Instruction::CallTruncateIfNoLiftedHeapGrowthDiff(_) | + &Instruction::CallTruncateIfNoLiftedHeapGrowth(_) | + &Instruction::CallGetAttributedVariableList(_) | + &Instruction::CallGetAttrVarQueueDelimiter(_) | + &Instruction::CallGetAttrVarQueueBeyond(_) | + &Instruction::CallGetBValue(_) | + &Instruction::CallGetContinuationChunk(_) | + &Instruction::CallGetNextDBRef(_) | + &Instruction::CallGetNextOpDBRef(_) | + &Instruction::CallIsPartialString(_) | + &Instruction::CallHalt(_) | + &Instruction::CallGetLiftedHeapFromOffset(_) | + &Instruction::CallGetLiftedHeapFromOffsetDiff(_) | + &Instruction::CallGetSCCCleaner(_) | + &Instruction::CallHeadIsDynamic(_) | + &Instruction::CallInstallSCCCleaner(_) | + &Instruction::CallInstallInferenceCounter(_) | + &Instruction::CallLiftedHeapLength(_) | + &Instruction::CallLoadLibraryAsStream(_) | + &Instruction::CallModuleExists(_) | + &Instruction::CallNextEP(_) | + &Instruction::CallNoSuchPredicate(_) | + &Instruction::CallNumberToChars(_) | + &Instruction::CallNumberToCodes(_) | + &Instruction::CallOpDeclaration(_) | + &Instruction::CallOpen(_) | + &Instruction::CallSetStreamOptions(_) | + &Instruction::CallNextStream(_) | + &Instruction::CallPartialStringTail(_) | + &Instruction::CallPeekByte(_) | + &Instruction::CallPeekChar(_) | + &Instruction::CallPeekCode(_) | + &Instruction::CallPointsToContinuationResetMarker(_) | + &Instruction::CallPutByte(_) | + &Instruction::CallPutChar(_) | + &Instruction::CallPutChars(_) | + &Instruction::CallPutCode(_) | + &Instruction::CallReadQueryTerm(_) | + &Instruction::CallReadTerm(_) | + &Instruction::CallRedoAttrVarBinding(_) | + &Instruction::CallRemoveCallPolicyCheck(_) | + &Instruction::CallRemoveInferenceCounter(_) | + &Instruction::CallResetContinuationMarker(_) | + &Instruction::CallRestoreCutPolicy(_) | + &Instruction::CallSetCutPoint(..) | + &Instruction::CallSetInput(_) | + &Instruction::CallSetOutput(_) | + &Instruction::CallStoreBacktrackableGlobalVar(_) | + &Instruction::CallStoreGlobalVar(_) | + &Instruction::CallStreamProperty(_) | + &Instruction::CallSetStreamPosition(_) | + &Instruction::CallInferenceLevel(_) | + &Instruction::CallCleanUpBlock(_) | + &Instruction::CallEraseBall(_) | + &Instruction::CallFail(_) | + &Instruction::CallGetBall(_) | + &Instruction::CallGetCurrentBlock(_) | + &Instruction::CallGetCutPoint(_) | + &Instruction::CallGetStaggeredCutPoint(_) | + &Instruction::CallGetDoubleQuotes(_) | + &Instruction::CallInstallNewBlock(_) | + &Instruction::CallMaybe(_) | + &Instruction::CallCpuNow(_) | + &Instruction::CallCurrentTime(_) | + &Instruction::CallQuotedToken(_) | + &Instruction::CallReadTermFromChars(_) | + &Instruction::CallResetBlock(_) | + &Instruction::CallReturnFromVerifyAttr(_) | + &Instruction::CallSetBall(_) | + &Instruction::CallSetCutPointByDefault(..) | + &Instruction::CallSetDoubleQuotes(_) | + &Instruction::CallSetSeed(_) | + &Instruction::CallSkipMaxList(_) | + &Instruction::CallSleep(_) | + &Instruction::CallSocketClientOpen(_) | + &Instruction::CallSocketServerOpen(_) | + &Instruction::CallSocketServerAccept(_) | + &Instruction::CallSocketServerClose(_) | + &Instruction::CallTLSAcceptClient(_) | + &Instruction::CallTLSClientConnect(_) | + &Instruction::CallSucceed(_) | + &Instruction::CallTermAttributedVariables(_) | + &Instruction::CallTermVariables(_) | + &Instruction::CallTermVariablesUnderMaxDepth(_) | + &Instruction::CallTruncateLiftedHeapTo(_) | + &Instruction::CallUnifyWithOccursCheck(_) | + &Instruction::CallUnwindEnvironments(_) | + &Instruction::CallUnwindStack(_) | + &Instruction::CallWAMInstructions(_) | + &Instruction::CallWriteTerm(_) | + &Instruction::CallWriteTermToChars(_) | + &Instruction::CallScryerPrologVersion(_) | + &Instruction::CallCryptoRandomByte(_) | + &Instruction::CallCryptoDataHash(_) | + &Instruction::CallCryptoDataHKDF(_) | + &Instruction::CallCryptoPasswordHash(_) | + &Instruction::CallCryptoDataEncrypt(_) | + &Instruction::CallCryptoDataDecrypt(_) | + &Instruction::CallCryptoCurveScalarMult(_) | + &Instruction::CallEd25519Sign(_) | + &Instruction::CallEd25519Verify(_) | + &Instruction::CallEd25519NewKeyPair(_) | + &Instruction::CallEd25519KeyPairPublicKey(_) | + &Instruction::CallCurve25519ScalarMult(_) | + &Instruction::CallFirstNonOctet(_) | + &Instruction::CallLoadHTML(_) | + &Instruction::CallLoadXML(_) | + &Instruction::CallGetEnv(_) | + &Instruction::CallSetEnv(_) | + &Instruction::CallUnsetEnv(_) | + &Instruction::CallShell(_) | + &Instruction::CallPID(_) | + &Instruction::CallCharsBase64(_) | + &Instruction::CallDevourWhitespace(_) | + &Instruction::CallIsSTOEnabled(_) | + &Instruction::CallSetSTOAsUnify(_) | + &Instruction::CallSetNSTOAsUnify(_) | + &Instruction::CallSetSTOWithErrorAsUnify(_) | + &Instruction::CallHomeDirectory(_) | + &Instruction::CallDebugHook(_) | + &Instruction::CallAddDiscontiguousPredicate(_) | + &Instruction::CallAddDynamicPredicate(_) | + &Instruction::CallAddMultifilePredicate(_) | + &Instruction::CallAddGoalExpansionClause(_) | + &Instruction::CallAddTermExpansionClause(_) | + &Instruction::CallAddInSituFilenameModule(_) | + &Instruction::CallClauseToEvacuable(_) | + &Instruction::CallScopedClauseToEvacuable(_) | + &Instruction::CallConcludeLoad(_) | + &Instruction::CallDeclareModule(_) | + &Instruction::CallLoadCompiledLibrary(_) | + &Instruction::CallLoadContextSource(_) | + &Instruction::CallLoadContextFile(_) | + &Instruction::CallLoadContextDirectory(_) | + &Instruction::CallLoadContextModule(_) | + &Instruction::CallLoadContextStream(_) | + &Instruction::CallPopLoadContext(_) | + &Instruction::CallPopLoadStatePayload(_) | + &Instruction::CallPushLoadContext(_) | + &Instruction::CallPushLoadStatePayload(_) | + &Instruction::CallUseModule(_) | + &Instruction::CallBuiltInProperty(_) | + &Instruction::CallMetaPredicateProperty(_) | + &Instruction::CallMultifileProperty(_) | + &Instruction::CallDiscontiguousProperty(_) | + &Instruction::CallDynamicProperty(_) | + &Instruction::CallAbolishClause(_) | + &Instruction::CallAsserta(_) | + &Instruction::CallAssertz(_) | + &Instruction::CallRetract(_) | + &Instruction::CallIsConsistentWithTermQueue(_) | + &Instruction::CallFlushTermQueue(_) | + &Instruction::CallRemoveModuleExports(_) | + &Instruction::CallAddNonCountedBacktracking(_) | + &Instruction::CallPopCount(_) => { + let (name, arity) = self.to_name_and_arity(); + functor!(atom!("call"), [atom(name), fixnum(arity)]) + } + // + &Instruction::ExecuteAtomChars(_) | + &Instruction::ExecuteAtomCodes(_) | + &Instruction::ExecuteAtomLength(_) | + &Instruction::ExecuteBindFromRegister(_) | + &Instruction::ExecuteContinuation(_) | + &Instruction::ExecuteCharCode(_) | + &Instruction::ExecuteCharType(_) | + &Instruction::ExecuteCharsToNumber(_) | + &Instruction::ExecuteCodesToNumber(_) | + &Instruction::ExecuteCopyTermWithoutAttrVars(_) | + &Instruction::ExecuteCheckCutPoint(_) | + &Instruction::ExecuteClose(_) | + &Instruction::ExecuteCopyToLiftedHeap(_) | + &Instruction::ExecuteCreatePartialString(_) | + &Instruction::ExecuteCurrentHostname(_) | + &Instruction::ExecuteCurrentInput(_) | + &Instruction::ExecuteCurrentOutput(_) | + &Instruction::ExecuteDirectoryFiles(_) | + &Instruction::ExecuteFileSize(_) | + &Instruction::ExecuteFileExists(_) | + &Instruction::ExecuteDirectoryExists(_) | + &Instruction::ExecuteDirectorySeparator(_) | + &Instruction::ExecuteMakeDirectory(_) | + &Instruction::ExecuteMakeDirectoryPath(_) | + &Instruction::ExecuteDeleteFile(_) | + &Instruction::ExecuteRenameFile(_) | + &Instruction::ExecuteWorkingDirectory(_) | + &Instruction::ExecuteDeleteDirectory(_) | + &Instruction::ExecutePathCanonical(_) | + &Instruction::ExecuteFileTime(_) | + &Instruction::ExecuteDeleteAttribute(_) | + &Instruction::ExecuteDeleteHeadAttribute(_) | + &Instruction::ExecuteDynamicModuleResolution(_, _) | + &Instruction::ExecuteEnqueueAttributedVar(_) | + &Instruction::ExecuteFetchGlobalVar(_) | + &Instruction::ExecuteFirstStream(_) | + &Instruction::ExecuteFlushOutput(_) | + &Instruction::ExecuteGetByte(_) | + &Instruction::ExecuteGetChar(_) | + &Instruction::ExecuteGetNChars(_) | + &Instruction::ExecuteGetCode(_) | + &Instruction::ExecuteGetSingleChar(_) | + &Instruction::ExecuteResetAttrVarState(_) | + &Instruction::ExecuteTruncateIfNoLiftedHeapGrowthDiff(_) | + &Instruction::ExecuteTruncateIfNoLiftedHeapGrowth(_) | + &Instruction::ExecuteGetAttributedVariableList(_) | + &Instruction::ExecuteGetAttrVarQueueDelimiter(_) | + &Instruction::ExecuteGetAttrVarQueueBeyond(_) | + &Instruction::ExecuteGetBValue(_) | + &Instruction::ExecuteGetContinuationChunk(_) | + &Instruction::ExecuteGetNextDBRef(_) | + &Instruction::ExecuteGetNextOpDBRef(_) | + &Instruction::ExecuteIsPartialString(_) | + &Instruction::ExecuteHalt(_) | + &Instruction::ExecuteGetLiftedHeapFromOffset(_) | + &Instruction::ExecuteGetLiftedHeapFromOffsetDiff(_) | + &Instruction::ExecuteGetSCCCleaner(_) | + &Instruction::ExecuteHeadIsDynamic(_) | + &Instruction::ExecuteInstallSCCCleaner(_) | + &Instruction::ExecuteInstallInferenceCounter(_) | + &Instruction::ExecuteLiftedHeapLength(_) | + &Instruction::ExecuteLoadLibraryAsStream(_) | + &Instruction::ExecuteModuleExists(_) | + &Instruction::ExecuteNextEP(_) | + &Instruction::ExecuteNoSuchPredicate(_) | + &Instruction::ExecuteNumberToChars(_) | + &Instruction::ExecuteNumberToCodes(_) | + &Instruction::ExecuteOpDeclaration(_) | + &Instruction::ExecuteOpen(_) | + &Instruction::ExecuteSetStreamOptions(_) | + &Instruction::ExecuteNextStream(_) | + &Instruction::ExecutePartialStringTail(_) | + &Instruction::ExecutePeekByte(_) | + &Instruction::ExecutePeekChar(_) | + &Instruction::ExecutePeekCode(_) | + &Instruction::ExecutePointsToContinuationResetMarker(_) | + &Instruction::ExecutePutByte(_) | + &Instruction::ExecutePutChar(_) | + &Instruction::ExecutePutChars(_) | + &Instruction::ExecutePutCode(_) | + &Instruction::ExecuteReadQueryTerm(_) | + &Instruction::ExecuteReadTerm(_) | + &Instruction::ExecuteRedoAttrVarBinding(_) | + &Instruction::ExecuteRemoveCallPolicyCheck(_) | + &Instruction::ExecuteRemoveInferenceCounter(_) | + &Instruction::ExecuteResetContinuationMarker(_) | + &Instruction::ExecuteRestoreCutPolicy(_) | + &Instruction::ExecuteSetCutPoint(_, _) | + &Instruction::ExecuteSetInput(_) | + &Instruction::ExecuteSetOutput(_) | + &Instruction::ExecuteStoreBacktrackableGlobalVar(_) | + &Instruction::ExecuteStoreGlobalVar(_) | + &Instruction::ExecuteStreamProperty(_) | + &Instruction::ExecuteSetStreamPosition(_) | + &Instruction::ExecuteInferenceLevel(_) | + &Instruction::ExecuteCleanUpBlock(_) | + &Instruction::ExecuteEraseBall(_) | + &Instruction::ExecuteFail(_) | + &Instruction::ExecuteGetBall(_) | + &Instruction::ExecuteGetCurrentBlock(_) | + &Instruction::ExecuteGetCutPoint(_) | + &Instruction::ExecuteGetStaggeredCutPoint(_) | + &Instruction::ExecuteGetDoubleQuotes(_) | + &Instruction::ExecuteInstallNewBlock(_) | + &Instruction::ExecuteMaybe(_) | + &Instruction::ExecuteCpuNow(_) | + &Instruction::ExecuteCurrentTime(_) | + &Instruction::ExecuteQuotedToken(_) | + &Instruction::ExecuteReadTermFromChars(_) | + &Instruction::ExecuteResetBlock(_) | + &Instruction::ExecuteReturnFromVerifyAttr(_) | + &Instruction::ExecuteSetBall(_) | + &Instruction::ExecuteSetCutPointByDefault(_, _) | + &Instruction::ExecuteSetDoubleQuotes(_) | + &Instruction::ExecuteSetSeed(_) | + &Instruction::ExecuteSkipMaxList(_) | + &Instruction::ExecuteSleep(_) | + &Instruction::ExecuteSocketClientOpen(_) | + &Instruction::ExecuteSocketServerOpen(_) | + &Instruction::ExecuteSocketServerAccept(_) | + &Instruction::ExecuteSocketServerClose(_) | + &Instruction::ExecuteTLSAcceptClient(_) | + &Instruction::ExecuteTLSClientConnect(_) | + &Instruction::ExecuteSucceed(_) | + &Instruction::ExecuteTermAttributedVariables(_) | + &Instruction::ExecuteTermVariables(_) | + &Instruction::ExecuteTermVariablesUnderMaxDepth(_) | + &Instruction::ExecuteTruncateLiftedHeapTo(_) | + &Instruction::ExecuteUnifyWithOccursCheck(_) | + &Instruction::ExecuteUnwindEnvironments(_) | + &Instruction::ExecuteUnwindStack(_) | + &Instruction::ExecuteWAMInstructions(_) | + &Instruction::ExecuteWriteTerm(_) | + &Instruction::ExecuteWriteTermToChars(_) | + &Instruction::ExecuteScryerPrologVersion(_) | + &Instruction::ExecuteCryptoRandomByte(_) | + &Instruction::ExecuteCryptoDataHash(_) | + &Instruction::ExecuteCryptoDataHKDF(_) | + &Instruction::ExecuteCryptoPasswordHash(_) | + &Instruction::ExecuteCryptoDataEncrypt(_) | + &Instruction::ExecuteCryptoDataDecrypt(_) | + &Instruction::ExecuteCryptoCurveScalarMult(_) | + &Instruction::ExecuteEd25519Sign(_) | + &Instruction::ExecuteEd25519Verify(_) | + &Instruction::ExecuteEd25519NewKeyPair(_) | + &Instruction::ExecuteEd25519KeyPairPublicKey(_) | + &Instruction::ExecuteCurve25519ScalarMult(_) | + &Instruction::ExecuteFirstNonOctet(_) | + &Instruction::ExecuteLoadHTML(_) | + &Instruction::ExecuteLoadXML(_) | + &Instruction::ExecuteGetEnv(_) | + &Instruction::ExecuteSetEnv(_) | + &Instruction::ExecuteUnsetEnv(_) | + &Instruction::ExecuteShell(_) | + &Instruction::ExecutePID(_) | + &Instruction::ExecuteCharsBase64(_) | + &Instruction::ExecuteDevourWhitespace(_) | + &Instruction::ExecuteIsSTOEnabled(_) | + &Instruction::ExecuteSetSTOAsUnify(_) | + &Instruction::ExecuteSetNSTOAsUnify(_) | + &Instruction::ExecuteSetSTOWithErrorAsUnify(_) | + &Instruction::ExecuteHomeDirectory(_) | + &Instruction::ExecuteDebugHook(_) | + &Instruction::ExecuteAddDiscontiguousPredicate(_) | + &Instruction::ExecuteAddDynamicPredicate(_) | + &Instruction::ExecuteAddMultifilePredicate(_) | + &Instruction::ExecuteAddGoalExpansionClause(_) | + &Instruction::ExecuteAddTermExpansionClause(_) | + &Instruction::ExecuteAddInSituFilenameModule(_) | + &Instruction::ExecuteClauseToEvacuable(_) | + &Instruction::ExecuteScopedClauseToEvacuable(_) | + &Instruction::ExecuteConcludeLoad(_) | + &Instruction::ExecuteDeclareModule(_) | + &Instruction::ExecuteLoadCompiledLibrary(_) | + &Instruction::ExecuteLoadContextSource(_) | + &Instruction::ExecuteLoadContextFile(_) | + &Instruction::ExecuteLoadContextDirectory(_) | + &Instruction::ExecuteLoadContextModule(_) | + &Instruction::ExecuteLoadContextStream(_) | + &Instruction::ExecutePopLoadContext(_) | + &Instruction::ExecutePopLoadStatePayload(_) | + &Instruction::ExecutePushLoadContext(_) | + &Instruction::ExecutePushLoadStatePayload(_) | + &Instruction::ExecuteUseModule(_) | + &Instruction::ExecuteBuiltInProperty(_) | + &Instruction::ExecuteMetaPredicateProperty(_) | + &Instruction::ExecuteMultifileProperty(_) | + &Instruction::ExecuteDiscontiguousProperty(_) | + &Instruction::ExecuteDynamicProperty(_) | + &Instruction::ExecuteAbolishClause(_) | + &Instruction::ExecuteAsserta(_) | + &Instruction::ExecuteAssertz(_) | + &Instruction::ExecuteRetract(_) | + &Instruction::ExecuteIsConsistentWithTermQueue(_) | + &Instruction::ExecuteFlushTermQueue(_) | + &Instruction::ExecuteRemoveModuleExports(_) | + &Instruction::ExecuteAddNonCountedBacktracking(_) | + &Instruction::ExecutePopCount(_) => { + let (name, arity) = self.to_name_and_arity(); + functor!(atom!("execute"), [atom(name), fixnum(arity)]) + } + // + &Instruction::Deallocate => { + functor!(atom!("deallocate")) + } + &Instruction::JmpByCall(_, offset, ..) => { + functor!(atom!("jmp_by_call"), [fixnum(offset)]) + } + &Instruction::JmpByExecute(_, offset, ..) => { + functor!(atom!("jmp_by_execute"), [fixnum(offset)]) + } + &Instruction::RevJmpBy(offset) => { + functor!(atom!("rev_jmp_by"), [fixnum(offset)]) + } + &Instruction::Proceed => { + functor!(atom!("proceed")) + } + &Instruction::GetConstant(lvl, c, r) => { + let lvl_stub = lvl.into_functor(); + let rt_stub = reg_type_into_functor(r); + + functor!( + atom!("get_constant"), + [str(h, 0), cell(c), str(h, 1)], + [lvl_stub, rt_stub] + ) + } + &Instruction::GetList(lvl, r) => { + let lvl_stub = lvl.into_functor(); + let rt_stub = reg_type_into_functor(r); + + functor!( + atom!("get_list"), + [str(h, 0), str(h, 1)], + [lvl_stub, rt_stub] + ) + } + &Instruction::GetPartialString(lvl, s, r, has_tail) => { + let lvl_stub = lvl.into_functor(); + let rt_stub = reg_type_into_functor(r); + + functor!( + atom!("get_partial_string"), + [ + str(h, 0), + string(h, s), + str(h, 1), + boolean(has_tail) + ], + [lvl_stub, rt_stub] + ) + } + &Instruction::GetStructure(name, arity, r) => { + let rt_stub = reg_type_into_functor(r); + + functor!( + atom!("get_structure"), + [atom(name), fixnum(arity), str(h, 0)], + [rt_stub] + ) + } + &Instruction::GetValue(r, arg) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub]) + } + &Instruction::GetVariable(r, arg) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) + } + &Instruction::UnifyConstant(c) => { + functor!(atom!("unify_constant"), [cell(c)]) + } + &Instruction::UnifyLocalValue(r) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub]) + } + &Instruction::UnifyVariable(r) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub]) + } + &Instruction::UnifyValue(r) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("unify_value"), [str(h, 0)], [rt_stub]) + } + &Instruction::UnifyVoid(vars) => { + functor!(atom!("unify_void"), [fixnum(vars)]) + } + &Instruction::PutUnsafeValue(norm, arg) => { + functor!(atom!("put_unsafe_value"), [fixnum(norm), fixnum(arg)]) + } + &Instruction::PutConstant(lvl, c, r) => { + let lvl_stub = lvl.into_functor(); + let rt_stub = reg_type_into_functor(r); + + functor!( + atom!("put_constant"), + [str(h, 0), cell(c), str(h, 1)], + [lvl_stub, rt_stub] + ) + } + &Instruction::PutList(lvl, r) => { + let lvl_stub = lvl.into_functor(); + let rt_stub = reg_type_into_functor(r); + + functor!( + atom!("put_list"), + [str(h, 0), str(h, 1)], + [lvl_stub, rt_stub] + ) + } + &Instruction::PutPartialString(lvl, s, r, has_tail) => { + let lvl_stub = lvl.into_functor(); + let rt_stub = reg_type_into_functor(r); + + functor!( + atom!("put_partial_string"), + [ + str(h, 0), + string(h, s), + str(h, 1), + boolean(has_tail) + ], + [lvl_stub, rt_stub] + ) + } + &Instruction::PutStructure(name, arity, r) => { + let rt_stub = reg_type_into_functor(r); + + functor!( + atom!("put_structure"), + [atom(name), fixnum(arity), str(h, 0)], + [rt_stub] + ) + } + &Instruction::PutValue(r, arg) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub]) + } + &Instruction::PutVariable(r, arg) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) + } + &Instruction::SetConstant(c) => { + functor!(atom!("set_constant"), [cell(c)]) + } + &Instruction::SetLocalValue(r) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub]) + } + &Instruction::SetVariable(r) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("set_variable"), [str(h, 0)], [rt_stub]) + } + &Instruction::SetValue(r) => { + let rt_stub = reg_type_into_functor(r); + functor!(atom!("set_value"), [str(h, 0)], [rt_stub]) + } + &Instruction::SetVoid(vars) => { + functor!(atom!("set_void"), [fixnum(vars)]) + } + &Instruction::BreakFromDispatchLoop => { + functor!(atom!("$break_from_dispatch_loop")) + } + } + } + } + } +} + +pub fn generate_instructions_rs() -> TokenStream { + let input = InstructionTemplate::to_derive_input(); + let mut instr_data = InstructionData::new(); + + instr_data.generate_instruction_enum_loop(input); + + let instr_variants: Vec<_> = instr_data.instr_variants + .iter() + .cloned() + .map(|(_, _, _, variant)| variant) + .collect(); + + fn attributeless_enum() -> Vec { + if let Data::Enum(DataEnum { mut variants, .. }) = T::to_derive_input().data { + for variant in &mut variants { + variant.attrs.clear(); + } + + variants.into_iter().collect() + } else { + unreachable!() + } + } + + let clause_type_variants = attributeless_enum::(); + let builtin_type_variants = attributeless_enum::(); + let inlined_type_variants = attributeless_enum::(); + let system_clause_type_variants = attributeless_enum::(); + let repl_code_ptr_variants = attributeless_enum::(); + let compare_number_variants = attributeless_enum::(); + let compare_term_variants = attributeless_enum::(); + + let mut clause_type_from_name_and_arity_arms = vec![]; + let mut clause_type_to_instr_arms = vec![]; + let mut clause_type_name_arms = vec![]; + + for (name, arity, variant) in instr_data.compare_number_variants { + let ident = variant.ident.clone(); + + let variant_fields: Vec<_> = variant.fields + .into_iter() + .map(|field| { + let ty = field.ty; + quote! { #ty::default() } + }) + .collect(); + + clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() { + quote! { + (atom!(#name), #arity) => ClauseType::Inlined( + InlinedClauseType::CompareNumber(CompareNumber::#ident(#(#variant_fields),*)) + ) + } + } else { + quote! { + (atom!(#name), #arity) => ClauseType::Inlined( + InlinedClauseType::CompareNumber(CompareNumber::#ident) + ) + } + }); + + clause_type_name_arms.push(if !variant_fields.is_empty() { + quote! { + ClauseType::Inlined( + InlinedClauseType::CompareNumber(CompareNumber::#ident(..)) + ) => atom!(#name) + } + } else { + quote! { + ClauseType::Inlined( + InlinedClauseType::CompareNumber(CompareNumber::#ident) + ) => (atom!(#name), #arity) + } + }); + + let ident = variant.ident; + let instr_ident = format_ident!("Call{}", ident); + + let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) + .map(|n| format_ident!("f_{}", n)) + .collect(); + + clause_type_to_instr_arms.push( + quote! { + ClauseType::Inlined( + InlinedClauseType::CompareNumber(CompareNumber::#ident(#(#placeholder_ids),*)) + ) => Instruction::#instr_ident(#(#placeholder_ids),*, 0) + } + ); + } + + for (name, arity, variant) in instr_data.compare_term_variants { + let ident = variant.ident.clone(); + + clause_type_from_name_and_arity_arms.push(quote! { + (atom!(#name), #arity) => ClauseType::BuiltIn( + BuiltInClauseType::CompareTerm(CompareTerm::#ident) + ) + }); + + clause_type_name_arms.push( + quote! { + ClauseType::BuiltIn( + BuiltInClauseType::CompareTerm(CompareTerm::#ident) + ) => atom!(#name) + } + ); + + let ident = variant.ident; + let instr_ident = format_ident!("Call{}", ident); + + clause_type_to_instr_arms.push( + quote! { + ClauseType::BuiltIn( + BuiltInClauseType::CompareTerm(CompareTerm::#ident) + ) => Instruction::#instr_ident(0) + } + ); + } + + for (name, arity, variant) in instr_data.builtin_type_variants { + let ident = variant.ident.clone(); + + let variant_fields: Vec<_> = variant.fields + .into_iter() + .map(|field| { + let ty = field.ty; + quote! { #ty::default() } + }) + .collect(); + + clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() { + quote! { + (atom!(#name), #arity) => ClauseType::BuiltIn( + BuiltInClauseType::#ident(#(#variant_fields),*) + ) + } + } else { + quote! { + (atom!(#name), #arity) => ClauseType::BuiltIn( + BuiltInClauseType::#ident + ) + } + }); + + clause_type_name_arms.push(if !variant_fields.is_empty() { + quote! { + ClauseType::BuiltIn( + BuiltInClauseType::#ident(..) + ) => atom!(#name) + } + } else { + quote! { + ClauseType::BuiltIn( + BuiltInClauseType::#ident + ) => atom!(#name) + } + }); + + let ident = variant.ident; + let instr_ident = format_ident!("Call{}", ident); + + let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) + .map(|n| format_ident!("f_{}", n)) + .collect(); + + clause_type_to_instr_arms.push(if !variant_fields.is_empty() { + quote! { + ClauseType::BuiltIn( + BuiltInClauseType::#ident(#(#placeholder_ids),*) + ) => Instruction::#instr_ident(#(#placeholder_ids),*,0) + } + } else { + quote! { + ClauseType::BuiltIn( + BuiltInClauseType::#ident + ) => Instruction::#instr_ident(0) + } + }); + } + + for (name, arity, variant) in instr_data.inlined_type_variants { + let ident = variant.ident.clone(); + + let variant_fields: Vec<_> = variant.fields + .into_iter() + .map(|field| { + if field.ty.type_id() == TypeId::of::() { + quote! { #arity } + } else { + let ty = field.ty; + quote! { #ty::default() } + } + }) + .collect(); + + clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() { + quote! { + (atom!(#name), #arity) => ClauseType::Inlined( + InlinedClauseType::#ident(#(#variant_fields),*) + ) + } + } else { + quote! { + (atom!(#name), #arity) => ClauseType::Inlined( + InlinedClauseType::#ident + ) + } + }); + + clause_type_name_arms.push(if !variant_fields.is_empty() { + quote! { + ClauseType::Inlined( + InlinedClauseType::#ident(..) + ) => atom!(#name) + } + } else { + quote! { + ClauseType::Inlined( + InlinedClauseType::#ident + ) => atom!(#name) + } + }); + + let ident = variant.ident; + let instr_ident = format_ident!("Call{}", ident); + + let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) + .map(|n| format_ident!("f_{}", n)) + .collect(); + + clause_type_to_instr_arms.push( + quote! { + ClauseType::Inlined( + InlinedClauseType::#ident(#(#placeholder_ids),*) + ) => Instruction::#instr_ident(#(#placeholder_ids),*,0) + } + ); + } + + for (name, arity, variant) in instr_data.system_clause_type_variants { + let ident = variant.ident.clone(); + + let variant_fields: Vec<_> = variant.fields + .into_iter() + .map(|field| { + if field.ty == parse_quote! { usize } { + quote! { #arity } + } else { + let ty = field.ty; + quote! { #ty::default() } + } + }) + .collect(); + + clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() { + if ident.to_string() == "SetCutPoint" { + quote! { + (atom!(#name), #arity) => ClauseType::System( + SystemClauseType::#ident(temp_v!(1)) + ) + } + } else if ident.to_string() == "SetCutPointByDefault" { + quote! { + (atom!(#name), #arity) => ClauseType::System( + SystemClauseType::#ident(temp_v!(1)) + ) + } + } else { + quote! { + (atom!(#name), #arity) => ClauseType::System( + SystemClauseType::#ident(#(#variant_fields),*) + ) + } + } + } else { + quote! { + (atom!(#name), #arity) => ClauseType::System( + SystemClauseType::#ident + ) + } + }); + + clause_type_name_arms.push(if !variant_fields.is_empty() { + quote! { + ClauseType::System( + SystemClauseType::#ident(..) + ) => atom!(#name) + } + } else { + quote! { + ClauseType::System( + SystemClauseType::#ident + ) => atom!(#name) + } + }); + + let ident = variant.ident; + let instr_ident = if ident != "CallContinuation" { + format_ident!("Call{}", ident) + } else { + ident.clone() + }; + + let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) + .map(|n| format_ident!("f_{}", n)) + .collect(); + + clause_type_to_instr_arms.push(if !variant_fields.is_empty() { + quote! { + ClauseType::System( + SystemClauseType::#ident(#(#placeholder_ids),*) + ) => Instruction::#instr_ident(#(#placeholder_ids),*,0) + } + } else { + quote! { + ClauseType::System( + SystemClauseType::#ident + ) => Instruction::#instr_ident(0) + } + }); + } + + for (name, arity, variant) in instr_data.repl_code_ptr_variants { + let ident = variant.ident.clone(); + + let variant_fields: Vec<_> = variant.fields + .into_iter() + .map(|field| { + if field.ty.type_id() == TypeId::of::() { + quote! { #arity } + } else { + let ty = field.ty; + quote! { #ty::default() } + } + }) + .collect(); + + clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() { + quote! { + (atom!(#name), #arity) => ClauseType::System(SystemClauseType::REPL( + REPLCodePtr::#ident(#(#variant_fields),*) + )) + } + } else { + quote! { + (atom!(#name), #arity) => ClauseType::System(SystemClauseType::REPL( + REPLCodePtr::#ident + )) + } + }); + + clause_type_name_arms.push(if !variant_fields.is_empty() { + quote! { + ClauseType::System( + SystemClauseType::REPL(REPLCodePtr::#ident(..)) + ) => atom!(#name) + } + } else { + quote! { + ClauseType::System( + SystemClauseType::REPL(REPLCodePtr::#ident) + ) => atom!(#name) + } + }); + + let ident = variant.ident; + let instr_ident = format_ident!("Call{}", ident); + + let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) + .map(|n| format_ident!("f_{}", n)) + .collect(); + + clause_type_to_instr_arms.push(if !variant_fields.is_empty() { + quote! { + ClauseType::System(SystemClauseType::REPL( + REPLCodePtr::#ident(#(#placeholder_ids),*) + )) => Instruction::#instr_ident(#(#placeholder_ids),*,0) + } + } else { + quote! { + ClauseType::System(SystemClauseType::REPL( + REPLCodePtr::#ident + )) => Instruction::#instr_ident(0) + } + }); + } + + for (name, arity, variant) in instr_data.clause_type_variants { + let ident = variant.ident.clone(); + + if ident == "Named" { + clause_type_from_name_and_arity_arms.push(quote! { + (name, arity) => ClauseType::Named(arity, name, CodeIndex::default()) + }); + + clause_type_to_instr_arms.push(quote! { + ClauseType::Named(arity, name, idx) => Instruction::CallNamed(arity, name, idx, 0) + }); + + clause_type_name_arms.push(quote! { + ClauseType::Named(_, name, _) => *name + }); + + continue; + } + + let variant_fields: Vec<_> = variant.fields + .into_iter() + .map(|field| { + if field.ty == parse_quote! { usize } { + quote! { #arity } + } else { + let ty = field.ty; + quote! { #ty::default() } + } + }) + .collect(); + + clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() { + quote! { + (atom!(#name), #arity) => ClauseType::#ident(#(#variant_fields),*) + } + } else { + quote! { + (atom!(#name), #arity) => ClauseType::#ident + } + }); + + clause_type_name_arms.push(if !variant_fields.is_empty() { + quote! { + ClauseType::#ident(..) => atom!(#name) + } + } else { + quote! { + ClauseType::#ident => atom!(#name) + } + }); + + let ident = variant.ident; + + let placeholder_ids: Vec<_> = (0 .. variant_fields.len()) + .map(|n| format_ident!("f_{}", n)) + .collect(); + + clause_type_to_instr_arms.push(if !variant_fields.is_empty() { + quote! { + ClauseType::#ident(#(#placeholder_ids),*) => + Instruction::#ident(#(#placeholder_ids),*,0) + } + } else { + quote! { + ClauseType::#ident => Instruction::#ident(0) + } + }); + } + + let to_execute_arms: Vec<_> = instr_data.instr_variants + .iter() + .cloned() + .filter_map(|(_, _, _, variant)| { + let variant_ident = variant.ident.clone(); + let variant_string = variant.ident.to_string(); + + let enum_arity = if let Fields::Unnamed(fields) = &variant.fields { + fields.unnamed.len() + } else { + 0 + }; + + let placeholder_ids: Vec<_> = (0 .. enum_arity) + .map(|n| format_ident!("f_{}", n)) + .collect(); + + if variant_string.starts_with("Call") { + let execute_ident = format_ident!("Execute{}", variant_string["Call".len() ..]); + + Some(if enum_arity == 0 { + quote! { + Instruction::#variant_ident => + Instruction::#execute_ident + } + } else { + quote! { + Instruction::#variant_ident(#(#placeholder_ids),*) => + Instruction::#execute_ident(#(#placeholder_ids),*) + } + }) + } else if variant_string.starts_with("DefaultCall") { + let execute_ident = + format_ident!("DefaultExecute{}", variant_string["DefaultCall".len() ..]); + + Some(if enum_arity == 0 { + quote! { + Instruction::#variant_ident => + Instruction::#execute_ident + } + } else { + quote! { + Instruction::#variant_ident(#(#placeholder_ids),*) => + Instruction::#execute_ident(#(#placeholder_ids),*) + } + }) + } else if variant_string == "JmpByCall" { + Some(quote! { + Instruction::JmpByCall(#(#placeholder_ids),*) => + Instruction::JmpByExecute(#(#placeholder_ids),*) + }) + } else { + None + } + }) + .collect(); + + let is_execute_arms: Vec<_> = instr_data.instr_variants + .iter() + .cloned() + .filter_map(|(_, _, _, variant)| { + let variant_ident = variant.ident.clone(); + let variant_string = variant.ident.to_string(); + + let enum_arity = if let Fields::Unnamed(fields) = &variant.fields { + fields.unnamed.len() + } else { + 0 + }; + + if variant_string.starts_with("Execute") { + Some(if enum_arity == 0 { + quote! { + Instruction::#variant_ident => true + } + } else { + quote! { + Instruction::#variant_ident(..) => true + } + }) + } else if variant_string.starts_with("DefaultExecute") { + Some(if enum_arity == 0 { + quote! { + Instruction::#variant_ident => true + } + } else { + quote! { + Instruction::#variant_ident(..) => true + } + }) + } else if variant_string == "JmpByExecute" { + Some(quote! { + Instruction::#variant_ident(..) => true + }) + } else { + None + } + }) + .collect(); + + let to_default_arms: Vec<_> = instr_data.instr_variants + .iter() + .cloned() + .filter_map(|(_, _, countable_inference, variant)| { + if !is_non_default_callable(&variant.ident) { + return None; + } + + if let CountableInference::HasDefault = countable_inference { + let variant_ident = variant.ident.clone(); + let def_variant_ident = format_ident!("Default{}", variant.ident); + let enum_arity = if let Fields::Unnamed(fields) = &variant.fields { + fields.unnamed.len() + } else { + unreachable!() + }; + + let placeholder_ids: Vec<_> = (0 .. enum_arity) + .map(|n| format_ident!("f_{}", n)) + .collect(); + + Some(quote! { + Instruction::#variant_ident(#(#placeholder_ids),*) => + Instruction::#def_variant_ident(#(#placeholder_ids),*) + }) + } else { + None + } + }) + .collect(); + + let perm_vars_mut_arms: Vec<_> = instr_data.instr_variants + .iter() + .cloned() + .filter_map(|(_, _, _, variant)| { + if !is_callable(&variant.ident) && !is_jmp(&variant.ident) { + return None; + } + + let variant_ident = variant.ident.clone(); + let enum_arity = if let Fields::Unnamed(fields) = &variant.fields { + fields.unnamed.len() + } else { + 0 + }; + + let placeholder_ids: Vec<_> = (1 .. enum_arity) + .map(|_| format_ident!("_")) + .collect(); + + Some(if enum_arity == 1 { + quote! { + Instruction::#variant_ident(ref mut perm_vars) => Some(perm_vars) + } + } else { + quote! { + Instruction::#variant_ident(#(#placeholder_ids),*, ref mut perm_vars) => + Some(perm_vars) + } + }) + }) + .collect(); + + let control_flow_arms: Vec<_> = instr_data.instr_variants + .iter() + .cloned() + .filter_map(|(_, _, _, variant)| { + if !is_callable(&variant.ident) && !is_jmp(&variant.ident) { + return None; + } + + let variant_ident = variant.ident.clone(); + + Some(quote! { + Instruction::#variant_ident(..) => true + }) + }) + .collect(); + + let instr_macro_arms: Vec<_> = instr_data.instr_variants + .iter() + .rev() // produce default, execute & default & execute cases first. + .cloned() + .filter_map(|(name, arity, _, variant)| { + let variant_ident = variant.ident.clone(); + let variant_string = variant.ident.to_string(); + let arity = match arity { + Arity::Static(arity) => arity, + _ => 1 + }; + + Some(if variant_string.starts_with("Execute") { + quote! { + (#name, execute, $($args:expr),*) => { + Instruction::#variant_ident($($args),*) + } + } + } else if variant_string.starts_with("Call") { + quote! { + (#name, $($args:expr),*) => { + Instruction::#variant_ident($($args),*) + } + } + } else if variant_string.starts_with("DefaultExecute") { + quote! { + (#name, execute, default, $($args:expr),*) => { + Instruction::#variant_ident($($args),*) + } + } + } else if variant_string.starts_with("DefaultCall") { + quote! { + (#name, default, $($args:expr),*) => { + Instruction::#variant_ident($($args),*) + } + } + } else { + if arity == 0 { + quote! { + (#name) => { + Instruction::#variant_ident + } + } + } else { + quote! { + (#name, $($args:expr),*) => { + Instruction::#variant_ident($($args),*) + } + } + } + }) + }) + .collect(); + + let name_and_arity_arms: Vec<_> = instr_data.instr_variants + .into_iter() + .map(|(name,arity,_,variant)| { + let ident = &variant.ident; + + let enum_arity = if let Fields::Unnamed(fields) = &variant.fields { + fields.unnamed.len() + } else { + 0 + }; + + match arity { + Arity::Static(_) if enum_arity == 0 => { + quote! { &Instruction::#ident => (atom!(#name), #arity) } + } + Arity::Static(_) => { + quote! { &Instruction::#ident(..) => (atom!(#name), #arity) } + } + Arity::Ident(_) if enum_arity == 0 => { + quote! { &Instruction::#ident(#arity) => (atom!(#name), #arity) } + } + Arity::Ident(_) => { + quote! { &Instruction::#ident(#arity, ..) => (atom!(#name), #arity) } + } + } + }) + .collect(); + + let preface_tokens = generate_instruction_preface(); + + quote! { + #preface_tokens + + #[derive(Clone, Debug)] + pub enum CompareTerm { + #( + #compare_term_variants, + )* + } + + #[derive(Clone, Copy, Debug)] + pub enum CompareNumber { + #( + #compare_number_variants, + )* + } + + impl CompareNumber { + pub fn set_terms(&mut self, l_at_1: ArithmeticTerm, l_at_2: ArithmeticTerm) { + match self { + CompareNumber::NumberGreaterThan(ref mut at_1, ref mut at_2) | + CompareNumber::NumberLessThan(ref mut at_1, ref mut at_2) | + CompareNumber::NumberGreaterThanOrEqual(ref mut at_1, ref mut at_2) | + CompareNumber::NumberLessThanOrEqual(ref mut at_1, ref mut at_2) | + CompareNumber::NumberNotEqual(ref mut at_1, ref mut at_2) | + CompareNumber::NumberEqual(ref mut at_1, ref mut at_2) => { + *at_1 = l_at_1; + *at_2 = l_at_2; + } + } + } + } + + #[derive(Clone, Debug)] + pub enum BuiltInClauseType { + #( + #builtin_type_variants, + )* + } + + #[derive(Clone, Debug)] + pub enum InlinedClauseType { + #( + #inlined_type_variants, + )* + } + + #[derive(Clone, Debug)] + pub enum SystemClauseType { + #( + #system_clause_type_variants, + )* + } + + #[derive(Clone, Debug)] + pub enum REPLCodePtr { + #( + #repl_code_ptr_variants, + )* + } + + #[derive(Clone, Debug)] + pub enum ClauseType { + #( + #clause_type_variants, + )* + } + + impl ClauseType { + pub fn from(name: Atom, arity: usize) -> ClauseType { + match (name, arity) { + #( + #clause_type_from_name_and_arity_arms, + )* + } + } + + pub fn to_instr(self) -> Instruction { + match self { + #( + #clause_type_to_instr_arms, + )* + } + } + + pub fn is_builtin(&self) -> bool { + if let ClauseType::BuiltIn(_) = self { + true + } else { + false + } + } + + pub fn is_inlined(&self) -> bool { + if let ClauseType::Inlined(_) = self { + true + } else { + false + } + } + + pub fn name(&self) -> Atom { + match self { + #( + #clause_type_name_arms, + )* + } + } + } + + #[derive(Clone, Debug)] + pub enum Instruction { + #( + #instr_variants, + )* + } + + impl Instruction { + pub fn to_name_and_arity(&self) -> (Atom, usize) { + match self { + #( + #name_and_arity_arms, + )* + } + } + + pub fn to_default(self) -> Instruction { + match self { + #( + #to_default_arms, + )* + _ => self, + } + } + + pub fn to_execute(self) -> Instruction { + match self { + #( + #to_execute_arms, + )* + _ => self + } + } + + pub fn is_execute(&self) -> bool { + match self { + #( + #is_execute_arms, + )* + _ => false, + } + } + + pub fn perm_vars_mut(&mut self) -> Option<&mut usize> { + match self { + #( + #perm_vars_mut_arms, + )* + _ => None, + } + } + + pub fn is_ctrl_instr(&self) -> bool { + match self { + &Instruction::Allocate(_) | + &Instruction::Deallocate | + &Instruction::Proceed | + &Instruction::RevJmpBy(_) => true, + #( + #control_flow_arms, + )* + _ => false, + } + } + + pub fn is_query_instr(&self) -> bool { + match self { + &Instruction::GetVariable(..) | + &Instruction::PutConstant(..) | + &Instruction::PutList(..) | + &Instruction::PutPartialString(..) | + &Instruction::PutStructure(..) | + &Instruction::PutUnsafeValue(..) | + &Instruction::PutValue(..) | + &Instruction::PutVariable(..) | + &Instruction::SetConstant(..) | + &Instruction::SetLocalValue(..) | + &Instruction::SetVariable(..) | + &Instruction::SetValue(..) | + &Instruction::SetVoid(..) => true, + _ => false, + } + } + } + + #[macro_export] + macro_rules! instr { + #( + #instr_macro_arms + );* + } + } +} + +fn is_callable(id: &Ident) -> bool { + let id = id.to_string(); + + id.starts_with("Call") || id.starts_with("Execute") || id.starts_with("DefaultCall") || + id.starts_with("DefaultExecute") +} + +fn is_non_default_callable(id: &Ident) -> bool { + let id = id.to_string(); + id.starts_with("Call") || id.starts_with("Execute") +} + +fn is_jmp(id: &Ident) -> bool { + let id = id.to_string(); + id.starts_with("JmpByCall") || id.starts_with("JmpByExecute") +} + +fn create_instr_variant(id: Ident, mut variant: Variant) -> Variant { + use proc_macro2::Span; + use syn::punctuated::Punctuated; + use syn::token::Paren; + + // add the perm_vars usize field to the variant. + + if is_callable(&id) || is_jmp(&id) { + let field = Field { + attrs: vec![], + vis: Visibility::Inherited, + ident: None, + colon_token: None, + ty: parse_quote! { usize }, + }; + + match &mut variant.fields { + Fields::Unnamed(ref mut fields) => { + fields.unnamed.push(field); + } + Fields::Unit => { + variant.fields = Fields::Unnamed(FieldsUnnamed { + paren_token: Paren(Span::call_site()), + unnamed: { + let mut fields_seq = Punctuated::new(); + fields_seq.push(field); + fields_seq + } + }); + } + _ => { + unreachable!(); + } + } + } + + variant.ident = id; + variant.attrs.clear(); + + variant +} + +fn prop_from_ident(id: &Ident, key: &'static str) -> &'static str + where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug +{ + let disc = match DiscriminantT::from_str(id.to_string().as_str()) { + Ok(disc) => disc, + Err(_) => { + panic!("can't generate discriminant {}", id); + } + }; + + match disc.get_str(key) { + Some(prop) => prop, + None => { + panic!("can't find property {} of discriminant {:?}", key, disc); + } + } +} + +#[derive(Clone, Copy)] +enum Arity { + Static(usize), + Ident(&'static str) +} + +impl From<&'static str> for Arity { + fn from(arity: &'static str) -> Self { + usize::from_str_radix(&arity, 10) + .map(|n| Arity::Static(n)) + .unwrap_or_else(|_| Arity::Ident(arity)) + } +} + +#[derive(Clone, Copy)] +enum CountableInference { + HasDefault, + NotCounted, +} + +struct InstructionData { + instr_variants: Vec<(&'static str, Arity, CountableInference, Variant)>, + clause_type_variants: Vec<(&'static str, Arity, Variant)>, + builtin_type_variants: Vec<(&'static str, Arity, Variant)>, + inlined_type_variants: Vec<(&'static str, Arity, Variant)>, + system_clause_type_variants: Vec<(&'static str, Arity, Variant)>, + compare_number_variants: Vec<(&'static str, Arity, Variant)>, + compare_term_variants: Vec<(&'static str, Arity, Variant)>, + repl_code_ptr_variants: Vec<(&'static str, Arity, Variant)>, +} + +impl InstructionData { + fn new() -> Self { + Self { + instr_variants: vec![], + clause_type_variants: vec![], + builtin_type_variants: vec![], + inlined_type_variants: vec![], + system_clause_type_variants: vec![], + compare_number_variants: vec![], + compare_term_variants: vec![], + repl_code_ptr_variants: vec![], + } + } + + fn label_variant(&mut self, id: &Ident, prefix: &'static str, variant: Variant) { + let (name, arity, countable_inference) = if id == "CompareNumber" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.compare_number_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else if id == "CompareTerm" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.compare_term_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else if id == "BuiltInClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.builtin_type_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else if id == "InlinedClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.inlined_type_variants, + ); + + (name, arity, CountableInference::NotCounted) + } else if id == "REPLCodePtr" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.repl_code_ptr_variants, + ); + + (name, arity, CountableInference::NotCounted) + } else if id == "SystemClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.system_clause_type_variants, + ); + + (name, arity, CountableInference::NotCounted) + } else if id == "InstructionTemplate" { + ( prop_from_ident::(&variant.ident, "Name"), + Arity::from(prop_from_ident::(&variant.ident, "Arity")), + CountableInference::NotCounted + ) + } else if id == "ClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.clause_type_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else { + panic!("type ID is: {}", id); + }; + + let v_string = variant.ident.to_string(); + + let v_ident = if v_string.starts_with("Call") { + format_ident!("{}", v_string["Call".len() ..]) + } else { + variant.ident.clone() + }; + + let generated_variant = create_instr_variant( + format_ident!("{}{}", prefix, v_ident), + variant.clone(), + ); + + self.instr_variants.push( + (name, arity, countable_inference, generated_variant) + ); + } + + fn generate_instruction_enum_loop(&mut self, input: syn::DeriveInput) { + if let Data::Enum(DataEnum { variants, .. }) = input.data { + for mut variant in variants { + if let Some(field) = variant.fields.iter().next() { + if let Some(input) = derive_input(&field.ty) { + self.generate_instruction_enum_loop(input); + continue; + } + } + + if input.ident == "InstructionTemplate" { + variant.attrs.clear(); + self.label_variant(&input.ident, "", variant); + continue; + } + + self.label_variant(&input.ident, "Call", variant.clone()); + self.label_variant(&input.ident, "Execute", variant.clone()); + + if input.ident == "BuiltInClauseType" || + input.ident == "CompareNumber" || + input.ident == "CompareTerm" || + input.ident == "ClauseType" + { + self.label_variant(&input.ident, "DefaultCall", variant.clone()); + self.label_variant(&input.ident, "DefaultExecute", variant); + } + } + } else { + panic!("{} must be an enum!", input.ident); + } + } +} diff --git a/crates/prolog_parser/Cargo.toml b/crates/prolog_parser/Cargo.toml deleted file mode 100644 index dc19afbd..00000000 --- a/crates/prolog_parser/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "prolog_parser" -version = "0.8.68" -authors = ["Mark Thom "] -edition = "2021" -repository = "https://github.com/mthom/scryer-prolog" -description = " An operator precedence parser for the Rebis development version of Scryer Prolog, an up and coming ISO Prolog implementation." -license = "BSD-3-Clause" - -[dependencies] -indexmap = "1.0.2" -lexical = "5.2.1" -ordered-float = "0.5.0" -rug = { optional = true, version = "1.4.0" } -num-rug-adapter = { optional = true, path = "../num-rug-adapter" } -unicode_reader = "1.0.0" - -[lib] -path = "src/lib.rs" - -[features] -num = ["num-rug-adapter"] -# no default features to make num tests work -# workaround for --no-default-features and --features not working intuitively for workspaces with a root package -# see rust-lang/cargo#7160 -# default = ["rug"] diff --git a/crates/static-string-indexing/Cargo.toml b/crates/static-string-indexing/Cargo.toml index a6da96b9..1432ae68 100644 --- a/crates/static-string-indexing/Cargo.toml +++ b/crates/static-string-indexing/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "static-string-indexing" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] proc-macro2 = "*" diff --git a/crates/to-syn-value/Cargo.toml b/crates/to-syn-value/Cargo.toml new file mode 100644 index 00000000..3fa4953d --- /dev/null +++ b/crates/to-syn-value/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "to-syn-value" +version = "0.1.0" +authors = ["Mark Thom "] +edition = "2021" +publish = false + +[dependencies] +syn = { version = "*", features = ['full', 'visit', 'extra-traits'] } +to-syn-value_derive = { path = "../to-syn-value_derive" } \ No newline at end of file diff --git a/crates/to-syn-value/src/lib.rs b/crates/to-syn-value/src/lib.rs new file mode 100644 index 00000000..753c44a9 --- /dev/null +++ b/crates/to-syn-value/src/lib.rs @@ -0,0 +1,3 @@ +pub trait ToDeriveInput { + fn to_derive_input() -> syn::DeriveInput; +} diff --git a/crates/to-syn-value_derive/Cargo.toml b/crates/to-syn-value_derive/Cargo.toml new file mode 100644 index 00000000..9dc0e8ac --- /dev/null +++ b/crates/to-syn-value_derive/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "to-syn-value_derive" +version = "0.1.0" +authors = ["Mark Thom "] +edition = "2021" +publish = false + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "*" +syn = { version = "*", features = ['full', 'visit', 'extra-traits'] } +quote = "*" \ No newline at end of file diff --git a/crates/to-syn-value_derive/src/lib.rs b/crates/to-syn-value_derive/src/lib.rs new file mode 100644 index 00000000..13845ac4 --- /dev/null +++ b/crates/to-syn-value_derive/src/lib.rs @@ -0,0 +1,20 @@ +use syn::*; +use quote::*; + +#[proc_macro_derive(ToDeriveInput)] +pub fn derive_to_derive_input(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let derive_input = parse_macro_input!(input as DeriveInput); + let ty_name = derive_input.ident.clone(); + + quote! { + use to_syn_value::*; + + impl ToDeriveInput for #ty_name { + fn to_derive_input() -> syn::DeriveInput { + syn::parse_quote! { + #derive_input + } + } + } + }.into() +} diff --git a/src/allocator.rs b/src/allocator.rs index c29adc92..7a3b43a0 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -3,6 +3,7 @@ use crate::temp_v; use crate::fixtures::*; use crate::forms::*; +use crate::instructions::*; use crate::machine::machine_indices::*; use std::cell::Cell; @@ -11,7 +12,7 @@ use std::rc::Rc; pub(crate) trait Allocator<'a> { fn new() -> Self; - fn mark_anon_var(&mut self, _: Level, _: GenContext, _: &mut Vec) + fn mark_anon_var(&mut self, _: Level, _: GenContext, _: &mut Code) where Target: crate::targets::CompilationTarget<'a>; fn mark_non_var( @@ -19,7 +20,7 @@ pub(crate) trait Allocator<'a> { _: Level, _: GenContext, _: &'a Cell, - _: &mut Vec, + _: &mut Code, ) where Target: crate::targets::CompilationTarget<'a>; fn mark_reserved_var( @@ -28,7 +29,7 @@ pub(crate) trait Allocator<'a> { _: Level, _: &'a Cell, _: GenContext, - _: &mut Vec, + _: &mut Code, _: RegType, _: bool, ) where @@ -39,7 +40,7 @@ pub(crate) trait Allocator<'a> { _: Level, _: &'a Cell, _: GenContext, - _: &mut Vec, + _: &mut Code, ) where Target: crate::targets::CompilationTarget<'a>; diff --git a/src/arithmetic.rs b/src/arithmetic.rs index d09187f8..6396336d 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -1,6 +1,5 @@ use crate::arena::*; use crate::atom_table::*; -use crate::clause_types::*; use crate::fixtures::*; use crate::forms::*; use crate::instructions::*; @@ -25,6 +24,29 @@ use std::ops::Div; use std::rc::Rc; use std::vec::Vec; +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ArithmeticTerm { + Reg(RegType), + Interm(usize), + Number(Number), +} + +impl ArithmeticTerm { + pub(crate) fn interm_or(&self, interm: usize) -> usize { + if let &ArithmeticTerm::Interm(interm) = self { + interm + } else { + interm + } + } +} + +impl Default for ArithmeticTerm { + fn default() -> Self { + ArithmeticTerm::Number(Number::default()) + } +} + #[derive(Debug)] pub(crate) struct ArithInstructionIterator<'a> { state_stack: Vec>, @@ -46,7 +68,7 @@ impl<'a> ArithInstructionIterator<'a> { Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) } ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => { - let ct = ClauseType::Named(atom!("float"), 1, CodeIndex::default()); + let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default()); Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms)) } _ => Err(ArithmeticError::NonEvaluableFunctor( @@ -174,27 +196,27 @@ impl<'a> ArithmeticEvaluator<'a> { name: Atom, a1: ArithmeticTerm, t: usize, - ) -> Result { + ) -> Result { match name { - atom!("abs") => Ok(ArithmeticInstruction::Abs(a1, t)), - atom!("-") => Ok(ArithmeticInstruction::Neg(a1, t)), - atom!("+") => Ok(ArithmeticInstruction::Plus(a1, t)), - atom!("cos") => Ok(ArithmeticInstruction::Cos(a1, t)), - atom!("sin") => Ok(ArithmeticInstruction::Sin(a1, t)), - atom!("tan") => Ok(ArithmeticInstruction::Tan(a1, t)), - atom!("log") => Ok(ArithmeticInstruction::Log(a1, t)), - atom!("exp") => Ok(ArithmeticInstruction::Exp(a1, t)), - atom!("sqrt") => Ok(ArithmeticInstruction::Sqrt(a1, t)), - atom!("acos") => Ok(ArithmeticInstruction::ACos(a1, t)), - atom!("asin") => Ok(ArithmeticInstruction::ASin(a1, t)), - atom!("atan") => Ok(ArithmeticInstruction::ATan(a1, t)), - atom!("float") => Ok(ArithmeticInstruction::Float(a1, t)), - atom!("truncate") => Ok(ArithmeticInstruction::Truncate(a1, t)), - atom!("round") => Ok(ArithmeticInstruction::Round(a1, t)), - atom!("ceiling") => Ok(ArithmeticInstruction::Ceiling(a1, t)), - atom!("floor") => Ok(ArithmeticInstruction::Floor(a1, t)), - atom!("sign") => Ok(ArithmeticInstruction::Sign(a1, t)), - atom!("\\") => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)), + atom!("abs") => Ok(Instruction::Abs(a1, t)), + atom!("-") => Ok(Instruction::Neg(a1, t)), + atom!("+") => Ok(Instruction::Plus(a1, t)), + atom!("cos") => Ok(Instruction::Cos(a1, t)), + atom!("sin") => Ok(Instruction::Sin(a1, t)), + atom!("tan") => Ok(Instruction::Tan(a1, t)), + atom!("log") => Ok(Instruction::Log(a1, t)), + atom!("exp") => Ok(Instruction::Exp(a1, t)), + atom!("sqrt") => Ok(Instruction::Sqrt(a1, t)), + atom!("acos") => Ok(Instruction::ACos(a1, t)), + atom!("asin") => Ok(Instruction::ASin(a1, t)), + atom!("atan") => Ok(Instruction::ATan(a1, t)), + atom!("float") => Ok(Instruction::Float(a1, t)), + atom!("truncate") => Ok(Instruction::Truncate(a1, t)), + atom!("round") => Ok(Instruction::Round(a1, t)), + atom!("ceiling") => Ok(Instruction::Ceiling(a1, t)), + atom!("floor") => Ok(Instruction::Floor(a1, t)), + atom!("sign") => Ok(Instruction::Sign(a1, t)), + atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)), _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)), } } @@ -205,28 +227,28 @@ impl<'a> ArithmeticEvaluator<'a> { a1: ArithmeticTerm, a2: ArithmeticTerm, t: usize, - ) -> Result { + ) -> Result { match name { - atom!("+") => Ok(ArithmeticInstruction::Add(a1, a2, t)), - atom!("-") => Ok(ArithmeticInstruction::Sub(a1, a2, t)), - atom!("/") => Ok(ArithmeticInstruction::Div(a1, a2, t)), - atom!("//") => Ok(ArithmeticInstruction::IDiv(a1, a2, t)), - atom!("max") => Ok(ArithmeticInstruction::Max(a1, a2, t)), - atom!("min") => Ok(ArithmeticInstruction::Min(a1, a2, t)), - atom!("div") => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)), - atom!("rdiv") => Ok(ArithmeticInstruction::RDiv(a1, a2, t)), - atom!("*") => Ok(ArithmeticInstruction::Mul(a1, a2, t)), - atom!("**") => Ok(ArithmeticInstruction::Pow(a1, a2, t)), - atom!("^") => Ok(ArithmeticInstruction::IntPow(a1, a2, t)), - atom!(">>") => Ok(ArithmeticInstruction::Shr(a1, a2, t)), - atom!("<<") => Ok(ArithmeticInstruction::Shl(a1, a2, t)), - atom!("/\\") => Ok(ArithmeticInstruction::And(a1, a2, t)), - atom!("\\/") => Ok(ArithmeticInstruction::Or(a1, a2, t)), - atom!("xor") => Ok(ArithmeticInstruction::Xor(a1, a2, t)), - atom!("mod") => Ok(ArithmeticInstruction::Mod(a1, a2, t)), - atom!("rem") => Ok(ArithmeticInstruction::Rem(a1, a2, t)), - atom!("gcd") => Ok(ArithmeticInstruction::Gcd(a1, a2, t)), - atom!("atan2") => Ok(ArithmeticInstruction::ATan2(a1, a2, t)), + atom!("+") => Ok(Instruction::Add(a1, a2, t)), + atom!("-") => Ok(Instruction::Sub(a1, a2, t)), + atom!("/") => Ok(Instruction::Div(a1, a2, t)), + atom!("//") => Ok(Instruction::IDiv(a1, a2, t)), + atom!("max") => Ok(Instruction::Max(a1, a2, t)), + atom!("min") => Ok(Instruction::Min(a1, a2, t)), + atom!("div") => Ok(Instruction::IntFloorDiv(a1, a2, t)), + atom!("rdiv") => Ok(Instruction::RDiv(a1, a2, t)), + atom!("*") => Ok(Instruction::Mul(a1, a2, t)), + atom!("**") => Ok(Instruction::Pow(a1, a2, t)), + atom!("^") => Ok(Instruction::IntPow(a1, a2, t)), + atom!(">>") => Ok(Instruction::Shr(a1, a2, t)), + atom!("<<") => Ok(Instruction::Shl(a1, a2, t)), + atom!("/\\") => Ok(Instruction::And(a1, a2, t)), + atom!("\\/") => Ok(Instruction::Or(a1, a2, t)), + atom!("xor") => Ok(Instruction::Xor(a1, a2, t)), + atom!("mod") => Ok(Instruction::Mod(a1, a2, t)), + atom!("rem") => Ok(Instruction::Rem(a1, a2, t)), + atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)), + atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)), _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)), } } @@ -244,7 +266,7 @@ impl<'a> ArithmeticEvaluator<'a> { &mut self, name: Atom, arity: usize, - ) -> Result { + ) -> Result { match arity { 1 => { let a1 = self.interm.pop().unwrap(); @@ -310,7 +332,7 @@ impl<'a> ArithmeticEvaluator<'a> { self.interm.push(ArithmeticTerm::Reg(r)); } ArithTermRef::Op(name, arity) => { - code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?)); + code.push(self.instr_from_clause(name, arity)?); } } } diff --git a/src/clause_types.rs b/src/clause_types.rs deleted file mode 100644 index 8083775a..00000000 --- a/src/clause_types.rs +++ /dev/null @@ -1,952 +0,0 @@ -use crate::atom_table::*; -use crate::machine::machine_indices::*; -use crate::parser::ast::*; -use crate::parser::rug::rand::RandState; - -use crate::forms::Number; -use crate::temp_v; - -use ref_thread_local::{ref_thread_local}; - -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum CompareNumberQT { - GreaterThan, - LessThan, - GreaterThanOrEqual, - LessThanOrEqual, - NotEqual, - Equal, -} - -impl CompareNumberQT { - fn name(self) -> Atom { - match self { - CompareNumberQT::GreaterThan => atom!(">"), - CompareNumberQT::LessThan => atom!("<"), - CompareNumberQT::GreaterThanOrEqual => atom!(">="), - CompareNumberQT::LessThanOrEqual => atom!("=<"), - CompareNumberQT::NotEqual => atom!("=\\="), - CompareNumberQT::Equal => atom!("=:="), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum CompareTermQT { - LessThan, - LessThanOrEqual, - GreaterThanOrEqual, - GreaterThan, -} - -impl CompareTermQT { - fn name(self) -> Atom { - match self { - CompareTermQT::GreaterThan => atom!("@>"), - CompareTermQT::LessThan => atom!("@<"), - CompareTermQT::GreaterThanOrEqual => atom!("@>="), - CompareTermQT::LessThanOrEqual => atom!("@=<"), - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ArithmeticTerm { - Reg(RegType), - Interm(usize), - Number(Number), -} - -impl ArithmeticTerm { - pub(crate) fn interm_or(&self, interm: usize) -> usize { - if let &ArithmeticTerm::Interm(interm) = self { - interm - } else { - interm - } - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum InlinedClauseType { - CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm), - IsAtom(RegType), - IsAtomic(RegType), - IsCompound(RegType), - IsInteger(RegType), - IsNumber(RegType), - IsRational(RegType), - IsFloat(RegType), - IsNonVar(RegType), - IsVar(RegType), -} - -ref_thread_local! { - pub(crate) static managed RANDOM_STATE: RandState<'static> = RandState::new(); -} - -pub fn clause_type_form(name: Atom, arity: usize) -> Option { - match (name, arity) { - (atom!(">"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( - CompareNumberQT::GreaterThan, - ar_reg!(temp_v!(1)), - ar_reg!(temp_v!(2)), - ))), - (atom!("<"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( - CompareNumberQT::LessThan, - ar_reg!(temp_v!(1)), - ar_reg!(temp_v!(2)), - ))), - (atom!(">="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( - CompareNumberQT::GreaterThanOrEqual, - ar_reg!(temp_v!(1)), - ar_reg!(temp_v!(2)), - ))), - (atom!("=<"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( - CompareNumberQT::LessThanOrEqual, - ar_reg!(temp_v!(1)), - ar_reg!(temp_v!(2)), - ))), - (atom!("=:="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( - CompareNumberQT::Equal, - ar_reg!(temp_v!(1)), - ar_reg!(temp_v!(2)), - ))), - (atom!("=\\="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber( - CompareNumberQT::NotEqual, - ar_reg!(temp_v!(1)), - ar_reg!(temp_v!(2)), - ))), - (atom!("atom"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsAtom(temp_v!(1)))), - (atom!("atomic"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsAtomic(temp_v!(1)))), - (atom!("compound"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsCompound(temp_v!( - 1 - )))), - (atom!("integer"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsInteger(temp_v!( - 1 - )))), - (atom!("number"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsNumber(temp_v!(1)))), - (atom!("rational"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsRational(temp_v!( - 1 - )))), - (atom!("float"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsFloat(temp_v!(1)))), - (atom!("nonvar"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsNonVar(temp_v!(1)))), - (atom!("var"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsVar(temp_v!(1)))), - (atom!("acyclic_term"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm)), - (atom!("arg"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Arg)), - (atom!("compare"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Compare)), - (atom!("@>"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( - CompareTermQT::GreaterThan, - ))), - (atom!("@<"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( - CompareTermQT::LessThan, - ))), - (atom!("@>="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( - CompareTermQT::GreaterThanOrEqual, - ))), - (atom!("@=<"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm( - CompareTermQT::LessThanOrEqual, - ))), - (atom!("copy_term"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CopyTerm)), - (atom!("=="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Eq)), - (atom!("functor"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Functor)), - (atom!("ground"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::Ground)), - (atom!("is"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Is( - temp_v!(1), - ar_reg!(temp_v!(2)), - ))), - (atom!("keysort"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::KeySort)), - (atom!("\\=="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::NotEq)), - (atom!("read"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Read)), - (atom!("sort"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Sort)), - _ => None, - } -} - -impl InlinedClauseType { - pub(crate) fn name(&self) -> Atom { - match self { - &InlinedClauseType::CompareNumber(qt, ..) => qt.name(), - &InlinedClauseType::IsAtom(..) => atom!("atom"), - &InlinedClauseType::IsAtomic(..) => atom!("atomic"), - &InlinedClauseType::IsCompound(..) => atom!("compound"), - &InlinedClauseType::IsNumber(..) => atom!("number"), - &InlinedClauseType::IsInteger(..) => atom!("integer"), - &InlinedClauseType::IsRational(..) => atom!("rational"), - &InlinedClauseType::IsFloat(..) => atom!("float"), - &InlinedClauseType::IsNonVar(..) => atom!("nonvar"), - &InlinedClauseType::IsVar(..) => atom!("var"), - } - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum SystemClauseType { - AtomChars, - AtomCodes, - AtomLength, - BindFromRegister, - CallContinuation, - CharCode, - CharType, - CharsToNumber, - CodesToNumber, - CopyTermWithoutAttrVars, - CheckCutPoint, - Close, - CopyToLiftedHeap, - CreatePartialString, - CurrentHostname, - CurrentInput, - CurrentOutput, - DirectoryFiles, - FileSize, - FileExists, - DirectoryExists, - DirectorySeparator, - MakeDirectory, - MakeDirectoryPath, - DeleteFile, - RenameFile, - WorkingDirectory, - DeleteDirectory, - PathCanonical, - FileTime, - DeleteAttribute, - DeleteHeadAttribute, - DynamicModuleResolution(usize), - EnqueueAttributedVar, - FetchGlobalVar, - FirstStream, - FlushOutput, - GetByte, - GetChar, - GetNChars, - GetCode, - GetSingleChar, - ResetAttrVarState, - TruncateIfNoLiftedHeapGrowthDiff, - TruncateIfNoLiftedHeapGrowth, - GetAttributedVariableList, - GetAttrVarQueueDelimiter, - GetAttrVarQueueBeyond, - GetBValue, - GetContinuationChunk, - GetNextDBRef, - GetNextOpDBRef, - IsPartialString, - Halt, - GetLiftedHeapFromOffset, - GetLiftedHeapFromOffsetDiff, - GetSCCCleaner, - HeadIsDynamic, - InstallSCCCleaner, - InstallInferenceCounter, - LiftedHeapLength, - LoadLibraryAsStream, - ModuleExists, - NextEP, - NoSuchPredicate, - NumberToChars, - NumberToCodes, - OpDeclaration, - Open, - SetStreamOptions, - NextStream, - PartialStringTail, - PeekByte, - PeekChar, - PeekCode, - PointsToContinuationResetMarker, - PutByte, - PutChar, - PutChars, - PutCode, - REPL(REPLCodePtr), - ReadQueryTerm, - ReadTerm, - RedoAttrVarBinding, - RemoveCallPolicyCheck, - RemoveInferenceCounter, - ResetContinuationMarker, - RestoreCutPolicy, - SetCutPoint(RegType), - SetInput, - SetOutput, - StoreBacktrackableGlobalVar, - StoreGlobalVar, - StreamProperty, - SetStreamPosition, - InferenceLevel, - CleanUpBlock, - EraseBall, - Fail, - GetBall, - GetCurrentBlock, - GetCutPoint, - GetStaggeredCutPoint, - GetDoubleQuotes, - InstallNewBlock, - Maybe, - CpuNow, - CurrentTime, - QuotedToken, - ReadTermFromChars, - ResetBlock, - ReturnFromVerifyAttr, - SetBall, - SetCutPointByDefault(RegType), - SetDoubleQuotes, - SetSeed, - SkipMaxList, - Sleep, - SocketClientOpen, - SocketServerOpen, - SocketServerAccept, - SocketServerClose, - TLSAcceptClient, - TLSClientConnect, - Succeed, - TermAttributedVariables, - TermVariables, - TermVariablesUnderMaxDepth, - TruncateLiftedHeapTo, - UnifyWithOccursCheck, - UnwindEnvironments, - UnwindStack, - WAMInstructions, - WriteTerm, - WriteTermToChars, - ScryerPrologVersion, - CryptoRandomByte, - CryptoDataHash, - CryptoDataHKDF, - CryptoPasswordHash, - CryptoDataEncrypt, - CryptoDataDecrypt, - CryptoCurveScalarMult, - Ed25519Sign, - Ed25519Verify, - Ed25519NewKeyPair, - Ed25519KeyPairPublicKey, - Curve25519ScalarMult, - FirstNonOctet, - LoadHTML, - LoadXML, - GetEnv, - SetEnv, - UnsetEnv, - Shell, - PID, - CharsBase64, - DevourWhitespace, - IsSTOEnabled, - SetSTOAsUnify, - SetNSTOAsUnify, - SetSTOWithErrorAsUnify, - HomeDirectory, - DebugHook, - PopCount -} - -impl SystemClauseType { - pub(crate) fn name(&self) -> Atom { - match self { - &SystemClauseType::AtomChars => atom!("$atom_chars"), - &SystemClauseType::AtomCodes => atom!("$atom_codes"), - &SystemClauseType::AtomLength => atom!("$atom_length"), - &SystemClauseType::BindFromRegister => atom!("$bind_from_register"), - &SystemClauseType::CallContinuation => atom!("$call_continuation"), - &SystemClauseType::CharCode => atom!("$char_code"), - &SystemClauseType::CharType => atom!("$char_type"), - &SystemClauseType::CharsToNumber => atom!("$chars_to_number"), - &SystemClauseType::CheckCutPoint => atom!("$check_cp"), - &SystemClauseType::CodesToNumber => atom!("$codes_to_number"), - &SystemClauseType::CopyTermWithoutAttrVars => { - atom!("$copy_term_without_attr_vars") - } - &SystemClauseType::CreatePartialString => atom!("$create_partial_string"), - &SystemClauseType::CurrentInput => atom!("$current_input"), - &SystemClauseType::CurrentHostname => atom!("$current_hostname"), - &SystemClauseType::CurrentOutput => atom!("$current_output"), - &SystemClauseType::DirectoryFiles => atom!("$directory_files"), - &SystemClauseType::FileSize => atom!("$file_size"), - &SystemClauseType::FileExists => atom!("$file_exists"), - &SystemClauseType::DirectoryExists => atom!("$directory_exists"), - &SystemClauseType::DirectorySeparator => atom!("$directory_separator"), - &SystemClauseType::MakeDirectory => atom!("$make_directory"), - &SystemClauseType::MakeDirectoryPath => atom!("$make_directory_path"), - &SystemClauseType::DeleteFile => atom!("$delete_file"), - &SystemClauseType::RenameFile => atom!("$rename_file"), - &SystemClauseType::DeleteDirectory => atom!("$delete_directory"), - &SystemClauseType::WorkingDirectory => atom!("$working_directory"), - &SystemClauseType::PathCanonical => atom!("$path_canonical"), - &SystemClauseType::FileTime => atom!("$file_time"), - &SystemClauseType::REPL(REPLCodePtr::AddDiscontiguousPredicate) => { - atom!("$add_discontiguous_predicate") - } - &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => atom!("$add_dynamic_predicate"), - &SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate) => { - atom!("$add_multifile_predicate") - } - &SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause) => { - atom!("$add_goal_expansion_clause") - } - &SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause) => { - atom!("$add_term_expansion_clause") - } - &SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) => atom!("$clause_to_evacuable"), - &SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable) => { - atom!("$scoped_clause_to_evacuable") - } - &SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) => atom!("$conclude_load"), - &SystemClauseType::REPL(REPLCodePtr::DeclareModule) => atom!("$declare_module"), - &SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary) => atom!("$load_compiled_library"), - &SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload) => { - atom!("$push_load_state_payload") - } - &SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule) => { - atom!("$add_in_situ_filename_module") - } - &SystemClauseType::REPL(REPLCodePtr::Asserta) => atom!("$asserta"), - &SystemClauseType::REPL(REPLCodePtr::Assertz) => atom!("$assertz"), - &SystemClauseType::REPL(REPLCodePtr::Retract) => atom!("$retract_clause"), - &SystemClauseType::REPL(REPLCodePtr::UseModule) => atom!("$use_module"), - &SystemClauseType::REPL(REPLCodePtr::PushLoadContext) => atom!("$push_load_context"), - &SystemClauseType::REPL(REPLCodePtr::PopLoadContext) => atom!("$pop_load_context"), - &SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) => atom!("$pop_load_state_payload"), - &SystemClauseType::REPL(REPLCodePtr::LoadContextSource) => atom!("$prolog_lc_source"), - &SystemClauseType::REPL(REPLCodePtr::LoadContextFile) => atom!("$prolog_lc_file"), - &SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) => atom!("$prolog_lc_dir"), - &SystemClauseType::REPL(REPLCodePtr::LoadContextModule) => atom!("$prolog_lc_module"), - &SystemClauseType::REPL(REPLCodePtr::LoadContextStream) => atom!("$prolog_lc_stream"), - &SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty) => { - atom!("$cpp_meta_predicate_property") - } - &SystemClauseType::REPL(REPLCodePtr::BuiltInProperty) => atom!("$cpp_built_in_property"), - &SystemClauseType::REPL(REPLCodePtr::DynamicProperty) => atom!("$cpp_dynamic_property"), - &SystemClauseType::REPL(REPLCodePtr::MultifileProperty) => atom!("$cpp_multifile_property"), - &SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty) => { - atom!("$cpp_discontiguous_property") - } - &SystemClauseType::REPL(REPLCodePtr::AbolishClause) => atom!("$abolish_clause"), - &SystemClauseType::REPL(REPLCodePtr::IsConsistentWithTermQueue) => { - atom!("$is_consistent_with_term_queue") - } - &SystemClauseType::REPL(REPLCodePtr::FlushTermQueue) => atom!("$flush_term_queue"), - &SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports) => atom!("$remove_module_exports"), - &SystemClauseType::REPL(REPLCodePtr::AddNonCountedBacktracking) => { - atom!("$add_non_counted_backtracking") - } - &SystemClauseType::Close => atom!("$close"), - &SystemClauseType::CopyToLiftedHeap => atom!("$copy_to_lh"), - &SystemClauseType::DeleteAttribute => atom!("$del_attr_non_head"), - &SystemClauseType::DeleteHeadAttribute => atom!("$del_attr_head"), - &SystemClauseType::DynamicModuleResolution(_) => atom!("$module_call"), - &SystemClauseType::EnqueueAttributedVar => atom!("$enqueue_attr_var"), - &SystemClauseType::FetchGlobalVar => atom!("$fetch_global_var"), - &SystemClauseType::FirstStream => atom!("$first_stream"), - &SystemClauseType::FlushOutput => atom!("$flush_output"), - &SystemClauseType::GetByte => atom!("$get_byte"), - &SystemClauseType::GetChar => atom!("$get_char"), - &SystemClauseType::GetNChars => atom!("$get_n_chars"), - &SystemClauseType::GetCode => atom!("$get_code"), - &SystemClauseType::GetSingleChar => atom!("$get_single_char"), - &SystemClauseType::ResetAttrVarState => atom!("$reset_attr_var_state"), - &SystemClauseType::TruncateIfNoLiftedHeapGrowth => atom!("$truncate_if_no_lh_growth"), - &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => atom!("$truncate_if_no_lh_growth_diff"), - &SystemClauseType::GetAttributedVariableList => atom!("$get_attr_list"), - &SystemClauseType::GetAttrVarQueueDelimiter => atom!("$get_attr_var_queue_delim"), - &SystemClauseType::GetAttrVarQueueBeyond => atom!("$get_attr_var_queue_beyond"), - &SystemClauseType::GetContinuationChunk => atom!("$get_cont_chunk"), - &SystemClauseType::GetLiftedHeapFromOffset => atom!("$get_lh_from_offset"), - &SystemClauseType::GetLiftedHeapFromOffsetDiff => atom!("$get_lh_from_offset_diff"), - &SystemClauseType::GetBValue => atom!("$get_b_value"), - &SystemClauseType::GetNextDBRef => atom!("$get_next_db_ref"), - &SystemClauseType::GetNextOpDBRef => atom!("$get_next_op_db_ref"), - &SystemClauseType::GetDoubleQuotes => atom!("$get_double_quotes"), - &SystemClauseType::GetSCCCleaner => atom!("$get_scc_cleaner"), - &SystemClauseType::Halt => atom!("$halt"), - &SystemClauseType::HeadIsDynamic => atom!("$head_is_dynamic"), - &SystemClauseType::Open => atom!("$open"), - &SystemClauseType::OpDeclaration => atom!("$op"), - &SystemClauseType::InstallSCCCleaner => atom!("$install_scc_cleaner"), - &SystemClauseType::InstallInferenceCounter => atom!("$install_inference_counter"), - &SystemClauseType::IsPartialString => atom!("$is_partial_string"), - &SystemClauseType::PartialStringTail => atom!("$partial_string_tail"), - &SystemClauseType::PeekByte => atom!("$peek_byte"), - &SystemClauseType::PeekChar => atom!("$peek_char"), - &SystemClauseType::PeekCode => atom!("$peek_code"), - &SystemClauseType::LiftedHeapLength => atom!("$lh_length"), - &SystemClauseType::Maybe => atom!("maybe"), - &SystemClauseType::CpuNow => atom!("$cpu_now"), - &SystemClauseType::CurrentTime => atom!("$current_time"), - &SystemClauseType::ModuleExists => atom!("$module_exists"), - &SystemClauseType::NextStream => atom!("$next_stream"), - &SystemClauseType::NoSuchPredicate => atom!("$no_such_predicate"), - &SystemClauseType::NumberToChars => atom!("$number_to_chars"), - &SystemClauseType::NumberToCodes => atom!("$number_to_codes"), - &SystemClauseType::PointsToContinuationResetMarker => { - atom!("$points_to_cont_reset_marker") - } - &SystemClauseType::PutByte => { - atom!("$put_byte") - } - &SystemClauseType::PutChar => { - atom!("$put_char") - } - &SystemClauseType::PutChars => { - atom!("$put_chars") - } - &SystemClauseType::PutCode => { - atom!("$put_code") - } - &SystemClauseType::QuotedToken => { - atom!("$quoted_token") - } - &SystemClauseType::RedoAttrVarBinding => atom!("$redo_attr_var_binding"), - &SystemClauseType::RemoveCallPolicyCheck => atom!("$remove_call_policy_check"), - &SystemClauseType::RemoveInferenceCounter => atom!("$remove_inference_counter"), - &SystemClauseType::RestoreCutPolicy => atom!("$restore_cut_policy"), - &SystemClauseType::SetCutPoint(_) => atom!("$set_cp"), - &SystemClauseType::SetInput => atom!("$set_input"), - &SystemClauseType::SetOutput => atom!("$set_output"), - &SystemClauseType::SetSeed => atom!("$set_seed"), - &SystemClauseType::StreamProperty => atom!("$stream_property"), - &SystemClauseType::SetStreamPosition => atom!("$set_stream_position"), - &SystemClauseType::SetStreamOptions => atom!("$set_stream_options"), - &SystemClauseType::StoreBacktrackableGlobalVar => { - atom!("$store_back_trackable_global_var") - } - &SystemClauseType::StoreGlobalVar => atom!("$store_global_var"), - &SystemClauseType::InferenceLevel => atom!("$inference_level"), - &SystemClauseType::CleanUpBlock => atom!("$clean_up_block"), - &SystemClauseType::EraseBall => atom!("$erase_ball"), - &SystemClauseType::Fail => atom!("$fail"), - &SystemClauseType::GetBall => atom!("$get_ball"), - &SystemClauseType::GetCutPoint => atom!("$get_cp"), - &SystemClauseType::GetStaggeredCutPoint => atom!("$get_staggered_cp"), - &SystemClauseType::GetCurrentBlock => atom!("$get_current_block"), - &SystemClauseType::InstallNewBlock => atom!("$install_new_block"), - &SystemClauseType::NextEP => atom!("$nextEP"), - &SystemClauseType::ReadQueryTerm => atom!("$read_query_term"), - &SystemClauseType::ReadTerm => atom!("$read_term"), - &SystemClauseType::ReadTermFromChars => atom!("$read_term_from_chars"), - &SystemClauseType::ResetBlock => atom!("$reset_block"), - &SystemClauseType::ResetContinuationMarker => atom!("$reset_cont_marker"), - &SystemClauseType::ReturnFromVerifyAttr => atom!("$return_from_verify_attr"), - &SystemClauseType::SetBall => atom!("$set_ball"), - &SystemClauseType::SetCutPointByDefault(_) => atom!("$set_cp_by_default"), - &SystemClauseType::SetDoubleQuotes => atom!("$set_double_quotes"), - &SystemClauseType::SkipMaxList => atom!("$skip_max_list"), - &SystemClauseType::Sleep => atom!("$sleep"), - &SystemClauseType::SocketClientOpen => atom!("$socket_client_open"), - &SystemClauseType::SocketServerOpen => atom!("$socket_server_open"), - &SystemClauseType::SocketServerAccept => atom!("$socket_server_accept"), - &SystemClauseType::SocketServerClose => atom!("$socket_server_close"), - &SystemClauseType::TLSAcceptClient => atom!("$tls_accept_client"), - &SystemClauseType::TLSClientConnect => atom!("$tls_client_connect"), - &SystemClauseType::Succeed => atom!("$succeed"), - &SystemClauseType::TermAttributedVariables => { - atom!("$term_attributed_variables") - } - &SystemClauseType::TermVariables => atom!("$term_variables"), - &SystemClauseType::TermVariablesUnderMaxDepth => atom!("$term_variables_under_max_depth"), - &SystemClauseType::TruncateLiftedHeapTo => atom!("$truncate_lh_to"), - &SystemClauseType::UnifyWithOccursCheck => atom!("$unify_with_occurs_check"), - &SystemClauseType::UnwindEnvironments => atom!("$unwind_environments"), - &SystemClauseType::UnwindStack => atom!("$unwind_stack"), - &SystemClauseType::WAMInstructions => atom!("$wam_instructions"), - &SystemClauseType::WriteTerm => atom!("$write_term"), - &SystemClauseType::WriteTermToChars => atom!("$write_term_to_chars"), - &SystemClauseType::ScryerPrologVersion => atom!("$scryer_prolog_version"), - &SystemClauseType::CryptoRandomByte => atom!("$crypto_random_byte"), - &SystemClauseType::CryptoDataHash => atom!("$crypto_data_hash"), - &SystemClauseType::CryptoDataHKDF => atom!("$crypto_data_hkdf"), - &SystemClauseType::CryptoPasswordHash => atom!("$crypto_password_hash"), - &SystemClauseType::CryptoDataEncrypt => atom!("$crypto_data_encrypt"), - &SystemClauseType::CryptoDataDecrypt => atom!("$crypto_data_decrypt"), - &SystemClauseType::CryptoCurveScalarMult => atom!("$crypto_curve_scalar_mult"), - &SystemClauseType::Ed25519Sign => atom!("$ed25519_sign"), - &SystemClauseType::Ed25519Verify => atom!("$ed25519_verify"), - &SystemClauseType::Ed25519NewKeyPair => atom!("$ed25519_new_keypair"), - &SystemClauseType::Ed25519KeyPairPublicKey => { - atom!("$ed25519_keypair_public_key") - } - &SystemClauseType::Curve25519ScalarMult => atom!("$curve25519_scalar_mult"), - &SystemClauseType::FirstNonOctet => atom!("$first_non_octet"), - &SystemClauseType::LoadHTML => atom!("$load_html"), - &SystemClauseType::LoadXML => atom!("$load_xml"), - &SystemClauseType::GetEnv => atom!("$getenv"), - &SystemClauseType::SetEnv => atom!("$setenv"), - &SystemClauseType::UnsetEnv => atom!("$unsetenv"), - &SystemClauseType::Shell => atom!("$shell"), - &SystemClauseType::PID => atom!("$pid"), - &SystemClauseType::CharsBase64 => atom!("$chars_base64"), - &SystemClauseType::LoadLibraryAsStream => atom!("$load_library_as_stream"), - &SystemClauseType::DevourWhitespace => atom!("$devour_whitespace"), - &SystemClauseType::IsSTOEnabled => atom!("$is_sto_enabled"), - &SystemClauseType::SetSTOAsUnify => atom!("$set_sto_as_unify"), - &SystemClauseType::SetNSTOAsUnify => atom!("$set_nsto_as_unify"), - &SystemClauseType::HomeDirectory => atom!("$home_directory"), - &SystemClauseType::SetSTOWithErrorAsUnify => { - atom!("$set_sto_with_error_as_unify") - } - &SystemClauseType::DebugHook => atom!("$debug_hook"), - &SystemClauseType::PopCount => atom!("$popcount"), - } - } - - pub(crate) fn from(name: Atom, arity: usize) -> Option { - match (name, arity) { - (atom!("$abolish_clause"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)), - (atom!("$add_dynamic_predicate"), 4) => { - Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate)) - } - (atom!("$add_multifile_predicate"), 4) => { - Some(SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate)) - } - (atom!("$add_discontiguous_predicate"), 4) => Some(SystemClauseType::REPL( - REPLCodePtr::AddDiscontiguousPredicate, - )), - (atom!("$add_goal_expansion_clause"), 3) => { - Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause)) - } - (atom!("$add_term_expansion_clause"), 2) => { - Some(SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause)) - } - (atom!("$atom_chars"), 2) => Some(SystemClauseType::AtomChars), - (atom!("$atom_codes"), 2) => Some(SystemClauseType::AtomCodes), - (atom!("$atom_length"), 2) => Some(SystemClauseType::AtomLength), - (atom!("$bind_from_register"), 2) => Some(SystemClauseType::BindFromRegister), - (atom!("$call_continuation"), 1) => Some(SystemClauseType::CallContinuation), - (atom!("$char_code"), 2) => Some(SystemClauseType::CharCode), - (atom!("$char_type"), 2) => Some(SystemClauseType::CharType), - (atom!("$chars_to_number"), 2) => Some(SystemClauseType::CharsToNumber), - (atom!("$codes_to_number"), 2) => Some(SystemClauseType::CodesToNumber), - (atom!("$copy_term_without_attr_vars"), 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), - (atom!("$create_partial_string"), 3) => Some(SystemClauseType::CreatePartialString), - (atom!("$check_cp"), 1) => Some(SystemClauseType::CheckCutPoint), - (atom!("$copy_to_lh"), 2) => Some(SystemClauseType::CopyToLiftedHeap), - (atom!("$close"), 2) => Some(SystemClauseType::Close), - (atom!("$current_hostname"), 1) => Some(SystemClauseType::CurrentHostname), - (atom!("$current_input"), 1) => Some(SystemClauseType::CurrentInput), - (atom!("$current_output"), 1) => Some(SystemClauseType::CurrentOutput), - (atom!("$first_stream"), 1) => Some(SystemClauseType::FirstStream), - (atom!("$next_stream"), 2) => Some(SystemClauseType::NextStream), - (atom!("$flush_output"), 1) => Some(SystemClauseType::FlushOutput), - (atom!("$del_attr_non_head"), 1) => Some(SystemClauseType::DeleteAttribute), - (atom!("$del_attr_head"), 1) => Some(SystemClauseType::DeleteHeadAttribute), - (atom!("$get_next_db_ref"), 4) => Some(SystemClauseType::GetNextDBRef), - (atom!("$get_next_op_db_ref"), 7) => Some(SystemClauseType::GetNextOpDBRef), - (atom!("$module_call"), _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)), - (atom!("$enqueue_attr_var"), 1) => Some(SystemClauseType::EnqueueAttributedVar), - (atom!("$partial_string_tail"), 2) => Some(SystemClauseType::PartialStringTail), - (atom!("$peek_byte"), 2) => Some(SystemClauseType::PeekByte), - (atom!("$peek_char"), 2) => Some(SystemClauseType::PeekChar), - (atom!("$peek_code"), 2) => Some(SystemClauseType::PeekCode), - (atom!("$is_partial_string"), 1) => Some(SystemClauseType::IsPartialString), - (atom!("$fetch_global_var"), 2) => Some(SystemClauseType::FetchGlobalVar), - (atom!("$get_byte"), 2) => Some(SystemClauseType::GetByte), - (atom!("$get_char"), 2) => Some(SystemClauseType::GetChar), - (atom!("$get_n_chars"), 3) => Some(SystemClauseType::GetNChars), - (atom!("$get_code"), 2) => Some(SystemClauseType::GetCode), - (atom!("$get_single_char"), 1) => Some(SystemClauseType::GetSingleChar), - (atom!("$points_to_cont_reset_marker"), 1) => { - Some(SystemClauseType::PointsToContinuationResetMarker) - } - (atom!("$put_byte"), 2) => Some(SystemClauseType::PutByte), - (atom!("$put_char"), 2) => Some(SystemClauseType::PutChar), - (atom!("$put_chars"), 2) => Some(SystemClauseType::PutChars), - (atom!("$put_code"), 2) => Some(SystemClauseType::PutCode), - (atom!("$reset_attr_var_state"), 0) => Some(SystemClauseType::ResetAttrVarState), - (atom!("$truncate_if_no_lh_growth"), 1) => { - Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth) - } - (atom!("$truncate_if_no_lh_growth_diff"), 2) => { - Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff) - } - (atom!("$get_attr_list"), 2) => Some(SystemClauseType::GetAttributedVariableList), - (atom!("$get_b_value"), 1) => Some(SystemClauseType::GetBValue), - (atom!("$get_lh_from_offset"), 2) => Some(SystemClauseType::GetLiftedHeapFromOffset), - (atom!("$get_lh_from_offset_diff"), 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff), - (atom!("$get_double_quotes"), 1) => Some(SystemClauseType::GetDoubleQuotes), - (atom!("$get_scc_cleaner"), 1) => Some(SystemClauseType::GetSCCCleaner), - (atom!("$halt"), 1) => Some(SystemClauseType::Halt), - (atom!("$head_is_dynamic"), 2) => Some(SystemClauseType::HeadIsDynamic), - (atom!("$install_scc_cleaner"), 2) => Some(SystemClauseType::InstallSCCCleaner), - (atom!("$install_inference_counter"), 3) => Some(SystemClauseType::InstallInferenceCounter), - (atom!("$lh_length"), 1) => Some(SystemClauseType::LiftedHeapLength), - (atom!("$maybe"), 0) => Some(SystemClauseType::Maybe), - (atom!("$cpu_now"), 1) => Some(SystemClauseType::CpuNow), - (atom!("$current_time"), 1) => Some(SystemClauseType::CurrentTime), - (atom!("$module_exists"), 1) => Some(SystemClauseType::ModuleExists), - (atom!("$no_such_predicate"), 2) => Some(SystemClauseType::NoSuchPredicate), - (atom!("$number_to_chars"), 2) => Some(SystemClauseType::NumberToChars), - (atom!("$number_to_codes"), 2) => Some(SystemClauseType::NumberToCodes), - (atom!("$op"), 3) => Some(SystemClauseType::OpDeclaration), - (atom!("$open"), 7) => Some(SystemClauseType::Open), - (atom!("$set_stream_options"), 5) => Some(SystemClauseType::SetStreamOptions), - (atom!("$redo_attr_var_binding"), 2) => Some(SystemClauseType::RedoAttrVarBinding), - (atom!("$remove_call_policy_check"), 1) => Some(SystemClauseType::RemoveCallPolicyCheck), - (atom!("$remove_inference_counter"), 2) => Some(SystemClauseType::RemoveInferenceCounter), - (atom!("$restore_cut_policy"), 0) => Some(SystemClauseType::RestoreCutPolicy), - (atom!("$set_cp"), 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))), - (atom!("$set_input"), 1) => Some(SystemClauseType::SetInput), - (atom!("$set_output"), 1) => Some(SystemClauseType::SetOutput), - (atom!("$stream_property"), 3) => Some(SystemClauseType::StreamProperty), - (atom!("$set_stream_position"), 2) => Some(SystemClauseType::SetStreamPosition), - (atom!("$inference_level"), 2) => Some(SystemClauseType::InferenceLevel), - (atom!("$clean_up_block"), 1) => Some(SystemClauseType::CleanUpBlock), - (atom!("$erase_ball"), 0) => Some(SystemClauseType::EraseBall), - (atom!("$fail"), 0) => Some(SystemClauseType::Fail), - (atom!("$get_attr_var_queue_beyond"), 2) => Some(SystemClauseType::GetAttrVarQueueBeyond), - (atom!("$get_attr_var_queue_delim"), 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter), - (atom!("$get_ball"), 1) => Some(SystemClauseType::GetBall), - (atom!("$get_cont_chunk"), 3) => Some(SystemClauseType::GetContinuationChunk), - (atom!("$get_current_block"), 1) => Some(SystemClauseType::GetCurrentBlock), - (atom!("$get_cp"), 1) => Some(SystemClauseType::GetCutPoint), - (atom!("$get_staggered_cp"), 1) => Some(SystemClauseType::GetStaggeredCutPoint), - (atom!("$install_new_block"), 1) => Some(SystemClauseType::InstallNewBlock), - (atom!("$quoted_token"), 1) => Some(SystemClauseType::QuotedToken), - (atom!("$nextEP"), 3) => Some(SystemClauseType::NextEP), - (atom!("$read_query_term"), 5) => Some(SystemClauseType::ReadQueryTerm), - (atom!("$read_term"), 5) => Some(SystemClauseType::ReadTerm), - (atom!("$read_term_from_chars"), 2) => Some(SystemClauseType::ReadTermFromChars), - (atom!("$reset_block"), 1) => Some(SystemClauseType::ResetBlock), - (atom!("$reset_cont_marker"), 0) => Some(SystemClauseType::ResetContinuationMarker), - (atom!("$return_from_verify_attr"), 0) => Some(SystemClauseType::ReturnFromVerifyAttr), - (atom!("$set_ball"), 1) => Some(SystemClauseType::SetBall), - (atom!("$set_cp_by_default"), 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))), - (atom!("$set_double_quotes"), 1) => Some(SystemClauseType::SetDoubleQuotes), - (atom!("$set_seed"), 1) => Some(SystemClauseType::SetSeed), - (atom!("$skip_max_list"), 4) => Some(SystemClauseType::SkipMaxList), - (atom!("$sleep"), 1) => Some(SystemClauseType::Sleep), - (atom!("$tls_accept_client"), 4) => Some(SystemClauseType::TLSAcceptClient), - (atom!("$tls_client_connect"), 3) => Some(SystemClauseType::TLSClientConnect), - (atom!("$socket_client_open"), 8) => Some(SystemClauseType::SocketClientOpen), - (atom!("$socket_server_open"), 3) => Some(SystemClauseType::SocketServerOpen), - (atom!("$socket_server_accept"), 7) => Some(SystemClauseType::SocketServerAccept), - (atom!("$socket_server_close"), 1) => Some(SystemClauseType::SocketServerClose), - (atom!("$store_global_var"), 2) => Some(SystemClauseType::StoreGlobalVar), - (atom!("$store_backtrackable_global_var"), 2) => { - Some(SystemClauseType::StoreBacktrackableGlobalVar) - } - (atom!("$term_attributed_variables"), 2) => Some(SystemClauseType::TermAttributedVariables), - (atom!("$term_variables"), 2) => Some(SystemClauseType::TermVariables), - (atom!("$term_variables_under_max_depth"), 3) => Some(SystemClauseType::TermVariablesUnderMaxDepth), - (atom!("$truncate_lh_to"), 1) => Some(SystemClauseType::TruncateLiftedHeapTo), - (atom!("$unwind_environments"), 0) => Some(SystemClauseType::UnwindEnvironments), - (atom!("$unwind_stack"), 0) => Some(SystemClauseType::UnwindStack), - (atom!("$unify_with_occurs_check"), 2) => Some(SystemClauseType::UnifyWithOccursCheck), - (atom!("$directory_files"), 2) => Some(SystemClauseType::DirectoryFiles), - (atom!("$file_size"), 2) => Some(SystemClauseType::FileSize), - (atom!("$file_exists"), 1) => Some(SystemClauseType::FileExists), - (atom!("$directory_exists"), 1) => Some(SystemClauseType::DirectoryExists), - (atom!("$directory_separator"), 1) => Some(SystemClauseType::DirectorySeparator), - (atom!("$make_directory"), 1) => Some(SystemClauseType::MakeDirectory), - (atom!("$make_directory_path"), 1) => Some(SystemClauseType::MakeDirectoryPath), - (atom!("$delete_file"), 1) => Some(SystemClauseType::DeleteFile), - (atom!("$rename_file"), 2) => Some(SystemClauseType::RenameFile), - (atom!("$delete_directory"), 1) => Some(SystemClauseType::DeleteDirectory), - (atom!("$working_directory"), 2) => Some(SystemClauseType::WorkingDirectory), - (atom!("$path_canonical"), 2) => Some(SystemClauseType::PathCanonical), - (atom!("$file_time"), 3) => Some(SystemClauseType::FileTime), - (atom!("$clause_to_evacuable"), 2) => { - Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable)) - } - (atom!("$scoped_clause_to_evacuable"), 3) => { - Some(SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable)) - } - (atom!("$conclude_load"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)), - (atom!("$use_module"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)), - (atom!("$declare_module"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)), - (atom!("$load_compiled_library"), 3) => { - Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary)) - } - (atom!("$push_load_state_payload"), 1) => { - Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload)) - } - (atom!("$add_in_situ_filename_module"), 1) => { - Some(SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule)) - } - (atom!("$asserta"), 5) => Some(SystemClauseType::REPL(REPLCodePtr::Asserta)), - (atom!("$assertz"), 5) => Some(SystemClauseType::REPL(REPLCodePtr::Assertz)), - (atom!("$retract_clause"), 4) => Some(SystemClauseType::REPL(REPLCodePtr::Retract)), - (atom!("$is_consistent_with_term_queue"), 4) => Some(SystemClauseType::REPL( - REPLCodePtr::IsConsistentWithTermQueue, - )), - (atom!("$flush_term_queue"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::FlushTermQueue)), - (atom!("$remove_module_exports"), 2) => { - Some(SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports)) - } - (atom!("$add_non_counted_backtracking"), 3) => Some(SystemClauseType::REPL( - REPLCodePtr::AddNonCountedBacktracking, - )), - (atom!("$wam_instructions"), 4) => Some(SystemClauseType::WAMInstructions), - (atom!("$write_term"), 7) => Some(SystemClauseType::WriteTerm), - (atom!("$write_term_to_chars"), 7) => Some(SystemClauseType::WriteTermToChars), - (atom!("$scryer_prolog_version"), 1) => Some(SystemClauseType::ScryerPrologVersion), - (atom!("$crypto_random_byte"), 1) => Some(SystemClauseType::CryptoRandomByte), - (atom!("$crypto_data_hash"), 4) => Some(SystemClauseType::CryptoDataHash), - (atom!("$crypto_data_hkdf"), 7) => Some(SystemClauseType::CryptoDataHKDF), - (atom!("$crypto_password_hash"), 4) => Some(SystemClauseType::CryptoPasswordHash), - (atom!("$crypto_data_encrypt"), 7) => Some(SystemClauseType::CryptoDataEncrypt), - (atom!("$crypto_data_decrypt"), 6) => Some(SystemClauseType::CryptoDataDecrypt), - (atom!("$crypto_curve_scalar_mult"), 5) => Some(SystemClauseType::CryptoCurveScalarMult), - (atom!("$ed25519_sign"), 4) => Some(SystemClauseType::Ed25519Sign), - (atom!("$ed25519_verify"), 4) => Some(SystemClauseType::Ed25519Verify), - (atom!("$ed25519_new_keypair"), 1) => Some(SystemClauseType::Ed25519NewKeyPair), - (atom!("$ed25519_keypair_public_key"), 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey), - (atom!("$curve25519_scalar_mult"), 3) => Some(SystemClauseType::Curve25519ScalarMult), - (atom!("$first_non_octet"), 2) => Some(SystemClauseType::FirstNonOctet), - (atom!("$load_html"), 3) => Some(SystemClauseType::LoadHTML), - (atom!("$load_xml"), 3) => Some(SystemClauseType::LoadXML), - (atom!("$getenv"), 2) => Some(SystemClauseType::GetEnv), - (atom!("$setenv"), 2) => Some(SystemClauseType::SetEnv), - (atom!("$unsetenv"), 1) => Some(SystemClauseType::UnsetEnv), - (atom!("$shell"), 2) => Some(SystemClauseType::Shell), - (atom!("$pid"), 1) => Some(SystemClauseType::PID), - (atom!("$chars_base64"), 4) => Some(SystemClauseType::CharsBase64), - (atom!("$load_library_as_stream"), 3) => Some(SystemClauseType::LoadLibraryAsStream), - (atom!("$push_load_context"), 2) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadContext)), - (atom!("$pop_load_state_payload"), 1) => { - Some(SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload)) - } - (atom!("$pop_load_context"), 0) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadContext)), - (atom!("$prolog_lc_source"), 1) => { - Some(SystemClauseType::REPL(REPLCodePtr::LoadContextSource)) - } - (atom!("$prolog_lc_file"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextFile)), - (atom!("$prolog_lc_dir"), 1) => { - Some(SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory)) - } - (atom!("$prolog_lc_module"), 1) => { - Some(SystemClauseType::REPL(REPLCodePtr::LoadContextModule)) - } - (atom!("$prolog_lc_stream"), 1) => { - Some(SystemClauseType::REPL(REPLCodePtr::LoadContextStream)) - } - (atom!("$cpp_meta_predicate_property"), 4) => { - Some(SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty)) - } - (atom!("$cpp_built_in_property"), 2) => { - Some(SystemClauseType::REPL(REPLCodePtr::BuiltInProperty)) - } - (atom!("$cpp_dynamic_property"), 3) => { - Some(SystemClauseType::REPL(REPLCodePtr::DynamicProperty)) - } - (atom!("$cpp_multifile_property"), 3) => { - Some(SystemClauseType::REPL(REPLCodePtr::MultifileProperty)) - } - (atom!("$cpp_discontiguous_property"), 3) => { - Some(SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty)) - } - (atom!("$devour_whitespace"), 1) => Some(SystemClauseType::DevourWhitespace), - (atom!("$is_sto_enabled"), 1) => Some(SystemClauseType::IsSTOEnabled), - (atom!("$set_sto_as_unify"), 0) => Some(SystemClauseType::SetSTOAsUnify), - (atom!("$set_nsto_as_unify"), 0) => Some(SystemClauseType::SetNSTOAsUnify), - (atom!("$set_sto_with_error_as_unify"), 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify), - (atom!("$home_directory"), 1) => Some(SystemClauseType::HomeDirectory), - (atom!("$debug_hook"), 0) => Some(SystemClauseType::DebugHook), - (atom!("$popcount"), 2) => Some(SystemClauseType::PopCount), - _ => None, - } - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum BuiltInClauseType { - AcyclicTerm, - Arg, - Compare, - CompareTerm(CompareTermQT), - CopyTerm, - Eq, - Functor, - Ground, - Is(RegType, ArithmeticTerm), - KeySort, - NotEq, - Read, - Sort, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ClauseType { - BuiltIn(BuiltInClauseType), - CallN, - Inlined(InlinedClauseType), - Named(Atom, usize, CodeIndex), // name, arity, index. - System(SystemClauseType), -} - -impl BuiltInClauseType { - pub(crate) fn name(&self) -> Atom { - match self { - &BuiltInClauseType::AcyclicTerm => atom!("acyclic_term"), - &BuiltInClauseType::Arg => atom!("arg"), - &BuiltInClauseType::Compare => atom!("compare"), - &BuiltInClauseType::CompareTerm(qt) => qt.name(), - &BuiltInClauseType::CopyTerm => atom!("copy_term"), - &BuiltInClauseType::Eq => atom!("=="), - &BuiltInClauseType::Functor => atom!("functor"), - &BuiltInClauseType::Ground => atom!("ground"), - &BuiltInClauseType::Is(..) => atom!("is"), - &BuiltInClauseType::KeySort => atom!("keysort"), - &BuiltInClauseType::NotEq => atom!("\\=="), - &BuiltInClauseType::Read => atom!("read"), - &BuiltInClauseType::Sort => atom!("sort"), - } - } - - pub(crate) fn arity(&self) -> usize { - match self { - &BuiltInClauseType::AcyclicTerm => 1, - &BuiltInClauseType::Arg => 3, - &BuiltInClauseType::Compare => 2, - &BuiltInClauseType::CompareTerm(_) => 2, - &BuiltInClauseType::CopyTerm => 2, - &BuiltInClauseType::Eq => 2, - &BuiltInClauseType::Functor => 3, - &BuiltInClauseType::Ground => 1, - &BuiltInClauseType::Is(..) => 2, - &BuiltInClauseType::KeySort => 2, - &BuiltInClauseType::NotEq => 2, - &BuiltInClauseType::Read => 1, - &BuiltInClauseType::Sort => 2, - } - } -} - -impl ClauseType { - pub(crate) fn name(&self) -> Atom { - match self { - &ClauseType::BuiltIn(ref built_in) => built_in.name(), - &ClauseType::CallN => atom!("$call"), - &ClauseType::Inlined(ref inlined) => inlined.name(), - &ClauseType::Named(name, ..) => name, - &ClauseType::System(ref system) => system.name(), - } - } - - pub(crate) fn from(name: Atom, arity: usize) -> Self { - clause_type_form(name, arity).unwrap_or_else(|| { - SystemClauseType::from(name, arity) - .map(ClauseType::System) - .unwrap_or_else(|| { - if name == atom!("$call") { - ClauseType::CallN - } else { - ClauseType::Named(name, arity, CodeIndex::default()) - } - }) - }) - } -} - -impl From for ClauseType { - fn from(inlined_ct: InlinedClauseType) -> Self { - ClauseType::Inlined(inlined_ct) - } -} diff --git a/src/codegen.rs b/src/codegen.rs index ca344558..a8094841 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -4,7 +4,6 @@ use crate::{perm_v, temp_v}; use crate::allocator::*; use crate::arithmetic::*; -use crate::clause_types::*; use crate::fixtures::*; use crate::forms::*; use crate::indexing::*; @@ -13,6 +12,7 @@ use crate::iterators::*; use crate::targets::*; use crate::types::*; +use crate::instr; use crate::machine::machine_errors::*; use indexmap::{IndexMap, IndexSet}; @@ -57,7 +57,9 @@ impl<'a> ConjunctInfo<'a> { let mut code_index = 0; for phase in 0.. { - while let Line::Query(ref query_instr) = &code[code_index] { + while code[code_index].is_query_instr() { + let query_instr = &mut code[code_index]; + if !unsafe_var_marker.mark_safe_vars(query_instr) { unsafe_var_marker.mark_phase(query_instr, phase); } @@ -75,7 +77,8 @@ impl<'a> ConjunctInfo<'a> { code_index = 0; for phase in 0.. { - while let Line::Query(ref mut query_instr) = &mut code[code_index] { + while code[code_index].is_query_instr() { + let query_instr = &mut code[code_index]; unsafe_var_marker.mark_unsafe_vars(query_instr, phase); code_index += 1; } @@ -103,9 +106,9 @@ impl CodeGenSettings { } #[inline] - pub(crate) fn internal_try_me_else(&self, offset: usize) -> ChoiceInstruction { + pub(crate) fn internal_try_me_else(&self, offset: usize) -> Instruction { if let Some(global_clock_time) = self.global_clock_tick { - ChoiceInstruction::DynamicInternalElse( + Instruction::DynamicInternalElse( global_clock_time, Death::Infinity, if offset == 0 { @@ -115,13 +118,13 @@ impl CodeGenSettings { }, ) } else { - ChoiceInstruction::TryMeElse(offset) + Instruction::TryMeElse(offset) } } - pub(crate) fn try_me_else(&self, offset: usize) -> ChoiceInstruction { + pub(crate) fn try_me_else(&self, offset: usize) -> Instruction { if let Some(global_clock_tick) = self.global_clock_tick { - ChoiceInstruction::DynamicElse( + Instruction::DynamicElse( global_clock_tick, Death::Infinity, if offset == 0 { @@ -131,13 +134,13 @@ impl CodeGenSettings { }, ) } else { - ChoiceInstruction::TryMeElse(offset) + Instruction::TryMeElse(offset) } } - pub(crate) fn internal_retry_me_else(&self, offset: usize) -> ChoiceInstruction { + pub(crate) fn internal_retry_me_else(&self, offset: usize) -> Instruction { if let Some(global_clock_tick) = self.global_clock_tick { - ChoiceInstruction::DynamicInternalElse( + Instruction::DynamicInternalElse( global_clock_tick, Death::Infinity, if offset == 0 { @@ -147,13 +150,13 @@ impl CodeGenSettings { }, ) } else { - ChoiceInstruction::RetryMeElse(offset) + Instruction::RetryMeElse(offset) } } - pub(crate) fn retry_me_else(&self, offset: usize) -> ChoiceInstruction { + pub(crate) fn retry_me_else(&self, offset: usize) -> Instruction { if let Some(global_clock_tick) = self.global_clock_tick { - ChoiceInstruction::DynamicElse( + Instruction::DynamicElse( global_clock_tick, Death::Infinity, if offset == 0 { @@ -163,33 +166,33 @@ impl CodeGenSettings { }, ) } else if self.non_counted_bt { - ChoiceInstruction::DefaultRetryMeElse(offset) + Instruction::DefaultRetryMeElse(offset) } else { - ChoiceInstruction::RetryMeElse(offset) + Instruction::RetryMeElse(offset) } } - pub(crate) fn internal_trust_me(&self) -> ChoiceInstruction { + pub(crate) fn internal_trust_me(&self) -> Instruction { if let Some(global_clock_tick) = self.global_clock_tick { - ChoiceInstruction::DynamicInternalElse( + Instruction::DynamicInternalElse( global_clock_tick, Death::Infinity, NextOrFail::Fail(0), ) } else if self.non_counted_bt { - ChoiceInstruction::DefaultTrustMe(0) + Instruction::DefaultTrustMe(0) } else { - ChoiceInstruction::TrustMe(0) + Instruction::TrustMe(0) } } - pub(crate) fn trust_me(&self) -> ChoiceInstruction { + pub(crate) fn trust_me(&self) -> Instruction { if let Some(global_clock_tick) = self.global_clock_tick { - ChoiceInstruction::DynamicElse(global_clock_tick, Death::Infinity, NextOrFail::Fail(0)) + Instruction::DynamicElse(global_clock_tick, Death::Infinity, NextOrFail::Fail(0)) } else if self.non_counted_bt { - ChoiceInstruction::DefaultTrustMe(0) + Instruction::DefaultTrustMe(0) } else { - ChoiceInstruction::TrustMe(0) + Instruction::TrustMe(0) } } } @@ -238,12 +241,11 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { vr: &'a Cell, code: &mut Code, ) -> RegType { - let mut target = Vec::new(); - self.marker - .mark_var(name, Level::Shallow, vr, term_loc, &mut target); + let mut target = Code::new(); + self.marker.mark_var::(name, Level::Shallow, vr, term_loc, &mut target); if !target.is_empty() { - code.extend(target.into_iter().map(Line::Query)); + code.extend(target.into_iter()); } vr.get().norm() @@ -271,7 +273,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } } - fn add_or_increment_void_instr(target: &mut Vec) + fn add_or_increment_void_instr(target: &mut Code) where Target: crate::targets::CompilationTarget<'a>, { @@ -291,13 +293,12 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { var: &'a Rc, term_loc: GenContext, is_exposed: bool, - target: &mut Vec, + target: &mut Code, ) { if is_exposed || self.get_var_count(var.as_ref()) > 1 { - self.marker - .mark_var(var.clone(), Level::Deep, cell, term_loc, target); + self.marker.mark_var::(var.clone(), Level::Deep, cell, term_loc, target); } else { - Self::add_or_increment_void_instr(target); + Self::add_or_increment_void_instr::(target); } } @@ -306,27 +307,26 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { subterm: &'a Term, term_loc: GenContext, is_exposed: bool, - target: &mut Vec, + target: &mut Code, ) { match subterm { &Term::AnonVar if is_exposed => { - self.marker.mark_anon_var(Level::Deep, term_loc, target); + self.marker.mark_anon_var::(Level::Deep, term_loc, target); } &Term::AnonVar => { - Self::add_or_increment_void_instr(target); + Self::add_or_increment_void_instr::(target); } &Term::Cons(ref cell, ..) | &Term::Clause(ref cell, ..) | Term::PartialString(ref cell, ..) => { - self.marker - .mark_non_var(Level::Deep, term_loc, cell, target); + self.marker.mark_non_var::(Level::Deep, term_loc, cell, target); target.push(Target::clause_arg_to_instr(cell.get())); } &Term::Literal(_, ref constant) => { target.push(Target::constant_subterm(constant.clone())); } &Term::Var(ref cell, ref var) => { - self.deep_var_instr(cell, var, term_loc, is_exposed, target); + self.deep_var_instr::(cell, var, term_loc, is_exposed, target); } }; } @@ -336,12 +336,12 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { iter: Iter, term_loc: GenContext, is_exposed: bool, - ) -> Vec + ) -> Code where Target: crate::targets::CompilationTarget<'a>, Iter: Iterator>, { - let mut target = Vec::new(); + let mut target: Code = Vec::new(); for term in iter { match term { @@ -349,38 +349,38 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { if let GenContext::Head = term_loc { self.marker.advance_arg(); } else { - self.marker.mark_anon_var(lvl, term_loc, &mut target); + self.marker.mark_anon_var::(lvl, term_loc, &mut target); } } TermRef::Clause(lvl, cell, ct, terms) => { - self.marker.mark_non_var(lvl, term_loc, cell, &mut target); - target.push(Target::to_structure(ct, terms.len(), cell.get())); + self.marker.mark_non_var::(lvl, term_loc, cell, &mut target); + target.push(Target::to_structure(ct.name(), terms.len(), cell.get())); for subterm in terms { - self.subterm_to_instr(subterm, term_loc, is_exposed, &mut target); + self.subterm_to_instr::(subterm, term_loc, is_exposed, &mut target); } } TermRef::Cons(lvl, cell, head, tail) => { - self.marker.mark_non_var(lvl, term_loc, cell, &mut target); + self.marker.mark_non_var::(lvl, term_loc, cell, &mut target); target.push(Target::to_list(lvl, cell.get())); - self.subterm_to_instr(head, term_loc, is_exposed, &mut target); - self.subterm_to_instr(tail, term_loc, is_exposed, &mut target); + self.subterm_to_instr::(head, term_loc, is_exposed, &mut target); + self.subterm_to_instr::(tail, term_loc, is_exposed, &mut target); } TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => { - self.marker.mark_non_var(lvl, term_loc, cell, &mut target); + self.marker.mark_non_var::(lvl, term_loc, cell, &mut target); target.push(Target::to_pstr(lvl, *string, cell.get(), false)); } TermRef::Literal(lvl @ Level::Shallow, cell, constant) => { - self.marker.mark_non_var(lvl, term_loc, cell, &mut target); + self.marker.mark_non_var::(lvl, term_loc, cell, &mut target); target.push(Target::to_constant(lvl, *constant, cell.get())); } TermRef::PartialString(lvl, cell, string, tail) => { - self.marker.mark_non_var(lvl, term_loc, cell, &mut target); + self.marker.mark_non_var::(lvl, term_loc, cell, &mut target); if let Some(tail) = tail { target.push(Target::to_pstr(lvl, string, cell.get(), true)); - self.subterm_to_instr(tail, term_loc, is_exposed, &mut target); + self.subterm_to_instr::(tail, term_loc, is_exposed, &mut target); } else { target.push(Target::to_pstr(lvl, string, cell.get(), false)); } @@ -388,7 +388,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => { if self.marker.is_unbound(var.clone()) { if term_loc != GenContext::Head { - self.marker.mark_reserved_var( + self.marker.mark_reserved_var::( var.clone(), lvl, cell, @@ -401,12 +401,10 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } } - self.marker - .mark_var(var.clone(), lvl, cell, term_loc, &mut target); + self.marker.mark_var::(var.clone(), lvl, cell, term_loc, &mut target); } TermRef::Var(lvl @ Level::Shallow, cell, var) => { - self.marker - .mark_var(var.clone(), lvl, cell, term_loc, &mut target); + self.marker.mark_var::(var.clone(), lvl, cell, term_loc, &mut target); } _ => {} }; @@ -451,13 +449,13 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { match qt { &QueryTerm::Jump(ref vars) => { self.jmp_by_locs.push(code.len()); - code.push(jmp_call!(vars.len(), 0, pvs)); + code.push(instr!("jmp_by_call", vars.len(), 0, pvs)); } - &QueryTerm::Clause(_, ref ct, ref terms, true) => { - code.push(call_clause_by_default!(ct.clone(), terms.len(), pvs)); + &QueryTerm::Clause(_, ref ct, _, true) => { + code.push(call_clause_by_default!(ct.clone(), pvs)); } - &QueryTerm::Clause(_, ref ct, ref terms, false) => { - code.push(call_clause!(ct.clone(), terms.len(), pvs)); + &QueryTerm::Clause(_, ref ct, _, false) => { + code.push(call_clause!(ct.clone(), pvs)); } _ => {} } @@ -465,25 +463,29 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { fn lco(code: &mut Code) -> usize { let mut dealloc_index = code.len() - 1; + let last_instr = code.pop(); - match code.last_mut() { - Some(&mut Line::Control(ref mut ctrl)) => match ctrl { - &mut ControlInstruction::CallClause(_, _, _, ref mut last_call, _) => { - *last_call = true; - } - &mut ControlInstruction::JmpBy(_, _, _, ref mut last_call) => { - *last_call = true; - } - &mut ControlInstruction::Proceed => {} - _ => { - dealloc_index += 1; - } - }, - Some(&mut Line::Cut(CutInstruction::Cut(_))) => { + match last_instr { + Some(instr @ Instruction::Proceed) => { + code.push(instr); + } + Some(instr @ Instruction::Cut(_)) => { dealloc_index += 1; + code.push(instr); } - _ => {} - }; + Some(mut instr) if instr.is_ctrl_instr() => { + code.push(if instr.perm_vars_mut().is_some() { + instr.to_execute() + } else { + dealloc_index += 1; + instr + }); + } + Some(instr) => { + code.push(instr); + } + None => {} + } dealloc_index } @@ -496,7 +498,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { code: &mut Code, ) -> Result<(), CompilationError> { match ct { - &InlinedClauseType::CompareNumber(cmp, ..) => { + &InlinedClauseType::CompareNumber(mut cmp) => { self.marker.reset_arg(2); let (mut lcode, at_1) = self.call_arith_eval(&terms[0], 1)?; @@ -523,71 +525,71 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { &Term::Literal(_, Literal::Char(_)) | &Term::Literal(_, Literal::Atom(atom!("[]"))) | &Term::Literal(_, Literal::Atom(..)) => { - code.push(succeed!()); + code.push(instr!("$succeed", 0)); } &Term::Var(ref vr, ref name) => { self.marker.reset_arg(1); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); - code.push(is_atom!(r)); + code.push(instr!("atom", r, 0)); } _ => { - code.push(fail!()); + code.push(instr!("$fail", 0)); } }, &InlinedClauseType::IsAtomic(..) => match &terms[0] { &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) => { - code.push(fail!()); + code.push(instr!("$fail", 0)); } &Term::Literal(_, Literal::String(_)) => { - code.push(fail!()); + code.push(instr!("$fail", 0)); } &Term::Literal(..) => { - code.push(succeed!()); + code.push(instr!("$succeed", 0)); } &Term::Var(ref vr, ref name) => { self.marker.reset_arg(1); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); - code.push(is_atomic!(r)); + code.push(instr!("atomic", r, 0)); } }, &InlinedClauseType::IsCompound(..) => match &terms[0] { &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) | &Term::Literal(_, Literal::String(..)) => { - code.push(succeed!()); + code.push(instr!("$succeed", 0)); } &Term::Var(ref vr, ref name) => { self.marker.reset_arg(1); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); - code.push(is_compound!(r)); + code.push(instr!("compound", r, 0)); } _ => { - code.push(fail!()); + code.push(instr!("$fail", 0)); } }, &InlinedClauseType::IsRational(..) => match &terms[0] { &Term::Literal(_, Literal::Rational(_)) => { - code.push(succeed!()); + code.push(instr!("$succeed", 0)); } &Term::Var(ref vr, ref name) => { self.marker.reset_arg(1); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); - code.push(is_rational!(r)); + code.push(instr!("rational", r, 0)); } _ => { - code.push(fail!()); + code.push(instr!("$fail", 0)); } }, &InlinedClauseType::IsFloat(..) => match &terms[0] { &Term::Literal(_, Literal::Float(_)) => { - code.push(succeed!()); + code.push(instr!("$succeed", 0)); } &Term::Var(ref vr, ref name) => { self.marker.reset_arg(1); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); - code.push(is_float!(r)); + code.push(instr!("float", r, 0)); } _ => { - code.push(fail!()); + code.push(instr!("$fail", 0)); } }, &InlinedClauseType::IsNumber(..) => match &terms[0] { @@ -595,41 +597,41 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { | &Term::Literal(_, Literal::Rational(_)) | &Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => { - code.push(succeed!()); + code.push(instr!("$succeed", 0)); } &Term::Var(ref vr, ref name) => { self.marker.reset_arg(1); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); - code.push(is_number!(r)); + code.push(instr!("number", r, 0)); } _ => { - code.push(fail!()); + code.push(instr!("$fail", 0)); } }, &InlinedClauseType::IsNonVar(..) => match &terms[0] { &Term::AnonVar => { - code.push(fail!()); + code.push(instr!("$fail", 0)); } &Term::Var(ref vr, ref name) => { self.marker.reset_arg(1); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); - code.push(is_nonvar!(r)); + code.push(instr!("nonvar", r, 0)); } _ => { - code.push(succeed!()); + code.push(instr!("$succeed", 0)); } }, &InlinedClauseType::IsInteger(..) => match &terms[0] { &Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => { - code.push(succeed!()); + code.push(instr!("$succeed", 0)); } &Term::Var(ref vr, ref name) => { self.marker.reset_arg(1); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); - code.push(is_integer!(r)); + code.push(instr!("integer", r, 0)); } _ => { - code.push(fail!()); + code.push(instr!("$fail", 0)); } }, &InlinedClauseType::IsVar(..) => match &terms[0] { @@ -637,15 +639,15 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { | &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) => { - code.push(fail!()); + code.push(instr!("$fail", 0)); } &Term::AnonVar => { - code.push(succeed!()); + code.push(instr!("$succeed", 0)); } &Term::Var(ref vr, ref name) => { self.marker.reset_arg(1); let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code); - code.push(is_var!(r)); + code.push(instr!("var", r, 0)); } }, } @@ -678,34 +680,39 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { &Term::Var(ref vr, ref name) => { let mut target = vec![]; - self.marker - .mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target); + self.marker.mark_var::( + name.clone(), + Level::Shallow, + vr, + term_loc, + &mut target, + ); if !target.is_empty() { - code.extend(target.into_iter().map(Line::Query)); + code.extend(target.into_iter()); } } &Term::Literal(_, c @ Literal::Integer(_)) | &Term::Literal(_, c @ Literal::Fixnum(_)) => { let v = HeapCellValue::from(c); - code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1)))); + code.push(instr!("put_constant", Level::Shallow, v, temp_v!(1))); self.marker.advance_arg(); } &Term::Literal(_, c @ Literal::Float(_)) => { let v = HeapCellValue::from(c); - code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1)))); + code.push(instr!("put_constant", Level::Shallow, v, temp_v!(1))); self.marker.advance_arg(); } &Term::Literal(_, c @ Literal::Rational(_)) => { let v = HeapCellValue::from(c); - code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1)))); + code.push(instr!("put_constant", Level::Shallow, v, temp_v!(1))); self.marker.advance_arg(); } _ => { - code.push(fail!()); + code.push(instr!("$fail", 0)); return Ok(()); } } @@ -717,9 +724,9 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { }; Ok(if use_default_call_policy { - code.push(is_call_by_default!(temp_v!(1), at)); + code.push(instr!("is", default, temp_v!(1), at, 0)); } else { - code.push(is_call!(temp_v!(1), at)); + code.push(instr!("is", temp_v!(1), at, 0)); }) } @@ -727,7 +734,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { fn compile_unblocked_cut(&mut self, code: &mut Code, cell: &'a Cell) { let r = self.marker.get(Rc::new(String::from("!"))); cell.set(VarReg::Norm(r)); - code.push(set_cp!(cell.get().norm())); + code.push(instr!("$set_cp", cell.get().norm(), 0)); } fn compile_get_level_and_unify( @@ -737,21 +744,16 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { var: Rc, term_loc: GenContext, ) { - let mut target = Vec::new(); + let mut target = Code::new(); self.marker.reset_arg(1); - self.marker - .mark_var(var, Level::Shallow, cell, term_loc, &mut target); + self.marker.mark_var::(var, Level::Shallow, cell, term_loc, &mut target); if !target.is_empty() { - code.extend( - target - .into_iter() - .map(|query_instr| Line::Query(query_instr)), - ); + code.extend(target.into_iter()); } - code.push(get_level_and_unify!(cell.get().norm())); + code.push(instr!("get_level_and_unify", cell.get().norm())); } fn compile_seq( @@ -775,9 +777,9 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } &QueryTerm::UnblockedCut(ref cell) => self.compile_unblocked_cut(code, cell), &QueryTerm::BlockedCut => code.push(if chunk_num == 0 { - Line::Cut(CutInstruction::NeckCut) + Instruction::NeckCut } else { - Line::Cut(CutInstruction::Cut(perm_v!(1))) + Instruction::Cut(perm_v!(1)) }), &QueryTerm::Clause( _, @@ -810,10 +812,10 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { if conjunct_info.allocates() { let perm_vars = conjunct_info.perm_vars(); - body.push(Line::Control(ControlInstruction::Allocate(perm_vars))); + body.push(Instruction::Allocate(perm_vars)); if conjunct_info.has_deep_cut { - body.push(Line::Cut(CutInstruction::GetLevel(perm_v!(1)))); + body.push(Instruction::GetLevel(perm_v!(1))); } } } @@ -826,8 +828,9 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { ) { // add a proceed to bookend any trailing cuts. match toc { - &QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => code.push(proceed!()), - &QueryTerm::Clause(_, ClauseType::Inlined(..), ..) => code.push(proceed!()), + &QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => { + code.push(instr!("proceed")); + } _ => {} }; @@ -843,7 +846,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } } - code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate)); + code.insert(dealloc_index, instr!("deallocate")); } } @@ -865,16 +868,13 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { self.compile_seq_prelude(&conjunct_info, &mut code); let iter = FactIterator::from_rule_head_clause(args); - let mut fact = self.compile_target(iter, GenContext::Head, false); + let mut fact = self.compile_target::(iter, GenContext::Head, false); let mut unsafe_var_marker = UnsafeVarMarker::new(); if !fact.is_empty() { unsafe_var_marker = self.mark_unsafe_fact_vars(&mut fact); - - for fact_instr in fact { - code.push(Line::Fact(fact_instr)); - } + code.extend(fact.into_iter()); } let iter = ChunkedIterator::from_rule_body(p1, clauses); @@ -886,18 +886,18 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { Ok(code) } - fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker { + fn mark_unsafe_fact_vars(&self, fact: &mut Code) -> UnsafeVarMarker { let mut safe_vars = IndexSet::new(); for fact_instr in fact.iter_mut() { match fact_instr { - &mut FactInstruction::UnifyValue(r) => { + &mut Instruction::UnifyValue(r) => { if !safe_vars.contains(&r) { - *fact_instr = FactInstruction::UnifyLocalValue(r); + *fact_instr = Instruction::UnifyLocalValue(r); safe_vars.insert(r); } } - &mut FactInstruction::UnifyVariable(r) => { + &mut Instruction::UnifyVariable(r) => { safe_vars.insert(r); } _ => {} @@ -923,18 +923,20 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { self.marker.reset_at_head(args); let iter = FactInstruction::iter(term); - let mut compiled_fact = self.compile_target(iter, GenContext::Head, false); + let mut compiled_fact = self.compile_target::( + iter, + GenContext::Head, + false, + ); self.mark_unsafe_fact_vars(&mut compiled_fact); if !compiled_fact.is_empty() { - for fact_instr in compiled_fact { - code.push(Line::Fact(fact_instr)); - } + code.extend(compiled_fact.into_iter()); } } - code.push(proceed!()); + code.push(instr!("proceed")); code } @@ -949,12 +951,10 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { self.marker.reset_arg(term.arity()); let iter = query_term_post_order_iter(term); - let query = self.compile_target(iter, term_loc, is_exposed); + let query = self.compile_target::(iter, term_loc, is_exposed); if !query.is_empty() { - for query_instr in query { - code.push(Line::Query(query_instr)); - } + code.extend(query.into_iter()); } self.add_conditional_call(code, term, num_perm_vars_left); @@ -1061,12 +1061,12 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { if clauses.len() > 1 { let choice = match i { 0 => self.settings.internal_try_me_else(clause_code.len() + 1), - //ChoiceInstruction::TryMeElse(clause_code.len() + 1), + //Instruction::TryMeElse(clause_code.len() + 1), _ if i == clauses.len() - 1 => self.settings.internal_trust_me(), _ => self.settings.internal_retry_me_else(clause_code.len() + 1), }; - code.push_back(Line::Choice(choice)); + code.push_back(choice); } else if self.settings.is_extensible { /* generate stub choice instructions for extensible @@ -1079,9 +1079,8 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { over them. */ - code.push_front(Line::Choice(self.settings.internal_try_me_else(0))); - //Line::Choice(ChoiceInstruction::TryMeElse(0))); - skip_stub_try_me_else = !self.settings.is_dynamic(); //true; + code.push_front(self.settings.internal_try_me_else(0)); + skip_stub_try_me_else = !self.settings.is_dynamic(); } let arg = match clause.args() { @@ -1109,7 +1108,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { self.global_jmp_by_locs_offset = jmp_by_locs_len; if !index_code.is_empty() { - code.push_front(Line::IndexingCode(index_code)); + code.push_front(Instruction::IndexingCode(index_code)); if skip_stub_try_me_else { // skip the TryMeElse(0) also. @@ -1160,13 +1159,13 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { _ => self.settings.retry_me_else(code_segment.len() + 1), }; - code.push(Line::Choice(choice)); + code.push(choice); } else if self.settings.is_extensible { - code.push(Line::Choice(self.settings.try_me_else(0))); + code.push(self.settings.try_me_else(0)); } if self.settings.is_extensible { - let segment_is_indexed = to_indexing_line(&code_segment[0]).is_some(); + let segment_is_indexed = code_segment[0].to_indexing_line().is_some(); for clause_index_info in self.skeleton.clauses[skel_lower_bound..].iter_mut() { clause_index_info.clause_start += diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 2b67c56d..9c688858 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -3,23 +3,26 @@ use indexmap::IndexMap; use crate::allocator::*; use crate::fixtures::*; use crate::forms::Level; +use crate::instructions::*; use crate::machine::machine_indices::*; use crate::parser::ast::*; use crate::targets::CompilationTarget; use crate::temp_v; +use fxhash::FxBuildHasher; + use std::cell::Cell; use std::collections::BTreeSet; use std::rc::Rc; #[derive(Debug)] pub(crate) struct DebrayAllocator { - bindings: IndexMap, VarData>, + bindings: IndexMap, VarData, FxBuildHasher>, arg_c: usize, temp_lb: usize, arity: usize, // 0 if not at head. - contents: IndexMap>, + contents: IndexMap, FxBuildHasher>, in_use: BTreeSet, } @@ -123,7 +126,7 @@ impl DebrayAllocator { } } - fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec) + fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec) where Target: CompilationTarget<'a>, { @@ -152,7 +155,7 @@ impl DebrayAllocator { var: &String, lvl: Level, term_loc: GenContext, - target: &mut Vec, + target: &mut Vec, ) -> usize where Target: CompilationTarget<'a>, @@ -160,7 +163,7 @@ impl DebrayAllocator { match term_loc { GenContext::Head => { if let Level::Shallow = lvl { - self.evacuate_arg(0, target); + self.evacuate_arg::(0, target); self.alloc_with_cr(var) } else { self.alloc_with_ca(var) @@ -169,7 +172,7 @@ impl DebrayAllocator { GenContext::Mid(_) => self.alloc_with_ca(var), GenContext::Last(chunk_num) => { if let Level::Shallow = lvl { - self.evacuate_arg(chunk_num, target); + self.evacuate_arg::(chunk_num, target); self.alloc_with_cr(var) } else { self.alloc_with_ca(var) @@ -210,13 +213,18 @@ impl<'a> Allocator<'a> for DebrayAllocator { arity: 0, arg_c: 1, temp_lb: 1, - bindings: IndexMap::new(), - contents: IndexMap::new(), + bindings: IndexMap::with_hasher(FxBuildHasher::default()), + contents: IndexMap::with_hasher(FxBuildHasher::default()), in_use: BTreeSet::new(), } } - fn mark_anon_var(&mut self, lvl: Level, term_loc: GenContext, target: &mut Vec) + fn mark_anon_var( + &mut self, + lvl: Level, + term_loc: GenContext, + target: &mut Vec, + ) where Target: CompilationTarget<'a>, { @@ -228,7 +236,7 @@ impl<'a> Allocator<'a> for DebrayAllocator { let k = self.arg_c; if let GenContext::Last(chunk_num) = term_loc { - self.evacuate_arg(chunk_num, target); + self.evacuate_arg::(chunk_num, target); } self.arg_c += 1; @@ -243,7 +251,7 @@ impl<'a> Allocator<'a> for DebrayAllocator { lvl: Level, term_loc: GenContext, cell: &Cell, - target: &mut Vec, + target: &mut Vec, ) where Target: CompilationTarget<'a>, { @@ -254,7 +262,7 @@ impl<'a> Allocator<'a> for DebrayAllocator { let k = self.arg_c; if let GenContext::Last(chunk_num) = term_loc { - self.evacuate_arg(chunk_num, target); + self.evacuate_arg::(chunk_num, target); } self.arg_c += 1; @@ -270,20 +278,18 @@ impl<'a> Allocator<'a> for DebrayAllocator { cell.set(r); } - fn mark_var( + fn mark_var>( &mut self, var: Rc, lvl: Level, cell: &'a Cell, term_loc: GenContext, - target: &mut Vec, - ) where - Target: CompilationTarget<'a>, - { + target: &mut Vec, + ) { let (r, is_new_var) = match self.get(var.clone()) { RegType::Temp(0) => { // here, r is temporary *and* unassigned. - let o = self.alloc_reg_to_var(&var, lvl, term_loc, target); + let o = self.alloc_reg_to_var::(&var, lvl, term_loc, target); cell.set(VarReg::Norm(RegType::Temp(o))); (RegType::Temp(o), true) @@ -297,27 +303,25 @@ impl<'a> Allocator<'a> for DebrayAllocator { r => (r, false), }; - self.mark_reserved_var(var, lvl, cell, term_loc, target, r, is_new_var); + self.mark_reserved_var::(var, lvl, cell, term_loc, target, r, is_new_var); } - fn mark_reserved_var( + fn mark_reserved_var>( &mut self, var: Rc, lvl: Level, cell: &'a Cell, term_loc: GenContext, - target: &mut Vec, + target: &mut Vec, r: RegType, is_new_var: bool, - ) where - Target: CompilationTarget<'a>, - { + ) { match lvl { Level::Root | Level::Shallow => { let k = self.arg_c; if self.is_curr_arg_distinct_from(&var) { - self.evacuate_arg(term_loc.chunk_num(), target); + self.evacuate_arg::(term_loc.chunk_num(), target); } self.arg_c += 1; diff --git a/src/fixtures.rs b/src/fixtures.rs index d6a1eea9..43c3ace8 100644 --- a/src/fixtures.rs +++ b/src/fixtures.rs @@ -272,10 +272,10 @@ impl UnsafeVarMarker { } } - pub(crate) fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool { + pub(crate) fn mark_safe_vars(&mut self, query_instr: &Instruction) -> bool { match query_instr { - &QueryInstruction::PutVariable(r @ RegType::Temp(_), _) - | &QueryInstruction::SetVariable(r) => { + &Instruction::PutVariable(r @ RegType::Temp(_), _) | + &Instruction::SetVariable(r) => { self.safe_vars.insert(r); true } @@ -283,10 +283,10 @@ impl UnsafeVarMarker { } } - pub(crate) fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) { + pub(crate) fn mark_phase(&mut self, query_instr: &Instruction, phase: usize) { match query_instr { - &QueryInstruction::PutValue(r @ RegType::Perm(_), _) - | &QueryInstruction::SetValue(r) => { + &Instruction::PutValue(r @ RegType::Perm(_), _) | + &Instruction::SetValue(r) => { let p = self.unsafe_vars.entry(r).or_insert(0); *p = phase; } @@ -294,21 +294,21 @@ impl UnsafeVarMarker { } } - pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) { + pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut Instruction, phase: usize) { match query_instr { - &mut QueryInstruction::PutValue(RegType::Perm(i), arg) => { + &mut Instruction::PutValue(RegType::Perm(i), arg) => { if let Some(p) = self.unsafe_vars.swap_remove(&RegType::Perm(i)) { if p == phase { - *query_instr = QueryInstruction::PutUnsafeValue(i, arg); + *query_instr = Instruction::PutUnsafeValue(i, arg); self.safe_vars.insert(RegType::Perm(i)); } else { self.unsafe_vars.insert(RegType::Perm(i), p); } } } - &mut QueryInstruction::SetValue(r) => { + &mut Instruction::SetValue(r) => { if !self.safe_vars.contains(&r) { - *query_instr = QueryInstruction::SetLocalValue(r); + *query_instr = Instruction::SetLocalValue(r); self.safe_vars.insert(r); self.unsafe_vars.remove(&r); diff --git a/src/forms.rs b/src/forms.rs index b8042820..ce517a5f 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -1,17 +1,17 @@ use crate::arena::*; use crate::atom_table::*; -use crate::parser::ast::*; -use crate::parser::parser::CompositeOpDesc; -use crate::parser::rug::{Integer, Rational}; -use crate::{is_infix, is_postfix}; - -use crate::clause_types::*; +use crate::instructions::*; use crate::machine::heap::*; use crate::machine::loader::PredicateQueue; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; +use crate::parser::ast::*; +use crate::parser::parser::CompositeOpDesc; +use crate::parser::rug::{Integer, Rational}; use crate::types::*; +use fxhash::FxBuildHasher; + use indexmap::{IndexMap, IndexSet}; use ordered_float::OrderedFloat; @@ -19,10 +19,13 @@ use slice_deque::*; use std::cell::Cell; use std::convert::TryFrom; +use std::fmt; use std::ops::AddAssign; use std::path::PathBuf; use std::rc::Rc; +use crate::{is_infix, is_postfix}; + pub type PredicateKey = (Atom, usize); // name, arity. pub type Predicate = Vec; @@ -375,7 +378,6 @@ impl AtomOrString { } } -//TODO: try to rid yourself and the earth of the next two functions. pub(crate) fn fetch_atom_op_spec( name: Atom, spec: Option, @@ -431,7 +433,7 @@ pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option< } } -pub(crate) type ModuleDir = IndexMap; +pub(crate) type ModuleDir = IndexMap; #[derive(Debug, Clone, Eq, Hash, PartialEq)] pub enum ModuleExport { @@ -464,11 +466,13 @@ impl Module { ) -> Self { Module { module_decl, - code_dir: CodeDir::new(), + code_dir: CodeDir::with_hasher(FxBuildHasher::default()), op_dir: default_op_dir(), - meta_predicates: MetaPredicateDir::new(), - extensible_predicates: ExtensiblePredicates::new(), - local_extensible_predicates: LocalExtensiblePredicates::new(), + meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()), + extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()), + local_extensible_predicates: LocalExtensiblePredicates::with_hasher( + FxBuildHasher::default(), + ), listing_src, } } @@ -476,11 +480,13 @@ impl Module { pub(crate) fn new_in_situ(module_decl: ModuleDecl) -> Self { Module { module_decl, - code_dir: CodeDir::new(), - op_dir: OpDir::new(), - meta_predicates: MetaPredicateDir::new(), - extensible_predicates: ExtensiblePredicates::new(), - local_extensible_predicates: LocalExtensiblePredicates::new(), + code_dir: CodeDir::with_hasher(FxBuildHasher::default()), + op_dir: OpDir::with_hasher(FxBuildHasher::default()), + meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()), + extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()), + local_extensible_predicates: LocalExtensiblePredicates::with_hasher( + FxBuildHasher::default() + ), listing_src: ListingSource::DynamicallyGenerated, } } @@ -495,12 +501,22 @@ pub enum Number { } impl Default for Number { - #[inline] fn default() -> Self { Number::Fixnum(Fixnum::build_with(0)) } } +impl fmt::Display for Number { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Number::Float(fl) => write!(f, "{}", fl), + Number::Integer(n) => write!(f, "{}", n), + Number::Rational(r) => write!(f, "{}", r), + Number::Fixnum(n) => write!(f, "{}", n.get_num()), + } + } +} + pub trait ArenaFrom { fn arena_from(value: T, arena: &mut Arena) -> Self; } @@ -849,12 +865,3 @@ impl PredicateSkeleton { } } } - -#[derive(Debug, Clone, Copy)] -pub(crate) enum IndexingCodePtr { - External(usize), // the index points past the indexing instruction prelude. - DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction. - Fail, - Internal(usize), // the index points into the indexing instruction prelude. -} - diff --git a/src/heap_print.rs b/src/heap_print.rs index f9421788..e1c4e214 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1,5 +1,6 @@ use crate::arena::*; use crate::atom_table::*; +use crate::instructions::*; use crate::parser::ast::*; use crate::parser::rug::{Integer, Rational}; use crate::{ @@ -8,7 +9,6 @@ use crate::{ sign_char, single_quote_char, small_letter_char, solo_char, variable_indicator_char, }; -use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; use crate::machine::heap::*; diff --git a/src/instructions.rs b/src/instructions.rs deleted file mode 100644 index efaf4d5a..00000000 --- a/src/instructions.rs +++ /dev/null @@ -1,919 +0,0 @@ -use crate::arena::*; -use crate::atom_table::*; -use crate::parser::ast::*; - -use crate::clause_types::*; -use crate::forms::*; -use crate::types::*; -use crate::machine::heap::*; -use crate::machine::machine_errors::MachineStub; - -use indexmap::IndexMap; -use slice_deque::SliceDeque; - -fn reg_type_into_functor(r: RegType) -> MachineStub { - match r { - RegType::Temp(r) => functor!(atom!("x"), [fixnum(r)]), - RegType::Perm(r) => functor!(atom!("y"), [fixnum(r)]), - } -} - -impl Level { - fn into_functor(self) -> MachineStub { - match self { - Level::Root => functor!(atom!("level"), [atom(atom!("root"))]), - Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]), - Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]), - } - } -} - -impl ArithmeticTerm { - fn into_functor(&self, arena: &mut Arena) -> MachineStub { - match self { - &ArithmeticTerm::Reg(r) => reg_type_into_functor(r), - &ArithmeticTerm::Interm(i) => { - functor!(atom!("intermediate"), [fixnum(i)]) - } - &ArithmeticTerm::Number(n) => { - vec![HeapCellValue::from((n, arena))] - } - } - } -} - -#[derive(Debug, Clone, Copy)] -pub(crate) enum NextOrFail { - Next(usize), - Fail(usize), -} - -impl NextOrFail { - #[inline] - pub fn is_next(&self) -> bool { - if let NextOrFail::Next(_) = self { - true - } else { - false - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) enum Death { - Finite(usize), - Infinity, -} - -#[derive(Debug)] -pub(crate) enum ChoiceInstruction { - DynamicElse(usize, Death, NextOrFail), - DynamicInternalElse(usize, Death, NextOrFail), - DefaultRetryMeElse(usize), - DefaultTrustMe(usize), - RetryMeElse(usize), - TrustMe(usize), - TryMeElse(usize), -} - -impl ChoiceInstruction { - pub(crate) fn to_functor(&self, h: usize) -> MachineStub { - match self { - &ChoiceInstruction::DynamicElse(birth, death, next_or_fail) => { - match (death, next_or_fail) { - (Death::Infinity, NextOrFail::Next(i)) => { - functor!( - atom!("dynamic_else"), - [fixnum(birth), atom(atom!("inf")), fixnum(i)] - ) - } - (Death::Infinity, NextOrFail::Fail(i)) => { - let next_functor = functor!(atom!("fail"), [fixnum(i)]); - - functor!( - atom!("dynamic_else"), - [fixnum(birth), atom(atom!("inf")), str(h, 0)], - [next_functor] - ) - } - (Death::Finite(d), NextOrFail::Fail(i)) => { - let next_functor = functor!(atom!("fail"), [fixnum(i)]); - - functor!( - atom!("dynamic_else"), - [fixnum(birth), fixnum(d), str(h, 0)], - [next_functor] - ) - } - (Death::Finite(d), NextOrFail::Next(i)) => { - functor!(atom!("dynamic_else"), [fixnum(birth), fixnum(d), fixnum(i)]) - } - } - } - &ChoiceInstruction::DynamicInternalElse(birth, death, next_or_fail) => { - match (death, next_or_fail) { - (Death::Infinity, NextOrFail::Next(i)) => { - functor!( - atom!("dynamic_internal_else"), - [fixnum(birth), atom(atom!("inf")), fixnum(i)] - ) - } - (Death::Infinity, NextOrFail::Fail(i)) => { - let next_functor = functor!(atom!("fail"), [fixnum(i)]); - - functor!( - atom!("dynamic_internal_else"), - [fixnum(birth), atom(atom!("inf")), str(h, 0)], - [next_functor] - ) - } - (Death::Finite(d), NextOrFail::Fail(i)) => { - let next_functor = functor!(atom!("fail"), [fixnum(i)]); - - functor!( - atom!("dynamic_internal_else"), - [fixnum(birth), fixnum(d), str(h, 0)], - [next_functor] - ) - } - (Death::Finite(d), NextOrFail::Next(i)) => { - functor!( - atom!("dynamic_internal_else"), - [fixnum(birth), fixnum(d), fixnum(i)] - ) - } - } - } - &ChoiceInstruction::TryMeElse(offset) => { - functor!(atom!("try_me_else"), [fixnum(offset)]) - } - &ChoiceInstruction::RetryMeElse(offset) => { - functor!(atom!("retry_me_else"), [fixnum(offset)]) - } - &ChoiceInstruction::TrustMe(offset) => { - functor!(atom!("trust_me"), [fixnum(offset)]) - } - &ChoiceInstruction::DefaultRetryMeElse(offset) => { - functor!(atom!("default_retry_me_else"), [fixnum(offset)]) - } - &ChoiceInstruction::DefaultTrustMe(offset) => { - functor!(atom!("default_trust_me"), [fixnum(offset)]) - } - } - } -} - -#[derive(Debug)] -pub(crate) enum CutInstruction { - Cut(RegType), - GetLevel(RegType), - GetLevelAndUnify(RegType), - NeckCut, -} - -impl CutInstruction { - pub(crate) fn to_functor(&self, h: usize) -> MachineStub { - match self { - &CutInstruction::Cut(r) => { - let rt_stub = reg_type_into_functor(r); - functor!(atom!("cut"), [str(h, 0)], [rt_stub]) - } - &CutInstruction::GetLevel(r) => { - let rt_stub = reg_type_into_functor(r); - functor!(atom!("get_level"), [str(h, 0)], [rt_stub]) - } - &CutInstruction::GetLevelAndUnify(r) => { - let rt_stub = reg_type_into_functor(r); - functor!(atom!("get_level_and_unify"), [str(h, 0)], [rt_stub]) - } - &CutInstruction::NeckCut => { - functor!(atom!("neck_cut")) - } - } - } -} - -#[derive(Clone, Copy, Debug)] -pub(crate) enum IndexedChoiceInstruction { - Retry(usize), - Trust(usize), - Try(usize), -} - -impl IndexedChoiceInstruction { - pub(crate) fn offset(&self) -> usize { - match self { - &IndexedChoiceInstruction::Retry(offset) => offset, - &IndexedChoiceInstruction::Trust(offset) => offset, - &IndexedChoiceInstruction::Try(offset) => offset, - } - } - - pub(crate) fn to_functor(&self) -> MachineStub { - match self { - &IndexedChoiceInstruction::Try(offset) => { - functor!(atom!("try"), [fixnum(offset)]) - } - &IndexedChoiceInstruction::Trust(offset) => { - functor!(atom!("trust"), [fixnum(offset)]) - } - &IndexedChoiceInstruction::Retry(offset) => { - functor!(atom!("retry"), [fixnum(offset)]) - } - } - } -} - -/// A `Line` is an instruction (cf. page 98 of wambook). -#[derive(Debug)] -pub(crate) enum IndexingLine { - Indexing(IndexingInstruction), - IndexedChoice(SliceDeque), - DynamicIndexedChoice(SliceDeque), -} - -impl From for IndexingLine { - #[inline] - fn from(instr: IndexingInstruction) -> Self { - IndexingLine::Indexing(instr) - } -} - -impl From> for IndexingLine { - #[inline] - fn from(instrs: SliceDeque) -> Self { - IndexingLine::IndexedChoice(instrs) - } -} - -#[derive(Debug)] -pub(crate) enum Line { - Arithmetic(ArithmeticInstruction), - Choice(ChoiceInstruction), - Control(ControlInstruction), - Cut(CutInstruction), - Fact(FactInstruction), - IndexingCode(Vec), - IndexedChoice(IndexedChoiceInstruction), - DynamicIndexedChoice(usize), - Query(QueryInstruction), -} - -impl Line { - #[inline] - pub(crate) fn is_head_instr(&self) -> bool { - match self { - &Line::Fact(_) => true, - &Line::Query(_) => true, - _ => false, - } - } - - pub(crate) fn enqueue_functors( - &self, - mut h: usize, - arena: &mut Arena, - functors: &mut Vec, - ) { - match self { - &Line::Arithmetic(ref arith_instr) => { - functors.push(arith_instr.to_functor(h, arena)) - } - &Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor(h)), - &Line::Control(ref control_instr) => functors.push(control_instr.to_functor()), - &Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)), - &Line::Fact(ref fact_instr) => functors.push(fact_instr.to_functor(h)), - &Line::IndexingCode(ref indexing_instrs) => { - for indexing_instr in indexing_instrs { - match indexing_instr { - IndexingLine::Indexing(indexing_instr) => { - let section = indexing_instr.to_functor(h); - h += section.len(); - functors.push(section); - } - IndexingLine::IndexedChoice(indexed_choice_instrs) => { - for indexed_choice_instr in indexed_choice_instrs { - let section = indexed_choice_instr.to_functor(); - h += section.len(); - functors.push(section); - } - } - IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => { - for indexed_choice_instr in indexed_choice_instrs { - let section = functor!( - atom!("dynamic"), - [fixnum(*indexed_choice_instr)] - ); - - h += section.len(); - functors.push(section); - } - } - } - } - } - &Line::IndexedChoice(ref indexed_choice_instr) => { - functors.push(indexed_choice_instr.to_functor()) - } - &Line::DynamicIndexedChoice(ref indexed_choice_instr) => { - functors.push(functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)])); - } - &Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)), - } - } -} - -#[inline] -pub(crate) fn to_indexing_line_mut(line: &mut Line) -> Option<&mut Vec> { - match line { - Line::IndexingCode(ref mut indexing_code) => Some(indexing_code), - _ => None, - } -} - -#[inline] -pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec> { - match line { - Line::IndexingCode(ref indexing_code) => Some(indexing_code), - _ => None, - } -} - -#[derive(Debug, Copy, Clone)] -pub enum ArithmeticInstruction { - Add(ArithmeticTerm, ArithmeticTerm, usize), - Sub(ArithmeticTerm, ArithmeticTerm, usize), - Mul(ArithmeticTerm, ArithmeticTerm, usize), - Pow(ArithmeticTerm, ArithmeticTerm, usize), - IntPow(ArithmeticTerm, ArithmeticTerm, usize), - IDiv(ArithmeticTerm, ArithmeticTerm, usize), - Max(ArithmeticTerm, ArithmeticTerm, usize), - Min(ArithmeticTerm, ArithmeticTerm, usize), - IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize), - RDiv(ArithmeticTerm, ArithmeticTerm, usize), - Div(ArithmeticTerm, ArithmeticTerm, usize), - Shl(ArithmeticTerm, ArithmeticTerm, usize), - Shr(ArithmeticTerm, ArithmeticTerm, usize), - Xor(ArithmeticTerm, ArithmeticTerm, usize), - And(ArithmeticTerm, ArithmeticTerm, usize), - Or(ArithmeticTerm, ArithmeticTerm, usize), - Mod(ArithmeticTerm, ArithmeticTerm, usize), - Rem(ArithmeticTerm, ArithmeticTerm, usize), - Gcd(ArithmeticTerm, ArithmeticTerm, usize), - Sign(ArithmeticTerm, usize), - Cos(ArithmeticTerm, usize), - Sin(ArithmeticTerm, usize), - Tan(ArithmeticTerm, usize), - Log(ArithmeticTerm, usize), - Exp(ArithmeticTerm, usize), - ACos(ArithmeticTerm, usize), - ASin(ArithmeticTerm, usize), - ATan(ArithmeticTerm, usize), - ATan2(ArithmeticTerm, ArithmeticTerm, usize), - Sqrt(ArithmeticTerm, usize), - Abs(ArithmeticTerm, usize), - Float(ArithmeticTerm, usize), - Truncate(ArithmeticTerm, usize), - Round(ArithmeticTerm, usize), - Ceiling(ArithmeticTerm, usize), - Floor(ArithmeticTerm, usize), - Neg(ArithmeticTerm, usize), - Plus(ArithmeticTerm, usize), - BitwiseComplement(ArithmeticTerm, usize), -} - -fn arith_instr_unary_functor( - h: usize, - name: Atom, - arena: &mut Arena, - at: &ArithmeticTerm, - t: usize, -) -> MachineStub { - let at_stub = at.into_functor(arena); - functor!(name, [str(h, 0), fixnum(t)], [at_stub]) -} - -fn arith_instr_bin_functor( - h: usize, - name: Atom, - arena: &mut Arena, - at_1: &ArithmeticTerm, - at_2: &ArithmeticTerm, - t: usize, -) -> MachineStub { - let at_1_stub = at_1.into_functor(arena); - let at_2_stub = at_2.into_functor(arena); - - functor!( - name, - [str(h, 0), str(h, 1), fixnum(t)], - [at_1_stub, at_2_stub] - ) -} - -impl ArithmeticInstruction { - pub(crate) fn to_functor( - &self, - h: usize, - arena: &mut Arena, - ) -> MachineStub { - match self { - &ArithmeticInstruction::Add(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("add"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Sub(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("sub"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Mul(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("mul"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::IntPow(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("int_pow"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Pow(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("pow"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::IDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("idiv"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Max(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("max"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Min(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("min"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::IntFloorDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("int_floor_div"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::RDiv(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("rdiv"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Div(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("div"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Shl(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("shl"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Shr(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("shr"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Xor(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("xor"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::And(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("and"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Or(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("or"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Mod(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("mod"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Rem(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => { - arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t) - } - &ArithmeticInstruction::Sign(ref at, t) => { - arith_instr_unary_functor(h, atom!("sign"), arena, at, t) - } - &ArithmeticInstruction::Cos(ref at, t) => { - arith_instr_unary_functor(h, atom!("cos"), arena, at, t) - } - &ArithmeticInstruction::Sin(ref at, t) => { - arith_instr_unary_functor(h, atom!("sin"), arena, at, t) - } - &ArithmeticInstruction::Tan(ref at, t) => { - arith_instr_unary_functor(h, atom!("tan"), arena, at, t) - } - &ArithmeticInstruction::Log(ref at, t) => { - arith_instr_unary_functor(h, atom!("log"), arena, at, t) - } - &ArithmeticInstruction::Exp(ref at, t) => { - arith_instr_unary_functor(h, atom!("exp"), arena, at, t) - } - &ArithmeticInstruction::ACos(ref at, t) => { - arith_instr_unary_functor(h, atom!("acos"), arena, at, t) - } - &ArithmeticInstruction::ASin(ref at, t) => { - arith_instr_unary_functor(h, atom!("asin"), arena, at, t) - } - &ArithmeticInstruction::ATan(ref at, t) => { - arith_instr_unary_functor(h, atom!("atan"), arena, at, t) - } - &ArithmeticInstruction::Sqrt(ref at, t) => { - arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t) - } - &ArithmeticInstruction::Abs(ref at, t) => { - arith_instr_unary_functor(h, atom!("abs"), arena, at, t) - } - &ArithmeticInstruction::Float(ref at, t) => { - arith_instr_unary_functor(h, atom!("float"), arena, at, t) - } - &ArithmeticInstruction::Truncate(ref at, t) => { - arith_instr_unary_functor(h, atom!("truncate"), arena, at, t) - } - &ArithmeticInstruction::Round(ref at, t) => { - arith_instr_unary_functor(h, atom!("round"), arena, at, t) - } - &ArithmeticInstruction::Ceiling(ref at, t) => { - arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t) - } - &ArithmeticInstruction::Floor(ref at, t) => { - arith_instr_unary_functor(h, atom!("floor"), arena, at, t) - } - &ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor( - h, - atom!("-"), - arena, - at, - t, - ), - &ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor( - h, - atom!("+"), - arena, - at, - t, - ), - &ArithmeticInstruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor( - h, - atom!("\\"), - arena, - at, - t, - ), - } - } -} - -#[derive(Debug)] -pub enum ControlInstruction { - Allocate(usize), // num_frames. - // name, arity, perm_vars after threshold, last call, use default call policy. - CallClause(ClauseType, usize, usize, bool, bool), - Deallocate, - JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call. - RevJmpBy(usize), // notice the lack of context change as in - // JmpBy. RevJmpBy is used only to patch extensible - // predicates together. - Proceed, -} - -impl ControlInstruction { - pub(crate) fn perm_vars(&self) -> Option { - match self { - ControlInstruction::CallClause(_, _, num_cells, ..) => Some(*num_cells), - ControlInstruction::JmpBy(_, _, num_cells, ..) => Some(*num_cells), - _ => None, - } - } - - pub(crate) fn to_functor(&self) -> MachineStub { - match self { - &ControlInstruction::Allocate(num_frames) => { - functor!(atom!("allocate"), [fixnum(num_frames)]) - } - &ControlInstruction::CallClause(ref ct, arity, _, false, _) => { - functor!(atom!("call"), [atom(ct.name()), fixnum(arity)]) - } - &ControlInstruction::CallClause(ref ct, arity, _, true, _) => { - functor!(atom!("execute"), [atom(ct.name()), fixnum(arity)]) - } - &ControlInstruction::Deallocate => { - functor!(atom!("deallocate")) - } - &ControlInstruction::JmpBy(_, offset, ..) => { - functor!(atom!("jmp_by"), [fixnum(offset)]) - } - &ControlInstruction::RevJmpBy(offset) => { - functor!(atom!("rev_jmp_by"), [fixnum(offset)]) - } - &ControlInstruction::Proceed => { - functor!(atom!("proceed")) - } - } - } -} - -/// `IndexingInstruction` cf. page 110 of wambook. -#[derive(Debug)] -pub(crate) enum IndexingInstruction { - // The first index is the optimal argument being indexed. - SwitchOnTerm( - usize, - IndexingCodePtr, - IndexingCodePtr, - IndexingCodePtr, - IndexingCodePtr, - ), - SwitchOnConstant(IndexMap), - SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>), -} - -impl IndexingCodePtr { - #[allow(dead_code)] - pub(crate) fn to_functor(self) -> MachineStub { - match self { - IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]), - IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]), - IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]), - IndexingCodePtr::Fail => { - vec![atom_as_cell!(atom!("fail"))] - }, - } - } -} - -impl IndexingInstruction { - pub(crate) fn to_functor(&self, mut h: usize) -> MachineStub { - match self { - &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => { - functor!( - atom!("switch_on_term"), - [ - fixnum(arg), - indexing_code_ptr(h, vars), - indexing_code_ptr(h, constants), - indexing_code_ptr(h, lists), - indexing_code_ptr(h, structures) - ] - ) - } - &IndexingInstruction::SwitchOnConstant(ref constants) => { - let mut key_value_list_stub = vec![]; - let orig_h = h; - - h += 2; // skip the 2-cell "switch_on_constant" functor. - - for (c, ptr) in constants.iter() { - let key_value_pair = functor!( - atom!(":"), - [literal(*c), indexing_code_ptr(h + 3, *ptr)] - ); - - key_value_list_stub.push(list_loc_as_cell!(h + 1)); - key_value_list_stub.push(str_loc_as_cell!(h + 3)); - key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len())); - - h += key_value_pair.len() + 3; - key_value_list_stub.extend(key_value_pair.into_iter()); - } - - key_value_list_stub.push(empty_list_as_cell!()); - - functor!( - atom!("switch_on_constant"), - [str(orig_h, 0)], - [key_value_list_stub] - ) - } - &IndexingInstruction::SwitchOnStructure(ref structures) => { - let mut key_value_list_stub = vec![]; - let orig_h = h; - - h += 2; // skip the 2-cell "switch_on_constant" functor. - - for ((name, arity), ptr) in structures.iter() { - let predicate_indicator_stub = functor!( - atom!("/"), - [atom(name), fixnum(*arity)] - ); - - let key_value_pair = functor!( - atom!(":"), - [str(h + 3, 0), indexing_code_ptr(h + 3, *ptr)], - [predicate_indicator_stub] - ); - - key_value_list_stub.push(list_loc_as_cell!(h + 1)); - key_value_list_stub.push(str_loc_as_cell!(h + 3)); - key_value_list_stub.push(heap_loc_as_cell!(h + 3 + key_value_pair.len())); - - h += key_value_pair.len() + 3; - key_value_list_stub.extend(key_value_pair.into_iter()); - } - - key_value_list_stub.push(empty_list_as_cell!()); - - functor!( - atom!("switch_on_structure"), - [str(orig_h, 0)], - [key_value_list_stub] - ) - } - } - } -} - -#[derive(Debug, Clone)] -pub enum FactInstruction { - GetConstant(Level, HeapCellValue, RegType), - GetList(Level, RegType), - GetPartialString(Level, Atom, RegType, bool), - GetStructure(ClauseType, usize, RegType), - GetValue(RegType, usize), - GetVariable(RegType, usize), - UnifyConstant(HeapCellValue), - UnifyLocalValue(RegType), - UnifyVariable(RegType), - UnifyValue(RegType), - UnifyVoid(usize), -} - -impl FactInstruction { - pub(crate) fn to_functor(&self, h: usize) -> MachineStub { - match self { - &FactInstruction::GetConstant(lvl, c, r) => { - let lvl_stub = lvl.into_functor(); - let rt_stub = reg_type_into_functor(r); - - functor!( - atom!("get_constant"), - [str(h, 0), cell(c), str(h, 1)], - [lvl_stub, rt_stub] - ) - } - &FactInstruction::GetList(lvl, r) => { - let lvl_stub = lvl.into_functor(); - let rt_stub = reg_type_into_functor(r); - - functor!( - atom!("get_list"), - [str(h, 0), str(h, 1)], - [lvl_stub, rt_stub] - ) - } - &FactInstruction::GetPartialString(lvl, s, r, has_tail) => { - let lvl_stub = lvl.into_functor(); - let rt_stub = reg_type_into_functor(r); - - functor!( - atom!("get_partial_string"), - [ - str(h, 0), - string(h, s), - str(h, 1), - boolean(has_tail) - ], - [lvl_stub, rt_stub] - ) - } - &FactInstruction::GetStructure(ref ct, arity, r) => { - let rt_stub = reg_type_into_functor(r); - - functor!( - atom!("get_structure"), - [atom(ct.name()), fixnum(arity), str(h, 0)], - [rt_stub] - ) - } - &FactInstruction::GetValue(r, arg) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub]) - } - &FactInstruction::GetVariable(r, arg) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) - } - &FactInstruction::UnifyConstant(c) => { - functor!(atom!("unify_constant"), [cell(c)]) - } - &FactInstruction::UnifyLocalValue(r) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub]) - } - &FactInstruction::UnifyVariable(r) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub]) - } - &FactInstruction::UnifyValue(r) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("unify_value"), [str(h, 0)], [rt_stub]) - } - &FactInstruction::UnifyVoid(vars) => { - functor!(atom!("unify_void"), [fixnum(vars)]) - } - } - } -} - -#[derive(Debug, Clone)] -pub(crate) enum QueryInstruction { - GetVariable(RegType, usize), - PutConstant(Level, HeapCellValue, RegType), - PutList(Level, RegType), - PutPartialString(Level, Atom, RegType, bool), - PutStructure(ClauseType, usize, RegType), - PutUnsafeValue(usize, usize), - PutValue(RegType, usize), - PutVariable(RegType, usize), - SetConstant(HeapCellValue), - SetLocalValue(RegType), - SetVariable(RegType), - SetValue(RegType), - SetVoid(usize), -} - -impl QueryInstruction { - pub(crate) fn to_functor(&self, h: usize) -> MachineStub { - match self { - &QueryInstruction::PutUnsafeValue(norm, arg) => { - functor!(atom!("put_unsafe_value"), [fixnum(norm), fixnum(arg)]) - } - &QueryInstruction::PutConstant(lvl, c, r) => { - let lvl_stub = lvl.into_functor(); - let rt_stub = reg_type_into_functor(r); - - functor!( - atom!("put_constant"), - [str(h, 0), cell(c), str(h, 1)], - [lvl_stub, rt_stub] - ) - } - &QueryInstruction::PutList(lvl, r) => { - let lvl_stub = lvl.into_functor(); - let rt_stub = reg_type_into_functor(r); - - functor!( - atom!("put_list"), - [str(h, 0), str(h, 1)], - [lvl_stub, rt_stub] - ) - } - &QueryInstruction::PutPartialString(lvl, s, r, has_tail) => { - let lvl_stub = lvl.into_functor(); - let rt_stub = reg_type_into_functor(r); - - functor!( - atom!("put_partial_string"), - [ - str(h, 0), - string(h, s), - str(h, 1), - boolean(has_tail) - ], - [lvl_stub, rt_stub] - ) - } - &QueryInstruction::PutStructure(ref ct, arity, r) => { - let rt_stub = reg_type_into_functor(r); - - functor!( - atom!("put_structure"), - [atom(ct.name()), fixnum(arity), str(h, 0)], - [rt_stub] - ) - } - &QueryInstruction::PutValue(r, arg) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub]) - } - &QueryInstruction::GetVariable(r, arg) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) - } - &QueryInstruction::PutVariable(r, arg) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub]) - } - &QueryInstruction::SetConstant(c) => { - functor!(atom!("set_constant"), [cell(c)], []) - } - &QueryInstruction::SetLocalValue(r) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub]) - } - &QueryInstruction::SetVariable(r) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("set_variable"), [str(h, 0)], [rt_stub]) - } - &QueryInstruction::SetValue(r) => { - let rt_stub = reg_type_into_functor(r); - - functor!(atom!("set_value"), [str(h, 0)], [rt_stub]) - } - &QueryInstruction::SetVoid(vars) => { - functor!(atom!("set_void"), [fixnum(vars)]) - } - } - } -} - -pub(crate) type CompiledFact = Vec; - -pub(crate) type Code = Vec; diff --git a/src/iterators.rs b/src/iterators.rs index 3c6e955c..4f255584 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -1,9 +1,8 @@ use crate::atom_table::*; -use crate::parser::ast::*; - -use crate::clause_types::*; use crate::forms::*; +use crate::instructions::*; use crate::machine::machine_indices::*; +use crate::parser::ast::*; use std::cell::Cell; use std::collections::VecDeque; @@ -52,7 +51,7 @@ impl<'a> TermIterState<'a> { match term { Term::AnonVar => TermIterState::AnonVar(lvl), Term::Clause(cell, name, subterms) => { - let ct = ClauseType::Named(name.clone(), subterms.len(), CodeIndex::default()); + let ct = ClauseType::Named(subterms.len(), *name, CodeIndex::default()); TermIterState::Clause(lvl, 0, cell, ct, subterms) } Term::Cons(cell, head, tail) => { @@ -112,8 +111,8 @@ impl<'a> QueryIterator<'a> { fn new(term: &'a QueryTerm) -> Self { match term { - &QueryTerm::Clause(ref cell, ClauseType::CallN, ref terms, _) => { - let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN, terms); + &QueryTerm::Clause(ref cell, ClauseType::CallN(arity), ref terms, _) => { + let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN(arity), terms); QueryIterator { state_stack: vec![state], } @@ -164,7 +163,7 @@ impl<'a> Iterator for QueryIterator<'a> { TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => { if child_num == child_terms.len() { match ct { - ClauseType::CallN => { + ClauseType::CallN(_) => { self.push_subterm(Level::Shallow, &child_terms[0]); } ClauseType::Named(..) => { @@ -499,7 +498,7 @@ impl<'a> ChunkedIterator<'a> { } ChunkedTerm::BodyTerm(&QueryTerm::Clause( _, - ClauseType::CallN, + ClauseType::CallN(_), ref subterms, _, )) => { diff --git a/src/lib.rs b/src/lib.rs index 458ad485..a4aff98c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![recursion_limit = "4112"] + #[macro_use] extern crate static_assertions; @@ -11,7 +13,6 @@ pub mod arena; pub mod parser; mod allocator; mod arithmetic; -mod clause_types; pub mod codegen; mod debray_allocator; mod fixtures; @@ -19,7 +20,8 @@ mod forms; mod heap_iter; pub mod heap_print; mod indexing; -mod instructions; +#[macro_use] +pub mod instructions; mod iterators; pub mod machine; mod raw_block; diff --git a/src/lib/between.pl b/src/lib/between.pl index b162e023..3e023c8c 100644 --- a/src/lib/between.pl +++ b/src/lib/between.pl @@ -12,9 +12,7 @@ between(Lower, Upper, X) :- ( nonvar(X) -> Lower =< X, X =< Upper - ; % compare(Ord, Lower, Upper), - % between_(Ord, Lower, Upper, X) - Lower =< Upper, + ; Lower =< Upper, between_(Lower, Upper, X) ). @@ -27,16 +25,6 @@ between_(Lower, Upper, Lower1) :- ) ). -/* -between_(<, Lower0, Upper, X) :- - ( X = Lower0 - ; Lower1 is Lower0 + 1, - compare(Ord, Lower1, Upper), - between_(Ord, Lower1, Upper, X) - ). -between_(=, Upper, Upper, Upper). -*/ - enumerate_nats(I, I). enumerate_nats(I0, N) :- I1 is I0 + 1, diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index f1b2f2d9..32527df9 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -59,15 +59,13 @@ call(G, A, B, C, D, E, F, G) :- '$call'(G, A, B, C, D, E, F, G). call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H). +% dynamic module resolution. Module : Predicate :- ( atom(Module) -> '$module_call'(Module, Predicate) ; throw(error(type_error(atom, Module), (:)/2)) ). - -% dynamic module resolution. - :(Module, Predicate, A1) :- ( atom(Module) -> '$module_call'(A1, Module, Predicate) diff --git a/src/lib/lists.pl b/src/lib/lists.pl index a64c3ad3..752e8271 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -56,13 +56,16 @@ length(Xs, N) :- !, '$skip_max_list'(M, -1, Xs, Xs0), ( Xs0 == [] -> N = M - ; var(Xs0) -> length_addendum(Xs0, N, M)). + ; var(Xs0) -> length_addendum(Xs0, N, M) + ). length(Xs, N) :- integer(N), - N >= 0, !, + N >= 0, + !, '$skip_max_list'(M, N, Xs, Xs0), ( Xs0 == [] -> N = M - ; var(Xs0) -> R is N-M, length_rundown(Xs0, R)). + ; var(Xs0) -> R is N-M, length_rundown(Xs0, R) + ). length(_, N) :- integer(N), !, domain_error(not_less_than_zero, N, length/2). diff --git a/src/loader.pl b/src/loader.pl index a9e8f8d7..dd26bbb8 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -90,7 +90,6 @@ unload_evacuable(Evacuable) :- run_initialization_goals(Module) :- ( predicate_property(Module:'$initialization_goals'(_), dynamic) -> % FIXME: failing here. also, see add_module. - '$debug_hook', findall(Module:Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals), abolish(Module:'$initialization_goals'/1), ( maplist(Module:call, Goals) -> @@ -543,15 +542,15 @@ use_module(Module, Exports, Evacuable) :- check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :- - '$cpp_meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm). + '$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm). check_predicate_property(built_in, _, Name, Arity, built_in) :- - '$cpp_built_in_property'(Name, Arity). + '$built_in_property'(Name, Arity). check_predicate_property(dynamic, Module, Name, Arity, dynamic) :- - '$cpp_dynamic_property'(Module, Name, Arity). + '$dynamic_property'(Module, Name, Arity). check_predicate_property(multifile, Module, Name, Arity, multifile) :- - '$cpp_multifile_property'(Module, Name, Arity). + '$multifile_property'(Module, Name, Arity). check_predicate_property(discontiguous, Module, Name, Arity, discontiguous) :- - '$cpp_discontiguous_property'(Module, Name, Arity). + '$discontiguous_property'(Module, Name, Arity). diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 85b6cbc3..5cc64098 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -3,7 +3,6 @@ use divrem::*; use crate::arena::*; use crate::arithmetic::*; use crate::atom_table::*; -use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; use crate::machine::machine_errors::*; @@ -1080,7 +1079,7 @@ impl MachineState { pub fn get_number(&mut self, at: &ArithmeticTerm) -> Result { match at { &ArithmeticTerm::Reg(r) => { - let value = self.store(self.deref(self[r])); + let value = self.store(self.deref(self[r])); match Number::try_from(value) { Ok(n) => Ok(n), diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 568978d8..a158d3af 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -15,8 +15,9 @@ pub(super) type Bindings = Vec<(usize, HeapCellValue)>; pub(super) struct AttrVarInitializer { pub(super) attr_var_queue: Vec, pub(super) bindings: Bindings, - pub(super) cp: LocalCodePtr, - pub(super) instigating_p: LocalCodePtr, + pub(super) p: usize, + pub(super) cp: usize, + // pub(super) instigating_p: usize, pub(super) verify_attrs_loc: usize, } @@ -25,8 +26,8 @@ impl AttrVarInitializer { AttrVarInitializer { attr_var_queue: vec![], bindings: vec![], - instigating_p: LocalCodePtr::default(), - cp: LocalCodePtr::default(), + p: 0, + cp: 0, verify_attrs_loc, } } @@ -41,15 +42,14 @@ impl AttrVarInitializer { impl MachineState { pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: HeapCellValue) { if self.attr_var_init.bindings.is_empty() { - self.attr_var_init.instigating_p = self.p.local(); + // save self.p and self.cp and ensure that the next + // instruction is InstallVerifyAttrInterrupt. - if self.last_call { - self.attr_var_init.cp = self.cp; - } else { - self.attr_var_init.cp = self.p.local() + 1; - } + self.attr_var_init.p = self.p; + self.attr_var_init.cp = self.cp; - self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc); + self.p = INSTALL_VERIFY_ATTR_INTERRUPT - 1; + self.cp = INSTALL_VERIFY_ATTR_INTERRUPT; } self.attr_var_init.bindings.push((h, addr)); @@ -109,25 +109,27 @@ impl MachineState { } pub(super) fn verify_attr_interrupt(&mut self, p: usize) { - self.allocate(self.num_of_args + 2); + self.allocate(self.num_of_args + 3); let e = self.e; - self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp; + let and_frame = self.stack.index_and_frame_mut(e); for i in 1..self.num_of_args + 1 { - self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)]; + and_frame[i] = self.registers[i]; } - self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = + and_frame[self.num_of_args + 1] = fixnum_as_cell!(Fixnum::build_with(self.b0 as i64)); - self.stack.index_and_frame_mut(e)[self.num_of_args + 2] = + and_frame[self.num_of_args + 2] = fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64)); + and_frame[self.num_of_args + 3] = + fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64)); self.verify_attributes(); - self.num_of_args = 2; + self.num_of_args = 3; self.b0 = self.b; - self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + self.p = p; } pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec { diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs deleted file mode 100644 index f6fb6aa0..00000000 --- a/src/machine/code_repo.rs +++ /dev/null @@ -1,197 +0,0 @@ -use crate::clause_types::*; -use crate::instructions::*; -use crate::machine::{Machine, MachineState}; -use crate::machine::machine_indices::*; - -use std::fmt; - -pub(crate) enum OwnedOrIndexed { - Indexed(usize), - Owned(Line), -} - -impl fmt::Debug for OwnedOrIndexed { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &OwnedOrIndexed::Indexed(ref index) => write!(f, "Indexed({:?})", index), - &OwnedOrIndexed::Owned(ref owned) => write!(f, "Owned({:?})", owned), - } - } -} - -impl OwnedOrIndexed { - #[inline(always)] - pub(crate) fn as_ref<'a>(&'a self, code: &'a Code) -> &'a Line { - match self { - &OwnedOrIndexed::Indexed(p) => &code[p], - &OwnedOrIndexed::Owned(ref r) => r, - } - } -} - - -// TODO: remove this, replace with just 'Code'. -#[derive(Debug)] -pub struct CodeRepo { - pub(super) code: Code, -} - -impl CodeRepo { - pub(super) fn lookup_instr(&self, machine_st: &MachineState, p: &CodePtr) -> Option { - match p { - &CodePtr::Local(local) => { - return Some(self.lookup_local_instr(machine_st, local)); - } - &CodePtr::REPL(..) => None, - &CodePtr::BuiltInClause(ref built_in, _) => { - let call_clause = call_clause!( - ClauseType::BuiltIn(built_in.clone()), - built_in.arity(), - 0, - machine_st.last_call - ); - - Some(OwnedOrIndexed::Owned(call_clause)) - } - &CodePtr::CallN(arity, _, last_call) => { - let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call); - Some(OwnedOrIndexed::Owned(call_clause)) - } - &CodePtr::VerifyAttrInterrupt(p) => Some(OwnedOrIndexed::Indexed(p)), - } - } - - #[inline] - pub(super) fn lookup_local_instr(&self, machine_st: &MachineState, p: LocalCodePtr) -> OwnedOrIndexed { - match p { - LocalCodePtr::Halt => { - // exit with the interrupt exit code. - std::process::exit(1); - } - LocalCodePtr::DirEntry(p) => match &self.code[p] { - &Line::IndexingCode(ref indexing_lines) => { - match &indexing_lines[machine_st.oip as usize] { - &IndexingLine::IndexedChoice(ref indexed_choice_instrs) => { - OwnedOrIndexed::Owned( - Line::IndexedChoice(indexed_choice_instrs[machine_st.iip as usize]) - ) - } - &IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => { - OwnedOrIndexed::Owned( - Line::DynamicIndexedChoice(indexed_choice_instrs[machine_st.iip as usize]) - ) - } - _ => { - OwnedOrIndexed::Indexed(p) - } - } - } - _ => OwnedOrIndexed::Indexed(p) - } - } - } -} - -impl Machine { - pub(super) fn find_living_dynamic_else(&self, mut p: usize) -> Option<(usize, usize)> { - loop { - match &self.code_repo.code[p] { - &Line::Choice(ChoiceInstruction::DynamicElse( - birth, - death, - NextOrFail::Next(i), - )) => { - if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { - return Some((p, i)); - } else if i > 0 { - p += i; - } else { - return None; - } - } - &Line::Choice(ChoiceInstruction::DynamicElse( - birth, - death, - NextOrFail::Fail(_), - )) => { - if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { - return Some((p, 0)); - } else { - return None; - } - } - &Line::Choice(ChoiceInstruction::DynamicInternalElse( - birth, - death, - NextOrFail::Next(i), - )) => { - if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { - return Some((p, i)); - } else if i > 0 { - p += i; - } else { - return None; - } - } - &Line::Choice(ChoiceInstruction::DynamicInternalElse( - birth, - death, - NextOrFail::Fail(_), - )) => { - if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { - return Some((p, 0)); - } else { - return None; - } - } - &Line::Control(ControlInstruction::RevJmpBy(i)) => { - p -= i; - } - _ => { - unreachable!(); - } - } - } - } - - pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> { - let p = self.machine_st.p.local().abs_loc(); - - let indexed_choice_instrs = match &self.code_repo.code[p] { - Line::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] { - IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => { - indexed_choice_instrs - } - _ => unreachable!(), - }, - _ => unreachable!(), - }; - - loop { - match &indexed_choice_instrs.get(ii as usize) { - Some(&offset) => match &self.code_repo.code[p + offset - 1] { - &Line::Choice(ChoiceInstruction::DynamicInternalElse( - birth, - death, - next_or_fail, - )) => { - if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { - return Some((offset, oi, ii, next_or_fail.is_next())); - } else { - ii += 1; - } - } - _ => unreachable!(), - }, - None => return None, - } - } - } -} - -impl CodeRepo { - #[inline] - pub(super) fn new() -> Self { - CodeRepo { code: Code::new() } - } -} diff --git a/src/machine/code_walker.rs b/src/machine/code_walker.rs index fe63347f..fcda8710 100644 --- a/src/machine/code_walker.rs +++ b/src/machine/code_walker.rs @@ -2,45 +2,47 @@ use crate::instructions::*; use indexmap::IndexSet; -fn capture_offset(line: &Line, index: usize, stack: &mut Vec) -> bool { +fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec) -> bool { match line { - &Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => { + &Instruction::TryMeElse(offset) if offset > 0 => { stack.push(index + offset); } - &Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) - | &Line::Choice(ChoiceInstruction::RetryMeElse(offset)) + &Instruction::DefaultRetryMeElse(offset) | + &Instruction::RetryMeElse(offset) if offset > 0 => { stack.push(index + offset); } - &Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset))) + &Instruction::DynamicElse(_, _, NextOrFail::Next(offset)) if offset > 0 => { stack.push(index + offset); } - &Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset))) + &Instruction::DynamicInternalElse(_, _, NextOrFail::Next(offset)) if offset > 0 => { stack.push(index + offset); } - &Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => { + &Instruction::JmpByCall(_, offset, _) => { stack.push(index + offset); } - &Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => { + &Instruction::JmpByExecute(_, offset, _) => { stack.push(index + offset); return true; } - &Line::Control(ControlInstruction::Proceed) - | &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => { + &Instruction::Proceed => { return true; } - &Line::Control(ControlInstruction::RevJmpBy(offset)) => { + &Instruction::RevJmpBy(offset) => { if offset > 0 { stack.push(index - offset); } else { return true; } } + instr if instr.is_execute() => { + return true; + } _ => {} }; @@ -51,7 +53,7 @@ fn capture_offset(line: &Line, index: usize, stack: &mut Vec) -> bool { * begin in code at the offset p. Each instruction is passed to the * walker function. */ -pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line)) { +pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Instruction)) { let mut stack = vec![p]; let mut visited_indices = IndexSet::new(); diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 8b69ced8..fa1f7250 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -38,7 +38,7 @@ pub(super) fn bootstrapping_compile( ); let payload = BootstrappingLoadState( - LoadStatePayload::new(wam_prelude.code_repo.code.len(), term_stream) + LoadStatePayload::new(wam_prelude.code.len(), term_stream) ); let loader: Loader<'_, BootstrappingLoadState> = Loader { payload, wam_prelude }; @@ -73,7 +73,8 @@ pub(super) fn compile_appendix( let code_len = code.len(); match &mut code[jmp_by_offset] { - &mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) => { + &mut Instruction::JmpByCall(_, ref mut offset, ..) | + &mut Instruction::JmpByExecute(_, ref mut offset, ..) => { *offset = code_len - jmp_by_offset; } _ => { @@ -144,20 +145,20 @@ fn derelictize_try_me_else( retraction_info: &mut RetractionInfo, ) -> Option { match &mut code[index] { - Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(0))) => None, - Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) => { + Instruction::DynamicElse(_, _, NextOrFail::Next(0)) => None, + Instruction::DynamicElse(_, _, NextOrFail::Next(ref mut o)) => { retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o)); Some(mem::replace(o, 0)) } - Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(0))) => None, - Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o))) => { + Instruction::DynamicInternalElse(_, _, NextOrFail::Next(0)) => None, + Instruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o)) => { retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o)); Some(mem::replace(o, 0)) } - Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(_))) - | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(_))) => None, - Line::Choice(ChoiceInstruction::TryMeElse(0)) => None, - Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + Instruction::DynamicElse(_, _, NextOrFail::Fail(_)) | + Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(_)) => None, + Instruction::TryMeElse(0) => None, + Instruction::TryMeElse(ref mut o) => { retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(index, *o)); Some(mem::replace(o, 0)) } @@ -183,7 +184,7 @@ fn merge_indices( let clause_loc = find_inner_choice_instr(code, skeleton[clause_index].clause_start, index_loc); - let target_indexing_line = to_indexing_line_mut(&mut code[target_index_loc]).unwrap(); + let target_indexing_line = code[target_index_loc].to_indexing_line_mut().unwrap(); skeleton[clause_index] .opt_arg_index_key @@ -210,8 +211,8 @@ fn merge_indices( fn find_outer_choice_instr(code: &Code, mut index: usize) -> usize { loop { match &code[index] { - Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(i))) - | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(i))) + Instruction::DynamicElse(_, _, NextOrFail::Next(i)) | + Instruction::DynamicInternalElse(_, _, NextOrFail::Next(i)) if *i > 0 => { index += i; @@ -226,15 +227,15 @@ fn find_outer_choice_instr(code: &Code, mut index: usize) -> usize { fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> usize { loop { match &code[index] { - Line::Choice(ChoiceInstruction::TryMeElse(o)) - | Line::Choice(ChoiceInstruction::RetryMeElse(o)) => { + Instruction::TryMeElse(o) | + Instruction::RetryMeElse(o) => { if *o > 0 { return index; } else { index = index_loc; } } - &Line::Choice(ChoiceInstruction::DynamicElse(_, _, next_or_fail)) => match next_or_fail + &Instruction::DynamicElse(_, _, next_or_fail) => match next_or_fail { NextOrFail::Next(i) => { if i == 0 { @@ -247,7 +248,7 @@ fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> u index = index_loc; } }, - &Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, next_or_fail)) => { + &Instruction::DynamicInternalElse(_, _, next_or_fail) => { match next_or_fail { NextOrFail::Next(i) => { if i == 0 { @@ -261,20 +262,20 @@ fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> u } } } - Line::Choice(ChoiceInstruction::TrustMe(_)) => { + Instruction::TrustMe(_) => { return index; } - Line::IndexingCode(indexing_code) => match &indexing_code[0] { + Instruction::IndexingCode(indexing_code) => match &indexing_code[0] { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v { IndexingCodePtr::External(v) => { index += v; } IndexingCodePtr::DynamicExternal(v) => match &code[index + v] { - &Line::Choice(ChoiceInstruction::DynamicInternalElse( + &Instruction::DynamicInternalElse( _, _, NextOrFail::Next(0), - )) => { + ) => { return index + v; } _ => { @@ -287,7 +288,7 @@ fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> u unreachable!(); } }, - Line::Control(ControlInstruction::RevJmpBy(offset)) => { + Instruction::RevJmpBy(offset) => { index -= offset; } _ => { @@ -310,9 +311,7 @@ fn remove_index_from_subsequence( ) { if let Some(index_loc) = opt_arg_index_key.switch_on_term_loc() { let clause_start = find_inner_choice_instr(code, clause_start, index_loc); - - let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); - + let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap(); let offset = clause_start - index_loc + 1; remove_index(opt_arg_index_key, target_indexing_line, offset); @@ -351,7 +350,7 @@ fn merge_indexed_subsequences( ); match &mut code[inner_try_me_else_loc] { - Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + Instruction::TryMeElse(ref mut o) => { retraction_info.push_record(RetractionRecord::ModifiedTryMeElse( inner_try_me_else_loc, *o, @@ -359,15 +358,15 @@ fn merge_indexed_subsequences( match *o { 0 => { - code[inner_try_me_else_loc] = Line::Choice(ChoiceInstruction::TrustMe(0)); + code[inner_try_me_else_loc] = Instruction::TrustMe(0); } o => match &code[inner_try_me_else_loc + o] { - Line::Control(ControlInstruction::RevJmpBy(0)) => { - code[inner_try_me_else_loc] = Line::Choice(ChoiceInstruction::TrustMe(o)); + Instruction::RevJmpBy(0) => { + code[inner_try_me_else_loc] = Instruction::TrustMe(o); } _ => { code[inner_try_me_else_loc] = - Line::Choice(ChoiceInstruction::RetryMeElse(o)); + Instruction::RetryMeElse(o); } }, } @@ -403,7 +402,7 @@ fn merge_indexed_subsequences( ); } None => match &mut code[outer_threaded_choice_instr_loc] { - Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + Instruction::TryMeElse(ref mut o) => { retraction_info .push_record(RetractionRecord::ModifiedTryMeElse(inner_trust_me_loc, *o)); @@ -461,60 +460,55 @@ fn blunt_leading_choice_instr( ) -> usize { loop { match &mut code[instr_loc] { - Line::Choice(ChoiceInstruction::RetryMeElse(o)) => { + Instruction::RetryMeElse(o) => { retraction_info.push_record(RetractionRecord::ModifiedRetryMeElse(instr_loc, *o)); - - code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(*o)); - + code[instr_loc] = Instruction::TryMeElse(*o); return instr_loc; } - Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(_))) - | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(_))) => { + Instruction::DynamicElse(_, _, NextOrFail::Next(_)) | + Instruction::DynamicInternalElse(_, _, NextOrFail::Next(_)) => { return instr_loc; } - &mut Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Fail(o))) => { + &mut Instruction::DynamicElse(b, d, NextOrFail::Fail(o)) => { retraction_info.push_record(RetractionRecord::AppendedNextOrFail( instr_loc, NextOrFail::Fail(o), )); - code[instr_loc] = - Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(0))); - + code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Next(0)); return instr_loc; } - &mut Line::Choice(ChoiceInstruction::DynamicInternalElse( + &mut Instruction::DynamicInternalElse( b, d, NextOrFail::Fail(o), - )) => { + ) => { retraction_info.push_record(RetractionRecord::AppendedNextOrFail( instr_loc, NextOrFail::Fail(o), )); - code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse( + code[instr_loc] = Instruction::DynamicInternalElse( b, d, NextOrFail::Next(0), - )); + ); return instr_loc; } - Line::Choice(ChoiceInstruction::TrustMe(o)) => { - retraction_info - .push_record(RetractionRecord::AppendedTrustMe(instr_loc, *o, false)); + Instruction::TrustMe(o) => { + retraction_info.push_record(RetractionRecord::AppendedTrustMe(instr_loc, *o, false)); - code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(0)); + code[instr_loc] = Instruction::TryMeElse(0); return instr_loc + 1; } - Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + Instruction::TryMeElse(0) => { return instr_loc + 1; } - Line::Choice(ChoiceInstruction::TryMeElse(o)) => { + Instruction::TryMeElse(o) => { instr_loc += *o; } - Line::Control(ControlInstruction::RevJmpBy(o)) => { + Instruction::RevJmpBy(o) => { instr_loc -= *o; } _ => { @@ -530,7 +524,7 @@ fn set_switch_var_offset_to_choice_instr( offset: usize, retraction_info: &mut RetractionInfo, ) { - let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); + let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap(); let v = match &target_indexing_line[0] { &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v { @@ -543,9 +537,9 @@ fn set_switch_var_offset_to_choice_instr( }; match &code[index_loc + v] { - Line::Choice(ChoiceInstruction::TryMeElse(_)) - | Line::Choice(ChoiceInstruction::DynamicElse(..)) - | Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => {} + Instruction::TryMeElse(_) | + Instruction::DynamicElse(..) | + Instruction::DynamicInternalElse(..) => {} _ => { set_switch_var_offset(code, index_loc, offset, retraction_info); } @@ -559,7 +553,7 @@ fn set_switch_var_offset( offset: usize, retraction_info: &mut RetractionInfo, ) { - let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); + let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap(); let old_v = match &mut target_indexing_line[0] { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, ref mut v, ..)) => match *v { @@ -585,72 +579,67 @@ fn internalize_choice_instr_at( retraction_info: &mut RetractionInfo, ) { match &mut code[instr_loc] { - Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(_))) - | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(_))) => {} - Line::Choice(ChoiceInstruction::DynamicElse(_, _, ref mut o @ NextOrFail::Next(0))) => { + Instruction::DynamicElse(_, _, NextOrFail::Fail(_)) | + Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(_)) => { + } + Instruction::DynamicElse(_, _, ref mut o @ NextOrFail::Next(0)) => { retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0)); *o = NextOrFail::Fail(0); } - &mut Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(o))) => { + &mut Instruction::DynamicElse(b, d, NextOrFail::Next(o)) => { retraction_info.push_record(RetractionRecord::AppendedNextOrFail( instr_loc, NextOrFail::Next(o), )); match &mut code[instr_loc + o] { - Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => { - code[instr_loc] = - Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Fail(o))); + Instruction::RevJmpBy(p) if *p == 0 => { + code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Fail(o)); } _ => { - code[instr_loc] = - Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(o))); + code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Next(o)); } } } - Line::Choice(ChoiceInstruction::DynamicInternalElse( - _, - _, - ref mut o @ NextOrFail::Next(0), - )) => { + Instruction::DynamicInternalElse(_, _, ref mut o @ NextOrFail::Next(0)) => { retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0)); *o = NextOrFail::Fail(0); } - &mut Line::Choice(ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Next(o))) => { + &mut Instruction::DynamicInternalElse(b, d, NextOrFail::Next(o)) => { retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, o)); match &mut code[instr_loc + o] { - Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => { - code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse( + Instruction::RevJmpBy(p) if *p == 0 => { + code[instr_loc] = Instruction::DynamicInternalElse( b, d, NextOrFail::Fail(o), - )); + ); } _ => { - code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse( + code[instr_loc] = Instruction::DynamicInternalElse( b, d, NextOrFail::Next(o), - )); + ); } } } - Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + Instruction::TryMeElse(0) => { retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, 0)); - code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0)); + code[instr_loc] = Instruction::TrustMe(0); } - Line::Choice(ChoiceInstruction::TryMeElse(o)) => { + Instruction::TryMeElse(o) => { let o = *o; retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, o)); match &mut code[instr_loc + o] { - Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => { - code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(o)); + Instruction::RevJmpBy(p) if *p == 0 => { + code[instr_loc] = Instruction::TrustMe(o); } _ => { - code[instr_loc] = Line::Choice(ChoiceInstruction::RetryMeElse(o)); + code[instr_loc] = Instruction::RetryMeElse(o); } } } @@ -668,8 +657,7 @@ fn thread_choice_instr_at_to( ) { loop { match &mut code[instr_loc] { - Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) - | Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) + Instruction::TryMeElse(ref mut o) | Instruction::RetryMeElse(ref mut o) if target_loc >= instr_loc => { retraction_info.push_record(RetractionRecord::ReplacedChoiceOffset(instr_loc, *o)); @@ -677,82 +665,80 @@ fn thread_choice_instr_at_to( *o = target_loc - instr_loc; return; } - Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) - | Line::Choice(ChoiceInstruction::DynamicInternalElse( + Instruction::DynamicElse(_, _, NextOrFail::Next(ref mut o)) | + Instruction::DynamicInternalElse( _, _, NextOrFail::Next(ref mut o), - )) if target_loc >= instr_loc => { + ) if target_loc >= instr_loc => { retraction_info .push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, *o)); *o = target_loc - instr_loc; return; } - Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(o))) - | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(o))) => { + Instruction::DynamicElse(_, _, NextOrFail::Next(o)) | + Instruction::DynamicInternalElse(_, _, NextOrFail::Next(o)) => { instr_loc += *o; } - Line::Choice(ChoiceInstruction::TryMeElse(o)) - | Line::Choice(ChoiceInstruction::RetryMeElse(o)) => { + Instruction::TryMeElse(o) + | Instruction::RetryMeElse(o) => { instr_loc += *o; } - Line::Control(ControlInstruction::RevJmpBy(ref mut o)) if instr_loc >= target_loc => { + Instruction::RevJmpBy(ref mut o) if instr_loc >= target_loc => { retraction_info.push_record(RetractionRecord::ModifiedRevJmpBy(instr_loc, *o)); *o = instr_loc - target_loc; return; } - &mut Line::Control(ControlInstruction::RevJmpBy(o)) => { + &mut Instruction::RevJmpBy(o) => { instr_loc -= o; } - &mut Line::Choice(ChoiceInstruction::DynamicElse(birth, death, ref mut fail)) + &mut Instruction::DynamicElse(birth, death, ref mut fail) if target_loc >= instr_loc => { retraction_info.push_record(RetractionRecord::AppendedNextOrFail(instr_loc, *fail)); - code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicElse( + code[instr_loc] = instr!("dynamic_else", birth, death, - NextOrFail::Next(target_loc - instr_loc), - )); + NextOrFail::Next(target_loc - instr_loc) + ); return; } - Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(o))) if *o > 0 => { + Instruction::DynamicElse(_, _, NextOrFail::Fail(o)) if *o > 0 => { instr_loc += *o; } - &mut Line::Choice(ChoiceInstruction::DynamicInternalElse( + &mut Instruction::DynamicInternalElse( birth, death, ref mut fail, - )) if target_loc >= instr_loc => { + ) if target_loc >= instr_loc => { retraction_info.push_record(RetractionRecord::AppendedNextOrFail(instr_loc, *fail)); - code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse( + code[instr_loc] = instr!("dynamic_internal_else", birth, death, - NextOrFail::Next(target_loc - instr_loc), - )); + NextOrFail::Next(target_loc - instr_loc) + ); return; } - Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(o))) + Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(o)) if *o > 0 => { instr_loc += *o; } - Line::Choice(ChoiceInstruction::TrustMe(ref mut o)) if target_loc >= instr_loc => { + Instruction::TrustMe(ref mut o) if target_loc >= instr_loc => { retraction_info.push_record( RetractionRecord::AppendedTrustMe(instr_loc, *o, false), //choice_instr.is_default()), ); - code[instr_loc] = - Line::Choice(ChoiceInstruction::RetryMeElse(target_loc - instr_loc)); - + code[instr_loc] = instr!("retry_me_else", target_loc - instr_loc); return; } - Line::Choice(ChoiceInstruction::TrustMe(o)) if *o > 0 => { + Instruction::TrustMe(o) if *o > 0 => { instr_loc += *o; } _ => { @@ -769,7 +755,7 @@ fn remove_non_leading_clause( retraction_info: &mut RetractionInfo, ) -> Option { match &mut code[non_indexed_choice_instr_loc] { - Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => { + Instruction::RetryMeElse(ref mut o) => { let o = *o; thread_choice_instr_at_to( @@ -781,19 +767,19 @@ fn remove_non_leading_clause( None } - Line::Choice(ChoiceInstruction::TrustMe(_)) => { + Instruction::TrustMe(_) => { match &mut code[preceding_choice_instr_loc] { - Line::Choice(ChoiceInstruction::RetryMeElse(o)) => { + Instruction::RetryMeElse(o) => { retraction_info.push_record(RetractionRecord::ModifiedRetryMeElse( preceding_choice_instr_loc, *o, )); - code[preceding_choice_instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0)); + code[preceding_choice_instr_loc] = Instruction::TrustMe(0); None } - Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + Instruction::TryMeElse(ref mut o) => { retraction_info.push_record(RetractionRecord::ModifiedTryMeElse( preceding_choice_instr_loc, *o, @@ -850,7 +836,7 @@ fn remove_leading_unindexed_clause( retraction_info: &mut RetractionInfo, ) -> Option { match &mut code[non_indexed_choice_instr_loc] { - Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + Instruction::TryMeElse(ref mut o) => { if *o > 0 { retraction_info.push_record(RetractionRecord::ModifiedTryMeElse( non_indexed_choice_instr_loc, @@ -878,7 +864,7 @@ fn remove_leading_unindexed_clause( fn find_dynamic_outer_choice_instr(code: &Code, index_loc: usize) -> usize { match &code[index_loc] { - Line::IndexingCode(indexing_code) => match &indexing_code[0] { + Instruction::IndexingCode(indexing_code) => match &indexing_code[0] { &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( _, IndexingCodePtr::DynamicExternal(v), @@ -951,22 +937,16 @@ fn prepend_compiled_clause( let inner_thread_rev_offset = 3 + prepend_queue.len() + clause_loc - skeleton.clauses[1].clause_start; - prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy( - inner_thread_rev_offset, - ))); + prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset)); - prepend_queue.push_front(Line::Choice( - settings.internal_try_me_else(prepend_queue.len()), - )); + prepend_queue.push_front(settings.internal_try_me_else(prepend_queue.len())); // prepend_queue is now: // | TryMeElse N_2 // | (clause_code) // +N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1) - prepend_queue.push_front(Line::Control(ControlInstruction::RevJmpBy( - 1 + clause_loc - index_loc, - ))); + prepend_queue.push_front(Instruction::RevJmpBy(1 + clause_loc - index_loc)); let outer_thread_choice_offset = // outer_thread_choice_loc WAS index_loc - 1.. match derelictize_try_me_else(code, outer_thread_choice_loc, retraction_info) { @@ -978,7 +958,7 @@ fn prepend_compiled_clause( next_subseq_offset; prepend_queue.push_back( - Line::Control(ControlInstruction::RevJmpBy(outer_thread_rev_offset)) + Instruction::RevJmpBy(outer_thread_rev_offset) ); prepend_queue.len() @@ -994,17 +974,13 @@ fn prepend_compiled_clause( // awaiting the addition of unindexed // clauses. - prepend_queue.push_back( - Line::Control(ControlInstruction::RevJmpBy(0)), - ); + prepend_queue.push_back(Instruction::RevJmpBy(0)); 0 } }; - prepend_queue.push_front(Line::Choice( - settings.try_me_else(outer_thread_choice_offset), - )); + prepend_queue.push_front(settings.try_me_else(outer_thread_choice_offset)); // prepend_queue is now: // | TryMeElse N_3 @@ -1014,7 +990,7 @@ fn prepend_compiled_clause( // N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1) // N_3 | RevJmpBy (TryMeElse(N_1) at index_loc - 1 or TrustMe if N_1 == 0) - let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); + let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap(); merge_clause_index( target_indexing_line, @@ -1060,19 +1036,19 @@ fn prepend_compiled_clause( // this is a stub for chaining inner-threaded choice // instructions. - prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(0))); + prepend_queue.push_back(Instruction::RevJmpBy(0)); let prepend_queue_len = prepend_queue.len(); match &mut prepend_queue[1] { - Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) if *o == 0 => { + Instruction::TryMeElse(ref mut o) if *o == 0 => { *o = prepend_queue_len - 2; } - Line::Choice(ChoiceInstruction::DynamicInternalElse( + Instruction::DynamicInternalElse( _, _, ref mut o @ NextOrFail::Next(0), - )) => { + ) => { *o = NextOrFail::Fail(prepend_queue_len - 2); } _ => { @@ -1080,11 +1056,8 @@ fn prepend_compiled_clause( } } - prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy( - inner_thread_rev_offset, - ))); - - prepend_queue.push_front(Line::Choice(settings.try_me_else(prepend_queue.len()))); + prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset)); + prepend_queue.push_front(settings.try_me_else(prepend_queue.len())); // prepend_queue is now: // | TryMeElse(N_2) @@ -1114,11 +1087,8 @@ fn prepend_compiled_clause( let inner_thread_rev_offset = 1 + prepend_queue.len() + clause_loc - old_clause_start; - prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy( - inner_thread_rev_offset, - ))); - - prepend_queue.push_front(Line::Choice(settings.try_me_else(prepend_queue.len()))); + prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset)); + prepend_queue.push_front(settings.try_me_else(prepend_queue.len())); // prepend_queue is now: // | TryMeElse(N_2) @@ -1142,11 +1112,8 @@ fn prepend_compiled_clause( let inner_thread_rev_offset = 1 + prepend_queue.len() + clause_loc - old_clause_start; - prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy( - inner_thread_rev_offset, - ))); - - prepend_queue.push_front(Line::Choice(settings.try_me_else(prepend_queue.len()))); + prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset)); + prepend_queue.push_front(settings.try_me_else(prepend_queue.len())); // prepend_queue is now: // | TryMeElse(N_2) @@ -1205,7 +1172,7 @@ fn append_compiled_clause( .switch_on_term_loc() { Some(index_loc) if lower_bound_arg_num == target_arg_num => { - code.push(Line::Choice(settings.internal_trust_me())); + code.push(settings.internal_trust_me()); code.extend(clause_code.drain(3..)); // skip the indexing code @@ -1218,7 +1185,7 @@ fn append_compiled_clause( skeleton.clauses[target_pos].clause_start, )); - let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); + let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap(); merge_clause_index( target_indexing_line, @@ -1252,7 +1219,7 @@ fn append_compiled_clause( target_pos_clause_start // skeleton.clauses[target_pos - 1].clause_start } _ => { - code.push(Line::Choice(settings.trust_me())); + code.push(settings.trust_me()); skeleton.clauses[target_pos].opt_arg_index_key += clause_loc; code.extend(clause_code.drain(1..)); @@ -1331,9 +1298,9 @@ fn print_overwrite_warning( key: &PredicateKey, is_dynamic: bool, ) { - if let CompilationTarget::Module(ref module_name) = compilation_target { - match module_name.as_str() { - "builtins" | "loader" => return, + if let CompilationTarget::Module(module_name) = compilation_target { + match module_name { + atom!("builtins") | atom!("loader") => return, _ => {} } } @@ -1405,7 +1372,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ) -> Result { let code_index = self.get_or_insert_code_index(key, predicates.compilation_target); - let code_len = self.wam_prelude.code_repo.code.len(); + let code_len = self.wam_prelude.code.len(); let mut code_ptr = code_len; let mut clauses = vec![]; @@ -1443,7 +1410,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } match &mut code[0] { - Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + Instruction::TryMeElse(0) => { code_ptr += 1; } _ => {} @@ -1514,7 +1481,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { index_ptr, ); - self.wam_prelude.code_repo.code.extend(code.into_iter()); + self.wam_prelude.code.extend(code.into_iter()); Ok(code_index) } @@ -1690,7 +1657,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { mut standalone_skeleton, } = self.compile_standalone_clause(clause, settings)?; - let code_len = self.wam_prelude.code_repo.code.len(); + let code_len = self.wam_prelude.code.len(); let skeleton = match self .wam_prelude @@ -1717,7 +1684,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let global_clock = LS::machine_st(&mut self.payload).global_clock; let result = append_compiled_clause( - &mut self.wam_prelude.code_repo.code, + &mut self.wam_prelude.code, clause_code, skeleton, &mut self.payload.retraction_info, @@ -1757,7 +1724,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let global_clock = LS::machine_st(&mut self.payload).global_clock; let new_code_ptr = prepend_compiled_clause( - &mut self.wam_prelude.code_repo.code, + &mut self.wam_prelude.code, compilation_target, key, clause_code, @@ -1801,16 +1768,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .switch_on_term_loc() { Some(index_loc) => find_inner_choice_instr( - &self.wam_prelude.code_repo.code, + &self.wam_prelude.code, skeleton.clauses[target_pos].clause_start, index_loc, ), None => skeleton.clauses[target_pos].clause_start, }; - match &mut self.wam_prelude.code_repo.code[clause_loc] { - Line::Choice(ChoiceInstruction::DynamicElse(_, ref mut d, _)) - | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, ref mut d, _)) => { + match &mut self.wam_prelude.code[clause_loc] { + Instruction::DynamicElse(_, ref mut d, _) | + Instruction::DynamicInternalElse(_, ref mut d, _) => { *d = Death::Finite(LS::machine_st(&mut self.payload).global_clock); } _ => unreachable!(), @@ -1840,7 +1807,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } }; - let code = &mut self.wam_prelude.code_repo.code; + let code = &mut self.wam_prelude.code; let lower_bound = lower_bound_of_target_clause(skeleton, target_pos); let lower_bound_is_unindexed = !skeleton.clauses[lower_bound].opt_arg_index_key.is_some(); @@ -1975,13 +1942,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { Some(later_indexing_loc) if later_indexing_loc < target_indexing_loc => { let target_indexing_line = mem::replace( &mut code[target_indexing_loc], - Line::Control(ControlInstruction::RevJmpBy( - target_indexing_loc - later_indexing_loc, - )), + Instruction::RevJmpBy(target_indexing_loc - later_indexing_loc), ); match target_indexing_line { - Line::IndexingCode(indexing_code) => { + Instruction::IndexingCode(indexing_code) => { self.payload.retraction_info.push_record( RetractionRecord::ReplacedIndexingLine( target_indexing_loc, @@ -2073,7 +2038,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ); match &mut code[preceding_choice_instr_loc] { - Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + Instruction::TryMeElse(0) => { set_switch_var_offset( code, index_loc, diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 9b02d191..6f5d9d02 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -3,1277 +3,4872 @@ use crate::atom_table::*; use crate::instructions::*; use crate::machine::*; use crate::machine::arithmetic_ops::*; -use crate::machine::code_repo::*; use crate::machine::machine_errors::*; use crate::machine::machine_state::*; use crate::types::*; use crate::try_numeric_result; -impl Machine { - #[inline(always)] - pub(super) fn dispatch_instr(&mut self, instr: OwnedOrIndexed) { - match instr.as_ref(&self.code_repo.code) { - &Line::Arithmetic(ref arith_instr) => { - let stub_gen = || functor_stub(atom!("is"), 2); - - match arith_instr { - &ArithmeticInstruction::Add(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); - - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - try_numeric_result!(add(n1, n2, &mut self.machine_st.arena), stub_gen) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Sub(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); +macro_rules! step_or_fail { + ($self:expr, $step_e:expr) => { + if $self.machine_st.fail { + $self.machine_st.backtrack(); + } else { + $step_e; + } + }; +} - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Mul(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); +macro_rules! try_or_throw { + ($s:expr, $e:expr) => {{ + match $e { + Ok(val) => val, + Err(msg) => { + $s.throw_exception(msg); + $s.backtrack(); + continue; + } + } + }}; +} - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - try_numeric_result!(mul(n1, n2, &mut self.machine_st.arena), stub_gen) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Max(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); +macro_rules! try_or_throw_gen { + ($s:expr, $e:expr) => {{ + match $e { + Ok(val) => val, + Err(msg_fn) => { + let e = msg_fn($s); + $s.throw_exception(e); + $s.backtrack(); + continue; + } + } + }}; +} - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - max(n1, n2) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Min(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); +static INSTRUCTIONS_PER_INTERRUPT_POLL: usize = 256; - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - min(n1, n2) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::IntPow(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); +impl MachineState { + #[inline(always)] + fn compare(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("compare"), 3); - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - int_pow(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + let a1 = self.store(self.deref(self.registers[1])); + let a2 = self.registers[2]; + let a3 = self.registers[3]; - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - gcd(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Pow(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + read_heap_cell!(a1, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - pow(n1, n2, atom!("**")) - ); - self.machine_st.p += 1; + match name { + atom!(">") | atom!("<") | atom!("=") if arity == 2 => { } - &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => { - let stub_gen = || functor_stub(atom!("(rdiv)"), 2); - - let r1 = try_or_fail!(self.machine_st, self.machine_st.get_rational(a1, stub_gen)); - let r2 = try_or_fail!(self.machine_st, self.machine_st.get_rational(a2, stub_gen)); - - self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!( - try_or_fail_gen!(&mut self.machine_st, rdiv(r1, r2)), - self.machine_st.arena - )); - self.machine_st.p += 1; + _ => { + let err = self.domain_error(DomainErrorType::Order, a1); + return Err(self.error_form(err, stub_gen())); } - &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + } + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + } + _ => { + let err = self.type_error(ValidType::Atom, a1); + return Err(self.error_form(err, stub_gen())); + } + ); - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - int_floor_div(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + let atom = match compare_term_test!(self, a2, a3) { + Some(Ordering::Greater) => { + atom!(">") + } + Some(Ordering::Equal) => { + atom!("=") + } + None | Some(Ordering::Less) => { + atom!("<") + } + }; - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - idiv(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Abs(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + self.unify_atom(atom, a1); + Ok(()) + } - self.machine_st.interms[t - 1] = abs(n1, &mut self.machine_st.arena); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Sign(ref a1, t) => { - let n = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { + let old_h = self.heap.len(); - self.machine_st.interms[t - 1] = sign(n); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Neg(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let a1 = self.registers[1]; + let a2 = self.registers[2]; - self.machine_st.interms[t - 1] = neg(n1, &mut self.machine_st.arena); - self.machine_st.p += 1; - } - &ArithmeticInstruction::BitwiseComplement(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + copy_term(CopyTerm::new(self), a1, attr_var_policy); - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - bitwise_complement(n1, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Div(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + unify_fn!(*self, heap_loc_as_cell!(old_h), a2); + } - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - div(n1, n2) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Shr(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + fn sort(&mut self) -> CallResult { + self.check_sort_errors()?; - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - shr(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Shl(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + let stub_gen = || functor_stub(atom!("sort"), 2); + let mut list = self.try_from_list(self.registers[1], stub_gen)?; - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - shl(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Xor(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + list.sort_unstable_by(|v1, v2| { + compare_term_test!(self, *v1, *v2).unwrap_or(Ordering::Less) + }); - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - xor(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::And(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + list.dedup_by(|v1, v2| { + compare_term_test!(self, *v1, *v2) == Some(Ordering::Equal) + }); - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - and(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Or(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + let heap_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, list.into_iter()) + ); - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - or(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Mod(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + let target_addr = self.registers[2]; - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - modulus(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Rem(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + unify_fn!(*self, target_addr, heap_addr); + Ok(()) + } - self.machine_st.interms[t - 1] = try_or_fail_gen!( - &mut self.machine_st, - remainder(n1, n2, &mut self.machine_st.arena) - ); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Cos(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + fn keysort(&mut self) -> CallResult { + self.check_keysort_errors()?; - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, cos(n1)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Sin(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let stub_gen = || functor_stub(atom!("keysort"), 2); + let list = self.try_from_list(self.registers[1], stub_gen)?; - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, sin(n1)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Tan(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let mut key_pairs = Vec::with_capacity(list.len()); - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, tan(n1)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Sqrt(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + for val in list { + let key = self.project_onto_key(val)?; + key_pairs.push((key, val)); + } - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, sqrt(n1)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Log(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + key_pairs.sort_by(|a1, a2| { + compare_term_test!(self, a1.0, a2.0).unwrap_or(Ordering::Less) + }); - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, log(n1)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Exp(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let key_pairs = key_pairs.into_iter().map(|kp| kp.1); + let heap_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut self.heap, key_pairs) + ); - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, exp(n1)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::ACos(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + let target_addr = self.registers[2]; - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, acos(n1)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::ASin(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + unify_fn!(*self, target_addr, heap_addr); + Ok(()) + } - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, asin(n1)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::ATan(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + fn is(&mut self, r: RegType, at: ArithmeticTerm) -> CallResult { + let n1 = self.store(self.deref(self[r])); - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, atan(n1)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::ATan2(ref a1, ref a2, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2)); + match self.get_number(&at)? { + Number::Fixnum(n) => self.unify_fixnum(n, n1), + Number::Float(n) => { + // TODO: argghh.. allocate floats to their own area. + let n = arena_alloc!(n, &mut self.arena); + self.unify_f64(n, n1) + } + Number::Integer(n) => self.unify_big_int(n, n1), + Number::Rational(n) => self.unify_rational(n, n1), + } - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, atan2(n1, n2)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Float(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + Ok(()) + } +} - self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( - try_or_fail_gen!(&mut self.machine_st, float(n1)) - )); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Truncate(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); +impl Machine { + fn read(&mut self) -> CallResult { + let stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("read"), + 2, + )?; + + match self.machine_st.read(stream, &self.indices.op_dir) { + Ok(offset) => { + let value = self.machine_st.registers[2]; + unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc)); + } + Err(ParserError::UnexpectedEOF) => { + let value = self.machine_st.registers[2]; + self.machine_st.unify_atom(atom!("end_of_file"), value); + } + Err(e) => { + let stub = functor_stub(atom!("read"), 2); + let err = self.machine_st.syntax_error(e); - self.machine_st.interms[t - 1] = truncate(n1, &mut self.machine_st.arena); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Round(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + return Err(self.machine_st.error_form(err, stub)); + } + }; - self.machine_st.interms[t - 1] = - try_or_fail_gen!(&mut self.machine_st, round(n1, &mut self.machine_st.arena)); - self.machine_st.p += 1; - } - &ArithmeticInstruction::Ceiling(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); + Ok(()) + } - self.machine_st.interms[t - 1] = ceiling(n1, &mut self.machine_st.arena); - self.machine_st.p += 1; + pub(super) fn find_living_dynamic_else(&self, mut p: usize) -> Option<(usize, usize)> { + loop { + match &self.code[p] { + &Instruction::DynamicElse( + birth, + death, + NextOrFail::Next(i), + ) => { + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { + return Some((p, i)); + } else if i > 0 { + p += i; + } else { + return None; } - &ArithmeticInstruction::Floor(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - - self.machine_st.interms[t - 1] = floor(n1, &mut self.machine_st.arena); - self.machine_st.p += 1; + } + &Instruction::DynamicElse( + birth, + death, + NextOrFail::Fail(_), + ) => { + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { + return Some((p, 0)); + } else { + return None; } - &ArithmeticInstruction::Plus(ref a1, t) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1)); - - self.machine_st.interms[t - 1] = n1; - self.machine_st.p += 1; + } + &Instruction::DynamicInternalElse( + birth, + death, + NextOrFail::Next(i), + ) => { + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { + return Some((p, i)); + } else if i > 0 { + p += i; + } else { + return None; + } + } + &Instruction::DynamicInternalElse( + birth, + death, + NextOrFail::Fail(_), + ) => { + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { + return Some((p, 0)); + } else { + return None; } } + &Instruction::RevJmpBy(i) => { + p -= i; + } + _ => { + unreachable!(); + } } - &Line::Choice(ref choice_instr) => { - match choice_instr { - &ChoiceInstruction::DynamicElse(..) => { - if let FirstOrNext::First = self.machine_st.dynamic_mode { - self.machine_st.cc = self.machine_st.global_clock; - } - - let p = self.machine_st.p.local().abs_loc(); + } + } - match self.find_living_dynamic_else(p) { - Some((p, next_i)) => { - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> { + let p = self.machine_st.p; - match self.machine_st.dynamic_mode { - FirstOrNext::First if next_i == 0 => { - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1)); - } - FirstOrNext::First => { - self.machine_st.cc = self.machine_st.global_clock; + let indexed_choice_instrs = match &self.code[p] { + Instruction::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] { + IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => { + indexed_choice_instrs + } + _ => unreachable!(), + }, + _ => unreachable!(), + }; + + loop { + match &indexed_choice_instrs.get(ii as usize) { + Some(&offset) => match &self.code[p + offset - 1] { + &Instruction::DynamicInternalElse( + birth, + death, + next_or_fail, + ) => { + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { + return Some((offset, oi, ii, next_or_fail.is_next())); + } else { + ii += 1; + } + } + _ => unreachable!(), + }, + None => return None, + } + } + } - match self.find_living_dynamic_else(p + next_i) { - Some(_) => { - self.machine_st.registers[self.machine_st.num_of_args + 1] = - fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); + #[inline(always)] + fn execute_switch_on_term(&mut self) { + #[inline(always)] + fn dynamic_external_of_clause_is_valid(machine: &mut Machine, p: usize) -> bool { + match &machine.code[p] { + Instruction::DynamicInternalElse(..) => { + machine.machine_st.dynamic_mode = FirstOrNext::First; + return true; + } + _ => {} + } - self.machine_st.num_of_args += 1; - self.machine_st.try_me_else(next_i); - self.machine_st.num_of_args -= 1; - } - None => { - self.machine_st.p += 1; - } - } - } - FirstOrNext::Next => { - let n = self.machine_st - .stack - .index_or_frame(self.machine_st.b) - .prelude - .univ_prelude - .num_cells; - - self.machine_st.cc = cell_as_fixnum!( - self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)] - ).get_num() as usize; - - if next_i > 0 { - match self.find_living_dynamic_else(p + next_i) { - Some(_) => { - self.retry_me_else(next_i); + match &machine.code[p - 1] { + &Instruction::DynamicInternalElse(birth, death, _) => { + if birth < machine.machine_st.cc && Death::Finite(machine.machine_st.cc) <= death { + return true; + } else { + return false; + } + } + _ => {} + } - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - None => { - self.trust_me(); + true + } - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - } - } else { - self.trust_me(); + let indexing_lines = self.code[self.machine_st.p].to_indexing_line_mut().unwrap(); - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - } + let mut index = 0; + let addr = match &indexing_lines[0] { + &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => { + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[arg])) + } + _ => { + unreachable!() + } + }; + + loop { + match &indexing_lines[index] { + &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => { + let offset = read_heap_cell!(addr, + (HeapCellValueTag::Var | + HeapCellValueTag::StackVar | + HeapCellValueTag::AttrVar) => { + v + } + (HeapCellValueTag::PStrLoc | + HeapCellValueTag::Lis | + HeapCellValueTag::CStr) => { + l + } + (HeapCellValueTag::Fixnum | + HeapCellValueTag::Char | + HeapCellValueTag::F64) => { + c + } + (HeapCellValueTag::Atom, (_name, arity)) => { + // if arity == 0 { c } else { s } + debug_assert!(arity == 0); + c + } + (HeapCellValueTag::Str) => { + s + } + (HeapCellValueTag::Cons, ptr) => { + match ptr.get_tag() { + ArenaHeaderTag::Rational | ArenaHeaderTag::Integer | + ArenaHeaderTag::F64 => { + c + } + _ => { + IndexingCodePtr::Fail } - } - None => { - self.machine_st.fail = true; } } + _ => { + unreachable!(); + } + ); - self.machine_st.dynamic_mode = FirstOrNext::Next; - } - &ChoiceInstruction::DynamicInternalElse(..) => { - let p = self.machine_st.p.local().abs_loc(); - - match self.find_living_dynamic_else(p) { - Some((p, next_i)) => { - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + match offset { + IndexingCodePtr::Fail => { + self.machine_st.fail = true; + break; + } + IndexingCodePtr::DynamicExternal(o) => { + // either points directly to a + // DynamicInternalElse, or just ahead of + // one. Or neither! + let p = self.machine_st.p; - match self.machine_st.dynamic_mode { - FirstOrNext::First if next_i == 0 => { - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1)); - } - FirstOrNext::First => { - match self.find_living_dynamic_else(p + next_i) { - Some(_) => { - self.machine_st.registers[self.machine_st.num_of_args + 1] = - fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); + if !dynamic_external_of_clause_is_valid(self, p + o) { + self.machine_st.fail = true; + } else { + self.machine_st.p += o; + } - self.machine_st.num_of_args += 1; - self.machine_st.try_me_else(next_i); - self.machine_st.num_of_args -= 1; - } - None => { - self.machine_st.p += 1; - } - } - } - FirstOrNext::Next => { - let n = self.machine_st - .stack - .index_or_frame(self.machine_st.b) - .prelude - .univ_prelude - .num_cells; - - self.machine_st.cc = cell_as_fixnum!( - self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)] - ).get_num() as usize; - - if next_i > 0 { - match self.find_living_dynamic_else(p + next_i) { - Some(_) => { - self.retry_me_else(next_i); + break; + } + IndexingCodePtr::External(o) => { + self.machine_st.p += o; + break; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + } + } + &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => { + let lit = read_heap_cell!(addr, + (HeapCellValueTag::Char, c) => { + Literal::Char(c) + } + (HeapCellValueTag::Fixnum, n) => { + Literal::Fixnum(n) + } + (HeapCellValueTag::F64, f) => { + Literal::Float(f) + } + (HeapCellValueTag::Atom, (atom, arity)) => { + debug_assert_eq!(arity, 0); + Literal::Atom(atom) + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Rational, r) => { + Literal::Rational(r) + } + (ArenaHeaderTag::F64, f) => { + Literal::Float(F64Ptr(f)) + } + (ArenaHeaderTag::Integer, n) => { + Literal::Integer(n) + } + _ => { + unreachable!() + } + ) + } + _ => { + unreachable!() + } + ); - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - None => { - self.trust_me(); + let offset = match hm.get(&lit) { + Some(offset) => *offset, + _ => IndexingCodePtr::Fail, + }; - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - } - } else { - self.trust_me(); + match offset { + IndexingCodePtr::Fail => { + self.machine_st.fail = true; + break; + } + IndexingCodePtr::DynamicExternal(o) => { + // either points directly to a + // DynamicInternalElse, or just ahead of + // one. Or neither! + let p = self.machine_st.p; - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - } - } - } - None => { + if !dynamic_external_of_clause_is_valid(self, p + o) { self.machine_st.fail = true; + } else { + self.machine_st.p += o; } - } - - self.machine_st.dynamic_mode = FirstOrNext::Next; - } - &ChoiceInstruction::TryMeElse(offset) => { - self.machine_st.try_me_else(offset); - } - &ChoiceInstruction::DefaultRetryMeElse(offset) => { - self.retry_me_else(offset); - } - &ChoiceInstruction::DefaultTrustMe(_) => { - self.trust_me(); - } - &ChoiceInstruction::RetryMeElse(offset) => { - self.retry_me_else(offset); - - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - &ChoiceInstruction::TrustMe(_) => { - self.trust_me(); - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); + break; + } + IndexingCodePtr::External(o) => { + self.machine_st.p += o; + break; + } + IndexingCodePtr::Internal(o) => { + index += o; + } } } - } - &Line::Cut(ref cut_instr) => { - match cut_instr { - &CutInstruction::NeckCut => { - let b = self.machine_st.b; - let b0 = self.machine_st.b0; - - if b > b0 { - self.machine_st.b = b0; + &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => { + let offset = read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, arity)) => { + match hm.get(&(name, arity)) { + Some(offset) => *offset, + None => IndexingCodePtr::Fail, + } + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) + .get_name_and_arity(); - if b > self.machine_st.e { - self.machine_st.stack.truncate(b); + match hm.get(&(name, arity)) { + Some(offset) => *offset, + None => IndexingCodePtr::Fail, } } + _ => { + IndexingCodePtr::Fail + } + ); - self.machine_st.p += 1; - } - &CutInstruction::GetLevel(r) => { - let b0 = self.machine_st.b0; - - self.machine_st[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64)); - self.machine_st.p += 1; - } - &CutInstruction::GetLevelAndUnify(r) => { - let b0 = self.machine_st[perm_v!(1)]; - let a = self.machine_st[r]; + match offset { + IndexingCodePtr::Fail => { + self.machine_st.fail = true; + break; + } + IndexingCodePtr::DynamicExternal(o) => { + let p = self.machine_st.p; - unify_fn!(&mut self.machine_st, a, b0); - self.machine_st.p += 1; - } - &CutInstruction::Cut(r) => { - let value = self.machine_st[r]; - self.machine_st.cut_body(value); + if !dynamic_external_of_clause_is_valid(self, p + o) { + self.machine_st.fail = true; + } else { + self.machine_st.p += o; + } - if !self.machine_st.fail && !(self.machine_st.run_cleaners_fn)(self) { - self.machine_st.p += 1; + break; + } + IndexingCodePtr::External(o) => { + self.machine_st.p += o; + break; + } + IndexingCodePtr::Internal(o) => { + index += o; } } } + &IndexingLine::IndexedChoice(_) => { + self.machine_st.oip = index as u32; + self.machine_st.iip = 0; + + break; + } + &IndexingLine::DynamicIndexedChoice(_) => { + self.machine_st.dynamic_mode = FirstOrNext::First; + + self.machine_st.oip = index as u32; + self.machine_st.iip = 0; + + break; + } } - &Line::Control(ref ctrl_instr) => { - match ctrl_instr { - &ControlInstruction::Allocate(num_cells) => - self.machine_st.allocate(num_cells), - &ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) => { - let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); - - match INTERRUPT.compare_exchange( - interrupted, - false, - std::sync::atomic::Ordering::Relaxed, - std::sync::atomic::Ordering::Relaxed, - ) { - Ok(interruption) => { - if interruption { - self.machine_st.throw_interrupt_exception(); - return; - } - } - Err(_) => unreachable!(), - } + } + } - self.machine_st.last_call = lco; + #[inline(always)] + pub(super) fn dispatch_loop(&mut self) { + 'outer: loop { + for _ in 0 .. INSTRUCTIONS_PER_INTERRUPT_POLL { + match &self.code[self.machine_st.p] { + &Instruction::BreakFromDispatchLoop => { + break 'outer; + } + &Instruction::InstallVerifyAttr => { + self.machine_st.p = self.machine_st.attr_var_init.p; - match ct { - &ClauseType::BuiltIn(ref ct) => { - let ct = ct.clone(); + if self.code[self.machine_st.p].is_execute() { + self.machine_st.p = self.machine_st.attr_var_init.cp; + } else { + self.machine_st.p += 1; + self.machine_st.cp = self.machine_st.attr_var_init.cp; + } - try_or_fail!( - self.machine_st, - self.call_builtin(&ct) - ); + let mut p = self.machine_st.p; - if !use_default_cp { - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - } - &ClauseType::CallN => { - try_or_fail!( - self.machine_st, - self.call_n(atom!("user"), arity) - ); - - if !use_default_cp { - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - } - &ClauseType::Inlined(ref ct) => { - let ct = ct.clone(); - self.execute_inlined(&ct); + while self.code[p].is_head_instr() { + p += 1; + } - if lco { - self.machine_st.p = CodePtr::Local(self.machine_st.cp); - } - } - &ClauseType::Named(name, _, ref idx) => { - let idx = idx.clone(); + let instr = std::mem::replace( + &mut self.code[p], + Instruction::VerifyAttrInterrupt, + ); - try_or_fail!( - self.machine_st, - self.context_call(name, arity, idx) // TODO: change to idx.get() ??? - ); + self.code[VERIFY_ATTR_INTERRUPT_LOC] = instr; + self.machine_st.attr_var_init.cp = p; + } + &Instruction::VerifyAttrInterrupt => { + self.run_verify_attr_interrupt(); + } + &Instruction::Add(ref a1, ref a2, t) => { + let stub_gen = || functor_stub(atom!("is"), 2); - if !use_default_cp { - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - } - &ClauseType::System(ref ct) => { - let ct = ct.clone(); + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - try_or_fail!( - self.machine_st, - self.system_call(&ct) - ); - } - }; + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + try_numeric_result!(add(n1, n2, &mut self.machine_st.arena), stub_gen) + ); - self.machine_st.last_call = false; - } - &ControlInstruction::Deallocate => - self.machine_st.deallocate(), - &ControlInstruction::JmpBy(arity, offset, _, lco) => { - if !lco { - self.machine_st.cp.assign_if_local(self.machine_st.p.clone() + 1); - } + self.machine_st.p += 1; + } + &Instruction::Sub(ref a1, ref a2, t) => { + let stub_gen = || functor_stub(atom!("is"), 2); - self.machine_st.num_of_args = arity; - self.machine_st.b0 = self.machine_st.b; - self.machine_st.p += offset; - } - &ControlInstruction::RevJmpBy(offset) => { - self.machine_st.p -= offset; - } - &ControlInstruction::Proceed => { - self.machine_st.p = CodePtr::Local(self.machine_st.cp); - } + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen) + ); + self.machine_st.p += 1; } - } - &Line::Fact(ref fact_instr) => { - match fact_instr { - &FactInstruction::GetConstant(_, c, reg) => { - let value = self.machine_st.deref(self.machine_st[reg]); - self.machine_st.write_literal_to_var(value, c); - } - &FactInstruction::GetList(_, reg) => { - let deref_v = self.machine_st.deref(self.machine_st[reg]); - let store_v = self.machine_st.store(deref_v); - - read_heap_cell!(store_v, - (HeapCellValueTag::PStrLoc, h) => { - let (h, n) = pstr_loc_and_offset(&self.machine_st.heap, h); - - self.machine_st.s = HeapPtr::PStrChar(h, n.get_num() as usize); - self.machine_st.mode = MachineMode::Read; - } - (HeapCellValueTag::CStr) => { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(store_v); + &Instruction::Mul(ref a1, ref a2, t) => { + let stub_gen = || functor_stub(atom!("is"), 2); - self.machine_st.s = HeapPtr::PStrChar(h, 0); - self.machine_st.mode = MachineMode::Read; - } - (HeapCellValueTag::Lis, l) => { - self.machine_st.s = HeapPtr::HeapCell(l); - self.machine_st.mode = MachineMode::Read; - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - let h = self.machine_st.heap.len(); + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - self.machine_st.heap.push(list_loc_as_cell!(h+1)); - self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + try_numeric_result!(mul(n1, n2, &mut self.machine_st.arena), stub_gen) + ); - self.machine_st.mode = MachineMode::Write; - } - _ => { - self.machine_st.fail = true; - } - ); - } - &FactInstruction::GetPartialString(_, string, reg, has_tail) => { - let deref_v = self.machine_st.deref(self.machine_st[reg]); - let store_v = self.machine_st.store(deref_v); + self.machine_st.p += 1; + } + &Instruction::Max(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - read_heap_cell!(store_v, - (HeapCellValueTag::Str | HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar | - HeapCellValueTag::StackVar | HeapCellValueTag::Var | - HeapCellValueTag::CStr) => { - self.machine_st.match_partial_string(store_v, string, has_tail); - } - _ => { - self.machine_st.fail = true; - } - ); - } - &FactInstruction::GetStructure(ref ct, arity, reg) => { - let deref_v = self.machine_st.deref(self.machine_st[reg]); - let store_v = self.machine_st.store(deref_v); - - read_heap_cell!(store_v, - (HeapCellValueTag::Str, a) => { - let result = self.machine_st.heap[a]; - - read_heap_cell!(result, - (HeapCellValueTag::Atom, (name, narity)) => { - if narity == arity && ct.name() == name { - self.machine_st.s = HeapPtr::HeapCell(a + 1); - self.machine_st.mode = MachineMode::Read; - } else { - self.machine_st.fail = true; - } - } - _ => { - unreachable!(); - } - ); - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - let h = self.machine_st.heap.len(); + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + max(n1, n2) + ); - self.machine_st.heap.push(str_loc_as_cell!(h+1)); - self.machine_st.heap.push(atom_as_cell!(ct.name(), arity)); + self.machine_st.p += 1; + } + &Instruction::Min(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + min(n1, n2) + ); - self.machine_st.mode = MachineMode::Write; - } - _ => { - self.machine_st.fail = true; - } - ); - } - &FactInstruction::GetVariable(norm, arg) => { - self.machine_st[norm] = self.machine_st.registers[arg]; - } - &FactInstruction::GetValue(norm, arg) => { - let norm_addr = self.machine_st[norm]; - let reg_addr = self.machine_st.registers[arg]; + self.machine_st.p += 1; + } + &Instruction::IntPow(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - unify_fn!(&mut self.machine_st, norm_addr, reg_addr); - } - &FactInstruction::UnifyConstant(v) => { - match self.machine_st.mode { - MachineMode::Read => { - let addr = self.machine_st.read_s(); + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + int_pow(n1, n2, &mut self.machine_st.arena) + ); - self.machine_st.write_literal_to_var(addr, v); - self.machine_st.increment_s_ptr(1); - } - MachineMode::Write => { - self.machine_st.heap.push(v); - } - }; - } - &FactInstruction::UnifyVariable(reg) => { - match self.machine_st.mode { - MachineMode::Read => { - self.machine_st[reg] = self.machine_st.read_s(); - self.machine_st.increment_s_ptr(1); - } - MachineMode::Write => { - let h = self.machine_st.heap.len(); + self.machine_st.p += 1; + } + &Instruction::Gcd(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - self.machine_st.heap.push(heap_loc_as_cell!(h)); - self.machine_st[reg] = heap_loc_as_cell!(h); - } - }; - } - &FactInstruction::UnifyLocalValue(reg) => { - match self.machine_st.mode { - MachineMode::Read => { - let reg_addr = self.machine_st[reg]; - let value = self.machine_st.read_s(); + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + gcd(n1, n2, &mut self.machine_st.arena) + ); - unify_fn!(&mut self.machine_st, reg_addr, value); - self.machine_st.increment_s_ptr(1); - } - MachineMode::Write => { - let value = self.machine_st.store(self.machine_st.deref(self.machine_st[reg])); - let h = self.machine_st.heap.len(); + self.machine_st.p += 1; + } + &Instruction::Pow(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - read_heap_cell!(value, - (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => { - let value = self.machine_st.heap[hc]; + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + pow(n1, n2, atom!("**")) + ); - self.machine_st.heap.push(value); - self.machine_st.increment_s_ptr(1); - } - _ => { - self.machine_st.heap.push(heap_loc_as_cell!(h)); - (self.machine_st.bind_fn)( - &mut self.machine_st, - Ref::heap_cell(h), - value, - ); - } - ); - } - }; - } - &FactInstruction::UnifyValue(reg) => { - match self.machine_st.mode { - MachineMode::Read => { - let reg_addr = self.machine_st[reg]; - let value = self.machine_st.read_s(); + self.machine_st.p += 1; + } + &Instruction::RDiv(ref a1, ref a2, t) => { + let stub_gen = || functor_stub(atom!("(rdiv)"), 2); - unify_fn!(&mut self.machine_st, reg_addr, value); - self.machine_st.increment_s_ptr(1); - } - MachineMode::Write => { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + let r1 = try_or_throw!(self.machine_st, self.machine_st.get_rational(a1, stub_gen)); + let r2 = try_or_throw!(self.machine_st, self.machine_st.get_rational(a2, stub_gen)); - let addr = self.machine_st.store(self.machine_st[reg]); - (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr); + self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!( + try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)), + self.machine_st.arena + )); - // the former code of this match arm was: + self.machine_st.p += 1; + } + &Instruction::IntFloorDiv(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + int_floor_div(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &Instruction::IDiv(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + idiv(n1, n2, &mut self.machine_st.arena) + ); + self.machine_st.p += 1; + } + &Instruction::Abs(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); - // let addr = self.machine_st.store(self.machine_st[reg]); - // self.machine_st.heap.push(HeapCellValue::Addr(addr)); + self.machine_st.interms[t - 1] = abs(n1, &mut self.machine_st.arena); + self.machine_st.p += 1; + } + &Instruction::Sign(ref a1, t) => { + let n = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); - // the old code didn't perform the occurs - // check when enabled and so it was changed to - // the above, which is only slightly less - // efficient when the occurs_check is disabled. - } - }; - } - &FactInstruction::UnifyVoid(n) => { - match self.machine_st.mode { - MachineMode::Read => { - self.machine_st.increment_s_ptr(n); - } - MachineMode::Write => { - let h = self.machine_st.heap.len(); + self.machine_st.interms[t - 1] = sign(n); + self.machine_st.p += 1; + } + &Instruction::Neg(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); - for i in h..h + n { - self.machine_st.heap.push(heap_loc_as_cell!(i)); - } - } - }; - } + self.machine_st.interms[t - 1] = neg(n1, &mut self.machine_st.arena); + self.machine_st.p += 1; } - self.machine_st.p += 1; - } - &Line::IndexingCode(ref indexing_lines) => { - #[inline(always)] - fn dynamic_external_of_clause_is_valid(machine: &mut Machine, p: usize) -> bool { - match &machine.code_repo.code[p] { - Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => { - machine.machine_st.dynamic_mode = FirstOrNext::First; - return true; - } - _ => {} - } + &Instruction::BitwiseComplement(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); - match &machine.code_repo.code[p - 1] { - &Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => { - if birth < machine.machine_st.cc && Death::Finite(machine.machine_st.cc) <= death { - return true; - } else { - return false; - } - } - _ => {} - } + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + bitwise_complement(n1, &mut self.machine_st.arena) + ); - true + self.machine_st.p += 1; } + &Instruction::Div(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - let mut index = 0; - let addr = match &indexing_lines[0] { - &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => { - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[arg])) - } - _ => { - unreachable!() - } - }; - - loop { - match &indexing_lines[index] { - &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => { - let offset = read_heap_cell!(addr, - (HeapCellValueTag::Var | - HeapCellValueTag::StackVar | - HeapCellValueTag::AttrVar) => { - v - } - (HeapCellValueTag::PStrLoc | - HeapCellValueTag::Lis | - HeapCellValueTag::CStr) => { - l - } - (HeapCellValueTag::Fixnum | - HeapCellValueTag::Char | - HeapCellValueTag::F64) => { - c - } - (HeapCellValueTag::Atom, (_name, arity)) => { - // if arity == 0 { c } else { s } - debug_assert!(arity == 0); - c - } - (HeapCellValueTag::Str) => { - s - } - (HeapCellValueTag::Cons, ptr) => { - match ptr.get_tag() { - ArenaHeaderTag::Rational | ArenaHeaderTag::Integer | - ArenaHeaderTag::F64 => { - c - } - _ => { - IndexingCodePtr::Fail - } - } - } - _ => { - unreachable!(); - } - ); + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + div(n1, n2) + ); - match offset { - IndexingCodePtr::Fail => { - self.machine_st.fail = true; - break; - } - IndexingCodePtr::DynamicExternal(o) => { - // either points directly to a - // DynamicInternalElse, or just ahead of - // one. Or neither! - let p = self.machine_st.p.local().abs_loc(); - - if !dynamic_external_of_clause_is_valid(self, p + o) { - self.machine_st.fail = true; - } else { - self.machine_st.p += o; - } + self.machine_st.p += 1; + } + &Instruction::Shr(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - break; - } - IndexingCodePtr::External(o) => { - self.machine_st.p += o; - break; - } - IndexingCodePtr::Internal(o) => { - index += o; - } - } - } - &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => { - let lit = read_heap_cell!(addr, - (HeapCellValueTag::Char, c) => { - Literal::Char(c) - } - (HeapCellValueTag::Fixnum, n) => { - Literal::Fixnum(n) - } - (HeapCellValueTag::F64, f) => { - Literal::Float(f) - } - (HeapCellValueTag::Atom, (atom, arity)) => { - debug_assert_eq!(arity, 0); - Literal::Atom(atom) - } - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::Rational, r) => { - Literal::Rational(r) - } - (ArenaHeaderTag::F64, f) => { - Literal::Float(F64Ptr(f)) - } - (ArenaHeaderTag::Integer, n) => { - Literal::Integer(n) - } - _ => { - unreachable!() - } - ) - } - _ => { - unreachable!() - } - ); + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + shr(n1, n2, &mut self.machine_st.arena) + ); - let offset = match hm.get(&lit) { - Some(offset) => *offset, - _ => IndexingCodePtr::Fail, - }; + self.machine_st.p += 1; + } + &Instruction::Shl(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - match offset { - IndexingCodePtr::Fail => { - self.machine_st.fail = true; - break; - } - IndexingCodePtr::DynamicExternal(o) => { - // either points directly to a - // DynamicInternalElse, or just ahead of - // one. Or neither! - let p = self.machine_st.p.local().abs_loc(); - - if !dynamic_external_of_clause_is_valid(self, p + o) { - self.machine_st.fail = true; - } else { - self.machine_st.p += o; - } + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + shl(n1, n2, &mut self.machine_st.arena) + ); - break; - } - IndexingCodePtr::External(o) => { - self.machine_st.p += o; - break; - } - IndexingCodePtr::Internal(o) => { - index += o; - } - } - } - &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => { - let offset = read_heap_cell!(addr, - (HeapCellValueTag::Atom, (name, arity)) => { - match hm.get(&(name, arity)) { - Some(offset) => *offset, - None => IndexingCodePtr::Fail, - } - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) - .get_name_and_arity(); + self.machine_st.p += 1; + } + &Instruction::Xor(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - match hm.get(&(name, arity)) { - Some(offset) => *offset, - None => IndexingCodePtr::Fail, - } - } - _ => { - IndexingCodePtr::Fail - } - ); + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + xor(n1, n2, &mut self.machine_st.arena) + ); - match offset { - IndexingCodePtr::Fail => { - self.machine_st.fail = true; - break; - } - IndexingCodePtr::DynamicExternal(o) => { - let p = self.machine_st.p.local().abs_loc(); + self.machine_st.p += 1; + } + &Instruction::And(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - if !dynamic_external_of_clause_is_valid(self, p + o) { - self.machine_st.fail = true; - } else { - self.machine_st.p += o; - } + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + and(n1, n2, &mut self.machine_st.arena) + ); - break; - } - IndexingCodePtr::External(o) => { - self.machine_st.p += o; - break; - } - IndexingCodePtr::Internal(o) => { - index += o; - } - } - } - &IndexingLine::IndexedChoice(_) => { - if let LocalCodePtr::DirEntry(p) = self.machine_st.p.local() { - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); - self.machine_st.oip = index as u32; - self.machine_st.iip = 0; - } else { - unreachable!() - } + self.machine_st.p += 1; + } + &Instruction::Or(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - break; - } - &IndexingLine::DynamicIndexedChoice(_) => { - self.machine_st.dynamic_mode = FirstOrNext::First; + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + or(n1, n2, &mut self.machine_st.arena) + ); - if let LocalCodePtr::DirEntry(p) = self.machine_st.p.local() { - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); - self.machine_st.oip = index as u32; - self.machine_st.iip = 0; - } else { - unreachable!() - } + self.machine_st.p += 1; + } + &Instruction::Mod(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - break; - } - } + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + modulus(n1, n2, &mut self.machine_st.arena) + ); + + self.machine_st.p += 1; } - } - &Line::IndexedChoice(ref choice_instr) => { - match choice_instr { - &IndexedChoiceInstruction::Try(offset) => { - self.machine_st.indexed_try(offset); - } - &IndexedChoiceInstruction::Retry(l) => { - self.retry(l); + &Instruction::Rem(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - &IndexedChoiceInstruction::Trust(l) => { - self.trust(l); + self.machine_st.interms[t - 1] = try_or_throw_gen!( + &mut self.machine_st, + remainder(n1, n2, &mut self.machine_st.arena) + ); - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } + self.machine_st.p += 1; } - } - &Line::DynamicIndexedChoice(_) => self.execute_dynamic_indexed_choice_instr(), - &Line::Query(ref query_instr) => { - match query_instr { - &QueryInstruction::GetVariable(norm, arg) => { - self.machine_st[norm] = self.machine_st.registers[arg]; - } - &QueryInstruction::PutConstant(_, c, reg) => { - self.machine_st[reg] = c; - } - &QueryInstruction::PutList(_, reg) => { - self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.len()); - } - &QueryInstruction::PutPartialString(_, string, reg, has_tail) => { - let pstr_addr = if has_tail { - if string != atom!("") { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(string_as_pstr_cell!(string)); + &Instruction::Cos(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); - // the tail will be pushed by the next - // instruction, so don't push one here. + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, cos(n1)) + )); - pstr_loc_as_cell!(h) - } else { - empty_list_as_cell!() - } - } else { - string_as_cstr_cell!(string) - }; + self.machine_st.p += 1; + } + &Instruction::Sin(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); - self.machine_st[reg] = pstr_addr; - } - &QueryInstruction::PutStructure(ref ct, arity, reg) => { - let h = self.machine_st.heap.len(); + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, sin(n1)) + )); - self.machine_st.heap.push(atom_as_cell!(ct.name(), arity)); - self.machine_st[reg] = str_loc_as_cell!(h); - } - &QueryInstruction::PutUnsafeValue(n, arg) => { - let s = stack_loc!(AndFrame, self.machine_st.e, n); - let addr = self.machine_st.store(self.machine_st.deref(stack_loc_as_cell!(s))); + self.machine_st.p += 1; + } + &Instruction::Tan(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); - if addr.is_protected(self.machine_st.e) { - self.machine_st.registers[arg] = addr; - } else { - let h = self.machine_st.heap.len(); + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, tan(n1)) + )); - self.machine_st.heap.push(heap_loc_as_cell!(h)); - (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr); + self.machine_st.p += 1; + } + &Instruction::Sqrt(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); - self.machine_st.registers[arg] = heap_loc_as_cell!(h); - } - } - &QueryInstruction::PutValue(norm, arg) => { - self.machine_st.registers[arg] = self.machine_st[norm]; - } - &QueryInstruction::PutVariable(norm, arg) => { - match norm { - RegType::Perm(n) => { - self.machine_st[norm] = stack_loc_as_cell!(AndFrame, self.machine_st.e, n); - self.machine_st.registers[arg] = self.machine_st[norm]; - } - RegType::Temp(_) => { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, sqrt(n1)) + )); - self.machine_st[norm] = heap_loc_as_cell!(h); - self.machine_st.registers[arg] = heap_loc_as_cell!(h); - } - }; - } - &QueryInstruction::SetConstant(c) => { - self.machine_st.heap.push(c); - } - &QueryInstruction::SetLocalValue(reg) => { - let addr = self.machine_st.deref(self.machine_st[reg]); - let stored_v = self.machine_st.store(addr); + self.machine_st.p += 1; + } + &Instruction::Log(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); - if stored_v.is_stack_var() { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); - (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), stored_v); - } else { - self.machine_st.heap.push(stored_v); - } - } - &QueryInstruction::SetVariable(reg) => { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); - self.machine_st[reg] = heap_loc_as_cell!(h); - } - &QueryInstruction::SetValue(reg) => { - let heap_val = self.machine_st.store(self.machine_st[reg]); - self.machine_st.heap.push(heap_val); - } - &QueryInstruction::SetVoid(n) => { - let h = self.machine_st.heap.len(); + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, log(n1)) + )); - for i in h..h + n { - self.machine_st.heap.push(heap_loc_as_cell!(i)); - } - } + self.machine_st.p += 1; } + &Instruction::Exp(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); - self.machine_st.p += 1; - } + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, exp(n1)) + )); + + self.machine_st.p += 1; + } + &Instruction::ACos(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, acos(n1)) + )); + + self.machine_st.p += 1; + } + &Instruction::ASin(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, asin(n1)) + )); + + self.machine_st.p += 1; + } + &Instruction::ATan(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, atan(n1)) + )); + + self.machine_st.p += 1; + } + &Instruction::ATan2(ref a1, ref a2, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, atan2(n1, n2)) + )); + + self.machine_st.p += 1; + } + &Instruction::Float(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = Number::Float(OrderedFloat( + try_or_throw_gen!(&mut self.machine_st, float(n1)) + )); + + self.machine_st.p += 1; + } + &Instruction::Truncate(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = truncate(n1, &mut self.machine_st.arena); + self.machine_st.p += 1; + } + &Instruction::Round(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = + try_or_throw_gen!(&mut self.machine_st, round(n1, &mut self.machine_st.arena)); + + self.machine_st.p += 1; + } + &Instruction::Ceiling(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = ceiling(n1, &mut self.machine_st.arena); + self.machine_st.p += 1; + } + &Instruction::Floor(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = floor(n1, &mut self.machine_st.arena); + self.machine_st.p += 1; + } + &Instruction::Plus(ref a1, t) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1)); + + self.machine_st.interms[t - 1] = n1; + self.machine_st.p += 1; + } + &Instruction::DynamicElse(..) => { + if let FirstOrNext::First = self.machine_st.dynamic_mode { + self.machine_st.cc = self.machine_st.global_clock; + } + + let p = self.machine_st.p; + + match self.find_living_dynamic_else(p) { + Some((p, next_i)) => { + self.machine_st.p = p; + + match self.machine_st.dynamic_mode { + FirstOrNext::First if next_i == 0 => { + self.machine_st.p += 1; + } + FirstOrNext::First => { + self.machine_st.cc = self.machine_st.global_clock; + + match self.find_living_dynamic_else(p + next_i) { + Some(_) => { + self.machine_st.registers[self.machine_st.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); + + self.machine_st.num_of_args += 1; + self.machine_st.try_me_else(next_i); + self.machine_st.num_of_args -= 1; + } + None => { + self.machine_st.p += 1; + } + } + } + FirstOrNext::Next => { + let n = self.machine_st + .stack + .index_or_frame(self.machine_st.b) + .prelude + .univ_prelude + .num_cells; + + self.machine_st.cc = cell_as_fixnum!( + self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)] + ).get_num() as usize; + + if next_i > 0 { + match self.find_living_dynamic_else(p + next_i) { + Some(_) => { + self.retry_me_else(next_i); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + None => { + self.trust_me(); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } else { + self.trust_me(); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } + } + None => { + self.machine_st.fail = true; + } + } + + if self.machine_st.fail { + self.machine_st.backtrack(); + continue; + } + + self.machine_st.dynamic_mode = FirstOrNext::Next; + } + &Instruction::DynamicInternalElse(..) => { + let p = self.machine_st.p; + + match self.find_living_dynamic_else(p) { + Some((p, next_i)) => { + self.machine_st.p = p; + + match self.machine_st.dynamic_mode { + FirstOrNext::First if next_i == 0 => { + self.machine_st.p += 1; + } + FirstOrNext::First => { + match self.find_living_dynamic_else(p + next_i) { + Some(_) => { + self.machine_st.registers[self.machine_st.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); + + self.machine_st.num_of_args += 1; + self.machine_st.try_me_else(next_i); + self.machine_st.num_of_args -= 1; + } + None => { + self.machine_st.p += 1; + } + } + } + FirstOrNext::Next => { + let n = self.machine_st + .stack + .index_or_frame(self.machine_st.b) + .prelude + .univ_prelude + .num_cells; + + self.machine_st.cc = cell_as_fixnum!( + self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)] + ).get_num() as usize; + + if next_i > 0 { + match self.find_living_dynamic_else(p + next_i) { + Some(_) => { + self.retry_me_else(next_i); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + None => { + self.trust_me(); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } else { + self.trust_me(); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } + } + None => { + self.machine_st.fail = true; + } + } + + if self.machine_st.fail { + self.machine_st.backtrack(); + continue; + } + + self.machine_st.dynamic_mode = FirstOrNext::Next; + } + &Instruction::TryMeElse(offset) => { + self.machine_st.try_me_else(offset); + } + &Instruction::DefaultRetryMeElse(offset) => { + self.retry_me_else(offset); + } + &Instruction::DefaultTrustMe(_) => { + self.trust_me(); + } + &Instruction::RetryMeElse(offset) => { + self.retry_me_else(offset); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + &Instruction::TrustMe(_) => { + self.trust_me(); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + &Instruction::NeckCut => { + let b = self.machine_st.b; + let b0 = self.machine_st.b0; + + if b > b0 { + self.machine_st.b = b0; + + if b > self.machine_st.e { + self.machine_st.stack.truncate(b); + } + } + + self.machine_st.p += 1; + } + &Instruction::GetLevel(r) => { + let b0 = self.machine_st.b0; + + self.machine_st[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64)); + self.machine_st.p += 1; + } + &Instruction::GetLevelAndUnify(r) => { + // let b0 = self.machine_st[perm_v!(1)]; + let b0 = cell_as_fixnum!( + self.machine_st.stack[stack_loc!(AndFrame, self.machine_st.e, 1)] + ); + let a = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + // unify_fn!(&mut self.machine_st, a, b0); + self.machine_st.unify_fixnum(b0, a); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::Cut(r) => { + let value = self.machine_st[r]; + self.machine_st.cut_body(value); + + if self.machine_st.fail { + self.machine_st.backtrack(); + continue; + } + + if (self.machine_st.run_cleaners_fn)(self) { + continue; + } + + self.machine_st.p += 1; + } + &Instruction::Allocate(num_cells) => { + self.machine_st.allocate(num_cells); + } + &Instruction::DefaultCallAcyclicTerm(_) => { + let addr = self.machine_st.registers[1]; + + if self.machine_st.is_cyclic_term(addr) { + self.machine_st.backtrack(); + } else { + self.machine_st.p += 1; + } + } + &Instruction::DefaultExecuteAcyclicTerm(_) => { + let addr = self.machine_st.registers[1]; + + if self.machine_st.is_cyclic_term(addr) { + self.machine_st.backtrack(); + } else { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::DefaultCallArg(_) => { + try_or_throw!(self.machine_st, self.machine_st.try_arg()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::DefaultExecuteArg(_) => { + try_or_throw!(self.machine_st, self.machine_st.try_arg()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::DefaultCallCompare(_) => { + try_or_throw!(self.machine_st, self.machine_st.compare()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::DefaultExecuteCompare(_) => { + try_or_throw!(self.machine_st, self.machine_st.compare()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::DefaultCallTermGreaterThan(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) { + self.machine_st.p += 1; + } else { + self.machine_st.backtrack(); + } + } + &Instruction::DefaultExecuteTermGreaterThan(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) { + self.machine_st.p = self.machine_st.cp; + } else { + self.machine_st.backtrack(); + } + } + &Instruction::DefaultCallTermLessThan(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) { + self.machine_st.p += 1; + } else { + self.machine_st.backtrack(); + } + } + &Instruction::DefaultExecuteTermLessThan(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) { + self.machine_st.p = self.machine_st.cp; + } else { + self.machine_st.backtrack(); + } + } + &Instruction::DefaultCallTermGreaterThanOrEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + match compare_term_test!(self.machine_st, a1, a2) { + Some(Ordering::Greater | Ordering::Equal) => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultExecuteTermGreaterThanOrEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + match compare_term_test!(self.machine_st, a1, a2) { + Some(Ordering::Greater | Ordering::Equal) => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultCallTermLessThanOrEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + match compare_term_test!(self.machine_st, a1, a2) { + Some(Ordering::Less | Ordering::Equal) => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultExecuteTermLessThanOrEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + match compare_term_test!(self.machine_st, a1, a2) { + Some(Ordering::Less | Ordering::Equal) => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultCallRead(_) => { + try_or_throw!(self.machine_st, self.read()); + + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::DefaultExecuteRead(_) => { + try_or_throw!(self.machine_st, self.read()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::DefaultCallCopyTerm(_) => { + self.machine_st.copy_term(AttrVarPolicy::DeepCopy); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::DefaultExecuteCopyTerm(_) => { + self.machine_st.copy_term(AttrVarPolicy::DeepCopy); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::DefaultCallTermEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if self.machine_st.eq_test(a1, a2) { + self.machine_st.backtrack(); + } else { + self.machine_st.p += 1; + } + } + &Instruction::DefaultExecuteTermEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if self.machine_st.eq_test(a1, a2) { + self.machine_st.backtrack(); + } else { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::DefaultCallGround(_) => { + if self.machine_st.ground_test() { + self.machine_st.backtrack(); + } else { + self.machine_st.p += 1; + } + } + &Instruction::DefaultExecuteGround(_) => { + if self.machine_st.ground_test() { + self.machine_st.backtrack(); + } else { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::DefaultCallFunctor(_) => { + try_or_throw!(self.machine_st, self.machine_st.try_functor()); + + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::DefaultExecuteFunctor(_) => { + try_or_throw!(self.machine_st, self.machine_st.try_functor()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::DefaultCallTermNotEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { + self.machine_st.backtrack(); + } else { + self.machine_st.p += 1; + } + } + &Instruction::DefaultExecuteTermNotEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { + self.machine_st.backtrack(); + } else { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::DefaultCallSort(_) => { + try_or_throw!(self.machine_st, self.machine_st.sort()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::DefaultExecuteSort(_) => { + try_or_throw!(self.machine_st, self.machine_st.sort()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::DefaultCallKeySort(_) => { + try_or_throw!(self.machine_st, self.machine_st.keysort()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::DefaultExecuteKeySort(_) => { + try_or_throw!(self.machine_st, self.machine_st.keysort()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::DefaultCallIs(r, at, _) => { + try_or_throw!(self.machine_st, self.machine_st.is(r, at)); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::DefaultExecuteIs(r, at, _) => { + try_or_throw!(self.machine_st, self.machine_st.is(r, at)); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallAcyclicTerm(_) => { + let addr = self.machine_st.registers[1]; + + if self.machine_st.is_cyclic_term(addr) { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteAcyclicTerm(_) => { + let addr = self.machine_st.registers[1]; + + if self.machine_st.is_cyclic_term(addr) { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallArg(_) => { + try_or_throw!(self.machine_st, self.machine_st.try_arg()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteArg(_) => { + try_or_throw!(self.machine_st, self.machine_st.try_arg()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallCompare(_) => { + try_or_throw!(self.machine_st, self.machine_st.compare()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteCompare(_) => { + try_or_throw!(self.machine_st, self.machine_st.compare()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallTermGreaterThan(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } else { + self.machine_st.backtrack(); + } + } + &Instruction::ExecuteTermGreaterThan(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } else { + self.machine_st.backtrack(); + } + } + &Instruction::CallTermLessThan(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } else { + self.machine_st.backtrack(); + } + } + &Instruction::ExecuteTermLessThan(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } else { + self.machine_st.backtrack(); + } + } + &Instruction::CallTermGreaterThanOrEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + match compare_term_test!(self.machine_st, a1, a2) { + Some(Ordering::Greater | Ordering::Equal) => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteTermGreaterThanOrEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + match compare_term_test!(self.machine_st, a1, a2) { + Some(Ordering::Greater | Ordering::Equal) => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::CallTermLessThanOrEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + match compare_term_test!(self.machine_st, a1, a2) { + Some(Ordering::Less | Ordering::Equal) => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteTermLessThanOrEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + match compare_term_test!(self.machine_st, a1, a2) { + Some(Ordering::Less | Ordering::Equal) => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::CallRead(_) => { + try_or_throw!(self.machine_st, self.read()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteRead(_) => { + try_or_throw!(self.machine_st, self.read()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallCopyTerm(_) => { + self.machine_st.copy_term(AttrVarPolicy::DeepCopy); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteCopyTerm(_) => { + self.machine_st.copy_term(AttrVarPolicy::DeepCopy); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallTermEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if self.machine_st.eq_test(a1, a2) { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteTermEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if self.machine_st.eq_test(a1, a2) { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallGround(_) => { + if self.machine_st.ground_test() { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteGround(_) => { + if self.machine_st.ground_test() { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallFunctor(_) => { + try_or_throw!(self.machine_st, self.machine_st.try_functor()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteFunctor(_) => { + try_or_throw!(self.machine_st, self.machine_st.try_functor()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallTermNotEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteTermNotEqual(_) => { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; + + if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallSort(_) => { + try_or_throw!(self.machine_st, self.machine_st.sort()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteSort(_) => { + try_or_throw!(self.machine_st, self.machine_st.sort()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallKeySort(_) => { + try_or_throw!(self.machine_st, self.machine_st.keysort()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteKeySort(_) => { + try_or_throw!(self.machine_st, self.machine_st.keysort()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallIs(r, at, _) => { + try_or_throw!(self.machine_st, self.machine_st.is(r, at)); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + &Instruction::ExecuteIs(r, at, _) => { + try_or_throw!(self.machine_st, self.machine_st.is(r, at)); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallN(arity, _) => { + let pred = self.machine_st.registers[1]; + + for i in 2..arity + 1 { + self.machine_st.registers[i - 1] = self.machine_st.registers[i]; + } + + self.machine_st.registers[arity] = pred; + + try_or_throw!( + self.machine_st, + self.call_n(atom!("user"), arity) + ); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + &Instruction::ExecuteN(arity, _) => { + let pred = self.machine_st.registers[1]; + + for i in 2..arity + 1 { + self.machine_st.registers[i - 1] = self.machine_st.registers[i]; + } + + self.machine_st.registers[arity] = pred; + + try_or_throw!( + self.machine_st, + self.execute_n(atom!("user"), arity) + ); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + &Instruction::DefaultCallN(arity, _) => { + let pred = self.machine_st.registers[1]; + + for i in 2..arity + 1 { + self.machine_st.registers[i - 1] = self.machine_st.registers[i]; + } + + self.machine_st.registers[arity] = pred; + + try_or_throw!( + self.machine_st, + self.call_n(atom!("user"), arity) + ); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } + } + &Instruction::DefaultExecuteN(arity, _) => { + let pred = self.machine_st.registers[1]; + + for i in 2..arity + 1 { + self.machine_st.registers[i - 1] = self.machine_st.registers[i]; + } + + self.machine_st.registers[arity] = pred; + + try_or_throw!( + self.machine_st, + self.execute_n(atom!("user"), arity) + ); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } + } + &Instruction::CallNumberLessThanOrEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Less | Ordering::Equal => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteNumberLessThanOrEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Less | Ordering::Equal => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::CallNumberEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Equal => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteNumberEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Equal => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::CallNumberNotEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Equal => { + self.machine_st.backtrack(); + } + _ => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + } + } + &Instruction::ExecuteNumberNotEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Equal => { + self.machine_st.backtrack(); + } + _ => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + } + } + &Instruction::CallNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Greater | Ordering::Equal => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Greater | Ordering::Equal => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::CallNumberGreaterThan(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Greater => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteNumberGreaterThan(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Greater => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::CallNumberLessThan(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Less => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteNumberLessThan(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Less => { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultCallNumberLessThanOrEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Less | Ordering::Equal => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultExecuteNumberLessThanOrEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Less | Ordering::Equal => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultCallNumberNotEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Equal => { + self.machine_st.backtrack(); + } + _ => { + self.machine_st.p += 1; + } + } + } + &Instruction::DefaultExecuteNumberNotEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Equal => { + self.machine_st.backtrack(); + } + _ => { + self.machine_st.p = self.machine_st.cp; + } + } + } + &Instruction::DefaultCallNumberEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Equal => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultExecuteNumberEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Equal => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultCallNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Greater | Ordering::Equal => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultExecuteNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Greater | Ordering::Equal => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultCallNumberGreaterThan(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Greater => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultExecuteNumberGreaterThan(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Greater => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultCallNumberLessThan(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Less => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::DefaultExecuteNumberLessThan(ref at_1, ref at_2, _) => { + let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1)); + let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2)); + + match n1.cmp(&n2) { + Ordering::Less => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + // + &Instruction::CallIsAtom(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + read_heap_cell!(d, + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + self.machine_st.p += 1; + } else { + self.machine_st.backtrack(); + } + } + (HeapCellValueTag::Char) => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + ); + } + &Instruction::ExecuteIsAtom(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + read_heap_cell!(d, + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + self.machine_st.p = self.machine_st.cp; + } else { + self.machine_st.backtrack(); + } + } + (HeapCellValueTag::Char) => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + ); + } + &Instruction::CallIsAtomic(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + read_heap_cell!(d, + (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + HeapCellValueTag::Cons) => { + self.machine_st.p += 1; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + self.machine_st.p += 1; + } else { + self.machine_st.backtrack(); + } + } + _ => { + self.machine_st.backtrack(); + } + ); + } + &Instruction::ExecuteIsAtomic(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + read_heap_cell!(d, + (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + HeapCellValueTag::Cons) => { + self.machine_st.p = self.machine_st.cp; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity == 0 { + self.machine_st.p = self.machine_st.cp; + } else { + self.machine_st.backtrack(); + } + } + _ => { + self.machine_st.backtrack(); + } + ); + } + &Instruction::CallIsCompound(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + read_heap_cell!(d, + (HeapCellValueTag::Str | HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { + self.machine_st.p += 1; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity > 0 { + self.machine_st.p += 1; + } else { + self.machine_st.backtrack(); + } + } + _ => { + self.machine_st.backtrack(); + } + ); + } + &Instruction::ExecuteIsCompound(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + read_heap_cell!(d, + (HeapCellValueTag::Str | HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { + self.machine_st.p = self.machine_st.cp; + } + (HeapCellValueTag::Atom, (_name, arity)) => { + if arity > 0 { + self.machine_st.p = self.machine_st.cp; + } else { + self.machine_st.backtrack(); + } + } + _ => { + self.machine_st.backtrack(); + } + ); + } + &Instruction::CallIsInteger(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + match Number::try_from(d) { + Ok(Number::Fixnum(_) | Number::Integer(_)) => { + self.machine_st.p += 1; + } + Ok(Number::Rational(n)) => { + if n.denom() == &1 { + self.machine_st.p += 1; + } else { + self.machine_st.backtrack(); + } + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteIsInteger(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + match Number::try_from(d) { + Ok(Number::Fixnum(_) | Number::Integer(_)) => { + self.machine_st.p = self.machine_st.cp; + } + Ok(Number::Rational(n)) => { + if n.denom() == &1 { + self.machine_st.p = self.machine_st.cp; + } else { + self.machine_st.backtrack(); + } + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::CallIsNumber(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + match Number::try_from(d) { + Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => { + self.machine_st.p += 1; + } + Ok(Number::Rational(n)) => { + if n.denom() == &1 { + self.machine_st.p += 1; + } else { + self.machine_st.backtrack(); + } + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteIsNumber(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + match Number::try_from(d) { + Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => { + self.machine_st.p = self.machine_st.cp; + } + Ok(Number::Rational(n)) => { + if n.denom() == &1 { + self.machine_st.p = self.machine_st.cp; + } else { + self.machine_st.backtrack(); + } + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::CallIsRational(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + read_heap_cell!(d, + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Rational, _r) => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + ); + } + _ => { + self.machine_st.backtrack(); + } + ); + } + &Instruction::ExecuteIsRational(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + read_heap_cell!(d, + (HeapCellValueTag::Cons, ptr) => { + match_untyped_arena_ptr!(ptr, + (ArenaHeaderTag::Rational, _r) => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + ); + } + _ => { + self.machine_st.backtrack(); + } + ); + } + &Instruction::CallIsFloat(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + match Number::try_from(d) { + Ok(Number::Float(_)) => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteIsFloat(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + match Number::try_from(d) { + Ok(Number::Float(_)) => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::CallIsNonVar(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + match d.get_tag() { + HeapCellValueTag::AttrVar | + HeapCellValueTag::Var | + HeapCellValueTag::StackVar => { + self.machine_st.backtrack(); + } + _ => { + self.machine_st.p += 1; + } + } + } + &Instruction::ExecuteIsNonVar(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + match d.get_tag() { + HeapCellValueTag::AttrVar | + HeapCellValueTag::Var | + HeapCellValueTag::StackVar => { + self.machine_st.backtrack(); + } + _ => { + self.machine_st.p = self.machine_st.cp; + } + } + } + &Instruction::CallIsVar(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + match d.get_tag() { + HeapCellValueTag::AttrVar | + HeapCellValueTag::Var | + HeapCellValueTag::StackVar => { + self.machine_st.p += 1; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::ExecuteIsVar(r, _) => { + let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + + match d.get_tag() { + HeapCellValueTag::AttrVar | + HeapCellValueTag::Var | + HeapCellValueTag::StackVar => { + self.machine_st.p = self.machine_st.cp; + } + _ => { + self.machine_st.backtrack(); + } + } + } + &Instruction::CallNamed(arity, name, ref idx, _) => { + let idx = idx.get(); + + try_or_throw!( + self.machine_st, + self.try_call(name, arity, idx) + ); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + &Instruction::ExecuteNamed(arity, name, ref idx, _) => { + let idx = idx.get(); + + try_or_throw!( + self.machine_st, + self.try_execute(name, arity, idx) + ); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + &Instruction::DefaultCallNamed(arity, name, ref idx, _) => { + let idx = idx.get(); + + try_or_throw!( + self.machine_st, + self.try_call(name, arity, idx) + ); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } + } + &Instruction::DefaultExecuteNamed(arity, name, ref idx, _) => { + let idx = idx.get(); + + try_or_throw!( + self.machine_st, + self.try_execute(name, arity, idx) + ); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } + } + &Instruction::Deallocate => { + self.machine_st.deallocate() + } + &Instruction::JmpByCall(arity, offset, _) => { + self.machine_st.num_of_args = arity; + self.machine_st.b0 = self.machine_st.b; + self.machine_st.cp = self.machine_st.p + 1; + self.machine_st.p += offset; + } + &Instruction::JmpByExecute(arity, offset, _) => { + self.machine_st.num_of_args = arity; + self.machine_st.b0 = self.machine_st.b; + self.machine_st.p += offset; + } + &Instruction::RevJmpBy(offset) => { + self.machine_st.p -= offset; + } + &Instruction::Proceed => { + self.machine_st.p = self.machine_st.cp; + } + &Instruction::GetConstant(_, c, reg) => { + let value = self.machine_st.deref(self.machine_st[reg]); + self.machine_st.write_literal_to_var(value, c); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::GetList(_, reg) => { + let deref_v = self.machine_st.deref(self.machine_st[reg]); + let store_v = self.machine_st.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::PStrLoc, h) => { + let (h, n) = pstr_loc_and_offset(&self.machine_st.heap, h); + + self.machine_st.s = HeapPtr::PStrChar(h, n.get_num() as usize); + self.machine_st.mode = MachineMode::Read; + } + (HeapCellValueTag::CStr) => { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(store_v); + + self.machine_st.s = HeapPtr::PStrChar(h, 0); + self.machine_st.mode = MachineMode::Read; + } + (HeapCellValueTag::Lis, l) => { + self.machine_st.s = HeapPtr::HeapCell(l); + self.machine_st.mode = MachineMode::Read; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(list_loc_as_cell!(h+1)); + self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); + + self.machine_st.mode = MachineMode::Write; + } + _ => { + self.machine_st.backtrack(); + continue; + } + ); + + self.machine_st.p += 1; + } + &Instruction::GetPartialString(_, string, reg, has_tail) => { + let deref_v = self.machine_st.deref(self.machine_st[reg]); + let store_v = self.machine_st.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::Str | HeapCellValueTag::Lis | + HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar | + HeapCellValueTag::StackVar | HeapCellValueTag::Var | + HeapCellValueTag::CStr) => { + self.machine_st.match_partial_string(store_v, string, has_tail); + } + _ => { + self.machine_st.backtrack(); + continue; + } + ); + + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::GetStructure(name, arity, reg) => { + let deref_v = self.machine_st.deref(self.machine_st[reg]); + let store_v = self.machine_st.store(deref_v); + + read_heap_cell!(store_v, + (HeapCellValueTag::Str, a) => { + read_heap_cell!(self.machine_st.heap[a], + (HeapCellValueTag::Atom, (result_name, result_arity)) => { + if arity == result_arity && name == result_name { + self.machine_st.s = HeapPtr::HeapCell(a + 1); + self.machine_st.mode = MachineMode::Read; + } else { + self.machine_st.backtrack(); + continue; + } + } + _ => { + unreachable!(); + } + ); + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(str_loc_as_cell!(h+1)); + self.machine_st.heap.push(atom_as_cell!(name, arity)); + + self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); + self.machine_st.mode = MachineMode::Write; + } + _ => { + self.machine_st.backtrack(); + continue; + } + ); + + self.machine_st.p += 1; + } + &Instruction::GetVariable(norm, arg) => { + self.machine_st[norm] = self.machine_st.registers[arg]; + self.machine_st.p += 1; + } + &Instruction::GetValue(norm, arg) => { + let norm_addr = self.machine_st[norm]; + let reg_addr = self.machine_st.registers[arg]; + + unify_fn!(&mut self.machine_st, norm_addr, reg_addr); + + if self.machine_st.fail { + self.machine_st.backtrack(); + continue; + } + + self.machine_st.p += 1; + } + &Instruction::UnifyConstant(v) => { + match self.machine_st.mode { + MachineMode::Read => { + let addr = self.machine_st.read_s(); + + self.machine_st.write_literal_to_var(addr, v); + + if self.machine_st.fail { + self.machine_st.backtrack(); + continue; + } else { + self.machine_st.increment_s_ptr(1); + } + } + MachineMode::Write => { + self.machine_st.heap.push(v); + } + } + + self.machine_st.p += 1; + } + &Instruction::UnifyLocalValue(reg) => { + match self.machine_st.mode { + MachineMode::Read => { + let reg_addr = self.machine_st[reg]; + let value = self.machine_st.read_s(); + + unify_fn!(&mut self.machine_st, reg_addr, value); + + if self.machine_st.fail { + self.machine_st.backtrack(); + continue; + } else { + self.machine_st.increment_s_ptr(1); + } + } + MachineMode::Write => { + let value = self.machine_st.store(self.machine_st.deref(self.machine_st[reg])); + let h = self.machine_st.heap.len(); + + read_heap_cell!(value, + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => { + let value = self.machine_st.heap[hc]; + + self.machine_st.heap.push(value); + self.machine_st.increment_s_ptr(1); + } + _ => { + self.machine_st.heap.push(heap_loc_as_cell!(h)); + (self.machine_st.bind_fn)( + &mut self.machine_st, + Ref::heap_cell(h), + value, + ); + } + ); + } + } + + self.machine_st.p += 1; + } + &Instruction::UnifyVariable(reg) => { + match self.machine_st.mode { + MachineMode::Read => { + self.machine_st[reg] = self.machine_st.read_s(); + self.machine_st.increment_s_ptr(1); + } + MachineMode::Write => { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(heap_loc_as_cell!(h)); + self.machine_st[reg] = heap_loc_as_cell!(h); + } + } + + self.machine_st.p += 1; + } + &Instruction::UnifyValue(reg) => { + match self.machine_st.mode { + MachineMode::Read => { + let reg_addr = self.machine_st[reg]; + let value = self.machine_st.read_s(); + + unify_fn!(&mut self.machine_st, reg_addr, value); + + if self.machine_st.fail { + self.machine_st.backtrack(); + continue; + } else { + self.machine_st.increment_s_ptr(1); + } + } + MachineMode::Write => { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(heap_loc_as_cell!(h)); + + let addr = self.machine_st.store(self.machine_st[reg]); + (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr); + + // the former code of this match arm was: + + // let addr = self.machine_st.store(self.machine_st[reg]); + // self.machine_st.heap.push(HeapCellValue::Addr(addr)); + + // the old code didn't perform the occurs + // check when enabled and so it was changed to + // the above, which is only slightly less + // efficient when the occurs_check is disabled. + } + } + + self.machine_st.p += 1; + } + &Instruction::UnifyVoid(n) => { + match self.machine_st.mode { + MachineMode::Read => { + self.machine_st.increment_s_ptr(n); + } + MachineMode::Write => { + let h = self.machine_st.heap.len(); + + for i in h..h + n { + self.machine_st.heap.push(heap_loc_as_cell!(i)); + } + } + } + + self.machine_st.p += 1; + } + &Instruction::IndexingCode(ref indexing_lines) => { + match &indexing_lines[self.machine_st.oip as usize] { + IndexingLine::Indexing(_) => { + self.execute_switch_on_term(); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } + } + IndexingLine::IndexedChoice(ref indexed_choice) => { + match &indexed_choice[self.machine_st.iip as usize] { + &IndexedChoiceInstruction::Try(offset) => { + self.machine_st.indexed_try(offset); + } + &IndexedChoiceInstruction::Retry(l) => { + self.retry(l); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + &IndexedChoiceInstruction::Trust(l) => { + self.trust(l); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } + IndexingLine::DynamicIndexedChoice(_) => { + let p = self.machine_st.p; + + match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { + Some((offset, oi, ii, is_next_clause)) => { + self.machine_st.p = p; + self.machine_st.oip = oi; + self.machine_st.iip = ii; + + match self.machine_st.dynamic_mode { + FirstOrNext::First if !is_next_clause => { + self.machine_st.p = p + offset; + } + FirstOrNext::First => { + // there's a leading DynamicElse that sets self.machine_st.cc. + // self.machine_st.cc = self.machine_st.global_clock; + + // see that there is a following dynamic_else + // clause so we avoid generating a choice + // point in case there isn't. + match self.find_living_dynamic(oi, ii + 1) { + Some(_) => { + self.machine_st.registers[self.machine_st.num_of_args + 1] = + fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); + + self.machine_st.num_of_args += 2; + self.machine_st.indexed_try(offset); + self.machine_st.num_of_args -= 2; + } + None => { + self.machine_st.p = p + offset; + self.machine_st.oip = 0; + self.machine_st.iip = 0; + } + } + } + FirstOrNext::Next => { + let b = self.machine_st.b; + let n = self.machine_st + .stack + .index_or_frame(b) + .prelude + .univ_prelude + .num_cells; + + self.machine_st.cc = cell_as_fixnum!( + self.machine_st.stack[stack_loc!(OrFrame, b, n-2)] + ).get_num() as usize; + + if is_next_clause { + match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { + Some(_) => { + self.retry(offset); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + None => { + self.trust(offset); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } else { + self.trust(offset); + + try_or_throw!( + self.machine_st, + (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + ); + } + } + } + } + None => { + self.machine_st.fail = true; + } + } + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + self.machine_st.dynamic_mode = FirstOrNext::Next; + } + } + } + } + &Instruction::PutConstant(_, c, reg) => { + self.machine_st[reg] = c; + self.machine_st.p += 1; + } + &Instruction::PutList(_, reg) => { + self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.len()); + self.machine_st.p += 1; + } + &Instruction::PutPartialString(_, string, reg, has_tail) => { + let pstr_addr = if has_tail { + if string != atom!("") { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(string_as_pstr_cell!(string)); + + // the tail will be pushed by the next + // instruction, so don't push one here. + + pstr_loc_as_cell!(h) + } else { + empty_list_as_cell!() + } + } else { + string_as_cstr_cell!(string) + }; + + self.machine_st[reg] = pstr_addr; + self.machine_st.p += 1; + } + &Instruction::PutStructure(name, arity, reg) => { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(atom_as_cell!(name, arity)); + self.machine_st[reg] = str_loc_as_cell!(h); + + self.machine_st.p += 1; + } + &Instruction::PutUnsafeValue(n, arg) => { + let s = stack_loc!(AndFrame, self.machine_st.e, n); + let addr = self.machine_st.store(self.machine_st.deref(stack_loc_as_cell!(s))); + + if addr.is_protected(self.machine_st.e) { + self.machine_st.registers[arg] = addr; + } else { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(heap_loc_as_cell!(h)); + (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr); + + self.machine_st.registers[arg] = heap_loc_as_cell!(h); + } + + self.machine_st.p += 1; + } + &Instruction::PutValue(norm, arg) => { + self.machine_st.registers[arg] = self.machine_st[norm]; + self.machine_st.p += 1; + } + &Instruction::PutVariable(norm, arg) => { + match norm { + RegType::Perm(n) => { + self.machine_st[norm] = stack_loc_as_cell!(AndFrame, self.machine_st.e, n); + self.machine_st.registers[arg] = self.machine_st[norm]; + } + RegType::Temp(_) => { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(heap_loc_as_cell!(h)); + + self.machine_st[norm] = heap_loc_as_cell!(h); + self.machine_st.registers[arg] = heap_loc_as_cell!(h); + } + }; + + self.machine_st.p += 1; + } + &Instruction::SetConstant(c) => { + self.machine_st.heap.push(c); + self.machine_st.p += 1; + } + &Instruction::SetLocalValue(reg) => { + let addr = self.machine_st.deref(self.machine_st[reg]); + let stored_v = self.machine_st.store(addr); + + if stored_v.is_stack_var() { + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(heap_loc_as_cell!(h)); + (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), stored_v); + } else { + self.machine_st.heap.push(stored_v); + } + + self.machine_st.p += 1; + } + &Instruction::SetVariable(reg) => { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(heap_loc_as_cell!(h)); + self.machine_st[reg] = heap_loc_as_cell!(h); + + self.machine_st.p += 1; + } + &Instruction::SetValue(reg) => { + let heap_val = self.machine_st.store(self.machine_st[reg]); + self.machine_st.heap.push(heap_val); + self.machine_st.p += 1; + } + &Instruction::SetVoid(n) => { + let h = self.machine_st.heap.len(); + + for i in h..h + n { + self.machine_st.heap.push(heap_loc_as_cell!(i)); + } + + self.machine_st.p += 1; + } + // + &Instruction::CallAtomChars(_) => { + self.atom_chars(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteAtomChars(_) => { + self.atom_chars(); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallAtomCodes(_) => { + try_or_throw!(self.machine_st, self.atom_codes()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + self.machine_st.p += 1; + } + } + &Instruction::ExecuteAtomCodes(_) => { + try_or_throw!(self.machine_st, self.atom_codes()); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } else { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallAtomLength(_) => { + self.atom_length(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteAtomLength(_) => { + self.atom_length(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallBindFromRegister(_) => { + self.bind_from_register(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteBindFromRegister(_) => { + self.bind_from_register(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallContinuation(_) => { + try_or_throw!(self.machine_st, self.call_continuation(false)); + } + &Instruction::ExecuteContinuation(_) => { + try_or_throw!(self.machine_st, self.call_continuation(true)); + } + &Instruction::CallCharCode(_) => { + try_or_throw!(self.machine_st, self.char_code()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCharCode(_) => { + try_or_throw!(self.machine_st, self.char_code()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCharType(_) => { + self.char_type(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCharType(_) => { + self.char_type(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCharsToNumber(_) => { + try_or_throw!(self.machine_st, self.chars_to_number()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCharsToNumber(_) => { + try_or_throw!(self.machine_st, self.chars_to_number()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCodesToNumber(_) => { + try_or_throw!(self.machine_st, self.codes_to_number()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCodesToNumber(_) => { + try_or_throw!(self.machine_st, self.codes_to_number()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCopyTermWithoutAttrVars(_) => { + self.copy_term_without_attr_vars(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCopyTermWithoutAttrVars(_) => { + self.copy_term_without_attr_vars(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCheckCutPoint(_) => { + self.check_cut_point(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCheckCutPoint(_) => { + self.check_cut_point(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallClose(_) => { + try_or_throw!(self.machine_st, self.close()); + self.machine_st.p += 1; + } + &Instruction::ExecuteClose(_) => { + try_or_throw!(self.machine_st, self.close()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallCopyToLiftedHeap(_) => { + self.copy_to_lifted_heap(); + self.machine_st.p += 1; + } + &Instruction::ExecuteCopyToLiftedHeap(_) => { + self.copy_to_lifted_heap(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallCreatePartialString(_) => { + self.create_partial_string(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCreatePartialString(_) => { + self.create_partial_string(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCurrentHostname(_) => { + self.current_hostname(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCurrentHostname(_) => { + self.current_hostname(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCurrentInput(_) => { + try_or_throw!(self.machine_st, self.current_input()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCurrentInput(_) => { + try_or_throw!(self.machine_st, self.current_input()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCurrentOutput(_) => { + try_or_throw!(self.machine_st, self.current_output()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCurrentOutput(_) => { + try_or_throw!(self.machine_st, self.current_output()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallDirectoryFiles(_) => { + try_or_throw!(self.machine_st, self.directory_files()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteDirectoryFiles(_) => { + try_or_throw!(self.machine_st, self.directory_files()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallFileSize(_) => { + self.file_size(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteFileSize(_) => { + self.file_size(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallFileExists(_) => { + self.file_exists(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteFileExists(_) => { + self.file_exists(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallDirectoryExists(_) => { + self.directory_exists(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteDirectoryExists(_) => { + self.directory_exists(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallDirectorySeparator(_) => { + self.directory_separator(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteDirectorySeparator(_) => { + self.directory_separator(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallMakeDirectory(_) => { + self.make_directory(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteMakeDirectory(_) => { + self.make_directory(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallMakeDirectoryPath(_) => { + self.make_directory_path(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteMakeDirectoryPath(_) => { + self.make_directory_path(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallDeleteFile(_) => { + self.delete_file(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteDeleteFile(_) => { + self.delete_file(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallRenameFile(_) => { + self.rename_file(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteRenameFile(_) => { + self.rename_file(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallWorkingDirectory(_) => { + try_or_throw!(self.machine_st, self.working_directory()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteWorkingDirectory(_) => { + try_or_throw!(self.machine_st, self.working_directory()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallDeleteDirectory(_) => { + self.delete_directory(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteDeleteDirectory(_) => { + self.delete_directory(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallPathCanonical(_) => { + try_or_throw!(self.machine_st, self.path_canonical()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecutePathCanonical(_) => { + try_or_throw!(self.machine_st, self.path_canonical()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallFileTime(_) => { + self.file_time(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteFileTime(_) => { + self.file_time(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallDeleteAttribute(_) => { + self.delete_attribute(); + self.machine_st.p += 1; + } + &Instruction::ExecuteDeleteAttribute(_) => { + self.delete_attribute(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallDeleteHeadAttribute(_) => { + self.delete_head_attribute(); + self.machine_st.p += 1; + } + &Instruction::ExecuteDeleteHeadAttribute(_) => { + self.delete_head_attribute(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallDynamicModuleResolution(arity, _) => { + let (module_name, key) = try_or_throw!( + self.machine_st, + self.dynamic_module_resolution(arity - 2) + ); + + try_or_throw!(self.machine_st, self.call_clause(module_name, key)); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } + } + &Instruction::ExecuteDynamicModuleResolution(arity, _) => { + let (module_name, key) = try_or_throw!( + self.machine_st, + self.dynamic_module_resolution(arity - 2) + ); + + try_or_throw!(self.machine_st, self.execute_clause(module_name, key)); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } + } + &Instruction::CallEnqueueAttributedVar(_) => { + self.enqueue_attributed_var(); + self.machine_st.p += 1; + } + &Instruction::ExecuteEnqueueAttributedVar(_) => { + self.enqueue_attributed_var(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallFetchGlobalVar(_) => { + self.fetch_global_var(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteFetchGlobalVar(_) => { + self.fetch_global_var(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallFirstStream(_) => { + self.first_stream(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteFirstStream(_) => { + self.first_stream(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallFlushOutput(_) => { + try_or_throw!(self.machine_st, self.flush_output()); + self.machine_st.p += 1; + } + &Instruction::ExecuteFlushOutput(_) => { + try_or_throw!(self.machine_st, self.flush_output()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallGetByte(_) => { + try_or_throw!(self.machine_st, self.get_byte()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetByte(_) => { + try_or_throw!(self.machine_st, self.get_byte()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetChar(_) => { + try_or_throw!(self.machine_st, self.get_char()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetChar(_) => { + try_or_throw!(self.machine_st, self.get_char()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetNChars(_) => { + try_or_throw!(self.machine_st, self.get_n_chars()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetNChars(_) => { + try_or_throw!(self.machine_st, self.get_n_chars()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetCode(_) => { + try_or_throw!(self.machine_st, self.get_code()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetCode(_) => { + try_or_throw!(self.machine_st, self.get_code()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetSingleChar(_) => { + try_or_throw!(self.machine_st, self.get_single_char()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetSingleChar(_) => { + try_or_throw!(self.machine_st, self.get_single_char()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallResetAttrVarState(_) => { + self.reset_attr_var_state(); + self.machine_st.p += 1; + } + &Instruction::ExecuteResetAttrVarState(_) => { + self.reset_attr_var_state(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallTruncateIfNoLiftedHeapGrowthDiff(_) => { + self.truncate_if_no_lifted_heap_growth_diff(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteTruncateIfNoLiftedHeapGrowthDiff(_) => { + self.truncate_if_no_lifted_heap_growth_diff(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallTruncateIfNoLiftedHeapGrowth(_) => { + self.truncate_if_no_lifted_heap_growth(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteTruncateIfNoLiftedHeapGrowth(_) => { + self.truncate_if_no_lifted_heap_growth(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetAttributedVariableList(_) => { + self.get_attributed_variable_list(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetAttributedVariableList(_) => { + self.get_attributed_variable_list(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetAttrVarQueueDelimiter(_) => { + self.get_attr_var_queue_delimiter(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetAttrVarQueueDelimiter(_) => { + self.get_attr_var_queue_delimiter(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetAttrVarQueueBeyond(_) => { + self.get_attr_var_queue_beyond(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetAttrVarQueueBeyond(_) => { + self.get_attr_var_queue_beyond(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetBValue(_) => { + self.get_b_value(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetBValue(_) => { + self.get_b_value(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetContinuationChunk(_) => { + self.get_continuation_chunk(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetContinuationChunk(_) => { + self.get_continuation_chunk(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetNextDBRef(_) => { + self.get_next_db_ref(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetNextDBRef(_) => { + self.get_next_db_ref(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetNextOpDBRef(_) => { + self.get_next_op_db_ref(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetNextOpDBRef(_) => { + self.get_next_op_db_ref(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallIsPartialString(_) => { + self.is_partial_string(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteIsPartialString(_) => { + self.is_partial_string(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallHalt(_) => { + self.halt(); + self.machine_st.p += 1; + } + &Instruction::ExecuteHalt(_) => { + self.halt(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallGetLiftedHeapFromOffset(_) => { + self.get_lifted_heap_from_offset(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetLiftedHeapFromOffset(_) => { + self.get_lifted_heap_from_offset(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetLiftedHeapFromOffsetDiff(_) => { + self.get_lifted_heap_from_offset_diff(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetLiftedHeapFromOffsetDiff(_) => { + self.get_lifted_heap_from_offset_diff(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetSCCCleaner(_) => { + self.get_scc_cleaner(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetSCCCleaner(_) => { + self.get_scc_cleaner(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallHeadIsDynamic(_) => { + self.head_is_dynamic(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteHeadIsDynamic(_) => { + self.head_is_dynamic(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallInstallSCCCleaner(_) => { + self.install_scc_cleaner(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteInstallSCCCleaner(_) => { + self.install_scc_cleaner(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallInstallInferenceCounter(_) => { + try_or_throw!(self.machine_st, self.install_inference_counter()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteInstallInferenceCounter(_) => { + try_or_throw!(self.machine_st, self.install_inference_counter()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallLiftedHeapLength(_) => { + self.lifted_heap_length(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteLiftedHeapLength(_) => { + self.lifted_heap_length(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallLoadLibraryAsStream(_) => { + try_or_throw!(self.machine_st, self.load_library_as_stream()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteLoadLibraryAsStream(_) => { + try_or_throw!(self.machine_st, self.load_library_as_stream()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallModuleExists(_) => { + self.module_exists(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteModuleExists(_) => { + self.module_exists(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallNextEP(_) => { + self.next_ep(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteNextEP(_) => { + self.next_ep(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallNoSuchPredicate(_) => { + try_or_throw!(self.machine_st, self.no_such_predicate()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteNoSuchPredicate(_) => { + try_or_throw!(self.machine_st, self.no_such_predicate()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallNumberToChars(_) => { + self.number_to_chars(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteNumberToChars(_) => { + self.number_to_chars(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallNumberToCodes(_) => { + self.number_to_codes(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteNumberToCodes(_) => { + self.number_to_codes(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallOpDeclaration(_) => { + try_or_throw!(self.machine_st, self.op_declaration()); + self.machine_st.p += 1; + } + &Instruction::ExecuteOpDeclaration(_) => { + try_or_throw!(self.machine_st, self.op_declaration()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallOpen(_) => { + try_or_throw!(self.machine_st, self.open()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteOpen(_) => { + try_or_throw!(self.machine_st, self.open()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSetStreamOptions(_) => { + try_or_throw!(self.machine_st, self.set_stream_options()); + self.machine_st.p += 1; + } + &Instruction::ExecuteSetStreamOptions(_) => { + try_or_throw!(self.machine_st, self.set_stream_options()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallNextStream(_) => { + self.next_stream(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteNextStream(_) => { + self.next_stream(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallPartialStringTail(_) => { + self.partial_string_tail(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecutePartialStringTail(_) => { + self.partial_string_tail(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallPeekByte(_) => { + try_or_throw!(self.machine_st, self.peek_byte()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecutePeekByte(_) => { + try_or_throw!(self.machine_st, self.peek_byte()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallPeekChar(_) => { + try_or_throw!(self.machine_st, self.peek_char()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecutePeekChar(_) => { + try_or_throw!(self.machine_st, self.peek_char()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallPeekCode(_) => { + try_or_throw!(self.machine_st, self.peek_code()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecutePeekCode(_) => { + try_or_throw!(self.machine_st, self.peek_code()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallPointsToContinuationResetMarker(_) => { + self.points_to_continuation_reset_marker(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecutePointsToContinuationResetMarker(_) => { + self.points_to_continuation_reset_marker(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallPutByte(_) => { + try_or_throw!(self.machine_st, self.put_byte()); + self.machine_st.p += 1; + } + &Instruction::ExecutePutByte(_) => { + try_or_throw!(self.machine_st, self.put_byte()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallPutChar(_) => { + try_or_throw!(self.machine_st, self.put_char()); + self.machine_st.p += 1; + } + &Instruction::ExecutePutChar(_) => { + try_or_throw!(self.machine_st, self.put_char()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallPutChars(_) => { + try_or_throw!(self.machine_st, self.put_chars()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecutePutChars(_) => { + try_or_throw!(self.machine_st, self.put_chars()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallPutCode(_) => { + try_or_throw!(self.machine_st, self.put_code()); + self.machine_st.p += 1; + } + &Instruction::ExecutePutCode(_) => { + try_or_throw!(self.machine_st, self.put_code()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallReadQueryTerm(_) => { + try_or_throw!(self.machine_st, self.read_query_term()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteReadQueryTerm(_) => { + try_or_throw!(self.machine_st, self.read_query_term()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallReadTerm(_) => { + try_or_throw!(self.machine_st, self.read_term()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteReadTerm(_) => { + try_or_throw!(self.machine_st, self.read_term()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallRedoAttrVarBinding(_) => { + self.redo_attr_var_binding(); + self.machine_st.p += 1; + } + &Instruction::ExecuteRedoAttrVarBinding(_) => { + self.redo_attr_var_binding(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallRemoveCallPolicyCheck(_) => { + self.remove_call_policy_check(); + self.machine_st.p += 1; + } + &Instruction::ExecuteRemoveCallPolicyCheck(_) => { + self.remove_call_policy_check(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallRemoveInferenceCounter(_) => { + self.remove_inference_counter(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteRemoveInferenceCounter(_) => { + self.remove_inference_counter(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallResetContinuationMarker(_) => { + self.reset_continuation_marker(); + self.machine_st.p += 1; + } + &Instruction::ExecuteResetContinuationMarker(_) => { + self.reset_continuation_marker(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallRestoreCutPolicy(_) => { + self.restore_cut_policy(); + self.machine_st.p += 1; + } + &Instruction::ExecuteRestoreCutPolicy(_) => { + self.restore_cut_policy(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallSetCutPoint(r, _) => { + if !self.set_cut_point(r) { + step_or_fail!(self, self.machine_st.p += 1); + } + } + &Instruction::ExecuteSetCutPoint(r, _) => { + let cp = self.machine_st.cp; + + if !self.set_cut_point(r) { + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } else { + // run_cleaners in set_cut_point calls call_by_index. + // replace the effect of call_by_index with that + // of execute_by_index here. + + self.machine_st.cp = cp; + } + } + &Instruction::CallSetInput(_) => { + try_or_throw!(self.machine_st, self.set_input()); + self.machine_st.p += 1; + } + &Instruction::ExecuteSetInput(_) => { + try_or_throw!(self.machine_st, self.set_input()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallSetOutput(_) => { + try_or_throw!(self.machine_st, self.set_output()); + self.machine_st.p += 1; + } + &Instruction::ExecuteSetOutput(_) => { + try_or_throw!(self.machine_st, self.set_output()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallStoreBacktrackableGlobalVar(_) => { + self.store_backtrackable_global_var(); + self.machine_st.p += 1; + } + &Instruction::ExecuteStoreBacktrackableGlobalVar(_) => { + self.store_backtrackable_global_var(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallStoreGlobalVar(_) => { + self.store_global_var(); + self.machine_st.p += 1; + } + &Instruction::ExecuteStoreGlobalVar(_) => { + self.store_global_var(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallStreamProperty(_) => { + try_or_throw!(self.machine_st, self.stream_property()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteStreamProperty(_) => { + try_or_throw!(self.machine_st, self.stream_property()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSetStreamPosition(_) => { + try_or_throw!(self.machine_st, self.set_stream_position()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteSetStreamPosition(_) => { + try_or_throw!(self.machine_st, self.set_stream_position()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallInferenceLevel(_) => { + self.inference_level(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteInferenceLevel(_) => { + self.inference_level(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCleanUpBlock(_) => { + self.clean_up_block(); + self.machine_st.p += 1; + } + &Instruction::ExecuteCleanUpBlock(_) => { + self.clean_up_block(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallEraseBall(_) => { + self.erase_ball(); + self.machine_st.p += 1; + } + &Instruction::ExecuteEraseBall(_) => { + self.erase_ball(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallFail(_) | &Instruction::ExecuteFail(_) => { + self.machine_st.backtrack(); + } + &Instruction::CallGetBall(_) => { + self.get_ball(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetBall(_) => { + self.get_ball(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetCurrentBlock(_) => { + self.get_current_block(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetCurrentBlock(_) => { + self.get_current_block(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetCutPoint(_) => { + self.get_cut_point(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetCutPoint(_) => { + self.get_cut_point(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetStaggeredCutPoint(_) => { + self.get_staggered_cut_point(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetStaggeredCutPoint(_) => { + self.get_staggered_cut_point(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetDoubleQuotes(_) => { + self.get_double_quotes(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetDoubleQuotes(_) => { + self.get_double_quotes(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallInstallNewBlock(_) => { + self.machine_st.install_new_block(self.machine_st.registers[1]); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteInstallNewBlock(_) => { + self.machine_st.install_new_block(self.machine_st.registers[1]); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallMaybe(_) => { + self.maybe(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteMaybe(_) => { + self.maybe(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCpuNow(_) => { + self.cpu_now(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCpuNow(_) => { + self.cpu_now(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCurrentTime(_) => { + self.current_time(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCurrentTime(_) => { + self.current_time(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallQuotedToken(_) => { + self.quoted_token(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteQuotedToken(_) => { + self.quoted_token(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallReadTermFromChars(_) => { + try_or_throw!(self.machine_st, self.read_term_from_chars()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteReadTermFromChars(_) => { + try_or_throw!(self.machine_st, self.read_term_from_chars()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallResetBlock(_) => { + self.reset_block(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteResetBlock(_) => { + self.reset_block(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallReturnFromVerifyAttr(_) | + &Instruction::ExecuteReturnFromVerifyAttr(_) => { + self.return_from_verify_attr(); + } + &Instruction::CallSetBall(_) => { + self.set_ball(); + self.machine_st.p += 1; + } + &Instruction::ExecuteSetBall(_) => { + self.set_ball(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallSetCutPointByDefault(r, _) => { + self.set_cut_point_by_default(r); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteSetCutPointByDefault(r, _) => { + self.set_cut_point_by_default(r); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSetDoubleQuotes(_) => { + self.set_double_quotes(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteSetDoubleQuotes(_) => { + self.set_double_quotes(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSetSeed(_) => { + self.set_seed(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteSetSeed(_) => { + self.set_seed(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSkipMaxList(_) => { + try_or_throw!(self.machine_st, self.machine_st.skip_max_list()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteSkipMaxList(_) => { + try_or_throw!(self.machine_st, self.machine_st.skip_max_list()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSleep(_) => { + self.sleep(); + self.machine_st.p += 1; + } + &Instruction::ExecuteSleep(_) => { + self.sleep(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallSocketClientOpen(_) => { + try_or_throw!(self.machine_st, self.socket_client_open()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteSocketClientOpen(_) => { + try_or_throw!(self.machine_st, self.socket_client_open()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSocketServerOpen(_) => { + try_or_throw!(self.machine_st, self.socket_server_open()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteSocketServerOpen(_) => { + try_or_throw!(self.machine_st, self.socket_server_open()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSocketServerAccept(_) => { + try_or_throw!(self.machine_st, self.socket_server_accept()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteSocketServerAccept(_) => { + try_or_throw!(self.machine_st, self.socket_server_accept()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSocketServerClose(_) => { + try_or_throw!(self.machine_st, self.socket_server_close()); + self.machine_st.p += 1; + } + &Instruction::ExecuteSocketServerClose(_) => { + try_or_throw!(self.machine_st, self.socket_server_close()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallTLSAcceptClient(_) => { + try_or_throw!(self.machine_st, self.tls_accept_client()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteTLSAcceptClient(_) => { + try_or_throw!(self.machine_st, self.tls_accept_client()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallTLSClientConnect(_) => { + try_or_throw!(self.machine_st, self.tls_client_connect()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteTLSClientConnect(_) => { + try_or_throw!(self.machine_st, self.tls_client_connect()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSucceed(_) => { + self.machine_st.p += 1; + } + &Instruction::ExecuteSucceed(_) => { + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallTermAttributedVariables(_) => { + self.term_attributed_variables(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteTermAttributedVariables(_) => { + self.term_attributed_variables(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallTermVariables(_) => { + self.term_variables(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteTermVariables(_) => { + self.term_variables(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallTermVariablesUnderMaxDepth(_) => { + self.term_variables_under_max_depth(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteTermVariablesUnderMaxDepth(_) => { + self.term_variables_under_max_depth(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallTruncateLiftedHeapTo(_) => { + self.truncate_lifted_heap_to(); + self.machine_st.p += 1; + } + &Instruction::ExecuteTruncateLiftedHeapTo(_) => { + self.truncate_lifted_heap_to(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallUnifyWithOccursCheck(_) => { + self.unify_with_occurs_check(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteUnifyWithOccursCheck(_) => { + self.unify_with_occurs_check(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallUnwindEnvironments(_) => { + if !self.unwind_environments() { + self.machine_st.p += 1; + } + } + &Instruction::ExecuteUnwindEnvironments(_) => { + if !self.unwind_environments() { + self.machine_st.p = self.machine_st.cp; + } + } + &Instruction::CallUnwindStack(_) | &Instruction::ExecuteUnwindStack(_) => { + self.machine_st.unwind_stack(); + self.machine_st.backtrack(); + } + &Instruction::CallWAMInstructions(_) => { + try_or_throw!(self.machine_st, self.wam_instructions()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteWAMInstructions(_) => { + try_or_throw!(self.machine_st, self.wam_instructions()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallWriteTerm(_) => { + try_or_throw!(self.machine_st, self.write_term()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteWriteTerm(_) => { + try_or_throw!(self.machine_st, self.write_term()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallWriteTermToChars(_) => { + try_or_throw!(self.machine_st, self.write_term_to_chars()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteWriteTermToChars(_) => { + try_or_throw!(self.machine_st, self.write_term_to_chars()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallScryerPrologVersion(_) => { + self.scryer_prolog_version(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteScryerPrologVersion(_) => { + self.scryer_prolog_version(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCryptoRandomByte(_) => { + self.crypto_random_byte(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCryptoRandomByte(_) => { + self.crypto_random_byte(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCryptoDataHash(_) => { + self.crypto_data_hash(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCryptoDataHash(_) => { + self.crypto_data_hash(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCryptoDataHKDF(_) => { + self.crypto_data_hkdf(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCryptoDataHKDF(_) => { + self.crypto_data_hkdf(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCryptoPasswordHash(_) => { + self.crypto_password_hash(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCryptoPasswordHash(_) => { + self.crypto_password_hash(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCryptoDataEncrypt(_) => { + self.crypto_data_encrypt(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCryptoDataEncrypt(_) => { + self.crypto_data_encrypt(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCryptoDataDecrypt(_) => { + self.crypto_data_decrypt(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCryptoDataDecrypt(_) => { + self.crypto_data_decrypt(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCryptoCurveScalarMult(_) => { + self.crypto_curve_scalar_mult(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCryptoCurveScalarMult(_) => { + self.crypto_curve_scalar_mult(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallEd25519Sign(_) => { + self.ed25519_sign(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteEd25519Sign(_) => { + self.ed25519_sign(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallEd25519Verify(_) => { + self.ed25519_verify(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteEd25519Verify(_) => { + self.ed25519_verify(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallEd25519NewKeyPair(_) => { + self.ed25519_new_key_pair(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteEd25519NewKeyPair(_) => { + self.ed25519_new_key_pair(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallEd25519KeyPairPublicKey(_) => { + self.ed25519_key_pair_public_key(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteEd25519KeyPairPublicKey(_) => { + self.ed25519_key_pair_public_key(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCurve25519ScalarMult(_) => { + self.curve25519_scalar_mult(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCurve25519ScalarMult(_) => { + self.curve25519_scalar_mult(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallFirstNonOctet(_) => { + self.first_non_octet(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteFirstNonOctet(_) => { + self.first_non_octet(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallLoadHTML(_) => { + self.load_html(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteLoadHTML(_) => { + self.load_html(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallLoadXML(_) => { + self.load_xml(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteLoadXML(_) => { + self.load_xml(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallGetEnv(_) => { + self.get_env(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteGetEnv(_) => { + self.get_env(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSetEnv(_) => { + self.set_env(); + self.machine_st.p += 1; + } + &Instruction::ExecuteSetEnv(_) => { + self.set_env(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallUnsetEnv(_) => { + self.unset_env(); + self.machine_st.p += 1; + } + &Instruction::ExecuteUnsetEnv(_) => { + self.unset_env(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallShell(_) => { + self.shell(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteShell(_) => { + self.shell(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallPID(_) => { + self.pid(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecutePID(_) => { + self.pid(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallCharsBase64(_) => { + try_or_throw!(self.machine_st, self.chars_base64()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteCharsBase64(_) => { + try_or_throw!(self.machine_st, self.chars_base64()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallDevourWhitespace(_) => { + try_or_throw!(self.machine_st, self.devour_whitespace()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteDevourWhitespace(_) => { + try_or_throw!(self.machine_st, self.devour_whitespace()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallIsSTOEnabled(_) => { + self.is_sto_enabled(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteIsSTOEnabled(_) => { + self.is_sto_enabled(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallSetSTOAsUnify(_) => { + self.set_sto_as_unify(); + self.machine_st.p += 1; + } + &Instruction::ExecuteSetSTOAsUnify(_) => { + self.set_sto_as_unify(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallSetNSTOAsUnify(_) => { + self.set_nsto_as_unify(); + self.machine_st.p += 1; + } + &Instruction::ExecuteSetNSTOAsUnify(_) => { + self.set_nsto_as_unify(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallSetSTOWithErrorAsUnify(_) => { + self.set_sto_with_error_as_unify(); + self.machine_st.p += 1; + } + &Instruction::ExecuteSetSTOWithErrorAsUnify(_) => { + self.set_sto_with_error_as_unify(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallHomeDirectory(_) => { + self.home_directory(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteHomeDirectory(_) => { + self.home_directory(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallDebugHook(_) => { + self.debug_hook(); + self.machine_st.p += 1; + } + &Instruction::ExecuteDebugHook(_) => { + self.debug_hook(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallPopCount(_) => { + self.pop_count(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecutePopCount(_) => { + self.pop_count(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallAddDiscontiguousPredicate(_) => { + try_or_throw!(self.machine_st, self.add_discontiguous_predicate()); + self.machine_st.p += 1; + } + &Instruction::ExecuteAddDiscontiguousPredicate(_) => { + try_or_throw!(self.machine_st, self.add_discontiguous_predicate()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallAddDynamicPredicate(_) => { + try_or_throw!(self.machine_st, self.add_dynamic_predicate()); + self.machine_st.p += 1; + } + &Instruction::ExecuteAddDynamicPredicate(_) => { + try_or_throw!(self.machine_st, self.add_dynamic_predicate()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallAddMultifilePredicate(_) => { + try_or_throw!(self.machine_st, self.add_multifile_predicate()); + self.machine_st.p += 1; + } + &Instruction::ExecuteAddMultifilePredicate(_) => { + try_or_throw!(self.machine_st, self.add_multifile_predicate()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallAddGoalExpansionClause(_) => { + try_or_throw!(self.machine_st, self.add_goal_expansion_clause()); + self.machine_st.p += 1; + } + &Instruction::ExecuteAddGoalExpansionClause(_) => { + try_or_throw!(self.machine_st, self.add_goal_expansion_clause()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallAddTermExpansionClause(_) => { + try_or_throw!(self.machine_st, self.add_term_expansion_clause()); + self.machine_st.p += 1; + } + &Instruction::ExecuteAddTermExpansionClause(_) => { + try_or_throw!(self.machine_st, self.add_term_expansion_clause()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallAddInSituFilenameModule(_) => { + try_or_throw!(self.machine_st, self.add_in_situ_filename_module()); + self.machine_st.p += 1; + } + &Instruction::ExecuteAddInSituFilenameModule(_) => { + try_or_throw!(self.machine_st, self.add_in_situ_filename_module()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallClauseToEvacuable(_) => { + try_or_throw!(self.machine_st, self.clause_to_evacuable()); + self.machine_st.p += 1; + } + &Instruction::ExecuteClauseToEvacuable(_) => { + try_or_throw!(self.machine_st, self.clause_to_evacuable()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallScopedClauseToEvacuable(_) => { + try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable()); + self.machine_st.p += 1; + } + &Instruction::ExecuteScopedClauseToEvacuable(_) => { + try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallConcludeLoad(_) => { + try_or_throw!(self.machine_st, self.conclude_load()); + self.machine_st.p += 1; + } + &Instruction::ExecuteConcludeLoad(_) => { + try_or_throw!(self.machine_st, self.conclude_load()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallDeclareModule(_) => { + try_or_throw!(self.machine_st, self.declare_module()); + self.machine_st.p += 1; + } + &Instruction::ExecuteDeclareModule(_) => { + try_or_throw!(self.machine_st, self.declare_module()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallLoadCompiledLibrary(_) => { + try_or_throw!(self.machine_st, self.load_compiled_library()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteLoadCompiledLibrary(_) => { + try_or_throw!(self.machine_st, self.load_compiled_library()); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallLoadContextSource(_) => { + self.load_context_source(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteLoadContextSource(_) => { + self.load_context_source(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallLoadContextFile(_) => { + self.load_context_file(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteLoadContextFile(_) => { + self.load_context_file(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallLoadContextDirectory(_) => { + self.load_context_directory(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteLoadContextDirectory(_) => { + self.load_context_directory(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallLoadContextModule(_) => { + self.load_context_module(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteLoadContextModule(_) => { + self.load_context_module(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallLoadContextStream(_) => { + self.load_context_stream(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteLoadContextStream(_) => { + self.load_context_stream(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallPopLoadContext(_) => { + self.pop_load_context(); + self.machine_st.p += 1; + } + &Instruction::ExecutePopLoadContext(_) => { + self.pop_load_context(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallPopLoadStatePayload(_) => { + self.pop_load_state_payload(); + self.machine_st.p += 1; + } + &Instruction::ExecutePopLoadStatePayload(_) => { + self.pop_load_state_payload(); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallPushLoadContext(_) => { + try_or_throw!(self.machine_st, self.push_load_context()); + self.machine_st.p += 1; + } + &Instruction::ExecutePushLoadContext(_) => { + try_or_throw!(self.machine_st, self.push_load_context()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallPushLoadStatePayload(_) => { + self.push_load_state_payload(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecutePushLoadStatePayload(_) => { + self.push_load_state_payload(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallUseModule(_) => { + try_or_throw!(self.machine_st, self.use_module()); + self.machine_st.p += 1; + } + &Instruction::ExecuteUseModule(_) => { + try_or_throw!(self.machine_st, self.use_module()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallBuiltInProperty(_) => { + self.builtin_property(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteBuiltInProperty(_) => { + self.builtin_property(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallMetaPredicateProperty(_) => { + self.meta_predicate_property(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteMetaPredicateProperty(_) => { + self.meta_predicate_property(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallMultifileProperty(_) => { + self.multifile_property(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteMultifileProperty(_) => { + self.multifile_property(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallDiscontiguousProperty(_) => { + self.discontiguous_property(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteDiscontiguousProperty(_) => { + self.discontiguous_property(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallDynamicProperty(_) => { + self.dynamic_property(); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteDynamicProperty(_) => { + self.dynamic_property(); + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); + } + &Instruction::CallAbolishClause(_) => { + try_or_throw!(self.machine_st, self.abolish_clause()); + self.machine_st.p += 1; + } + &Instruction::ExecuteAbolishClause(_) => { + try_or_throw!(self.machine_st, self.abolish_clause()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallAsserta(_) => { + try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Prepend)); + self.machine_st.p += 1; + } + &Instruction::ExecuteAsserta(_) => { + try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Prepend)); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallAssertz(_) => { + try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Append)); + self.machine_st.p += 1; + } + &Instruction::ExecuteAssertz(_) => { + try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Append)); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallRetract(_) => { + try_or_throw!(self.machine_st, self.retract_clause()); + self.machine_st.p += 1; + } + &Instruction::ExecuteRetract(_) => { + try_or_throw!(self.machine_st, self.retract_clause()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallIsConsistentWithTermQueue(_) => { + try_or_throw!(self.machine_st, self.is_consistent_with_term_queue()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::ExecuteIsConsistentWithTermQueue(_) => { + try_or_throw!(self.machine_st, self.is_consistent_with_term_queue()); + step_or_fail!(self, self.machine_st.p += 1); + } + &Instruction::CallFlushTermQueue(_) => { + try_or_throw!(self.machine_st, self.flush_term_queue()); + self.machine_st.p += 1; + } + &Instruction::ExecuteFlushTermQueue(_) => { + try_or_throw!(self.machine_st, self.flush_term_queue()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallRemoveModuleExports(_) => { + try_or_throw!(self.machine_st, self.remove_module_exports()); + self.machine_st.p += 1; + } + &Instruction::ExecuteRemoveModuleExports(_) => { + try_or_throw!(self.machine_st, self.remove_module_exports()); + self.machine_st.p = self.machine_st.cp; + } + &Instruction::CallAddNonCountedBacktracking(_) => { + try_or_throw!(self.machine_st, self.add_non_counted_backtracking()); + self.machine_st.p += 1; + } + &Instruction::ExecuteAddNonCountedBacktracking(_) => { + try_or_throw!(self.machine_st, self.add_non_counted_backtracking()); + self.machine_st.p = self.machine_st.cp; + } + } + } + + let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); + + match INTERRUPT.compare_exchange( + interrupted, + false, + std::sync::atomic::Ordering::Relaxed, + std::sync::atomic::Ordering::Relaxed, + ) { + Ok(interruption) => { + if interruption { + self.machine_st.throw_interrupt_exception(); + self.machine_st.backtrack(); + } + } + Err(_) => unreachable!(), + } } } } diff --git a/src/machine/gc.rs b/src/machine/gc.rs index 1b7f83fe..1f9c80dc 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -4,7 +4,6 @@ use crate::types::*; use core::marker::PhantomData; -// TODO: rename to 'unmark_if_iter', 'mark_if_gc' pub(crate) trait UnmarkPolicy { fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool; fn mark(heap: &mut [HeapCellValue], current: usize); diff --git a/src/machine/heap.rs b/src/machine/heap.rs index cb166b69..6a5e14ef 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -1,7 +1,6 @@ use crate::arena::*; use crate::atom_table::*; use crate::forms::*; -use crate::machine::machine_indices::*; use crate::machine::partial_string::*; use crate::parser::ast::*; use crate::types::*; @@ -251,7 +250,7 @@ where filtered_iter_to_heap_list(heap, values, |_, _| true) } -pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option { +pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option { let extract_integer = |s: usize| -> Option { match Number::try_from(heap[s]) { Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), @@ -265,7 +264,7 @@ pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option Option HeapTemplate { - #[inline] - pub(crate) fn new() -> Self { - HeapTemplate { - buf: RawBlock::new(), - _marker: PhantomData, - } - } - - /* - // TODO: move this to the WAM, then remove the temporary (and by - // then, unnecessary and impossible) "arena" argument. OR, remove - // this thing totally! if we can. by that I mean, just convert a - // little to a HeapCellValue. don't bother writing to the - // heap at all. Each of these data is either already inlinable in a - // HeapCellValue or a pointer to an GC'ed location in memory. - #[inline] - pub(crate) fn put_literal(&mut self, literal: Literal) -> HeapCellValue { - match literal { - Literal::Atom(name) => atom_as_cell!(name), - Literal::Char(c) => char_as_cell!(c), - Literal::EmptyList => empty_list_as_cell!(), - Literal::Fixnum(n) => fixnum_as_cell!(n), - Literal::Integer(bigint_ptr) => { - let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr)); - self[h] - } - Literal::Rational(bigint_ptr) => { - let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr)); - self[h] - } - Literal::Float(f) => typed_arena_ptr_as_cell!(f), - Literal::String(s) => { - if s.as_str().is_empty() { - empty_list_as_cell!() - } else { - // TODO: how do we know where the tail is located?? well, there is no tail. separate tag? - untyped_arena_ptr_as_cell!(s) // self.put_complete_string(arena, &s) - } - } // Literal::Usize(n) => Addr::Usize(n), - } - } - */ - - #[inline] - pub(crate) fn is_empty(&self) -> bool { - self.h() == 0 - } - - #[inline] - pub(crate) fn pop(&mut self) { - let h = self.h(); - - if h > 0 { - self.truncate(h - 1); - } - } - - #[inline] - pub(crate) fn push(&mut self, val: HeapCellValue) -> usize { - let h = self.h(); - - unsafe { - let new_ptr = self.buf.alloc(mem::size_of::()); - ptr::write(new_ptr as *mut _, val); - } - - h - } - - /* - #[inline] - pub(crate) fn atom_at(&self, h: usize) -> bool { - if let HeapCellValue::Atom(..) = &self[h] { - true - } else { - false - } - } - - #[inline] - pub(crate) fn to_unifiable(&mut self, non_heap_value: HeapCellValue) -> Addr { - match non_heap_value { - HeapCellValue::Addr(addr) => addr, - val @ HeapCellValue::Atom(..) - | val @ HeapCellValue::Integer(_) - | val @ HeapCellValue::DBRef(_) - | val @ HeapCellValue::Rational(_) => Addr::Con(self.push(val)), - val @ HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(self.push(val)), - val @ HeapCellValue::NamedStr(..) => Addr::Str(self.push(val)), - HeapCellValue::PartialString(pstr, has_tail) => { - let h = self.push(HeapCellValue::PartialString(pstr, has_tail)); - - if has_tail { - self.push(HeapCellValue::Addr(Addr::EmptyList)); - } - - Addr::Con(h) - } - val @ HeapCellValue::Stream(..) => Addr::Stream(self.push(val)), - val @ HeapCellValue::TcpListener(..) => Addr::TcpListener(self.push(val)), - } - } - */ - - #[inline] - pub(crate) fn truncate(&mut self, h: usize) { - let new_ptr = self.buf.top as usize - h * mem::size_of::(); - self.buf.ptr = new_ptr as *mut _; - } - - #[inline] - pub(crate) fn h(&self) -> usize { - (self.buf.top as usize - self.buf.ptr as usize) / mem::size_of::() - } - - pub(crate) fn append(&mut self, vals: Vec) { - for val in vals { - self.push(val); - } - } - - pub(crate) fn clear(&mut self) { - if !self.buf.base.is_null() { - self.truncate(0); - self.buf.top = self.buf.base; - } - } - - /* TODO: get rid of this!! - #[inline] - pub(crate) fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> { - match addr { - &Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => { - RefOrOwned::Borrowed(&self[h]) - } - addr => RefOrOwned::Owned(HeapCellValue::Addr(*addr)), - } - } - */ -} - -impl Index for HeapTemplate { - type Output = HeapCellValue; - - #[inline] - fn index(&self, index: u64) -> &Self::Output { - unsafe { - let ptr = - self.buf.top as usize - (index as usize + 1) * mem::size_of::(); - &*(ptr as *const HeapCellValue) - } - } -} - -impl Index for HeapTemplate { - type Output = HeapCellValue; - - #[inline] - fn index(&self, index: usize) -> &Self::Output { - unsafe { - let ptr = self.buf.top as usize - (index + 1) * mem::size_of::(); - &*(ptr as *const HeapCellValue) - } - } -} - -impl IndexMut for HeapTemplate { - #[inline] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - unsafe { - let ptr = self.buf.top as usize - (index + 1) * mem::size_of::(); - &mut *(ptr as *mut HeapCellValue) - } - } -} -*/ diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 036c31d7..1ad94f15 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -1,4 +1,3 @@ -use crate::clause_types::*; use crate::forms::*; use crate::machine::loader::*; use crate::machine::machine_errors::*; @@ -8,6 +7,7 @@ use crate::machine::term_stream::*; use crate::machine::*; use crate::parser::ast::*; +use fxhash::FxBuildHasher; use indexmap::IndexSet; use ref_thread_local::RefThreadLocal; use slice_deque::{sdeq, SliceDeque}; @@ -753,7 +753,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType { match ClauseType::from(name, arity) { - ClauseType::Named(name, arity, _) => { + ClauseType::Named(arity, name, _) => { let payload_compilation_target = self.payload.compilation_target; let idx = self.get_or_insert_code_index( @@ -761,7 +761,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { payload_compilation_target, ); - ClauseType::Named(name, arity, idx) + ClauseType::Named(arity, name, idx) } ct => ct, } @@ -774,11 +774,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { arity: usize, ) -> ClauseType { match ClauseType::from(name, arity) { - ClauseType::Named(name, arity, _) => { + ClauseType::Named(arity, name, _) => { let key = (name, arity); let idx = self.get_or_insert_qualified_code_index(module_name, key); - ClauseType::Named(name, arity, idx) + ClauseType::Named(arity, name, idx) } ct => ct, } @@ -922,7 +922,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let local_extensible_predicates = mem::replace( &mut module.local_extensible_predicates, - LocalExtensiblePredicates::new(), + LocalExtensiblePredicates::with_hasher(FxBuildHasher::default()), ); for ((compilation_target, key), skeleton) in local_extensible_predicates.iter() { @@ -1162,11 +1162,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let subloader: Loader<'_, BootstrappingLoadState> = Loader { payload: BootstrappingLoadState( - LoadStatePayload::new(self.wam_prelude.code_repo.code.len(), term_stream) + LoadStatePayload::new(self.wam_prelude.code.len(), term_stream) ), wam_prelude: MachinePreludeView { indices: self.wam_prelude.indices, - code_repo: self.wam_prelude.code_repo, + code: self.wam_prelude.code, load_contexts: self.wam_prelude.load_contexts, } }; @@ -1225,11 +1225,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let subloader: Loader<'_, BootstrappingLoadState> = Loader { payload: BootstrappingLoadState( - LoadStatePayload::new(self.wam_prelude.code_repo.code.len(), term_stream), + LoadStatePayload::new(self.wam_prelude.code.len(), term_stream), ), wam_prelude: MachinePreludeView { indices: self.wam_prelude.indices, - code_repo: self.wam_prelude.code_repo, + code: self.wam_prelude.code, load_contexts: self.wam_prelude.load_contexts, } }; diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 061452ab..e4a40a20 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -1,6 +1,5 @@ use crate::arena::*; use crate::atom_table::*; -use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; use crate::indexing::*; @@ -327,7 +326,7 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> { loader.compile_and_submit()?; } - let repo_len = loader.wam_prelude.code_repo.code.len(); + let repo_len = loader.wam_prelude.code.len(); loader .payload @@ -363,7 +362,7 @@ pub struct Loader<'a, LS: LoadState<'a>> { impl<'a, LS: LoadState<'a>> Loader<'a, LS> { #[inline] pub(super) fn new(wam: &'a mut Machine, term_stream: >::TS) -> Self { - let payload = LoadStatePayload::new(wam.code_repo.code.len(), term_stream); + let payload = LoadStatePayload::new(wam.code.len(), term_stream); let (wam_prelude, machine_st) = wam.prelude_view_and_machine_st(); Self { @@ -696,8 +695,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { RetractionRecord::AddedIndex(index_key, clause_loc) => { // WAS: inner_index_locs) => { if let Some(index_loc) = index_key.switch_on_term_loc() { - let indexing_code = match &mut self.wam_prelude.code_repo.code[index_loc] { - Line::IndexingCode(indexing_code) => indexing_code, + let indexing_code = match &mut self.wam_prelude.code[index_loc] { + Instruction::IndexingCode(indexing_code) => indexing_code, _ => { unreachable!() } @@ -743,10 +742,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { // write the retraction logic of this arm. } RetractionRecord::ReplacedChoiceOffset(instr_loc, offset) => { - match self.wam_prelude.code_repo.code[instr_loc] { - Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) - | Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) - | Line::Choice(ChoiceInstruction::DefaultRetryMeElse(ref mut o)) => { + match self.wam_prelude.code[instr_loc] { + Instruction::TryMeElse(ref mut o) | + Instruction::RetryMeElse(ref mut o) | + Instruction::DefaultRetryMeElse(ref mut o) => { *o = offset; } _ => { @@ -755,22 +754,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } } RetractionRecord::AppendedTrustMe(instr_loc, offset, is_default) => { - match self.wam_prelude.code_repo.code[instr_loc] { - Line::Choice(ref mut choice_instr) => { - *choice_instr = if is_default { - ChoiceInstruction::DefaultTrustMe(offset) - } else { - ChoiceInstruction::TrustMe(offset) - }; - } - _ => { - unreachable!(); - } - } + self.wam_prelude.code[instr_loc] = if is_default { + Instruction::DefaultTrustMe(offset) + } else { + Instruction::TrustMe(offset) + }; } RetractionRecord::ReplacedSwitchOnTermVarIndex(index_loc, old_v) => { - match self.wam_prelude.code_repo.code[index_loc] { - Line::IndexingCode(ref mut indexing_code) => match &mut indexing_code[0] { + match self.wam_prelude.code[index_loc] { + Instruction::IndexingCode(ref mut indexing_code) => match &mut indexing_code[0] { IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm( _, ref mut v, @@ -784,16 +776,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } } RetractionRecord::ModifiedTryMeElse(instr_loc, o) => { - self.wam_prelude.code_repo.code[instr_loc] = - Line::Choice(ChoiceInstruction::TryMeElse(o)); + self.wam_prelude.code[instr_loc] = Instruction::TryMeElse(o); } RetractionRecord::ModifiedRetryMeElse(instr_loc, o) => { - self.wam_prelude.code_repo.code[instr_loc] = - Line::Choice(ChoiceInstruction::RetryMeElse(o)); + self.wam_prelude.code[instr_loc] = Instruction::RetryMeElse(o); } RetractionRecord::ModifiedRevJmpBy(instr_loc, o) => { - self.wam_prelude.code_repo.code[instr_loc] = - Line::Control(ControlInstruction::RevJmpBy(o)); + self.wam_prelude.code[instr_loc] = Instruction::RevJmpBy(o); } RetractionRecord::SkeletonClausePopBack(compilation_target, key) => { match self @@ -959,7 +948,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } } RetractionRecord::ReplacedIndexingLine(index_loc, indexing_code) => { - self.wam_prelude.code_repo.code[index_loc] = Line::IndexingCode(indexing_code); + self.wam_prelude.code[index_loc] = Instruction::IndexingCode(indexing_code); } RetractionRecord::RemovedLocalSkeletonClauseLocations( compilation_target, @@ -992,34 +981,34 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } } RetractionRecord::ReplacedDynamicElseOffset(instr_loc, next) => { - match self.wam_prelude.code_repo.code[instr_loc] { - Line::Choice(ChoiceInstruction::DynamicElse( + match self.wam_prelude.code[instr_loc] { + Instruction::DynamicElse( _, _, NextOrFail::Next(ref mut o), - )) - | Line::Choice(ChoiceInstruction::DynamicInternalElse( + ) + | Instruction::DynamicInternalElse( _, _, NextOrFail::Next(ref mut o), - )) => { + ) => { *o = next; } _ => {} } } RetractionRecord::AppendedNextOrFail(instr_loc, fail) => { - match self.wam_prelude.code_repo.code[instr_loc] { - Line::Choice(ChoiceInstruction::DynamicElse( + match self.wam_prelude.code[instr_loc] { + Instruction::DynamicElse( _, _, ref mut next_or_fail, - )) - | Line::Choice(ChoiceInstruction::DynamicInternalElse( + ) + | Instruction::DynamicInternalElse( _, _, ref mut next_or_fail, - )) => { + ) => { *next_or_fail = fail; } _ => {} @@ -1384,7 +1373,7 @@ impl<'a> MachinePreludeView<'a> { } impl Machine { - pub(crate) fn use_module(&mut self) { + pub(crate) fn use_module(&mut self) -> CallResult { let subevacuable_addr = self .machine_st .store(self.machine_st.deref(self.machine_st.registers[2])); @@ -1395,7 +1384,7 @@ impl Machine { match payload.compilation_target { CompilationTarget::Module(module_name) => module_name, CompilationTarget::User => { - return; + return Ok(()); } } }); @@ -1415,10 +1404,10 @@ impl Machine { }; let result = use_module(); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } - pub(crate) fn load_compiled_library(&mut self) { + pub(crate) fn load_compiled_library(&mut self) -> CallResult { let library = cell_as_atom!( self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); @@ -1426,7 +1415,7 @@ impl Machine { if let Some(module) = self.indices.modules.get(&library) { if let ListingSource::DynamicallyGenerated = module.listing_src { self.machine_st.fail = true; - return; + return Ok(()); } let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); @@ -1444,13 +1433,14 @@ impl Machine { }; let result = import_module(); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } else { self.machine_st.fail = true; + Ok(()) } } - pub(crate) fn declare_module(&mut self) { + pub(crate) fn declare_module(&mut self) -> CallResult { let module_name = cell_as_atom!( self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); @@ -1471,34 +1461,34 @@ impl Machine { }; let result = declare_module(); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } #[inline] - pub(crate) fn add_discontiguous_predicate(&mut self) { + pub(crate) fn add_discontiguous_predicate(&mut self) -> CallResult { self.add_extensible_predicate_declaration( |loader, compilation_target, clause_name, arity| { loader.add_discontiguous_predicate(compilation_target, clause_name, arity) }, - ); + ) } #[inline] - pub(crate) fn add_dynamic_predicate(&mut self) { + pub(crate) fn add_dynamic_predicate(&mut self) -> CallResult { self.add_extensible_predicate_declaration( |loader, compilation_target, clause_name, arity| { loader.add_dynamic_predicate(compilation_target, clause_name, arity) }, - ); + ) } #[inline] - pub(crate) fn add_multifile_predicate(&mut self) { + pub(crate) fn add_multifile_predicate(&mut self) -> CallResult { self.add_extensible_predicate_declaration( |loader, compilation_target, clause_name, arity| { loader.add_multifile_predicate(compilation_target, clause_name, arity) }, - ); + ) } fn add_extensible_predicate_declaration( @@ -1509,7 +1499,7 @@ impl Machine { Atom, usize, ) -> Result<(), SessionError>, - ) { + ) -> CallResult { let module_name = cell_as_atom!( self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); @@ -1543,10 +1533,10 @@ impl Machine { }; let result = add_predicate_decl(); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } - pub(crate) fn add_term_expansion_clause(&mut self) { + pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult { let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let add_clause = || { @@ -1564,10 +1554,10 @@ impl Machine { }; let result = add_clause(); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } - pub(crate) fn add_goal_expansion_clause(&mut self) { + pub(crate) fn add_goal_expansion_clause(&mut self) -> CallResult { let target_module_name = cell_as_atom!( self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); @@ -1594,10 +1584,10 @@ impl Machine { }; let result = add_clause(); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } - pub(crate) fn add_in_situ_filename_module(&mut self) { + pub(crate) fn add_in_situ_filename_module(&mut self) -> CallResult { let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let add_in_situ_filename_module = || { @@ -1643,7 +1633,7 @@ impl Machine { }; let result = add_in_situ_filename_module(); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } pub(crate) fn loader_from_heap_evacuable<'a>( @@ -1668,15 +1658,13 @@ impl Machine { pub(crate) fn push_load_state_payload(&mut self) { let payload = arena_alloc!( LoadStatePayload::new( - self.code_repo.code.len(), + self.code.len(), LiveTermStream::new(ListingSource::User), ), &mut self.machine_st.arena ); - let var = self.machine_st.deref( - self.machine_st.registers[1] - ); + let var = self.machine_st.deref(self.machine_st.registers[1]); self.machine_st.bind( var.as_var().unwrap(), @@ -1718,38 +1706,40 @@ impl Machine { self.load_contexts.pop(); } - pub(crate) fn push_load_context(&mut self) { - let stream = try_or_fail!( - self.machine_st, - self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("$push_load_context"), - 2, - ) - ); + pub(crate) fn push_load_context(&mut self) -> CallResult { + let stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("$push_load_context"), + 2, + )?; let path = cell_as_atom!( self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) ); self.load_contexts.push(LoadContext::new(path.as_str(), stream)); + Ok(()) } pub(crate) fn restore_load_state_payload( &mut self, result: Result, SessionError>, - ) { + ) -> CallResult { match result { Ok(_payload) => { + Ok(()) } Err(e) => { - self.throw_session_error(e, (atom!("load"), 1)); + let err = self.machine_st.session_error(e); + let stub = functor_stub(atom!("load"), 1); + + Err(self.machine_st.error_form(err, stub)) } } } - pub(crate) fn scoped_clause_to_evacuable(&mut self) { + pub(crate) fn scoped_clause_to_evacuable(&mut self) -> CallResult { let module_name = cell_as_atom!( self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); @@ -1762,18 +1752,18 @@ impl Machine { }; let result = loader.read_and_enqueue_term(temp_v!(2), compilation_target); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } - pub(crate) fn clause_to_evacuable(&mut self) { + pub(crate) fn clause_to_evacuable(&mut self) -> CallResult { let loader = self.loader_from_heap_evacuable(temp_v!(2)); let compilation_target = loader.payload.compilation_target; let result = loader.read_and_enqueue_term(temp_v!(1), compilation_target); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } - pub(crate) fn conclude_load(&mut self) { + pub(crate) fn conclude_load(&mut self) -> CallResult { let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let compile_final_terms = || { @@ -1786,7 +1776,7 @@ impl Machine { }; let result = compile_final_terms(); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } pub(crate) fn load_context_source(&mut self) { @@ -1852,7 +1842,7 @@ impl Machine { } } - pub(crate) fn compile_assert<'a>(&'a mut self, append_or_prepend: AppendOrPrepend) { + pub(crate) fn compile_assert<'a>(&'a mut self, append_or_prepend: AppendOrPrepend) -> CallResult { let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(3)], self.machine_st[temp_v!(4)]); @@ -1906,26 +1896,27 @@ impl Machine { }; match compile_assert() { - Ok(_) => {} + Ok(_) => Ok(()), Err(e) => { - let error_pi = match append_or_prepend { - AppendOrPrepend::Append => (atom!("assertz"), 1), - AppendOrPrepend::Prepend => (atom!("asserta"), 1), + let stub = match append_or_prepend { + AppendOrPrepend::Append => functor_stub(atom!("assertz"), 1), + AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1), }; + let err = self.machine_st.session_error(e); - self.throw_session_error(e, error_pi); + Err(self.machine_st.error_form(err, stub)) } } } - pub(crate) fn abolish_clause(&mut self) { + pub(crate) fn abolish_clause(&mut self) -> CallResult { let module_name = cell_as_atom!( self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); let key = self .machine_st - .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]); + .read_predicate_key(self.machine_st.registers[2], self.machine_st.registers[3]); let compilation_target = match module_name { atom!("user") => CompilationTarget::User, @@ -2000,14 +1991,16 @@ impl Machine { }; match abolish_clause() { - Ok(_) => {} + Ok(_) => Ok(()), Err(e) => { - self.throw_session_error(e, (atom!("abolish"), 1)); + let stub = functor_stub(atom!("abolish"), 1); + let err = self.machine_st.session_error(e); + Err(self.machine_st.error_form(err, stub)) } } } - pub(crate) fn retract_clause(&mut self) { + pub(crate) fn retract_clause(&mut self) -> CallResult { let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]); @@ -2066,14 +2059,17 @@ impl Machine { }; match retract_clause() { - Ok(_) => {} + Ok(_) => Ok(()), Err(e) => { - self.throw_session_error(e, (atom!("retract"), 1)); + let stub = functor_stub(atom!("retract"), 1); + let err = self.machine_st.session_error(e); + + Err(self.machine_st.error_form(err, stub)) } } } - pub(crate) fn is_consistent_with_term_queue(&mut self) { + pub(crate) fn is_consistent_with_term_queue(&mut self) -> CallResult { let module_name = cell_as_atom!( self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); @@ -2095,10 +2091,10 @@ impl Machine { || !key.is_consistent(&loader.payload.predicates); let result = LiveLoadAndMachineState::evacuate(loader); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } - pub(crate) fn flush_term_queue(&mut self) { + pub(crate) fn flush_term_queue(&mut self) -> CallResult { let mut loader = self.loader_from_heap_evacuable(temp_v!(1)); let flush_term_queue = || { @@ -2110,10 +2106,10 @@ impl Machine { }; let result = flush_term_queue(); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } - pub(crate) fn remove_module_exports(&mut self) { + pub(crate) fn remove_module_exports(&mut self) -> CallResult { let module_name = cell_as_atom!( self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) ); @@ -2126,10 +2122,10 @@ impl Machine { }; let result = remove_module_exports(); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } - pub(crate) fn add_non_counted_backtracking(&mut self) { + pub(crate) fn add_non_counted_backtracking(&mut self) -> CallResult { let key = self .machine_st .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]); @@ -2138,7 +2134,7 @@ impl Machine { loader.payload.non_counted_bt_preds.insert(key); let result = LiveLoadAndMachineState::evacuate(loader); - self.restore_load_state_payload(result); + self.restore_load_state_payload(result) } pub(crate) fn meta_predicate_property(&mut self) { @@ -2271,10 +2267,10 @@ impl Machine { .read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]); match ClauseType::from(key.0, key.1) { - ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN => { + ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN(_) => { return; } - ClauseType::Named(name, arity, _) => { + ClauseType::Named(arity, name, _) => { if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) { self.machine_st.fail = !module.code_dir.contains_key(&(name, arity)); return; diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index cae977e5..37910002 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -538,13 +538,18 @@ impl MachineState { pub(super) fn throw_exception(&mut self, err: MachineStub) { let h = self.heap.len(); + let err_len = err.len(); self.ball.boundary = 0; self.ball.stub.truncate(0); self.heap.extend(err.into_iter()); - self.registers[1] = str_loc_as_cell!(h); + self.registers[1] = if err_len == 1 { + heap_loc_as_cell!(h) + } else { + str_loc_as_cell!(h) + }; self.set_ball(); self.unwind_stack(); diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 3f8d47e8..5f9d08d5 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -2,30 +2,22 @@ use crate::parser::ast::*; use crate::arena::*; use crate::atom_table::*; -use crate::clause_types::*; use crate::fixtures::*; use crate::forms::*; use crate::instructions::*; -use crate::machine::*; -use crate::machine::heap::*; use crate::machine::loader::*; -use crate::machine::machine_errors::MachineStub; use crate::machine::machine_state::*; use crate::machine::streams::Stream; +use fxhash::FxBuildHasher; use indexmap::IndexMap; use std::cell::Cell; use std::cmp::Ordering; use std::collections::BTreeSet; -use std::ops::{Add, AddAssign, Deref, Sub, SubAssign}; +use std::ops::Deref; use std::rc::Rc; -// these statics store the locations of one-off control instructions -// in the code vector. - -pub static HALT_CODE: usize = 0; - use crate::types::*; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity); @@ -134,6 +126,7 @@ impl Default for CodeIndex { } } +/* #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] pub enum REPLCodePtr { AddDiscontiguousPredicate, @@ -174,156 +167,28 @@ pub enum REPLCodePtr { #[derive(Debug, Clone, Copy, PartialEq)] pub enum CodePtr { - BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call. - CallN(usize, LocalCodePtr, bool), // arity, local, last call. - Local(LocalCodePtr), - REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer. + BuiltInClause(BuiltInClauseType, usize), // local is the successor call. + CallN(usize, usize, bool), // arity, local, last call. + Local(usize), + REPL(REPLCodePtr, usize), // the REPL code, the return pointer. VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir. } impl CodePtr { - pub(crate) fn local(&self) -> LocalCodePtr { + pub(crate) fn local(&self) -> usize { match self { - &CodePtr::BuiltInClause(_, ref local) - | &CodePtr::CallN(_, ref local, _) - | &CodePtr::Local(ref local) => local.clone(), - &CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p), - &CodePtr::REPL(_, p) => p, // | &CodePtr::DynamicTransaction(_, p) => p, + &CodePtr::BuiltInClause(_, ref local) | + &CodePtr::CallN(_, ref local, _) | + &CodePtr::Local(ref local) => *local, + &CodePtr::VerifyAttrInterrupt(p) => p, + &CodePtr::REPL(_, p) => p, } } - #[inline] - pub(crate) fn is_halt(&self) -> bool { - if let CodePtr::Local(LocalCodePtr::Halt) = self { - true - } else { - false - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum LocalCodePtr { - DirEntry(usize), // offset - Halt, - // IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset - // TopLevel(usize, usize), // chunk_num, offset -} - -impl Machine { - pub(crate) fn is_reset_cont_marker(&self, p: LocalCodePtr) -> bool { - match self.code_repo.lookup_instr(&self.machine_st, &CodePtr::Local(p)) { - Some(line) => match line.as_ref(&self.code_repo.code) { - Line::Control(ControlInstruction::CallClause(ref ct, ..)) => { - if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct { - return true; - } - } - _ => {} - }, - None => {} - } - - false - } -} - -impl LocalCodePtr { - pub fn assign_if_local(&mut self, cp: CodePtr) { - match cp { - CodePtr::Local(local) => *self = local, - _ => {} - } - } - - #[inline] - pub fn abs_loc(&self) -> usize { - match self { - LocalCodePtr::DirEntry(ref p) => *p, - // LocalCodePtr::IndexingBuf(ref p, ..) => *p, - LocalCodePtr::Halt => unreachable!(), - } - } - - pub(crate) fn as_functor(&self) -> MachineStub { + pub fn assign_if_local(&self, cp: &mut usize) { match self { - LocalCodePtr::DirEntry(p) => { - functor!(atom!("dir_entry"), [fixnum(*p)]) - } - LocalCodePtr::Halt => { - functor!(atom!("halt")) - } - /* - LocalCodePtr::IndexingBuf(p, o, i) => { - functor!( - atom!("indexed_buf"), - [fixnum(*p), fixnum(*o), fixnum(*i)] - ) - } - */ - } - } -} - -impl Default for CodePtr { - #[inline] - fn default() -> Self { - CodePtr::Local(LocalCodePtr::default()) - } -} - -impl Default for LocalCodePtr { - #[inline] - fn default() -> Self { - LocalCodePtr::DirEntry(0) - } -} - -impl Add for LocalCodePtr { - type Output = LocalCodePtr; - - #[inline] - fn add(self, rhs: usize) -> Self::Output { - match self { - LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs), - LocalCodePtr::Halt => unreachable!(), - // LocalCodePtr::IndexingBuf(p, o, i) => LocalCodePtr::IndexingBuf(p, o, i + rhs), - } - } -} - -impl Sub for LocalCodePtr { - type Output = Option; - - #[inline] - fn sub(self, rhs: usize) -> Self::Output { - match self { - LocalCodePtr::DirEntry(p) => p.checked_sub(rhs).map(LocalCodePtr::DirEntry), - LocalCodePtr::Halt => unreachable!(), - // LocalCodePtr::IndexingBuf(p, o, i) => i - // .checked_sub(rhs) - // .map(|r| LocalCodePtr::IndexingBuf(p, o, r)), - } - } -} - -impl SubAssign for LocalCodePtr { - #[inline] - fn sub_assign(&mut self, rhs: usize) { - match self { - LocalCodePtr::DirEntry(ref mut p) => *p -= rhs, - LocalCodePtr::Halt => unreachable!() // | LocalCodePtr::IndexingBuf(..) => unreachable!(), - } - } -} - -impl AddAssign for LocalCodePtr { - #[inline] - fn add_assign(&mut self, rhs: usize) { - match self { - &mut LocalCodePtr::DirEntry(ref mut i) => *i += rhs, - // | &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs, - &mut LocalCodePtr::Halt => unreachable!(), + CodePtr::Local(local) => *cp = *local, + _ => {} } } } @@ -333,7 +198,9 @@ impl Add for CodePtr { fn add(self, rhs: usize) -> Self::Output { match self { - p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => p, + p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => { + p + } CodePtr::Local(local) => CodePtr::Local(local + rhs), CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => { CodePtr::Local(local + rhs) @@ -362,20 +229,30 @@ impl SubAssign for CodePtr { } } -pub(crate) type HeapVarDict = IndexMap, HeapCellValue>; -pub(crate) type AllocVarDict = IndexMap, VarData>; +impl Default for CodePtr { + #[inline] + fn default() -> Self { + CodePtr::Local(0) + } +} +*/ + +pub(crate) type HeapVarDict = IndexMap, HeapCellValue, FxBuildHasher>; +pub(crate) type AllocVarDict = IndexMap, VarData, FxBuildHasher>; -pub(crate) type GlobalVarDir = IndexMap)>; +pub(crate) type GlobalVarDir = IndexMap), FxBuildHasher>; -pub(crate) type StreamAliasDir = IndexMap; +pub(crate) type StreamAliasDir = IndexMap; pub(crate) type StreamDir = BTreeSet; -pub(crate) type MetaPredicateDir = IndexMap>; +pub(crate) type MetaPredicateDir = IndexMap, FxBuildHasher>; -pub(crate) type ExtensiblePredicates = IndexMap; +pub(crate) type ExtensiblePredicates = IndexMap; pub(crate) type LocalExtensiblePredicates = - IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>; + IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton, FxBuildHasher>; + +pub(crate) type CodeDir = IndexMap; #[derive(Debug)] pub struct IndexStore { @@ -504,14 +381,14 @@ impl IndexStore { ) -> Option { if module == atom!("user") { match ClauseType::from(name, arity) { - ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(), + ClauseType::Named(arity, name, _) => self.code_dir.get(&(name, arity)).cloned(), _ => None, } } else { self.modules .get(&module) .and_then(|module| match ClauseType::from(name, arity) { - ClauseType::Named(name, arity, _) => { + ClauseType::Named(arity, name, _) => { module.code_dir.get(&(name, arity)).cloned() } _ => None, @@ -561,8 +438,10 @@ impl IndexStore { #[inline] pub(super) fn new() -> Self { - index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new()) + index_store!( + CodeDir::with_hasher(FxBuildHasher::default()), + default_op_dir(), + ModuleDir::with_hasher(FxBuildHasher::default()) + ) } } - -pub(crate) type CodeDir = IndexMap; diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 6bd29da2..6da9674b 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -55,14 +55,14 @@ pub struct MachineState { pub arena: Arena, pub(super) pdl: Vec, pub(super) s: HeapPtr, - pub(super) p: CodePtr, + pub(super) p: usize, pub(super) oip: u32, // first internal code ptr pub(super) iip : u32, // second internal code ptr pub(super) b: usize, pub(super) b0: usize, pub(super) e: usize, pub(super) num_of_args: usize, - pub(super) cp: LocalCodePtr, + pub(super) cp: usize, pub(super) attr_var_init: AttrVarInitializer, pub(super) fail: bool, pub heap: Heap, @@ -79,7 +79,6 @@ pub struct MachineState { // locations of cleaners, cut points, the previous block. for setup_call_cleanup. pub(super) cont_pts: Vec<(HeapCellValue, usize, usize)>, pub(super) cwil: CWIL, - pub(super) last_call: bool, // TODO: REMOVE THIS. pub(crate) flags: MachineFlags, pub(crate) cc: usize, pub(crate) global_clock: usize, @@ -115,7 +114,6 @@ impl fmt::Debug for MachineState { .field("ball", &self.ball) .field("lifted_heap", &self.lifted_heap) .field("interms", &self.interms) - .field("last_call", &self.last_call) .field("flags", &self.flags) .field("cc", &self.cc) .field("global_clock", &self.global_clock) @@ -365,6 +363,20 @@ impl<'a> CopierTarget for CopyBallTerm<'a> { } impl MachineState { + pub(crate) fn backtrack(&mut self) { + let b = self.b; + let or_frame = self.stack.index_or_frame(b); + + self.b0 = or_frame.prelude.b0; + self.p = or_frame.prelude.bp; + + self.oip = or_frame.prelude.boip; + self.iip = or_frame.prelude.biip; + + self.pdl.clear(); + self.fail = false; + } + pub(crate) fn increment_call_count(&mut self) -> CallResult { if self.cwil.inference_limit_exceeded || self.ball.stub.len() > 0 { return Ok(()); @@ -422,17 +434,19 @@ impl MachineState { self.error_form(err, stub) } - pub(super) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) { - self.cp.assign_if_local(self.p + 1); + #[inline(always)] + pub(super) fn call_at_index(&mut self, arity: usize, p: usize) { + self.cp = self.p + 1; + self.p = p; self.num_of_args = arity; self.b0 = self.b; - self.p = CodePtr::Local(p); } - pub(super) fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) { + #[inline(always)] + pub(super) fn execute_at_index(&mut self, arity: usize, p: usize) { self.num_of_args = arity; self.b0 = self.b; - self.p = CodePtr::Local(p); + self.p = p; } pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult { @@ -467,7 +481,7 @@ impl MachineState { if stream.past_end_of_stream() { if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.last_call, self); + return Ok(()); } else if self.fail { return Ok(()); } @@ -710,7 +724,7 @@ impl MachineState { or_frame.prelude.e = self.e; or_frame.prelude.cp = self.cp; or_frame.prelude.b = self.b; - or_frame.prelude.bp = self.p.local() + offset; + or_frame.prelude.bp = self.p + offset; or_frame.prelude.boip = 0; or_frame.prelude.biip = 0; or_frame.prelude.tr = self.tr; @@ -720,7 +734,7 @@ impl MachineState { self.b = b; for i in 0..n { - self.stack[stack_loc!(OrFrame, b, i)] = self.registers[i+1]; + or_frame[i] = self.registers[i+1]; } self.hb = self.heap.len(); @@ -737,7 +751,7 @@ impl MachineState { or_frame.prelude.e = self.e; or_frame.prelude.cp = self.cp; or_frame.prelude.b = self.b; - or_frame.prelude.bp = self.p.local(); // + 1; in self.iip now! + or_frame.prelude.bp = self.p; // + 1; in self.iip now! or_frame.prelude.boip = self.oip; or_frame.prelude.biip = self.iip + 1; or_frame.prelude.tr = self.tr; @@ -751,7 +765,7 @@ impl MachineState { } self.hb = self.heap.len(); - self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset)); + self.p = self.p + offset; self.oip = 0; self.iip = 0; diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index ee04d645..6461f7f0 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1,13 +1,11 @@ use crate::arena::*; use crate::atom_table::*; use crate::types::*; -use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; use crate::machine::attributed_variables::*; use crate::machine::copier::*; use crate::machine::heap::*; -use crate::machine::Machine; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; @@ -23,11 +21,6 @@ use indexmap::IndexSet; use std::cmp::Ordering; use std::convert::TryFrom; -// TODO: move this block to.. a place. -impl Machine { - -} - impl MachineState { pub(crate) fn new() -> Self { MachineState { @@ -35,14 +28,14 @@ impl MachineState { atom_tbl: AtomTable::new(), pdl: Vec::with_capacity(1024), s: HeapPtr::default(), - p: CodePtr::default(), + p: 0, oip: 0, iip: 0, b: 0, b0: 0, e: 0, num_of_args: 0, - cp: LocalCodePtr::default(), + cp: 0, attr_var_init: AttrVarInitializer::new(0), fail: false, heap: Heap::with_capacity(256 * 256), @@ -58,7 +51,6 @@ impl MachineState { interms: vec![Number::default();256], cont_pts: Vec::with_capacity(256), cwil: CWIL::new(), - last_call: false, flags: MachineFlags::default(), cc: 0, global_clock: 0, @@ -202,16 +194,16 @@ impl MachineState { match r1.get_tag() { RefTag::StackCell => { self.stack[r1.get_value() as usize] = t2; + self.trail(TrailRef::Ref(r1)); } RefTag::HeapCell => { self.heap[r1.get_value() as usize] = t2; + self.trail(TrailRef::Ref(r1)); } RefTag::AttrVar => { self.bind_attr_var(r1.get_value() as usize, t2); } }; - - self.trail(TrailRef::Ref(r1)); } else { read_heap_cell!(a2, (HeapCellValueTag::StackVar, s) => { @@ -864,17 +856,6 @@ impl MachineState { ); } - pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { - let old_h = self.heap.len(); - - let a1 = self.registers[1]; - let a2 = self.registers[2]; - - copy_term(CopyTerm::new(self), a1, attr_var_policy); - - unify_fn!(*self, heap_loc_as_cell!(old_h), a2); - } - pub(super) fn unwind_stack(&mut self) { self.b = self.block; self.fail = true; @@ -1912,9 +1893,6 @@ impl MachineState { ); } Some(PStrPrefixCmpResult { prefix_len, .. }) => { - // TODO: this is woefully insufficient! you need to - // match the remaining portion of string if offset < - // pstr.len(). let focus = heap_pstr_iter.focus(); let tail_addr = self.heap[focus]; @@ -1996,23 +1974,7 @@ impl MachineState { ) } - pub(super) fn handle_internal_call_n(&mut self, arity: usize) { - let arity = arity + 1; - let pred = self.registers[1]; - - for i in 2..arity { - self.registers[i - 1] = self.registers[i]; - } - - if arity > 1 { - self.registers[arity - 1] = pred; - return; - } - - self.fail = true; - } - - pub(super) fn setup_call_n(&mut self, arity: usize) -> Option { + pub(super) fn setup_call_n(&mut self, arity: usize) -> Result { let addr = self.store(self.deref(self.registers[arity])); let (name, narity) = read_heap_cell!(addr, @@ -2022,10 +1984,7 @@ impl MachineState { if narity + arity > MAX_ARITY { let stub = functor_stub(atom!("call"), arity + 1); let err = self.representation_error(RepFlag::MaxArity); - let representation_error = self.error_form(err, stub); - - self.throw_exception(representation_error); - return None; + return Err(self.error_form(err, stub)); } for i in (1..arity).rev() { @@ -2039,12 +1998,8 @@ impl MachineState { (name, narity) } (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - (name, 0) - } else { - self.fail = true; - return None; - } + debug_assert_eq!(arity, 0); + (name, 0) } (HeapCellValueTag::Char, c) => { (self.atom_tbl.build_with(&c.to_string()), 0) @@ -2052,22 +2007,16 @@ impl MachineState { (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, _h) => { let stub = functor_stub(atom!("call"), arity + 1); let err = self.instantiation_error(); - let instantiation_error = self.error_form(err, stub); - - self.throw_exception(instantiation_error); - return None; + return Err(self.error_form(err, stub)); } _ => { let stub = functor_stub(atom!("call"), arity + 1); let err = self.type_error(ValidType::Callable, addr); - let type_error = self.error_form(err, stub); - - self.throw_exception(type_error); - return None; + return Err(self.error_form(err, stub)); } ); - Some((name, arity + narity - 1)) + Ok((name, arity + narity - 1)) } #[inline] @@ -2233,45 +2182,6 @@ impl MachineState { Ok(()) } - pub fn compare_numbers(&mut self, cmp: CompareNumberQT, n1: Number, n2: Number) { - let ordering = n1.cmp(&n2); - - self.fail = match cmp { - CompareNumberQT::GreaterThan if ordering == Ordering::Greater => false, - CompareNumberQT::GreaterThanOrEqual if ordering != Ordering::Less => false, - CompareNumberQT::LessThan if ordering == Ordering::Less => false, - CompareNumberQT::LessThanOrEqual if ordering != Ordering::Greater => false, - CompareNumberQT::NotEqual if ordering != Ordering::Equal => false, - CompareNumberQT::Equal if ordering == Ordering::Equal => false, - _ => true, - }; - - self.p += 1; - } - - pub fn compare_term(&mut self, qt: CompareTermQT) { - let a1 = self.registers[1]; - let a2 = self.registers[2]; - - match compare_term_test!(self, a1, a2) { - Some(Ordering::Greater) => match qt { - CompareTermQT::GreaterThan | CompareTermQT::GreaterThanOrEqual => {} - _ => self.fail = true, - }, - Some(Ordering::Equal) => match qt { - CompareTermQT::GreaterThanOrEqual | CompareTermQT::LessThanOrEqual => {} - _ => self.fail = true, - }, - Some(Ordering::Less) => match qt { - CompareTermQT::LessThan | CompareTermQT::LessThanOrEqual => {} - _ => self.fail = true, - }, - None => { - self.fail = true; - } - } - } - // returns true on failure, false on success. pub fn eq_test(&mut self, h1: HeapCellValue, h2: HeapCellValue) -> bool { if h1 == h2 { @@ -2652,12 +2562,14 @@ impl MachineState { ) } + /* pub fn setup_built_in_call(&mut self, ct: BuiltInClauseType) { self.num_of_args = ct.arity(); self.b0 = self.b; self.p = CodePtr::BuiltInClause(ct, self.p.local()); } + */ pub fn deallocate(&mut self) { let e = self.e; diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 7f73755a..0b4923da 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -227,7 +227,7 @@ impl Machine { let mut wam = Machine { machine_st, indices: IndexStore::new(), - code_repo: CodeRepo::new(), + code: Code::new(), user_input, user_output, user_error, @@ -239,6 +239,8 @@ impl Machine { lib_path.pop(); lib_path.push("lib"); + wam.add_impls_to_indices(); + bootstrapping_compile( Stream::from_static_string( LIBRARIES.borrow()["ops_and_meta_predicates"], @@ -262,7 +264,7 @@ impl Machine { ) .unwrap(); - if let Some(builtins) = wam.indices.modules.get(&atom!("builtins")) { + if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) { load_module( &mut wam.indices.code_dir, &mut wam.indices.op_dir, @@ -270,6 +272,8 @@ impl Machine { &CompilationTarget::User, builtins, ); + + import_builtin_impls(&wam.indices.code_dir, builtins); } else { unreachable!() } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index b33df9d4..7c2be32d 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1,6 +1,5 @@ pub mod arithmetic_ops; pub mod attributed_variables; -pub mod code_repo; pub mod code_walker; #[macro_use] pub mod loader; @@ -22,11 +21,10 @@ pub mod streams; pub mod system_calls; pub mod term_stream; -use crate::arena::*; +use crate::arithmetic::*; use crate::atom_table::*; -use crate::clause_types::*; use crate::forms::*; -use crate::machine::code_repo::*; +use crate::instructions::*; use crate::machine::compile::*; use crate::machine::copier::*; use crate::machine::heap::*; @@ -57,7 +55,7 @@ lazy_static! { pub struct Machine { pub(super) machine_st: MachineState, pub(super) indices: IndexStore, - pub(super) code_repo: CodeRepo, + pub(super) code: Code, pub(super) user_input: Stream, pub(super) user_output: Stream, pub(super) user_error: Stream, @@ -97,19 +95,74 @@ fn current_dir() -> PathBuf { include!(concat!(env!("OUT_DIR"), "/libraries.rs")); +pub static BREAK_FROM_DISPATCH_LOOP_LOC: usize = 0; +pub static INSTALL_VERIFY_ATTR_INTERRUPT: usize = 1; +pub static VERIFY_ATTR_INTERRUPT_LOC: usize = 2; + pub struct MachinePreludeView<'a> { pub indices: &'a mut IndexStore, - pub code_repo: &'a mut CodeRepo, + pub code: &'a mut Code, pub load_contexts: &'a mut Vec, } +pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) { + let keys = [ + (atom!("@>"), 2), + (atom!("@<"), 2), + (atom!("@>="), 2), + (atom!("@=<"), 2), + (atom!("=="), 2), + (atom!("\\=="), 2), + (atom!(">"), 2), + (atom!("<"), 2), + (atom!(">="), 2), + (atom!("=<"), 2), + (atom!("=:="), 2), + (atom!("=\\="), 2), + (atom!("is"), 2), + (atom!("acyclic_term"), 1), + (atom!("arg"), 3), + (atom!("compare"), 3), + (atom!("copy_term"), 2), + (atom!("functor"), 3), + (atom!("ground"), 1), + (atom!("keysort"), 2), + (atom!("read"), 1), + (atom!("sort"), 2), + (atom!("$call"), 1), + (atom!("$call"), 2), + (atom!("$call"), 3), + (atom!("$call"), 4), + (atom!("$call"), 5), + (atom!("$call"), 6), + (atom!("$call"), 7), + (atom!("$call"), 8), + (atom!("$call"), 9), + (atom!("atom"), 1), + (atom!("atomic"), 1), + (atom!("compound"), 1), + (atom!("integer"), 1), + (atom!("number"), 1), + (atom!("rational"), 1), + (atom!("float"), 1), + (atom!("nonvar"), 1), + (atom!("var"), 1), + ]; + + for key in keys { + let idx = code_dir.get(&key).unwrap(); + builtins.code_dir.insert(key, idx.clone()); + builtins.module_decl.exports.push(ModuleExport::PredicateKey(key)); + } +} + impl Machine { #[inline] pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) { ( MachinePreludeView { indices: &mut self.indices, - code_repo: &mut self.code_repo, + code: &mut self.code, load_contexts: &mut self.load_contexts, }, &mut self.machine_st @@ -122,7 +175,6 @@ impl Machine { let err = self.machine_st.error_form(err, stub); self.machine_st.throw_exception(err); - return; } fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) { @@ -130,10 +182,10 @@ impl Machine { if let Some(ref code_index) = module.code_dir.get(&key) { let p = code_index.local().unwrap(); - self.machine_st.cp = LocalCodePtr::Halt; - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); + self.machine_st.cp = BREAK_FROM_DISPATCH_LOOP_LOC; + self.machine_st.p = p; - return self.run_query(); + return self.dispatch_loop(); } } @@ -286,6 +338,61 @@ impl Machine { } } + pub(crate) fn add_impls_to_indices(&mut self) { + let impls_offset = self.code.len() + 3; + + self.code.extend(vec![ + Instruction::BreakFromDispatchLoop, + Instruction::InstallVerifyAttr, + Instruction::VerifyAttrInterrupt, + Instruction::ExecuteTermGreaterThan(0), + Instruction::ExecuteTermLessThan(0), + Instruction::ExecuteTermGreaterThanOrEqual(0), + Instruction::ExecuteTermLessThanOrEqual(0), + Instruction::ExecuteTermEqual(0), + Instruction::ExecuteTermNotEqual(0), + Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), + Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), + Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), + Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), + Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), + Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0), + Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2)), 0), + Instruction::ExecuteAcyclicTerm(0), + Instruction::ExecuteArg(0), + Instruction::ExecuteCompare(0), + Instruction::ExecuteCopyTerm(0), + Instruction::ExecuteFunctor(0), + Instruction::ExecuteGround(0), + Instruction::ExecuteKeySort(0), + Instruction::ExecuteRead(0), + Instruction::ExecuteSort(0), + Instruction::ExecuteN(1, 0), + Instruction::ExecuteN(2, 0), + Instruction::ExecuteN(3, 0), + Instruction::ExecuteN(4, 0), + Instruction::ExecuteN(5, 0), + Instruction::ExecuteN(6, 0), + Instruction::ExecuteN(7, 0), + Instruction::ExecuteN(8, 0), + Instruction::ExecuteN(9, 0), + Instruction::ExecuteIsAtom(temp_v!(1), 0), + Instruction::ExecuteIsAtomic(temp_v!(1), 0), + Instruction::ExecuteIsCompound(temp_v!(1), 0), + Instruction::ExecuteIsInteger(temp_v!(1), 0), + Instruction::ExecuteIsNumber(temp_v!(1), 0), + Instruction::ExecuteIsRational(temp_v!(1), 0), + Instruction::ExecuteIsFloat(temp_v!(1), 0), + Instruction::ExecuteIsNonVar(temp_v!(1), 0), + Instruction::ExecuteIsVar(temp_v!(1), 0) + ].into_iter()); + + for (p, instr) in self.code[impls_offset ..].iter().enumerate() { + let key = instr.to_name_and_arity(); + self.indices.code_dir.insert(key, CodeIndex::new(IndexPtr::Index(p + impls_offset))); + } + } + pub fn new() -> Self { use ref_thread_local::RefThreadLocal; @@ -298,7 +405,7 @@ impl Machine { let mut wam = Machine { machine_st, indices: IndexStore::new(), - code_repo: CodeRepo::new(), + code: vec![], user_input, user_output, user_error, @@ -310,6 +417,8 @@ impl Machine { lib_path.pop(); lib_path.push("lib"); + wam.add_impls_to_indices(); + bootstrapping_compile( Stream::from_static_string( LIBRARIES.borrow()["ops_and_meta_predicates"], @@ -333,7 +442,7 @@ impl Machine { ) .unwrap(); - if let Some(builtins) = wam.indices.modules.get(&atom!("builtins")) { + if let Some(builtins) = wam.indices.modules.get_mut(&atom!("builtins")) { load_module( &mut wam.indices.code_dir, &mut wam.indices.op_dir, @@ -341,6 +450,8 @@ impl Machine { &CompilationTarget::User, builtins, ); + + import_builtin_impls(&wam.indices.code_dir, builtins); } else { unreachable!() } @@ -399,509 +510,14 @@ impl Machine { self.indices.streams.insert(self.user_error); } - fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) { - match code_ptr { - REPLCodePtr::AddDiscontiguousPredicate => { - self.add_discontiguous_predicate(); - } - REPLCodePtr::AddDynamicPredicate => { - self.add_dynamic_predicate(); - } - REPLCodePtr::AddMultifilePredicate => { - self.add_multifile_predicate(); - } - REPLCodePtr::AddGoalExpansionClause => { - self.add_goal_expansion_clause(); - } - REPLCodePtr::AddTermExpansionClause => { - self.add_term_expansion_clause(); - } - REPLCodePtr::AddInSituFilenameModule => { - self.add_in_situ_filename_module(); - } - REPLCodePtr::ClauseToEvacuable => { - self.clause_to_evacuable(); - } - REPLCodePtr::ScopedClauseToEvacuable => { - self.scoped_clause_to_evacuable(); - } - REPLCodePtr::ConcludeLoad => { - self.conclude_load(); - } - REPLCodePtr::PopLoadContext => { - self.pop_load_context(); - } - REPLCodePtr::PushLoadContext => { - self.push_load_context(); - } - REPLCodePtr::PopLoadStatePayload => { - self.pop_load_state_payload(); - } - REPLCodePtr::UseModule => { - self.use_module(); - } - REPLCodePtr::LoadCompiledLibrary => { - self.load_compiled_library(); - } - REPLCodePtr::DeclareModule => { - self.declare_module(); - } - REPLCodePtr::PushLoadStatePayload => { - self.push_load_state_payload(); - } - REPLCodePtr::LoadContextSource => { - self.load_context_source(); - } - REPLCodePtr::LoadContextFile => { - self.load_context_file(); - } - REPLCodePtr::LoadContextDirectory => { - self.load_context_directory(); - } - REPLCodePtr::LoadContextModule => { - self.load_context_module(); - } - REPLCodePtr::LoadContextStream => { - self.load_context_stream(); - } - REPLCodePtr::MetaPredicateProperty => { - self.meta_predicate_property(); - } - REPLCodePtr::BuiltInProperty => { - self.builtin_property(); - } - REPLCodePtr::MultifileProperty => { - self.multifile_property(); - } - REPLCodePtr::DiscontiguousProperty => { - self.discontiguous_property(); - } - REPLCodePtr::DynamicProperty => { - self.dynamic_property(); - } - REPLCodePtr::Assertz => { - self.compile_assert(AppendOrPrepend::Append); - } - REPLCodePtr::Asserta => { - self.compile_assert(AppendOrPrepend::Prepend); - } - REPLCodePtr::Retract => { - self.retract_clause(); - } - REPLCodePtr::AbolishClause => { - self.abolish_clause(); - } - REPLCodePtr::IsConsistentWithTermQueue => { - self.is_consistent_with_term_queue(); - } - REPLCodePtr::FlushTermQueue => { - self.flush_term_queue(); - } - REPLCodePtr::RemoveModuleExports => { - self.remove_module_exports(); - } - REPLCodePtr::AddNonCountedBacktracking => { - self.add_non_counted_backtracking(); - } - } - - self.machine_st.p = CodePtr::Local(p); - } - - pub(crate) fn run_query(&mut self) { - while !self.machine_st.p.is_halt() { - self.query_stepper(); - - match self.machine_st.p { - CodePtr::REPL(code_ptr, p) => { - self.handle_toplevel_command(code_ptr, p); - - if self.machine_st.fail { - self.backtrack(); - } - } - _ => { - break; - } - }; - } - } - - fn execute_instr(&mut self) { - let instr = match self.code_repo.lookup_instr(&self.machine_st, &self.machine_st.p) { - Some(instr) => instr, - None => return, - }; - - self.dispatch_instr(instr); - } - - fn backtrack(&mut self) { - let b = self.machine_st.b; - let or_frame = self.machine_st.stack.index_or_frame(b); - - self.machine_st.b0 = or_frame.prelude.b0; - self.machine_st.p = CodePtr::Local(or_frame.prelude.bp); - - self.machine_st.oip = or_frame.prelude.boip; - self.machine_st.iip = or_frame.prelude.biip; - - self.machine_st.pdl.clear(); - self.machine_st.fail = false; - } - - fn check_machine_index(&mut self) -> bool { - match self.machine_st.p { - CodePtr::Local(LocalCodePtr::DirEntry(p)) - if p < self.code_repo.code.len() => {} - CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => { - return false; - } - _ => {} - } - - true - } - - // return true iff verify_attr_interrupt is called. - fn verify_attr_stepper(&mut self) -> bool { - loop { - let instr = match self.code_repo.lookup_instr(&self.machine_st, &self.machine_st.p) { - Some(instr) => { - if instr.as_ref(&self.code_repo.code).is_head_instr() { - instr - } else { - let cp = self.machine_st.p.local(); - self.run_verify_attr_interrupt(cp); - return true; - } - } - None => return false, - }; - - self.dispatch_instr(instr); - - if self.machine_st.fail { - self.backtrack(); - } - - if !self.check_machine_index() { - return false; - } - } - } - - fn run_verify_attr_interrupt(&mut self, cp: LocalCodePtr) { + #[inline(always)] + pub(crate) fn run_verify_attr_interrupt(&mut self) { //, cp: usize) { let p = self.machine_st.attr_var_init.verify_attrs_loc; - self.machine_st.attr_var_init.cp = cp; + // self.machine_st.attr_var_init.cp = cp; self.machine_st.verify_attr_interrupt(p); } - fn query_stepper(&mut self) { - loop { - self.execute_instr(); - - if self.machine_st.fail { - self.backtrack(); - } - - match self.machine_st.p { - CodePtr::VerifyAttrInterrupt(_) => { - self.machine_st.p = CodePtr::Local(self.machine_st.attr_var_init.cp); - - let instigating_p = CodePtr::Local(self.machine_st.attr_var_init.instigating_p); - let instigating_instr = self.code_repo - .lookup_instr(&self.machine_st, &instigating_p) - .unwrap(); - - if !instigating_instr.as_ref(&self.code_repo.code).is_head_instr() { - let cp = self.machine_st.p.local(); - self.run_verify_attr_interrupt(cp); - } else if !self.verify_attr_stepper() { - if self.machine_st.fail { - break; - } - - let cp = self.machine_st.p.local(); - self.run_verify_attr_interrupt(cp); - } - } - _ => { - if !self.check_machine_index() { - break; - } - } - } - } - } - - pub fn execute_inlined(&mut self, inlined: &InlinedClauseType) { - match inlined { - &InlinedClauseType::CompareNumber(cmp, ref at_1, ref at_2) => { - let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(at_1)); - let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(at_2)); - - self.machine_st.compare_numbers(cmp, n1, n2); - } - &InlinedClauseType::IsAtom(r1) => { - let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); - - read_heap_cell!(d, - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity == 0 { - self.machine_st.p += 1; - } else { - self.machine_st.fail = true; - } - } - (HeapCellValueTag::Char) => { - self.machine_st.p += 1; - } - _ => { - self.machine_st.fail = true; - } - ); - } - &InlinedClauseType::IsAtomic(r1) => { - let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); - - read_heap_cell!(d, - (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | - HeapCellValueTag::Cons) => { - self.machine_st.p += 1; - } - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity == 0 { - self.machine_st.p += 1; - } else { - self.machine_st.fail = true; - } - } - _ => { - self.machine_st.fail = true; - } - ); - } - &InlinedClauseType::IsInteger(r1) => { - let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); - - match Number::try_from(d) { - Ok(Number::Fixnum(_)) => { - self.machine_st.p += 1; - } - Ok(Number::Integer(_)) => { - self.machine_st.p += 1; - } - Ok(Number::Rational(n)) => { - if n.denom() == &1 { - self.machine_st.p += 1; - } else { - self.machine_st.fail = true; - } - } - _ => { - self.machine_st.fail = true; - } - } - } - &InlinedClauseType::IsCompound(r1) => { - let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); - - read_heap_cell!(d, - (HeapCellValueTag::Str | HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { - self.machine_st.p += 1; - } - (HeapCellValueTag::Atom, (_name, arity)) => { - if arity > 0 { - self.machine_st.p += 1; - } else { - self.machine_st.fail = true; - } - } - _ => { - self.machine_st.fail = true; - } - ); - } - &InlinedClauseType::IsFloat(r1) => { - let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); - - match Number::try_from(d) { - Ok(Number::Float(_)) => { - self.machine_st.p += 1; - } - _ => { - self.machine_st.fail = true; - } - } - } - &InlinedClauseType::IsNumber(r1) => { - let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); - - match Number::try_from(d) { - Ok(Number::Fixnum(_)) => { - self.machine_st.p += 1; - } - Ok(Number::Integer(_)) => { - self.machine_st.p += 1; - } - Ok(Number::Rational(n)) => { - if n.denom() == &1 { - self.machine_st.p += 1; - } else { - self.machine_st.fail = true; - } - } - Ok(Number::Float(_)) => { - self.machine_st.p += 1; - } - _ => { - self.machine_st.fail = true; - } - } - } - &InlinedClauseType::IsRational(r1) => { - let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); - - read_heap_cell!(d, - (HeapCellValueTag::Cons, ptr) => { - match_untyped_arena_ptr!(ptr, - (ArenaHeaderTag::Rational, _r) => { - self.machine_st.p += 1; - } - _ => { - self.machine_st.fail = true; - } - ); - } - _ => { - self.machine_st.fail = true; - } - ); - } - &InlinedClauseType::IsNonVar(r1) => { - let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); - - match d.get_tag() { - HeapCellValueTag::AttrVar - | HeapCellValueTag::Var - | HeapCellValueTag::StackVar => { - self.machine_st.fail = true; - } - _ => { - self.machine_st.p += 1; - } - } - } - &InlinedClauseType::IsVar(r1) => { - let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1])); - - match d.get_tag() { - HeapCellValueTag::AttrVar | - HeapCellValueTag::Var | - HeapCellValueTag::StackVar => { - self.machine_st.p += 1; - } - _ => { - self.machine_st.fail = true; - } - } - } - } - } - - #[inline(always)] - pub(super) fn execute_dynamic_indexed_choice_instr(&mut self) { - let p = self.machine_st.p.local(); - - match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { - Some((offset, oi, ii, is_next_clause)) => { - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc())); - self.machine_st.oip = oi; - self.machine_st.iip = ii; - - match self.machine_st.dynamic_mode { - FirstOrNext::First if !is_next_clause => { - self.machine_st.p = - CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset)); - } - FirstOrNext::First => { - // there's a leading DynamicElse that sets self.machine_st.cc. - // self.machine_st.cc = self.machine_st.global_clock; - - // see that there is a following dynamic_else - // clause so we avoid generating a choice - // point in case there isn't. - match self.find_living_dynamic(oi, ii + 1) { - Some(_) => { - self.machine_st.registers[self.machine_st.num_of_args + 1] = - fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); - - self.machine_st.num_of_args += 2; - self.machine_st.indexed_try(offset); - self.machine_st.num_of_args -= 2; - } - None => { - self.machine_st.p = - CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset)); - self.machine_st.oip = 0; - self.machine_st.iip = 0; - } - } - } - FirstOrNext::Next => { - let b = self.machine_st.b; - let n = self.machine_st - .stack - .index_or_frame(b) - .prelude - .univ_prelude - .num_cells; - - self.machine_st.cc = cell_as_fixnum!( - self.machine_st.stack[stack_loc!(OrFrame, b, n-2)] - ).get_num() as usize; - - if is_next_clause { - match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { - Some(_) => { - self.retry(offset); - - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - None => { - self.trust(offset); - - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - } - } else { - self.trust(offset); - - try_or_fail!( - self.machine_st, - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) - ); - } - } - } - } - None => { - self.machine_st.fail = true; - } - } - - self.machine_st.dynamic_mode = FirstOrNext::Next; - } - #[inline(always)] fn retry_me_else(&mut self, offset: usize) { let b = self.machine_st.b; @@ -916,7 +532,7 @@ impl Machine { self.machine_st.e = or_frame.prelude.e; self.machine_st.cp = or_frame.prelude.cp; - or_frame.prelude.bp = self.machine_st.p.local() + offset; + or_frame.prelude.bp = self.machine_st.p + offset; let old_tr = or_frame.prelude.tr; let curr_tr = self.machine_st.tr; @@ -924,14 +540,15 @@ impl Machine { self.machine_st.tr = or_frame.prelude.tr; - self.machine_st.attr_var_init.reset(); + self.reset_attr_var_state(); self.machine_st.hb = self.machine_st.heap.len(); - self.machine_st.p += 1; self.unwind_trail(old_tr, curr_tr); self.machine_st.trail.truncate(self.machine_st.tr); self.machine_st.heap.truncate(target_h); + + self.machine_st.p += 1; } #[inline(always)] @@ -948,7 +565,7 @@ impl Machine { self.machine_st.e = or_frame.prelude.e; self.machine_st.cp = or_frame.prelude.cp; - // WAS: or_frame.prelude.bp = self.machine_st.p.local() + 1; + // WAS: or_frame.prelude.bp = self.machine_st.p + 1; or_frame.prelude.biip += 1; let old_tr = or_frame.prelude.tr; @@ -956,7 +573,7 @@ impl Machine { let target_h = or_frame.prelude.h; self.machine_st.tr = or_frame.prelude.tr; - self.machine_st.attr_var_init.reset(); + self.reset_attr_var_state(); self.unwind_trail(old_tr, curr_tr); @@ -964,7 +581,7 @@ impl Machine { self.machine_st.heap.truncate(target_h); self.machine_st.hb = self.machine_st.heap.len(); - self.machine_st.p = CodePtr::Local(dir_entry!(self.machine_st.p.local().abs_loc() + offset)); + self.machine_st.p = self.machine_st.p + offset; self.machine_st.oip = 0; self.machine_st.iip = 0; @@ -989,10 +606,9 @@ impl Machine { let target_h = or_frame.prelude.h; self.machine_st.tr = or_frame.prelude.tr; - - self.machine_st.attr_var_init.reset(); self.machine_st.b = or_frame.prelude.b; + self.reset_attr_var_state(); self.unwind_trail(old_tr, curr_tr); self.machine_st.trail.truncate(self.machine_st.tr); @@ -1000,7 +616,7 @@ impl Machine { self.machine_st.heap.truncate(target_h); self.machine_st.hb = self.machine_st.heap.len(); - self.machine_st.p = CodePtr::Local(dir_entry!(self.machine_st.p.local().abs_loc() + offset)); + self.machine_st.p = self.machine_st.p + offset; self.machine_st.oip = 0; self.machine_st.iip = 0; @@ -1025,10 +641,9 @@ impl Machine { let target_h = or_frame.prelude.h; self.machine_st.tr = or_frame.prelude.tr; - - self.machine_st.attr_var_init.reset(); self.machine_st.b = or_frame.prelude.b; + self.reset_attr_var_state(); self.unwind_trail(old_tr, curr_tr); self.machine_st.trail.truncate(self.machine_st.tr); @@ -1040,30 +655,20 @@ impl Machine { } #[inline(always)] - fn context_call(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult { - if self.machine_st.last_call { - self.try_execute(name, arity, idx) - } else { - self.try_call(name, arity, idx) - } - } - - #[inline(always)] - fn try_call(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult { - match idx.get() { + fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult { + match idx { IndexPtr::DynamicUndefined => { self.machine_st.fail = true; - return Ok(()); } IndexPtr::Undefined => { return Err(self.machine_st.throw_undefined_error(name, arity)); } IndexPtr::DynamicIndex(compiled_tl_index) => { self.machine_st.dynamic_mode = FirstOrNext::First; - self.machine_st.call_at_index(arity, dir_entry!(compiled_tl_index)); + self.machine_st.call_at_index(arity, compiled_tl_index); } IndexPtr::Index(compiled_tl_index) => { - self.machine_st.call_at_index(arity, dir_entry!(compiled_tl_index)); + self.machine_st.call_at_index(arity, compiled_tl_index); } } @@ -1071,21 +676,20 @@ impl Machine { } #[inline(always)] - fn try_execute(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult { - match idx.get() { + fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult { + match idx { IndexPtr::DynamicUndefined => { self.machine_st.fail = true; - return Ok(()); } IndexPtr::Undefined => { return Err(self.machine_st.throw_undefined_error(name, arity)); } IndexPtr::DynamicIndex(compiled_tl_index) => { self.machine_st.dynamic_mode = FirstOrNext::First; - self.machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index)); + self.machine_st.execute_at_index(arity, compiled_tl_index); } IndexPtr::Index(compiled_tl_index) => { - self.machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index)) + self.machine_st.execute_at_index(arity, compiled_tl_index) } } @@ -1093,265 +697,67 @@ impl Machine { } #[inline(always)] - fn call_builtin(&mut self, ct: &BuiltInClauseType) -> CallResult { - match ct { - &BuiltInClauseType::AcyclicTerm => { - let addr = self.machine_st.registers[1]; - self.machine_st.fail = self.machine_st.is_cyclic_term(addr); - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::Arg => { - self.machine_st.try_arg()?; - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::Compare => { - let stub_gen = || functor_stub(atom!("compare"), 3); - - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let a2 = self.machine_st.registers[2]; - let a3 = self.machine_st.registers[3]; - - read_heap_cell!(a1, - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) - .get_name_and_arity(); - - match name { - atom!(">") | atom!("<") | atom!("=") if arity == 2 => { - } - _ => { - let err = self.machine_st.domain_error(DomainErrorType::Order, a1); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - } - _ => { - let err = self.machine_st.type_error(ValidType::Atom, a1); - return Err(self.machine_st.error_form(err, stub_gen())); - } - ); - - let atom = match compare_term_test!(self.machine_st, a2, a3) { - Some(Ordering::Greater) => { - atom!(">") - } - Some(Ordering::Equal) => { - atom!("=") - } - None | Some(Ordering::Less) => { - atom!("<") - } - }; - - self.machine_st.unify_atom(atom, a1); - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::CompareTerm(qt) => { - self.machine_st.compare_term(qt); - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::Read => { - let stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("read"), - 2, - )?; - - match self.machine_st.read(stream, &self.indices.op_dir) { - Ok(offset) => { - let value = self.machine_st.registers[2]; - unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc)); - } - Err(ParserError::UnexpectedEOF) => { - let value = self.machine_st.registers[2]; - self.machine_st.unify_atom(atom!("end_of_file"), value); - } - Err(e) => { - let stub = functor_stub(atom!("read"), 2); - let err = self.machine_st.syntax_error(e); - - return Err(self.machine_st.error_form(err, stub)); - } - }; - - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::CopyTerm => { - self.machine_st.copy_term(AttrVarPolicy::DeepCopy); - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::Eq => { - let a1 = self.machine_st.registers[1]; - let a2 = self.machine_st.registers[2]; - - self.machine_st.fail = self.machine_st.eq_test(a1, a2); - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::Ground => { - self.machine_st.fail = self.machine_st.ground_test(); - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::Functor => { - self.machine_st.try_functor()?; - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::NotEq => { - let a1 = self.machine_st.registers[1]; - let a2 = self.machine_st.registers[2]; - - self.machine_st.fail = - if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) { - true - } else { - false - }; - - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::Sort => { - self.machine_st.check_sort_errors()?; - - let stub_gen = || functor_stub(atom!("sort"), 2); - let mut list = self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen)?; - - list.sort_unstable_by(|v1, v2| { - compare_term_test!(self.machine_st, *v1, *v2).unwrap_or(Ordering::Less) - }); - - list.dedup_by(|v1, v2| { - compare_term_test!(self.machine_st, *v1, *v2) == Some(Ordering::Equal) - }); - - let heap_addr = heap_loc_as_cell!( - iter_to_heap_list(&mut self.machine_st.heap, list.into_iter()) - ); - - let r2 = self.machine_st.registers[2]; - unify_fn!(&mut self.machine_st, r2, heap_addr); - - return_from_clause!(self.machine_st.last_call, self.machine_st) - } - &BuiltInClauseType::KeySort => { - self.machine_st.check_keysort_errors()?; - - let stub_gen = || functor_stub(atom!("keysort"), 2); - let list = self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen)?; - - let mut key_pairs = Vec::with_capacity(list.len()); - - for val in list { - let key = self.machine_st.project_onto_key(val)?; - key_pairs.push((key, val)); - } - - key_pairs.sort_by(|a1, a2| { - compare_term_test!(self.machine_st, a1.0, a2.0).unwrap_or(Ordering::Less) - }); - - let key_pairs = key_pairs.into_iter().map(|kp| kp.1); - let heap_addr = heap_loc_as_cell!( - iter_to_heap_list(&mut self.machine_st.heap, key_pairs) - ); - - let r2 = self.machine_st.registers[2]; - unify_fn!(&mut self.machine_st, r2, heap_addr); + fn call_clause(&mut self, module_name: Atom, key: PredicateKey) -> CallResult { + let (name, arity) = key; - return_from_clause!(self.machine_st.last_call, self.machine_st) + if module_name == atom!("user") { + if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { + self.try_call(name, arity, idx.get()) + } else { + Err(self.machine_st.throw_undefined_error(name, arity)) } - &BuiltInClauseType::Is(r, ref at) => { - let n1 = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); - let n2 = self.machine_st.get_number(at)?; - - match n2 { - Number::Fixnum(n) => self.machine_st.unify_fixnum(n, n1), - Number::Float(n) => { - // TODO: argghh.. deal with it. - let n = arena_alloc!(n, &mut self.machine_st.arena); - self.machine_st.unify_f64(n, n1) - } - Number::Integer(n) => self.machine_st.unify_big_int(n, n1), - Number::Rational(n) => self.machine_st.unify_rational(n, n1), + } else { + if let Some(module) = self.indices.modules.get(&module_name) { + if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() { + self.try_call(name, arity, idx.get()) + } else { + Err(self.machine_st.throw_undefined_error(name, arity)) } + } else { + let stub = functor_stub(name, arity); + let err = self.machine_st.module_resolution_error(module_name, name, arity); - return_from_clause!(self.machine_st.last_call, self.machine_st) + Err(self.machine_st.error_form(err, stub)) } } } #[inline(always)] - fn call_clause_type(&mut self, module_name: Atom, key: PredicateKey) -> CallResult { + fn execute_clause(&mut self, module_name: Atom, key: PredicateKey) -> CallResult { let (name, arity) = key; - match ClauseType::from(name, arity) { - ClauseType::BuiltIn(built_in) => { - self.machine_st.setup_built_in_call(built_in); - self.call_builtin(&built_in)?; + if module_name == atom!("user") { + if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { + self.try_execute(name, arity, idx.get()) + } else { + Err(self.machine_st.throw_undefined_error(name, arity)) } - ClauseType::CallN => { - self.machine_st.handle_internal_call_n(arity); - - if self.machine_st.fail { - return Ok(()); - } - - self.machine_st.p = CodePtr::CallN( - arity, - self.machine_st.p.local(), - self.machine_st.last_call, - ); - } - ClauseType::Inlined(inlined) => { - self.execute_inlined(&inlined); - - if self.machine_st.last_call { - self.machine_st.p = CodePtr::Local(self.machine_st.cp); - } - } - ClauseType::Named(..) if module_name == atom!("user") => { - return if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { - self.context_call(name, arity, idx) + } else { + if let Some(module) = self.indices.modules.get(&module_name) { + if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() { + self.try_execute(name, arity, idx.get()) } else { Err(self.machine_st.throw_undefined_error(name, arity)) - }; - } - ClauseType::Named(..) => { - return if let Some(module) = self.indices.modules.get(&module_name) { - if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() { - self.context_call(name, arity, idx) - } else { - Err(self.machine_st.throw_undefined_error(name, arity)) - } - } else { - let stub = functor_stub(name, arity); - let err = self.machine_st.module_resolution_error(module_name, name, arity); - - Err(self.machine_st.error_form(err, stub)) - }; - } - ClauseType::System(_) => { - let (name, arity) = key; - let name = functor!(name); - - let stub = functor_stub(atom!("call"), arity + 1); - let err = self.machine_st.type_error(ValidType::Callable, name); + } + } else { + let stub = functor_stub(name, arity); + let err = self.machine_st.module_resolution_error(module_name, name, arity); - return Err(self.machine_st.error_form(err, stub)); + Err(self.machine_st.error_form(err, stub)) } } - - Ok(()) } #[inline(always)] fn call_n(&mut self, module_name: Atom, arity: usize) -> CallResult { - if let Some(key) = self.machine_st.setup_call_n(arity) { - self.call_clause_type(module_name, key)?; - } + let key = self.machine_st.setup_call_n(arity)?; + self.call_clause(module_name, key) + } - (self.machine_st.increment_call_count_fn)(&mut self.machine_st) + #[inline(always)] + fn execute_n(&mut self, module_name: Atom, arity: usize) -> CallResult { + let key = self.machine_st.setup_call_n(arity)?; + self.execute_clause(module_name, key) } #[inline(always)] @@ -1383,21 +789,16 @@ impl Machine { if let Some(&(_, b_cutoff, prev_block)) = self.machine_st.cont_pts.last() { if self.machine_st.b < b_cutoff { let (idx, arity) = if self.machine_st.block > prev_block { - (dir_entry!(r_c_w_h), 0) + (r_c_w_h, 0) } else { self.machine_st.registers[1] = fixnum_as_cell!( Fixnum::build_with(b_cutoff as i64) ); - (dir_entry!(r_c_wo_h), 1) + (r_c_wo_h, 1) }; - if self.machine_st.last_call { - self.machine_st.execute_at_index(arity, idx); - } else { - self.machine_st.call_at_index(arity, idx); - } - + self.machine_st.call_at_index(arity, idx); return true; } } @@ -1407,7 +808,7 @@ impl Machine { pub(super) fn unwind_trail(&mut self, a1: usize, a2: usize) { // the sequence is reversed to respect the chronology of trail - // additions, now that deleted attributes can be undeleted by + // additions now that deleted attributes can be undeleted by // backtracking. for i in (a1..a2).rev() { let h = self.machine_st.trail[i].get_value() as usize; diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index c3711db0..50a46947 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -1,6 +1,6 @@ use crate::atom_table::*; -use crate::clause_types::*; use crate::forms::*; +use crate::instructions::*; use crate::iterators::*; use crate::machine::loader::*; use crate::machine::machine_errors::*; @@ -207,34 +207,6 @@ fn setup_use_module_decl(mut terms: Vec) -> Result>) -> Result { - let dbl_quotes = *terms.pop().unwrap(); - - match terms[0].as_ref() { - Term::Literal(_, Literal::Atom(ref name, _)) - if name.as_str() == "double_quotes" => { - match dbl_quotes { - Term::Literal(_, Literal::Atom(name, _)) => { - match name.as_str() { - "atom" => Ok(DoubleQuotes::Atom), - "chars" => Ok(DoubleQuotes::Chars), - "codes" => Ok(DoubleQuotes::Codes), - _ => Err(CompilationError::InvalidDoubleQuotesDecl), - } - } - _ => { - Err(CompilationError::InvalidDoubleQuotesDecl) - } - } - }, - _ => { - Err(CompilationError::InvalidDoubleQuotesDecl) - } - } -} - */ - type UseModuleExport = (ModuleSource, IndexSet); fn setup_qualified_import( @@ -735,7 +707,7 @@ impl Preprocessor { }, Term::Var(..) => Ok(QueryTerm::Clause( Cell::default(), - ClauseType::CallN, + ClauseType::CallN(1), vec![term], false, )), diff --git a/src/machine/stack.rs b/src/machine/stack.rs index b175917b..388c3008 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -1,9 +1,7 @@ use core::marker::PhantomData; -use crate::types::*; - -use crate::machine::machine_indices::*; use crate::raw_block::*; +use crate::types::*; use std::mem; use std::ops::{Index, IndexMut}; @@ -47,8 +45,7 @@ pub(crate) struct FramePrelude { pub(crate) struct AndFramePrelude { pub(crate) univ_prelude: FramePrelude, pub(crate) e: usize, - pub(crate) cp: LocalCodePtr, - pub(crate) interrupt_cp: LocalCodePtr, // TODO: get rid of it! + pub(crate) cp: usize, } #[derive(Debug)] @@ -118,9 +115,9 @@ impl IndexMut for Stack { pub(crate) struct OrFramePrelude { pub(crate) univ_prelude: FramePrelude, pub(crate) e: usize, - pub(crate) cp: LocalCodePtr, + pub(crate) cp: usize, pub(crate) b: usize, - pub(crate) bp: LocalCodePtr, + pub(crate) bp: usize, pub(crate) boip: u32, pub(crate) biip: u32, pub(crate) tr: usize, diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index d84c2ea9..08a99f30 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -5,13 +5,12 @@ use lazy_static::lazy_static; use crate::arena::*; use crate::atom_table::*; -use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; use crate::heap_print::*; use crate::instructions::*; use crate::machine; -use crate::machine::Machine; +use crate::machine::{Machine, VERIFY_ATTR_INTERRUPT_LOC}; use crate::machine::code_walker::*; use crate::machine::copier::*; use crate::machine::heap::*; @@ -24,6 +23,7 @@ use crate::machine::stack::*; use crate::machine::streams::*; use crate::parser::char_reader::*; use crate::parser::rug::Integer; +use crate::parser::rug::rand::RandState; use crate::read::*; use crate::types::*; @@ -31,7 +31,7 @@ use ordered_float::OrderedFloat; use indexmap::IndexSet; -use ref_thread_local::RefThreadLocal; +use ref_thread_local::{RefThreadLocal, ref_thread_local}; use std::collections::BTreeSet; use std::convert::TryFrom; @@ -39,6 +39,7 @@ use std::env; use std::fs; use std::io::{ErrorKind, Read, Write}; use std::iter::{once, FromIterator}; +use std::mem; use std::net::{TcpListener, TcpStream}; use std::num::NonZeroU32; use std::ops::Sub; @@ -72,6 +73,10 @@ use base64; use roxmltree; use select; +ref_thread_local! { + pub(crate) static managed RANDOM_STATE: RandState<'static> = RandState::new(); +} + pub(crate) fn get_key() -> KeyEvent { let key; enable_raw_mode().expect("failed to enable raw mode"); @@ -326,7 +331,7 @@ impl MachineState { let deref_v = self.deref(value); let store_v = self.store(deref_v); - // let mut pstr_chars = 0; + let mut pstr_chars = 0; let hare = read_heap_cell!(store_v, (HeapCellValueTag::Lis, offset) => { @@ -337,14 +342,29 @@ impl MachineState { } } (HeapCellValueTag::PStrLoc, h) => { - let (h_offset, _n) = pstr_loc_and_offset(&self.heap, h); + let (h_offset, n) = pstr_loc_and_offset(&self.heap, h); + let n = n.get_num() as usize; + let pstr = cell_as_string!(self.heap[h_offset]); - if self.heap[h].get_tag() == HeapCellValueTag::PStr { - h_offset+1 - } else { + pstr_chars = pstr.as_str_from(n).chars().count() - 1; + + if self.heap[h].get_tag() == HeapCellValueTag::PStrOffset { debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset); - h + + if self.heap[h_offset].get_tag() == HeapCellValueTag::CStr { + return if pstr_chars + 1 <= max_steps { + CycleSearchResult::ProperList(pstr_chars + 1) + } else { + CycleSearchResult::UntouchedCStr(pstr.into(), max_steps) + }; + } + } + + if pstr_chars + 1 > max_steps { + return CycleSearchResult::PStrLocation(max_steps, h_offset); } + + h_offset+1 } (HeapCellValueTag::PStrOffset) => { unreachable!() @@ -379,11 +399,11 @@ impl MachineState { } } (HeapCellValueTag::Atom, (name, arity)) => { - if name == atom!("[]") && arity == 0 { - return CycleSearchResult::EmptyList; + return if name == atom!("[]") && arity == 0 { + CycleSearchResult::EmptyList } else { - return CycleSearchResult::NotList; - } + CycleSearchResult::NotList + }; } _ => { return CycleSearchResult::NotList; @@ -393,7 +413,7 @@ impl MachineState { let mut brent_st = BrentAlgState::new(hare); brent_st.power += 1; // advance a step. - // brent_st.pstr_chars = pstr_chars; + brent_st.pstr_chars = pstr_chars; loop { if brent_st.num_steps() == max_steps { @@ -406,41 +426,6 @@ impl MachineState { } } - fn term_variables_under_max_depth( - &mut self, - term: HeapCellValue, - max_depth: usize, - list_of_vars: HeapCellValue, - ) { - let mut seen_set = IndexSet::new(); - - { - let mut iter = stackful_post_order_iter(&mut self.heap, term); - - while let Some(value) = iter.next() { - if iter.parent_stack_len() >= max_depth { - iter.pop_stack(); - continue; - } - - let value = unmark_cell_bits!(value); - - if value.is_var() && !seen_set.contains(&value) { - seen_set.insert(value); - } - } - } - - let outcome = heap_loc_as_cell!( - iter_to_heap_list( - &mut self.heap, - seen_set.into_iter().rev(), - ) - ); - - unify_fn!(*self, list_of_vars, outcome); - } - fn finalize_skip_max_list(&mut self, n: usize, value: HeapCellValue) { let target_n = self.registers[1]; self.unify_fixnum(Fixnum::build_with(n as i64), target_n); @@ -541,18 +526,51 @@ impl MachineState { Ok(()) } -} -impl MachineState { + fn term_variables_under_max_depth( + &mut self, + term: HeapCellValue, + max_depth: usize, + list_of_vars: HeapCellValue, + ) { + let mut seen_set = IndexSet::new(); + + { + let mut iter = stackful_post_order_iter(&mut self.heap, term); + + while let Some(value) = iter.next() { + if iter.parent_stack_len() >= max_depth { + iter.pop_stack(); + continue; + } + + let value = unmark_cell_bits!(value); + + if value.is_var() && !seen_set.contains(&value) { + seen_set.insert(value); + } + } + } + + let outcome = heap_loc_as_cell!( + iter_to_heap_list( + &mut self.heap, + seen_set.into_iter().rev(), + ) + ); + + unify_fn!(*self, list_of_vars, outcome); + } + #[inline] - fn install_new_block(&mut self, value: HeapCellValue) -> usize { + pub(crate) fn install_new_block(&mut self, value: HeapCellValue) -> usize { self.block = self.b; self.unify_fixnum(Fixnum::build_with(self.block as i64), value); self.block } - fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: HeapCellValue) -> usize { + pub(crate) fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: HeapCellValue) -> usize { let threshold = self.lifted_heap.len() - lh_offset; let mut copy_ball_term = @@ -567,18 +585,8 @@ impl MachineState { threshold + lh_offset + 2 } - fn repl_redirect(&mut self, repl_code_ptr: REPLCodePtr) -> CallResult { - let p = if self.last_call { - self.cp - } else { - self.p.local() + 1 - }; - - Ok(self.p = CodePtr::REPL(repl_code_ptr, p)) - } - #[inline(always)] - fn truncate_if_no_lifted_heap_diff( + pub(crate) fn truncate_if_no_lifted_heap_diff( &mut self, addr_constr: impl Fn(usize) -> HeapCellValue, ) { @@ -599,7 +607,7 @@ impl MachineState { ); } - fn get_next_db_ref(&self, indices: &IndexStore, db_ref: &DBRef) -> Option { + pub(crate) fn get_next_db_ref(&self, indices: &IndexStore, db_ref: &DBRef) -> Option { match db_ref { DBRef::NamedPred(name, arity) => { let key = (*name, *arity); @@ -612,10 +620,6 @@ impl MachineState { return None; } - if SystemClauseType::from(*name, *arity).is_some() { - continue; - } - return Some(DBRef::NamedPred(*name, *arity)); } } @@ -634,7 +638,7 @@ impl MachineState { None } - fn parse_number_from_string( + pub(crate) fn parse_number_from_string( &mut self, mut string: String, indices: &IndexStore, @@ -691,7 +695,7 @@ impl MachineState { Ok(()) } - fn call_continuation_chunk(&mut self, chunk: HeapCellValue, return_p: LocalCodePtr) -> LocalCodePtr { + pub(crate) fn call_continuation_chunk(&mut self, chunk: HeapCellValue, return_p: usize) -> usize { let chunk = self.store(self.deref(chunk)); let s = chunk.get_value(); @@ -709,7 +713,7 @@ impl MachineState { and_frame.prelude.e = prev_e; and_frame.prelude.cp = return_p; - self.p = CodePtr::Local(cp + 1); + self.p = cp + 1; // adjust cut point to occur after call_continuation. if num_cells > 0 { @@ -725,7 +729,7 @@ impl MachineState { } self.e = e; - self.p.local() + self.p } pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option { @@ -734,7 +738,7 @@ impl MachineState { // avoid allocating a String if possible ... Some(AtomOrString::Atom(cstr_atom)) } - (HeapCellValueTag::Atom, (atom, arity)) => { // TODO: Char?? + (HeapCellValueTag::Atom, (atom, arity)) => { if arity == 0 { // ... likewise. Some(AtomOrString::Atom(atom)) @@ -742,6 +746,9 @@ impl MachineState { None } } + (HeapCellValueTag::Char, c) => { + Some(AtomOrString::Atom(self.atom_tbl.build_with(&c.to_string()))) + } _ => { if value.is_constant() { return None; @@ -768,7 +775,7 @@ impl MachineState { ) } - fn codes_to_string( + pub(crate) fn codes_to_string( &mut self, addrs: impl Iterator, stub_gen: impl Fn() -> FunctorStub, @@ -809,73 +816,76 @@ impl MachineState { } impl Machine { - pub(super) fn system_call(&mut self, ct: &SystemClauseType) -> CallResult { - match ct { - &SystemClauseType::BindFromRegister => { - let reg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - let n = match Number::try_from(reg) { - Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), - Ok(Number::Integer(n)) => n.to_usize(), - _ => { - unreachable!() - } - }; + #[inline(always)] + pub(crate) fn is_reset_cont_marker(&self, p: usize) -> bool { + match &self.code[p] { + &Instruction::CallResetContinuationMarker(_) | + &Instruction::ExecuteResetContinuationMarker(_) => true, + _ => false + } + } - if let Some(n) = n { - if n <= MAX_ARITY { - let target = self.machine_st.registers[n]; - let addr = self.machine_st.registers[1]; + #[inline(always)] + pub(crate) fn bind_from_register(&mut self) { + let reg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + let n = match Number::try_from(reg) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), + Ok(Number::Integer(n)) => n.to_usize(), + _ => { + unreachable!() + } + }; - unify_fn!(self.machine_st, addr, target); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - } + if let Some(n) = n { + if n <= MAX_ARITY { + let target = self.machine_st.registers[n]; + let addr = self.machine_st.registers[1]; - self.machine_st.fail = true; + unify_fn!(self.machine_st, addr, target); + return; } - &SystemClauseType::CurrentHostname => { - match hostname::get().ok() { - Some(host) => match host.to_str() { - Some(host) => { - let hostname = self.machine_st.atom_tbl.build_with(host); + } - self.machine_st.unify_atom( - hostname, - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) - ); + self.machine_st.fail = true; + } - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - None => {} - }, - None => {} + #[inline(always)] + pub(crate) fn current_hostname(&mut self) { + match hostname::get().ok() { + Some(host) => match host.to_str() { + Some(host) => { + let hostname = self.machine_st.atom_tbl.build_with(host); + + self.machine_st.unify_atom( + hostname, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) + ); + + return; } + None => {} + }, + None => {} + } - self.machine_st.fail = true; - return Ok(()); - } - &SystemClauseType::CurrentInput => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let stream = self.user_input; + self.machine_st.fail = true; + } - if let Some(var) = addr.as_var() { - self.machine_st.bind(var, stream_as_cell!(stream)); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + #[inline(always)] + pub(crate) fn current_input(&mut self) -> CallResult { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let stream = self.user_input; - read_heap_cell!(addr, - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::Stream, other_stream) => { - self.machine_st.fail = stream != other_stream; - } - _ => { - let stub = functor_stub(atom!("current_input"), 1); - let err = self.machine_st.domain_error(DomainErrorType::Stream, addr); + if let Some(var) = addr.as_var() { + self.machine_st.bind(var, stream_as_cell!(stream)); + return Ok(()); + } - return Err(self.machine_st.error_form(err, stub)); - } - ); + read_heap_cell!(addr, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Stream, other_stream) => { + self.machine_st.fail = stream != other_stream; } _ => { let stub = functor_stub(atom!("current_input"), 1); @@ -885,28 +895,32 @@ impl Machine { } ); } - &SystemClauseType::CurrentOutput => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let stream = self.user_output; + _ => { + let stub = functor_stub(atom!("current_input"), 1); + let err = self.machine_st.domain_error(DomainErrorType::Stream, addr); - if let Some(var) = addr.as_var() { - self.machine_st.bind(var, stream_as_cell!(stream)); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + return Err(self.machine_st.error_form(err, stub)); + } + ); - read_heap_cell!(addr, - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::Stream, other_stream) => { - self.machine_st.fail = stream != other_stream; - } - _ => { - let stub = functor_stub(atom!("current_output"), 1); - let err = self.machine_st.domain_error(DomainErrorType::Stream, addr); + Ok(()) + } - return Err(self.machine_st.error_form(err, stub)); - } - ); + #[inline(always)] + pub(crate) fn current_output(&mut self) -> CallResult { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let stream = self.user_output; + + if let Some(var) = addr.as_var() { + self.machine_st.bind(var, stream_as_cell!(stream)); + return Ok(()); + } + + read_heap_cell!(addr, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Stream, other_stream) => { + self.machine_st.fail = stream != other_stream; } _ => { let stub = functor_stub(atom!("current_output"), 1); @@ -916,150 +930,245 @@ impl Machine { } ); } - &SystemClauseType::DirectoryFiles => { - if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - let path = std::path::Path::new(dir.as_str()); - let mut files = Vec::new(); + _ => { + let stub = functor_stub(atom!("current_output"), 1); + let err = self.machine_st.domain_error(DomainErrorType::Stream, addr); - if let Ok(entries) = fs::read_dir(path) { - for entry in entries { - if let Ok(entry) = entry { - if let Some(name) = entry.file_name().to_str() { - let name = self.machine_st.atom_tbl.build_with(name); - files.push(atom_as_cstr_cell!(name)); + return Err(self.machine_st.error_form(err, stub)); + } + ); - continue; - } - } + Ok(()) + } - let stub = functor_stub(atom!("directory_files"), 2); - let err = self.machine_st.representation_error(RepFlag::Character); - let err = self.machine_st.error_form(err, stub); + #[inline(always)] + pub(crate) fn directory_files(&mut self) -> CallResult { + if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + let path = std::path::Path::new(dir.as_str()); + let mut files = Vec::new(); + + if let Ok(entries) = fs::read_dir(path) { + for entry in entries { + if let Ok(entry) = entry { + if let Some(name) = entry.file_name().to_str() { + let name = self.machine_st.atom_tbl.build_with(name); + files.push(atom_as_cstr_cell!(name)); - return Err(err); + continue; } + } - let files_list = heap_loc_as_cell!( - iter_to_heap_list(&mut self.machine_st.heap, files.into_iter()) - ); + let stub = functor_stub(atom!("directory_files"), 2); + let err = self.machine_st.representation_error(RepFlag::Character); + let err = self.machine_st.error_form(err, stub); - unify!(self.machine_st, self.machine_st.registers[2], files_list); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + return Err(err); } + let files_list = heap_loc_as_cell!( + iter_to_heap_list(&mut self.machine_st.heap, files.into_iter()) + ); + + unify!(self.machine_st, self.machine_st.registers[2], files_list); + return Ok(()); + } + } + + self.machine_st.fail = true; + Ok(()) + } + + #[inline(always)] + pub(crate) fn file_size(&mut self) { + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + let len = Number::arena_from( + fs::metadata(file.as_str()).unwrap().len(), + &mut self.machine_st.arena, + ); + + match len { + Number::Fixnum(n) => self.machine_st.unify_fixnum(n, self.machine_st.registers[2]), + Number::Integer(n) => self.machine_st.unify_big_int(n, self.machine_st.registers[2]), + _ => unreachable!(), + } + } else { + self.machine_st.fail = true; + } + } + + #[inline(always)] + pub(crate) fn file_exists(&mut self) { + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + let file_str = file.as_str(); + + if !std::path::Path::new(file_str).exists() || !fs::metadata(file_str).unwrap().is_file() { self.machine_st.fail = true; } - &SystemClauseType::FileSize => { - if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - let len = Number::arena_from( - fs::metadata(file.as_str()).unwrap().len(), - &mut self.machine_st.arena, - ); + } else { + self.machine_st.fail = true; + } + } + + #[inline(always)] + pub(crate) fn directory_exists(&mut self) { + if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + let dir_str = dir.as_str(); + + if !std::path::Path::new(dir_str).exists() || !fs::metadata(dir_str).unwrap().is_dir() { + self.machine_st.fail = true; + } + } else { + self.machine_st.fail = true; + } + } - match len { - Number::Fixnum(n) => self.machine_st.unify_fixnum(n, self.machine_st.registers[2]), - Number::Integer(n) => self.machine_st.unify_big_int(n, self.machine_st.registers[2]), - _ => unreachable!(), + #[inline(always)] + pub(crate) fn file_time(&mut self) { + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + let which = cell_as_atom!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2] + ))); + + if let Ok(md) = fs::metadata(file.as_str()) { + if let Ok(time) = match which { + atom!("modification") => md.modified(), + atom!("access") => md.accessed(), + atom!("creation") => md.created(), + _ => { + unreachable!() } - } else { - self.machine_st.fail = true; + } { + let chars_atom = self.systemtime_to_timestamp(time); + + self.machine_st.unify_complete_string( + chars_atom, + self.machine_st.registers[3], + ); + + return; } } - &SystemClauseType::FileExists => { - if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - let file_str = file.as_str(); + } - if !std::path::Path::new(file_str).exists() || !fs::metadata(file_str).unwrap().is_file() { - self.machine_st.fail = true; - } - } else { + self.machine_st.fail = true; + } + + #[inline(always)] + pub(crate) fn directory_separator(&mut self) { + self.machine_st.unify_char(std::path::MAIN_SEPARATOR, self.machine_st.registers[1]); + } + + #[inline(always)] + pub(crate) fn make_directory(&mut self) { + if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + match fs::create_dir(dir.as_str()) { + Ok(_) => {} + _ => { self.machine_st.fail = true; } } - &SystemClauseType::DirectoryExists => { - if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - let dir_str = dir.as_str(); + } else { + self.machine_st.fail = true; + } + } - if !std::path::Path::new(dir_str).exists() - || !fs::metadata(dir_str).unwrap().is_dir() - { - self.machine_st.fail = true; - return Ok(()); - } - } else { + #[inline(always)] + pub(crate) fn make_directory_path(&mut self) { + if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + + match fs::create_dir_all(dir.as_str()) { + Ok(_) => {} + _ => { self.machine_st.fail = true; } } - &SystemClauseType::DirectorySeparator => { - self.machine_st.unify_char(std::path::MAIN_SEPARATOR, self.machine_st.registers[1]); - } - &SystemClauseType::MakeDirectory => { - if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - match fs::create_dir(dir.as_str()) { - Ok(_) => {} - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } - } else { + } else { + self.machine_st.fail = true; + } + } + + #[inline(always)] + pub(crate) fn delete_file(&mut self) { + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + match fs::remove_file(file.as_str()) { + Ok(_) => {} + _ => { self.machine_st.fail = true; } } - &SystemClauseType::MakeDirectoryPath => { - if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + } + } - match fs::create_dir_all(dir.as_str()) { - Ok(_) => {} - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } - } else { - self.machine_st.fail = true; + #[inline(always)] + pub(crate) fn rename_file(&mut self) { + if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + if let Some(renamed) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { + if fs::rename(file.as_str(), renamed.as_str()).is_ok() { + return; } } - &SystemClauseType::DeleteFile => { - if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - match fs::remove_file(file.as_str()) { - Ok(_) => {} - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } + } + + self.machine_st.fail = true; + } + + #[inline(always)] + pub(crate) fn delete_directory(&mut self) { + if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + match fs::remove_dir(dir.as_str()) { + Ok(_) => {} + _ => { + self.machine_st.fail = true; } } - &SystemClauseType::RenameFile => { - if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - if let Some(renamed) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { - if fs::rename(file.as_str(), renamed.as_str()).is_ok() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - } + } + } + + #[inline(always)] + pub(crate) fn working_directory(&mut self) -> CallResult { + if let Ok(dir) = env::current_dir() { + let current = match dir.to_str() { + Some(d) => d, + _ => { + let stub = functor_stub(atom!("working_directory"), 2); + let err = self.machine_st.representation_error(RepFlag::Character); + let err = self.machine_st.error_form(err, stub); + + return Err(err); } + }; - self.machine_st.fail = true; + let current_atom = self.machine_st.atom_tbl.build_with(¤t); + + self.machine_st.unify_complete_string( + current_atom, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])), + ); + + if self.machine_st.fail { + return Ok(()); } - &SystemClauseType::DeleteDirectory => { - if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - match fs::remove_dir(dir.as_str()) { - Ok(_) => {} - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } + + if let Some(next) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { + if env::set_current_dir(std::path::Path::new(next.as_str())).is_ok() { + return Ok(()); } } - &SystemClauseType::WorkingDirectory => { - if let Ok(dir) = env::current_dir() { - let current = match dir.to_str() { - Some(d) => d, + } + + self.machine_st.fail = true; + Ok(()) + } + + #[inline(always)] + pub(crate) fn path_canonical(&mut self) -> CallResult { + if let Some(path) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + match fs::canonicalize(path.as_str()) { + Ok(canonical) => { + let cs = match canonical.to_str() { + Some(s) => s, _ => { - let stub = functor_stub(atom!("working_directory"), 2); + let stub = functor_stub(atom!("path_canonical"), 2); let err = self.machine_st.representation_error(RepFlag::Character); let err = self.machine_st.error_form(err, stub); @@ -1067,4379 +1176,4701 @@ impl Machine { } }; - let current_atom = self.machine_st.atom_tbl.build_with(¤t); + let canonical_atom = self.machine_st.atom_tbl.build_with(cs); self.machine_st.unify_complete_string( - current_atom, - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])), + canonical_atom, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), ); - if self.machine_st.fail { - return Ok(()); - } - - if let Some(next) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { - if env::set_current_dir(std::path::Path::new(next.as_str())).is_ok() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - } + return Ok(()); + } + _ => { } - - self.machine_st.fail = true; } - &SystemClauseType::PathCanonical => { - if let Some(path) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - match fs::canonicalize(path.as_str()) { - Ok(canonical) => { - let cs = match canonical.to_str() { - Some(s) => s, - _ => { - let stub = functor_stub(atom!("path_canonical"), 2); - let err = self.machine_st.representation_error(RepFlag::Character); - let err = self.machine_st.error_form(err, stub); - - return Err(err); - } - }; + } + + self.machine_st.fail = true; + Ok(()) + } - let canonical_atom = self.machine_st.atom_tbl.build_with(cs); + #[inline(always)] + pub(crate) fn atom_chars(&mut self) { + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - self.machine_st.unify_complete_string( - canonical_atom, - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), - ); + read_heap_cell!(a1, + (HeapCellValueTag::Char) => { + let h = self.machine_st.heap.len(); + + self.machine_st.heap.push(a1); + self.machine_st.heap.push(empty_list_as_cell!()); + + unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h)); + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + self.machine_st.unify_complete_string( + name, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), + ); + } else { + self.machine_st.fail = true; + } + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - return return_from_clause!(self.machine_st.last_call, self.machine_st); + if let Some(str_like) = self.machine_st.value_to_str_like(a2) { + let atom = match str_like { + AtomOrString::Atom(atom) => { + atom } - _ => { + AtomOrString::String(string) => { + self.machine_st.atom_tbl.build_with(&string) } - } + }; + + self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); + return; } self.machine_st.fail = true; } - &SystemClauseType::FileTime => { - if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - let which = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); + _ => { + unreachable!(); + } + ); + } - if let Ok(md) = fs::metadata(file.as_str()) { - if let Ok(time) = match which { - atom!("modification") => md.modified(), - atom!("access") => md.accessed(), - atom!("creation") => md.created(), - _ => { - unreachable!() - } - } { - let chars_atom = self.systemtime_to_timestamp(time); + #[inline(always)] + pub(crate) fn atom_codes(&mut self) -> CallResult { + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - self.machine_st.unify_complete_string( - chars_atom, - self.machine_st.registers[3], - ); + read_heap_cell!(a1, + (HeapCellValueTag::Char, c) => { + let h = self.machine_st.heap.len(); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - } - } + self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64))); + self.machine_st.heap.push(empty_list_as_cell!()); - self.machine_st.fail = true; + unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]); } - &SystemClauseType::AtomChars => { - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + let iter = name.chars() + .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); - read_heap_cell!(a1, - (HeapCellValueTag::Char) => { - let h = self.machine_st.heap.len(); + let h = iter_to_heap_list(&mut self.machine_st.heap, iter); + unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]); + } else { + self.machine_st.fail = true; + } + } + (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { + let stub_gen = || functor_stub(atom!("atom_codes"), 2); - self.machine_st.heap.push(a1); - self.machine_st.heap.push(empty_list_as_cell!()); + match self.machine_st.try_from_list(self.machine_st.registers[2], stub_gen) { + Ok(addrs) => { + let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?; + let atom = self.machine_st.atom_tbl.build_with(&string); - unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h)); + self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); } - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - self.machine_st.unify_complete_string( - name, - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), - ); - } else { - self.machine_st.fail = true; - } + Err(e) => { + return Err(e); } - (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { - let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + } + } + _ => { + unreachable!(); + } + ); - if let Some(str_like) = self.machine_st.value_to_str_like(a2) { - let atom = match str_like { - AtomOrString::Atom(atom) => { - atom - } - AtomOrString::String(string) => { - self.machine_st.atom_tbl.build_with(&string) - } - }; + Ok(()) + } - self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + #[inline(always)] + pub(crate) fn atom_length(&mut self) { + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - self.machine_st.fail = true; - } - _ => { - unreachable!(); - } - ); + let len: i64 = read_heap_cell!(a1, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + name.chars().count() as i64 + } else { + self.machine_st.fail = true; + return; + } } - &SystemClauseType::AtomCodes => { - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - - read_heap_cell!(a1, - (HeapCellValueTag::Char, c) => { - let h = self.machine_st.heap.len(); + (HeapCellValueTag::Char) => { + 1 + } + _ => { + unreachable!() + } + ); - self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64))); - self.machine_st.heap.push(empty_list_as_cell!()); + self.machine_st.unify_fixnum( + Fixnum::build_with(len), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), + ); + } - unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]); - } - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - let iter = name.chars() - .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); + #[inline(always)] + pub(crate) fn call_continuation(&mut self, last_call: bool) -> CallResult { + let stub_gen = || functor_stub(atom!("call_continuation"), 1); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + match self.machine_st.try_from_list(a1, stub_gen) { + Err(e) => Err(e), + Ok(cont_chunks) => { + let mut return_p = if last_call { + self.machine_st.cp + } else { + self.machine_st.p + 1 + }; - let h = iter_to_heap_list(&mut self.machine_st.heap, iter); - unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]); - } else { - self.machine_st.fail = true; - } - } - (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { - let stub_gen = || functor_stub(atom!("atom_codes"), 2); + self.machine_st.p = return_p; - match self.machine_st.try_from_list(self.machine_st.registers[2], stub_gen) { - Ok(addrs) => { - let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?; - let atom = self.machine_st.atom_tbl.build_with(&string); + for chunk in cont_chunks.into_iter().rev() { + return_p = self.machine_st.call_continuation_chunk(chunk, return_p); + } - self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom)); - } - Err(e) => { - return Err(e); - } - } - } - _ => { - unreachable!(); - } - ); + Ok(()) } - &SystemClauseType::AtomLength => { - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + } + } - let len: i64 = read_heap_cell!(a1, - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - name.chars().count() as i64 - } else { - self.machine_st.fail = true; - return Ok(()); - } - } - (HeapCellValueTag::Char) => { - 1 - } - _ => { - unreachable!() - } - ); + #[inline(always)] + pub(crate) fn chars_to_number(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("number_chars"), 2); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + if let Some(atom_or_string) = self.machine_st.value_to_str_like(a1) { + self.machine_st.parse_number_from_string( + atom_or_string.to_string(), + &self.indices, + stub_gen, + )?; + } else { + // a1 is a ground list at the call site within + // number_chars/2, so failure of value_to_str_like + // means the list contains a non-character. + let err = self.machine_st.type_error(ValidType::Character, a1); + return Err(self.machine_st.error_form(err, stub_gen())); + } - self.machine_st.unify_fixnum( - Fixnum::build_with(len), - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), - ); - } - &SystemClauseType::CallContinuation => { - let stub_gen = || functor_stub(atom!("call_continuation"), 1); - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + Ok(()) + } - match self.machine_st.try_from_list(a1, stub_gen) { - Err(e) => return Err(e), - Ok(cont_chunks) => { - let mut return_p = if self.machine_st.last_call { - self.machine_st.cp - } else { - self.machine_st.p.local() + 1 - }; + #[inline(always)] + pub(crate) fn create_partial_string(&mut self) { + let atom = cell_as_atom!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) + ); - self.machine_st.p = CodePtr::Local(return_p); + if atom == atom!("") { + self.machine_st.fail = true; + return; + } - for chunk in cont_chunks.into_iter().rev() { - return_p = self.machine_st.call_continuation_chunk(chunk, return_p); - } - } - } + let pstr_h = self.machine_st.heap.len(); - return Ok(()); - } - &SystemClauseType::CharsToNumber => { - let stub_gen = || functor_stub(atom!("number_chars"), 2); - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + self.machine_st.heap.push(pstr_as_cell!(atom)); + self.machine_st.heap.push(heap_loc_as_cell!(pstr_h+1)); - if let Some(atom_or_string) = self.machine_st.value_to_str_like(a1) { - self.machine_st.parse_number_from_string( - atom_or_string.to_string(), - &self.indices, - stub_gen, - )?; - } else { - // a1 is a ground list at the call site within - // number_chars/2, so failure of value_to_str_like - // means the list contains a non-character. - let err = self.machine_st.type_error(ValidType::Character, a1); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - &SystemClauseType::CreatePartialString => { - let atom = cell_as_atom!( - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) - ); + unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_as_cell!(pstr_h)); - if atom == atom!("") { - self.machine_st.fail = true; - return Ok(()); - } + if !self.machine_st.fail { + self.machine_st.bind(Ref::heap_cell(pstr_h+1), self.machine_st.registers[3]); + } + } - let pstr_h = self.machine_st.heap.len(); + #[inline(always)] + pub(crate) fn is_partial_string(&mut self) { + let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - self.machine_st.heap.push(pstr_as_cell!(atom)); - self.machine_st.heap.push(heap_loc_as_cell!(pstr_h+1)); + let h = self.machine_st.heap.len(); + self.machine_st.heap.push(value); - unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_as_cell!(pstr_h)); + let mut iter = HeapPStrIter::new(&self.machine_st.heap, h); - if !self.machine_st.fail { - self.machine_st.bind(Ref::heap_cell(pstr_h+1), self.machine_st.registers[3]); - } - } - &SystemClauseType::IsPartialString => { - let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + while let Some(_) = iter.next() {} - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(value); + let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator(); + self.machine_st.fail = !at_end_of_pstr; - let mut iter = HeapPStrIter::new(&self.machine_st.heap, h); + self.machine_st.heap.pop(); + } - while let Some(_) = iter.next() {} + #[inline(always)] + pub(crate) fn partial_string_tail(&mut self) { + let pstr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator(); - self.machine_st.fail = !at_end_of_pstr; + read_heap_cell!(pstr, + (HeapCellValueTag::PStrLoc, h) => { + let (h, _) = pstr_loc_and_offset(&self.machine_st.heap, h); - self.machine_st.heap.pop(); + if HeapCellValueTag::CStr == self.machine_st.heap[h].get_tag() { + self.machine_st.unify_atom( + atom!("[]"), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) + ); + } else { + unify_fn!( + self.machine_st, + heap_loc_as_cell!(h+1), + self.machine_st.registers[2] + ); + } } - &SystemClauseType::PartialStringTail => { - let pstr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - - read_heap_cell!(pstr, - (HeapCellValueTag::PStrLoc, h) => { - let (h, _) = pstr_loc_and_offset(&self.machine_st.heap, h); - - if HeapCellValueTag::CStr == self.machine_st.heap[h].get_tag() { - self.machine_st.unify_atom( - atom!("[]"), - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) - ); - } else { - unify_fn!( - self.machine_st, - heap_loc_as_cell!(h+1), - self.machine_st.registers[2] - ); - } - } - (HeapCellValueTag::CStr) => { - self.machine_st.unify_atom( - atom!("[]"), - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) - ); - } - (HeapCellValueTag::Lis, h) => { - unify_fn!( - self.machine_st, - heap_loc_as_cell!(h+1), - self.machine_st.registers[2] - ); - } - _ => { - self.machine_st.fail = true; - } + (HeapCellValueTag::CStr) => { + self.machine_st.unify_atom( + atom!("[]"), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) ); } - &SystemClauseType::PeekByte => { - let stub_gen = || functor_stub(atom!("peek_byte"), 2); - - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("peek_byte"), - 2, - )?; - - self.machine_st.check_stream_properties( - stream, - StreamType::Binary, - Some(self.machine_st.registers[2]), - atom!("peek_byte"), - 2, - )?; - - if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } else if self.machine_st.fail { - return Ok(()); - } - } + (HeapCellValueTag::Lis, h) => { + unify_fn!( + self.machine_st, + heap_loc_as_cell!(h+1), + self.machine_st.registers[2] + ); + } + _ => { + self.machine_st.fail = true; + } + ); + } - if stream.at_end_of_stream() { - stream.set_past_end_of_stream(true); + #[inline(always)] + pub(crate) fn peek_byte(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("peek_byte"), 2); + + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("peek_byte"), + 2, + )?; + + self.machine_st.check_stream_properties( + stream, + StreamType::Binary, + Some(self.machine_st.registers[2]), + atom!("peek_byte"), + 2, + )?; + + if stream.past_end_of_stream() { + if EOFAction::Reset != stream.options().eof_action() { + return Ok(()); + } else if self.machine_st.fail { + return Ok(()); + } + } - self.machine_st.unify_fixnum( - Fixnum::build_with(-1), - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), - ); + if stream.at_end_of_stream() { + stream.set_past_end_of_stream(true); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + self.machine_st.unify_fixnum( + Fixnum::build_with(-1), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), + ); - let addr = match self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) { - addr if addr.is_var() => addr, - addr => match Number::try_from(addr) { - Ok(Number::Integer(n)) => { - if let Some(nb) = n.to_u8() { - fixnum_as_cell!(Fixnum::build_with(nb as i64)) - } else { - let err = self.machine_st.type_error(ValidType::InByte, addr); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n.get_num()) { - fixnum_as_cell!(Fixnum::build_with(nb as i64)) - } else { - let err = self.machine_st.type_error(ValidType::InByte, addr); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - _ => { - let err = self.machine_st.type_error(ValidType::InByte, addr); - return Err(self.machine_st.error_form(err, stub_gen())); - } - }, - }; + return Ok(()); + } - loop { - match stream.peek_byte().map_err(|e| e.kind()) { - Ok(b) => { - self.machine_st.unify_fixnum(Fixnum::build_with(b as i64), addr); - } - Err(ErrorKind::PermissionDenied) => { - self.machine_st.fail = true; - break; - } - _ => { - self.machine_st.eof_action( - self.machine_st.registers[2], - stream, - atom!("peek_byte"), - 2, - )?; - - if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } else if self.machine_st.fail { - return Ok(()); - } - } + let addr = match self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) { + addr if addr.is_var() => addr, + addr => match Number::try_from(addr) { + Ok(Number::Integer(n)) => { + if let Some(nb) = n.to_u8() { + fixnum_as_cell!(Fixnum::build_with(nb as i64)) + } else { + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); } } - } - &SystemClauseType::PeekChar => { - let stub_gen = || functor_stub(atom!("peek_char"), 2); - - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("peek_char"), - 2, - )?; + Ok(Number::Fixnum(n)) => { + if let Ok(nb) = u8::try_from(n.get_num()) { + fixnum_as_cell!(Fixnum::build_with(nb as i64)) + } else { + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + _ => { + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); + } + }, + }; - self.machine_st.check_stream_properties( - stream, - StreamType::Text, - Some(self.machine_st.registers[2]), - atom!("peek_char"), - 2, - )?; + loop { + match stream.peek_byte().map_err(|e| e.kind()) { + Ok(b) => { + self.machine_st.unify_fixnum(Fixnum::build_with(b as i64), addr); + } + Err(ErrorKind::PermissionDenied) => { + self.machine_st.fail = true; + break; + } + _ => { + self.machine_st.eof_action( + self.machine_st.registers[2], + stream, + atom!("peek_byte"), + 2, + )?; - if stream.past_end_of_stream() { if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); + break; } else if self.machine_st.fail { - return Ok(()); + break; } } + } + } - if stream.at_end_of_stream() { - let end_of_file = atom!("end_of_file"); - stream.set_past_end_of_stream(true); + Ok(()) + } + + #[inline(always)] + pub(crate) fn peek_char(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("peek_char"), 2); + + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("peek_char"), + 2, + )?; + + self.machine_st.check_stream_properties( + stream, + StreamType::Text, + Some(self.machine_st.registers[2]), + atom!("peek_char"), + 2, + )?; + + if stream.past_end_of_stream() { + if EOFAction::Reset != stream.options().eof_action() { + return Ok(()); + } else if self.machine_st.fail { + return Ok(()); + } + } + + if stream.at_end_of_stream() { + let end_of_file = atom!("end_of_file"); + stream.set_past_end_of_stream(true); + + self.machine_st.unify_atom( + end_of_file, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), + ); - self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); - return return_from_clause!(self.machine_st.last_call, self.machine_st); + return Ok(()); + } + + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + let a2 = read_heap_cell!(a2, + (HeapCellValueTag::Char) => { + a2 + } + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + if let Some(c) = name.as_char() { + char_as_cell!(c) + } else { + let err = self.machine_st.type_error(ValidType::InCharacter, a2); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } else { + let err = self.machine_st.type_error(ValidType::InCharacter, a2); + return Err(self.machine_st.error_form(err, stub_gen())); } + } + (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { + a2 + } + _ => { + let err = self.machine_st.type_error(ValidType::InCharacter, a2); + return Err(self.machine_st.error_form(err, stub_gen())); + } + ); - let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + loop { + match stream.peek_char().map(|result| result.map_err(|e| e.kind())) { + Some(Ok(d)) => { + self.machine_st.unify_char(d, a2); + break; + } + Some(Err(ErrorKind::PermissionDenied)) => { + self.machine_st.fail = true; + break; + } + _ => { + self.machine_st.eof_action( + self.machine_st.registers[2], + stream, + atom!("peek_char"), + 2, + )?; - let a2 = read_heap_cell!(a2, - (HeapCellValueTag::Char) => { - a2 + if EOFAction::Reset != stream.options().eof_action() { + break; + } else if self.machine_st.fail { + break; } - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - if let Some(c) = name.as_char() { - char_as_cell!(c) - } else { - let err = self.machine_st.type_error(ValidType::InCharacter, a2); - return Err(self.machine_st.error_form(err, stub_gen())); - } + } + } + } + + Ok(()) + } + + #[inline(always)] + pub(crate) fn peek_code(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("peek_code"), 2); + + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("peek_code"), + 2, + )?; + + self.machine_st.check_stream_properties( + stream, + StreamType::Text, + Some(self.machine_st.registers[2]), + atom!("peek_code"), + 2, + )?; + + if stream.past_end_of_stream() { + if EOFAction::Reset != stream.options().eof_action() { + return Ok(()); + } else if self.machine_st.fail { + return Ok(()); + } + } + + if stream.at_end_of_stream() { + let end_of_file = atom!("end_of_file"); + stream.set_past_end_of_stream(true); + + self.machine_st.unify_atom( + end_of_file, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), + ); + + return Ok(()); + } + + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + let addr = read_heap_cell!(a2, + (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { + a2 + } + _ => { + match Number::try_from(a2) { + Ok(Number::Integer(n)) => { + let n = n + .to_u32() + .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + + if let Some(n) = n { + fixnum_as_cell!(Fixnum::build_with(n as i64)) } else { - let err = self.machine_st.type_error(ValidType::InCharacter, a2); + let err = self.machine_st.representation_error(RepFlag::InCharacterCode); return Err(self.machine_st.error_form(err, stub_gen())); } } - (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { - a2 + Ok(Number::Fixnum(n)) => { + let n = u32::try_from(n.get_num()) + .ok() + .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); + + if let Some(n) = n { + fixnum_as_cell!(Fixnum::build_with(n as i64)) + } else { + let err = self.machine_st.representation_error(RepFlag::InCharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); + } } _ => { - let err = self.machine_st.type_error(ValidType::InCharacter, a2); + let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]); return Err(self.machine_st.error_form(err, stub_gen())); } - ); - - loop { - match stream.peek_char().map(|result| result.map_err(|e| e.kind())) { - Some(Ok(d)) => { - self.machine_st.unify_char(d, a2); - break; - } - Some(Err(ErrorKind::PermissionDenied)) => { - self.machine_st.fail = true; - break; - } - _ => { - self.machine_st.eof_action( - self.machine_st.registers[2], - stream, - atom!("peek_char"), - 2, - )?; - - if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } else if self.machine_st.fail { - return Ok(()); - } - } - } } } - &SystemClauseType::PeekCode => { - let stub_gen = || functor_stub(atom!("peek_code"), 2); + ); - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("peek_code"), - 2, - )?; + loop { + let result = stream.peek_char(); - self.machine_st.check_stream_properties( - stream, - StreamType::Text, - Some(self.machine_st.registers[2]), - atom!("peek_code"), - 2, - )?; + match result.map(|result| result.map_err(|e| e.kind())) { + Some(Ok(c)) => { + self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr); + break; + } + Some(Err(ErrorKind::PermissionDenied)) => { + self.machine_st.fail = true; + break; + } + _ => { + self.machine_st.eof_action( + self.machine_st.registers[2], + stream, + atom!("peek_code"), + 2, + )?; - if stream.past_end_of_stream() { if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); + break; } else if self.machine_st.fail { - return Ok(()); + break; } } + } + } - if stream.at_end_of_stream() { - let end_of_file = atom!("end_of_file"); - stream.set_past_end_of_stream(true); + return Ok(()); + } - self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + #[inline(always)] + pub(crate) fn number_to_chars(&mut self) { + let n = self.machine_st.registers[1]; + let chs = self.machine_st.registers[2]; + + let n = self.machine_st.store(self.machine_st.deref(n)); + + let string = match Number::try_from(n) { + Ok(Number::Float(OrderedFloat(n))) => { + format!("{0:<20?}", n) + } + Ok(Number::Fixnum(n)) => n.get_num().to_string(), + Ok(Number::Integer(n)) => n.to_string(), + Ok(Number::Rational(r)) => { + // n has already been confirmed as an integer, and + // internally, Rational is assumed reduced, so its denominator + // must be 1. + r.numer().to_string() + } + _ => { + unreachable!() + } + }; + + let chars_atom = self.machine_st.atom_tbl.build_with(&string.trim()); + self.machine_st.unify_complete_string(chars_atom, self.machine_st.store(self.machine_st.deref(chs))); + } + + #[inline(always)] + pub(crate) fn number_to_codes(&mut self) { + let n = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let chs = self.machine_st.registers[2]; + + let string = match Number::try_from(n) { + Ok(Number::Float(OrderedFloat(n))) => { + format!("{0:<20?}", n) + } + Ok(Number::Fixnum(n)) => n.get_num().to_string(), + Ok(Number::Integer(n)) => n.to_string(), + Ok(Number::Rational(r)) => { + // n has already been confirmed as an integer, and + // internally, Rational is assumed reduced, so its + // denominator must be 1. + r.numer().to_string() + } + _ => { + unreachable!() + } + }; + + let codes = string.trim().chars().map(|c| { + fixnum_as_cell!(Fixnum::build_with(c as i64)) + }); + + let h = iter_to_heap_list(&mut self.machine_st.heap, codes); + unify!(self.machine_st, heap_loc_as_cell!(h), chs); + } + + #[inline(always)] + pub(crate) fn codes_to_number(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("number_codes"), 2); + + match self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen) { + Err(e) => { + return Err(e); + } + Ok(addrs) => { + let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?; + self.machine_st.parse_number_from_string(string, &self.indices, stub_gen)?; + } + } + + Ok(()) + } + + #[inline(always)] + pub(crate) fn lifted_heap_length(&mut self) { + let a1 = self.machine_st.registers[1]; + let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.len() as i64); + + self.machine_st.unify_fixnum(lh_len, a1); + } + + #[inline(always)] + pub(crate) fn char_code(&mut self) -> CallResult { + let stub_gen = || functor_stub(atom!("char_code"), 2); + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let c = read_heap_cell!(a1, + (HeapCellValueTag::Atom, (name, _arity)) => { + name.as_char().unwrap() + } + (HeapCellValueTag::Char, c) => { + c + } + _ => { let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - let addr = read_heap_cell!(a2, - (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { - a2 - } - _ => { - match Number::try_from(a2) { - Ok(Number::Integer(n)) => { - let n = n - .to_u32() - .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); - - if let Some(n) = n { - fixnum_as_cell!(Fixnum::build_with(n as i64)) - } else { - let err = self.machine_st.representation_error(RepFlag::InCharacterCode); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - Ok(Number::Fixnum(n)) => { - let n = u32::try_from(n.get_num()) - .ok() - .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n))); - - if let Some(n) = n { - fixnum_as_cell!(Fixnum::build_with(n as i64)) - } else { - let err = self.machine_st.representation_error(RepFlag::InCharacterCode); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } + match Number::try_from(a2) { + Ok(Number::Integer(n)) => { + let c = match n.to_u32().and_then(std::char::from_u32) { + Some(c) => c, _ => { - let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]); + let err = self.machine_st.representation_error(RepFlag::CharacterCode); return Err(self.machine_st.error_form(err, stub_gen())); } - } - } - ); - - loop { - let result = stream.peek_char(); + }; - match result.map(|result| result.map_err(|e| e.kind())) { - Some(Ok(c)) => { - self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr); - break; - } - Some(Err(ErrorKind::PermissionDenied)) => { - self.machine_st.fail = true; - break; - } - _ => { - self.machine_st.eof_action( - self.machine_st.registers[2], - stream, - atom!("peek_code"), - 2, - )?; - - if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } else if self.machine_st.fail { - return Ok(()); + self.machine_st.unify_char(c, a2); + return Ok(()); + } + Ok(Number::Fixnum(n)) => { + match u32::try_from(n.get_num()) { + Ok(n) => { + if let Some(c) = std::char::from_u32(n) { + self.machine_st.unify_char(c, a1); + return Ok(()); + } } + _ => {} } + + let err = self.machine_st.representation_error(RepFlag::CharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); + } + _ => { + self.machine_st.fail = true; + return Ok(()); } } } - &SystemClauseType::NumberToChars => { - let n = self.machine_st.registers[1]; - let chs = self.machine_st.registers[2]; + ); + + self.machine_st.unify_fixnum( + Fixnum::build_with(c as i64), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), + ); + + Ok(()) + } + + #[inline(always)] + pub(crate) fn char_type(&mut self) { + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + let c = read_heap_cell!(a1, + (HeapCellValueTag::Char, c) => { + c + } + (HeapCellValueTag::Atom, (name, _arity)) => { + name.as_char().unwrap() + } + _ => { + unreachable!() + } + ); + + let chars = cell_as_atom!(a2); + self.machine_st.fail = true; // This predicate fails by default. + + macro_rules! macro_check { + ($id:ident, $name:expr) => { + if $id!(c) && chars == $name { + self.machine_st.fail = false; + return; + } + }; + } + + macro_rules! method_check { + ($id:ident, $name:expr) => { + if c.$id() && chars == $name { + self.machine_st.fail = false; + return; + } + }; + } + + macro_check!(alpha_char, atom!("alpha")); + method_check!(is_alphabetic, atom!("alphabetic")); + method_check!(is_alphanumeric, atom!("alphanumeric")); + macro_check!(alpha_numeric_char, atom!("alnum")); + method_check!(is_ascii, atom!("ascii")); + method_check!(is_ascii_punctuation, atom!("ascii_ponctuaction")); + method_check!(is_ascii_graphic, atom!("ascii_graphic")); + // macro_check!(backslash_char, atom!("backslash")); + // macro_check!(back_quote_char, atom!("back_quote")); + macro_check!(binary_digit_char, atom!("binary_digit")); + // macro_check!(capital_letter_char, atom!("upper")); + // macro_check!(comment_1_char, "comment_1"); + // macro_check!(comment_2_char, "comment_2"); + method_check!(is_control, atom!("control")); + // macro_check!(cut_char, atom!("cut")); + macro_check!(decimal_digit_char, atom!("decimal_digit")); + // macro_check!(decimal_point_char, atom!("decimal_point")); + // macro_check!(double_quote_char, atom!("double_quote")); + macro_check!(exponent_char, atom!("exponent")); + macro_check!(graphic_char, atom!("graphic")); + macro_check!(graphic_token_char, atom!("graphic_token")); + macro_check!(hexadecimal_digit_char, atom!("hexadecimal_digit")); + macro_check!(layout_char, atom!("layout")); + method_check!(is_lowercase, atom!("lower")); + macro_check!(meta_char, atom!("meta")); + // macro_check!(new_line_char, atom!("new_line")); + method_check!(is_numeric, atom!("numeric")); + macro_check!(octal_digit_char, atom!("octal_digit")); + macro_check!(octet_char, atom!("octet")); + macro_check!(prolog_char, atom!("prolog")); + // macro_check!(semicolon_char, atom!("semicolon")); + macro_check!(sign_char, atom!("sign")); + // macro_check!(single_quote_char, atom!("single_quote")); + // macro_check!(small_letter_char, atom!("lower")); + macro_check!(solo_char, atom!("solo")); + // macro_check!(space_char, atom!("space")); + macro_check!(symbolic_hexadecimal_char, atom!("symbolic_hexadecimal")); + macro_check!(symbolic_control_char, atom!("symbolic_control")); + method_check!(is_uppercase, atom!("upper")); + // macro_check!(variable_indicator_char, atom!("variable_indicator")); + method_check!(is_whitespace, atom!("whitespace")); + } + + #[inline(always)] + pub(crate) fn check_cut_point(&mut self) { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let old_b = cell_as_fixnum!(addr).get_num() as usize; + + let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b; + let prev_b = self.machine_st.stack.index_or_frame(prev_b).prelude.b; + + if prev_b > old_b { + self.machine_st.fail = true; + } + } + + #[inline(always)] + pub(crate) fn copy_term_without_attr_vars(&mut self) { + self.machine_st.copy_term(AttrVarPolicy::StripAttributes); + } + + #[inline(always)] + pub(crate) fn fetch_global_var(&mut self) { + let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); + let addr = self.machine_st.registers[2]; + + match self.indices.global_variables.get_mut(&key) { + Some((ref ball, ref mut loc)) => match loc { + Some(value_loc) => { + unify_fn!(self.machine_st, addr, *value_loc); + } + None if !ball.stub.is_empty() => { + let h = self.machine_st.heap.len(); + let stub = ball.copy_and_align(h); + + self.machine_st.heap.extend(stub.into_iter()); + + unify_fn!(self.machine_st, addr, heap_loc_as_cell!(h)); + + if !self.machine_st.fail { + *loc = Some(heap_loc_as_cell!(h)); + self.machine_st.trail(TrailRef::BlackboardEntry(key)); + } + } + _ => self.machine_st.fail = true, + }, + None => self.machine_st.fail = true, + }; + } + + #[inline(always)] + pub(crate) fn put_code(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("put_code"), + 2, + )?; + + self.machine_st.check_stream_properties( + stream, + StreamType::Text, + None, + atom!("put_code"), + 2, + )?; + + let stub_gen = || functor_stub(atom!("put_code"), 2); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + if addr.is_var() { + let err = self.machine_st.instantiation_error(); + return Err(self.machine_st.error_form(err, stub_gen())); + } else { + match Number::try_from(addr) { + Ok(Number::Integer(n)) => { + if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) { + write!(&mut stream, "{}", c).unwrap(); + return Ok(()); + } + } + Ok(Number::Fixnum(n)) => { + let n = n.get_num(); + + if let Some(c) = u32::try_from(n).ok().and_then(|c| char::from_u32(c)) { + write!(&mut stream, "{}", c).unwrap(); + return Ok(()); + } + } + _ => { + let err = self.machine_st.type_error(ValidType::Integer, addr); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + + let err = self.machine_st.representation_error(RepFlag::CharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + + #[inline(always)] + pub(crate) fn put_char(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("put_char"), + 2, + )?; + + self.machine_st.check_stream_properties( + stream, + StreamType::Text, + None, + atom!("put_char"), + 2, + )?; + + let stub_gen = || functor_stub(atom!("put_char"), 2); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + if addr.is_var() { + let err = self.machine_st.instantiation_error(); + return Err(self.machine_st.error_form(err, stub_gen())); + } else { + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (name, _arity)) => { + let c = name.as_char().unwrap(); + write!(&mut stream, "{}", c).unwrap(); + return Ok(()); + } + (HeapCellValueTag::Char, c) => { + write!(&mut stream, "{}", c).unwrap(); + return Ok(()); + } + _ => { + } + ); + + let err = self.machine_st.type_error(ValidType::Character, addr); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + + #[inline(always)] + pub(crate) fn put_chars(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("$put_chars"), + 2, + )?; + + let mut bytes = Vec::new(); + let stub_gen = || functor_stub(atom!("$put_chars"), 2); + + if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { + if stream.options().stream_type() == StreamType::Binary { + for c in string.as_str().chars() { + if c as u32 > 255 { + let err = self.machine_st.type_error(ValidType::Byte, char_as_cell!(c)); + return Err(self.machine_st.error_form(err, stub_gen())); + } + + bytes.push(c as u8); + } + } else { + bytes = string.as_str().bytes().collect(); + } + + match stream.write_all(&bytes) { + Ok(_) => { + } + _ => { + let addr = stream_as_cell!(stream); + let err = self.machine_st.existence_error(ExistenceError::Stream(addr)); + + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + } else { + self.machine_st.fail = true; + } + + Ok(()) + } + + #[inline(always)] + pub(crate) fn put_byte(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("put_byte"), + 2, + )?; + + self.machine_st.check_stream_properties( + stream, + StreamType::Binary, + None, + atom!("put_byte"), + 2, + )?; + + let stub_gen = || functor_stub(atom!("put_byte"), 2); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + if addr.is_var() { + let err = self.machine_st.instantiation_error(); + return Err(self.machine_st.error_form(err, stub_gen())); + } else { + match Number::try_from(addr) { + Ok(Number::Integer(n)) => { + if let Some(nb) = n.to_u8() { + match stream.write(&mut [nb]) { + Ok(1) => { + return Ok(()); + } + _ => { + let err = self.machine_st.existence_error( + ExistenceError::Stream(stream_as_cell!(stream)) + ); + + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + } + } + Ok(Number::Fixnum(n)) => { + if let Ok(nb) = u8::try_from(n.get_num()) { + match stream.write(&mut [nb]) { + Ok(1) => { + return Ok(()); + } + _ => { + let err = self.machine_st.existence_error( + ExistenceError::Stream(stream_as_cell!(stream)) + ); + + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + } + } + _ => { + } + } + } + + let err = self.machine_st.type_error(ValidType::Byte, self.machine_st.registers[2]); + Err(self.machine_st.error_form(err, stub_gen())) + } + + #[inline(always)] + pub(crate) fn get_byte(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("get_byte"), + 2, + )?; + + self.machine_st.check_stream_properties( + stream, + StreamType::Binary, + Some(self.machine_st.registers[2]), + atom!("get_byte"), + 2, + )?; + + if stream.past_end_of_stream() { + self.machine_st.eof_action(self.machine_st.registers[2], stream, atom!("get_byte"), 2)?; + + if EOFAction::Reset != stream.options().eof_action() { + return Ok(()); + } else if self.machine_st.fail { + return Ok(()); + } + } + + let stub_gen = || functor_stub(atom!("get_byte"), 2); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + let addr = if addr.is_var() { + addr + } else { + match Number::try_from(addr) { + Ok(Number::Integer(n)) => { + if let Some(nb) = n.to_u8() { + fixnum_as_cell!(Fixnum::build_with(nb as i64)) + } else { + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + Ok(Number::Fixnum(n)) => { + if let Ok(nb) = u8::try_from(n.get_num()) { + fixnum_as_cell!(Fixnum::build_with(nb as i64)) + } else { + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + _ => { + let err = self.machine_st.type_error(ValidType::InByte, addr); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + }; + + loop { + let mut b = [0u8; 1]; + + match stream.read(&mut b) { + Ok(1) => { + self.machine_st.unify_fixnum(Fixnum::build_with(b[0] as i64), addr); + break; + } + _ => { + stream.set_past_end_of_stream(true); + self.machine_st.unify_fixnum(Fixnum::build_with(-1), self.machine_st.registers[2]); + break; + } + } + } + + Ok(()) + } + + #[inline(always)] + pub(crate) fn get_char(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("get_char"), + 2, + )?; + + self.machine_st.check_stream_properties( + stream, + StreamType::Text, + Some(self.machine_st.registers[2]), + atom!("get_char"), + 2, + )?; + + if stream.past_end_of_stream() { + if EOFAction::Reset != stream.options().eof_action() { + return Ok(()); + } else if self.machine_st.fail { + return Ok(()); + } + } + + if stream.at_end_of_stream() { + let end_of_file = atom!("end_of_file"); + stream.set_past_end_of_stream(true); + + self.machine_st.unify_atom( + end_of_file, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) + ); + + return Ok(()); + } + + let stub_gen = || functor_stub(atom!("get_char"), 2); + let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_char"), 2)?; + + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + let addr = if addr.is_var() { + addr + } else { + read_heap_cell!(addr, + (HeapCellValueTag::Atom, (atom, _arity)) => { + char_as_cell!(atom.as_char().unwrap()) + } + (HeapCellValueTag::Char) => { + addr + } + _ => { + let err = self.machine_st.type_error(ValidType::InCharacter, addr); + return Err(self.machine_st.error_form(err, stub_gen())); + } + ) + }; + + loop { + let result = iter.read_char(); + + match result { + Some(Ok(c)) => { + self.machine_st.unify_char(c, addr); + break; + } + _ => { + self.machine_st.eof_action( + self.machine_st.registers[2], + stream, + atom!("get_char"), + 2, + )?; + + if EOFAction::Reset != stream.options().eof_action() { + break; + } else if self.machine_st.fail { + break; + } + } + } + } + + Ok(()) + } + + #[inline(always)] + pub(crate) fn get_n_chars(&mut self) -> CallResult { + let stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("get_n_chars"), + 3, + )?; + + let num = match Number::try_from(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), + Ok(Number::Integer(n)) => match n.to_usize() { + Some(u) => u, + _ => { + self.machine_st.fail = true; + return Ok(()); + } + }, + _ => { + unreachable!() + } + }; + + let mut string = String::new(); + + if stream.options().stream_type() == StreamType::Binary { + let mut buf = vec![]; + let mut chunk = stream.take(num as u64); + + chunk.read_to_end(&mut buf).ok(); + + for c in buf { + string.push(c as char); + } + } else { + let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_n_chars"), 2)?; + + for _ in 0..num { + let result = iter.read_char(); + + match result { + Some(Ok(c)) => { + string.push(c); + } + _ => { + break; + } + } + } + }; + + let atom = self.machine_st.atom_tbl.build_with(&string); + self.machine_st.unify_complete_string(atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]))); + + Ok(()) + } + + #[inline(always)] + pub(crate) fn get_code(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("get_code"), + 2, + )?; + + self.machine_st.check_stream_properties( + stream, + StreamType::Text, + Some(self.machine_st.registers[2]), + atom!("get_code"), + 2, + )?; + + if stream.past_end_of_stream() { + if EOFAction::Reset != stream.options().eof_action() { + return Ok(()); + } else if self.machine_st.fail { + return Ok(()); + } + } + + if stream.at_end_of_stream() { + let end_of_file = atom!("end_of_file"); + stream.set_past_end_of_stream(true); + + self.machine_st.unify_atom( + end_of_file, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), + ); + + return Ok(()); + } + + let stub_gen = || functor_stub(atom!("get_code"), 2); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + let addr = if addr.is_var() { + addr + } else { + match Number::try_from(addr) { + Ok(Number::Integer(n)) => { + let n = n + .to_u32() + .and_then(|n| std::char::from_u32(n)); + + if let Some(n) = n { + fixnum_as_cell!(Fixnum::build_with(n as i64)) + } else { + let err = self.machine_st.representation_error(RepFlag::InCharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + Ok(Number::Fixnum(n)) => { + let nf = u32::try_from(n.get_num()) + .ok() + .and_then(|n| std::char::from_u32(n)); + + if nf.is_some() { + fixnum_as_cell!(n) + } else { + let err = self.machine_st.representation_error(RepFlag::InCharacterCode); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + _ => { + let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]); + return Err(self.machine_st.error_form(err, stub_gen())); + } + } + }; + + let mut iter = self.machine_st.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?; + + loop { + let result = iter.read_char(); + + match result { + Some(Ok(c)) => { + self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr); + break; + } + _ => { + self.machine_st.eof_action( + self.machine_st.registers[2], + stream, + atom!("get_code"), + 2, + )?; + + if EOFAction::Reset != stream.options().eof_action() { + break; + } else if self.machine_st.fail { + break; + } + } + } + } + + Ok(()) + } + + #[inline(always)] + pub(crate) fn first_stream(&mut self) { + let mut first_stream = None; + let mut null_streams = BTreeSet::new(); + + for stream in self.indices.streams.iter().cloned() { + if !stream.is_null_stream() { + first_stream = Some(stream); + break; + } else { + null_streams.insert(stream); + } + } + + self.indices.streams = self.indices.streams.sub(&null_streams); + + if let Some(first_stream) = first_stream { + let stream = stream_as_cell!(first_stream); + + let var = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1] + )).as_var().unwrap(); + + self.machine_st.bind(var, stream); + } else { + self.machine_st.fail = true; + } + } + + #[inline(always)] + pub(crate) fn next_stream(&mut self) { + let prev_stream = cell_as_stream!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1] + ))); + + let mut next_stream = None; + let mut null_streams = BTreeSet::new(); + + for stream in self.indices + .streams + .range(prev_stream..) + .skip(1) + .cloned() + { + if !stream.is_null_stream() { + next_stream = Some(stream); + break; + } else { + null_streams.insert(stream); + } + } + + self.indices.streams = self.indices.streams.sub(&null_streams); + + if let Some(next_stream) = next_stream { + let var = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2] + )).as_var().unwrap(); + + let next_stream = stream_as_cell!(next_stream); + self.machine_st.bind(var, next_stream); + } else { + self.machine_st.fail = true; + } + } + + #[inline(always)] + pub(crate) fn flush_output(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("flush_output"), + 1, + )?; + + if !stream.is_output_stream() { + let stub = functor_stub(atom!("flush_output"), 1); + let addr = stream_as_cell!(stream); + + let err = self.machine_st.permission_error( + Permission::OutputStream, + atom!("stream"), + addr, + ); + + return Err(self.machine_st.error_form(err, stub)); + } + + stream.flush().unwrap(); + Ok(()) + } + + #[inline(always)] + pub(crate) fn get_single_char(&mut self) -> CallResult { + let ctrl_c = KeyEvent { + code: KeyCode::Char('c'), + modifiers: KeyModifiers::CONTROL, + }; + + let key = get_key(); + + if key == ctrl_c { + let stub = functor_stub(atom!("get_single_char"), 1); + let err = self.machine_st.interrupt_error(); + let err = self.machine_st.error_form(err, stub); + + return Err(err); + } + + let c = match key.code { + KeyCode::Enter => '\n', + KeyCode::Tab => '\t', + KeyCode::Char(c) => c, + _ => unreachable!(), + }; + + self.machine_st.unify_char( + c, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])), + ); + + Ok(()) + } + + #[inline(always)] + pub(crate) fn head_is_dynamic(&mut self) { + let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1]) + )); + + let (name, arity) = read_heap_cell!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), + (HeapCellValueTag::Str, s) => { + cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity() + } + (HeapCellValueTag::Atom, (name, _arity)) => { + (name, 0) + } + _ => { + unreachable!() + } + ); + + self.machine_st.fail = !self.indices.is_dynamic_predicate(module_name, (name, arity)); + } + + #[inline(always)] + pub(crate) fn close(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("close"), + 2, + )?; + + if !stream.is_input_stream() { + stream.flush().unwrap(); // 8.11.6.1b) + } - let n = self.machine_st.store(self.machine_st.deref(n)); + self.indices.streams.remove(&stream); - let string = match Number::try_from(n) { - Ok(Number::Float(OrderedFloat(n))) => { - format!("{0:<20?}", n) - } - Ok(Number::Fixnum(n)) => n.get_num().to_string(), - Ok(Number::Integer(n)) => n.to_string(), - Ok(Number::Rational(r)) => { - // n has already been confirmed as an integer, and - // internally, Rational is assumed reduced, so its denominator - // must be 1. - r.numer().to_string() - } - _ => { - unreachable!() - } - }; + if stream == self.user_input { + self.user_input = self.indices + .stream_aliases + .get(&atom!("user_input")) + .cloned() + .unwrap(); - let chars_atom = self.machine_st.atom_tbl.build_with(&string.trim()); - self.machine_st.unify_complete_string(chars_atom, self.machine_st.store(self.machine_st.deref(chs))); - } - &SystemClauseType::NumberToCodes => { - let n = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let chs = self.machine_st.registers[2]; + self.indices.streams.insert(self.user_input); + } else if stream == self.user_output { + self.user_output = self.indices + .stream_aliases + .get(&atom!("user_output")) + .cloned() + .unwrap(); - let string = match Number::try_from(n) { - Ok(Number::Float(OrderedFloat(n))) => { - format!("{0:<20?}", n) - } - Ok(Number::Fixnum(n)) => n.get_num().to_string(), - Ok(Number::Integer(n)) => n.to_string(), - Ok(Number::Rational(r)) => { - // n has already been confirmed as an integer, and - // internally, Rational is assumed reduced, so its - // denominator must be 1. - r.numer().to_string() - } - _ => { - unreachable!() - } - }; + self.indices.streams.insert(self.user_output); + } - let codes = string.trim().chars().map(|c| { - fixnum_as_cell!(Fixnum::build_with(c as i64)) - }); + if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() { + let close_result = stream.close(); - let h = iter_to_heap_list(&mut self.machine_st.heap, codes); - unify!(self.machine_st, heap_loc_as_cell!(h), chs); + if let Some(alias) = stream.options().get_alias() { + self.indices.stream_aliases.remove(&alias); } - &SystemClauseType::CodesToNumber => { - let stub_gen = || functor_stub(atom!("number_codes"), 2); - match self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen) { - Err(e) => { - return Err(e); - } - Ok(addrs) => { - let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?; - self.machine_st.parse_number_from_string(string, &self.indices, stub_gen)?; - } - } - } - &SystemClauseType::LiftedHeapLength => { - let a1 = self.machine_st.registers[1]; - let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.len() as i64); + if let Err(_) = close_result { + let stub = functor_stub(atom!("close"), 1); + let addr = stream_as_cell!(stream); + let err = self.machine_st.existence_error(ExistenceError::Stream(addr)); - self.machine_st.unify_fixnum(lh_len, a1); + return Err(self.machine_st.error_form(err, stub)); } - &SystemClauseType::CharCode => { - let stub_gen = || functor_stub(atom!("char_code"), 2); - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + } - let c = read_heap_cell!(a1, - (HeapCellValueTag::Atom, (name, _arity)) => { - name.as_char().unwrap() - } - (HeapCellValueTag::Char, c) => { - c - } - _ => { - let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - - match Number::try_from(a2) { - Ok(Number::Integer(n)) => { - let c = match n.to_u32().and_then(std::char::from_u32) { - Some(c) => c, - _ => { - let err = self.machine_st.representation_error(RepFlag::CharacterCode); - return Err(self.machine_st.error_form(err, stub_gen())); - } - }; + Ok(()) + } - self.machine_st.unify_char(c, a2); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - Ok(Number::Fixnum(n)) => { - match u32::try_from(n.get_num()) { - Ok(n) => { - if let Some(c) = std::char::from_u32(n) { - self.machine_st.unify_char(c, a1); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - } - _ => {} - } + #[inline(always)] + pub(crate) fn copy_to_lifted_heap(&mut self) { + let lh_offset = cell_as_fixnum!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) + ).get_num() as usize; - let err = self.machine_st.representation_error(RepFlag::CharacterCode); - return Err(self.machine_st.error_form(err, stub_gen())); - } - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } - } - ); + let copy_target = self.machine_st.registers[2]; - self.machine_st.unify_fixnum( - Fixnum::build_with(c as i64), - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), - ); - } - &SystemClauseType::CharType => { - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + let old_threshold = self.machine_st.copy_findall_solution(lh_offset, copy_target); + let new_threshold = self.machine_st.lifted_heap.len() - lh_offset; + + self.machine_st.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold); + + for addr in self.machine_st.lifted_heap[old_threshold + 1 ..].iter_mut() { + *addr -= self.machine_st.heap.len() + lh_offset; + } + } + + #[inline(always)] + pub(crate) fn delete_attribute(&mut self) { + let ls0 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + if let HeapCellValueTag::Lis = ls0.get_tag() { + let l1 = ls0.get_value(); + let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1))); + + if let HeapCellValueTag::Lis = ls1.get_tag() { + let l2 = ls1.get_value(); + + let old_addr = self.machine_st.heap[l1+1]; + let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1))); + + let tail = if tail.is_var() { + heap_loc_as_cell!(l1 + 1) + } else { + tail + }; - let c = read_heap_cell!(a1, - (HeapCellValueTag::Char, c) => { - c + let trail_ref = read_heap_cell!(old_addr, + (HeapCellValueTag::Var, h) => { + TrailRef::AttrVarHeapLink(h) } - (HeapCellValueTag::Atom, (name, _arity)) => { - name.as_char().unwrap() + (HeapCellValueTag::Lis, l) => { + TrailRef::AttrVarListLink(l1 + 1, l) } _ => { unreachable!() } ); - let chars = cell_as_atom!(a2); - self.machine_st.fail = true; // This predicate fails by default. - - macro_rules! macro_check { - ($id:ident, $name:expr) => { - if $id!(c) && chars == $name { - self.machine_st.fail = false; - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - }; - } + self.machine_st.heap[l1 + 1] = tail; + self.machine_st.trail(trail_ref); + } + } + } - macro_rules! method_check { - ($id:ident, $name:expr) => { - if c.$id() && chars == $name { - self.machine_st.fail = false; - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - }; - } + #[inline(always)] + pub(crate) fn delete_head_attribute(&mut self) { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - macro_check!(alpha_char, atom!("alpha")); - method_check!(is_alphabetic, atom!("alphabetic")); - method_check!(is_alphanumeric, atom!("alphanumeric")); - macro_check!(alpha_numeric_char, atom!("alnum")); - method_check!(is_ascii, atom!("ascii")); - method_check!(is_ascii_punctuation, atom!("ascii_ponctuaction")); - method_check!(is_ascii_graphic, atom!("ascii_graphic")); - // macro_check!(backslash_char, atom!("backslash")); - // macro_check!(back_quote_char, atom!("back_quote")); - macro_check!(binary_digit_char, atom!("binary_digit")); - // macro_check!(capital_letter_char, atom!("upper")); - // macro_check!(comment_1_char, "comment_1"); - // macro_check!(comment_2_char, "comment_2"); - method_check!(is_control, atom!("control")); - // macro_check!(cut_char, atom!("cut")); - macro_check!(decimal_digit_char, atom!("decimal_digit")); - // macro_check!(decimal_point_char, atom!("decimal_point")); - // macro_check!(double_quote_char, atom!("double_quote")); - macro_check!(exponent_char, atom!("exponent")); - macro_check!(graphic_char, atom!("graphic")); - macro_check!(graphic_token_char, atom!("graphic_token")); - macro_check!(hexadecimal_digit_char, atom!("hexadecimal_digit")); - macro_check!(layout_char, atom!("layout")); - method_check!(is_lowercase, atom!("lower")); - macro_check!(meta_char, atom!("meta")); - // macro_check!(new_line_char, atom!("new_line")); - method_check!(is_numeric, atom!("numeric")); - macro_check!(octal_digit_char, atom!("octal_digit")); - macro_check!(octet_char, atom!("octet")); - macro_check!(prolog_char, atom!("prolog")); - // macro_check!(semicolon_char, atom!("semicolon")); - macro_check!(sign_char, atom!("sign")); - // macro_check!(single_quote_char, atom!("single_quote")); - // macro_check!(small_letter_char, atom!("lower")); - macro_check!(solo_char, atom!("solo")); - // macro_check!(space_char, atom!("space")); - macro_check!(symbolic_hexadecimal_char, atom!("symbolic_hexadecimal")); - macro_check!(symbolic_control_char, atom!("symbolic_control")); - method_check!(is_uppercase, atom!("upper")); - // macro_check!(variable_indicator_char, atom!("variable_indicator")); - method_check!(is_whitespace, atom!("whitespace")); - } - &SystemClauseType::CheckCutPoint => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let old_b = cell_as_fixnum!(addr).get_num() as usize; - - let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b; - let prev_b = self.machine_st.stack.index_or_frame(prev_b).prelude.b; - - if prev_b > old_b { - self.machine_st.fail = true; - } - } - &SystemClauseType::CopyTermWithoutAttrVars => { - self.machine_st.copy_term(AttrVarPolicy::StripAttributes); - } - &SystemClauseType::FetchGlobalVar => { - let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); - let addr = self.machine_st.registers[2]; + debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar); - match self.indices.global_variables.get_mut(&key) { - Some((ref ball, ref mut loc)) => match loc { - Some(value_loc) => { - unify_fn!(self.machine_st, addr, *value_loc); - } - None if !ball.stub.is_empty() => { - let h = self.machine_st.heap.len(); - let stub = ball.copy_and_align(h); + let h = addr.get_value(); + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1])); - self.machine_st.heap.extend(stub.into_iter()); + debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis); - unify_fn!(self.machine_st, addr, heap_loc_as_cell!(h)); + let l = addr.get_value(); + let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l + 1))); - if !self.machine_st.fail { - *loc = Some(heap_loc_as_cell!(h)); - self.machine_st.trail(TrailRef::BlackboardEntry(key)); - } - } - _ => self.machine_st.fail = true, - }, - None => self.machine_st.fail = true, - }; - } - &SystemClauseType::PutCode => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("put_code"), - 2, - )?; + let tail = if tail.is_var() { + self.machine_st.heap[h] = heap_loc_as_cell!(h); + self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h))); - self.machine_st.check_stream_properties( - stream, - StreamType::Text, - None, - atom!("put_code"), - 2, - )?; + heap_loc_as_cell!(h + 1) + } else { + tail + }; - let stub_gen = || functor_stub(atom!("put_code"), 2); + self.machine_st.heap[h + 1] = tail; + self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l)); + } - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + #[inline(always)] + pub(crate) fn dynamic_module_resolution( + &mut self, + narity: usize, + ) -> Result<(Atom, PredicateKey), MachineStub> { + let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1 + narity] + ))); + + let addr = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2 + narity] + )); + + read_heap_cell!(addr, + (HeapCellValueTag::Str, a) => { + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[a]) + .get_name_and_arity(); - if addr.is_var() { - let err = self.machine_st.instantiation_error(); - return Err(self.machine_st.error_form(err, stub_gen())); - } else { - match Number::try_from(addr) { - Ok(Number::Integer(n)) => { - if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - } - Ok(Number::Fixnum(n)) => { - let n = n.get_num(); - if let Some(c) = u32::try_from(n).ok().and_then(|c| char::from_u32(c)) { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - } - _ => { - let err = self.machine_st.type_error(ValidType::Integer, addr); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } + for i in (arity + 1..arity + narity + 1).rev() { + self.machine_st.registers[i] = self.machine_st.registers[i - arity]; + } - let err = self.machine_st.representation_error(RepFlag::CharacterCode); - return Err(self.machine_st.error_form(err, stub_gen())); + for i in 1..arity + 1 { + self.machine_st.registers[i] = self.machine_st.heap[a + i]; } - } - &SystemClauseType::PutChar => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("put_char"), - 2, - )?; - self.machine_st.check_stream_properties( - stream, - StreamType::Text, - None, - atom!("put_char"), - 2, - )?; + Ok((module_name, (name, arity + narity))) + } + (HeapCellValueTag::Atom, (name, _arity)) => { + Ok((module_name, (name, narity))) + } + (HeapCellValueTag::Char, c) => { + let key = (self.machine_st.atom_tbl.build_with(&c.to_string()), narity); + Ok((module_name, key)) + } + _ => { + let stub = functor_stub(atom!("(:)"), 2); + let err = self.machine_st.type_error(ValidType::Callable, addr); - let stub_gen = || functor_stub(atom!("put_char"), 2); - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + Err(self.machine_st.error_form(err, stub)) + } + ) + } - if addr.is_var() { - let err = self.machine_st.instantiation_error(); - return Err(self.machine_st.error_form(err, stub_gen())); - } else { - read_heap_cell!(addr, - (HeapCellValueTag::Atom, (name, _arity)) => { - let c = name.as_char().unwrap(); - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - (HeapCellValueTag::Char, c) => { - write!(&mut stream, "{}", c).unwrap(); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - _ => { - } - ); + #[inline(always)] + pub(crate) fn enqueue_attributed_var(&mut self) { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let err = self.machine_st.type_error(ValidType::Character, addr); - return Err(self.machine_st.error_form(err, stub_gen())); - } + read_heap_cell!(addr, + (HeapCellValueTag::AttrVar, h) => { + self.machine_st.attr_var_init.attr_var_queue.push(h); + } + _ => { } - &SystemClauseType::PutChars => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("$put_chars"), - 2, - )?; + ); + } - let mut bytes = Vec::new(); - let stub_gen = || functor_stub(atom!("$put_chars"), 2); + #[inline(always)] + pub(crate) fn get_next_db_ref(&mut self) { + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { - if stream.options().stream_type() == StreamType::Binary { - for c in string.as_str().chars() { - if c as u32 > 255 { - let err = self.machine_st.type_error(ValidType::Byte, char_as_cell!(c)); - return Err(self.machine_st.error_form(err, stub_gen())); - } + if let Some(name_var) = a1.as_var() { + let mut iter = self.indices.code_dir.iter(); - bytes.push(c as u8); - } - } else { - bytes = string.as_str().bytes().collect(); - } + while let Some(((name, arity), _)) = iter.next() { + let arity_var = self.machine_st.deref(self.machine_st.registers[2]) + .as_var().unwrap(); - match stream.write_all(&bytes) { - Ok(_) => { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - _ => { - let addr = stream_as_cell!(stream); - let err = self.machine_st.existence_error(ExistenceError::Stream(addr)); + self.machine_st.bind(name_var, atom_as_cell!(name)); + self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64))); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - } else { + return; + } + + self.machine_st.fail = true; + } else if a1.get_tag() == HeapCellValueTag::Atom { + let name = cell_as_atom!(a1); + let arity = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2]) + )).get_num() as usize; + + match self.machine_st.get_next_db_ref(&self.indices, &DBRef::NamedPred(name, arity)) { + Some(DBRef::NamedPred(name, arity)) => { + let atom_var = self.machine_st.deref(self.machine_st.registers[3]) + .as_var().unwrap(); + + let arity_var = self.machine_st.deref(self.machine_st.registers[4]) + .as_var().unwrap(); + + self.machine_st.bind(atom_var, atom_as_cell!(name)); + self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64))); + } + Some(DBRef::Op(..)) | None => { self.machine_st.fail = true; } } - &SystemClauseType::PutByte => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("put_byte"), - 2, - )?; + } else { + self.machine_st.fail = true; + } + } - self.machine_st.check_stream_properties( - stream, - StreamType::Binary, - None, - atom!("put_byte"), - 2, - )?; + #[inline(always)] + pub(crate) fn get_next_op_db_ref(&mut self) { + let prec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + if let Some(prec_var) = prec.as_var() { + let spec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + let op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + let orig_op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[7])); + + let spec_num = if spec.get_tag() == HeapCellValueTag::Atom { + (match cell_as_atom!(spec) { + atom!("xfx") => XFX, + atom!("xfy") => XFY, + atom!("yfx") => YFX, + atom!("fx") => FX, + atom!("fy") => FY, + atom!("xf") => XF, + _ => unreachable!(), + }) as u8 + } else { + 0 + }; - let stub_gen = || functor_stub(atom!("put_byte"), 2); - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + let unossified_op_dir = if !orig_op.is_var() { + let orig_op = cell_as_atom!(orig_op); - if addr.is_var() { - let err = self.machine_st.instantiation_error(); - return Err(self.machine_st.error_form(err, stub_gen())); - } else { - match Number::try_from(addr) { - Ok(Number::Integer(n)) => { - if let Some(nb) = n.to_u8() { - match stream.write(&mut [nb]) { - Ok(1) => { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - _ => { - let err = self.machine_st.existence_error( - ExistenceError::Stream(stream_as_cell!(stream)) - ); + let op_descs = [ + self.indices.op_dir.get_key_value(&(orig_op, Fixity::In)), + self.indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)), + self.indices.op_dir.get_key_value(&(orig_op, Fixity::Post)), + ]; - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - } - } - Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n.get_num()) { - match stream.write(&mut [nb]) { - Ok(1) => { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - _ => { - let err = self.machine_st.existence_error( - ExistenceError::Stream(stream_as_cell!(stream)) - ); + let number_of_keys = op_descs[0].is_some() as usize + + op_descs[1].is_some() as usize + + op_descs[2].is_some() as usize; - return Err(self.machine_st.error_form(err, stub_gen())); - } - } + match number_of_keys { + 0 => { + self.machine_st.fail = true; + return; + } + 1 => { + for op_desc in op_descs { + if let Some((_, op_desc)) = op_desc { + let (op_prec, op_spec) = + (op_desc.get_prec(), op_desc.get_spec()); + + let op_spec = match op_spec as u32 { + XFX => atom!("xfx"), + XFY => atom!("xfy"), + YFX => atom!("yfx"), + FX => atom!("fx"), + FY => atom!("fy"), + XF => atom!("xf"), + YF => atom!("yf"), + _ => unreachable!(), + }; + + let op_prec = Fixnum::build_with(op_prec as i64); + + self.machine_st.unify_fixnum(op_prec, prec); + self.machine_st.unify_atom(op_spec, spec); } } - _ => { - } - } - } - let err = self.machine_st.type_error(ValidType::Byte, self.machine_st.registers[2]); - return Err(self.machine_st.error_form(err, stub_gen())); - } - &SystemClauseType::GetByte => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("get_byte"), - 2, - )?; - - self.machine_st.check_stream_properties( - stream, - StreamType::Binary, - Some(self.machine_st.registers[2]), - atom!("get_byte"), - 2, - )?; - - if stream.past_end_of_stream() { - self.machine_st.eof_action(self.machine_st.registers[2], stream, atom!("get_byte"), 2)?; - - if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } else if self.machine_st.fail { - return Ok(()); + return; } - } - - let stub_gen = || functor_stub(atom!("get_byte"), 2); - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + _ => { + let mut unossified_op_dir = OssifiedOpDir::new(); - let addr = if addr.is_var() { - addr - } else { - match Number::try_from(addr) { - Ok(Number::Integer(n)) => { - if let Some(nb) = n.to_u8() { - fixnum_as_cell!(Fixnum::build_with(nb as i64)) - } else { - let err = self.machine_st.type_error(ValidType::InByte, addr); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - Ok(Number::Fixnum(n)) => { - if let Ok(nb) = u8::try_from(n.get_num()) { - fixnum_as_cell!(Fixnum::build_with(nb as i64)) - } else { - let err = self.machine_st.type_error(ValidType::InByte, addr); - return Err(self.machine_st.error_form(err, stub_gen())); + for op_desc in op_descs { + if let Some((key, op_desc)) = op_desc { + let (prec, spec) = (op_desc.get_prec(), op_desc.get_spec()); + unossified_op_dir.insert(*key, (prec as usize, spec as Specifier)); } } - _ => { - let err = self.machine_st.type_error(ValidType::InByte, addr); - return Err(self.machine_st.error_form(err, stub_gen())); - } + + unossified_op_dir } - }; + } + } else { + let mut unossified_op_dir = OssifiedOpDir::new(); - loop { - let mut b = [0u8; 1]; + unossified_op_dir.extend(self.indices.op_dir.iter().filter_map( + |(key, op_desc)| { + let (other_prec, other_spec) = (op_desc.get_prec(), op_desc.get_spec()); + let name = key.0; - match stream.read(&mut b) { - Ok(1) => { - self.machine_st.unify_fixnum(Fixnum::build_with(b[0] as i64), addr); - break; - } - _ => { - stream.set_past_end_of_stream(true); - self.machine_st.unify_fixnum(Fixnum::build_with(-1), self.machine_st.registers[2]); - return return_from_clause!(self.machine_st.last_call, self.machine_st); + if other_prec == 0 { + return None; } - } - } - } - &SystemClauseType::GetChar => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("get_char"), - 2, - )?; - self.machine_st.check_stream_properties( - stream, - StreamType::Text, - Some(self.machine_st.registers[2]), - atom!("get_char"), - 2, - )?; + if (!orig_op.is_var() && atom_as_cell!(name) != orig_op) || + (!spec.is_var() && other_spec != spec_num) { + return None; + } - if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } else if self.machine_st.fail { - return Ok(()); + Some((*key, (other_prec as usize, other_spec as Specifier))) } - } - - if stream.at_end_of_stream() { - let end_of_file = atom!("end_of_file"); - stream.set_past_end_of_stream(true); + )); - self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + unossified_op_dir + }; - let stub_gen = || functor_stub(atom!("get_char"), 2); - let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_char"), 2)?; + let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.machine_st.arena); - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + match ossified_op_dir.iter().next() { + Some(((op_atom, _), (op_prec, op_spec))) => { + let ossified_op_dir_var = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[4] + )).as_var().unwrap(); - let addr = if addr.is_var() { - addr - } else { - read_heap_cell!(addr, - (HeapCellValueTag::Atom, (atom, _arity)) => { - char_as_cell!(atom.as_char().unwrap()) - } - (HeapCellValueTag::Char) => { - addr - } + let spec_atom = match *op_spec { + FX => atom!("fx"), + FY => atom!("fy"), + XF => atom!("xf"), + YF => atom!("yf"), + XFX => atom!("xfx"), + XFY => atom!("xfy"), + YFX => atom!("yfx"), _ => { - let err = self.machine_st.type_error(ValidType::InCharacter, addr); - return Err(self.machine_st.error_form(err, stub_gen())); + self.machine_st.fail = true; + return; } - ) - }; + }; + + let spec_var = spec.as_var().unwrap(); + let op_var = op.as_var().unwrap(); - loop { - let result = iter.read_char(); + self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64))); + self.machine_st.bind(spec_var, atom_as_cell!(spec_atom)); + self.machine_st.bind(op_var, atom_as_cell!(op_atom)); + self.machine_st.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir)); + } + None => { + self.machine_st.fail = true; + return; + } + } + } else { + let spec = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); + let op_atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]))); + let ossified_op_dir_cell = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4])); - match result { - Some(Ok(c)) => { - self.machine_st.unify_char(c, addr); + if ossified_op_dir_cell.is_var() { + self.machine_st.fail = true; + return; + } - if self.machine_st.fail { - return Ok(()); - } + let ossified_op_dir = cell_as_ossified_op_dir!( + ossified_op_dir_cell + ); - break; - } + let fixity = match spec { + atom!("xfy") | atom!("yfx") | atom!("xfx") => Fixity::In, + atom!("xf") | atom!("yf") => Fixity::Post, + atom!("fx") | atom!("fy") => Fixity::Pre, + _ => { + self.machine_st.fail = true; + return; + } + }; + + match self.machine_st.get_next_db_ref( + &self.indices, + &DBRef::Op(op_atom, fixity, ossified_op_dir), + ) { + Some(DBRef::Op(op_atom, fixity, ossified_op_dir)) => { + let (prec, spec) = ossified_op_dir.get(&(op_atom, fixity)).unwrap(); + + let prec_var = self.machine_st.deref(self.machine_st.registers[5]) + .as_var().unwrap(); + + let spec_var = self.machine_st.deref(self.machine_st.registers[6]) + .as_var().unwrap(); + + let op_var = self.machine_st.deref(self.machine_st.registers[7]) + .as_var().unwrap(); + + let spec_atom = match *spec { + FX => atom!("fx"), + FY => atom!("fy"), + XF => atom!("xf"), + YF => atom!("yf"), + XFX => atom!("xfx"), + XFY => atom!("xfy"), + YFX => atom!("yfx"), _ => { - self.machine_st.eof_action( - self.machine_st.registers[2], - stream, - atom!("get_char"), - 2, - )?; - - if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } else if self.machine_st.fail { - return Ok(()); - } + self.machine_st.fail = true; + return; } - } + }; + + self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64))); + self.machine_st.bind(spec_var, atom_as_cell!(spec_atom)); + self.machine_st.bind(op_var, atom_as_cell!(op_atom)); + } + Some(DBRef::NamedPred(..)) | None => { + self.machine_st.fail = true; } } - &SystemClauseType::GetNChars => { - let stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("get_n_chars"), - 3, - )?; + } + } - let num = match Number::try_from(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))) { - Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), - Ok(Number::Integer(n)) => match n.to_usize() { - Some(u) => u, - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }, - _ => { - unreachable!() - } - }; + #[inline(always)] + pub(crate) fn maybe(&mut self) { + let result = { + let mut rand = RANDOM_STATE.borrow_mut(); + rand.bits(1) == 0 + }; - let mut string = String::new(); + self.machine_st.fail = result; + } - if stream.options().stream_type() == StreamType::Binary { - let mut buf = vec![]; - let mut chunk = stream.take(num as u64); + #[inline(always)] + pub(crate) fn cpu_now(&mut self) { + let secs = ProcessTime::now().as_duration().as_secs_f64(); + let secs = arena_alloc!(OrderedFloat(secs), &mut self.machine_st.arena); - chunk.read_to_end(&mut buf).ok(); + self.machine_st.unify_f64(secs, self.machine_st.registers[1]); + } - for c in buf { - string.push(c as char); - } - } else { - let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_n_chars"), 2)?; + #[inline(always)] + pub(crate) fn current_time(&mut self) { + let timestamp = self.systemtime_to_timestamp(SystemTime::now()); + self.machine_st.unify_atom(timestamp, self.machine_st.registers[1]); + } - for _ in 0..num { - let result = iter.read_char(); + #[inline(always)] + pub(crate) fn open(&mut self) -> CallResult { + let alias = self.machine_st.registers[4]; + let eof_action = self.machine_st.registers[5]; + let reposition = self.machine_st.registers[6]; + let stream_type = self.machine_st.registers[7]; - match result { - Some(Ok(c)) => { - string.push(c); - } - _ => { - break; - } - } - } - }; + let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); + let src_sink = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let atom = self.machine_st.atom_tbl.build_with(&string); - self.machine_st.unify_complete_string(atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]))); - } - &SystemClauseType::GetCode => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("get_code"), - 2, - )?; - - self.machine_st.check_stream_properties( - stream, - StreamType::Text, - Some(self.machine_st.registers[2]), - atom!("get_code"), - 2, - )?; - - if stream.past_end_of_stream() { - if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } else if self.machine_st.fail { - return Ok(()); - } + if let Some(str_like) = self.machine_st.value_to_str_like(src_sink) { + let file_spec = match str_like { + AtomOrString::Atom(atom) => { + atom } - - if stream.at_end_of_stream() { - let end_of_file = atom!("end_of_file"); - - stream.set_past_end_of_stream(true); - - self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); - return return_from_clause!(self.machine_st.last_call, self.machine_st); + AtomOrString::String(string) => { + self.machine_st.atom_tbl.build_with(&string) } + }; - let stub_gen = || functor_stub(atom!("get_code"), 2); - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + let mut stream = self.machine_st.stream_from_file_spec( + file_spec, + &mut self.indices, + &options, + )?; - let addr = if addr.is_var() { - addr - } else { - match Number::try_from(addr) { - Ok(Number::Integer(n)) => { - let n = n - .to_u32() - .and_then(|n| std::char::from_u32(n)); - - if let Some(n) = n { - fixnum_as_cell!(Fixnum::build_with(n as i64)) - } else { - let err = self.machine_st.representation_error(RepFlag::InCharacterCode); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - Ok(Number::Fixnum(n)) => { - let nf = u32::try_from(n.get_num()) - .ok() - .and_then(|n| std::char::from_u32(n)); - - if nf.is_some() { - fixnum_as_cell!(n) - } else { - let err = self.machine_st.representation_error(RepFlag::InCharacterCode); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - _ => { - let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]); - return Err(self.machine_st.error_form(err, stub_gen())); - } - } - }; + *stream.options_mut() = options; + self.indices.streams.insert(stream); - let mut iter = self.machine_st.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?; + if let Some(alias) = stream.options().get_alias() { + self.indices.stream_aliases.insert(alias, stream); + } - loop { - let result = iter.read_char(); + let stream_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + self.machine_st.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream)); + } else { + let err = self.machine_st.domain_error(DomainErrorType::SourceSink, src_sink); + let stub = functor_stub(atom!("open"), 4); - match result { - Some(Ok(c)) => { - self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr); + return Err(self.machine_st.error_form(err, stub)); + } - if self.machine_st.fail { - return Ok(()); - } + Ok(()) + } - break; - } - _ => { - self.machine_st.eof_action( - self.machine_st.registers[2], - stream, - atom!("get_code"), - 2, - )?; - - if EOFAction::Reset != stream.options().eof_action() { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } else if self.machine_st.fail { - return Ok(()); - } - } - } - } - } - &SystemClauseType::FirstStream => { - let mut first_stream = None; - let mut null_streams = BTreeSet::new(); + #[inline(always)] + pub(crate) fn op_declaration(&mut self) -> CallResult { + let priority = self.machine_st.registers[1]; + let specifier = self.machine_st.registers[2]; + let op = self.machine_st.registers[3]; - for stream in self.indices.streams.iter().cloned() { - if !stream.is_null_stream() { - first_stream = Some(stream); - break; - } else { - null_streams.insert(stream); - } - } + let priority = self.machine_st.store(self.machine_st.deref(priority)); - self.indices.streams = self.indices.streams.sub(&null_streams); + let priority = match Number::try_from(priority) { + Ok(Number::Integer(n)) => n.to_u16().unwrap(), + Ok(Number::Fixnum(n)) => u16::try_from(n.get_num()).unwrap(), + _ => { + unreachable!(); + } + }; - if let Some(first_stream) = first_stream { - let stream = stream_as_cell!(first_stream); + let specifier = cell_as_atom_cell!(self.machine_st.store(self.machine_st.deref(specifier))) + .get_name(); - let var = self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[1] - )).as_var().unwrap(); + let op = read_heap_cell!(self.machine_st.store(self.machine_st.deref(op)), + (HeapCellValueTag::Char) => { + self.machine_st.atom_tbl.build_with(&op.to_string()) + } + (HeapCellValueTag::Atom, (name, _arity)) => { + name + } + _ => { + unreachable!() + } + ); - self.machine_st.bind(var, stream); + let result = to_op_decl(priority, specifier, op) + .map_err(SessionError::from) + .and_then(|mut op_decl| { + if op_decl.op_desc.get_prec() == 0 { + Ok(op_decl.remove(&mut self.indices.op_dir)) } else { - self.machine_st.fail = true; - return Ok(()); + let spec = get_op_desc( + op_decl.name, + &CompositeOpDir::new(&self.indices.op_dir, None), + ); + + op_decl.submit(spec, &mut self.indices.op_dir) } + }); + + match result { + Ok(()) => Ok(()), + Err(e) => { + // 8.14.3.3 l) + let err = self.machine_st.session_error(e); + let stub = functor_stub(atom!("op"), 3); + + Err(self.machine_st.error_form(err, stub)) } - &SystemClauseType::NextStream => { - let prev_stream = cell_as_stream!(self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[1] - ))); + } + } - let mut next_stream = None; - let mut null_streams = BTreeSet::new(); + #[inline(always)] + pub(crate) fn set_stream_options(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("open"), + 4, + )?; + + let alias = self.machine_st.registers[2]; + let eof_action = self.machine_st.registers[3]; + let reposition = self.machine_st.registers[4]; + let stream_type = self.machine_st.registers[5]; + + let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); + *stream.options_mut() = options; - for stream in self.indices - .streams - .range(prev_stream..) - .skip(1) - .cloned() - { - if !stream.is_null_stream() { - next_stream = Some(stream); - break; - } else { - null_streams.insert(stream); - } - } + Ok(()) + } - self.indices.streams = self.indices.streams.sub(&null_streams); + #[inline(always)] + pub(crate) fn truncate_if_no_lifted_heap_growth_diff(&mut self) { + self.machine_st.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h)) + } - if let Some(next_stream) = next_stream { - let var = self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[2] - )).as_var().unwrap(); + #[inline(always)] + pub(crate) fn truncate_if_no_lifted_heap_growth(&mut self) { + self.machine_st.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!()) + } + + #[inline(always)] + pub(crate) fn get_attributed_variable_list(&mut self) { + let attr_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let attr_var_list = read_heap_cell!(attr_var, + (HeapCellValueTag::AttrVar, h) => { + h + 1 + } + (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { + // create an AttrVar in the heap. + let h = self.machine_st.heap.len(); - let next_stream = stream_as_cell!(next_stream); + self.machine_st.heap.push(attr_var_as_cell!(h)); + self.machine_st.heap.push(heap_loc_as_cell!(h+1)); - self.machine_st.bind(var, next_stream); - } else { - self.machine_st.fail = true; - return Ok(()); - } + self.machine_st.bind(Ref::attr_var(h), attr_var); + h + 1 + } + _ => { + self.machine_st.fail = true; + return; } - &SystemClauseType::FlushOutput => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("flush_output"), - 1, - )?; + ); - if !stream.is_output_stream() { - let stub = functor_stub(atom!("flush_output"), 1); - let addr = stream_as_cell!(stream); // vec![HeapCellValue::Stream(stream)]; + let list_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + self.machine_st.bind(Ref::heap_cell(attr_var_list), list_addr); + } - let err = self.machine_st.permission_error( - Permission::OutputStream, - atom!("stream"), - addr, - ); + #[inline(always)] + pub(crate) fn get_attr_var_queue_delimiter(&mut self) { + let addr = self.machine_st.registers[1]; + let value = Fixnum::build_with(self.machine_st.attr_var_init.attr_var_queue.len() as i64); - return Err(self.machine_st.error_form(err, stub)); - } + self.machine_st.unify_fixnum(value, self.machine_st.store(self.machine_st.deref(addr))); + } - stream.flush().unwrap(); + #[inline(always)] + pub(crate) fn get_attr_var_queue_beyond(&mut self) { + let addr = self.machine_st.registers[1]; + let addr = self.machine_st.store(self.machine_st.deref(addr)); + + let b = match Number::try_from(addr) { + Ok(Number::Integer(n)) => n.to_usize(), + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), + _ => { + self.machine_st.fail = true; + return; } - &SystemClauseType::GetSingleChar => { - let ctrl_c = KeyEvent { - code: KeyCode::Char('c'), - modifiers: KeyModifiers::CONTROL, - }; + }; - let key = get_key(); + if let Some(b) = b { + let iter = self.machine_st.gather_attr_vars_created_since(b); - if key == ctrl_c { - let stub = functor_stub(atom!("get_single_char"), 1); - let err = self.machine_st.interrupt_error(); - let err = self.machine_st.error_form(err, stub); + let var_list_addr = heap_loc_as_cell!( + iter_to_heap_list(&mut self.machine_st.heap, iter) + ); - return Err(err); - } + let list_addr = self.machine_st.registers[2]; + unify!(self.machine_st, var_list_addr, list_addr); + } + } - let c = match key.code { - KeyCode::Enter => '\n', - KeyCode::Tab => '\t', - KeyCode::Char(c) => c, - _ => unreachable!(), - }; + #[inline(always)] + pub(crate) fn get_continuation_chunk(&mut self) { + let e = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let e = cell_as_fixnum!(e).get_num() as usize; - self.machine_st.unify_char(c, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); - } - &SystemClauseType::HeadIsDynamic => { - let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); + let p_functor = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2] + )); - let (name, arity) = read_heap_cell!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), - (HeapCellValueTag::Str, s) => { - cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity() - } - (HeapCellValueTag::Atom, (name, _arity)) => { - (name, 0) - } - _ => { - unreachable!() - } - ); + let p = to_local_code_ptr(&self.machine_st.heap, p_functor).unwrap(); - self.machine_st.fail = !self.indices.is_dynamic_predicate(module_name, (name, arity)); - } - &SystemClauseType::Close => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("close"), - 2, - )?; + let num_cells = *self.code[p].perm_vars_mut().unwrap(); + let mut addrs = vec![]; - if !stream.is_input_stream() { - stream.flush().unwrap(); // 8.11.6.1b) - } + for idx in 1..num_cells + 1 { + addrs.push(self.machine_st.stack[stack_loc!(AndFrame, e, idx)]); + } - self.indices.streams.remove(&stream); + let chunk = str_loc_as_cell!(self.machine_st.heap.len()); - if stream == self.user_input { - self.user_input = self.indices - .stream_aliases - .get(&atom!("user_input")) - .cloned() - .unwrap(); + self.machine_st.heap.push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); + self.machine_st.heap.push(p_functor); + self.machine_st.heap.extend(addrs); - self.indices.streams.insert(self.user_input); - } else if stream == self.user_output { - self.user_output = self.indices - .stream_aliases - .get(&atom!("user_output")) - .cloned() - .unwrap(); + unify!(self.machine_st, self.machine_st.registers[3], chunk); + } - self.indices.streams.insert(self.user_output); - } + #[inline(always)] + pub(crate) fn get_lifted_heap_from_offset_diff(&mut self) { + let lh_offset = self.machine_st.registers[1]; + let lh_offset = cell_as_fixnum!( + self.machine_st.store(self.machine_st.deref(lh_offset)) + ).get_num() as usize; - if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() { - let close_result = stream.close(); + if lh_offset >= self.machine_st.lifted_heap.len() { + let solutions = self.machine_st.registers[2]; + let diff = self.machine_st.registers[3]; - if let Some(alias) = stream.options().get_alias() { - self.indices.stream_aliases.remove(&alias); - } - if let Err(_) = close_result { - let stub = functor_stub(atom!("close"), 1); - let addr = stream_as_cell!(stream); - let err = self.machine_st.existence_error(ExistenceError::Stream(addr)); + unify_fn!(self.machine_st, solutions, diff); + } else { + let h = self.machine_st.heap.len(); + let mut last_index = h; - return Err(self.machine_st.error_form(err, stub)); - } - } + for value in self.machine_st.lifted_heap[lh_offset ..].iter().cloned() { + last_index = self.machine_st.heap.len(); + self.machine_st.heap.push(value + h); } - &SystemClauseType::CopyToLiftedHeap => { - let lh_offset = cell_as_fixnum!( - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) - ).get_num() as usize; - let copy_target = self.machine_st.registers[2]; + if last_index < self.machine_st.heap.len() { + let diff = self.machine_st.registers[3]; + unify_fn!(self.machine_st, diff, self.machine_st.heap[last_index]); + } - let old_threshold = self.machine_st.copy_findall_solution(lh_offset, copy_target); - let new_threshold = self.machine_st.lifted_heap.len() - lh_offset; + self.machine_st.lifted_heap.truncate(lh_offset); - self.machine_st.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold); + let solutions = self.machine_st.registers[2]; + unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions); + } + } - for addr in self.machine_st.lifted_heap[old_threshold + 1 ..].iter_mut() { - *addr -= self.machine_st.heap.len() + lh_offset; - } - }, - &SystemClauseType::DeleteAttribute => { - let ls0 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + #[inline(always)] + pub(crate) fn get_lifted_heap_from_offset(&mut self) { + let lh_offset = self.machine_st.registers[1]; + let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref( + lh_offset + ))).get_num() as usize; + + if lh_offset >= self.machine_st.lifted_heap.len() { + let solutions = self.machine_st.registers[2]; + unify_fn!(self.machine_st, solutions, empty_list_as_cell!()); + } else { + let h = self.machine_st.heap.len(); - if let HeapCellValueTag::Lis = ls0.get_tag() { - let l1 = ls0.get_value(); - let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1))); + for addr in self.machine_st.lifted_heap[lh_offset..].iter().cloned() { + self.machine_st.heap.push(addr + h); + } - if let HeapCellValueTag::Lis = ls1.get_tag() { - let l2 = ls1.get_value(); + self.machine_st.lifted_heap.truncate(lh_offset); - let old_addr = self.machine_st.heap[l1+1]; - let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1))); + let solutions = self.machine_st.registers[2]; + unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions); + } + } - let tail = if tail.is_var() { - heap_loc_as_cell!(l1 + 1) - } else { - tail - }; + #[inline(always)] + pub(crate) fn get_double_quotes(&mut self) { + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + self.machine_st.unify_atom( + match self.machine_st.flags.double_quotes { + DoubleQuotes::Chars => atom!("chars"), + DoubleQuotes::Atom => atom!("atom"), + DoubleQuotes::Codes => atom!("codes"), + }, + a1, + ); + } - let trail_ref = read_heap_cell!(old_addr, - (HeapCellValueTag::Var, h) => { - TrailRef::AttrVarHeapLink(h) - } - (HeapCellValueTag::Lis, l) => { - TrailRef::AttrVarListLink(l1 + 1, l) - } - _ => { - unreachable!() - } - ); + #[inline(always)] + pub(crate) fn get_scc_cleaner(&mut self) { + let dest = self.machine_st.registers[1]; - self.machine_st.heap[l1 + 1] = tail; - self.machine_st.trail(trail_ref); - } + if let Some((addr, b_cutoff, prev_b)) = self.machine_st.cont_pts.pop() { + let b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b; + + if b <= b_cutoff { + self.machine_st.block = prev_b; + + if let Some(r) = dest.as_var() { + self.machine_st.bind(r, addr); + return; } + } else { + self.machine_st.cont_pts.push((addr, b_cutoff, prev_b)); } - &SystemClauseType::DeleteHeadAttribute => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + } - debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar); + self.machine_st.fail = true; + } - let h = addr.get_value(); - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1])); + #[inline(always)] + pub(crate) fn halt(&mut self) { + let code = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + let code = match Number::try_from(code) { + Ok(Number::Fixnum(n)) => i32::try_from(n.get_num()).unwrap(), + Ok(Number::Integer(n)) => n.to_i32().unwrap(), + Ok(Number::Rational(r)) => { + // n has already been confirmed as an integer, and + // internally, Rational is assumed reduced, so its + // denominator must be 1. + r.numer().to_i32().unwrap() + } + _ => { + unreachable!() + } + }; - debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis); + std::process::exit(code); + } - let l = addr.get_value(); - let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l + 1))); + #[inline(always)] + pub(crate) fn install_scc_cleaner(&mut self) { + let addr = self.machine_st.registers[1]; + let b = self.machine_st.b; + let prev_block = self.machine_st.block; - let tail = if tail.is_var() { - self.machine_st.heap[h] = heap_loc_as_cell!(h); - self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h))); + self.machine_st.run_cleaners_fn = Machine::run_cleaners; - heap_loc_as_cell!(h + 1) - } else { - tail - }; + self.machine_st.install_new_block(self.machine_st.registers[2]); + self.machine_st.cont_pts.push((addr, b, prev_block)); + } + + #[inline(always)] + pub(crate) fn install_inference_counter(&mut self) -> CallResult { + // A1 = B, A2 = L + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + let n = match Number::try_from(a2) { + Ok(Number::Fixnum(bp)) => bp.get_num() as usize, + Ok(Number::Integer(n)) => n.to_usize().unwrap(), + _ => { + let stub = functor_stub( + atom!("call_with_inference_limit"), + 3, + ); - self.machine_st.heap[h + 1] = tail; - self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l)); + let err = self.machine_st.type_error(ValidType::Integer, a2); + return Err(self.machine_st.error_form(err, stub)); } - &SystemClauseType::DynamicModuleResolution(narity) => { - let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[1 + narity] - ))); + }; - let addr = self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[2 + narity] - )); + let bp = cell_as_fixnum!(a1).get_num() as usize; + let count = self.machine_st.cwil.add_limit(n, bp); + let count = arena_alloc!(count.clone(), &mut self.machine_st.arena); - read_heap_cell!(addr, - (HeapCellValueTag::Str, a) => { - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[a]) - .get_name_and_arity(); + self.machine_st.increment_call_count_fn = MachineState::increment_call_count; - for i in (arity + 1..arity + narity + 1).rev() { - self.machine_st.registers[i] = self.machine_st.registers[i - arity]; - } + let a3 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + self.machine_st.unify_big_int(count, a3); - for i in 1..arity + 1 { - self.machine_st.registers[i] = self.machine_st.heap[a + i]; - } + Ok(()) + } - return self.call_clause_type(module_name, (name, arity + narity)); - } - (HeapCellValueTag::Atom, (name, _arity)) => { - return self.call_clause_type(module_name, (name, narity)); - } - (HeapCellValueTag::Char, c) => { - let key = (self.machine_st.atom_tbl.build_with(&c.to_string()), narity); - return self.call_clause_type(module_name, key); - } - _ => { - let stub = functor_stub(atom!("(:)"), 2); - let err = self.machine_st.type_error(ValidType::Callable, addr); + #[inline(always)] + pub(crate) fn module_exists(&mut self) { + let module = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let module_name = cell_as_atom!(module); - return Err(self.machine_st.error_form(err, stub)); + self.machine_st.fail = !self.indices.modules.contains_key(&module_name); + } + + #[inline(always)] + pub(crate) fn no_such_predicate(&mut self) -> CallResult { + let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1] + ))); + + let head = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + self.machine_st.fail = read_heap_cell!(head, + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) + .get_name_and_arity(); + + let ct = ClauseType::from(name, arity); + + if ct.is_inlined() || ct.is_builtin() { + true + } else { + let index = self.indices.get_predicate_code_index( + name, + arity, + module_name, + ) + .map(|index| index.get()) + .unwrap_or(IndexPtr::DynamicUndefined); + + match index { + IndexPtr::DynamicUndefined | IndexPtr::Undefined => false, + _ => true, } - ); + } } - &SystemClauseType::EnqueueAttributedVar => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); - read_heap_cell!(addr, - (HeapCellValueTag::AttrVar, h) => { - self.machine_st.attr_var_init.attr_var_queue.push(h); - } - _ => { + let ct = ClauseType::from(name, 0); + + if ct.is_inlined() || ct.is_builtin() { + true + } else { + let index = self.indices.get_predicate_code_index( + name, + 0, + module_name, + ) + .map(|index| index.get()) + .unwrap_or(IndexPtr::DynamicUndefined); + + match index { + IndexPtr::DynamicUndefined => false, + _ => true, } - ); + } } - &SystemClauseType::GetNextDBRef => { - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + _ => { + let err = self.machine_st.type_error(ValidType::Callable, head); + let stub = functor_stub(atom!("clause"), 2); - if let Some(name_var) = a1.as_var() { - let mut iter = self.indices.code_dir.iter(); + return Err(self.machine_st.error_form(err, stub)); + } + ); - while let Some(((name, arity), _)) = iter.next() { - if SystemClauseType::from(*name, *arity).is_some() { - continue; - } + Ok(()) + } + #[inline(always)] + pub(crate) fn redo_attr_var_binding(&mut self) { + let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - let arity_var = self.machine_st.deref(self.machine_st.registers[2]) - .as_var().unwrap(); + debug_assert_eq!(HeapCellValueTag::AttrVar, var.get_tag()); + self.machine_st.heap[var.get_value()] = value; + } - self.machine_st.bind(name_var, atom_as_cell!(name)); - self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64))); + #[inline(always)] + pub(super) fn restore_instr_at_verify_attr_interrupt(&mut self) { + match &self.code[VERIFY_ATTR_INTERRUPT_LOC] { + &Instruction::VerifyAttrInterrupt => {} + _ => { + let instr = mem::replace( + &mut self.code[VERIFY_ATTR_INTERRUPT_LOC], + Instruction::VerifyAttrInterrupt, + ); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + self.code[self.machine_st.attr_var_init.cp] = instr; + } + } + } - self.machine_st.fail = true; - } else if a1.get_tag() == HeapCellValueTag::Atom { - let name = cell_as_atom!(a1); - let arity = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))) - .get_num() as usize; + #[inline(always)] + pub(crate) fn reset_attr_var_state(&mut self) { // 1344! That's the value of self.b we need to pop this. + self.restore_instr_at_verify_attr_interrupt(); + self.machine_st.attr_var_init.reset(); + } + + #[inline(always)] + pub(crate) fn remove_call_policy_check(&mut self) { + let bp = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1] + ))).get_num() as usize; + + if bp == self.machine_st.b && self.machine_st.cwil.is_empty() { + self.machine_st.cwil.reset(); + self.machine_st.increment_call_count_fn = |_| { Ok(()) }; + } + } - match self.machine_st.get_next_db_ref(&self.indices, &DBRef::NamedPred(name, arity)) { - Some(DBRef::NamedPred(name, arity)) => { - let atom_var = self.machine_st.deref(self.machine_st.registers[3]) - .as_var().unwrap(); + #[inline(always)] + pub(crate) fn remove_inference_counter(&mut self) { + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let bp = cell_as_fixnum!(a1).get_num() as usize; - let arity_var = self.machine_st.deref(self.machine_st.registers[4]) - .as_var().unwrap(); + let count = self.machine_st.cwil.remove_limit(bp).clone(); + let count = arena_alloc!(count.clone(), &mut self.machine_st.arena); - self.machine_st.bind(atom_var, atom_as_cell!(name)); - self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64))); - } - Some(DBRef::Op(..)) | None => { - self.machine_st.fail = true; - } - } - } else { - self.machine_st.fail = true; - return Ok(()); - } - } - &SystemClauseType::GetNextOpDBRef => { - let prec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - - if let Some(prec_var) = prec.as_var() { - let spec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - let op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); - let orig_op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[7])); - - let spec_num = if spec.get_tag() == HeapCellValueTag::Atom { - (match cell_as_atom!(spec) { - atom!("xfx") => XFX, - atom!("xfy") => XFY, - atom!("yfx") => YFX, - atom!("fx") => FX, - atom!("fy") => FY, - atom!("xf") => XF, - _ => unreachable!(), - }) as u8 - } else { - 0 - }; + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + self.machine_st.unify_big_int(count, a2); + } - let unossified_op_dir = if !orig_op.is_var() { - let orig_op = cell_as_atom!(orig_op); + #[inline(always)] + pub(crate) fn return_from_verify_attr(&mut self) { + let e = self.machine_st.e; + let frame_len = self.machine_st.stack.index_and_frame(e).prelude.univ_prelude.num_cells; - let op_descs = [ - self.indices.op_dir.get_key_value(&(orig_op, Fixity::In)), - self.indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)), - self.indices.op_dir.get_key_value(&(orig_op, Fixity::Post)), - ]; + for i in 1..frame_len - 2 { + self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)]; + } - let number_of_keys = op_descs[0].is_some() as usize + - op_descs[1].is_some() as usize + - op_descs[2].is_some() as usize; + self.machine_st.b0 = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 2)]) + .get_num() as usize; - match number_of_keys { - 0 => { - self.machine_st.fail = true; - return Ok(()); - } - 1 => { - for op_desc in op_descs { - if let Some((_, op_desc)) = op_desc { - let (op_prec, op_spec) = - (op_desc.get_prec(), op_desc.get_spec()); - - let op_spec = match op_spec as u32 { - XFX => atom!("xfx"), - XFY => atom!("xfy"), - YFX => atom!("yfx"), - FX => atom!("fx"), - FY => atom!("fy"), - XF => atom!("xf"), - YF => atom!("yf"), - _ => unreachable!(), - }; - - let op_prec = Fixnum::build_with(op_prec as i64); - - self.machine_st.unify_fixnum(op_prec, prec); - self.machine_st.unify_atom(op_spec, spec); - } - } + self.machine_st.num_of_args = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)]) + .get_num() as usize; - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - _ => { - let mut unossified_op_dir = OssifiedOpDir::new(); + let p = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)]).get_num() as usize; - for op_desc in op_descs { - if let Some((key, op_desc)) = op_desc { - let (prec, spec) = (op_desc.get_prec(), op_desc.get_spec()); - unossified_op_dir.insert(*key, (prec as usize, spec as Specifier)); - } - } + self.machine_st.deallocate(); + self.machine_st.p = p; + } - unossified_op_dir - } - } - } else { - let mut unossified_op_dir = OssifiedOpDir::new(); + #[inline(always)] + pub(crate) fn restore_cut_policy(&mut self) { + if self.machine_st.cont_pts.is_empty() { + self.machine_st.run_cleaners_fn = |_| { false }; + } + } - unossified_op_dir.extend(self.indices.op_dir.iter().filter_map( - |(key, op_desc)| { - let (other_prec, other_spec) = (op_desc.get_prec(), op_desc.get_spec()); - let name = key.0; + #[inline(always)] + pub(crate) fn set_cut_point(&mut self, r: RegType) -> bool { + let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + self.machine_st.cut_body(cp); - if other_prec == 0 { - return None; - } + (self.machine_st.run_cleaners_fn)(self) + } - if (!orig_op.is_var() && atom_as_cell!(name) != orig_op) || - (!spec.is_var() && other_spec != spec_num) { - return None; - } + #[inline(always)] + pub(crate) fn set_cut_point_by_default(&mut self, r: RegType) { + let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); + self.machine_st.cut_body(cp); + } - Some((*key, (other_prec as usize, other_spec as Specifier))) - } - )); + #[inline(always)] + pub(crate) fn set_input(&mut self) -> CallResult { + let addr = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1] + )); + + let stream = self.machine_st.get_stream_or_alias( + addr, + &self.indices.stream_aliases, + atom!("set_input"), + 1, + )?; + + if !stream.is_input_stream() { + let stub = functor_stub(atom!("set_input"), 1); + let user_alias = atom_as_cell!(atom!("user")); + + let err = self.machine_st.permission_error( + Permission::InputStream, + atom!("stream"), + user_alias, + ); - unossified_op_dir - }; + return Err(self.machine_st.error_form(err, stub)); + } - let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.machine_st.arena); - - match ossified_op_dir.iter().next() { - Some(((op_atom, _), (op_prec, op_spec))) => { - let ossified_op_dir_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4])) - .as_var().unwrap(); - - let spec_atom = match *op_spec { - FX => atom!("fx"), - FY => atom!("fy"), - XF => atom!("xf"), - YF => atom!("yf"), - XFX => atom!("xfx"), - XFY => atom!("xfy"), - YFX => atom!("yfx"), - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }; + self.user_input = stream; + Ok(()) + } - let spec_var = spec.as_var().unwrap(); - let op_var = op.as_var().unwrap(); + #[inline(always)] + pub(crate) fn set_output(&mut self) -> CallResult { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let stream = self.machine_st.get_stream_or_alias( + addr, + &self.indices.stream_aliases, + atom!("set_output"), + 1, + )?; + + if !stream.is_output_stream() { + let stub = functor_stub(atom!("set_input"), 1); + + let user_alias = atom_as_cell!(atom!("user")); + let err = self.machine_st.permission_error( + Permission::OutputStream, + atom!("stream"), + user_alias, + ); - self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64))); - self.machine_st.bind(spec_var, atom_as_cell!(spec_atom)); - self.machine_st.bind(op_var, atom_as_cell!(op_atom)); - self.machine_st.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir)); - } - None => { - self.machine_st.fail = true; - return Ok(()); - } - } - } else { - let spec = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); - let op_atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]))); - let ossified_op_dir_cell = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4])); + return Err(self.machine_st.error_form(err, stub)); + } - if ossified_op_dir_cell.is_var() { - self.machine_st.fail = true; - return Ok(()); - } + self.user_output = stream; + Ok(()) + } - let ossified_op_dir = cell_as_ossified_op_dir!( - ossified_op_dir_cell - ); + #[inline(always)] + pub(crate) fn set_double_quotes(&mut self) { + let atom = cell_as_atom!(self.machine_st.registers[1]); - let fixity = match spec { - atom!("xfy") | atom!("yfx") | atom!("xfx") => Fixity::In, - atom!("xf") | atom!("yf") => Fixity::Post, - atom!("fx") | atom!("fy") => Fixity::Pre, - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }; + self.machine_st.flags.double_quotes = match atom { + atom!("atom") => DoubleQuotes::Atom, + atom!("chars") => DoubleQuotes::Chars, + atom!("codes") => DoubleQuotes::Codes, + _ => { + self.machine_st.fail = true; + return; + } + }; + } - match self.machine_st.get_next_db_ref( - &self.indices, - &DBRef::Op(op_atom, fixity, ossified_op_dir), - ) { - Some(DBRef::Op(op_atom, fixity, ossified_op_dir)) => { - let (prec, spec) = ossified_op_dir.get(&(op_atom, fixity)).unwrap(); - - let prec_var = self.machine_st.deref(self.machine_st.registers[5]) - .as_var().unwrap(); - - let spec_var = self.machine_st.deref(self.machine_st.registers[6]) - .as_var().unwrap(); - - let op_var = self.machine_st.deref(self.machine_st.registers[7]) - .as_var().unwrap(); - - let spec_atom = match *spec { - FX => atom!("fx"), - FY => atom!("fy"), - XF => atom!("xf"), - YF => atom!("yf"), - XFX => atom!("xfx"), - XFY => atom!("xfy"), - YFX => atom!("yfx"), - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }; + #[inline(always)] + pub(crate) fn inference_level(&mut self) { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64))); - self.machine_st.bind(spec_var, atom_as_cell!(spec_atom)); - self.machine_st.bind(op_var, atom_as_cell!(op_atom)); - } - Some(DBRef::NamedPred(..)) | None => { - self.machine_st.fail = true; - } - } - } - } - &SystemClauseType::Maybe => { - let result = { - let mut rand = RANDOM_STATE.borrow_mut(); - rand.bits(1) == 0 - }; + let bp = cell_as_fixnum!(a2).get_num() as usize; + let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b; - self.machine_st.fail = result; - } - &SystemClauseType::CpuNow => { - let secs = ProcessTime::now().as_duration().as_secs_f64(); - let secs = arena_alloc!(OrderedFloat(secs), &mut self.machine_st.arena); + if prev_b <= bp { + self.machine_st.unify_atom(atom!("!"), a1) + } else { + self.machine_st.unify_atom(atom!("true"), a1); + } + } - self.machine_st.unify_f64(secs, self.machine_st.registers[1]); - } - &SystemClauseType::CurrentTime => { - let timestamp = self.systemtime_to_timestamp(SystemTime::now()); - self.machine_st.unify_atom(timestamp, self.machine_st.registers[1]); - } - &SystemClauseType::Open => { - let alias = self.machine_st.registers[4]; - let eof_action = self.machine_st.registers[5]; - let reposition = self.machine_st.registers[6]; - let stream_type = self.machine_st.registers[7]; + #[inline(always)] + pub(crate) fn clean_up_block(&mut self) { + let nb = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let nb = cell_as_fixnum!(nb).get_num() as usize; - let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); - let src_sink = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let b = self.machine_st.b; - if let Some(str_like) = self.machine_st.value_to_str_like(src_sink) { - let file_spec = match str_like { - AtomOrString::Atom(atom) => { - atom - } - AtomOrString::String(string) => { - self.machine_st.atom_tbl.build_with(&string) - } - }; + if nb > 0 && self.machine_st.stack.index_or_frame(b).prelude.b == nb { + self.machine_st.b = self.machine_st.stack.index_or_frame(nb).prelude.b; + } + } - let mut stream = self.machine_st.stream_from_file_spec( - file_spec, - &mut self.indices, - &options, - )?; + #[inline(always)] + pub(crate) fn erase_ball(&mut self) { + self.machine_st.ball.reset(); + } - *stream.options_mut() = options; - self.indices.streams.insert(stream); + #[inline(always)] + pub(crate) fn get_ball(&mut self) { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let h = self.machine_st.heap.len(); - if let Some(alias) = stream.options().get_alias() { - self.indices.stream_aliases.insert(alias, stream); - } + if self.machine_st.ball.stub.len() > 0 { + let stub = self.machine_st.ball.copy_and_align(h); + self.machine_st.heap.extend(stub.into_iter()); + } else { + self.machine_st.fail = true; + return; + } - let stream_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); - self.machine_st.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream)); - } else { - let err = self.machine_st.domain_error(DomainErrorType::SourceSink, src_sink); - let stub = functor_stub(atom!("open"), 4); + match addr.as_var() { + Some(r) => self.machine_st.bind(r, self.machine_st.heap[h]), + _ => self.machine_st.fail = true, + }; + } - return Err(self.machine_st.error_form(err, stub)); - } - } - &SystemClauseType::OpDeclaration => { - let priority = self.machine_st.registers[1]; - let specifier = self.machine_st.registers[2]; - let op = self.machine_st.registers[3]; + #[inline(always)] + pub(crate) fn get_current_block(&mut self) { + let n = Fixnum::build_with(i64::try_from(self.machine_st.block).unwrap()); + self.machine_st.unify_fixnum(n, self.machine_st.registers[1]); + } - let priority = self.machine_st.store(self.machine_st.deref(priority)); + #[inline(always)] + pub(crate) fn get_b_value(&mut self) { + let n = Fixnum::build_with(i64::try_from(self.machine_st.b).unwrap()); + self.machine_st.unify_fixnum(n, self.machine_st.registers[1]); + } - let priority = match Number::try_from(priority) { - Ok(Number::Integer(n)) => n.to_u16().unwrap(), - Ok(Number::Fixnum(n)) => u16::try_from(n.get_num()).unwrap(), - _ => { - unreachable!(); - } - }; + #[inline(always)] + pub(crate) fn get_cut_point(&mut self) { + let n = Fixnum::build_with(i64::try_from(self.machine_st.b0).unwrap()); + self.machine_st.unify_fixnum(n, self.machine_st.registers[1]); + } - let specifier = cell_as_atom_cell!(self.machine_st.store(self.machine_st.deref(specifier))) - .get_name(); + #[inline(always)] + pub(crate) fn get_staggered_cut_point(&mut self) { + use std::sync::Once; - let op = read_heap_cell!(self.machine_st.store(self.machine_st.deref(op)), - (HeapCellValueTag::Char) => { - self.machine_st.atom_tbl.build_with(&op.to_string()) - } - (HeapCellValueTag::Atom, (name, _arity)) => { - name + let b = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + static mut SEMICOLON_SECOND_BRANCH_LOC: usize = 0; + static LOC_INIT: Once = Once::new(); + + let semicolon_second_clause_p = unsafe { + LOC_INIT.call_once(|| { + match self.indices.code_dir.get(&(atom!(";"), 2)).map(|cell| cell.get()) { + Some(IndexPtr::Index(p)) => { + match &self.code[p] { + &Instruction::TryMeElse(o) => { + SEMICOLON_SECOND_BRANCH_LOC = p + o; + } + _ => { + unreachable!(); + } + } } _ => { - unreachable!() + unreachable!(); } - ); + } + }); - let result = to_op_decl(priority, specifier, op) - .map_err(SessionError::from) - .and_then(|mut op_decl| { - if op_decl.op_desc.get_prec() == 0 { - Ok(op_decl.remove(&mut self.indices.op_dir)) - } else { - let spec = get_op_desc( - op_decl.name, - &CompositeOpDir::new(&self.indices.op_dir, None), - ); + SEMICOLON_SECOND_BRANCH_LOC + }; - op_decl.submit(spec, &mut self.indices.op_dir) - } - }); + let staggered_b0 = if self.machine_st.b > 0 { + let or_frame = self.machine_st.stack.index_or_frame(self.machine_st.b); - match result { - Ok(()) => {} - Err(e) => { - // 8.14.3.3 l) - let err = self.machine_st.session_error(e); - let stub = functor_stub(atom!("op"), 3); + if or_frame.prelude.bp == semicolon_second_clause_p { + or_frame.prelude.b0 + } else { + self.machine_st.b0 + } + } else { + self.machine_st.b0 + }; - return Err(self.machine_st.error_form(err, stub)); - } + let staggered_b0 = integer_as_cell!( + Number::arena_from(staggered_b0, &mut self.machine_st.arena) + ); + + self.machine_st.bind(b.as_var().unwrap(), staggered_b0); + } + + #[inline(always)] + pub(crate) fn next_ep(&mut self) { + let first_arg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + read_heap_cell!(first_arg, + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(name, atom!("first")); + debug_assert_eq!(arity, 0); + + if self.machine_st.e == 0 { + self.machine_st.fail = true; + return; } - } - &SystemClauseType::SetStreamOptions => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("open"), - 4, - )?; - let alias = self.machine_st.registers[2]; - let eof_action = self.machine_st.registers[3]; - let reposition = self.machine_st.registers[4]; - let stream_type = self.machine_st.registers[5]; + let and_frame = self.machine_st.stack.index_and_frame(self.machine_st.e); + let cp = and_frame.prelude.cp - 1; - let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); - *stream.options_mut() = options; - } - &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => { - self.machine_st.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h)) - } - &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { - self.machine_st.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!()) - } - &SystemClauseType::GetAttributedVariableList => { - let attr_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let attr_var_list = read_heap_cell!(attr_var, - (HeapCellValueTag::AttrVar, h) => { - h + 1 - } - (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - // create an AttrVar in the heap. - let h = self.machine_st.heap.len(); + let e = and_frame.prelude.e; + let e = Fixnum::build_with(i64::try_from(e).unwrap()); - self.machine_st.heap.push(attr_var_as_cell!(h)); - self.machine_st.heap.push(heap_loc_as_cell!(h+1)); + let p = str_loc_as_cell!(self.machine_st.heap.len()); - self.machine_st.bind(Ref::attr_var(h), attr_var); - h + 1 - } - _ => { - self.machine_st.fail = true; - return Ok(()); - } - ); + self.machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)])); + self.machine_st.unify_fixnum(e, self.machine_st.registers[2]); - let list_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - self.machine_st.bind(Ref::heap_cell(attr_var_list), list_addr); + if !self.machine_st.fail { + unify!(self.machine_st, p, self.machine_st.registers[3]); + } } - &SystemClauseType::GetAttrVarQueueDelimiter => { - let addr = self.machine_st.registers[1]; - let value = Fixnum::build_with(self.machine_st.attr_var_init.attr_var_queue.len() as i64); + (HeapCellValueTag::Fixnum, n) => { + let e = n.get_num() as usize; - self.machine_st.unify_fixnum(value, self.machine_st.store(self.machine_st.deref(addr))); - } - &SystemClauseType::GetAttrVarQueueBeyond => { - let addr = self.machine_st.registers[1]; - let addr = self.machine_st.store(self.machine_st.deref(addr)); + if e == 0 { + self.machine_st.fail = true; + return; + } - let b = match Number::try_from(addr) { - Ok(Number::Integer(n)) => n.to_usize(), - Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(), - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }; + // get the call site so that the number of + // active permanent variables can be read from + // it later. + let and_frame = self.machine_st.stack.index_and_frame(e); + let cp = and_frame.prelude.cp - 1; - if let Some(b) = b { - let iter = self.machine_st.gather_attr_vars_created_since(b); + let p = str_loc_as_cell!(self.machine_st.heap.len()); + self.machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)])); - let var_list_addr = heap_loc_as_cell!( - iter_to_heap_list(&mut self.machine_st.heap, iter) - ); + let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap()); + self.machine_st.unify_fixnum(e, self.machine_st.registers[2]); - let list_addr = self.machine_st.registers[2]; - unify!(self.machine_st, var_list_addr, list_addr); + if !self.machine_st.fail { + unify!(self.machine_st, p, self.machine_st.registers[3]); } } - &SystemClauseType::GetContinuationChunk => { - let e = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let e = cell_as_fixnum!(e).get_num() as usize; + _ => { + unreachable!(); + } + ); + } - let p_functor = self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[2] - )); - let p = to_local_code_ptr(&self.machine_st.heap, p_functor).unwrap(); + #[inline(always)] + pub(crate) fn points_to_continuation_reset_marker(&mut self) { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let num_cells = match self.code_repo.lookup_instr(&self.machine_st, &CodePtr::Local(p)) { - Some(line) => { - let perm_vars = match line.as_ref(&self.code_repo.code) { - Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(), - _ => None, - }; + let p = match to_local_code_ptr(&self.machine_st.heap, addr) { + Some(p) => p + 1, + None => { + self.machine_st.fail = true; + return; + } + }; - perm_vars.unwrap() - } - _ => unreachable!(), - }; + if !self.is_reset_cont_marker(p) { + self.machine_st.fail = true; + } + } + + #[inline(always)] + pub(crate) fn quoted_token(&mut self) { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let mut addrs = vec![]; + read_heap_cell!(addr, + (HeapCellValueTag::Fixnum, n) => { + let n = u32::try_from(n.get_num()).ok(); + let n = n.and_then(std::char::from_u32); - for idx in 1..num_cells + 1 { - addrs.push(self.machine_st.stack[stack_loc!(AndFrame, e, idx)]); - } + self.machine_st.fail = match n { + Some(c) => non_quoted_token(once(c)), + None => true, + }; + } + (HeapCellValueTag::Char, c) => { + self.machine_st.fail = non_quoted_token(once(c)); + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + self.machine_st.fail = non_quoted_token(name.as_str().chars()); + } + _ => { + self.machine_st.fail = true; + } + ); + } - let chunk = str_loc_as_cell!(self.machine_st.heap.len()); + #[inline(always)] + pub(crate) fn read_query_term(&mut self) -> CallResult { + self.user_input.reset(); - self.machine_st.heap.push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); - self.machine_st.heap.push(p_functor); - self.machine_st.heap.extend(addrs); + set_prompt(true); + let result = self.machine_st.read_term(self.user_input, &mut self.indices); + set_prompt(false); - unify!(self.machine_st, self.machine_st.registers[3], chunk); + match result { + Ok(()) => Ok(()), + Err(e) => { + self.user_input = input_stream(&mut self.machine_st.arena); + return Err(e); } - &SystemClauseType::GetLiftedHeapFromOffsetDiff => { - let lh_offset = self.machine_st.registers[1]; - let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))).get_num() as usize; + } + } - if lh_offset >= self.machine_st.lifted_heap.len() { - let solutions = self.machine_st.registers[2]; - let diff = self.machine_st.registers[3]; + #[inline(always)] + pub(crate) fn read_term(&mut self) -> CallResult { + set_prompt(false); - unify_fn!(self.machine_st, solutions, diff); - } else { - let h = self.machine_st.heap.len(); - let mut last_index = h; + let stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("read_term"), + 3, + )?; - for value in self.machine_st.lifted_heap[lh_offset ..].iter().cloned() { - last_index = self.machine_st.heap.len(); - self.machine_st.heap.push(value + h); - } + self.machine_st.read_term(stream, &mut self.indices) + } - if last_index < self.machine_st.heap.len() { - let diff = self.machine_st.registers[3]; - unify_fn!(self.machine_st, diff, self.machine_st.heap[last_index]); - } + #[inline(always)] + pub(crate) fn read_term_from_chars(&mut self) -> CallResult { + if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + let chars = atom_or_string.to_string(); + let stream = Stream::from_owned_string(chars, &mut self.machine_st.arena); - self.machine_st.lifted_heap.truncate(lh_offset); + let term_write_result = match self.machine_st.read(stream, &self.indices.op_dir) { + Ok(term_write_result) => term_write_result, + Err(e) => { + let stub = functor_stub(atom!("read_term_from_chars"), 2); + let e = self.machine_st.session_error(SessionError::from(e)); - let solutions = self.machine_st.registers[2]; - unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions); + return Err(self.machine_st.error_form(e, stub)); } - } - &SystemClauseType::GetLiftedHeapFromOffset => { - let lh_offset = self.machine_st.registers[1]; - let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))).get_num() as usize; + }; - if lh_offset >= self.machine_st.lifted_heap.len() { - let solutions = self.machine_st.registers[2]; - unify_fn!(self.machine_st, solutions, empty_list_as_cell!()); - } else { - let h = self.machine_st.heap.len(); + let result = heap_loc_as_cell!(term_write_result.heap_loc); + let var = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2] + )).as_var().unwrap(); - for addr in self.machine_st.lifted_heap[lh_offset..].iter().cloned() { - self.machine_st.heap.push(addr + h); - } + self.machine_st.bind(var, result); + } else { + unreachable!() + } - self.machine_st.lifted_heap.truncate(lh_offset); + Ok(()) + } - let solutions = self.machine_st.registers[2]; - unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions); - } - } - &SystemClauseType::GetDoubleQuotes => { - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + #[inline(always)] + pub(crate) fn reset_block(&mut self) { + let addr = self.machine_st.deref(self.machine_st.registers[1]); + self.machine_st.reset_block(addr); + } - self.machine_st.unify_atom( - match self.machine_st.flags.double_quotes { - DoubleQuotes::Chars => atom!("chars"), - DoubleQuotes::Atom => atom!("atom"), - DoubleQuotes::Codes => atom!("codes"), - }, - a1, - ); - } - &SystemClauseType::GetSCCCleaner => { - let dest = self.machine_st.registers[1]; + #[inline(always)] + pub(crate) fn reset_continuation_marker(&mut self) { + let h = self.machine_st.heap.len(); - if let Some((addr, b_cutoff, prev_b)) = self.machine_st.cont_pts.pop() { - let b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b; + self.machine_st.registers[3] = atom_as_cell!(atom!("none")); + self.machine_st.registers[4] = heap_loc_as_cell!(h); - if b <= b_cutoff { - self.machine_st.block = prev_b; + self.machine_st.heap.push(heap_loc_as_cell!(h)); + } - if let Some(r) = dest.as_var() { - self.machine_st.bind(r, addr); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - } else { - self.machine_st.cont_pts.push((addr, b_cutoff, prev_b)); - } - } + #[inline(always)] + pub(crate) fn set_ball(&mut self) { + self.machine_st.set_ball(); + } + #[inline(always)] + pub(crate) fn set_seed(&mut self) { + let seed = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let mut rand = RANDOM_STATE.borrow_mut(); + + match Number::try_from(seed) { + Ok(Number::Fixnum(n)) => rand.seed(&Integer::from(n)), + Ok(Number::Integer(n)) => rand.seed(&*n), + Ok(Number::Rational(n)) if n.denom() == &1 => rand.seed(n.numer()), + _ => { self.machine_st.fail = true; } - &SystemClauseType::Halt => { - let code = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - - let code = match Number::try_from(code) { - Ok(Number::Fixnum(n)) => i32::try_from(n.get_num()).unwrap(), - Ok(Number::Integer(n)) => n.to_i32().unwrap(), - Ok(Number::Rational(r)) => { - // n has already been confirmed as an integer, and - // internally, Rational is assumed reduced, so its - // denominator must be 1. - r.numer().to_i32().unwrap() - } - _ => { - unreachable!() - } - }; + } + } - std::process::exit(code); + #[inline(always)] + pub(crate) fn sleep(&mut self) { + let time = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + let time = match Number::try_from(time) { + Ok(Number::Float(n)) => n.into_inner(), + Ok(Number::Fixnum(n)) => n.get_num() as f64, + Ok(Number::Integer(n)) => n.to_f64(), + _ => { + unreachable!() } - &SystemClauseType::InstallSCCCleaner => { - let addr = self.machine_st.registers[1]; - let b = self.machine_st.b; - let prev_block = self.machine_st.block; + }; - self.machine_st.run_cleaners_fn = Machine::run_cleaners; + let duration = Duration::new(1, 0); + let duration = duration.mul_f64(time); - self.machine_st.install_new_block(self.machine_st.registers[2]); - self.machine_st.cont_pts.push((addr, b, prev_block)); - } - &SystemClauseType::InstallInferenceCounter => { - // A1 = B, A2 = L - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + std::thread::sleep(duration); + } + + #[inline(always)] + pub(crate) fn socket_client_open(&mut self) -> CallResult { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + let socket_atom = cell_as_atom!(addr); - let n = match Number::try_from(a2) { - Ok(Number::Fixnum(bp)) => bp.get_num() as usize, - Ok(Number::Integer(n)) => n.to_usize().unwrap(), + let _port = read_heap_cell!(port, + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + name + } + _ => { + self.machine_st.atom_tbl.build_with(&match Number::try_from(port) { + Ok(Number::Fixnum(n)) => n.get_num().to_string(), + Ok(Number::Integer(n)) => n.to_string(), _ => { - let stub = functor_stub( - atom!("call_with_inference_limit"), - 3, - ); - - let err = self.machine_st.type_error(ValidType::Integer, a2); - return Err(self.machine_st.error_form(err, stub)); + unreachable!() } - }; + }) + } + ); - let bp = cell_as_fixnum!(a1).get_num() as usize; - let count = self.machine_st.cwil.add_limit(n, bp); - let count = arena_alloc!(count.clone(), &mut self.machine_st.arena); + let socket_addr = if socket_atom == atom!("") { + atom!("127.0.0.1") + } else { + socket_atom + }; - self.machine_st.increment_call_count_fn = MachineState::increment_call_count; + let alias = self.machine_st.registers[4]; + let eof_action = self.machine_st.registers[5]; + let reposition = self.machine_st.registers[6]; + let stream_type = self.machine_st.registers[7]; - let a3 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); - self.machine_st.unify_big_int(count, a3); - } - &SystemClauseType::ModuleExists => { - let module = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let module_name = cell_as_atom!(module); + let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); + + if options.reposition() { + return Err(self.machine_st.reposition_error(atom!("socket_client_open"), 3)); + } - self.machine_st.fail = !self.indices.modules.contains_key(&module_name); + if let Some(alias) = options.get_alias() { + if self.indices.stream_aliases.contains_key(&alias) { + return Err(self.machine_st.occupied_alias_permission_error( + alias, + atom!("socket_client_open"), + 3, + )); } - &SystemClauseType::NoSuchPredicate => { - let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); - let head = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + } - self.machine_st.fail = read_heap_cell!(head, - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) - .get_name_and_arity(); + let stream = match TcpStream::connect(socket_addr.as_str()).map_err(|e| e.kind()) { + Ok(tcp_stream) => { + let mut stream = { + let tls = cell_as_atom!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[8] + ))); - if clause_type_form(name, arity).is_some() { - true - } else { - let index = self.indices.get_predicate_code_index( - name, - arity, - module_name, - ) - .map(|index| index.get()) - .unwrap_or(IndexPtr::DynamicUndefined); - - match index { - IndexPtr::DynamicUndefined | IndexPtr::Undefined => false, - _ => true, - } + match tls { + atom!("false") => { + Stream::from_tcp_stream(socket_addr, tcp_stream, &mut self.machine_st.arena) } - } - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(arity, 0); + atom!("true") => { + let connector = TlsConnector::new().unwrap(); + let stream = Stream::from_tcp_stream( + socket_addr, + tcp_stream, + &mut self.machine_st.arena, + ); - if clause_type_form(name, 0).is_some() { - true - } else { - let index = self.indices.get_predicate_code_index( - name, - 0, - module_name, - ) - .map(|index| index.get()) - .unwrap_or(IndexPtr::DynamicUndefined); - - match index { - IndexPtr::DynamicUndefined => false, - _ => true, - } - } - } - _ => { - let err = self.machine_st.type_error(ValidType::Callable, head); - let stub = functor_stub(atom!("clause"), 2); + let stream = + match connector.connect(socket_atom.as_str(), stream) { + Ok(tls_stream) => tls_stream, + Err(_) => { + return Err(self.machine_st.open_permission_error( + addr, + atom!("socket_client_open"), + 3, + )); + } + }; - return Err(self.machine_st.error_form(err, stub)); + Stream::from_tls_stream(atom!("TLS"), stream, &mut self.machine_st.arena) + } + _ => { + unreachable!() + } } - ); - } - &SystemClauseType::RedoAttrVarBinding => { - let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + }; - debug_assert_eq!(HeapCellValueTag::AttrVar, var.get_tag()); - self.machine_st.heap[var.get_value()] = value; - } - &SystemClauseType::ResetAttrVarState => { - self.machine_st.attr_var_init.reset(); - } - &SystemClauseType::RemoveCallPolicyCheck => { - let bp = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[1] - ))).get_num() as usize; + *stream.options_mut() = options; - if bp == self.machine_st.b && self.machine_st.cwil.is_empty() { - self.machine_st.cwil.reset(); - self.machine_st.increment_call_count_fn = |_| { Ok(()) }; + if let Some(alias) = stream.options().get_alias() { + self.indices.stream_aliases.insert(alias, stream); } - } - &SystemClauseType::RemoveInferenceCounter => { - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let bp = cell_as_fixnum!(a1).get_num() as usize; - - let count = self.machine_st.cwil.remove_limit(bp).clone(); - let count = arena_alloc!(count.clone(), &mut self.machine_st.arena); - let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + self.indices.streams.insert(stream); - self.machine_st.unify_big_int(count, a2); + stream_as_cell!(stream) } - &SystemClauseType::REPL(repl_code_ptr) => { - return self.machine_st.repl_redirect(repl_code_ptr); + Err(ErrorKind::PermissionDenied) => { + return Err(self.machine_st.open_permission_error(addr, atom!("socket_client_open"), 3)); } - &SystemClauseType::ReturnFromVerifyAttr => { - let e = self.machine_st.e; - let frame_len = self.machine_st.stack.index_and_frame(e).prelude.univ_prelude.num_cells; + Err(ErrorKind::NotFound) => { + let stub = functor_stub(atom!("socket_client_open"), 3); + let err = self.machine_st.existence_error( + ExistenceError::SourceSink(addr), + ); - for i in 1..frame_len - 1 { - self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)]; - } + return Err(self.machine_st.error_form(err, stub)); + } + Err(_) => { + // for now, just fail. expand to meaningful error messages later. + self.machine_st.fail = true; + return Ok(()); + } + }; - self.machine_st.b0 = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)]) - .get_num() as usize; + let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + self.machine_st.bind(stream_addr.as_var().unwrap(), stream); - self.machine_st.num_of_args = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)]) - .get_num() as usize; + Ok(()) + } - self.machine_st.deallocate(); - self.machine_st.p = CodePtr::Local(self.machine_st.stack.index_and_frame(e).prelude.interrupt_cp); + #[inline(always)] + pub(crate) fn socket_server_open(&mut self) -> CallResult { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let socket_atom = cell_as_atom_cell!(addr).get_name(); - return Ok(()); - } - &SystemClauseType::RestoreCutPolicy => { - if self.machine_st.cont_pts.is_empty() { - self.machine_st.run_cleaners_fn = |_| { false }; - } - } - &SystemClauseType::SetCutPoint(r) => { - let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); - self.machine_st.cut_body(cp); + let socket_atom = if socket_atom == atom!("[]") { + atom!("127.0.0.1") + } else { + socket_atom + }; - if (self.machine_st.run_cleaners_fn)(self) { - return Ok(()); - } - } - &SystemClauseType::SetCutPointByDefault(r) => { - let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r])); - self.machine_st.cut_body(cp); - } - &SystemClauseType::SetInput => { - let addr = self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[1] - )); - let stream = self.machine_st.get_stream_or_alias( - addr, - &self.indices.stream_aliases, - atom!("set_input"), - 1, - )?; - - if !stream.is_input_stream() { - let stub = functor_stub(atom!("set_input"), 1); - let user_alias = atom_as_cell!(atom!("user")); - - let err = self.machine_st.permission_error( - Permission::InputStream, - atom!("stream"), - user_alias, - ); + let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - return Err(self.machine_st.error_form(err, stub)); + let port = if port.is_var() { + String::from("0") + } else { + match Number::try_from(port) { + Ok(Number::Fixnum(n)) => n.get_num().to_string(), + Ok(Number::Integer(n)) => n.to_string(), + _ => { + unreachable!() } - - self.user_input = stream; } - &SystemClauseType::SetOutput => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let stream = self.machine_st.get_stream_or_alias( - addr, - &self.indices.stream_aliases, - atom!("set_output"), - 1, - )?; - - if !stream.is_output_stream() { - let stub = functor_stub(atom!("set_input"), 1); + }; - let user_alias = atom_as_cell!(atom!("user")); - let err = self.machine_st.permission_error( - Permission::OutputStream, - atom!("stream"), - user_alias, - ); + let had_zero_port = &port == "0"; - return Err(self.machine_st.error_form(err, stub)); - } + let server_addr = if socket_atom == atom!("") { + port + } else { + format!("{}:{}", socket_atom.as_str(), port) + }; - self.user_output = stream; - } - &SystemClauseType::SetDoubleQuotes => { - let atom = cell_as_atom!(self.machine_st.registers[1]); + let (tcp_listener, port) = + match TcpListener::bind(server_addr).map_err(|e| e.kind()) { + Ok(tcp_listener) => { + let port = tcp_listener.local_addr().map(|addr| addr.port()).ok(); - self.machine_st.flags.double_quotes = match atom { - atom!("atom") => DoubleQuotes::Atom, - atom!("chars") => DoubleQuotes::Chars, - atom!("codes") => DoubleQuotes::Codes, - _ => { + if let Some(port) = port { + (arena_alloc!(tcp_listener, &mut self.machine_st.arena), port as usize) + } else { self.machine_st.fail = true; return Ok(()); } - }; - } - &SystemClauseType::InferenceLevel => { - let a1 = self.machine_st.registers[1]; - let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - - let bp = cell_as_fixnum!(a2).get_num() as usize; - let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b; - - if prev_b <= bp { - self.machine_st.unify_atom(atom!("!"), a1) - } else { - self.machine_st.unify_atom(atom!("true"), a1); } - } - &SystemClauseType::CleanUpBlock => { - let nb = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let nb = cell_as_fixnum!(nb).get_num() as usize; - - let b = self.machine_st.b; - - if nb > 0 && self.machine_st.stack.index_or_frame(b).prelude.b == nb { - self.machine_st.b = self.machine_st.stack.index_or_frame(nb).prelude.b; + Err(ErrorKind::PermissionDenied) => { + return Err(self.machine_st.open_permission_error(addr, atom!("socket_server_open"), 2)); } - } - &SystemClauseType::EraseBall => { - self.machine_st.ball.reset(); - } - &SystemClauseType::Fail => { - self.machine_st.fail = true; - } - &SystemClauseType::GetBall => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let h = self.machine_st.heap.len(); - - if self.machine_st.ball.stub.len() > 0 { - let stub = self.machine_st.ball.copy_and_align(h); - self.machine_st.heap.extend(stub.into_iter()); - } else { + _ => { self.machine_st.fail = true; return Ok(()); } + }; - match addr.as_var() { - Some(r) => self.machine_st.bind(r, self.machine_st.heap[h]), - _ => self.machine_st.fail = true, - }; - } - &SystemClauseType::GetCurrentBlock => { - let n = Fixnum::build_with(i64::try_from(self.machine_st.block).unwrap()); - self.machine_st.unify_fixnum(n, self.machine_st.registers[1]); - } - &SystemClauseType::GetBValue => { - let n = Fixnum::build_with(i64::try_from(self.machine_st.b).unwrap()); - self.machine_st.unify_fixnum(n, self.machine_st.registers[1]); - } - &SystemClauseType::GetCutPoint => { - let n = Fixnum::build_with(i64::try_from(self.machine_st.b0).unwrap()); - self.machine_st.unify_fixnum(n, self.machine_st.registers[1]); - } - &SystemClauseType::GetStaggeredCutPoint => { - use std::sync::Once; + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + self.machine_st.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener)); - let b = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + if had_zero_port { + self.machine_st.unify_fixnum(Fixnum::build_with(port as i64), self.machine_st.registers[2]); + } - static mut SEMICOLON_SECOND_BRANCH_LOC: usize = 0; - static LOC_INIT: Once = Once::new(); + Ok(()) + } - let semicolon_second_clause_p = unsafe { - LOC_INIT.call_once(|| { - match self.indices.code_dir.get(&(atom!(";"), 2)).map(|cell| cell.get()) { - Some(IndexPtr::Index(p)) => { - match self.code_repo.code[p] { - Line::Choice(ChoiceInstruction::TryMeElse(o)) => { - SEMICOLON_SECOND_BRANCH_LOC = p + o; - } - _ => { - unreachable!(); - } - } - } - _ => { - unreachable!(); - } - } - }); + #[inline(always)] + pub(crate) fn socket_server_accept(&mut self) -> CallResult { + let alias = self.machine_st.registers[4]; + let eof_action = self.machine_st.registers[5]; + let reposition = self.machine_st.registers[6]; + let stream_type = self.machine_st.registers[7]; - LocalCodePtr::DirEntry(SEMICOLON_SECOND_BRANCH_LOC) - }; + let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); - let staggered_b0 = if self.machine_st.b > 0 { - let or_frame = self.machine_st.stack.index_or_frame(self.machine_st.b); + if options.reposition() { + return Err(self.machine_st.reposition_error(atom!("socket_server_accept"), 4)); + } - if or_frame.prelude.bp == semicolon_second_clause_p { - or_frame.prelude.b0 - } else { - self.machine_st.b0 - } - } else { - self.machine_st.b0 - }; + if let Some(alias) = options.get_alias() { + if self.indices.stream_aliases.contains_key(&alias) { + return Err(self.machine_st.occupied_alias_permission_error( + alias, + atom!("socket_server_accept"), + 4, + )); + } + } - let staggered_b0 = integer_as_cell!( - Number::arena_from(staggered_b0, &mut self.machine_st.arena) - ); + let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - self.machine_st.bind(b.as_var().unwrap(), staggered_b0); - } - &SystemClauseType::InstallNewBlock => { - self.machine_st.install_new_block(self.machine_st.registers[1]); - } - &SystemClauseType::NextEP => { - let first_arg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + read_heap_cell!(culprit, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::TcpListener, tcp_listener) => { + match tcp_listener.accept().ok() { + Some((tcp_stream, socket_addr)) => { + let client = self.machine_st.atom_tbl.build_with(&socket_addr.to_string()); - read_heap_cell!(first_arg, - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(name, atom!("first")); - debug_assert_eq!(arity, 0); + let mut tcp_stream = Stream::from_tcp_stream( + client, + tcp_stream, + &mut self.machine_st.arena, + ); - if self.machine_st.e == 0 { - self.machine_st.fail = true; - return Ok(()); - } + *tcp_stream.options_mut() = options; - let and_frame = self.machine_st.stack.index_and_frame(self.machine_st.e); - let cp = (and_frame.prelude.cp - 1).unwrap(); + if let Some(alias) = &tcp_stream.options().get_alias() { + self.indices.stream_aliases.insert(*alias, tcp_stream); + } - let e = and_frame.prelude.e; - let e = Fixnum::build_with(i64::try_from(e).unwrap()); + self.indices.streams.insert(tcp_stream); - let p = str_loc_as_cell!(self.machine_st.heap.len()); + let tcp_stream = stream_as_cell!(tcp_stream); + let client = atom_as_cell!(client); - self.machine_st.heap.extend(cp.as_functor()); - self.machine_st.unify_fixnum(e, self.machine_st.registers[2]); + let client_addr = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2], + )); + let stream_addr = self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[3], + )); - if !self.machine_st.fail { - unify!(self.machine_st, p, self.machine_st.registers[3]); - } + self.machine_st.bind(client_addr.as_var().unwrap(), client); + self.machine_st.bind(stream_addr.as_var().unwrap(), tcp_stream); + } + None => { + self.machine_st.fail = true; + } + } + } + _ => { + } + ); + } + _ => { + } + ); + + Ok(()) + } + + #[inline(always)] + pub(crate) fn tls_client_connect(&mut self) -> CallResult { + if let Some(hostname) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + let stream0 = self.machine_st.get_stream_or_alias( + self.machine_st.registers[2], + &self.indices.stream_aliases, + atom!("tls_client_negotiate"), + 3, + )?; + + let connector = TlsConnector::new().unwrap(); + let stream = + match connector.connect(hostname.as_str(), stream0) { + Ok(tls_stream) => tls_stream, + Err(_) => { + return Err(self.machine_st.open_permission_error( + self.machine_st.registers[1], + atom!("tls_client_negotiate"), + 3, + )); } - (HeapCellValueTag::Fixnum, n) => { - let e = n.get_num() as usize; + }; - if e == 0 { - self.machine_st.fail = true; - return Ok(()); - } + let addr = atom!("TLS"); + let stream = Stream::from_tls_stream(addr, stream, &mut self.machine_st.arena); + self.indices.streams.insert(stream); - // get the call site so that the number of - // active permanent variables can be read from - // it later. - let and_frame = self.machine_st.stack.index_and_frame(e); - let cp = (and_frame.prelude.cp - 1).unwrap(); + self.machine_st.heap.push(stream_as_cell!(stream)); + let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); - let p = str_loc_as_cell!(self.machine_st.heap.len()); - self.machine_st.heap.extend(cp.as_functor()); + Ok(()) + } else { + unreachable!(); + } + } - let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap()); - self.machine_st.unify_fixnum(e, self.machine_st.registers[2]); + #[inline(always)] + pub(crate) fn tls_accept_client(&mut self) -> CallResult { + let pkcs12 = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); - if !self.machine_st.fail { - unify!(self.machine_st, p, self.machine_st.registers[3]); - } - } - _ => { - unreachable!(); + if let Some(password) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { + let identity = + match Identity::from_pkcs12(&pkcs12, password.as_str()) { + Ok(identity) => identity, + Err(_) => { + return Err(self.machine_st.open_permission_error( + self.machine_st.registers[1], + atom!("tls_server_negotiate"), + 3, + )); } - ); - } - &SystemClauseType::PointsToContinuationResetMarker => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + }; - let p = match to_local_code_ptr(&self.machine_st.heap, addr) { - Some(p) => p + 1, - None => { - self.machine_st.fail = true; - return Ok(()); + let stream0 = self.machine_st.get_stream_or_alias( + self.machine_st.registers[3], + &self.indices.stream_aliases, + atom!("tls_server_negotiate"), + 3, + )?; + + let acceptor = TlsAcceptor::new(identity).unwrap(); + + let stream = + match acceptor.accept(stream0) { + Ok(tls_stream) => tls_stream, + Err(_) => { + return Err(self.machine_st.open_permission_error( + self.machine_st.registers[3], + atom!("tls_server_negotiate"), + 3, + )); } }; - if self.is_reset_cont_marker(p) { - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.machine_st.arena); + self.indices.streams.insert(stream); - self.machine_st.fail = true; - return Ok(()); - } - &SystemClauseType::QuotedToken => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4])); + self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); + } else { + unreachable!(); + } - read_heap_cell!(addr, - (HeapCellValueTag::Fixnum, n) => { - let n = u32::try_from(n.get_num()).ok(); - let n = n.and_then(std::char::from_u32); + Ok(()) + } - self.machine_st.fail = match n { - Some(c) => non_quoted_token(once(c)), - None => true, - }; - } - (HeapCellValueTag::Char, c) => { - self.machine_st.fail = non_quoted_token(once(c)); - } - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(arity, 0); - self.machine_st.fail = non_quoted_token(name.as_str().chars()); + #[inline(always)] + pub(crate) fn socket_server_close(&mut self) -> CallResult { + let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + read_heap_cell!(culprit, + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::TcpListener, tcp_listener) => { + unsafe { + // dropping closes the instance. + std::ptr::drop_in_place(&mut tcp_listener as *mut _); + } + + tcp_listener.set_tag(ArenaHeaderTag::Dropped); + return Ok(()); } _ => { - self.machine_st.fail = true; } ); } - &SystemClauseType::ReadQueryTerm => { - self.user_input.reset(); - - set_prompt(true); - let result = self.machine_st.read_term(self.user_input, &mut self.indices); - set_prompt(false); - - match result { - Ok(()) => {} - Err(e) => { - self.user_input = input_stream(&mut self.machine_st.arena); - return Err(e); - } - } + _ => { } - &SystemClauseType::ReadTerm => { - set_prompt(false); + ); - let stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("read_term"), - 3, - )?; + let err = self.machine_st.type_error(ValidType::TcpListener, culprit); + let stub = functor_stub(atom!("socket_server_close"), 1); - self.machine_st.read_term(stream, &mut self.indices)?; - } - &SystemClauseType::ReadTermFromChars => { - if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - let chars = atom_or_string.to_string(); - let stream = Stream::from_owned_string(chars, &mut self.machine_st.arena); + return Err(self.machine_st.error_form(err, stub)); + } - let term_write_result = match self.machine_st.read(stream, &self.indices.op_dir) { - Ok(term_write_result) => term_write_result, - Err(e) => { - let stub = functor_stub(atom!("read_term_from_chars"), 2); - let e = self.machine_st.session_error(SessionError::from(e)); + #[inline(always)] + pub(crate) fn set_stream_position(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("set_stream_position"), + 2, + )?; + + if !stream.options().reposition() { + let stub = functor_stub(atom!("set_stream_position"), 2); + + let err = self.machine_st.permission_error( + Permission::Reposition, + atom!("stream"), + vec![stream_as_cell!(stream)], + ); - return Err(self.machine_st.error_form(e, stub)); - } - }; + return Err(self.machine_st.error_form(err, stub)); + } - let result = heap_loc_as_cell!(term_write_result.heap_loc); - let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])).as_var().unwrap(); + let position = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - self.machine_st.bind(var, result); + let position = match Number::try_from(position) { + Ok(Number::Fixnum(n)) => n.get_num() as u64, + Ok(Number::Integer(n)) => { + if let Some(n) = n.to_u64() { + n } else { - unreachable!() + self.machine_st.fail = true; + return Ok(()); } } - &SystemClauseType::ResetBlock => { - let addr = self.machine_st.deref(self.machine_st.registers[1]); - self.machine_st.reset_block(addr); + _ => { + unreachable!() } - &SystemClauseType::ResetContinuationMarker => { - let h = self.machine_st.heap.len(); + }; - self.machine_st.registers[3] = atom_as_cell!(atom!("none")); - self.machine_st.registers[4] = heap_loc_as_cell!(h); + stream.set_position(position); + Ok(()) + } - self.machine_st.heap.push(heap_loc_as_cell!(h)); - } - &SystemClauseType::SetBall => { - self.machine_st.set_ball(); + #[inline(always)] + pub(crate) fn stream_property(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("stream_property"), + 2, + )?; + + let atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[2] + ))); + + let property = match atom { + atom!("file_name") => { + atom_as_cell!(if let Some(file_name) = stream.file_name() { + file_name + } else { + self.machine_st.fail = true; + return Ok(()); + }) + } + atom!("mode") => atom_as_cell!(stream.mode()), + atom!("direction") => + atom_as_cell!(if stream.is_input_stream() && stream.is_output_stream() { + atom!("input_output") + } else if stream.is_input_stream() { + atom!("input") + } else { + atom!("output") + }), + atom!("alias") => { + atom_as_cell!(if let Some(alias) = stream.options().get_alias() { + alias + } else { + self.machine_st.fail = true; + return Ok(()); + }) } - &SystemClauseType::SetSeed => { - let seed = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let mut rand = RANDOM_STATE.borrow_mut(); + atom!("position") => { + if let Some((position, lines_read)) = stream.position() { + let h = self.machine_st.heap.len(); - match Number::try_from(seed) { - Ok(Number::Fixnum(n)) => rand.seed(&Integer::from(n)), - Ok(Number::Integer(n)) => rand.seed(&*n), - Ok(Number::Rational(n)) if n.denom() == &1 => rand.seed(n.numer()), - _ => { - self.machine_st.fail = true; - return Ok(()); - } + let position_term = functor!( + atom!("position_and_lines_read"), + [integer(position, &mut self.machine_st.arena), + integer(lines_read, &mut self.machine_st.arena)] + ); + + self.machine_st.heap.extend(position_term.into_iter()); + str_loc_as_cell!(h) + } else { + self.machine_st.fail = true; + return Ok(()); } } - &SystemClauseType::SkipMaxList => { - if let Err(err) = self.machine_st.skip_max_list() { - return Err(err); - } + atom!("end_of_stream") => { + let end_of_stream_pos = stream.position_relative_to_end(); + atom_as_cell!(end_of_stream_pos.as_atom()) } - &SystemClauseType::Sleep => { - let time = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - - let time = match Number::try_from(time) { - Ok(Number::Float(n)) => n.into_inner(), - Ok(Number::Fixnum(n)) => n.get_num() as f64, - Ok(Number::Integer(n)) => n.to_f64(), - _ => { - unreachable!() - } - }; - - let duration = Duration::new(1, 0); - let duration = duration.mul_f64(time); - - std::thread::sleep(duration); + atom!("eof_action") => { + atom_as_cell!(stream.options().eof_action().as_atom()) } - &SystemClauseType::SocketClientOpen => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - - let socket_atom = cell_as_atom!(addr); - - let _port = read_heap_cell!(port, - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(arity, 0); - name - } - _ => { - self.machine_st.atom_tbl.build_with(&match Number::try_from(port) { - Ok(Number::Fixnum(n)) => n.get_num().to_string(), - Ok(Number::Integer(n)) => n.to_string(), - _ => { - unreachable!() - } - }) - } - ); - - let socket_addr = if socket_atom == atom!("") { - atom!("127.0.0.1") - } else { - socket_atom - }; - - let alias = self.machine_st.registers[4]; - let eof_action = self.machine_st.registers[5]; - let reposition = self.machine_st.registers[6]; - let stream_type = self.machine_st.registers[7]; + atom!("reposition") => + atom_as_cell!(if stream.options().reposition() { + atom!("true") + } else { + atom!("false") + }), + atom!("type") => { + atom_as_cell!(stream.options().stream_type().as_property_atom()) + } + _ => { + unreachable!() + } + }; - let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); + unify!(self.machine_st, property, self.machine_st.registers[3]); + Ok(()) + } - if options.reposition() { - return Err(self.machine_st.reposition_error(atom!("socket_client_open"), 3)); - } + #[inline(always)] + pub(crate) fn store_global_var(&mut self) { + let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); - if let Some(alias) = options.get_alias() { - if self.indices.stream_aliases.contains_key(&alias) { - return Err(self.machine_st.occupied_alias_permission_error( - alias, - atom!("socket_client_open"), - 3, - )); - } - } + let value = self.machine_st.registers[2]; + let mut ball = Ball::new(); - let stream = match TcpStream::connect(socket_addr.as_str()).map_err(|e| e.kind()) { - Ok(tcp_stream) => { - let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream, &mut self.arena); + ball.boundary = self.machine_st.heap.len(); - *stream.options_mut() = options; + copy_term( + CopyBallTerm::new(&mut self.machine_st.stack, &mut self.machine_st.heap, &mut ball.stub), + value, + AttrVarPolicy::DeepCopy, + ); - if let Some(alias) = stream.options().get_alias() { - self.indices.stream_aliases.insert(alias, stream); - } + self.indices.global_variables.insert(key, (ball, None)); + } - self.indices.streams.insert(stream); + #[inline(always)] + pub(crate) fn store_backtrackable_global_var(&mut self) { + let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); + let new_value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - stream_as_cell!(stream) - } - Err(ErrorKind::PermissionDenied) => { - return Err(self.machine_st.open_permission_error(addr, atom!("socket_client_open"), 3)); - } - Err(ErrorKind::NotFound) => { - let stub = functor_stub(atom!("socket_client_open"), 3); - let err = self.machine_st.existence_error( - ExistenceError::SourceSink(addr), - ); + match self.indices.global_variables.get_mut(&key) { + Some((_, ref mut loc)) => match loc { + Some(ref mut value) => { + self.machine_st.trail(TrailRef::BlackboardOffset(key, *value)); + *value = new_value; + } + loc @ None => { + self.machine_st.trail(TrailRef::BlackboardEntry(key)); + *loc = Some(new_value); + } + }, + None => { + self.machine_st.trail(TrailRef::BlackboardEntry(key)); + self.indices + .global_variables + .insert(key, (Ball::new(), Some(new_value))); + } + } + } - return Err(self.machine_st.error_form(err, stub)); - } - Err(_) => { - // for now, just fail. expand to meaningful error messages later. - self.machine_st.fail = true; - return Ok(()); - } - }; + #[inline(always)] + pub(crate) fn term_attributed_variables(&mut self) { + if self.machine_st.registers[1].is_constant() { + self.machine_st.unify_atom( + atom!("[]"), + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])), + ); - let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); - self.machine_st.bind(stream_addr.as_var().unwrap(), stream); - } - &SystemClauseType::SocketServerOpen => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let socket_atom = cell_as_atom_cell!(addr).get_name(); + return; + } - let socket_atom = if socket_atom == atom!("[]") { - atom!("127.0.0.1") - } else { - socket_atom - }; + let seen_vars = self.machine_st.attr_vars_of_term(self.machine_st.registers[1]); + let outcome = heap_loc_as_cell!( + iter_to_heap_list(&mut self.machine_st.heap, seen_vars.into_iter()) + ); - let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + unify_fn!(self.machine_st, self.machine_st.registers[2], outcome); + } - let port = if port.is_var() { - String::from("0") - } else { - match Number::try_from(port) { - Ok(Number::Fixnum(n)) => n.get_num().to_string(), - Ok(Number::Integer(n)) => n.to_string(), - _ => { - unreachable!() - } - } - }; + #[inline(always)] + pub(crate) fn term_variables(&mut self) { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; - let had_zero_port = &port == "0"; + let stored_v = self.machine_st.store(self.machine_st.deref(a1)); - let server_addr = if socket_atom == atom!("") { - port - } else { - format!("{}:{}", socket_atom.as_str(), port) - }; + if stored_v.is_constant() { + self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(a2))); + return; + } - let (tcp_listener, port) = - match TcpListener::bind(server_addr).map_err(|e| e.kind()) { - Ok(tcp_listener) => { - let port = tcp_listener.local_addr().map(|addr| addr.port()).ok(); + let mut seen_set = IndexSet::new(); - if let Some(port) = port { - (arena_alloc!(tcp_listener, &mut self.machine_st.arena), port as usize) - } else { - self.machine_st.fail = true; - return Ok(()); - } - } - Err(ErrorKind::PermissionDenied) => { - return Err(self.machine_st.open_permission_error(addr, atom!("socket_server_open"), 2)); - } - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }; + { + let mut iter = stackless_preorder_iter(&mut self.machine_st.heap, stored_v); - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); - self.machine_st.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener)); + while let Some(addr) = iter.next() { + let addr = unmark_cell_bits!(addr); - if had_zero_port { - self.machine_st.unify_fixnum(Fixnum::build_with(port as i64), self.machine_st.registers[2]); + if addr.is_var() { + seen_set.insert(addr); } } - &SystemClauseType::SocketServerAccept => { - let alias = self.machine_st.registers[4]; - let eof_action = self.machine_st.registers[5]; - let reposition = self.machine_st.registers[6]; - let stream_type = self.machine_st.registers[7]; + } - let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type); + let outcome = heap_loc_as_cell!( + filtered_iter_to_heap_list( + &mut self.machine_st.heap, + seen_set.into_iter().rev(), + |heap, value| { + heap_bound_store( + heap, + heap_bound_deref(heap, value), + ).is_var() + }, + ) + ); - if options.reposition() { - return Err(self.machine_st.reposition_error(atom!("socket_server_accept"), 4)); - } + unify_fn!(self.machine_st, a2, outcome); + } - if let Some(alias) = options.get_alias() { - if self.indices.stream_aliases.contains_key(&alias) { - return Err(self.machine_st.occupied_alias_permission_error( - alias, - atom!("socket_server_accept"), - 4, - )); - } - } + #[inline(always)] + pub(crate) fn term_variables_under_max_depth(&mut self) { + // Term, MaxDepth, VarList + let max_depth = cell_as_fixnum!( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) + ).get_num() as usize; + + self.machine_st.term_variables_under_max_depth( + self.machine_st.registers[1], + max_depth, + self.machine_st.registers[3], + ); + } - let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + #[inline(always)] + pub(crate) fn truncate_lifted_heap_to(&mut self) { + let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let lh_offset = cell_as_fixnum!(a1).get_num() as usize; - read_heap_cell!(culprit, - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::TcpListener, tcp_listener) => { - match tcp_listener.accept().ok() { - Some((tcp_stream, socket_addr)) => { - let client = self.machine_st.atom_tbl.build_with(&socket_addr.to_string()); + self.machine_st.lifted_heap.truncate(lh_offset); + } - let mut tcp_stream = Stream::from_tcp_stream( - client, - tcp_stream, - &mut self.machine_st.arena, - ); + #[inline(always)] + pub(crate) fn unify_with_occurs_check(&mut self) { + let a1 = self.machine_st.registers[1]; + let a2 = self.machine_st.registers[2]; - *tcp_stream.options_mut() = options; + unify_with_occurs_check!(&mut self.machine_st, a1, a2); + } - if let Some(alias) = &tcp_stream.options().get_alias() { - self.indices.stream_aliases.insert(*alias, tcp_stream); - } + #[inline(always)] + pub(crate) fn unwind_environments(&mut self) -> bool { + let mut e = self.machine_st.e; + let mut cp = self.machine_st.cp; - self.indices.streams.insert(tcp_stream); + while e > 0 { + if self.is_reset_cont_marker(cp) { + self.machine_st.e = e; + self.machine_st.p = cp + 1; // skip the reset marker. - let tcp_stream = stream_as_cell!(tcp_stream); - let client = atom_as_cell!(client); + return true; + } - let client_addr = self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[2], - )); - let stream_addr = self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[3], - )); + let and_frame = self.machine_st.stack.index_and_frame(e); - self.machine_st.bind(client_addr.as_var().unwrap(), client); - self.machine_st.bind(stream_addr.as_var().unwrap(), tcp_stream); + cp = and_frame.prelude.cp; + e = and_frame.prelude.e; + } - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - None => { - self.machine_st.fail = true; - return Ok(()); - } - } - } - _ => { - } - ); - } - _ => { - } - ); - } - &SystemClauseType::TLSClientConnect => { - if let Some(hostname) = self.value_to_str_like(self.registers[1]) { - let stream0 = self.get_stream_or_alias( - self.registers[2], - &indices.stream_aliases, - atom!("tls_client_negotiate"), - 3, - )?; + false + } - let connector = TlsConnector::new().unwrap(); - let stream = - match connector.connect(hostname.as_str(), stream0) { - Ok(tls_stream) => tls_stream, - Err(_) => { - return Err(self.open_permission_error( - self[temp_v!(1)], - atom!("tls_client_negotiate"), - 3, - )); - } - }; + #[inline(always)] + pub(crate) fn wam_instructions(&mut self) -> CallResult { + let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1]) + )); - let addr = atom!("TLS"); - let stream = Stream::from_tls_stream(addr, stream, &mut self.arena); - indices.streams.insert(stream); + let name = self.machine_st.registers[2]; + let arity = self.machine_st.registers[3]; - self.heap.push(stream_as_cell!(stream)); - let stream_addr = self.store(self.deref(self.registers[3])); - self.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); - } else { - unreachable!(); - } - } - &SystemClauseType::TLSAcceptClient => { - let pkcs12 = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); - - if let Some(password) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { - let identity = - match Identity::from_pkcs12(&pkcs12, password.as_str()) { - Ok(identity) => identity, - Err(_) => { - return Err(self.machine_st.open_permission_error( - self.machine_st.registers[1], - atom!("tls_server_negotiate"), - 3, - )); - } - }; + let name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(name))); + let arity = self.machine_st.store(self.machine_st.deref(arity)); - let stream0 = self.machine_st.get_stream_or_alias( - self.machine_st.registers[3], - &self.indices.stream_aliases, - atom!("tls_server_negotiate"), - 3, - )?; + let arity = match Number::try_from(arity) { + Ok(Number::Fixnum(n)) => n.get_num() as usize, + Ok(Number::Integer(n)) => n.to_usize().unwrap(), + _ => { + unreachable!() + } + }; - let acceptor = TlsAcceptor::new(identity).unwrap(); - - let stream = - match acceptor.accept(stream0) { - Ok(tls_stream) => tls_stream, - Err(_) => { - return Err(self.machine_st.open_permission_error( - self.machine_st.registers[3], - atom!("tls_server_negotiate"), - 3, - )); - } - }; + let key = (name, arity); + + let first_idx = match module_name { + atom!("user") => self.indices.code_dir.get(&key), + _ => match self.indices.modules.get(&module_name) { + Some(module) => module.code_dir.get(&key), + None => { + let stub = functor_stub(key.0, key.1); + let err = self.machine_st.session_error( + SessionError::from(CompilationError::InvalidModuleResolution( + module_name, + )), + ); - let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.machine_st.arena); - self.indices.streams.insert(stream); + return Err(self.machine_st.error_form(err, stub)); + } + }, + }; - let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4])); - self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); + let first_idx = match first_idx { + Some(ref idx) if idx.local().is_some() => { + if let Some(idx) = idx.local() { + idx } else { - unreachable!(); + unreachable!() } } - &SystemClauseType::SocketServerClose => { - let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - - read_heap_cell!(culprit, - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::TcpListener, tcp_listener) => { - unsafe { - // dropping closes the instance. - std::ptr::drop_in_place(&mut tcp_listener as *mut _); - } - - tcp_listener.set_tag(ArenaHeaderTag::Dropped); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - _ => { - } - ); - } - _ => { - } + _ => { + let stub = functor_stub(name, arity); + let err = self.machine_st.existence_error( + ExistenceError::Procedure(name, arity), ); - let err = self.machine_st.type_error(ValidType::TcpListener, culprit); - let stub = functor_stub(atom!("socket_server_close"), 1); - return Err(self.machine_st.error_form(err, stub)); } - &SystemClauseType::SetStreamPosition => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("set_stream_position"), - 2, - )?; - - if !stream.options().reposition() { - let stub = functor_stub(atom!("set_stream_position"), 2); - - let err = self.machine_st.permission_error( - Permission::Reposition, - atom!("stream"), - vec![stream_as_cell!(stream)], - ); + }; - return Err(self.machine_st.error_form(err, stub)); - } + let mut h = self.machine_st.heap.len(); - let position = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + let mut functors = vec![]; + let mut functor_list = vec![]; - let position = match Number::try_from(position) { - Ok(Number::Fixnum(n)) => n.get_num() as u64, - Ok(Number::Integer(n)) => { - if let Some(n) = n.to_u64() { - n - } else { - self.machine_st.fail = true; - return Ok(()); - } + walk_code(&self.code, first_idx, |instr| { + let old_len = functors.len(); + instr.enqueue_functors(h, &mut self.machine_st.arena, &mut functors); + let new_len = functors.len(); + + for index in old_len..new_len { + let functor_len = functors[index].len(); + + match functor_len { + 0 => {} + 1 => { + functor_list.push(heap_loc_as_cell!(h)); + h += functor_len; } _ => { - unreachable!() + functor_list.push(str_loc_as_cell!(h)); + h += functor_len; } - }; - - stream.set_position(position); + } } - &SystemClauseType::StreamProperty => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("stream_property"), - 2, - )?; + }); - let atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); + for functor in functors { + self.machine_st.heap.extend(functor.into_iter()); + } - let property = match atom { - atom!("file_name") => { - atom_as_cell!(if let Some(file_name) = stream.file_name() { - file_name - } else { - self.machine_st.fail = true; - return Ok(()); - }) - } - atom!("mode") => atom_as_cell!(stream.mode()), - atom!("direction") => - atom_as_cell!(if stream.is_input_stream() && stream.is_output_stream() { - atom!("input_output") - } else if stream.is_input_stream() { - atom!("input") - } else { - atom!("output") - }), - atom!("alias") => { - atom_as_cell!(if let Some(alias) = stream.options().get_alias() { - alias - } else { - self.machine_st.fail = true; - return Ok(()); - }) - } - atom!("position") => { - if let Some((position, lines_read)) = stream.position() { - let h = self.machine_st.heap.len(); - - let position_term = functor!( - atom!("position_and_lines_read"), - [integer(position, &mut self.machine_st.arena), - integer(lines_read, &mut self.machine_st.arena)] - ); + let listing = heap_loc_as_cell!( + iter_to_heap_list(&mut self.machine_st.heap, functor_list.into_iter()) + ); - self.machine_st.heap.extend(position_term.into_iter()); - str_loc_as_cell!(h) - } else { - self.machine_st.fail = true; - return Ok(()); - } - } - atom!("end_of_stream") => { - let end_of_stream_pos = stream.position_relative_to_end(); - atom_as_cell!(end_of_stream_pos.as_atom()) - } - atom!("eof_action") => { - atom_as_cell!(stream.options().eof_action().as_atom()) - } - atom!("reposition") => - atom_as_cell!(if stream.options().reposition() { - atom!("true") - } else { - atom!("false") - }), - atom!("type") => { - atom_as_cell!(stream.options().stream_type().as_property_atom()) - } - _ => { - unreachable!() - } - }; + let listing_var = self.machine_st.registers[4]; - unify!(self.machine_st, property, self.machine_st.registers[3]); - } - &SystemClauseType::StoreGlobalVar => { - let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); + unify!(self.machine_st, listing, listing_var); + Ok(()) + } - let value = self.machine_st.registers[2]; - let mut ball = Ball::new(); + #[inline(always)] + pub(crate) fn write_term(&mut self) -> CallResult { + let mut stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("write_term"), + 3, + )?; + + self.machine_st.check_stream_properties( + stream, + StreamType::Text, + None, // input + atom!("write_term"), + 3, + )?; + + let opt_err = if !stream.is_output_stream() { + Some(atom!("stream")) // 8.14.2.3 g) + } else if stream.options().stream_type() == StreamType::Binary { + Some(atom!("binary_stream")) // 8.14.2.3 h) + } else { + None + }; - ball.boundary = self.machine_st.heap.len(); + if let Some(err_atom) = opt_err { + return Err(self.machine_st.stream_permission_error( + Permission::OutputStream, + err_atom, + stream, + atom!("write_term"), + 3, + )); + } - copy_term( - CopyBallTerm::new(&mut self.machine_st.stack, &mut self.machine_st.heap, &mut ball.stub), - value, - AttrVarPolicy::DeepCopy, - ); + let printer = match self.machine_st.write_term(&self.indices.op_dir)? { + Some(printer) => printer, + None => { + // this next line is executed by + // MachineState::write_term in this case. it's + // commented here because rustc can't prove + // that it's no longer borrowed. - self.indices.global_variables.insert(key, (ball, None)); + // self.machine_st.fail = true; + return Ok(()); } - &SystemClauseType::StoreBacktrackableGlobalVar => { - let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); - let new_value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + }; - match self.indices.global_variables.get_mut(&key) { - Some((_, ref mut loc)) => match loc { - Some(ref mut value) => { - self.machine_st.trail(TrailRef::BlackboardOffset(key, *value)); - *value = new_value; - } - loc @ None => { - self.machine_st.trail(TrailRef::BlackboardEntry(key)); - *loc = Some(new_value); - } - }, - None => { - self.machine_st.trail(TrailRef::BlackboardEntry(key)); - self.indices - .global_variables - .insert(key, (Ball::new(), Some(new_value))); - } - } - } - &SystemClauseType::TermAttributedVariables => { - if self.machine_st.registers[1].is_constant() { - self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + let output = printer.print(); - let seen_vars = self.machine_st.attr_vars_of_term(self.machine_st.registers[1]); - let outcome = heap_loc_as_cell!( - iter_to_heap_list(&mut self.machine_st.heap, seen_vars.into_iter()) + match write!(&mut stream, "{}", output.result()) { + Ok(_) => {} + Err(_) => { + let stub = functor_stub(atom!("open"), 4); + let err = self.machine_st.existence_error( + ExistenceError::Stream(self.machine_st.registers[1]), ); - unify_fn!(self.machine_st, self.machine_st.registers[2], outcome); + return Err(self.machine_st.error_form(err, stub)); } - &SystemClauseType::Succeed => {} - &SystemClauseType::TermVariables => { - let a1 = self.machine_st.registers[1]; - let a2 = self.machine_st.registers[2]; + } - let stored_v = self.machine_st.store(self.machine_st.deref(a1)); + stream.flush().unwrap(); + Ok(()) + } - if stored_v.is_constant() { - self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(a2))); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } + #[inline(always)] + pub(crate) fn write_term_to_chars(&mut self) -> CallResult { + let printer = match self.machine_st.write_term(&self.indices.op_dir)? { + None => { + // this next line is executed by + // MachineState::write_term in this case. it's + // commented here because rustc can't prove + // that it's no longer borrowed. - let mut seen_set = IndexSet::new(); + // self.machine_st.fail = true; + return Ok(()); + } + Some(printer) => printer, + }; - { - let mut iter = stackless_preorder_iter(&mut self.machine_st.heap, stored_v); + let result = printer.print().result(); + let chars = put_complete_string(&mut self.machine_st.heap, &result, &mut self.machine_st.atom_tbl); - while let Some(addr) = iter.next() { - let addr = unmark_cell_bits!(addr); + let result_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - if addr.is_var() { - seen_set.insert(addr); - } - } - } + if let Some(var) = result_addr.as_var() { + self.machine_st.bind(var, chars); + } else { + unreachable!() + } - let outcome = heap_loc_as_cell!( - filtered_iter_to_heap_list( - &mut self.machine_st.heap, - seen_set.into_iter().rev(), - |heap, value| { - heap_bound_store( - heap, - heap_bound_deref(heap, value), - ).is_var() - }, - ) - ); + Ok(()) + } - unify_fn!(self.machine_st, a2, outcome); - } - &SystemClauseType::TermVariablesUnderMaxDepth => { - // Term, MaxDepth, VarList - let max_depth = cell_as_fixnum!( - self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) - ).get_num() as usize; + #[inline(always)] + pub(crate) fn scryer_prolog_version(&mut self) { + use git_version::git_version; - self.machine_st.term_variables_under_max_depth( - self.machine_st.registers[1], - max_depth, - self.machine_st.registers[3], - ); - } - &SystemClauseType::TruncateLiftedHeapTo => { - let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let lh_offset = cell_as_fixnum!(a1).get_num() as usize; + let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); + let buffer_atom = self.machine_st.atom_tbl.build_with(buffer); - self.machine_st.lifted_heap.truncate(lh_offset); - } - &SystemClauseType::UnifyWithOccursCheck => { - let a1 = self.machine_st.registers[1]; - let a2 = self.machine_st.registers[2]; + self.machine_st.unify_complete_string( + buffer_atom, + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])), + ); + } - unify_with_occurs_check!(&mut self.machine_st, a1, a2); + #[inline(always)] + pub(crate) fn crypto_random_byte(&mut self) { + let arg = self.machine_st.registers[1]; + let mut bytes: [u8; 1] = [0]; + + match rng().fill(&mut bytes) { + Ok(()) => {} + Err(_) => { + // the error payload here is of type 'Unspecified', + // which contains no information whatsoever. So, for now, + // just fail. + self.machine_st.fail = true; + return; } - &SystemClauseType::UnwindEnvironments => { - let mut e = self.machine_st.e; - let mut cp = self.machine_st.cp; + } - while e > 0 { - if self.is_reset_cont_marker(cp) { - self.machine_st.e = e; - self.machine_st.p = CodePtr::Local(cp + 1); // skip the reset marker. + let byte = Fixnum::build_with(bytes[0] as i64); + self.machine_st.unify_fixnum(byte, arg); + } - return Ok(()); - } + #[inline(always)] + pub(crate) fn crypto_data_hash(&mut self) { + let encoding = cell_as_atom!(self.machine_st.registers[2]); + let bytes = self.string_encoding_bytes(self.machine_st.registers[1], encoding); - let and_frame = self.machine_st.stack.index_and_frame(e); + let algorithm = cell_as_atom!(self.machine_st.registers[4]); - cp = and_frame.prelude.cp; - e = and_frame.prelude.e; - } + let ints_list = match algorithm { + atom!("sha3_224") => { + let mut context = Sha3_224::new(); + context.input(&bytes); + + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + context + .result() + .as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) } - &SystemClauseType::UnwindStack => { - self.machine_st.unwind_stack(); + atom!("sha3_256") => { + let mut context = Sha3_256::new(); + context.input(&bytes); + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + context + .result() + .as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) } - &SystemClauseType::WAMInstructions => { - let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[1]) - )); - - let name = self.machine_st.registers[2]; - let arity = self.machine_st.registers[3]; - - let name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(name))); - let arity = self.machine_st.store(self.machine_st.deref(arity)); - - let arity = match Number::try_from(arity) { - Ok(Number::Fixnum(n)) => n.get_num() as usize, - Ok(Number::Integer(n)) => n.to_usize().unwrap(), - _ => { - unreachable!() - } - }; - - let key = (name, arity); - - let first_idx = match module_name { - atom!("user") => self.indices.code_dir.get(&key), - _ => match self.indices.modules.get(&module_name) { - Some(module) => module.code_dir.get(&key), - None => { - let stub = functor_stub(key.0, key.1); - let err = self.machine_st.session_error( - SessionError::from(CompilationError::InvalidModuleResolution( - module_name, - )), - ); + atom!("sha3_384") => { + let mut context = Sha3_384::new(); + context.input(&bytes); - return Err(self.machine_st.error_form(err, stub)); - } - }, - }; - - let first_idx = match first_idx { - Some(ref idx) if idx.local().is_some() => { - if let Some(idx) = idx.local() { - idx - } else { - unreachable!() - } - } - _ => { - let stub = functor_stub(name, arity); - let err = self.machine_st.existence_error( - ExistenceError::Procedure(name, arity), - ); - - return Err(self.machine_st.error_form(err, stub)); - } - }; - - let mut h = self.machine_st.heap.len(); + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + context + .result() + .as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) + } + atom!("sha3_512") => { + let mut context = Sha3_512::new(); + context.input(&bytes); - let mut functors = vec![]; - let mut functor_list = vec![]; + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + context + .result() + .as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) + } + atom!("blake2s256") => { + let mut context = Blake2s::new(); + context.input(&bytes); - walk_code(&self.code_repo.code, first_idx, |instr| { - let old_len = functors.len(); - instr.enqueue_functors(h, &mut self.machine_st.arena, &mut functors); - let new_len = functors.len(); + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + context + .result() + .as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) + } + atom!("blake2b512") => { + let mut context = Blake2b::new(); + context.input(&bytes); - for index in old_len..new_len { - let functor_len = functors[index].len(); + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + context + .result() + .as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) + } + atom!("ripemd160") => { + let mut context = Ripemd160::new(); + context.input(&bytes); - match functor_len { - 0 => {} - 1 => { - functor_list.push(heap_loc_as_cell!(h)); - h += functor_len; - } - _ => { - functor_list.push(str_loc_as_cell!(h)); - h += functor_len; - } + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + context + .result() + .as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) + } + _ => { + let ints = digest::digest( + match algorithm { + atom!("sha256") => &digest::SHA256, + atom!("sha384") => &digest::SHA384, + atom!("sha512") => &digest::SHA512, + atom!("sha512_256") => &digest::SHA512_256, + _ => { + unreachable!() } - } - }); - - for functor in functors { - self.machine_st.heap.extend(functor.into_iter()); - } - - let listing = heap_loc_as_cell!( - iter_to_heap_list(&mut self.machine_st.heap, functor_list.into_iter()) + }, + &bytes, ); - let listing_var = self.machine_st.registers[4]; - - unify!(self.machine_st, listing, listing_var); + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + ints.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) } - &SystemClauseType::WriteTerm => { - let mut stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("write_term"), - 3, - )?; - - self.machine_st.check_stream_properties( - stream, - StreamType::Text, - None, // input - atom!("write_term"), - 3, - )?; + }; - let opt_err = if !stream.is_output_stream() { - Some(atom!("stream")) // 8.14.2.3 g) - } else if stream.options().stream_type() == StreamType::Binary { - Some(atom!("binary_stream")) // 8.14.2.3 h) - } else { - None - }; + unify!(self.machine_st, self.machine_st.registers[3], ints_list); + } - if let Some(err_atom) = opt_err { - return Err(self.machine_st.stream_permission_error( - Permission::OutputStream, - err_atom, - stream, - atom!("write_term"), - 3, - )); - } + #[inline(always)] + pub(crate) fn crypto_data_hkdf(&mut self) { + let encoding = cell_as_atom!(self.machine_st.registers[2]); + let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding); - let printer = match self.machine_st.write_term(&self.indices.op_dir)? { - Some(printer) => printer, - None => { - // this next line is executed by - // MachineState::write_term in this case. it's - // commented here because rustc can't prove - // that it's no longer borrowed. + let stub1_gen = || functor_stub(atom!("crypto_data_hkdf"), 4); + let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen); - // self.machine_st.fail = true; - return Ok(()); - } - }; + let stub2_gen = || functor_stub(atom!("crypto_data_hkdf"), 4); + let info = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen); - let output = printer.print(); + let algorithm = cell_as_atom!(self.machine_st.registers[5]); - match write!(&mut stream, "{}", output.result()) { - Ok(_) => {} - Err(_) => { - let stub = functor_stub(atom!("open"), 4); - let err = self.machine_st.existence_error( - ExistenceError::Stream(self.machine_st.registers[1]), - ); + let length = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[6])); - return Err(self.machine_st.error_form(err, stub)); - } + let length = match Number::try_from(length) { + Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), + Ok(Number::Integer(n)) => match n.to_usize() { + Some(u) => u, + _ => { + self.machine_st.fail = true; + return; } - - stream.flush().unwrap(); + }, + _ => { + unreachable!() } - &SystemClauseType::WriteTermToChars => { - let printer = match self.machine_st.write_term(&self.indices.op_dir)? { - None => { - // this next line is executed by - // MachineState::write_term in this case. it's - // commented here because rustc can't prove - // that it's no longer borrowed. - - // self.machine_st.fail = true; - return Ok(()); - } - Some(printer) => printer, - }; - - let result = printer.print().result(); - let chars = put_complete_string(&mut self.machine_st.heap, &result, &mut self.machine_st.atom_tbl); - - let result_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + }; - if let Some(var) = result_addr.as_var() { - self.machine_st.bind(var, chars); - } else { - unreachable!() + let ints_list = { + let digest_alg = match algorithm { + atom!("sha256") => hkdf::HKDF_SHA256, + atom!("sha384") => hkdf::HKDF_SHA384, + atom!("sha512") => hkdf::HKDF_SHA512, + _ => { + self.machine_st.fail = true; + return; } - } - &SystemClauseType::ScryerPrologVersion => { - use git_version::git_version; + }; - let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); - let buffer_atom = self.machine_st.atom_tbl.build_with(buffer); + let salt = hkdf::Salt::new(digest_alg, &salt); + let mut bytes: Vec = Vec::new(); - self.machine_st.unify_complete_string(buffer_atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); - } - &SystemClauseType::CryptoRandomByte => { - let arg = self.machine_st.registers[1]; - let mut bytes: [u8; 1] = [0]; + bytes.resize(length, 0); - match rng().fill(&mut bytes) { - Ok(()) => {} - Err(_) => { - // the error payload here is of type 'Unspecified', - // which contains no information whatsoever. So, for now, - // just fail. - self.machine_st.fail = true; - return Ok(()); - } + match salt.extract(&data).expand(&[&info[..]], MyKey(length)) { + Ok(r) => { + r.fill(&mut bytes).unwrap(); + } + _ => { + self.machine_st.fail = true; + return; } - - let byte = Fixnum::build_with(bytes[0] as i64); - self.machine_st.unify_fixnum(byte, arg); } - &SystemClauseType::CryptoDataHash => { - let encoding = cell_as_atom!(self.machine_st.registers[2]); - let bytes = self.string_encoding_bytes(self.machine_st.registers[1], encoding); - let algorithm = cell_as_atom!(self.machine_st.registers[4]); - - let ints_list = match algorithm { - atom!("sha3_224") => { - let mut context = Sha3_224::new(); - context.input(&bytes); + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + bytes + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) + }; - heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - context - .result() - .as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ) - } - atom!("sha3_256") => { - let mut context = Sha3_256::new(); - context.input(&bytes); - heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - context - .result() - .as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ) - } - atom!("sha3_384") => { - let mut context = Sha3_384::new(); - context.input(&bytes); - - heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - context - .result() - .as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ) - } - atom!("sha3_512") => { - let mut context = Sha3_512::new(); - context.input(&bytes); - - heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - context - .result() - .as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ) - } - atom!("blake2s256") => { - let mut context = Blake2s::new(); - context.input(&bytes); - - heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - context - .result() - .as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ) - } - atom!("blake2b512") => { - let mut context = Blake2b::new(); - context.input(&bytes); - - heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - context - .result() - .as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ) - } - atom!("ripemd160") => { - let mut context = Ripemd160::new(); - context.input(&bytes); - - heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - context - .result() - .as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ) - } - _ => { - let ints = digest::digest( - match algorithm { - atom!("sha256") => &digest::SHA256, - atom!("sha384") => &digest::SHA384, - atom!("sha512") => &digest::SHA512, - atom!("sha512_256") => &digest::SHA512_256, - _ => { - unreachable!() - } - }, - &bytes, - ); - - heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - ints.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ) - } - }; + unify!(self.machine_st, self.machine_st.registers[7], ints_list); + } - unify!(self.machine_st, self.machine_st.registers[3], ints_list); + #[inline(always)] + pub(crate) fn crypto_password_hash(&mut self) { + let stub1_gen = || functor_stub(atom!("crypto_password_hash"), 3); + let data = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen); + let stub2_gen = || functor_stub(atom!("crypto_password_hash"), 3); + let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen); + + let iterations = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); + + let iterations = match Number::try_from(iterations) { + Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(), + Ok(Number::Integer(n)) => match n.to_u64() { + Some(i) => i, + None => { + self.machine_st.fail = true; + return; + } + }, + _ => { + unreachable!() } - &SystemClauseType::CryptoDataHKDF => { - let encoding = cell_as_atom!(self.machine_st.registers[2]); - let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding); + }; - let stub1_gen = || functor_stub(atom!("crypto_data_hkdf"), 4); - let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen); + let ints_list = { + let mut bytes = [0u8; digest::SHA512_OUTPUT_LEN]; - let stub2_gen = || functor_stub(atom!("crypto_data_hkdf"), 4); - let info = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen); + pbkdf2::derive( + pbkdf2::PBKDF2_HMAC_SHA512, + NonZeroU32::new(iterations as u32).unwrap(), + &salt, + &data, + &mut bytes, + ); - let algorithm = cell_as_atom!(self.machine_st.registers[5]); + heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + bytes + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) + }; - let length = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[6])); + unify!(self.machine_st, self.machine_st.registers[4], ints_list); + } - let length = match Number::try_from(length) { - Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(), - Ok(Number::Integer(n)) => match n.to_usize() { - Some(u) => u, - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }, - _ => { - unreachable!() - } - }; + #[inline(always)] + pub(crate) fn crypto_data_encrypt(&mut self) { + let encoding = cell_as_atom!(self.machine_st.registers[3]); - let ints_list = { - let digest_alg = match algorithm { - atom!("sha256") => hkdf::HKDF_SHA256, - atom!("sha384") => hkdf::HKDF_SHA384, - atom!("sha512") => hkdf::HKDF_SHA512, - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }; + let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding); + let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding); - let salt = hkdf::Salt::new(digest_alg, &salt); - let mut bytes: Vec = Vec::new(); + let stub2_gen = || functor_stub(atom!("crypto_data_encrypt"), 7); + let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen); - bytes.resize(length, 0); + let stub3_gen = || functor_stub(atom!("crypto_data_encrypt"), 7); + let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[5], stub3_gen); - match salt.extract(&data).expand(&[&info[..]], MyKey(length)) { - Ok(r) => { - r.fill(&mut bytes).unwrap(); - } - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } + let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); + let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap(); + let key = aead::LessSafeKey::new(unbound_key); - heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - bytes - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ) - }; + let mut in_out = data; - unify!(self.machine_st, self.machine_st.registers[7], ints_list); + let tag = match key.seal_in_place_separate_tag( + nonce, + aead::Aad::from(aad), + &mut in_out, + ) { + Ok(d) => d, + _ => { + self.machine_st.fail = true; + return; } - &SystemClauseType::CryptoPasswordHash => { - let stub1_gen = || functor_stub(atom!("crypto_password_hash"), 3); - let data = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen); - let stub2_gen = || functor_stub(atom!("crypto_password_hash"), 3); - let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen); - - let iterations = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); - - let iterations = match Number::try_from(iterations) { - Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(), - Ok(Number::Integer(n)) => match n.to_u64() { - Some(i) => i, - None => { - self.machine_st.fail = true; - return Ok(()); - } - }, - _ => { - unreachable!() - } - }; - - let ints_list = { - let mut bytes = [0u8; digest::SHA512_OUTPUT_LEN]; + }; - pbkdf2::derive( - pbkdf2::PBKDF2_HMAC_SHA512, - NonZeroU32::new(iterations as u32).unwrap(), - &salt, - &data, - &mut bytes, - ); + let tag_list = heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + tag.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ); - heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - bytes - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ) - }; + let complete_string = { + let buffer = String::from_iter(in_out.iter().map(|b| *b as char)); + put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl) + }; - unify!(self.machine_st, self.machine_st.registers[4], ints_list); - } - &SystemClauseType::CryptoDataEncrypt => { - let encoding = cell_as_atom!(self.machine_st.registers[3]); + unify!(self.machine_st, self.machine_st.registers[6], tag_list); + unify!(self.machine_st, self.machine_st.registers[7], complete_string); + } - let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding); - let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding); + #[inline(always)] + pub(crate) fn crypto_data_decrypt(&mut self) { + let data = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.machine_st.registers[5]); - let stub2_gen = || functor_stub(atom!("crypto_data_encrypt"), 7); - let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen); + let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding); + let stub1_gen = || functor_stub(atom!("crypto_data_decrypt"), 7); - let stub3_gen = || functor_stub(atom!("crypto_data_encrypt"), 7); - let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[5], stub3_gen); + let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen); + let stub2_gen = || functor_stub(atom!("crypto_data_decrypt"), 7); + let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen); - let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); - let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap(); - let key = aead::LessSafeKey::new(unbound_key); + let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); + let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap(); + let key = aead::LessSafeKey::new(unbound_key); - let mut in_out = data; + let mut in_out = data; - let tag = match key.seal_in_place_separate_tag( - nonce, - aead::Aad::from(aad), - &mut in_out, - ) { + let complete_string = { + let decrypted_data = + match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) { Ok(d) => d, _ => { self.machine_st.fail = true; - return Ok(()); + return; } }; - let tag_list = heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - tag.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ); - - let complete_string = { - let buffer = String::from_iter(in_out.iter().map(|b| *b as char)); - put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl) - }; - - unify!(self.machine_st, self.machine_st.registers[6], tag_list); - unify!(self.machine_st, self.machine_st.registers[7], complete_string); - } - &SystemClauseType::CryptoDataDecrypt => { - let data = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); - let encoding = cell_as_atom!(self.machine_st.registers[5]); - - let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding); - let stub1_gen = || functor_stub(atom!("crypto_data_decrypt"), 7); - - let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen); - let stub2_gen = || functor_stub(atom!("crypto_data_decrypt"), 7); - let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen); + let buffer = match encoding { + atom!("octet") => String::from_iter(decrypted_data.iter().map(|b| *b as char)), + atom!("utf8") => match String::from_utf8(decrypted_data.to_vec()) { + Ok(str) => str, + _ => { + self.machine_st.fail = true; + return; + } + }, + _ => { + unreachable!() + } + }; - let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); - let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap(); - let key = aead::LessSafeKey::new(unbound_key); + put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl) + }; - let mut in_out = data; + unify!(self.machine_st, self.machine_st.registers[6], complete_string); + } - let complete_string = { - let decrypted_data = - match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) { - Ok(d) => d, - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }; + #[inline(always)] + pub(crate) fn crypto_curve_scalar_mult(&mut self) { + let curve = cell_as_atom!(self.machine_st.registers[1]); - let buffer = match encoding { - atom!("octet") => String::from_iter(decrypted_data.iter().map(|b| *b as char)), - atom!("utf8") => match String::from_utf8(decrypted_data.to_vec()) { - Ok(str) => str, - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }, - _ => { - unreachable!() - } - }; + let curve_id = match curve { + atom!("secp112r1") => Nid::SECP112R1, + atom!("secp256k1") => Nid::SECP256K1, + _ => { + unreachable!() + } + }; - put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl) - }; + let scalar = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); - unify!(self.machine_st, self.machine_st.registers[6], complete_string); + let scalar = match Number::try_from(scalar) { + Ok(Number::Fixnum(n)) => Integer::from(n.get_num()), + Ok(Number::Integer(n)) => Integer::from(&*n), + _ => { + unreachable!() } - &SystemClauseType::CryptoCurveScalarMult => { - let curve = cell_as_atom!(self.machine_st.registers[1]); + }; - let curve_id = match curve { - atom!("secp112r1") => Nid::SECP112R1, - atom!("secp256k1") => Nid::SECP256K1, - _ => { - unreachable!() - } - }; + let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 5); + let qbytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub_gen); - let scalar = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + let mut bnctx = BigNumContext::new().unwrap(); + let group = EcGroup::from_curve_name(curve_id).unwrap(); + let mut point = EcPoint::from_bytes(&group, &qbytes, &mut bnctx).unwrap(); + let scalar_bn = BigNum::from_dec_str(&scalar.to_string()).unwrap(); + let mut result = EcPoint::new(&group).unwrap(); - let scalar = match Number::try_from(scalar) { - Ok(Number::Fixnum(n)) => Integer::from(n.get_num()), - Ok(Number::Integer(n)) => Integer::from(&*n), - _ => { - unreachable!() - } - }; + result.mul(&group, &mut point, &scalar_bn, &mut bnctx).ok(); - let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 5); - let qbytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub_gen); + let mut rx = BigNum::new().unwrap(); + let mut ry = BigNum::new().unwrap(); - let mut bnctx = BigNumContext::new().unwrap(); - let group = EcGroup::from_curve_name(curve_id).unwrap(); - let mut point = EcPoint::from_bytes(&group, &qbytes, &mut bnctx).unwrap(); - let scalar_bn = BigNum::from_dec_str(&scalar.to_string()).unwrap(); - let mut result = EcPoint::new(&group).unwrap(); + result + .affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx) + .ok(); - result.mul(&group, &mut point, &scalar_bn, &mut bnctx).ok(); + let sx = put_complete_string( + &mut self.machine_st.heap, + &rx.to_dec_str().unwrap(), + &mut self.machine_st.atom_tbl, + ); - let mut rx = BigNum::new().unwrap(); - let mut ry = BigNum::new().unwrap(); + let sy = put_complete_string( + &mut self.machine_st.heap, + &ry.to_dec_str().unwrap(), + &mut self.machine_st.atom_tbl, + ); - result - .affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx) - .ok(); + unify!(self.machine_st, self.machine_st.registers[4], sx); + unify!(self.machine_st, self.machine_st.registers[5], sy); + } - let sx = put_complete_string( - &mut self.machine_st.heap, - &rx.to_dec_str().unwrap(), - &mut self.machine_st.atom_tbl, - ); + #[inline(always)] + pub(crate) fn ed25519_new_key_pair(&mut self) { + let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap(); + let complete_string = { + let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char)); + put_complete_string( + &mut self.machine_st.heap, + &buffer, + &mut self.machine_st.atom_tbl, + ) + }; - let sy = put_complete_string( - &mut self.machine_st.heap, - &ry.to_dec_str().unwrap(), - &mut self.machine_st.atom_tbl, - ); + unify!(self.machine_st, self.machine_st.registers[1], complete_string) + } - unify!(self.machine_st, self.machine_st.registers[4], sx); - unify!(self.machine_st, self.machine_st.registers[5], sy); - } - &SystemClauseType::Ed25519NewKeyPair => { - let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap(); - let complete_string = { - let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char)); - put_complete_string( - &mut self.machine_st.heap, - &buffer, - &mut self.machine_st.atom_tbl, - ) - }; + #[inline(always)] + pub(crate) fn ed25519_key_pair_public_key(&mut self) { + let bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); - unify!(self.machine_st, self.machine_st.registers[1], complete_string) + let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) { + Ok(kp) => kp, + _ => { + self.machine_st.fail = true; + return; } - &SystemClauseType::Ed25519KeyPairPublicKey => { - let bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); + }; - let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) { - Ok(kp) => kp, - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }; + let complete_string = { + let buffer = String::from_iter( + key_pair.public_key().as_ref().iter().map(|b| *b as char), + ); + + put_complete_string( + &mut self.machine_st.heap, + &buffer, + &mut self.machine_st.atom_tbl, + ) + }; - let complete_string = { - let buffer = String::from_iter( - key_pair.public_key().as_ref().iter().map(|b| *b as char), - ); + unify!(self.machine_st, self.machine_st.registers[2], complete_string); + } - put_complete_string( - &mut self.machine_st.heap, - &buffer, - &mut self.machine_st.atom_tbl, - ) - }; + #[inline(always)] + pub(crate) fn ed25519_sign(&mut self) { + let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.machine_st.registers[3]); + let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding); - unify!(self.machine_st, self.machine_st.registers[2], complete_string); + let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) { + Ok(kp) => kp, + _ => { + self.machine_st.fail = true; + return; } - &SystemClauseType::Ed25519Sign => { - let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); - let encoding = cell_as_atom!(self.machine_st.registers[3]); - let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding); + }; - let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) { - Ok(kp) => kp, - _ => { - self.machine_st.fail = true; - return Ok(()); - } - }; + let sig = key_pair.sign(&data); - let sig = key_pair.sign(&data); + let sig_list = heap_loc_as_cell!( + iter_to_heap_list( + &mut self.machine_st.heap, + sig.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ); - let sig_list = heap_loc_as_cell!( - iter_to_heap_list( - &mut self.machine_st.heap, - sig.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - ) - ); + unify!(self.machine_st, self.machine_st.registers[4], sig_list); + } - unify!(self.machine_st, self.machine_st.registers[4], sig_list); - } - &SystemClauseType::Ed25519Verify => { - let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); - let encoding = cell_as_atom!(self.machine_st.registers[3]); - let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding); - let stub_gen = || functor_stub(atom!("ed25519_verify"), 5); - let signature = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub_gen); + #[inline(always)] + pub(crate) fn ed25519_verify(&mut self) { + let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet")); + let encoding = cell_as_atom!(self.machine_st.registers[3]); + let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding); + let stub_gen = || functor_stub(atom!("ed25519_verify"), 5); + let signature = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub_gen); - let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key); + let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key); - match peer_public_key.verify(&data, &signature) { - Ok(_) => {} - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } + match peer_public_key.verify(&data, &signature) { + Ok(_) => {} + _ => { + self.machine_st.fail = true; } - &SystemClauseType::Curve25519ScalarMult => { - let stub1_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3); - let scalar_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen); - let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap()); + } + } - let stub2_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3); - let point_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen); - let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap()); + #[inline(always)] + pub(crate) fn curve25519_scalar_mult(&mut self) { + let stub1_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3); + let scalar_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen); + let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap()); - let result = scalarmult(&scalar, &point).unwrap(); + let stub2_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3); + let point_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen); + let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap()); - let string = String::from_iter(result[..].iter().map(|b| *b as char)); - let cstr = put_complete_string(&mut self.machine_st.heap, &string, &mut self.machine_st.atom_tbl); + let result = scalarmult(&scalar, &point).unwrap(); - unify!(self.machine_st, self.machine_st.registers[3], cstr); - } - &SystemClauseType::FirstNonOctet => { - let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let string = String::from_iter(result[..].iter().map(|b| *b as char)); + let cstr = put_complete_string(&mut self.machine_st.heap, &string, &mut self.machine_st.atom_tbl); - if let Some(string) = self.machine_st.value_to_str_like(addr) { - for c in string.as_str().chars() { - if c as u32 > 255 { - let non_octet = self.machine_st.atom_tbl.build_with(&c.to_string()); - self.machine_st.unify_atom(non_octet, self.machine_st.registers[2]); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - } - } + unify!(self.machine_st, self.machine_st.registers[3], cstr); + } - self.machine_st.fail = true; - return Ok(()); + #[inline(always)] + pub(crate) fn first_non_octet(&mut self) { + let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + + if let Some(string) = self.machine_st.value_to_str_like(addr) { + for c in string.as_str().chars() { + if c as u32 > 255 { + let non_octet = self.machine_st.atom_tbl.build_with(&c.to_string()); + self.machine_st.unify_atom(non_octet, self.machine_st.registers[2]); + return; + } } - &SystemClauseType::LoadHTML => { - if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - let doc = select::document::Document::from_read(string.as_str().as_bytes()).unwrap(); - let result = self.html_node_to_term(doc.nth(0).unwrap()); + } + + self.machine_st.fail = true; + } + + #[inline(always)] + pub(crate) fn load_html(&mut self) { + if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + let doc = select::document::Document::from_read(string.as_str().as_bytes()).unwrap(); + let result = self.html_node_to_term(doc.nth(0).unwrap()); + + unify!(self.machine_st, self.machine_st.registers[2], result); + } else { + self.machine_st.fail = true; + } + } + #[inline(always)] + pub(crate) fn load_xml(&mut self) { + if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + match roxmltree::Document::parse(string.as_str()) { + Ok(doc) => { + let result = self.xml_node_to_term(doc.root_element()); unify!(self.machine_st, self.machine_st.registers[2], result); - } else { - self.machine_st.fail = true; - return Ok(()); } - } - &SystemClauseType::LoadXML => { - if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - match roxmltree::Document::parse(string.as_str()) { - Ok(doc) => { - let result = self.xml_node_to_term(doc.root_element()); - unify!(self.machine_st, self.machine_st.registers[2], result); - } - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } - } else { + _ => { self.machine_st.fail = true; - return Ok(()); } } - &SystemClauseType::GetEnv => { - if let Some(key) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { - match env::var(key.as_str()) { - Ok(value) => { - let cstr = put_complete_string( - &mut self.machine_st.heap, - &value, - &mut self.machine_st.atom_tbl, - ); + } else { + self.machine_st.fail = true; + } + } - unify!(self.machine_st, self.machine_st.registers[2], cstr); - } - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } - } else { + #[inline(always)] + pub(crate) fn get_env(&mut self) { + if let Some(key) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { + match env::var(key.as_str()) { + Ok(value) => { + let cstr = put_complete_string( + &mut self.machine_st.heap, + &value, + &mut self.machine_st.atom_tbl, + ); + + unify!(self.machine_st, self.machine_st.registers[2], cstr); + } + _ => { self.machine_st.fail = true; - return Ok(()); } } - &SystemClauseType::SetEnv => { - let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap(); - let value = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap(); + } else { + self.machine_st.fail = true; + } + } + + #[inline(always)] + pub(crate) fn set_env(&mut self) { + let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap(); + let value = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap(); - env::set_var(key.as_str(), value.as_str()); + env::set_var(key.as_str(), value.as_str()); + } + + #[inline(always)] + pub(crate) fn unset_env(&mut self) { + let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap(); + env::remove_var(key.as_str()); + } + + #[inline(always)] + pub(crate) fn pid(&mut self) { + let pid = process::id(); + + match fixnum!(Number, pid as i64, &mut self.machine_st.arena) { + Number::Fixnum(pid) => { + self.machine_st.unify_fixnum(pid, self.machine_st.registers[1]); } - &SystemClauseType::UnsetEnv => { - let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap(); - env::remove_var(key.as_str()); + Number::Integer(pid) => { + self.machine_st.unify_big_int(pid, self.machine_st.registers[1]); } - &SystemClauseType::PID => { - let pid = process::id(); - - match fixnum!(Number, pid as i64, &mut self.machine_st.arena) { - Number::Fixnum(pid) => { - self.machine_st.unify_fixnum(pid, self.machine_st.registers[1]); - } - Number::Integer(pid) => { - self.machine_st.unify_big_int(pid, self.machine_st.registers[1]); - } - _ => { - unreachable!(); - } - } + _ => { + unreachable!(); } - &SystemClauseType::Shell => { - // shell executes a command in a system shell - // the code looks for a SHELL env var to do it in a UNIX-style - // if not found, the code looks for COMSPEC env var to do it in a DOS-style - // the output is printed directly to stdout - // the output status code is returned after finishing - fn command_result(machine: &mut MachineState, command: std::io::Result) { - match command { - Ok(status) => { - match status.code() { - Some(code) => { - let code = integer_as_cell!(Number::arena_from(code, &mut machine.arena)); - unify!(machine, code, machine.registers[2]); - } - _ => { - machine.fail = true; - } - } + } + } + + #[inline(always)] + pub(crate) fn shell(&mut self) { + // shell executes a command in a system shell + // the code looks for a SHELL env var to do it in a UNIX-style + // if not found, the code looks for COMSPEC env var to do it in a DOS-style + // the output is printed directly to stdout + // the output status code is returned after finishing + fn command_result(machine: &mut MachineState, command: std::io::Result) { + match command { + Ok(status) => { + match status.code() { + Some(code) => { + let code = integer_as_cell!(Number::arena_from(code, &mut machine.arena)); + unify!(machine, code, machine.registers[2]); } _ => { machine.fail = true; } } } + _ => { + machine.fail = true; + } + } + } - let command = self.machine_st.value_to_str_like(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))).unwrap(); + let command = self.machine_st.value_to_str_like( + self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])) + ).unwrap(); - match env::var("SHELL") { + match env::var("SHELL") { + Ok(value) => { + let command = process::Command::new(&value) + .arg("-c") + .arg(command.as_str()) + .status(); + command_result(&mut self.machine_st, command); + } + _ => { + match env::var("COMSPEC") { Ok(value) => { let command = process::Command::new(&value) - .arg("-c") + .arg("/C") .arg(command.as_str()) .status(); command_result(&mut self.machine_st, command); } _ => { - match env::var("COMSPEC") { - Ok(value) => { - let command = process::Command::new(&value) - .arg("/C") - .arg(command.as_str()) - .status(); - command_result(&mut self.machine_st, command); - } - _ => { - self.machine_st.fail = true; - } - } + self.machine_st.fail = true; } - }; + } } - &SystemClauseType::CharsBase64 => { - let padding = cell_as_atom!(self.machine_st.registers[3]); - let charset = cell_as_atom!(self.machine_st.registers[4]); - - let config = if padding == atom!("true") { - if charset == atom!("standard") { - base64::STANDARD - } else { - base64::URL_SAFE - } - } else { - if charset == atom!("standard") { - base64::STANDARD_NO_PAD - } else { - base64::URL_SAFE_NO_PAD - } - }; - - if self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])).is_var() { - let b64 = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap(); - let bytes = base64::decode_config(b64.as_str(), config); - - match bytes { - Ok(bs) => { - let string = String::from_iter(bs.iter().map(|b| *b as char)); - let cstr = put_complete_string( - &mut self.machine_st.heap, - &string, - &mut self.machine_st.atom_tbl, - ); + }; + } - unify!(self.machine_st, self.machine_st.registers[1], cstr); - } - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } - } else { - let mut bytes = vec![]; - for c in self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap().as_str().chars() { - if c as u32 > 255 { - let stub = functor_stub(atom!("chars_base64"), 3); - - let err = self.machine_st.type_error( - ValidType::Byte, - char_as_cell!(c), - ); + #[inline(always)] + pub(crate) fn chars_base64(&mut self) -> CallResult { + let padding = cell_as_atom!(self.machine_st.registers[3]); + let charset = cell_as_atom!(self.machine_st.registers[4]); - return Err(self.machine_st.error_form(err, stub)); - } + let config = if padding == atom!("true") { + if charset == atom!("standard") { + base64::STANDARD + } else { + base64::URL_SAFE + } + } else { + if charset == atom!("standard") { + base64::STANDARD_NO_PAD + } else { + base64::URL_SAFE_NO_PAD + } + }; - bytes.push(c as u8); - } + if self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])).is_var() { + let b64 = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap(); + let bytes = base64::decode_config(b64.as_str(), config); - let b64 = base64::encode_config(bytes, config); + match bytes { + Ok(bs) => { + let string = String::from_iter(bs.iter().map(|b| *b as char)); let cstr = put_complete_string( &mut self.machine_st.heap, - &b64, + &string, &mut self.machine_st.atom_tbl, ); - unify!(self.machine_st, self.machine_st.registers[2], cstr); + unify!(self.machine_st, self.machine_st.registers[1], cstr); + } + _ => { + self.machine_st.fail = true; + return Ok(()); } } - &SystemClauseType::LoadLibraryAsStream => { - let library_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))); + } else { + let mut bytes = vec![]; + for c in self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap().as_str().chars() { + if c as u32 > 255 { + let stub = functor_stub(atom!("chars_base64"), 3); + + let err = self.machine_st.type_error( + ValidType::Byte, + char_as_cell!(c), + ); - use crate::machine::LIBRARIES; + return Err(self.machine_st.error_form(err, stub)); + } - match LIBRARIES.borrow().get(library_name.as_str()) { - Some(library) => { - let lib_stream = Stream::from_static_string(library, &mut self.machine_st.arena); - unify!(self.machine_st, stream_as_cell!(lib_stream), self.machine_st.registers[2]); + bytes.push(c as u8); + } - let mut path_buf = machine::current_dir(); + let b64 = base64::encode_config(bytes, config); + let cstr = put_complete_string( + &mut self.machine_st.heap, + &b64, + &mut self.machine_st.atom_tbl, + ); - path_buf.push("/lib"); - path_buf.push(library_name.as_str()); + unify!(self.machine_st, self.machine_st.registers[2], cstr); + } - let library_path_str = path_buf.to_str().unwrap(); - let library_path = self.machine_st.atom_tbl.build_with(library_path_str); + Ok(()) + } - self.machine_st.unify_atom(library_path, self.machine_st.registers[3]); - } - None => { - let stub = functor_stub(atom!("load"), 1); - let err = self.machine_st.existence_error( - ExistenceError::ModuleSource(ModuleSource::Library(library_name)) - ); + #[inline(always)] + pub(crate) fn load_library_as_stream(&mut self) -> CallResult { + let library_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref( + self.machine_st.registers[1] + ))); - return Err(self.machine_st.error_form(err, stub)); - } - } - } - &SystemClauseType::DevourWhitespace => { - let stream = self.machine_st.get_stream_or_alias( - self.machine_st.registers[1], - &self.indices.stream_aliases, - atom!("$devour_whitespace"), - 1, - )?; + use crate::machine::LIBRARIES; - match self.machine_st.devour_whitespace(stream) { - Ok(false) => { // not at EOF. - } - _ => { - self.machine_st.fail = true; - return Ok(()); - } - } - } - &SystemClauseType::IsSTOEnabled => { - if self.machine_st.unify_fn as usize == MachineState::unify_with_occurs_check as usize { - self.machine_st.unify_atom(atom!("true"), self.machine_st.registers[1]); - } else if self.machine_st.unify_fn as usize - == MachineState::unify_with_occurs_check_with_error as usize - { - self.machine_st.unify_atom(atom!("error"), self.machine_st.registers[1]); - } else { - self.machine_st.unify_atom(atom!("false"), self.machine_st.registers[1]); - } + match LIBRARIES.borrow().get(library_name.as_str()) { + Some(library) => { + let lib_stream = Stream::from_static_string(library, &mut self.machine_st.arena); + unify!(self.machine_st, stream_as_cell!(lib_stream), self.machine_st.registers[2]); + + let mut path_buf = machine::current_dir(); + + path_buf.push("/lib"); + path_buf.push(library_name.as_str()); + + let library_path_str = path_buf.to_str().unwrap(); + let library_path = self.machine_st.atom_tbl.build_with(library_path_str); + + self.machine_st.unify_atom(library_path, self.machine_st.registers[3]); } - &SystemClauseType::SetSTOAsUnify => { - self.machine_st.unify_fn = MachineState::unify_with_occurs_check; - self.machine_st.bind_fn = MachineState::bind_with_occurs_check_wrapper; + None => { + let stub = functor_stub(atom!("load"), 1); + let err = self.machine_st.existence_error( + ExistenceError::ModuleSource(ModuleSource::Library(library_name)) + ); + + return Err(self.machine_st.error_form(err, stub)); } - &SystemClauseType::SetNSTOAsUnify => { - self.machine_st.unify_fn = MachineState::unify; - self.machine_st.bind_fn = MachineState::bind; + } + + Ok(()) + } + + #[inline(always)] + pub(crate) fn devour_whitespace(&mut self) -> CallResult { + let stream = self.machine_st.get_stream_or_alias( + self.machine_st.registers[1], + &self.indices.stream_aliases, + atom!("$devour_whitespace"), + 1, + )?; + + match self.machine_st.devour_whitespace(stream) { + Ok(false) => { // not at EOF. } - &SystemClauseType::SetSTOWithErrorAsUnify => { - self.machine_st.unify_fn = MachineState::unify_with_occurs_check_with_error; - self.machine_st.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper; + _ => { + self.machine_st.fail = true; } - &SystemClauseType::HomeDirectory => { - let path = match dirs_next::home_dir() { - Some(path) => path, - None => { - self.machine_st.fail = true; - return Ok(()); - } - }; + } - if path.is_dir() { - if let Some(path) = path.to_str() { - let path_string = put_complete_string( - &mut self.machine_st.heap, - path, - &mut self.machine_st.atom_tbl, - ); + Ok(()) + } - unify!(self.machine_st, self.machine_st.registers[1], path_string); - return return_from_clause!(self.machine_st.last_call, self.machine_st); - } - } + #[inline(always)] + pub(crate) fn is_sto_enabled(&mut self) { + if self.machine_st.unify_fn as usize == MachineState::unify_with_occurs_check as usize { + self.machine_st.unify_atom(atom!("true"), self.machine_st.registers[1]); + } else if self.machine_st.unify_fn as usize + == MachineState::unify_with_occurs_check_with_error as usize + { + self.machine_st.unify_atom(atom!("error"), self.machine_st.registers[1]); + } else { + self.machine_st.unify_atom(atom!("false"), self.machine_st.registers[1]); + } + } + + #[inline(always)] + pub(crate) fn set_sto_as_unify(&mut self) { + self.machine_st.unify_fn = MachineState::unify_with_occurs_check; + self.machine_st.bind_fn = MachineState::bind_with_occurs_check_wrapper; + } + + #[inline(always)] + pub(crate) fn set_nsto_as_unify(&mut self) { + self.machine_st.unify_fn = MachineState::unify; + self.machine_st.bind_fn = MachineState::bind; + } + + #[inline(always)] + pub(crate) fn set_sto_with_error_as_unify(&mut self) { + self.machine_st.unify_fn = MachineState::unify_with_occurs_check_with_error; + self.machine_st.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper; + } + #[inline(always)] + pub(crate) fn home_directory(&mut self) { + let path = match dirs_next::home_dir() { + Some(path) => path, + None => { self.machine_st.fail = true; + return; } - &SystemClauseType::DebugHook => { - self.machine_st.fail = false; + }; + + if path.is_dir() { + if let Some(path) = path.to_str() { + let path_string = put_complete_string( + &mut self.machine_st.heap, + path, + &mut self.machine_st.atom_tbl, + ); + + unify!(self.machine_st, self.machine_st.registers[1], path_string); + return; } - &SystemClauseType::PopCount => { - let number = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); - let pop_count = integer_as_cell!(match Number::try_from(number) { - Ok(Number::Fixnum(n)) => { - Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64)) - } - Ok(Number::Integer(n)) => { - Number::arena_from(n.count_ones().unwrap(), &mut self.machine_st.arena) - } - _ => { - unreachable!() - } - }); + } + + self.machine_st.fail = true; + } - unify!(self.machine_st, self.machine_st.registers[2], pop_count); + pub(crate) fn debug_hook(&mut self) { + } + + #[inline(always)] + pub(crate) fn pop_count(&mut self) { + let number = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])); + let pop_count = integer_as_cell!(match Number::try_from(number) { + Ok(Number::Fixnum(n)) => { + Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64)) } - }; + Ok(Number::Integer(n)) => { + Number::arena_from(n.count_ones().unwrap(), &mut self.machine_st.arena) + } + _ => { + unreachable!() + } + }); - return_from_clause!(self.machine_st.last_call, self.machine_st) + unify!(self.machine_st, self.machine_st.registers[2], pop_count); } pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Atom { let datetime: DateTime = system_time.into(); let mut fstr = "[".to_string(); - const SPECIFIERS: [&'static str; 19] = [ - "Y", "m", "d", "H", "M", "S", "y", "b", "B", "a", "A", "w", "u", "U", "W", "j", "D", - "x", "v", + const SPECIFIERS: [char; 19] = [ + 'Y', 'm', 'd', 'H', 'M', 'S', 'y', 'b', 'B', 'a', 'A', 'w', 'u', 'U', 'W', 'j', 'D', + 'x', 'v', ]; for spec in SPECIFIERS { diff --git a/src/macros.rs b/src/macros.rs index 90fed110..0b83bbb7 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,9 +1,3 @@ -macro_rules! interm { - ($n: expr) => { - ArithmeticTerm::Interm($n) - }; -} - /* A simple macro to count the arguments in a variadic list * of token trees. */ @@ -524,6 +518,35 @@ macro_rules! functor_term { ); } +macro_rules! compare_number_instr { + ($cmp: expr, $at_1: expr, $at_2: expr) => {{ + $cmp.set_terms($at_1, $at_2); + call_clause!(ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp)), 0) + }}; +} + +macro_rules! call_clause { + ($clause_type:expr, $pvs:expr) => {{ + let mut instr = $clause_type.to_instr(); + instr.perm_vars_mut().map(|pvs| *pvs = $pvs); + instr + }}; +} + +macro_rules! call_clause_by_default { + ($clause_type:expr, $pvs:expr) => {{ + let mut instr = $clause_type.to_instr().to_default(); + instr.perm_vars_mut().map(|pvs| *pvs = $pvs); + instr + }}; +} + +macro_rules! interm { + ($n: expr) => { + ArithmeticTerm::Interm($n) + }; +} + macro_rules! ar_reg { ($r: expr) => { ArithmeticTerm::Reg($r) @@ -545,228 +568,17 @@ macro_rules! index_store { ($code_dir:expr, $op_dir:expr, $modules:expr) => { IndexStore { code_dir: $code_dir, - extensible_predicates: ExtensiblePredicates::new(), - local_extensible_predicates: LocalExtensiblePredicates::new(), - global_variables: GlobalVarDir::new(), - meta_predicates: MetaPredicateDir::new(), + extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()), + local_extensible_predicates: LocalExtensiblePredicates::with_hasher(FxBuildHasher::default()), + global_variables: GlobalVarDir::with_hasher(FxBuildHasher::default()), + meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()), modules: $modules, op_dir: $op_dir, streams: StreamDir::new(), - stream_aliases: StreamAliasDir::new(), - } - }; -} - -macro_rules! is_atom { - ($r:expr) => { - call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtom($r)), 1, 0) - }; -} - -macro_rules! is_atomic { - ($r:expr) => { - call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtomic($r)), 1, 0) - }; -} - -macro_rules! is_integer { - ($r:expr) => { - call_clause!(ClauseType::Inlined(InlinedClauseType::IsInteger($r)), 1, 0) - }; -} - -macro_rules! is_compound { - ($r:expr) => { - call_clause!(ClauseType::Inlined(InlinedClauseType::IsCompound($r)), 1, 0) - }; -} - -macro_rules! is_float { - ($r:expr) => { - call_clause!(ClauseType::Inlined(InlinedClauseType::IsFloat($r)), 1, 0) - }; -} - -macro_rules! is_rational { - ($r:expr) => { - call_clause!(ClauseType::Inlined(InlinedClauseType::IsRational($r)), 1, 0) - }; -} - -macro_rules! is_number { - ($r:expr) => { - call_clause!(ClauseType::Inlined(InlinedClauseType::IsNumber($r)), 1, 0) - }; -} - -macro_rules! is_nonvar { - ($r:expr) => { - call_clause!(ClauseType::Inlined(InlinedClauseType::IsNonVar($r)), 1, 0) - }; -} - -macro_rules! is_var { - ($r:expr) => { - call_clause!(ClauseType::Inlined(InlinedClauseType::IsVar($r)), 1, 0) - }; -} - -macro_rules! call_clause { - ($ct:expr, $arity:expr, $pvs:expr) => { - Line::Control(ControlInstruction::CallClause( - $ct, $arity, $pvs, false, false, - )) - }; - ($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => { - Line::Control(ControlInstruction::CallClause( - $ct, $arity, $pvs, $lco, false, - )) - }; -} - -macro_rules! call_clause_by_default { - ($ct:expr, $arity:expr, $pvs:expr) => { - Line::Control(ControlInstruction::CallClause( - $ct, $arity, $pvs, false, true, - )) - }; - ($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => { - Line::Control(ControlInstruction::CallClause( - $ct, $arity, $pvs, $lco, true, - )) - }; -} - -macro_rules! proceed { - () => { - Line::Control(ControlInstruction::Proceed) - }; -} - -macro_rules! is_call { - ($r:expr, $at:expr) => { - call_clause!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0) - }; -} - -macro_rules! is_call_by_default { - ($r:expr, $at:expr) => { - call_clause_by_default!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0) - }; -} - -macro_rules! set_cp { - ($r:expr) => { - call_clause!(ClauseType::System(SystemClauseType::SetCutPoint($r)), 1, 0) - }; -} - -macro_rules! succeed { - () => { - call_clause!(ClauseType::System(SystemClauseType::Succeed), 0, 0) - }; -} - -macro_rules! fail { - () => { - call_clause!(ClauseType::System(SystemClauseType::Fail), 0, 0) - }; -} - -macro_rules! compare_number_instr { - ($cmp: expr, $at_1: expr, $at_2: expr) => {{ - let ct = ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp, $at_1, $at_2)); - call_clause!(ct, 2, 0) - }}; -} - -macro_rules! jmp_call { - ($arity:expr, $offset:expr, $pvs:expr) => { - Line::Control(ControlInstruction::JmpBy($arity, $offset, $pvs, false)) - }; -} - -macro_rules! return_from_clause { - ($lco:expr, $machine_st:expr) => {{ - if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p { - return Ok(()); - } - - if $lco { - $machine_st.p = CodePtr::Local($machine_st.cp); - } else { - $machine_st.p += 1; - } - - Ok(()) - }}; -} - -macro_rules! dir_entry { - ($idx:expr) => { - LocalCodePtr::DirEntry($idx) - }; -} - -macro_rules! put_constant { - ($lvl:expr, $cons:expr, $r:expr) => { - QueryInstruction::PutConstant($lvl, $cons, $r) - }; -} - -macro_rules! get_level_and_unify { - ($r: expr) => { - Line::Cut(CutInstruction::GetLevelAndUnify($r)) - }; -} - -/* -macro_rules! unwind_protect { - ($e: expr, $protected: expr) => { - match $e { - Err(e) => { - $protected; - return Err(e); - } - _ => {} - } - }; -} -*/ -/* -macro_rules! discard_result { - ($f: expr) => { - match $f { - _ => (), + stream_aliases: StreamAliasDir::with_hasher(FxBuildHasher::default()), } }; } -*/ - -macro_rules! try_or_fail { - ($s:expr, $e:expr) => {{ - match $e { - Ok(val) => val, - Err(msg) => { - $s.throw_exception(msg); - return; - } - } - }}; -} - -macro_rules! try_or_fail_gen { - ($s:expr, $e:expr) => {{ - match $e { - Ok(val) => val, - Err(msg_fn) => { - let e = msg_fn($s); - $s.throw_exception(e); - return; - } - } - }}; -} macro_rules! unify { ($machine_st:expr, $($value:expr),*) => {{ diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 1bbde9c2..3db3ca0e 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -13,6 +13,7 @@ use std::vec::Vec; use rug::{Integer, Rational}; +use fxhash::FxBuildHasher; use indexmap::IndexMap; use modular_bitfield::error::OutOfBounds; use modular_bitfield::prelude::*; @@ -286,7 +287,7 @@ impl OpDesc { } // name and fixity -> operator type and precedence. -pub type OpDir = IndexMap<(Atom, Fixity), OpDesc>; +pub type OpDir = IndexMap<(Atom, Fixity), OpDesc, FxBuildHasher>; #[derive(Debug, Clone, Copy)] pub struct MachineFlags { @@ -329,7 +330,7 @@ impl Default for DoubleQuotes { } pub fn default_op_dir() -> OpDir { - let mut op_dir = OpDir::new(); + let mut op_dir = OpDir::with_hasher(FxBuildHasher::default()); op_dir.insert( (atom!(":-"), Fixity::In), diff --git a/src/read.rs b/src/read.rs index eced1d72..def66b10 100644 --- a/src/read.rs +++ b/src/read.rs @@ -12,6 +12,8 @@ use crate::machine::streams::*; use crate::parser::char_reader::*; use crate::types::*; +use fxhash::FxBuildHasher; + use rustyline::error::ReadlineError; use rustyline::{Cmd, Config, Editor, KeyEvent}; @@ -257,7 +259,7 @@ impl<'a, 'b> TermWriter<'a, 'b> { heap, atom_tbl, queue: SubtermDeque::new(), - var_dict: HeapVarDict::new(), + var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()), } } diff --git a/src/targets.rs b/src/targets.rs index 0d4ac6d6..cbb469f9 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -1,39 +1,41 @@ use crate::parser::ast::*; use crate::atom_table::*; -use crate::clause_types::*; use crate::forms::*; use crate::instructions::*; use crate::iterators::*; use crate::types::*; +pub(crate) struct FactInstruction; +pub(crate) struct QueryInstruction; + pub(crate) trait CompilationTarget<'a> { type Iterator: Iterator>; fn iter(term: &'a Term) -> Self::Iterator; - fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Self; - fn to_list(lvl: Level, r: RegType) -> Self; - fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self; + fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction; + fn to_list(lvl: Level, r: RegType) -> Instruction; + fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction; - fn to_void(num_subterms: usize) -> Self; - fn is_void_instr(&self) -> bool; + fn to_void(num_subterms: usize) -> Instruction; + fn is_void_instr(instr: &Instruction) -> bool; - fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self; + fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction; - fn incr_void_instr(&mut self); + fn incr_void_instr(instr: &mut Instruction); - fn constant_subterm(literal: Literal) -> Self; + fn constant_subterm(literal: Literal) -> Instruction; - fn argument_to_variable(r: RegType, r: usize) -> Self; - fn argument_to_value(r: RegType, val: usize) -> Self; + fn argument_to_variable(r: RegType, r: usize) -> Instruction; + fn argument_to_value(r: RegType, val: usize) -> Instruction; - fn move_to_register(r: RegType, val: usize) -> Self; + fn move_to_register(r: RegType, val: usize) -> Instruction; - fn subterm_to_variable(r: RegType) -> Self; - fn subterm_to_value(r: RegType) -> Self; + fn subterm_to_variable(r: RegType) -> Instruction; + fn subterm_to_value(r: RegType) -> Instruction; - fn clause_arg_to_instr(r: RegType) -> Self; + fn clause_arg_to_instr(r: RegType) -> Instruction; } impl<'a> CompilationTarget<'a> for FactInstruction { @@ -43,66 +45,66 @@ impl<'a> CompilationTarget<'a> for FactInstruction { breadth_first_iter(term, false) // do not iterate over the root clause if one exists. } - fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Self { - FactInstruction::GetConstant(lvl, HeapCellValue::from(constant), reg) + fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction { + Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg) } - fn to_structure(ct: ClauseType, arity: usize, reg: RegType) -> Self { - FactInstruction::GetStructure(ct, arity, reg) + fn to_structure(name: Atom, arity: usize, reg: RegType) -> Instruction { + Instruction::GetStructure(name, arity, reg) } - fn to_list(lvl: Level, reg: RegType) -> Self { - FactInstruction::GetList(lvl, reg) + fn to_list(lvl: Level, reg: RegType) -> Instruction { + Instruction::GetList(lvl, reg) } - fn to_void(num_subterms: usize) -> Self { - FactInstruction::UnifyVoid(num_subterms) + fn to_void(num_subterms: usize) -> Instruction { + Instruction::UnifyVoid(num_subterms) } - fn is_void_instr(&self) -> bool { - match self { - &FactInstruction::UnifyVoid(_) => true, + fn is_void_instr(instr: &Instruction) -> bool { + match instr { + &Instruction::UnifyVoid(_) => true, _ => false, } } - fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self { - FactInstruction::GetPartialString(lvl, string, r, has_tail) + fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction { + Instruction::GetPartialString(lvl, string, r, has_tail) } - fn incr_void_instr(&mut self) { - match self { - &mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1, + fn incr_void_instr(instr: &mut Instruction) { + match instr { + &mut Instruction::UnifyVoid(ref mut incr) => *incr += 1, _ => {} } } - fn constant_subterm(constant: Literal) -> Self { - FactInstruction::UnifyConstant(HeapCellValue::from(constant)) + fn constant_subterm(constant: Literal) -> Instruction { + Instruction::UnifyConstant(HeapCellValue::from(constant)) } - fn argument_to_variable(arg: RegType, val: usize) -> Self { - FactInstruction::GetVariable(arg, val) + fn argument_to_variable(arg: RegType, val: usize) -> Instruction { + Instruction::GetVariable(arg, val) } - fn move_to_register(arg: RegType, val: usize) -> Self { - FactInstruction::GetVariable(arg, val) + fn move_to_register(arg: RegType, val: usize) -> Instruction { + Instruction::GetVariable(arg, val) } - fn argument_to_value(arg: RegType, val: usize) -> Self { - FactInstruction::GetValue(arg, val) + fn argument_to_value(arg: RegType, val: usize) -> Instruction { + Instruction::GetValue(arg, val) } - fn subterm_to_variable(val: RegType) -> Self { - FactInstruction::UnifyVariable(val) + fn subterm_to_variable(val: RegType) -> Instruction { + Instruction::UnifyVariable(val) } - fn subterm_to_value(val: RegType) -> Self { - FactInstruction::UnifyValue(val) + fn subterm_to_value(val: RegType) -> Instruction { + Instruction::UnifyValue(val) } - fn clause_arg_to_instr(val: RegType) -> Self { - FactInstruction::UnifyVariable(val) + fn clause_arg_to_instr(val: RegType) -> Instruction { + Instruction::UnifyVariable(val) } } @@ -113,65 +115,65 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { post_order_iter(term) } - fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self { - QueryInstruction::PutStructure(ct, arity, r) + fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction { + Instruction::PutStructure(name, arity, r) } - fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Self { - QueryInstruction::PutConstant(lvl, HeapCellValue::from(constant), reg) + fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction { + Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg) } - fn to_list(lvl: Level, reg: RegType) -> Self { - QueryInstruction::PutList(lvl, reg) + fn to_list(lvl: Level, reg: RegType) -> Instruction { + Instruction::PutList(lvl, reg) } - fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self { - QueryInstruction::PutPartialString(lvl, string, r, has_tail) + fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction { + Instruction::PutPartialString(lvl, string, r, has_tail) } - fn to_void(subterms: usize) -> Self { - QueryInstruction::SetVoid(subterms) + fn to_void(subterms: usize) -> Instruction { + Instruction::SetVoid(subterms) } - fn is_void_instr(&self) -> bool { - match self { - &QueryInstruction::SetVoid(_) => true, + fn is_void_instr(instr: &Instruction) -> bool { + match instr { + &Instruction::SetVoid(_) => true, _ => false, } } - fn incr_void_instr(&mut self) { - match self { - &mut QueryInstruction::SetVoid(ref mut incr) => *incr += 1, + fn incr_void_instr(instr: &mut Instruction) { + match instr { + &mut Instruction::SetVoid(ref mut incr) => *incr += 1, _ => {} } } - fn constant_subterm(constant: Literal) -> Self { - QueryInstruction::SetConstant(HeapCellValue::from(constant)) + fn constant_subterm(constant: Literal) -> Instruction { + Instruction::SetConstant(HeapCellValue::from(constant)) } - fn argument_to_variable(arg: RegType, val: usize) -> Self { - QueryInstruction::PutVariable(arg, val) + fn argument_to_variable(arg: RegType, val: usize) -> Instruction { + Instruction::PutVariable(arg, val) } - fn move_to_register(arg: RegType, val: usize) -> Self { - QueryInstruction::GetVariable(arg, val) + fn move_to_register(arg: RegType, val: usize) -> Instruction { + Instruction::GetVariable(arg, val) } - fn argument_to_value(arg: RegType, val: usize) -> Self { - QueryInstruction::PutValue(arg, val) + fn argument_to_value(arg: RegType, val: usize) -> Instruction { + Instruction::PutValue(arg, val) } - fn subterm_to_variable(val: RegType) -> Self { - QueryInstruction::SetVariable(val) + fn subterm_to_variable(val: RegType) -> Instruction { + Instruction::SetVariable(val) } - fn subterm_to_value(val: RegType) -> Self { - QueryInstruction::SetValue(val) + fn subterm_to_value(val: RegType) -> Instruction { + Instruction::SetValue(val) } - fn clause_arg_to_instr(val: RegType) -> Self { - QueryInstruction::SetValue(val) + fn clause_arg_to_instr(val: RegType) -> Instruction { + Instruction::SetValue(val) } } diff --git a/src/toplevel.pl b/src/toplevel.pl index 18a6f3e8..b72e0ed1 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -158,7 +158,7 @@ instruction_match(Term, VarList) :- ( Item == user -> catch(load(user_input), E, print_exception_with_check(E)) ; - submit_query_and_print_results(consult(Item), []) + submit_query_and_print_results(consult(Item), []) ) ; catch(type_error(atom, Item, repl/0), E, @@ -184,7 +184,7 @@ submit_query_and_print_results_(_, _) :- submit_query_and_print_results(Term0, VarList) :- ( functor(Term0, call, _) -> Term = Term0 % prevent pre-mature expansion of incomplete goal - % in the first argument, which is done by call/N + % in the first argument, which is done by call/N ; expand_goal(Term0, user, Term) ), setup_call_cleanup(bb_put('$first_answer', true), diff --git a/src/write.rs b/src/write.rs index 455cc72b..38f8b139 100644 --- a/src/write.rs +++ b/src/write.rs @@ -1,6 +1,5 @@ use crate::arena::*; use crate::atom_table::*; -use crate::clause_types::*; use crate::forms::*; use crate::instructions::*; use crate::machine::loader::CompilationTarget; @@ -15,18 +14,7 @@ use ordered_float::OrderedFloat; use std::fmt; -impl fmt::Display for LocalCodePtr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p), - LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"), - // LocalCodePtr::IndexingBuf(p, o, i) => { - // write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i) - // } - } - } -} - +/* impl fmt::Display for REPLCodePtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -77,6 +65,7 @@ impl fmt::Display for REPLCodePtr { } } } +*/ impl fmt::Display for IndexPtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -97,6 +86,7 @@ impl fmt::Display for CompilationTarget { } } +/* impl fmt::Display for FactInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -221,6 +211,7 @@ impl fmt::Display for ClauseType { } } } +*/ impl fmt::Display for HeapCellValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -269,82 +260,10 @@ impl fmt::Display for HeapCellValue { unreachable!() } ) - /* - match self { - &HeapCellValue::Addr(ref addr) => write!(f, "{}", addr), - &HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()), - &HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref), - &HeapCellValue::Integer(ref n) => write!(f, "{}", n), - &HeapCellValue::LoadStatePayload(_) => write!(f, "LoadStatePayload"), - &HeapCellValue::Rational(ref n) => write!(f, "{}", n), - &HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!( - f, - "{}/{} (op, priority: {}, spec: {})", - name.as_str(), - arity, - cell.prec(), - cell.assoc() - ), - &HeapCellValue::NamedStr(arity, ref name, None) => { - write!(f, "{}/{}", name.as_str(), arity) - } - &HeapCellValue::PartialString(ref pstr, has_tail) => { - write!( - f, - "pstr ( buf: \"{}\", has_tail({}) )", - pstr.as_str_from(0), - has_tail, - ) - } - &HeapCellValue::Stream(ref stream) => { - write!(f, "$stream({})", stream.as_ptr() as usize) - } - &HeapCellValue::TcpListener(ref tcp_listener) => { - write!(f, "$tcp_listener({})", tcp_listener.local_addr().unwrap()) - } - } - */ } } /* -impl fmt::Display for DBRef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &DBRef::NamedPred(ref name, arity, _) => write!(f, "db_ref:named:{}/{}", name, arity), - &DBRef::Op(priority, spec, ref name, ..) => { - write!(f, "db_ref:op({}, {}, {})", priority, spec, name) - } - } - } -} -*/ - -/* -impl fmt::Display for Addr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &Addr::Char(c) => write!(f, "Addr::Char({})", c), - &Addr::EmptyList => write!(f, "Addr::EmptyList"), - &Addr::Fixnum(n) => write!(f, "Addr::Fixnum({})", n), - &Addr::Float(fl) => write!(f, "Addr::Float({})", fl), - &Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp), - &Addr::Con(ref c) => write!(f, "Addr::Con({})", c), - &Addr::Lis(l) => write!(f, "Addr::Lis({})", l), - &Addr::LoadStatePayload(s) => write!(f, "Addr::LoadStatePayload({})", s), - &Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h), - &Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h), - &Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc), - &Addr::Str(s) => write!(f, "Addr::Str({})", s), - &Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n), - &Addr::Stream(stream) => write!(f, "Addr::Stream({})", stream), - &Addr::TcpListener(tcp_listener) => write!(f, "Addr::TcpListener({})", tcp_listener), - &Addr::Usize(cp) => write!(f, "Addr::Usize({})", cp), - } - } -} -*/ - impl fmt::Display for ControlInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -375,6 +294,7 @@ impl fmt::Display for ControlInstruction { } } } +*/ impl fmt::Display for IndexedChoiceInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -386,6 +306,7 @@ impl fmt::Display for IndexedChoiceInstruction { } } +/* impl fmt::Display for ChoiceInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -443,6 +364,7 @@ impl fmt::Display for ChoiceInstruction { } } } +*/ impl fmt::Display for IndexingCodePtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -602,6 +524,7 @@ impl fmt::Display for IndexingLine { } } +/* impl fmt::Display for Line { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -625,17 +548,8 @@ impl fmt::Display for Line { } } } - -impl fmt::Display for Number { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Number::Float(fl) => write!(f, "{}", fl), - Number::Integer(n) => write!(f, "{}", n), - Number::Rational(r) => write!(f, "{}", r), - Number::Fixnum(n) => write!(f, "{}", n.get_num()), - } - } -} +*/ +/* impl fmt::Display for ArithmeticTerm { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -745,7 +659,8 @@ impl fmt::Display for CutInstruction { } } } - +*/ +/* impl fmt::Display for Level { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -754,3 +669,4 @@ impl fmt::Display for Level { } } } +*/ -- cgit v1.2.3-70-g09d2 From cf1e315d72c224fc64d80e38e5493bcc1b846496 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 6 Jan 2022 21:29:15 -0700 Subject: add parser tests --- src/tests/bom.rs | 37 ++++++++++++++++ src/tests/parse_tokens.rs | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 src/tests/bom.rs create mode 100644 src/tests/parse_tokens.rs diff --git a/src/tests/bom.rs b/src/tests/bom.rs new file mode 100644 index 00000000..9a394d63 --- /dev/null +++ b/src/tests/bom.rs @@ -0,0 +1,37 @@ +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::parser::lexer::{Lexer, Token}; + +#[test] +fn valid_token() { + let stream = parsing_stream("valid text".as_bytes()); + assert!(stream.is_ok()); +} + +#[test] +fn empty_stream() { + let bytes: &[u8] = &[]; + assert!(parsing_stream(bytes).is_ok()); +} + +#[test] +fn skip_utf8_bom() { + let mut machine_st = MachineState::new(); + let bytes: &[u8] = &[0xEF, 0xBB, 0xBF, '4' as u8, '\n' as u8]; + let stream = parsing_stream(bytes).expect("valid stream"); + let mut lexer = Lexer::new(stream, &mut machine_st); + match lexer.next_token() { + Ok(Token::Literal(Literal::Fixnum(Fixnum::build_with(4)))) => (), + _ => assert!(false), + } +} + +#[test] +fn invalid_utf16_bom() { + let bytes: &[u8] = &[0xFF, 0xFE, 'a' as u8, '\n' as u8]; + let stream = parsing_stream(bytes); + match stream { + Err(ParserError::Utf8Error(0, 0)) => (), + _ => assert!(false), + } +} diff --git a/src/tests/parse_tokens.rs b/src/tests/parse_tokens.rs new file mode 100644 index 00000000..a4763b4d --- /dev/null +++ b/src/tests/parse_tokens.rs @@ -0,0 +1,109 @@ +use crate::atom_table::*; +use crate::parser::ast::*; +use crate::parser::lexer::{Lexer, Token}; + +fn read_all_tokens(text: &str) -> Result, ParserError> { + let mut machine_st = MachineState::new(); + let stream = parsing_stream(text.as_bytes())?; + let mut lexer = Lexer::new(stream, &mut machine_st); + + let mut tokens = Vec::new(); + while !lexer.eof()? { + let token = lexer.next_token()?; + tokens.push(token); + } + Ok(tokens) +} + +#[test] +fn empty_multiline_comment() -> Result<(), ParserError> { + let tokens = read_all_tokens("/**/ 4\n")?; + assert_eq!(tokens, [Token::Literal(Literal::Fixnum(Fixnum::build_with(4)))]); + Ok(()) +} + +#[test] +fn any_char_multiline_comment() -> Result<(), ParserError> { + let tokens = read_all_tokens("/* █╗╚═══╝ © */ 4\n")?; + assert_eq!(tokens, [Token::Literal(Literal::Fixnum(4))]); + Ok(()) +} + +#[test] +fn simple_char() -> Result<(), ParserError> { + let tokens = read_all_tokens("'a'\n")?; + assert_eq!(tokens, [Token::Literal(Literal::Char('a'))]); + Ok(()) +} + +#[test] +fn char_with_meta_seq() -> Result<(), ParserError> { + let tokens = read_all_tokens(r#"'\\' '\'' '\"' '\`' "#)?; // use literal string so \ are escaped + assert_eq!( + tokens, + [ + Token::Literal(Literal::Char('\\')), + Token::Literal(Literal::Char('\'')), + Token::Literal(Literal::Char('"')), + Token::Literal(Literal::Char('`')) + ] + ); + Ok(()) +} + +#[test] +fn char_with_control_seq() -> Result<(), ParserError> { + let tokens = read_all_tokens(r"'\a' '\b' '\r' '\f' '\t' '\n' '\v' ")?; + assert_eq!( + tokens, + [ + Token::Literal(Literal::Char('\u{07}')), + Token::Literal(Literal::Char('\u{08}')), + Token::Literal(Literal::Char('\r')), + Token::Literal(Literal::Char('\u{0c}')), + Token::Literal(Literal::Char('\t')), + Token::Literal(Literal::Char('\n')), + Token::Literal(Literal::Char('\u{0b}')), + ] + ); + Ok(()) +} + +#[test] +fn char_with_octseq() -> Result<(), ParserError> { + let tokens = read_all_tokens(r"'\60433\' ")?; + assert_eq!(tokens, [Token::Literal(Literal::Char('愛'))]); // Japanese character + Ok(()) +} + +#[test] +fn char_with_octseq_0() -> Result<(), ParserError> { + let tokens = read_all_tokens(r"'\0\' ")?; + assert_eq!(tokens, [Token::Literal(Literal::Char('\u{0000}'))]); + Ok(()) +} + +#[test] +fn char_with_hexseq() -> Result<(), ParserError> { + let tokens = read_all_tokens(r"'\x2124\' ")?; + assert_eq!(tokens, [Token::Literal(Literal::Char('ℤ'))]); // Z math symbol + Ok(()) +} + +#[test] +fn char_with_hexseq_invalid() { + assert!(read_all_tokens(r"'\x\' ").is_err()); +} + +#[test] +fn empty() -> Result<(), ParserError> { + let tokens = read_all_tokens("")?; + assert!(tokens.is_empty()); + Ok(()) +} + +#[test] +fn comment_then_eof() -> Result<(), ParserError> { + assert!(read_all_tokens("% only a comment").is_err()); + Ok(()) +} -- cgit v1.2.3-70-g09d2 From 06313cac64d1379f75b103e46d00bf682283034f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 6 Jan 2022 22:18:46 -0700 Subject: update README.md --- README.md | 19 +++++++++++++++++++ logo/art_card.jpg | Bin 0 -> 155115 bytes src/machine/machine_state.rs | 27 ++++++++++++++++++--------- 3 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 logo/art_card.jpg diff --git a/README.md b/README.md index 09878933..2db7b76e 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,25 @@ programming, which is itself written in a high-level language. ![Scryer Logo: Cryer](logo/scryer.png) +# Rebis Development Branch + +![Art Card](logo/art_card.jpg) + +This is the Rebis Development Branch (rebis-dev). This iteration of +Rebis contains sweeping changes to the instruction dispatch loop +alongside a compacted heap representation. These changes are to +enhance the performance and robustness of Scryer Prolog and to prepare +for the introduction of a mark-compacting garbage collector. + +Several performance enhancing changes are due before rebis-dev will be +considered ready for merging into master, among them: + +* Replacing choice points pivoting on inlined deterministic predicates + (`atom`, `var`, etc) with if/else ladders +* Inlining all built-ins and system call instructions +* Greatly reducing the number of instructions used to compile disjunctives +* Storing short atoms to heap cells without writing them to the atom table + ## Phase 1 Produce an implementation of the Warren Abstract Machine in Rust, done diff --git a/logo/art_card.jpg b/logo/art_card.jpg new file mode 100644 index 00000000..27b21ba3 Binary files /dev/null and b/logo/art_card.jpg differ diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 6da9674b..11b2672a 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -499,13 +499,6 @@ impl MachineState { } let mut singleton_var_set: IndexMap = IndexMap::new(); - let mut var_list = vec![]; - - let list_of_var_eqs = push_var_eq_functors( - &mut self.heap, - term_write_result.var_dict.iter(), - &mut self.atom_tbl, - ); for addr in stackful_preorder_iter(&mut self.heap, term) { let addr = unmark_cell_bits!(addr); @@ -513,7 +506,6 @@ impl MachineState { if let Some(var) = addr.as_var() { if !singleton_var_set.contains_key(&var) { singleton_var_set.insert(var, true); - var_list.push(addr); } else { singleton_var_set.insert(var, false); } @@ -532,6 +524,23 @@ impl MachineState { &mut self.atom_tbl, ); + let mut var_list = Vec::with_capacity(singleton_var_set.len()); + + for (var_name, addr) in term_write_result.var_dict { + if let Some(var) = addr.as_var() { + let idx = singleton_var_set.get_index_of(&var).unwrap(); + var_list.push((var_name, addr, idx)); + } + } + + var_list.sort_by(|(_,_,idx_1),(_,_,idx_2)| idx_1.cmp(idx_2)); + + let list_of_var_eqs = push_var_eq_functors( + &mut self.heap, + var_list.iter().map(|(var_name, var,_)| (var_name,var)), + &mut self.atom_tbl, + ); + let singleton_addr = self.registers[3]; let singletons_offset = heap_loc_as_cell!( iter_to_heap_list(&mut self.heap, singleton_var_list.into_iter()) @@ -545,7 +554,7 @@ impl MachineState { let vars_addr = self.registers[4]; let vars_offset = heap_loc_as_cell!( - iter_to_heap_list(&mut self.heap, var_list.into_iter()) + iter_to_heap_list(&mut self.heap, var_list.into_iter().map(|(_,cell,_)| cell)) ); unify_fn!(*self, vars_offset, vars_addr); -- cgit v1.2.3-70-g09d2 From 693b6d25479417b96186340fcd8cdcda311fabbc Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 7 Jan 2022 07:52:14 -0700 Subject: add version dependency information to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 2db7b76e..3425e29f 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ considered ready for merging into master, among them: * Greatly reducing the number of instructions used to compile disjunctives * Storing short atoms to heap cells without writing them to the atom table +The rebis-dev branch should be built with **Rust 1.57 and up**. + ## Phase 1 Produce an implementation of the Warren Abstract Machine in Rust, done -- cgit v1.2.3-70-g09d2 From af3f676683f5e81a3b56a0f78f351cc0dec5b542 Mon Sep 17 00:00:00 2001 From: Adrián Arroyo Calle Date: Fri, 7 Jan 2022 19:28:07 +0100 Subject: Minor fixes --- src/lib/ugraphs.pl | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/lib/ugraphs.pl b/src/lib/ugraphs.pl index 257d4e01..159f4c00 100644 --- a/src/lib/ugraphs.pl +++ b/src/lib/ugraphs.pl @@ -1,6 +1,4 @@ -/* Part of SWI-Prolog - - Author: R.A.O'Keefe, Vitor Santos Costa, Jan Wielemaker +/* Author: R.A.O'Keefe, Vitor Santos Costa, Jan Wielemaker E-mail: J.Wielemaker@vu.nl WWW: http://www.swi-prolog.org Copyright (c) 1984-2021, VU University Amsterdam @@ -133,12 +131,10 @@ vertices_edges_to_ugraph(Vertices, Edges, Graph) :- % replace with real msort/2 when available msort_(List, Sorted) :- - maplist(item_pair, List, Pairs), + pairs_keys(Pairs, List), keysort(Pairs, SortedPairs), pairs_keys(SortedPairs, Sorted). -item_pair(X, X-X). - add_vertices(Graph, Vertices, NewGraph) :- % msort/2 not available in Scryer Prolog yet: msort(Vertices, V1), msort_(Vertices, V1), -- cgit v1.2.3-70-g09d2 From d90cf6384c38fc992163573d86616a6759e71e9f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 8 Jan 2022 00:04:04 -0700 Subject: complete handling of control operators in interpreted (,)/2 (#1172) --- src/lib/builtins.pl | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 32527df9..4619bfad 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -225,6 +225,11 @@ comma_dispatch(G1, G2, B) :- comma_dispatch_prep((G1, G2), B, Conts), comma_dispatch_call_list(Conts). +:- non_counted_backtracking cont_list_to_goal/2. + +cont_list_goal([Cont], Cont) :- !. +cont_list_goal(Conts, builtins:comma_dispatch_call_list(Conts)). + :- non_counted_backtracking comma_dispatch_prep/3. comma_dispatch_prep(Gs, B, [Cont|Conts]) :- @@ -232,14 +237,30 @@ comma_dispatch_prep(Gs, B, [Cont|Conts]) :- ( functor(Gs, ',', 2) -> arg(1, Gs, G1), arg(2, Gs, G2), - ( nonvar(G1), ( G1 = ! ; G1 = _:! ) -> - Cont = builtins:set_cp(B) - ; Cont = G1 - ), + comma_dispatch_prep(G1, B, IConts1), + cont_list_goal(IConts1, Cont), comma_dispatch_prep(G2, B, Conts) ; ( Gs = ! ; Gs = _:! ) -> Cont = builtins:set_cp(B), Conts = [] + ; functor(Gs, ';', 2) -> + arg(1, Gs, G1), + arg(2, Gs, G2), + comma_dispatch_prep(G1, B, IConts0), + comma_dispatch_prep(G2, B, IConts1), + cont_list_goal(IConts0, Cont0), + cont_list_goal(IConts1, Cont1), + Cont = ( Cont0 ; Cont1 ), + Conts = [] + ; functor(Gs, ->, 2) -> + arg(1, Gs, G1), + arg(2, Gs, G2), + comma_dispatch_prep(G1, B, IConts1), + comma_dispatch_prep(G2, B, IConts2), + cont_list_goal(IConts1, Cont1), + cont_list_goal(IConts2, Cont2), + Cont = (Cont1 -> Cont2), + Conts = [] ; Cont = Gs, Conts = [] ) @@ -247,7 +268,6 @@ comma_dispatch_prep(Gs, B, [Cont|Conts]) :- Conts = [] ). - :- non_counted_backtracking comma_dispatch_call_list/1. comma_dispatch_call_list([]). -- cgit v1.2.3-70-g09d2 From 2e46aa33c02f867cd0eaba53d982a9089ef6ff1f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 8 Jan 2022 00:19:17 -0700 Subject: correct read/2 arity to 2 (#1171) --- crates/instructions-template/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/instructions-template/src/lib.rs b/crates/instructions-template/src/lib.rs index 386bafd5..cc6e49f3 100644 --- a/crates/instructions-template/src/lib.rs +++ b/crates/instructions-template/src/lib.rs @@ -101,7 +101,7 @@ enum BuiltInClauseType { Is(RegType, ArithmeticTerm), #[strum_discriminants(strum(props(Arity = "2", Name = "keysort")))] KeySort, - #[strum_discriminants(strum(props(Arity = "1", Name = "read")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "read")))] Read, #[strum_discriminants(strum(props(Arity = "2", Name = "sort")))] Sort, -- cgit v1.2.3-70-g09d2 From a54e42961cbfbe8d974fc4b1714f1c89dc31326d Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 8 Jan 2022 11:47:35 -0700 Subject: unify current time as a complete string, not an atom (#1175) --- src/machine/system_calls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 08a99f30..9b4a65e7 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3148,7 +3148,7 @@ impl Machine { #[inline(always)] pub(crate) fn current_time(&mut self) { let timestamp = self.systemtime_to_timestamp(SystemTime::now()); - self.machine_st.unify_atom(timestamp, self.machine_st.registers[1]); + self.machine_st.unify_complete_string(timestamp, self.machine_st.registers[1]); } #[inline(always)] -- cgit v1.2.3-70-g09d2 From d01806ee2d96dfa42385ff035c75d869d01a9ca5 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 8 Jan 2022 12:50:09 -0700 Subject: correct heap offsets in setup_call_cleanup tests --- tests/scryer/src_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index 883d787a..56aa7374 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -51,7 +51,7 @@ fn rules() { fn setup_call_cleanup_load() { load_module_test( "src/tests/setup_call_cleanup.pl", - "1+21+31+2>_14304+_143051+_128981+2>41+2>_143051+2>31+2>31+2>4ba", + "1+21+31+2>_14313+_143141+_129071+2>41+2>_143141+2>31+2>31+2>4ba" ); } @@ -60,7 +60,7 @@ fn setup_call_cleanup_process() { run_top_level_test_with_args( &["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"], "", - "1+21+31+2>_15703+_157041+_142971+2>41+2>_157041+2>31+2>31+2>4ba", + "1+21+31+2>_15712+_157131+_143061+2>41+2>_157131+2>31+2>31+2>4ba", ); } -- cgit v1.2.3-70-g09d2 From 07bc97fb31e410489a5dd2f1a4993c8a8c300c5a Mon Sep 17 00:00:00 2001 From: Adrián Arroyo Calle Date: Sat, 8 Jan 2022 23:31:32 +0100 Subject: fix socket_client_open/3 --- src/lib/sockets.pl | 2 +- src/machine/system_calls.rs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib/sockets.pl b/src/lib/sockets.pl index e2b1b723..2fb3a7fd 100644 --- a/src/lib/sockets.pl +++ b/src/lib/sockets.pl @@ -25,7 +25,7 @@ socket_client_open(Addr, Stream, Options) :- builtins:parse_stream_options(Options, [Alias, EOFAction, Reposition, Type], socket_client_open/3), - '$socket_client_open'(Address, Port, Stream, Alias, EOFAction, Reposition, Type). + '$socket_client_open'(Address, Port, Stream, Alias, EOFAction, Reposition, Type, false). socket_server_open(Addr, ServerSocket) :- diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 9b4a65e7..88ccb421 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -4115,7 +4115,7 @@ impl Machine { let socket_atom = cell_as_atom!(addr); - let _port = read_heap_cell!(port, + let port = read_heap_cell!(port, (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); name @@ -4132,9 +4132,10 @@ impl Machine { ); let socket_addr = if socket_atom == atom!("") { - atom!("127.0.0.1") + atom!("127.0.0.1:80") } else { - socket_atom + let buffer = format!("{}:{}", socket_atom.as_str(), port.as_str()); + self.machine_st.atom_tbl.build_with(&buffer) }; let alias = self.machine_st.registers[4]; -- cgit v1.2.3-70-g09d2 From 35670c86541f4a4e1649e9d787ffff6a5c24798a Mon Sep 17 00:00:00 2001 From: Adrián Arroyo Calle Date: Sun, 9 Jan 2022 17:04:54 +0100 Subject: remove TLS option in socket_client_open/3 --- crates/instructions-template/src/lib.rs | 2 +- src/lib/sockets.pl | 2 +- src/machine/system_calls.rs | 37 +-------------------------------- 3 files changed, 3 insertions(+), 38 deletions(-) diff --git a/crates/instructions-template/src/lib.rs b/crates/instructions-template/src/lib.rs index cc6e49f3..a20be302 100644 --- a/crates/instructions-template/src/lib.rs +++ b/crates/instructions-template/src/lib.rs @@ -442,7 +442,7 @@ enum SystemClauseType { SkipMaxList, #[strum_discriminants(strum(props(Arity = "1", Name = "$sleep")))] Sleep, - #[strum_discriminants(strum(props(Arity = "8", Name = "$socket_client_open")))] + #[strum_discriminants(strum(props(Arity = "7", Name = "$socket_client_open")))] SocketClientOpen, #[strum_discriminants(strum(props(Arity = "3", Name = "$socket_server_open")))] SocketServerOpen, diff --git a/src/lib/sockets.pl b/src/lib/sockets.pl index 2fb3a7fd..e2b1b723 100644 --- a/src/lib/sockets.pl +++ b/src/lib/sockets.pl @@ -25,7 +25,7 @@ socket_client_open(Addr, Stream, Options) :- builtins:parse_stream_options(Options, [Alias, EOFAction, Reposition, Type], socket_client_open/3), - '$socket_client_open'(Address, Port, Stream, Alias, EOFAction, Reposition, Type, false). + '$socket_client_open'(Address, Port, Stream, Alias, EOFAction, Reposition, Type). socket_server_open(Addr, ServerSocket) :- diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 88ccb421..800693af 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -4161,42 +4161,7 @@ impl Machine { let stream = match TcpStream::connect(socket_addr.as_str()).map_err(|e| e.kind()) { Ok(tcp_stream) => { - let mut stream = { - let tls = cell_as_atom!(self.machine_st.store(self.machine_st.deref( - self.machine_st.registers[8] - ))); - - match tls { - atom!("false") => { - Stream::from_tcp_stream(socket_addr, tcp_stream, &mut self.machine_st.arena) - } - atom!("true") => { - let connector = TlsConnector::new().unwrap(); - let stream = Stream::from_tcp_stream( - socket_addr, - tcp_stream, - &mut self.machine_st.arena, - ); - - let stream = - match connector.connect(socket_atom.as_str(), stream) { - Ok(tls_stream) => tls_stream, - Err(_) => { - return Err(self.machine_st.open_permission_error( - addr, - atom!("socket_client_open"), - 3, - )); - } - }; - - Stream::from_tls_stream(atom!("TLS"), stream, &mut self.machine_st.arena) - } - _ => { - unreachable!() - } - } - }; + let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream, &mut self.machine_st.arena); *stream.options_mut() = options; -- cgit v1.2.3-70-g09d2 From bcacb49c05dd62979c124f65243e85ac0f62e5f7 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 9 Jan 2022 18:48:32 -0700 Subject: compare bigints by value not by pointer (#1183) --- src/arithmetic.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 6396336d..e909eed7 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -603,33 +603,33 @@ impl Ord for Number { } (&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).cmp(&n2), (&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2.get_num() as f64)), - (&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2), - (&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(n2), + (&Number::Integer(n1), &Number::Integer(n2)) => (*n1).cmp(&*n2), + (&Number::Integer(n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(n2), (&Number::Float(n1), &Number::Integer(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())), - (&Number::Integer(ref n1), &Number::Rational(ref n2)) => { + (&Number::Integer(n1), &Number::Rational(n2)) => { #[cfg(feature = "num")] { Rational::from(&**n1).cmp(n2) } #[cfg(not(feature = "num"))] { - (&**n1).partial_cmp(&**n2).unwrap_or(Ordering::Less) + (&*n1).partial_cmp(&*n2).unwrap_or(Ordering::Less) } } - (&Number::Rational(ref n1), &Number::Integer(ref n2)) => { + (&Number::Rational(n1), &Number::Integer(n2)) => { #[cfg(feature = "num")] { (&**n1).cmp(&Rational::from(&**n2)) } #[cfg(not(feature = "num"))] { - (&**n1).partial_cmp(&**n2).unwrap_or(Ordering::Less) + (&*n1).partial_cmp(&*n2).unwrap_or(Ordering::Less) } } - (&Number::Rational(ref n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2), - (&Number::Float(n1), &Number::Rational(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())), + (&Number::Rational(n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2), + (&Number::Float(n1), &Number::Rational(n2)) => n1.cmp(&OrderedFloat(n2.to_f64())), (&Number::Float(f1), &Number::Float(f2)) => f1.cmp(&f2), - (&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.cmp(&r2), + (&Number::Rational(r1), &Number::Rational(r2)) => (*r1).cmp(&*r2), } } } -- cgit v1.2.3-70-g09d2 From f5952088e35a56922c5214a9c747ca7c350a2d0d Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Mon, 10 Jan 2022 16:07:05 +0100 Subject: ADDED: format specifier ~NU, using underscores to separate groups of digits Example: ?- format("~2U", [10^12]). %@ 10_000_000_000.00 true. --- src/lib/format.pl | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/lib/format.pl b/src/lib/format.pl index 3fd28fb6..e28ad05e 100644 --- a/src/lib/format.pl +++ b/src/lib/format.pl @@ -1,5 +1,5 @@ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Written 2020, 2021 by Markus Triska (triska@metalevel.at) + Written 2020, 2021, 2022 by Markus Triska (triska@metalevel.at) Part of Scryer Prolog. This library provides the nonterminal format_//2 to describe @@ -28,6 +28,7 @@ if N is 0 or omitted, no decimal point is used. ~ND like ~Nd, separating digits to the left of the decimal point in groups of three, using the character "," (comma) + ~NU like ~ND, using "_" (underscore) to separate groups of digits ~Nr where N is an integer between 2 and 36: format the next argument, which must be an integer, in radix N. The characters "a" to "z" are used for radices 10 to 36. @@ -200,14 +201,12 @@ cells([~|Fs0], Args0, Tab, Es, VNs) --> cells([~|Fs0], Args0, Tab, Es, VNs) --> { numeric_argument(Fs0, Num, ['D'|Fs], Args0, [Arg|Args]) }, !, - { number_chars(Num, NCs), - phrase(("~",seq(NCs),"d"), FStr), - phrase(format_(FStr, [Arg]), Cs0), - phrase(upto_what(Bs0, .), Cs0, Ds), - reverse(Bs0, Bs1), - phrase(groups_of_three(Bs1), Bs2), - reverse(Bs2, Bs), - append(Bs, Ds, Cs) }, + { separate_digits_fractional(Arg, ',', Num, Cs) }, + cells(Fs, Args, Tab, [chars(Cs)|Es], VNs). +cells([~|Fs0], Args0, Tab, Es, VNs) --> + { numeric_argument(Fs0, Num, ['U'|Fs], Args0, [Arg|Args]) }, + !, + { separate_digits_fractional(Arg, '_', Num, Cs) }, cells(Fs, Args, Tab, [chars(Cs)|Es], VNs). cells([~,i|Fs], [_|Args], Tab, Es, VNs) --> !, cells(Fs, Args, Tab, Es, VNs). @@ -312,12 +311,22 @@ Cs = [a,b,c], Rest = [~,t,e,s,t]. Cs = [a,b,c], Rest = []. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +separate_digits_fractional(Arg, Sep, Num, Cs) :- + number_chars(Num, NCs), + phrase(("~",seq(NCs),"d"), FStr), + phrase(format_(FStr, [Arg]), Cs0), + phrase(upto_what(Bs0, .), Cs0, Ds), + reverse(Bs0, Bs1), + phrase(groups_of_three(Bs1,Sep), Bs2), + reverse(Bs2, Bs), + append(Bs, Ds, Cs). + upto_what([], W), [W] --> [W], !. upto_what([C|Cs], W) --> [C], !, upto_what(Cs, W). upto_what([], _) --> []. -groups_of_three([A,B,C,D|Rs]) --> !, [A,B,C], ",", groups_of_three([D|Rs]). -groups_of_three(Ls) --> seq(Ls). +groups_of_three([A,B,C,D|Rs], Sep) --> !, [A,B,C,Sep], groups_of_three([D|Rs], Sep). +groups_of_three(Ls, _) --> seq(Ls). cell(From, To, Es0) --> ( { Es0 == [] } -> [] -- cgit v1.2.3-70-g09d2 From 2889a4438b53e356f1329f591d1237f7a86dacdb Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Mon, 10 Jan 2022 17:29:45 +0100 Subject: ADDED: format specifier ~NL to limit the number of digits per line Example: %?- format("~65L", [2^1000]). %@ 10715086071862673209484250490600018105614048117055336074437503883_ %@ 70351051124936122493198378815695858127594672917553146825187145285_ %@ 69231404359845775746985748039345677748242309854210746050623711418_ %@ 77954182153046474983581941267398767559165543946077062914571196477_ %@ 686542167660429831652624386837205668069376 true. --- src/lib/format.pl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/lib/format.pl b/src/lib/format.pl index e28ad05e..fd2a9816 100644 --- a/src/lib/format.pl +++ b/src/lib/format.pl @@ -29,6 +29,8 @@ ~ND like ~Nd, separating digits to the left of the decimal point in groups of three, using the character "," (comma) ~NU like ~ND, using "_" (underscore) to separate groups of digits + ~NL format an integer so that at most N digits appear on a line. + If N is 0 or omitted, it defaults to 72. ~Nr where N is an integer between 2 and 36: format the next argument, which must be an integer, in radix N. The characters "a" to "z" are used for radices 10 to 36. @@ -208,6 +210,16 @@ cells([~|Fs0], Args0, Tab, Es, VNs) --> !, { separate_digits_fractional(Arg, '_', Num, Cs) }, cells(Fs, Args, Tab, [chars(Cs)|Es], VNs). +cells([~|Fs0], Args0, Tab, Es, VNs) --> + { numeric_argument(Fs0, Num0, ['L'|Fs], Args0, [Arg|Args]) }, + !, + { ( Num0 =:= 0 -> + Num = 72 + ; Num = Num0 + ), + phrase(format_("~d", [Arg]), Cs0), + phrase(split_lines_width(Cs0, Num), Cs) }, + cells(Fs, Args, Tab, [chars(Cs)|Es], VNs). cells([~,i|Fs], [_|Args], Tab, Es, VNs) --> !, cells(Fs, Args, Tab, Es, VNs). cells([~,n|Fs], Args, Tab, Es, VNs) --> !, @@ -328,6 +340,14 @@ upto_what([], _) --> []. groups_of_three([A,B,C,D|Rs], Sep) --> !, [A,B,C,Sep], groups_of_three([D|Rs], Sep). groups_of_three(Ls, _) --> seq(Ls). +split_lines_width(Cs, Num) --> + ( { length(Prefix, Num), + append(Prefix, [R|Rs], Cs) } -> + seq(Prefix), "_\n", + split_lines_width([R|Rs], Num) + ; seq(Cs) + ). + cell(From, To, Es0) --> ( { Es0 == [] } -> [] ; { reverse(Es0, Es) }, -- cgit v1.2.3-70-g09d2 From a5de329712324e296dcc2ba83f2da87a5ee27975 Mon Sep 17 00:00:00 2001 From: Skgland Date: Mon, 10 Jan 2022 19:59:21 +0100 Subject: don't genrate code in src/ [Outputs of Build Script](https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script) states that only files in $OUT_DIR may be modified --- build.rs | 6 ++--- crates/instructions-template/src/lib.rs | 4 ++- crates/static-string-indexing/src/lib.rs | 42 ++++++++++++++++++++++---------- src/atom_table.rs | 2 +- src/lib.rs | 6 ++++- 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/build.rs b/build.rs index 6c315769..3571199e 100644 --- a/build.rs +++ b/build.rs @@ -56,7 +56,7 @@ fn main() { find_prolog_files(&mut libraries, "", &lib_path); libraries.write_all(b"\n m\n };\n}\n").unwrap(); - let instructions_path = Path::new("src/instructions.rs"); + let instructions_path = Path::new(&out_dir).join("instructions.rs"); let mut instructions_file = File::create(&instructions_path).unwrap(); let quoted_output = generate_instructions_rs(); @@ -70,10 +70,10 @@ fn main() { .spawn().unwrap() .wait().unwrap(); - let static_atoms_path = Path::new("src/static_atoms.rs"); + let static_atoms_path = Path::new(&out_dir).join("static_atoms.rs"); let mut static_atoms_file = File::create(&static_atoms_path).unwrap(); - let quoted_output = index_static_strings(); + let quoted_output = index_static_strings(&instructions_path); static_atoms_file .write_all(quoted_output.to_string().as_bytes()) diff --git a/crates/instructions-template/src/lib.rs b/crates/instructions-template/src/lib.rs index a20be302..1a7e02a4 100644 --- a/crates/instructions-template/src/lib.rs +++ b/crates/instructions-template/src/lib.rs @@ -3037,11 +3037,13 @@ pub fn generate_instructions_rs() -> TokenStream { } #[macro_export] - macro_rules! instr { + macro_rules! _instr { #( #instr_macro_arms );* } + + pub use _instr as instr; // https://github.com/rust-lang/rust/pull/52234#issuecomment-976702997 } } diff --git a/crates/static-string-indexing/src/lib.rs b/crates/static-string-indexing/src/lib.rs index 22b87cc0..390c5405 100644 --- a/crates/static-string-indexing/src/lib.rs +++ b/crates/static-string-indexing/src/lib.rs @@ -84,7 +84,7 @@ impl<'ast> Visit<'ast> for StaticStrVisitor { } } -pub fn index_static_strings() -> TokenStream { +pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStream { use quote::*; use std::ffi::OsStr; @@ -103,20 +103,14 @@ pub fn index_static_strings() -> TokenStream { let mut visitor = StaticStrVisitor::new(); - for entry in WalkDir::new("src/").into_iter().filter_entry(filter_rust_files) { - let entry = entry.unwrap(); - - if entry.path().is_dir() { - continue; - } + fn process_filepath(path: &std::path::Path) -> std::result::Result { + let mut src = String::new(); - let mut file = match File::open(entry.path()) { + let mut file = match File::open(path) { Ok(file) => file, - Err(_) => continue, + Err(_) => return Err(()), }; - let mut src = String::new(); - match file.read_to_string(&mut src) { Ok(_) => {} Err(e) => { @@ -127,14 +121,36 @@ pub fn index_static_strings() -> TokenStream { let syntax = match syn::parse_file(&src) { Ok(s) => s, Err(e) => { - panic!("parse error: {} in file {:?}", e, entry.path()); + panic!("parse error: {} in file {:?}", e, path); } }; + Ok(syntax) + } + + for entry in WalkDir::new("src/") + .into_iter() + .filter_entry(filter_rust_files) + { + let entry = entry.unwrap(); + + if entry.path().is_dir() { + continue; + } + + let syntax = match process_filepath(entry.path()) { + Ok(syntax) => syntax, + Err(_) => continue, + }; visitor.visit_file(&syntax); } - let indices = (0 .. visitor.static_strs.len()).map(|i| i << 3); + match process_filepath(instruction_rs_path) { + Ok(syntax) => visitor.visit_file(&syntax), + Err(_) => {} + } + + let indices = (0..visitor.static_strs.len()).map(|i| i << 3); let indices_iter = indices.clone(); let static_strs_len = visitor.static_strs.len(); diff --git a/src/atom_table.rs b/src/atom_table.rs index 71771cc2..b925273a 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -21,7 +21,7 @@ pub struct Atom { const_assert!(mem::size_of::() == 8); -include!("./static_atoms.rs"); +include!(concat!(env!("OUT_DIR"), "/static_atoms.rs")); impl<'a> From<&'a Atom> for Atom { #[inline] diff --git a/src/lib.rs b/src/lib.rs index a4aff98c..6cb89830 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,9 @@ mod heap_iter; pub mod heap_print; mod indexing; #[macro_use] -pub mod instructions; +pub mod instructions { + include!(concat!(env!("OUT_DIR"), "/instructions.rs")); +} mod iterators; pub mod machine; mod raw_block; @@ -29,3 +31,5 @@ pub mod read; mod targets; pub mod types; pub mod write; + +use instructions::instr; -- cgit v1.2.3-70-g09d2 From 590d80268e06887feb468d533e0dd4df0e0a178d Mon Sep 17 00:00:00 2001 From: Skgland Date: Mon, 10 Jan 2022 19:59:56 +0100 Subject: only rerun build.rs when something in src/ has changed by default (when no rerun-if is emitted) build.rs is rerun if something in the package changes --- build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.rs b/build.rs index 3571199e..e0f1d16e 100644 --- a/build.rs +++ b/build.rs @@ -83,4 +83,6 @@ fn main() { .arg(static_atoms_path.as_os_str()) .spawn().unwrap() .wait().unwrap(); + + println!("cargo:rerun-if-changed=src/"); } -- cgit v1.2.3-70-g09d2 From ef0b239e7031cea7d7b6cfce6d7c18383afbea2b Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 10 Jan 2022 17:26:57 -0700 Subject: correctly print [] functors (#1189) --- src/heap_print.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index e1c4e214..f7ba606c 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1358,7 +1358,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { read_heap_cell!(addr, (HeapCellValueTag::Atom, (name, arity)) => { - if name == atom!("[]") { + if name == atom!("[]") && arity == 0 { if !self.at_cdr("") { append_str!(self, "[]"); } -- cgit v1.2.3-70-g09d2 From f0e6b8ca47ed1243746134aa7d71208dd823424e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 10 Jan 2022 18:25:30 -0700 Subject: imitate Rc-style equality for TypedArenaPtr (#1190) --- src/arena.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/arena.rs b/src/arena.rs index d0244fae..0dde0751 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -72,9 +72,17 @@ impl ArenaHeader { } } -#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)] +#[derive(Debug, PartialOrd, Ord)] pub struct TypedArenaPtr(ptr::NonNull); +impl PartialEq for TypedArenaPtr { + fn eq(&self, other: &TypedArenaPtr) -> bool { + self.0 == other.0 || &**self == &**other + } +} + +impl Eq for TypedArenaPtr {} + impl Hash for TypedArenaPtr { #[inline(always)] fn hash(&self, hasher: &mut H) { -- cgit v1.2.3-70-g09d2 From e3622e0860cfcaa8440b1d8224d5f878b9577f31 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 10 Jan 2022 18:34:25 -0700 Subject: improve between_/3 implementation (#1186, #1191) --- src/lib/between.pl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lib/between.pl b/src/lib/between.pl index 3e023c8c..2711e8e8 100644 --- a/src/lib/between.pl +++ b/src/lib/between.pl @@ -16,14 +16,14 @@ between(Lower, Upper, X) :- between_(Lower, Upper, X) ). -between_(Lower, Lower, Lower) :- !. between_(Lower, Upper, Lower1) :- - ( Lower < Upper, - ( Lower1 = Lower - ; Lower0 is Lower + 1, - between_(Lower0, Upper, Lower1) - ) - ). + Lower < Upper, + !, + ( Lower1 = Lower + ; Lower0 is Lower + 1, + between_(Lower0, Upper, Lower1) + ). +between_(Lower, Lower, Lower). enumerate_nats(I, I). enumerate_nats(I0, N) :- -- cgit v1.2.3-70-g09d2 From 5f4e70146123d7901a376ecde321e5c02eb9e851 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 10 Jan 2022 20:46:00 -0700 Subject: render [] as empty string in AtomOrString::as_str() (#1193) --- src/forms.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/forms.rs b/src/forms.rs index ce517a5f..167b937e 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -360,6 +360,7 @@ impl AtomOrString { #[inline] pub fn as_str(&self) -> &str { match self { + AtomOrString::Atom(atom) if atom == &atom!("[]") => "", AtomOrString::Atom(atom) => atom.as_str(), AtomOrString::String(string) => string.as_str(), } -- cgit v1.2.3-70-g09d2 From cfe257495a025fe13087b7d65b6a37d1e87c4a3d Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 10 Jan 2022 21:18:11 -0700 Subject: recognize characters as separate from atoms in ''/7 (#1192) --- src/machine/system_calls.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 800693af..71208ce4 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2947,7 +2947,17 @@ impl Machine { }; let unossified_op_dir = if !orig_op.is_var() { - let orig_op = cell_as_atom!(orig_op); + let orig_op = read_heap_cell!(orig_op, + (HeapCellValueTag::Atom, (name, _arity)) => { + name + } + (HeapCellValueTag::Char, c) => { + self.machine_st.atom_tbl.build_with(&c.to_string()) + } + _ => { + unreachable!() + } + ); let op_descs = [ self.indices.op_dir.get_key_value(&(orig_op, Fixity::In)), -- cgit v1.2.3-70-g09d2 From 67854e07201dbbd56bf0eafe6aba5a6d75740e8e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 11 Jan 2022 18:24:26 -0700 Subject: execute trust instead of retry at the end of dynamic choice blocks (#1204, #1173) --- src/machine/dispatch.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 6f5d9d02..3406f88c 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -266,7 +266,7 @@ impl Machine { } } - pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> { + pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, usize, bool)> { let p = self.machine_st.p; let indexed_choice_instrs = match &self.code[p] { @@ -287,8 +287,10 @@ impl Machine { death, next_or_fail, ) => { + let len = indexed_choice_instrs.len(); + if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { - return Some((offset, oi, ii, next_or_fail.is_next())); + return Some((offset, oi, ii, len, next_or_fail.is_next())); } else { ii += 1; } @@ -3037,7 +3039,7 @@ impl Machine { let p = self.machine_st.p; match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { - Some((offset, oi, ii, is_next_clause)) => { + Some((offset, oi, ii, _, is_next_clause)) => { self.machine_st.p = p; self.machine_st.oip = oi; self.machine_st.iip = ii; @@ -3084,7 +3086,11 @@ impl Machine { if is_next_clause { match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { - Some(_) => { + // if we're executing the last instruction + // of the internal block pointed to by + // self.machine_st.iip, we want trust, not retry. + // this is true iff ii + 1 < len. + Some((_,_,ii,len,_)) if (ii as usize) + 1 < len => { self.retry(offset); try_or_throw!( @@ -3092,7 +3098,7 @@ impl Machine { (self.machine_st.increment_call_count_fn)(&mut self.machine_st) ); } - None => { + _ => { self.trust(offset); try_or_throw!( -- cgit v1.2.3-70-g09d2 From c5cda99f9db904869177ec35efa8b1e749a128a4 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 11 Jan 2022 18:42:01 -0700 Subject: evaluate floats referenced from the heap by tagged pointers (#1203) --- src/machine/arithmetic_ops.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 5cc64098..2541f0a1 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1334,6 +1334,9 @@ impl MachineState { (ArenaHeaderTag::Rational, r) => { self.interms.push(Number::Rational(r)); } + (ArenaHeaderTag::F64, fl) => { + self.interms.push(Number::Float(*fl)); + } _ => { std::mem::drop(iter); -- cgit v1.2.3-70-g09d2 From cfbb05fb1b4259abc6d3a896f2fbdd9c0b801064 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Wed, 12 Jan 2022 21:58:23 +0100 Subject: deterministic --> semi-deterministic --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53d3f24b..105069ac 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ for the introduction of a mark-compacting garbage collector. Several performance enhancing changes are due before rebis-dev will be considered ready for merging into master, among them: -* Replacing choice points pivoting on inlined deterministic predicates +* Replacing choice points pivoting on inlined semi-deterministic predicates (`atom`, `var`, etc) with if/else ladders * Inlining all built-ins and system call instructions * Greatly reducing the number of instructions used to compile disjunctives -- cgit v1.2.3-70-g09d2 From 4dca86d5cfb0907e9eaa3ea8e5915075cd9c1d30 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 12 Jan 2022 16:57:12 -0700 Subject: serialize call_0 test (#1206) --- tests/scryer/issues.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/scryer/issues.rs b/tests/scryer/issues.rs index bae95d73..3c207471 100644 --- a/tests/scryer/issues.rs +++ b/tests/scryer/issues.rs @@ -1,4 +1,5 @@ use crate::helper::{load_module_test, run_top_level_test_no_args, run_top_level_test_with_args}; +use serial_test::serial; // issue #857 #[test] @@ -164,6 +165,7 @@ fn ignored_constraint() { } // issue #831 +#[serial] #[test] fn call_0() { load_module_test( -- cgit v1.2.3-70-g09d2 From d9e190096c21d69d02dd102f77ef2847b8fb6795 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 12 Jan 2022 22:10:59 -0700 Subject: delimit partial strings around \x0\ --- src/machine/partial_string.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 87256d04..4430b9e3 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -44,10 +44,10 @@ impl PartialString { #[inline] pub(super) fn new<'a>(src: &'a str, atom_tbl: &mut AtomTable) -> Option<(Self, &'a str)> { let terminator_idx = scan_for_terminator(src.chars()); - let pstr = PartialString(atom_tbl.build_with(src)); + let pstr = PartialString(atom_tbl.build_with(&src[.. terminator_idx])); - Some(if terminator_idx != src.as_bytes().len() { - (pstr, &src[terminator_idx..]) + Some(if terminator_idx < src.as_bytes().len() { + (pstr, &src[terminator_idx + 1..]) } else { (pstr, "") }) -- cgit v1.2.3-70-g09d2 From 39e28f1f2a25aaca245762cbc56e554aefc830cf Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 12 Jan 2022 22:11:59 -0700 Subject: write plaintext and ciphertext directly to atoms (#1193) --- src/machine/system_calls.rs | 84 +++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 71208ce4..6163a467 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1852,7 +1852,7 @@ impl Machine { } }; - self.machine_st.unify_char(c, a2); + self.machine_st.unify_char(c, a1); return Ok(()); } Ok(Number::Fixnum(n)) => { @@ -5266,7 +5266,12 @@ impl Machine { let complete_string = { let buffer = String::from_iter(in_out.iter().map(|b| *b as char)); - put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl) + + if buffer.len() == 0 { + empty_list_as_cell!() + } else { + atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&buffer)) + } }; unify!(self.machine_st, self.machine_st.registers[6], tag_list); @@ -5315,7 +5320,11 @@ impl Machine { } }; - put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl) + if buffer.len() == 0 { + empty_list_as_cell!() + } else { + atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&buffer)) + } }; unify!(self.machine_st, self.machine_st.registers[6], complete_string); @@ -5361,17 +5370,19 @@ impl Machine { .affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx) .ok(); - let sx = put_complete_string( - &mut self.machine_st.heap, - &rx.to_dec_str().unwrap(), - &mut self.machine_st.atom_tbl, - ); + let sx = rx.to_dec_str().unwrap(); + let sx = if sx.len() == 0 { + empty_list_as_cell!() + } else { + atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&sx)) + }; - let sy = put_complete_string( - &mut self.machine_st.heap, - &ry.to_dec_str().unwrap(), - &mut self.machine_st.atom_tbl, - ); + let sy = ry.to_dec_str().unwrap(); + let sy = if sy.len() == 0 { + empty_list_as_cell!() + } else { + atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&sy)) + }; unify!(self.machine_st, self.machine_st.registers[4], sx); unify!(self.machine_st, self.machine_st.registers[5], sy); @@ -5382,11 +5393,12 @@ impl Machine { let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap(); let complete_string = { let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char)); - put_complete_string( - &mut self.machine_st.heap, - &buffer, - &mut self.machine_st.atom_tbl, - ) + + if buffer.len() == 0 { + empty_list_as_cell!() + } else { + atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&buffer)) + } }; unify!(self.machine_st, self.machine_st.registers[1], complete_string) @@ -5409,11 +5421,11 @@ impl Machine { key_pair.public_key().as_ref().iter().map(|b| *b as char), ); - put_complete_string( - &mut self.machine_st.heap, - &buffer, - &mut self.machine_st.atom_tbl, - ) + if buffer.len() == 0 { + empty_list_as_cell!() + } else { + atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&buffer)) + } }; unify!(self.machine_st, self.machine_st.registers[2], complete_string); @@ -5478,7 +5490,11 @@ impl Machine { let result = scalarmult(&scalar, &point).unwrap(); let string = String::from_iter(result[..].iter().map(|b| *b as char)); - let cstr = put_complete_string(&mut self.machine_st.heap, &string, &mut self.machine_st.atom_tbl); + let cstr = if string.len() == 0 { + empty_list_as_cell!() + } else { + atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&string)) + }; unify!(self.machine_st, self.machine_st.registers[3], cstr); } @@ -5663,11 +5679,11 @@ impl Machine { match bytes { Ok(bs) => { let string = String::from_iter(bs.iter().map(|b| *b as char)); - let cstr = put_complete_string( - &mut self.machine_st.heap, - &string, - &mut self.machine_st.atom_tbl, - ); + let cstr = if string.len() == 0 { + empty_list_as_cell!() + } else { + atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&string)) + }; unify!(self.machine_st, self.machine_st.registers[1], cstr); } @@ -5694,11 +5710,11 @@ impl Machine { } let b64 = base64::encode_config(bytes, config); - let cstr = put_complete_string( - &mut self.machine_st.heap, - &b64, - &mut self.machine_st.atom_tbl, - ); + let cstr = if b64.len() == 0 { + empty_list_as_cell!() + } else { + atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&b64)) + }; unify!(self.machine_st, self.machine_st.registers[2], cstr); } -- cgit v1.2.3-70-g09d2 From 3b8afce7c72d5b3460eecde56e060b7201fa9c64 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 12 Jan 2022 23:55:40 -0700 Subject: fix syntax regressions (#1198, #1164) --- src/forms.rs | 7 +++++-- src/heap_print.rs | 31 ++++++++++++++----------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/forms.rs b/src/forms.rs index 167b937e..372613b8 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -384,8 +384,8 @@ pub(crate) fn fetch_atom_op_spec( spec: Option, op_dir: &OpDir, ) -> Option { - fetch_op_spec_from_existing(name, 1, spec, op_dir) - .or_else(|| fetch_op_spec_from_existing(name, 2, spec, op_dir)) + fetch_op_spec_from_existing(name, 2, spec, op_dir) + .or_else(|| fetch_op_spec_from_existing(name, 1, spec, op_dir)) } pub(crate) fn fetch_op_spec_from_existing( @@ -430,6 +430,9 @@ pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option< } }) } + 0 => { + fetch_atom_op_spec(name, None, op_dir) + } _ => None, } } diff --git a/src/heap_print.rs b/src/heap_print.rs index f7ba606c..cb8e34e5 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -88,7 +88,7 @@ fn needs_bracketing(child_desc: OpDesc, op: &DirectedOp) -> bool { true } else if (is_postfix!(spec) || is_infix!(spec)) && !is_postfix!(child_desc.get_spec()) { - *cell == child_desc && child_desc.get_prec() == priority + *cell != child_desc && child_desc.get_prec() == priority } else { false } @@ -191,10 +191,10 @@ enum NumberFocus { } impl NumberFocus { - fn is_positive(&self) -> bool { + fn is_negative(&self) -> bool { match self { - NumberFocus::Unfocused(n) => n.is_positive(), - NumberFocus::Denominator(r) | NumberFocus::Numerator(r) => **r > 0, + NumberFocus::Unfocused(n) => n.is_negative(), + NumberFocus::Denominator(r) | NumberFocus::Numerator(r) => **r < 0, } } } @@ -922,7 +922,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { fn print_number(&mut self, n: NumberFocus, op: &Option) { let add_brackets = if let Some(op) = op { - op.is_negative_sign() && n.is_positive() + op.is_negative_sign() && !n.is_negative() } else { false }; @@ -934,23 +934,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { match n { NumberFocus::Unfocused(n) => match n { Number::Float(fl) => { - if &fl == &OrderedFloat(0f64) { - push_space_if_amb!(self, "0.0", { - append_str!(self, "0.0"); - }); - } else { - let OrderedFloat(fl) = fl; - let output_str = format!("{0:<20?}", fl); + let OrderedFloat(fl) = fl; + let output_str = format!("{0:<20?}", fl); - push_space_if_amb!(self, &output_str, { - append_str!(self, &output_str.trim()); - }); - } + push_space_if_amb!(self, &output_str, { + append_str!(self, &output_str.trim()); + }); } Number::Rational(r) => { self.print_rational(r, add_brackets); return; } + Number::Fixnum(n) => { + append_str!(self, &format!("{}", n.get_num())); + } n => { let output_str = format!("{}", n); @@ -1427,7 +1424,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } (HeapCellValueTag::Fixnum, n) => { - append_str!(self, &format!("{}", n.get_num())); + self.print_number(NumberFocus::Unfocused(Number::Fixnum(n)), &op); } (HeapCellValueTag::F64, f) => { self.print_number(NumberFocus::Unfocused(Number::Float(**f)), &op); -- cgit v1.2.3-70-g09d2 From c6d23f9a0b18b0f9c88cbcefbe72f72940dd2a2c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 13 Jan 2022 18:06:44 -0700 Subject: fix off-by-one error in DynamicIndexedChoice (#1210) --- src/machine/dispatch.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 3406f88c..546781c7 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -266,7 +266,7 @@ impl Machine { } } - pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, usize, bool)> { + pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> { let p = self.machine_st.p; let indexed_choice_instrs = match &self.code[p] { @@ -287,10 +287,8 @@ impl Machine { death, next_or_fail, ) => { - let len = indexed_choice_instrs.len(); - if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { - return Some((offset, oi, ii, len, next_or_fail.is_next())); + return Some((offset, oi, ii, next_or_fail.is_next())); } else { ii += 1; } @@ -3039,7 +3037,7 @@ impl Machine { let p = self.machine_st.p; match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { - Some((offset, oi, ii, _, is_next_clause)) => { + Some((offset, oi, ii, is_next_clause)) => { self.machine_st.p = p; self.machine_st.oip = oi; self.machine_st.iip = ii; @@ -3060,9 +3058,9 @@ impl Machine { self.machine_st.registers[self.machine_st.num_of_args + 1] = fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64)); - self.machine_st.num_of_args += 2; + self.machine_st.num_of_args += 1; self.machine_st.indexed_try(offset); - self.machine_st.num_of_args -= 2; + self.machine_st.num_of_args -= 1; } None => { self.machine_st.p = p + offset; @@ -3081,16 +3079,16 @@ impl Machine { .num_cells; self.machine_st.cc = cell_as_fixnum!( - self.machine_st.stack[stack_loc!(OrFrame, b, n-2)] + self.machine_st.stack[stack_loc!(OrFrame, b, n-1)] ).get_num() as usize; if is_next_clause { - match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { + match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip + 1) { // if we're executing the last instruction // of the internal block pointed to by // self.machine_st.iip, we want trust, not retry. // this is true iff ii + 1 < len. - Some((_,_,ii,len,_)) if (ii as usize) + 1 < len => { + Some(_) => { self.retry(offset); try_or_throw!( -- cgit v1.2.3-70-g09d2 From bc5125b7192c7c1152fb18ac94393a67f296718f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 13 Jan 2022 19:43:54 -0700 Subject: put_complete_string should push the empty list to the heap for empty strings (#1209) --- src/machine/heap.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 6a5e14ef..a7317cc3 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -147,7 +147,9 @@ pub(crate) fn put_complete_string( } } None => { - empty_list_as_cell!() + let h = heap.len(); + heap.push(empty_list_as_cell!()); + heap_loc_as_cell!(h) } } } -- cgit v1.2.3-70-g09d2 From f3e5f7879d85853f5d6a2e64cddfaa276959b319 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 13 Jan 2022 20:30:29 -0700 Subject: allow late dynamic declaration for predicates (#1205) --- src/machine/compile.rs | 29 ++++++++++- src/machine/machine_indices.rs | 111 ----------------------------------------- 2 files changed, 27 insertions(+), 113 deletions(-) diff --git a/src/machine/compile.rs b/src/machine/compile.rs index fa1f7250..180a2b9d 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -2167,8 +2167,31 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { skeleton.core.clause_clause_locs.push_front(loc); } } + None if append_or_prepend.is_append() => { + let mut skeleton = PredicateSkeleton::new(); + + for loc in locs_vec { + skeleton.core.clause_clause_locs.push_back(loc); + } + + self.add_extensible_predicate( + (atom!("$clause"), 2), + skeleton, + clause_clause_compilation_target, + ); + } None => { - unreachable!(); + let mut skeleton = PredicateSkeleton::new(); + + for loc in locs_vec.into_iter().rev() { + skeleton.core.clause_clause_locs.push_back(loc); + } + + self.add_extensible_predicate( + (atom!("$clause"), 2), + skeleton, + clause_clause_compilation_target, + ); } } @@ -2315,8 +2338,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { if predicate_info.is_dynamic { LS::machine_st(&mut self.payload).global_clock += 1; + let clause_clauses_len = self.payload.clause_clauses.len(); let clauses_vec: Vec<_> = self.payload - .clause_clauses.drain(0..predicates_len).collect(); + .clause_clauses.drain(0..std::cmp::min(predicates_len, clause_clauses_len)) + .collect(); self.compile_clause_clauses( key, diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 5f9d08d5..794b09b1 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -126,117 +126,6 @@ impl Default for CodeIndex { } } -/* -#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] -pub enum REPLCodePtr { - AddDiscontiguousPredicate, - AddDynamicPredicate, - AddMultifilePredicate, - AddGoalExpansionClause, - AddTermExpansionClause, - AddInSituFilenameModule, - ClauseToEvacuable, - ScopedClauseToEvacuable, - ConcludeLoad, - DeclareModule, - LoadCompiledLibrary, - LoadContextSource, - LoadContextFile, - LoadContextDirectory, - LoadContextModule, - LoadContextStream, - PopLoadContext, - PopLoadStatePayload, - PushLoadContext, - PushLoadStatePayload, - UseModule, - BuiltInProperty, - MetaPredicateProperty, - MultifileProperty, - DiscontiguousProperty, - DynamicProperty, - AbolishClause, - Asserta, - Assertz, - Retract, - IsConsistentWithTermQueue, - FlushTermQueue, - RemoveModuleExports, - AddNonCountedBacktracking, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum CodePtr { - BuiltInClause(BuiltInClauseType, usize), // local is the successor call. - CallN(usize, usize, bool), // arity, local, last call. - Local(usize), - REPL(REPLCodePtr, usize), // the REPL code, the return pointer. - VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir. -} - -impl CodePtr { - pub(crate) fn local(&self) -> usize { - match self { - &CodePtr::BuiltInClause(_, ref local) | - &CodePtr::CallN(_, ref local, _) | - &CodePtr::Local(ref local) => *local, - &CodePtr::VerifyAttrInterrupt(p) => p, - &CodePtr::REPL(_, p) => p, - } - } - - pub fn assign_if_local(&self, cp: &mut usize) { - match self { - CodePtr::Local(local) => *cp = *local, - _ => {} - } - } -} - -impl Add for CodePtr { - type Output = CodePtr; - - fn add(self, rhs: usize) -> Self::Output { - match self { - p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => { - p - } - CodePtr::Local(local) => CodePtr::Local(local + rhs), - CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => { - CodePtr::Local(local + rhs) - } - } - } -} - -impl AddAssign for CodePtr { - fn add_assign(&mut self, rhs: usize) { - match self { - &mut CodePtr::VerifyAttrInterrupt(_) => {} - &mut CodePtr::Local(ref mut local) => *local += rhs, - _ => *self = CodePtr::Local(self.local() + rhs), - } - } -} - -impl SubAssign for CodePtr { - #[inline] - fn sub_assign(&mut self, rhs: usize) { - match self { - CodePtr::Local(ref mut local) => *local -= rhs, - _ => unreachable!(), - } - } -} - -impl Default for CodePtr { - #[inline] - fn default() -> Self { - CodePtr::Local(0) - } -} -*/ - pub(crate) type HeapVarDict = IndexMap, HeapCellValue, FxBuildHasher>; pub(crate) type AllocVarDict = IndexMap, VarData, FxBuildHasher>; -- cgit v1.2.3-70-g09d2 From 06abe2302bfc9b968a0ebcaa0d74b928bdbaeebe Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 15 Jan 2022 00:51:38 -0700 Subject: add missing cases to retract_clause (#1214) --- src/machine/compile.rs | 119 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 31 deletions(-) diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 180a2b9d..b8ffdcf2 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -235,19 +235,20 @@ fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> u index = index_loc; } } - &Instruction::DynamicElse(_, _, next_or_fail) => match next_or_fail - { - NextOrFail::Next(i) => { - if i == 0 { + &Instruction::DynamicElse(_, _, next_or_fail) => { + match next_or_fail { + NextOrFail::Next(i) => { + if i == 0 { + index = index_loc; + } else { + return index; + } + } + NextOrFail::Fail(_) => { index = index_loc; - } else { - return index; } } - NextOrFail::Fail(_) => { - index = index_loc; - } - }, + } &Instruction::DynamicInternalElse(_, _, next_or_fail) => { match next_or_fail { NextOrFail::Next(i) => { @@ -1173,7 +1174,6 @@ fn append_compiled_clause( { Some(index_loc) if lower_bound_arg_num == target_arg_num => { code.push(settings.internal_trust_me()); - code.extend(clause_code.drain(3..)); // skip the indexing code // set skeleton[target_pos].opt_arg_index_key to @@ -1796,24 +1796,19 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let payload_compilation_target = self.payload.compilation_target; let code_index = self.get_or_insert_code_index(key, payload_compilation_target); - let skeleton = match self + let skeleton = self .wam_prelude .indices .get_predicate_skeleton_mut(&payload_compilation_target, &key) - { - Some(skeleton) => skeleton, - None => { - unreachable!(); - } - }; + .unwrap(); let code = &mut self.wam_prelude.code; let lower_bound = lower_bound_of_target_clause(skeleton, target_pos); let lower_bound_is_unindexed = !skeleton.clauses[lower_bound].opt_arg_index_key.is_some(); if target_pos == 0 || (lower_bound + 1 == target_pos && lower_bound_is_unindexed) { - // the clause preceding target_pos, if there is one, is of key type - // OptArgIndexKey::None. + // the clause preceding target_pos, if there is one, is of + // key type OptArgIndexKey::None. match skeleton.clauses[target_pos] .opt_arg_index_key .switch_on_term_loc() @@ -2024,29 +2019,91 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .switch_on_term_loc() { Some(index_loc) => { - let preceding_choice_instr_loc = find_inner_choice_instr( + let clause_start = find_inner_choice_instr( code, - skeleton.clauses[target_pos - 1].clause_start, + skeleton.clauses[target_pos].clause_start, index_loc, ); - remove_non_leading_clause( - code, - preceding_choice_instr_loc, - skeleton.clauses[target_pos].clause_start, - &mut self.payload.retraction_info, - ); + let lower_bound_clause_start = skeleton.clauses[lower_bound].clause_start; + let preceding_choice_instr_loc; - match &mut code[preceding_choice_instr_loc] { + match &mut code[clause_start] { Instruction::TryMeElse(0) => { + preceding_choice_instr_loc = if skeleton.clauses[lower_bound] + .opt_arg_index_key + .is_some() + { + lower_bound_clause_start - 2 + } else { + lower_bound_clause_start + }; + + remove_non_leading_clause( + code, + preceding_choice_instr_loc, + skeleton.clauses[target_pos].clause_start - 2, + &mut self.payload.retraction_info, + ); + } + Instruction::TryMeElse(_) => { + let new_target_loc = blunt_leading_choice_instr( + code, + clause_start, + &mut self.payload.retraction_info, + ); + + derelictize_try_me_else( + code, + clause_start, + &mut self.payload.retraction_info, + ); + set_switch_var_offset( code, index_loc, - preceding_choice_instr_loc + 1 - index_loc, + new_target_loc - index_loc, + &mut self.payload.retraction_info, + ); + + self.payload.retraction_info.push_record( + RetractionRecord::SkeletonClauseStartReplaced( + payload_compilation_target, + key, + target_pos + 1, + skeleton.clauses[target_pos + 1].clause_start, + ), + ); + + skeleton.clauses[target_pos + 1].clause_start = + skeleton.clauses[target_pos].clause_start; + } + _ => { + preceding_choice_instr_loc = find_inner_choice_instr( + code, + skeleton.clauses[target_pos - 1].clause_start, + index_loc, + ); + + remove_non_leading_clause( + code, + preceding_choice_instr_loc, + skeleton.clauses[target_pos].clause_start, &mut self.payload.retraction_info, ); + + match &mut code[preceding_choice_instr_loc] { + Instruction::TryMeElse(0) => { + set_switch_var_offset( + code, + index_loc, + preceding_choice_instr_loc + 1 - index_loc, + &mut self.payload.retraction_info, + ); + } + _ => {} + } } - _ => {} } None -- cgit v1.2.3-70-g09d2 From 83378e4373b73e4cfc4266b1920d14517ffe984a Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 15 Jan 2022 11:03:41 -0700 Subject: deduplicate but do not sort anonymous variables in toplevel (#1196) --- src/machine/system_calls.rs | 2 +- src/toplevel.pl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 6163a467..67611cc5 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -555,7 +555,7 @@ impl MachineState { let outcome = heap_loc_as_cell!( iter_to_heap_list( &mut self.heap, - seen_set.into_iter().rev(), + seen_set.into_iter(), ) ); diff --git a/src/toplevel.pl b/src/toplevel.pl index b72e0ed1..27783c45 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -292,7 +292,7 @@ write_eqs_and_read_input(B, VarList) :- % one layer of depth added for (=/2) functor maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars), append([AttrGoalVars | EquationVars], Vars1), - sort(Vars1, Vars2), + term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order. charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated), ( bb_get('$first_answer', true) -> write(' '), -- cgit v1.2.3-70-g09d2 From 11d504e8f43dc6133f2cd230a8f3249d365f4238 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sun, 16 Jan 2022 17:49:13 +0100 Subject: retain the string "[]" as is, instead of converting it to '[]' (i.e., "") This addresses #1215. --- src/machine/system_calls.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 67611cc5..c4d4d4d6 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -735,8 +735,14 @@ impl MachineState { pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option { read_heap_cell!(value, (HeapCellValueTag::CStr, cstr_atom) => { - // avoid allocating a String if possible ... - Some(AtomOrString::Atom(cstr_atom)) + // avoid allocating a String if possible: + // We must be careful to preserve the string "[]" as is, + // instead of turning it into the atom [], i.e., "". + if cstr_atom == atom!("[]") { + Some(AtomOrString::String("[]".to_string())) + } else { + Some(AtomOrString::Atom(cstr_atom)) + } } (HeapCellValueTag::Atom, (atom, arity)) => { if arity == 0 { -- cgit v1.2.3-70-g09d2 From 177c98fa95f2b57ba10186b164d717ac80277009 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sun, 16 Jan 2022 23:20:43 +0100 Subject: correct reference to '$working_directory'/2 --- crates/instructions-template/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/instructions-template/src/lib.rs b/crates/instructions-template/src/lib.rs index 1a7e02a4..76725c04 100644 --- a/crates/instructions-template/src/lib.rs +++ b/crates/instructions-template/src/lib.rs @@ -262,7 +262,7 @@ enum SystemClauseType { DeleteFile, #[strum_discriminants(strum(props(Arity = "2", Name = "$rename_file")))] RenameFile, - #[strum_discriminants(strum(props(Arity = "2", Name = "working_directory")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "$working_directory")))] WorkingDirectory, #[strum_discriminants(strum(props(Arity = "1", Name = "$delete_directory")))] DeleteDirectory, -- cgit v1.2.3-70-g09d2 From c6400550e117e59f7383717195ec72fd1f095937 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 17 Jan 2022 00:00:23 -0700 Subject: dereference second argument of '/2 --- src/machine/system_calls.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index c4d4d4d6..98130bc2 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1155,7 +1155,9 @@ impl Machine { return Ok(()); } - if let Some(next) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) { + let target = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])); + + if let Some(next) = self.machine_st.value_to_str_like(target) { if env::set_current_dir(std::path::Path::new(next.as_str())).is_ok() { return Ok(()); } -- cgit v1.2.3-70-g09d2 From 20b6816562c3513c7f55f6940864925d696af9c5 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Mon, 17 Jan 2022 20:09:50 +0100 Subject: MODIFIED: library(charsio): read_term_from_chars/2 is now called read_from_chars/2 This is for compatibility with SICStus Prolog and GNU Prolog. --- src/lib/charsio.pl | 10 +++++----- src/lib/files.pl | 2 +- src/lib/time.pl | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/charsio.pl b/src/lib/charsio.pl index 85856810..3a944301 100644 --- a/src/lib/charsio.pl +++ b/src/lib/charsio.pl @@ -3,7 +3,7 @@ get_single_char/1, read_n_chars/3, read_line_to_chars/3, - read_term_from_chars/2, + read_from_chars/2, write_term_to_chars/3, chars_base64/3]). @@ -113,17 +113,17 @@ get_single_char(C) :- ). -read_term_from_chars(Chars, Term) :- +read_from_chars(Chars, Term) :- ( var(Chars) -> - instantiation_error(read_term_from_chars/2) + instantiation_error(read_from_chars/2) ; nonvar(Term) -> - throw(error(uninstantiation_error(Term), read_term_from_chars/2)) + throw(error(uninstantiation_error(Term), read_from_chars/2)) ; '$skip_max_list'(_, -1, Chars, Chars0), Chars0 == [], partial_string(Chars) -> true ; - type_error(complete_string, Chars, read_term_from_chars/2) + type_error(complete_string, Chars, read_from_chars/2) ), '$read_term_from_chars'(Chars, Term). diff --git a/src/lib/files.pl b/src/lib/files.pl index 6989cb46..9ee1c2b9 100644 --- a/src/lib/files.pl +++ b/src/lib/files.pl @@ -174,7 +174,7 @@ file_creation_time(File, T) :- file_time_(File, Which, T) :- file_must_exist(File, file_time_/3), '$file_time'(File, Which, T0), - read_term_from_chars(T0, T). + read_from_chars(T0, T). /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/lib/time.pl b/src/lib/time.pl index 56e31fae..5da5bb59 100644 --- a/src/lib/time.pl +++ b/src/lib/time.pl @@ -49,11 +49,11 @@ :- use_module(library(error)). :- use_module(library(dcgs)). :- use_module(library(lists)). -:- use_module(library(charsio), [read_term_from_chars/2]). +:- use_module(library(charsio), [read_from_chars/2]). current_time(T) :- '$current_time'(T0), - read_term_from_chars(T0, T). + read_from_chars(T0, T). format_time([], _) --> []. format_time(['%','%'|Fs], T) --> !, "%", format_time(Fs, T). -- cgit v1.2.3-70-g09d2 From 23adfef281c1158b6ebd84ef95c01a4b0f681190 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Mon, 17 Jan 2022 20:36:51 +0100 Subject: MODIFIED: library(charsio): read_n_chars/3 is now called get_n_chars/3 This is because "read" is associated with general Prolog terms. --- src/lib/charsio.pl | 4 ++-- src/lib/pio.pl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/charsio.pl b/src/lib/charsio.pl index 3a944301..3ef732db 100644 --- a/src/lib/charsio.pl +++ b/src/lib/charsio.pl @@ -1,7 +1,7 @@ :- module(charsio, [char_type/2, chars_utf8bytes/2, get_single_char/1, - read_n_chars/3, + get_n_chars/3, read_line_to_chars/3, read_from_chars/2, write_term_to_chars/3, @@ -205,7 +205,7 @@ read_line_to_chars(Stream, Cs0, Cs) :- characters read. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -read_n_chars(Stream, N, Cs) :- +get_n_chars(Stream, N, Cs) :- can_be(integer, N), ( var(N) -> read_to_eof(Stream, Cs), diff --git a/src/lib/pio.pl b/src/lib/pio.pl index 38849a4b..db609aa6 100644 --- a/src/lib/pio.pl +++ b/src/lib/pio.pl @@ -21,7 +21,7 @@ :- use_module(library(freeze)). :- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]). :- use_module(library(lists), [member/2, maplist/2]). -:- use_module(library(charsio), [read_n_chars/3]). +:- use_module(library(charsio), [get_n_chars/3]). :- meta_predicate(phrase_from_file(2, ?)). :- meta_predicate(phrase_from_file(2, ?, ?)). @@ -62,7 +62,7 @@ reader_step(Stream, Pos, Xs0) :- set_stream_position(Stream, Pos), ( at_end_of_stream(Stream) -> Xs0 = [] - ; read_n_chars(Stream, 4096, Cs), + ; get_n_chars(Stream, 4096, Cs), partial_string(Cs, Xs0, Xs), stream_to_lazy_list(Stream, Xs) ). -- cgit v1.2.3-70-g09d2 From 516ed1fd5b4768b02580344f016a0b37d2f064a3 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Mon, 17 Jan 2022 22:00:50 +0100 Subject: ENHANCED: library(crypto): Retain a compact internal representation of the ciphertext throughout decryption. This allows efficient decryption also of very large files and long strings. It is usually highly advisable to stick to common and portable library predicates such as append/3. However, since append/3 does not yet recognize this opportunity for improvement, I apply it manually in this case, so that also very large files can be efficiently decrypted using the compact internal string representation. Without this change, decrypting a 1 GB file takes 48 GB of RAM, whereas with this change, it only takes 2 GB (one for the string, one for its copy with the appended tag). --- src/lib/crypto.pl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib/crypto.pl b/src/lib/crypto.pl index efc478ae..63696b5c 100644 --- a/src/lib/crypto.pl +++ b/src/lib/crypto.pl @@ -1,5 +1,5 @@ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Written 2020, 2021 by Markus Triska (triska@metalevel.at) + Written 2020, 2021, 2022 by Markus Triska (triska@metalevel.at) Part of Scryer Prolog. Predicates for cryptographic applications. @@ -46,6 +46,7 @@ :- use_module(library(format)). :- use_module(library(charsio)). :- use_module(library(si)). +:- use_module(library(iso_ext), [partial_string/3]). /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - hex_bytes(?Hex, ?Bytes) is det. @@ -594,7 +595,9 @@ crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :- member(Encoding, [utf8,octet]), encoding_chars(octet, CipherText0, CipherText1), maplist(char_code, TagChars, Tag), - append(CipherText1, TagChars, CipherText), + % we append the tag very efficiently, retaining a compact + % internal string representation of the ciphertext + partial_string(CipherText1, CipherText, TagChars), ( Algorithm = 'chacha20-poly1305' -> true ; domain_error('chacha20-poly1305', Algorithm, crypto_data_decrypt/6) ), -- cgit v1.2.3-70-g09d2 From 6a610ac57da0ebacecfa5ddc0cc64d0edcd64762 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 18 Jan 2022 01:12:47 +0100 Subject: FIXED: toplevel to use (newly renamed) read_from_chars/2 --- src/toplevel.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toplevel.pl b/src/toplevel.pl index 27783c45..5df86d48 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -112,7 +112,7 @@ run_goals([g(Gs0)|Goals]) :- ( ends_with_dot(Gs0) -> Gs1 = Gs0 ; append(Gs0, ".", Gs1) ), - read_term_from_chars(Gs1, Goal), + read_from_chars(Gs1, Goal), ( catch( user:Goal, Exception, -- cgit v1.2.3-70-g09d2 From 3ebf8d5db9c3b87f45f7888aa022958fb945df4f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 17 Jan 2022 17:58:09 -0700 Subject: clear alias in close before resetting the stream to null (#1231) --- src/lib/builtins.pl | 3 ++- src/machine/system_calls.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 4619bfad..a060a69c 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1468,7 +1468,8 @@ open(SourceSink, Mode, Stream, StreamOptions) :- atom(SourceSink) -> atom_chars(SourceSink, SourceSinkString) ; SourceSink = SourceSinkString - ), '$open'(SourceSinkString, Mode, Stream, Alias, EOFAction, Reposition, Type) + ), + '$open'(SourceSinkString, Mode, Stream, Alias, EOFAction, Reposition, Type) ) ). diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 98130bc2..c9d988f9 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2728,12 +2728,12 @@ impl Machine { } if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() { - let close_result = stream.close(); - if let Some(alias) = stream.options().get_alias() { self.indices.stream_aliases.remove(&alias); } + let close_result = stream.close(); + if let Err(_) = close_result { let stub = functor_stub(atom!("close"), 1); let addr = stream_as_cell!(stream); -- cgit v1.2.3-70-g09d2 From 97b9d488d4b0e71f72b5a6a385460c9d85e78373 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 17 Jan 2022 21:53:52 -0700 Subject: include library(error) in toplevel.pl (#1226) --- src/toplevel.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toplevel.pl b/src/toplevel.pl index 5df86d48..290b92e9 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -2,6 +2,7 @@ copy_term/3]). :- use_module(library(charsio)). +:- use_module(library(error)). :- use_module(library(files)). :- use_module(library(iso_ext)). :- use_module(library(lambda)). @@ -153,7 +154,6 @@ instruction_match(Term, VarList) :- ( var(Term) -> throw(error(instantiation_error, repl/0)) ; Term = [Item] -> - !, ( atom(Item) -> ( Item == user -> catch(load(user_input), E, print_exception_with_check(E)) -- cgit v1.2.3-70-g09d2 From b980ae1e8c7a2aacef7557120f2df905ba9294a0 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 17 Jan 2022 22:04:10 -0700 Subject: fix floor for f64 (#1223) --- crates/instructions-template/src/lib.rs | 78 ++++++++++++++++----------------- src/arithmetic.rs | 2 +- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/crates/instructions-template/src/lib.rs b/crates/instructions-template/src/lib.rs index 76725c04..c4c821b4 100644 --- a/crates/instructions-template/src/lib.rs +++ b/crates/instructions-template/src/lib.rs @@ -617,83 +617,83 @@ enum InstructionTemplate { #[strum_discriminants(strum(props(Arity = "1", Name = "default_trust_me")))] TryMeElse(usize), // arithmetic instruction - #[strum_discriminants(strum(props(Arity = "3", Name = "add")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "add")))] Add(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "sub")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "sub")))] Sub(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "mul")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "mul")))] Mul(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "pow")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "pow")))] Pow(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "int_pow")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "int_pow")))] IntPow(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "i_div")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "i_div")))] IDiv(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "max")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "max")))] Max(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "min")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "min")))] Min(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "int_floor_div")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "int_floor_div")))] IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "r_div")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "r_div")))] RDiv(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "div")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "div")))] Div(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "shl")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "shl")))] Shl(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "shr")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "shr")))] Shr(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "xor")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "xor")))] Xor(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "and")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "and")))] And(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "or")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "or")))] Or(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "mod")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "mod")))] Mod(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "rem")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "rem")))] Rem(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "gcd")))] + #[strum_discriminants(strum(props(Arity = "2", Name = "gcd")))] Gcd(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "sign")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "sign")))] Sign(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "cos")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "cos")))] Cos(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "sin")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "sin")))] Sin(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "tan")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "tan")))] Tan(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "log")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "log")))] Log(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "exp")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "exp")))] Exp(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "acos")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "acos")))] ACos(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "asin")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "asin")))] ASin(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "atan")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "atan")))] ATan(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "3", Name = "atan2")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "atan2")))] ATan2(ArithmeticTerm, ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "sqrt")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "sqrt")))] Sqrt(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "abs")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "abs")))] Abs(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "float")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "float")))] Float(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "truncate")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "truncate")))] Truncate(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "round")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "round")))] Round(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "ceiling")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "ceiling")))] Ceiling(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "floor")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "floor")))] Floor(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "neg")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "neg")))] Neg(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "plus")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "plus")))] Plus(ArithmeticTerm, usize), - #[strum_discriminants(strum(props(Arity = "2", Name = "bitwise_complement")))] + #[strum_discriminants(strum(props(Arity = "1", Name = "bitwise_complement")))] BitwiseComplement(ArithmeticTerm, usize), // control instructions #[strum_discriminants(strum(props(Arity = "1", Name = "allocate")))] diff --git a/src/arithmetic.rs b/src/arithmetic.rs index e909eed7..82212522 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -345,7 +345,7 @@ impl<'a> ArithmeticEvaluator<'a> { pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number { match n { &Number::Integer(_) | &Number::Fixnum(_) => *n, - &Number::Float(OrderedFloat(f)) => fixnum!(Number, f.round() as i64, arena), + &Number::Float(OrderedFloat(f)) => fixnum!(Number, f.floor() as i64, arena), &Number::Rational(ref r) => { let r_ref = r.fract_floor_ref(); let (mut fract, mut floor) = (Rational::new(), Integer::new()); -- cgit v1.2.3-70-g09d2 From ff3ec78df98c5122c3cf4c5e3eb507f5f7532a73 Mon Sep 17 00:00:00 2001 From: Adrián Arroyo Calle Date: Tue, 18 Jan 2022 19:27:27 +0100 Subject: Fix Ctrl-D (#1168) --- src/parser/lexer.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index d2487666..4696b226 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -122,19 +122,11 @@ impl<'a, R: CharRead> Lexer<'a, R> { } pub fn eof(&mut self) -> Result { - if self.reader.peek_char().is_none() { - return Ok(true); - } - let mut c = is_not_eof!(self.reader, self.lookahead_char()); while layout_char!(c) { self.skip_char(c); - if self.reader.peek_char().is_none() { - return Ok(true); - } - c = is_not_eof!(self.reader, self.lookahead_char()); } @@ -1051,6 +1043,10 @@ impl<'a, R: CharRead> Lexer<'a, R> { }; } + if c == '\u{0}' { + return Err(ParserError::UnexpectedEOF); + } + self.name_token(c) } Err(e) => Err(e), -- cgit v1.2.3-70-g09d2 From 59992c8af232f22c03b7ec358598adf4e2bc1643 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 18 Jan 2022 17:38:45 -0700 Subject: remove number/3 from arithmetic.pl (#1170) --- src/lib/arithmetic.pl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/lib/arithmetic.pl b/src/lib/arithmetic.pl index dc9ce077..ee719a18 100644 --- a/src/lib/arithmetic.pl +++ b/src/lib/arithmetic.pl @@ -94,12 +94,6 @@ number_to_rational(Eps0, Real0, Fraction) :- ), !. -number(X) :- - ( integer(X) - ; float(X) - ; rational(X) - ). - stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :- Fn1 is A + C, Fd1 is B + D, -- cgit v1.2.3-70-g09d2 From 5a132aaff4530d62b1cd01777fd6996b08ae07aa Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 18 Jan 2022 19:16:14 -0700 Subject: throw error instead of overwriting builtin export (#1225) --- src/lib.rs | 1 - src/machine/compile.rs | 6 +- src/machine/loader.rs | 36 +++ src/machine/machine_errors.rs | 14 +- src/types.rs | 54 +++- src/write.rs | 672 ------------------------------------------ 6 files changed, 98 insertions(+), 685 deletions(-) delete mode 100644 src/write.rs diff --git a/src/lib.rs b/src/lib.rs index 6cb89830..99c5d9f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,5 @@ mod raw_block; pub mod read; mod targets; pub mod types; -pub mod write; use instructions::instr; diff --git a/src/machine/compile.rs b/src/machine/compile.rs index b8ffdcf2..e11466fc 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1295,7 +1295,7 @@ fn mergeable_indexed_subsequences( fn print_overwrite_warning( compilation_target: &CompilationTarget, code_ptr: IndexPtr, - key: &PredicateKey, + key: PredicateKey, is_dynamic: bool, ) { if let CompilationTarget::Module(module_name) = compilation_target { @@ -1372,6 +1372,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { ) -> Result { let code_index = self.get_or_insert_code_index(key, predicates.compilation_target); + LS::err_on_builtin_overwrite(self, key)?; + let code_len = self.wam_prelude.code.len(); let mut code_ptr = code_len; @@ -1463,7 +1465,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { print_overwrite_warning( &predicates.compilation_target, code_index.get(), - &key, + key, settings.is_dynamic(), ); diff --git a/src/machine/loader.rs b/src/machine/loader.rs index e4a40a20..0b436f6f 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -18,6 +18,7 @@ use slice_deque::{sdeq, SliceDeque}; use std::cell::Cell; use std::convert::TryFrom; +use std::fmt; use std::mem; use std::ops::{Deref, DerefMut}; use std::rc::Rc; @@ -156,6 +157,15 @@ pub enum CompilationTarget { User, } +impl fmt::Display for CompilationTarget { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + CompilationTarget::User => write!(f, "user"), + CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name.as_str()), + } + } +} + impl Default for CompilationTarget { #[inline] fn default() -> Self { @@ -252,6 +262,10 @@ pub trait LoadState<'a>: Sized { fn should_drop_load_state(loader: &Loader<'a, Self>) -> bool; fn reset_machine(loader: &mut Loader<'a, Self>); fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState; + fn err_on_builtin_overwrite( + loader: &Loader<'a, Self>, + key: PredicateKey, + ) -> Result<(), SessionError>; } pub struct LiveLoadAndMachineState<'a> { @@ -309,6 +323,20 @@ impl<'a> LoadState<'a> for LiveLoadAndMachineState<'a> { fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState { loader.machine_st } + + #[inline(always)] + fn err_on_builtin_overwrite( + loader: &Loader<'a, Self>, + key: PredicateKey, + ) -> Result<(), SessionError> { + if let Some(builtins) = loader.wam_prelude.indices.modules.get(&atom!("builtins")) { + if builtins.module_decl.exports.contains(&ModuleExport::PredicateKey(key)) { + return Err(SessionError::CannotOverwriteBuiltIn(key)); + } + } + + Ok(()) + } } impl<'a> LoadState<'a> for BootstrappingLoadState<'a> { @@ -352,6 +380,14 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> { fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState { &mut loader.term_stream.parser.lexer.machine_st } + + #[inline(always)] + fn err_on_builtin_overwrite( + _loader: &Loader<'a, Self>, + _key: PredicateKey, + ) -> Result<(), SessionError> { + Ok(()) + } } pub struct Loader<'a, LS: LoadState<'a>> { diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 37910002..d2f589df 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -401,18 +401,14 @@ impl MachineState { pub(super) fn session_error(&mut self, err: SessionError) -> MachineError { match err { - // SessionError::CannotOverwriteBuiltIn(pred_str) | - /* - SessionError::CannotOverwriteImport(pred_str) => { - Self::permission_error( - atom_tbl, - h, + SessionError::CannotOverwriteBuiltIn(key) => { + // SessionError::CannotOverwriteImport(pred_atom) => { + self.permission_error( Permission::Modify, atom!("private_procedure"), - functor!(atom(pred_str)), + functor_stub(key.0, key.1).into_iter().collect::(), ) } - */ SessionError::ExistenceError(err) => self.existence_error(err), // SessionError::InvalidFileName(filename) => { // Self::existence_error(h, ExistenceError::Module(filename)) @@ -903,7 +899,7 @@ pub enum ExistenceError { #[derive(Debug)] pub enum SessionError { CompilationError(CompilationError), - // CannotOverwriteBuiltIn(Atom), + CannotOverwriteBuiltIn(PredicateKey), // CannotOverwriteImport(Atom), ExistenceError(ExistenceError), // InvalidFileName(Atom), diff --git a/src/types.rs b/src/types.rs index b4278f41..b151ee23 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,9 +3,11 @@ use crate::atom_table::*; use crate::forms::*; use crate::machine::machine_indices::*; use crate::machine::partial_string::PartialString; +use crate::machine::streams::*; use crate::parser::ast::Fixnum; +use crate::parser::rug::{Integer, Rational}; -use modular_bitfield::prelude::*; +use ordered_float::OrderedFloat; use std::cmp::Ordering; use std::convert::TryFrom; @@ -242,6 +244,56 @@ pub struct HeapCellValue { tag: HeapCellValueTag, } +impl fmt::Display for HeapCellValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + read_heap_cell!(*self, + (HeapCellValueTag::Atom, (name, arity)) => { + if arity == 0 { + write!(f, "{}", name.as_str()) + } else { + write!( + f, + "{}/{}", + name.as_str(), + arity + ) + } + } + (HeapCellValueTag::PStr, pstr_atom) => { + let pstr = PartialString::from(pstr_atom); + + write!( + f, + "pstr ( \"{}\", )", + pstr.as_str_from(0) + ) + } + (HeapCellValueTag::Cons, c) => { + match_untyped_arena_ptr!(c, + (ArenaHeaderTag::Integer, n) => { + write!(f, "{}", n) + } + (ArenaHeaderTag::Rational, r) => { + write!(f, "{}", r) + } + (ArenaHeaderTag::F64, fl) => { + write!(f, "{}", fl) + } + (ArenaHeaderTag::Stream, stream) => { + write!(f, "$stream({})", stream.as_ptr() as usize) + } + _ => { + write!(f, "") + } + ) + } + _ => { + unreachable!() + } + ) + } +} + impl fmt::Debug for HeapCellValue { fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result { match self.get_tag() { diff --git a/src/write.rs b/src/write.rs deleted file mode 100644 index 38f8b139..00000000 --- a/src/write.rs +++ /dev/null @@ -1,672 +0,0 @@ -use crate::arena::*; -use crate::atom_table::*; -use crate::forms::*; -use crate::instructions::*; -use crate::machine::loader::CompilationTarget; -use crate::machine::machine_errors::*; -use crate::machine::machine_indices::*; -use crate::machine::partial_string::*; -use crate::machine::streams::*; -use crate::parser::rug::{Integer, Rational}; -use crate::types::*; - -use ordered_float::OrderedFloat; - -use std::fmt; - -/* -impl fmt::Display for REPLCodePtr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - REPLCodePtr::AddDiscontiguousPredicate => { - write!(f, "REPLCodePtr::AddDiscontiguousPredicate") - } - REPLCodePtr::AddDynamicPredicate => write!(f, "REPLCodePtr::AddDynamicPredicate"), - REPLCodePtr::AddMultifilePredicate => write!(f, "REPLCodePtr::AddMultifilePredicate"), - REPLCodePtr::AddGoalExpansionClause => write!(f, "REPLCodePtr::AddGoalExpansionClause"), - REPLCodePtr::AddTermExpansionClause => write!(f, "REPLCodePtr::AddTermExpansionClause"), - REPLCodePtr::AddInSituFilenameModule => { - write!(f, "REPLCodePtr::AddInSituFilenameModule") - } - REPLCodePtr::AbolishClause => write!(f, "REPLCodePtr::AbolishClause"), - REPLCodePtr::Assertz => write!(f, "REPLCodePtr::Assertz"), - REPLCodePtr::Asserta => write!(f, "REPLCodePtr::Asserta"), - REPLCodePtr::Retract => write!(f, "REPLCodePtr::Retract"), - REPLCodePtr::ClauseToEvacuable => write!(f, "REPLCodePtr::ClauseToEvacuable"), - REPLCodePtr::ScopedClauseToEvacuable => { - write!(f, "REPLCodePtr::ScopedClauseToEvacuable") - } - REPLCodePtr::ConcludeLoad => write!(f, "REPLCodePtr::ConcludeLoad"), - REPLCodePtr::DeclareModule => write!(f, "REPLCodePtr::DeclareModule"), - REPLCodePtr::LoadCompiledLibrary => write!(f, "REPLCodePtr::LoadCompiledLibrary"), - REPLCodePtr::LoadContextSource => write!(f, "REPLCodePtr::LoadContextSource"), - REPLCodePtr::LoadContextFile => write!(f, "REPLCodePtr::LoadContextFile"), - REPLCodePtr::LoadContextDirectory => write!(f, "REPLCodePtr::LoadContextDirectory"), - REPLCodePtr::LoadContextModule => write!(f, "REPLCodePtr::LoadContextModule"), - REPLCodePtr::LoadContextStream => write!(f, "REPLCodePtr::LoadContextStream"), - REPLCodePtr::PopLoadContext => write!(f, "REPLCodePtr::PopLoadContext"), - REPLCodePtr::PopLoadStatePayload => write!(f, "REPLCodePtr::PopLoadStatePayload"), - REPLCodePtr::PushLoadContext => write!(f, "REPLCodePtr::PushLoadContext"), - REPLCodePtr::PushLoadStatePayload => write!(f, "REPLCodePtr::PushLoadStatePayload"), - REPLCodePtr::UseModule => write!(f, "REPLCodePtr::UseModule"), - REPLCodePtr::MetaPredicateProperty => write!(f, "REPLCodePtr::MetaPredicateProperty"), - REPLCodePtr::BuiltInProperty => write!(f, "REPLCodePtr::BuiltInProperty"), - REPLCodePtr::DynamicProperty => write!(f, "REPLCodePtr::DynamicProperty"), - REPLCodePtr::MultifileProperty => write!(f, "REPLCodePtr::MultifileProperty"), - REPLCodePtr::DiscontiguousProperty => write!(f, "REPLCodePtr::DiscontiguousProperty"), - REPLCodePtr::IsConsistentWithTermQueue => { - write!(f, "REPLCodePtr::IsConsistentWithTermQueue") - } - REPLCodePtr::FlushTermQueue => write!(f, "REPLCodePtr::FlushTermQueue"), - REPLCodePtr::RemoveModuleExports => write!(f, "REPLCodePtr::RemoveModuleExports"), - REPLCodePtr::AddNonCountedBacktracking => { - write!(f, "REPLCodePtr::AddNonCountedBacktracking") - } - } - } -} -*/ - -impl fmt::Display for IndexPtr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &IndexPtr::DynamicUndefined => write!(f, "undefined"), - &IndexPtr::Undefined => write!(f, "undefined"), - &IndexPtr::DynamicIndex(i) | &IndexPtr::Index(i) => write!(f, "{}", i), - } - } -} - -impl fmt::Display for CompilationTarget { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - CompilationTarget::User => write!(f, "user"), - CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name.as_str()), - } - } -} - -/* -impl fmt::Display for FactInstruction { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &FactInstruction::GetConstant(lvl, ref constant, ref r) => { - write!(f, "get_constant {}, {}{}", constant, lvl, r.reg_num()) - } - &FactInstruction::GetList(lvl, ref r) => { - write!(f, "get_list {}{}", lvl, r.reg_num()) - } - &FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => { - write!( - f, - "get_partial_string({}, {}, {}, {})", - lvl, - s.as_str(), - r, - has_tail - ) - } - &FactInstruction::GetStructure(ref ct, ref arity, ref r) => { - write!(f, "get_structure {}/{}, {}", ct.name().as_str(), arity, r) - } - &FactInstruction::GetValue(ref x, ref a) => { - write!(f, "get_value {}, A{}", x, a) - } - &FactInstruction::GetVariable(ref x, ref a) => { - write!(f, "fact:get_variable {}, A{}", x, a) - } - &FactInstruction::UnifyConstant(ref constant) => { - write!(f, "unify_constant {}", constant) - } - &FactInstruction::UnifyVariable(ref r) => { - write!(f, "unify_variable {}", r) - } - &FactInstruction::UnifyLocalValue(ref r) => { - write!(f, "unify_local_value {}", r) - } - &FactInstruction::UnifyValue(ref r) => { - write!(f, "unify_value {}", r) - } - &FactInstruction::UnifyVoid(n) => { - write!(f, "unify_void {}", n) - } - } - } -} - -impl fmt::Display for QueryInstruction { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &QueryInstruction::GetVariable(ref x, ref a) => { - write!(f, "query:get_variable {}, A{}", x, a) - } - &QueryInstruction::PutConstant(lvl, ref constant, ref r) => { - write!(f, "put_constant {}, {}{}", constant, lvl, r.reg_num()) - } - &QueryInstruction::PutList(lvl, ref r) => { - write!(f, "put_list {}{}", lvl, r.reg_num()) - } - &QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => { - write!( - f, - "put_partial_string({}, {}, {}, {})", - lvl, - s.as_str(), - r, - has_tail - ) - } - &QueryInstruction::PutStructure(ref ct, ref arity, ref r) => { - write!(f, "put_structure {}/{}, {}", ct.name().as_str(), arity, r) - } - &QueryInstruction::PutUnsafeValue(y, a) => write!(f, "put_unsafe_value Y{}, A{}", y, a), - &QueryInstruction::PutValue(ref x, ref a) => write!(f, "put_value {}, A{}", x, a), - &QueryInstruction::PutVariable(ref x, ref a) => write!(f, "put_variable {}, A{}", x, a), - &QueryInstruction::SetConstant(ref constant) => write!(f, "set_constant {}", constant), - &QueryInstruction::SetLocalValue(ref r) => write!(f, "set_local_value {}", r), - &QueryInstruction::SetVariable(ref r) => write!(f, "set_variable {}", r), - &QueryInstruction::SetValue(ref r) => write!(f, "set_value {}", r), - &QueryInstruction::SetVoid(n) => write!(f, "set_void {}", n), - } - } -} - -impl fmt::Display for CompareNumberQT { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &CompareNumberQT::GreaterThan => write!(f, ">"), - &CompareNumberQT::GreaterThanOrEqual => write!(f, ">="), - &CompareNumberQT::LessThan => write!(f, "<"), - &CompareNumberQT::LessThanOrEqual => write!(f, "<="), - &CompareNumberQT::NotEqual => write!(f, "=\\="), - &CompareNumberQT::Equal => write!(f, "=:="), - } - } -} - -impl fmt::Display for CompareTermQT { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &CompareTermQT::GreaterThan => write!(f, "@>"), - &CompareTermQT::GreaterThanOrEqual => write!(f, "@>="), - &CompareTermQT::LessThan => write!(f, "@<"), - &CompareTermQT::LessThanOrEqual => write!(f, "@<="), - } - } -} - -impl fmt::Display for ClauseType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &ClauseType::System(SystemClauseType::SetCutPoint(r)) => { - write!(f, "$set_cp({})", r) - } - &ClauseType::Named(ref name, _, ref idx) => { - let idx = idx.0.get(); - write!(f, "{}/{}", name.as_str(), idx) - } - ref ct => { - write!(f, "{}", ct.name().as_str()) - } - } - } -} -*/ - -impl fmt::Display for HeapCellValue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - read_heap_cell!(*self, - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - write!(f, "{}", name.as_str()) - } else { - write!( - f, - "{}/{}", - name.as_str(), - arity - ) - } - } - (HeapCellValueTag::PStr, pstr_atom) => { - let pstr = PartialString::from(pstr_atom); - - write!( - f, - "pstr ( \"{}\", )", - pstr.as_str_from(0) - ) - } - (HeapCellValueTag::Cons, c) => { - match_untyped_arena_ptr!(c, - (ArenaHeaderTag::Integer, n) => { - write!(f, "{}", n) - } - (ArenaHeaderTag::Rational, r) => { - write!(f, "{}", r) - } - (ArenaHeaderTag::F64, fl) => { - write!(f, "{}", fl) - } - (ArenaHeaderTag::Stream, stream) => { - write!(f, "$stream({})", stream.as_ptr() as usize) - } - _ => { - write!(f, "") - } - ) - } - _ => { - unreachable!() - } - ) - } -} - -/* -impl fmt::Display for ControlInstruction { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &ControlInstruction::Allocate(num_cells) => write!(f, "allocate {}", num_cells), - &ControlInstruction::CallClause(ref ct, arity, pvs, true, true) => { - write!(f, "call_with_default_policy {}/{}, {}", ct, arity, pvs) - } - &ControlInstruction::CallClause(ref ct, arity, pvs, false, true) => { - write!(f, "execute_with_default_policy {}/{}, {}", ct, arity, pvs) - } - &ControlInstruction::CallClause(ref ct, arity, pvs, true, false) => { - write!(f, "execute {}/{}, {}", ct, arity, pvs) - } - &ControlInstruction::CallClause(ref ct, arity, pvs, false, false) => { - write!(f, "call {}/{}, {}", ct, arity, pvs) - } - &ControlInstruction::Deallocate => write!(f, "deallocate"), - &ControlInstruction::JmpBy(arity, offset, pvs, false) => { - write!(f, "jmp_by_call {}/{}, {}", offset, arity, pvs) - } - &ControlInstruction::JmpBy(arity, offset, pvs, true) => { - write!(f, "jmp_by_execute {}/{}, {}", offset, arity, pvs) - } - &ControlInstruction::RevJmpBy(offset) => { - write!(f, "rev_jmp_by {}", offset) - } - &ControlInstruction::Proceed => write!(f, "proceed"), - } - } -} -*/ - -impl fmt::Display for IndexedChoiceInstruction { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &IndexedChoiceInstruction::Try(offset) => write!(f, "try {}", offset), - &IndexedChoiceInstruction::Retry(offset) => write!(f, "retry {}", offset), - &IndexedChoiceInstruction::Trust(offset) => write!(f, "trust {}", offset), - } - } -} - -/* -impl fmt::Display for ChoiceInstruction { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &ChoiceInstruction::DynamicElse(offset, Death::Infinity, NextOrFail::Next(i)) => { - write!(f, "dynamic_else {}, {}, {}", offset, "inf", i) - } - &ChoiceInstruction::DynamicElse(offset, Death::Infinity, NextOrFail::Fail(i)) => { - write!(f, "dynamic_else {}, {}, fail({})", offset, "inf", i) - } - &ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Next(i)) => { - write!(f, "dynamic_else {}, {}, {}", offset, d, i) - } - &ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => { - write!(f, "dynamic_else {}, {}, fail({})", offset, d, i) - } - &ChoiceInstruction::DynamicInternalElse( - offset, - Death::Infinity, - NextOrFail::Next(i), - ) => { - write!(f, "dynamic_internal_else {}, {}, {}", offset, "inf", i) - } - &ChoiceInstruction::DynamicInternalElse( - offset, - Death::Infinity, - NextOrFail::Fail(i), - ) => { - write!( - f, - "dynamic_internal_else {}, {}, fail({})", - offset, "inf", i - ) - } - &ChoiceInstruction::DynamicInternalElse( - offset, - Death::Finite(d), - NextOrFail::Next(i), - ) => { - write!(f, "dynamic_internal_else {}, {}, {}", offset, d, i) - } - &ChoiceInstruction::DynamicInternalElse( - offset, - Death::Finite(d), - NextOrFail::Fail(i), - ) => { - write!(f, "dynamic_internal_else {}, {}, fail({})", offset, d, i) - } - &ChoiceInstruction::TryMeElse(offset) => write!(f, "try_me_else {}", offset), - &ChoiceInstruction::DefaultRetryMeElse(offset) => { - write!(f, "retry_me_else_by_default {}", offset) - } - &ChoiceInstruction::RetryMeElse(offset) => write!(f, "retry_me_else {}", offset), - &ChoiceInstruction::DefaultTrustMe(_) => write!(f, "trust_me_by_default"), - &ChoiceInstruction::TrustMe(_) => write!(f, "trust_me"), - } - } -} -*/ - -impl fmt::Display for IndexingCodePtr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &IndexingCodePtr::DynamicExternal(o) => { - write!(f, "IndexingCodePtr::DynamicExternal({})", o) - } - &IndexingCodePtr::External(o) => { - write!(f, "IndexingCodePtr::External({})", o) - } - &IndexingCodePtr::Fail => { - write!(f, "IndexingCodePtr::Fail") - } - &IndexingCodePtr::Internal(o) => { - write!(f, "IndexingCodePtr::Internal({})", o) - } - } - } -} - -impl fmt::Display for IndexingInstruction { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &IndexingInstruction::SwitchOnTerm(a, v, c, l, s) => { - write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s) - } - &IndexingInstruction::SwitchOnConstant(ref constants) => { - write!(f, "switch_on_constant {}", constants.len()) - } - &IndexingInstruction::SwitchOnStructure(ref structures) => { - write!(f, "switch_on_structure {}", structures.len()) - } - } - } -} - -impl fmt::Display for SessionError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &SessionError::ExistenceError(ref err) => { - write!(f, "{}", err) - } - // &SessionError::CannotOverwriteBuiltIn(ref msg) => { - // write!(f, "cannot overwrite {}", msg) - // } - // &SessionError::CannotOverwriteImport(ref msg) => { - // write!(f, "cannot overwrite import {}", msg) - // } - // &SessionError::InvalidFileName(ref filename) => { - // write!(f, "filename {} is invalid", filename) - // } - &SessionError::ModuleDoesNotContainExport(ref module, ref key) => { - write!( - f, - "module {} does not contain claimed export {}/{}", - module.as_str(), - key.0.as_str(), - key.1, - ) - } - &SessionError::OpIsInfixAndPostFix(_) => { - write!(f, "cannot define an op to be both postfix and infix.") - } - &SessionError::NamelessEntry => { - write!(f, "the predicate head is not an atom or clause.") - } - &SessionError::CompilationError(ref e) => { - write!(f, "syntax_error({:?})", e) - } - &SessionError::QueryCannotBeDefinedAsFact => { - write!(f, "queries cannot be defined as facts.") - } - &SessionError::ModuleCannotImportSelf(ref module_name) => { - write!( - f, - "modules ({}, in this case) cannot import themselves.", - module_name.as_str() - ) - } - &SessionError::PredicateNotMultifileOrDiscontiguous( - ref compilation_target, - ref key, - ) => { - write!( - f, - "module {} does not define {}/{} as multifile or discontiguous.", - compilation_target.module_name().as_str(), - key.0.as_str(), - key.1 - ) - } - } - } -} - -impl fmt::Display for ExistenceError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &ExistenceError::Module(module_name) => { - write!(f, "the module {} does not exist", module_name.as_str()) - } - &ExistenceError::ModuleSource(ref module_source) => { - write!(f, "the source/sink {} does not exist", module_source) - } - &ExistenceError::Procedure(name, arity) => { - write!( - f, - "the procedure {}/{} does not exist", - name.as_str(), - arity - ) - } - &ExistenceError::SourceSink(ref addr) => { - write!(f, "the source/sink {} does not exist", addr) - } - &ExistenceError::Stream(ref addr) => { - write!(f, "the stream at {} does not exist", addr) - } - } - } -} - -impl fmt::Display for ModuleSource { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &ModuleSource::File(ref file) => { - write!(f, "at the file {}", file.as_str()) - } - &ModuleSource::Library(ref library) => { - write!(f, "at library({})", library.as_str()) - } - } - } -} - -impl fmt::Display for IndexingLine { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &IndexingLine::Indexing(ref indexing_instr) => { - write!(f, "{}", indexing_instr) - } - &IndexingLine::IndexedChoice(ref indexed_choice_instrs) => { - for indexed_choice_instr in indexed_choice_instrs { - write!(f, "{}", indexed_choice_instr)?; - } - - Ok(()) - } - &IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => { - for indexed_choice_instr in indexed_choice_instrs { - write!(f, "dynamic({})", indexed_choice_instr)?; - } - - Ok(()) - } - } - } -} - -/* -impl fmt::Display for Line { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &Line::Arithmetic(ref arith_instr) => write!(f, "{}", arith_instr), - &Line::Choice(ref choice_instr) => write!(f, "{}", choice_instr), - &Line::Control(ref control_instr) => write!(f, "{}", control_instr), - &Line::Cut(ref cut_instr) => write!(f, "{}", cut_instr), - &Line::Fact(ref fact_instr) => write!(f, "{}", fact_instr), - &Line::IndexingCode(ref indexing_instrs) => { - for indexing_instr in indexing_instrs { - write!(f, "{}", indexing_instr)?; - } - - Ok(()) - } - &Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr), - &Line::DynamicIndexedChoice(ref indexed_choice_instr) => { - write!(f, "{}", indexed_choice_instr) - } - &Line::Query(ref query_instr) => write!(f, "{}", query_instr), - } - } -} -*/ -/* - -impl fmt::Display for ArithmeticTerm { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &ArithmeticTerm::Reg(r) => write!(f, "{}", r), - &ArithmeticTerm::Interm(i) => write!(f, "@{}", i), - &ArithmeticTerm::Number(ref n) => write!(f, "{}", n), - } - } -} - -impl fmt::Display for ArithmeticInstruction { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &ArithmeticInstruction::Abs(ref a1, ref t) => write!(f, "abs {}, @{}", a1, t), - &ArithmeticInstruction::Add(ref a1, ref a2, ref t) => { - write!(f, "add {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Sub(ref a1, ref a2, ref t) => { - write!(f, "sub {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Mul(ref a1, ref a2, ref t) => { - write!(f, "mul {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Pow(ref a1, ref a2, ref t) => { - write!(f, "** {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::IntPow(ref a1, ref a2, ref t) => { - write!(f, "^ {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Div(ref a1, ref a2, ref t) => { - write!(f, "div {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::IDiv(ref a1, ref a2, ref t) => { - write!(f, "idiv {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Max(ref a1, ref a2, ref t) => { - write!(f, "max {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Min(ref a1, ref a2, ref t) => { - write!(f, "min {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, ref t) => { - write!(f, "int_floor_div {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::RDiv(ref a1, ref a2, ref t) => { - write!(f, "rdiv {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Gcd(ref a1, ref a2, ref t) => { - write!(f, "gcd {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Shl(ref a1, ref a2, ref t) => { - write!(f, "shl {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Shr(ref a1, ref a2, ref t) => { - write!(f, "shr {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Xor(ref a1, ref a2, ref t) => { - write!(f, "xor {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::And(ref a1, ref a2, ref t) => { - write!(f, "and {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Or(ref a1, ref a2, ref t) => { - write!(f, "or {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Mod(ref a1, ref a2, ref t) => { - write!(f, "mod {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Rem(ref a1, ref a2, ref t) => { - write!(f, "rem {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::ATan2(ref a1, ref a2, ref t) => { - write!(f, "atan2 {}, {}, @{}", a1, a2, t) - } - &ArithmeticInstruction::Plus(ref a, ref t) => write!(f, "plus {}, @{}", a, t), - &ArithmeticInstruction::Sign(ref a, ref t) => write!(f, "sign {}, @{}", a, t), - &ArithmeticInstruction::Neg(ref a, ref t) => write!(f, "neg {}, @{}", a, t), - &ArithmeticInstruction::Cos(ref a, ref t) => write!(f, "cos {}, @{}", a, t), - &ArithmeticInstruction::Sin(ref a, ref t) => write!(f, "sin {}, @{}", a, t), - &ArithmeticInstruction::Tan(ref a, ref t) => write!(f, "tan {}, @{}", a, t), - &ArithmeticInstruction::ATan(ref a, ref t) => write!(f, "atan {}, @{}", a, t), - &ArithmeticInstruction::ASin(ref a, ref t) => write!(f, "asin {}, @{}", a, t), - &ArithmeticInstruction::ACos(ref a, ref t) => write!(f, "acos {}, @{}", a, t), - &ArithmeticInstruction::Log(ref a, ref t) => write!(f, "log {}, @{}", a, t), - &ArithmeticInstruction::Exp(ref a, ref t) => write!(f, "exp {}, @{}", a, t), - &ArithmeticInstruction::Sqrt(ref a, ref t) => write!(f, "sqrt {}, @{}", a, t), - &ArithmeticInstruction::BitwiseComplement(ref a, ref t) => { - write!(f, "bitwise_complement {}, @{}", a, t) - } - &ArithmeticInstruction::Truncate(ref a, ref t) => write!(f, "truncate {}, @{}", a, t), - &ArithmeticInstruction::Round(ref a, ref t) => write!(f, "round {}, @{}", a, t), - &ArithmeticInstruction::Ceiling(ref a, ref t) => write!(f, "ceiling {}, @{}", a, t), - &ArithmeticInstruction::Floor(ref a, ref t) => write!(f, "floor {}, @{}", a, t), - &ArithmeticInstruction::Float(ref a, ref t) => write!(f, "float {}, @{}", a, t), - } - } -} - -impl fmt::Display for CutInstruction { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &CutInstruction::Cut(r) => write!(f, "cut {}", r), - &CutInstruction::NeckCut => write!(f, "neck_cut"), - &CutInstruction::GetLevel(r) => write!(f, "get_level {}", r), - &CutInstruction::GetLevelAndUnify(r) => write!(f, "get_level_and_unify {}", r), - } - } -} -*/ -/* -impl fmt::Display for Level { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &Level::Root | &Level::Shallow => write!(f, "A"), - &Level::Deep => write!(f, "X"), - } - } -} -*/ -- cgit v1.2.3-70-g09d2 From f6116510a1cd2ee126d0a29230343f5db1e3ee0a Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 18 Jan 2022 21:31:14 -0700 Subject: print -0.0 as 0.0 (#1164) --- src/forms.rs | 4 ++-- src/heap_print.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/forms.rs b/src/forms.rs index 372613b8..3ccb7575 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -635,7 +635,7 @@ impl Number { match self { &Number::Fixnum(n) => n.get_num() < 0, &Number::Integer(ref n) => &**n < &0, - &Number::Float(OrderedFloat(f)) => f.is_sign_negative(), + &Number::Float(OrderedFloat(f)) => f.is_sign_negative() && OrderedFloat(f) != -0f64, &Number::Rational(ref r) => &**r < &0, } } @@ -645,7 +645,7 @@ impl Number { match self { &Number::Fixnum(n) => n.get_num() == 0, &Number::Integer(ref n) => &**n == &0, - &Number::Float(f) => f == OrderedFloat(0f64), + &Number::Float(f) => f == OrderedFloat(0f64) || f == OrderedFloat(-0f64), &Number::Rational(ref r) => &**r == &0, } } diff --git a/src/heap_print.rs b/src/heap_print.rs index cb8e34e5..af9503df 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -933,8 +933,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { match n { NumberFocus::Unfocused(n) => match n { - Number::Float(fl) => { - let OrderedFloat(fl) = fl; + Number::Float(OrderedFloat(mut fl)) => { + if OrderedFloat(fl) == -0f64 { + fl = 0f64; + } + let output_str = format!("{0:<20?}", fl); push_space_if_amb!(self, &output_str, { @@ -945,9 +948,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.print_rational(r, add_brackets); return; } - Number::Fixnum(n) => { - append_str!(self, &format!("{}", n.get_num())); - } n => { let output_str = format!("{}", n); -- cgit v1.2.3-70-g09d2 From 0da9d1c036c9c377ce7e8f7eb332a9337bcad9a0 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Wed, 19 Jan 2022 23:31:55 +0100 Subject: ENHANCED: more specific warning when initialization/1 fails (#1149) --- src/loader.pl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/loader.pl b/src/loader.pl index dd26bbb8..7c33d51e 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -92,16 +92,19 @@ run_initialization_goals(Module) :- % FIXME: failing here. also, see add_module. findall(Module:Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals), abolish(Module:'$initialization_goals'/1), - ( maplist(Module:call, Goals) -> - true - ; %% initialization goals can fail without thwarting the load. - write('Warning: initialization/1 failed for: '), - writeq(maplist(Module:call, Goals)), - nl - ) + maplist(loader:success_or_warning(Module), Goals) ; true ). +success_or_warning(Module, Goal) :- + ( Module:call(Goal) -> + true + ; %% initialization goals can fail without thwarting the load. + write('Warning: initialization/1 failed for: '), + writeq(Goal), + nl + ). + run_initialization_goals :- prolog_load_context(module, Module), run_initialization_goals(user), -- cgit v1.2.3-70-g09d2 From b703303dd4347c6e5696e13564b0d782f014d25a Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Thu, 20 Jan 2022 00:48:30 +0100 Subject: omit module prefix, because the goals are already module-qualified --- src/loader.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/loader.pl b/src/loader.pl index 7c33d51e..10e083f0 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -92,12 +92,12 @@ run_initialization_goals(Module) :- % FIXME: failing here. also, see add_module. findall(Module:Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals), abolish(Module:'$initialization_goals'/1), - maplist(loader:success_or_warning(Module), Goals) + maplist(loader:success_or_warning, Goals) ; true ). -success_or_warning(Module, Goal) :- - ( Module:call(Goal) -> +success_or_warning(Goal) :- + ( call(Goal) -> true ; %% initialization goals can fail without thwarting the load. write('Warning: initialization/1 failed for: '), -- cgit v1.2.3-70-g09d2 From 11b96875e0e5994aa3d2823f8017e68f950b9855 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 19 Jan 2022 20:07:15 -0700 Subject: streamline and fix phrase/{2,3} (#1237) --- src/lib/dcgs.pl | 69 ++++++++++++++++++--------------------------------------- 1 file changed, 22 insertions(+), 47 deletions(-) diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl index 35a0f27d..5f8543ed 100644 --- a/src/lib/dcgs.pl +++ b/src/lib/dcgs.pl @@ -25,47 +25,48 @@ load_context(GRBody, Module, GRBody0) :- :- meta_predicate phrase(2, ?, ?). phrase(GRBody, S0) :- - phrase(GRBody, S0, []). + load_context(GRBody, Module, GRBody0), + phrase(GRBody0, S0, [], Module). phrase(GRBody, S0, S) :- + load_context(GRBody, Module, GRBody0), + phrase(GRBody0, S0, S, Module). + +phrase(GRBody, S0, S, Module) :- ( var(GRBody) -> throw(error(instantiation_error, phrase/3)) - ; load_context(GRBody, Module, GRBody0), - dcg_constr(GRBody0) -> - ( var(Module) -> - phrase_(GRBody0, S0, S) - ; phrase_(GRBody0, S0, S, Module) - ) - ; functor(GRBody, _, _) -> - call(GRBody, S0, S) - ; throw(error(type_error(callable, GRBody), phrase/3)) + ; dcg_constr(GRBody) -> + phrase_(GRBody, S0, S, Module) + ; callable(GRBody) -> + call(Module:GRBody, S0, S) + ; throw(error(type_error(callable, Module:GRBody), phrase/3)) ). phrase_([], S, S, _). phrase_(!, S, S, _). phrase_((A, B), S0, S, M) :- - phrase(M:A, S0, S1), - phrase(M:B, S1, S). + phrase(A, S0, S1, M), + phrase(B, S1, S, M). phrase_((A -> B ; C), S0, S, M) :- - ( phrase(M:A, S0, S1) -> - phrase(M:B, S1, S) - ; phrase(M:C, S0, S) + ( phrase(A, S0, S1, M) -> + phrase(B, S1, S, M) + ; phrase(C, S0, S, M) ). phrase_((A ; B), S0, S, M) :- - ( phrase(M:A, S0, S) - ; phrase(M:B, S0, S) + ( phrase(A, S0, S, M) + ; phrase(B, S0, S, M) ). phrase_((A | B), S0, S, M) :- - ( phrase(M:A, S0, S) - ; phrase(M:B, S0, S) + ( phrase(A, S0, S, M) + ; phrase(B, S0, S, M) ). phrase_({G}, S, S, M) :- call(M:G). phrase_(call(G), S0, S, M) :- call(M:G, S0, S). phrase_((A -> B), S0, S, M) :- - ( phrase(M:A, S0, S1) -> - phrase(M:B, S1, S) + ( phrase(A, S0, S1, M) -> + phrase(B, S1, S, M) ; fail ). phrase_(phrase(NonTerminal), S0, S, M) :- @@ -73,32 +74,6 @@ phrase_(phrase(NonTerminal), S0, S, M) :- phrase_([T|Ts], S0, S, _) :- append([T|Ts], S, S0). -phrase_([], S, S). -phrase_(!, S, S). -phrase_(M:G, S0, S) :- - phrase_(G, S0, S, M). -phrase_((A, B), S0, S) :- - phrase(A, S0, S1), - phrase(B, S1, S). -phrase_((A -> B ; C), S0, S) :- - ( phrase(A, S0, S1) -> - phrase(B, S1, S) - ; phrase(C, S0, S) - ). -phrase_((A ; B), S0, S) :- - ( phrase(A, S0, S) ; phrase(B, S0, S) ). -phrase_((A | B), S0, S) :- - ( phrase(A, S0, S) ; phrase(B, S0, S) ). -phrase_({G}, S0, S) :- - ( call(G), S0 = S ). -phrase_(call(G), S0, S) :- - call(G, S0, S). -phrase_((A -> B), S0, S) :- - phrase((A -> B ; fail), S0, S). -phrase_(phrase(NonTerminal), S0, S) :- - phrase(NonTerminal, S0, S). -phrase_([T|Ts], S0, S) :- - append([T|Ts], S, S0). % The same version of the below two dcg_rule clauses, but with module scoping. dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :- -- cgit v1.2.3-70-g09d2 From 1854338ff460c4dd00f91bac12e76f501fc7b94b Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 19 Jan 2022 20:19:47 -0700 Subject: throw errors from phrase/{2,3} where expected (#1220) --- src/lib/dcgs.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl index 5f8543ed..10eab327 100644 --- a/src/lib/dcgs.pl +++ b/src/lib/dcgs.pl @@ -72,6 +72,7 @@ phrase_((A -> B), S0, S, M) :- phrase_(phrase(NonTerminal), S0, S, M) :- phrase(NonTerminal, S0, S, M). phrase_([T|Ts], S0, S, _) :- + must_be(list, [T|Ts]), append([T|Ts], S, S0). -- cgit v1.2.3-70-g09d2 From 5dddf0a4604380820ab0f3e5f3b3ebb7e84c5011 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 19 Jan 2022 20:51:23 -0700 Subject: dereference car of Lis in HeapPStRIter::step (#1238) --- src/machine/partial_string.rs | 15 +++++++++++++-- tests/scryer/src_tests.rs | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 4430b9e3..ed1ad919 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -1,6 +1,7 @@ use crate::atom_table::*; use crate::parser::ast::*; +use crate::machine::heap::*; use crate::machine::machine_errors::CycleSearchResult; use crate::machine::system_calls::BrentAlgState; use crate::types::*; @@ -296,7 +297,12 @@ impl<'a> HeapPStrIter<'a> { }; } (HeapCellValueTag::Lis, h) => { - return if let Some(c) = self.heap[h].as_char() { + let value = heap_bound_store( + self.heap, + heap_bound_deref(self.heap, self.heap[h]), + ); + + return if let Some(c) = value.as_char() { Some(PStrIterStep { iteratee: PStrIteratee::Char(curr_hare, c), next_hare: h+1, @@ -310,7 +316,12 @@ impl<'a> HeapPStrIter<'a> { .get_name_and_arity(); return if name == atom!(".") && arity == 2 { - if let Some(c) = self.heap[s+1].as_char() { + let value = heap_bound_store( + self.heap, + heap_bound_deref(self.heap, self.heap[s+1]), + ); + + if let Some(c) = value.as_char() { Some(PStrIterStep { iteratee: PStrIteratee::Char(curr_hare, c), next_hare: s+2, diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index 56aa7374..24259f3a 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -51,7 +51,7 @@ fn rules() { fn setup_call_cleanup_load() { load_module_test( "src/tests/setup_call_cleanup.pl", - "1+21+31+2>_14313+_143141+_129071+2>41+2>_143141+2>31+2>31+2>4ba" + "1+21+31+2>_14219+_142201+_128131+2>41+2>_142201+2>31+2>31+2>4ba" ); } @@ -60,7 +60,7 @@ fn setup_call_cleanup_process() { run_top_level_test_with_args( &["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"], "", - "1+21+31+2>_15712+_157131+_143061+2>41+2>_157131+2>31+2>31+2>4ba", + "1+21+31+2>_15618+_156191+_142121+2>41+2>_156191+2>31+2>31+2>4ba" ); } -- cgit v1.2.3-70-g09d2 From af760682976903c7a0bd909694dbdb04e8baa901 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 20 Jan 2022 17:40:45 -0700 Subject: module-qualify callables more liberally but not for built-ins (#1243) --- src/loader.pl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/loader.pl b/src/loader.pl index 10e083f0..f7b56e92 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -629,12 +629,15 @@ expand_subgoal(UnexpandedGoals, MS, Module, ExpandedGoals, HeadVars) :- ). -expand_module_name(ESG0, M, ESG) :- +expand_module_name(ESG0, MS, M, ESG) :- ( var(ESG0) -> ESG = M:ESG0 ; ESG0 = _:_ -> ESG = ESG0 - ; predicate_property(ESG0, built_in) -> + ; functor(ESG0, F, A0), + A is A0 + MS, + functor(EESG0, F, A), + predicate_property(EESG0, built_in) -> ESG = ESG0 ; ESG = M:ESG0 ). @@ -645,11 +648,10 @@ expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars MS >= 0 ) -> ( var(SG), - MS =:= 0, pairs:same_key(SG, HeadVars, [_|_], _) -> expand_subgoal(SG, MS, M, ESG, HeadVars) ; expand_subgoal(SG, MS, M, ESG0, HeadVars), - expand_module_name(ESG0, M, ESG) + expand_module_name(ESG0, MS, M, ESG) ), expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars) ; ESG = SG, @@ -664,8 +666,7 @@ expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :- ( GoalFunctor == (:), SubGoals = [M, SubGoal] -> expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars), - expand_module_name(ExpandedSubGoal, M, ExpandedGoals) - % ExpandedGoals = M:ExpandedSubGoal + expand_module_name(ExpandedSubGoal, 0, M, ExpandedGoals) ; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars), ExpandedGoals =.. [GoalFunctor | ExpandedGoalList] ). -- cgit v1.2.3-70-g09d2 From 8df346f3775c627a1a19265a5ed62a2eea8f9818 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 20 Jan 2022 23:32:08 -0700 Subject: expand phrase/{2,3} using dcg_body whenever possible --- src/lib/clpz.pl | 4 +- src/lib/dcgs.pl | 152 +++++++++++++++++----------------------------- tests/scryer/src_tests.rs | 4 +- 3 files changed, 59 insertions(+), 101 deletions(-) diff --git a/src/lib/clpz.pl b/src/lib/clpz.pl index f330b36f..ceac0221 100644 --- a/src/lib/clpz.pl +++ b/src/lib/clpz.pl @@ -6169,7 +6169,7 @@ distinct_goals_([flow_to(F,To)|Es], V) --> get_attr(To, lowlink, L2), L1 =\= L2 } -> { get_attr(To, value, N) }, - [neq_num(V, N)] + [clpz:neq_num(V, N)] ; [] ), distinct_goals_(Es, V). @@ -6690,7 +6690,7 @@ gcc_edge_goal(arc_to(_,_,V,F), Val) --> get_attr(Val, lowlink, L2), L1 =\= L2, get_attr(Val, value, Value) } -> - [neq_num(V, Value)] + [clpz:neq_num(V, Value)] ; [] ). diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl index 10eab327..7d6dd905 100644 --- a/src/lib/dcgs.pl +++ b/src/lib/dcgs.pl @@ -20,84 +20,52 @@ load_context(GRBody, Module, GRBody0) :- ; true ). + :- meta_predicate phrase(2, ?). :- meta_predicate phrase(2, ?, ?). phrase(GRBody, S0) :- - load_context(GRBody, Module, GRBody0), - phrase(GRBody0, S0, [], Module). + phrase(GRBody, S0, []). phrase(GRBody, S0, S) :- load_context(GRBody, Module, GRBody0), - phrase(GRBody0, S0, S, Module). - -phrase(GRBody, S0, S, Module) :- - ( var(GRBody) -> - throw(error(instantiation_error, phrase/3)) - ; dcg_constr(GRBody) -> - phrase_(GRBody, S0, S, Module) - ; callable(GRBody) -> - call(Module:GRBody, S0, S) - ; throw(error(type_error(callable, Module:GRBody), phrase/3)) + ( var(GRBody0) -> + instantiation_error(phrase/3) + ; dcg_body(GRBody0, S0, S, GRBody1, Module) -> + call(GRBody1) + ; type_error(callable, GRBody0, phrase/3) ). -phrase_([], S, S, _). -phrase_(!, S, S, _). -phrase_((A, B), S0, S, M) :- - phrase(A, S0, S1, M), - phrase(B, S1, S, M). -phrase_((A -> B ; C), S0, S, M) :- - ( phrase(A, S0, S1, M) -> - phrase(B, S1, S, M) - ; phrase(C, S0, S, M) - ). -phrase_((A ; B), S0, S, M) :- - ( phrase(A, S0, S, M) - ; phrase(B, S0, S, M) - ). -phrase_((A | B), S0, S, M) :- - ( phrase(A, S0, S, M) - ; phrase(B, S0, S, M) - ). -phrase_({G}, S, S, M) :- - call(M:G). -phrase_(call(G), S0, S, M) :- - call(M:G, S0, S). -phrase_((A -> B), S0, S, M) :- - ( phrase(A, S0, S1, M) -> - phrase(B, S1, S, M) - ; fail + +module_call_qualified(M, Call, Call1) :- + ( nonvar(M) -> Call1 = M:Call + ; Call = Call1 ). -phrase_(phrase(NonTerminal), S0, S, M) :- - phrase(NonTerminal, S0, S, M). -phrase_([T|Ts], S0, S, _) :- - must_be(list, [T|Ts]), - append([T|Ts], S, S0). % The same version of the below two dcg_rule clauses, but with module scoping. dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :- dcg_non_terminal(NonTerminal, S0, S, Head), - dcg_body(GRBody, S0, S1, Goal1), + dcg_body(GRBody, S0, S1, Goal1, _), dcg_terminals(Terminals, S, S1, Goal2), Body = ( Goal1, Goal2 ). dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :- NonTerminal \= ( _, _ ), dcg_non_terminal(NonTerminal, S0, S, Head), - dcg_body(GRBody, S0, S, Body). + dcg_body(GRBody, S0, S, Body, _). % This program uses append/3 as defined in the Prolog prologue. % Expands a DCG rule into a Prolog rule, when no error condition applies. dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :- dcg_non_terminal(NonTerminal, S0, S, Head), - dcg_body(GRBody, S0, S1, Goal1), + dcg_body(GRBody, S0, S1, Goal1, _), dcg_terminals(Terminals, S, S1, Goal2), Body = ( Goal1, Goal2 ). dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :- NonTerminal \= ( _, _ ), dcg_non_terminal(NonTerminal, S0, S, Head), - dcg_body(GRBody, S0, S, Body). + dcg_body(GRBody, S0, S, Body, _). dcg_non_terminal(NonTerminal, S0, S, Goal) :- NonTerminal =.. NonTerminalUniv, @@ -107,18 +75,20 @@ dcg_non_terminal(NonTerminal, S0, S, Goal) :- dcg_terminals(Terminals, S0, S, S0 = List) :- append(Terminals, S, List). -dcg_body(Var, S0, S, Body) :- +dcg_body(Var, S0, S, Body, M) :- var(Var), - Body = phrase(Var, S0, S). -dcg_body(GRBody, S0, S, Body) :- + module_call_qualified(M, Var, Var1), + Body = phrase(Var1, S0, S). +dcg_body(GRBody, S0, S, Body, M) :- nonvar(GRBody), dcg_constr(GRBody), - dcg_cbody(GRBody, S0, S, Body). -dcg_body(NonTerminal, S0, S, Goal) :- + dcg_cbody(GRBody, S0, S, Body, M). +dcg_body(NonTerminal, S0, S, Goal1, M) :- nonvar(NonTerminal), \+ dcg_constr(NonTerminal), NonTerminal \= ( _ -> _ ), NonTerminal \= ( \+ _ ), + module_call_qualified(M, Goal, Goal1), dcg_non_terminal(NonTerminal, S0, S, Goal). % The following constructs in a grammar rule body @@ -137,37 +107,40 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.) % The principal functor of the first argument indicates % the construct to be expanded. -dcg_cbody([], S0, S, S0 = S). -dcg_cbody([T|Ts], S0, S, Goal) :- +dcg_cbody([], S0, S, S0 = S, _M). +dcg_cbody([T|Ts], S0, S, Goal, _M) :- must_be(list, [T|Ts]), dcg_terminals([T|Ts], S0, S, Goal). -dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :- - dcg_body(GRFirst, S0, S1, First), - dcg_body(GRSecond, S1, S, Second). -dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or )) :- +dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second ), M) :- + dcg_body(GRFirst, S0, S1, First, M), + dcg_body(GRSecond, S1, S, Second, M). +dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or ), M) :- \+ subsumes_term(( _ -> _ ), GREither), - dcg_body(GREither, S0, S, Either), - dcg_body(GROr, S0, S, Or). -dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :- + dcg_body(GREither, S0, S, Either, M), + dcg_body(GROr, S0, S, Or, M). +dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else ), M) :- subsumes_term(( _GRIf -> _GRThen ), GRCond), - dcg_cbody(GRCond, S0, S, Cond), - dcg_body(GRElse, S0, S, Else). -dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :- - dcg_body(GREither, S0, S, Either), - dcg_body(GROr, S0, S, Or). -dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )). -dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)). -dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)). -dcg_cbody(!, S0, S, ( !, S0 = S )). -dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )). -dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :- - dcg_body(GRIf, S0, S1, If), - dcg_body(GRThen, S1, S, Then). + dcg_cbody(GRCond, S0, S, Cond, M), + dcg_body(GRElse, S0, S, Else, M). +dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or ), M) :- + dcg_body(GREither, S0, S, Either, M), + dcg_body(GROr, S0, S, Or, M). +dcg_cbody({Goal}, S0, S, ( Goal1, S0 = S ), M) :- + module_call_qualified(M, Goal, Goal1). +dcg_cbody(call(Cont), S0, S, call(Cont1, S0, S), M) :- + module_call_qualified(M, Cont, Cont1). +dcg_cbody(phrase(Body), S0, S, phrase(Body1, S0, S), M) :- + module_call_qualified(M, Body, Body1). +dcg_cbody(!, S0, S, ( !, S0 = S ), _M). +dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody1,S0,_), S0 = S ), M) :- + module_call_qualified(M, GRBody, GRBody1). +dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then ), M) :- + dcg_body(GRIf, S0, S1, If, M), + dcg_body(GRThen, S1, S, Then, M). user:term_expansion(Term0, Term) :- nonvar(Term0), - dcg_rule(Term0, (Head :- Body)), - Term = (Head :- Body). + dcg_rule(Term0, Term). % Describes a sequence seq([]) --> []. @@ -180,24 +153,9 @@ seqq([Es|Ess]) --> seq(Es), seqq(Ess). % Describes an arbitrary number of elements ... --> [] | [_], ... . -user:goal_expansion(phrase(GRBody, S, S0), phrase(GRBody1, S, S0)) :- - strip_module(GRBody, M, GRBody0), - var(M), - prolog_load_context(module, M), - ( nonvar(GRBody0) -> - GRBody0 \== [], - dcg_constr(GRBody0), - predicate_property(GRBody0, meta_predicate(_)) - ), - GRBody1 = M:GRBody0. - -user:goal_expansion(phrase(GRBody, S), phrase(GRBody1, S, [])) :- - strip_module(GRBody, M, GRBody0), - var(M), - prolog_load_context(module, M), - ( nonvar(GRBody0) -> - GRBody0 \== [], - dcg_constr(GRBody0), - predicate_property(GRBody0, meta_predicate(_)) - ), - GRBody1 = M:GRBody0. +user:goal_expansion(phrase(GRBody, S, S0), GRBody1) :- + load_context(GRBody, M, GRBody0), + nonvar(GRBody0), + dcg_body(GRBody0, S, S0, GRBody1, M). + +user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])). diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index 24259f3a..5e7b74a8 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -51,7 +51,7 @@ fn rules() { fn setup_call_cleanup_load() { load_module_test( "src/tests/setup_call_cleanup.pl", - "1+21+31+2>_14219+_142201+_128131+2>41+2>_142201+2>31+2>31+2>4ba" + "1+21+31+2>_15388+_153891+_139341+2>41+2>_153891+2>31+2>31+2>4ba" ); } @@ -60,7 +60,7 @@ fn setup_call_cleanup_process() { run_top_level_test_with_args( &["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"], "", - "1+21+31+2>_15618+_156191+_142121+2>41+2>_156191+2>31+2>31+2>4ba" + "1+21+31+2>_16835+_168361+_153811+2>41+2>_168361+2>31+2>31+2>4ba" ); } -- cgit v1.2.3-70-g09d2 From 5ff579f79328d0ed29257370b22e9b2d28ad758c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 20 Jan 2022 23:46:03 -0700 Subject: recognize []/N as callable (#1241, #989) --- src/loader.pl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/loader.pl b/src/loader.pl index f7b56e92..c5228d1f 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -578,15 +578,13 @@ predicate_property(Callable, Property) :- atom(Module), nonvar(Callable0) -> functor(Callable0, Name, Arity), - ( atom(Name), - Name \== [] -> + ( atom(Name) -> extract_predicate_property(Property, PropertyType), check_predicate_property(PropertyType, Module, Name, Arity, Property) ; type_error(callable, Callable0, predicate_property/2) ) ; functor(Callable, Name, Arity), - ( atom(Name), - Name \== [] -> + ( atom(Name) -> extract_predicate_property(Property, PropertyType), load_context(Module), check_predicate_property(PropertyType, Module, Name, Arity, Property) -- cgit v1.2.3-70-g09d2 From e6c4ecfc10b60d802400d8450fb73a37a605b70f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 22 Jan 2022 12:22:50 -0700 Subject: lazily throw exceptions of dcg_body from goal-expanded phrase/{2,3} (#1244) --- src/lib/dcgs.pl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl index 7d6dd905..488c7a92 100644 --- a/src/lib/dcgs.pl +++ b/src/lib/dcgs.pl @@ -156,6 +156,9 @@ seqq([Es|Ess]) --> seq(Es), seqq(Ess). user:goal_expansion(phrase(GRBody, S, S0), GRBody1) :- load_context(GRBody, M, GRBody0), nonvar(GRBody0), - dcg_body(GRBody0, S, S0, GRBody1, M). + catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1, M), + error(E, must_be/2), + ( GRBody1 = throw(error(E, must_be/2)) ) + ). user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])). -- cgit v1.2.3-70-g09d2 From a562793fce2f53c45fe00adaaf629ba1cd62dba1 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 24 Jan 2022 18:47:53 -0700 Subject: don't read into the heap while incrementing self.s (#1233, #1245) --- src/examples/least_time.pl | 10 ++-- src/machine/dispatch.rs | 16 +++--- src/machine/machine_state.rs | 1 + src/machine/machine_state_impl.rs | 100 +++++++++++++++++++++----------------- src/machine/partial_string.rs | 22 --------- 5 files changed, 71 insertions(+), 78 deletions(-) diff --git a/src/examples/least_time.pl b/src/examples/least_time.pl index 06eccd31..2b599b60 100644 --- a/src/examples/least_time.pl +++ b/src/examples/least_time.pl @@ -11,7 +11,7 @@ */ :- module(least_time, [find_min_time/2, - write_time_nl/1]). + write_time_nl/1]). :- use_module(library(dcgs)). @@ -27,10 +27,10 @@ valid_time([H1,H2,M1,M2], T) :- memberd_t(M2, [0,1,2,3,4,5,6,7,8,9], TM2), ( maplist(=(true), [TH1, TH2, TM1, TM2]) -> ( H1 =:= 2 -> - ( H2 =< 3 -> - T = true - ; T = false - ) + ( H2 =< 3 -> + T = true + ; T = false + ) ; T = true ) ; T = false diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 546781c7..4c02ea8b 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -2769,6 +2769,7 @@ impl Machine { let (h, n) = pstr_loc_and_offset(&self.machine_st.heap, h); self.machine_st.s = HeapPtr::PStrChar(h, n.get_num() as usize); + self.machine_st.s_offset = 0; self.machine_st.mode = MachineMode::Read; } (HeapCellValueTag::CStr) => { @@ -2776,10 +2777,12 @@ impl Machine { self.machine_st.heap.push(store_v); self.machine_st.s = HeapPtr::PStrChar(h, 0); + self.machine_st.s_offset = 0; self.machine_st.mode = MachineMode::Read; } (HeapCellValueTag::Lis, l) => { self.machine_st.s = HeapPtr::HeapCell(l); + self.machine_st.s_offset = 0; self.machine_st.mode = MachineMode::Read; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { @@ -2827,6 +2830,7 @@ impl Machine { (HeapCellValueTag::Atom, (result_name, result_arity)) => { if arity == result_arity && name == result_name { self.machine_st.s = HeapPtr::HeapCell(a + 1); + self.machine_st.s_offset = 0; self.machine_st.mode = MachineMode::Read; } else { self.machine_st.backtrack(); @@ -2883,7 +2887,7 @@ impl Machine { self.machine_st.backtrack(); continue; } else { - self.machine_st.increment_s_ptr(1); + self.machine_st.s_offset += 1; } } MachineMode::Write => { @@ -2905,7 +2909,7 @@ impl Machine { self.machine_st.backtrack(); continue; } else { - self.machine_st.increment_s_ptr(1); + self.machine_st.s_offset += 1; } } MachineMode::Write => { @@ -2917,7 +2921,7 @@ impl Machine { let value = self.machine_st.heap[hc]; self.machine_st.heap.push(value); - self.machine_st.increment_s_ptr(1); + self.machine_st.s_offset += 1; } _ => { self.machine_st.heap.push(heap_loc_as_cell!(h)); @@ -2937,7 +2941,7 @@ impl Machine { match self.machine_st.mode { MachineMode::Read => { self.machine_st[reg] = self.machine_st.read_s(); - self.machine_st.increment_s_ptr(1); + self.machine_st.s_offset += 1; } MachineMode::Write => { let h = self.machine_st.heap.len(); @@ -2961,7 +2965,7 @@ impl Machine { self.machine_st.backtrack(); continue; } else { - self.machine_st.increment_s_ptr(1); + self.machine_st.s_offset += 1; } } MachineMode::Write => { @@ -2988,7 +2992,7 @@ impl Machine { &Instruction::UnifyVoid(n) => { match self.machine_st.mode { MachineMode::Read => { - self.machine_st.increment_s_ptr(n); + self.machine_st.s_offset += n; } MachineMode::Write => { let h = self.machine_st.heap.len(); diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 11b2672a..27a35884 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -55,6 +55,7 @@ pub struct MachineState { pub arena: Arena, pub(super) pdl: Vec, pub(super) s: HeapPtr, + pub(super) s_offset: usize, pub(super) p: usize, pub(super) oip: u32, // first internal code ptr pub(super) iip : u32, // second internal code ptr diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 6461f7f0..373f8704 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -28,6 +28,7 @@ impl MachineState { atom_tbl: AtomTable::new(), pdl: Vec::with_capacity(1024), s: HeapPtr::default(), + s_offset: 0, p: 0, oip: 0, iip: 0, @@ -77,6 +78,7 @@ impl MachineState { ) } + #[inline] pub fn deref(&self, mut addr: HeapCellValue) -> HeapCellValue { loop { let value = self.store(addr); @@ -1390,28 +1392,25 @@ impl MachineState { } pub(crate) fn read_s(&mut self) -> HeapCellValue { - match &self.s { - &HeapPtr::HeapCell(h) => self.deref(self.heap[h]), - &HeapPtr::PStrChar(h, n) => { + match &mut self.s { + &mut HeapPtr::HeapCell(h) => self.deref(self.heap[h + self.s_offset]), + &mut HeapPtr::PStrChar(h, n) if self.s_offset == 0 => { read_heap_cell!(self.heap[h], (HeapCellValueTag::PStr, pstr_atom) => { let pstr = PartialString::from(pstr_atom); if let Some(c) = pstr.as_str_from(n).chars().next() { char_as_cell!(c) - } else { // if has_tail { - self.deref(self.heap[h+1]) // heap_loc_as_cell!(h+1) + } else { + self.deref(self.heap[h+1]) } - // } else { - // empty_list_as_cell!() - // } } (HeapCellValueTag::CStr, cstr_atom) => { let pstr = PartialString::from(cstr_atom); if let Some(c) = pstr.as_str_from(n).chars().next() { char_as_cell!(c) - } else { // if has_tail { + } else { empty_list_as_cell!() } } @@ -1420,14 +1419,25 @@ impl MachineState { } ) } - &HeapPtr::PStrLocation(h, n) => { + &mut HeapPtr::PStrChar(h, ref mut n) | + &mut HeapPtr::PStrLocation(h, ref mut n) => { read_heap_cell!(self.heap[h], (HeapCellValueTag::PStr, pstr_atom) => { - if n < pstr_atom.len() { + let pstr = PartialString::from(pstr_atom); + let n_offset: usize = pstr.as_str_from(*n) + .chars() + .take(self.s_offset) + .map(|c| c.len_utf8()) + .sum(); + + self.s_offset = 0; + *n += n_offset; + + if *n < pstr_atom.len() { let h_len = self.heap.len(); self.heap.push(pstr_offset_as_cell!(h)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with(n as i64))); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(*n as i64))); pstr_loc_as_cell!(h_len) } else { @@ -1435,11 +1445,21 @@ impl MachineState { } } (HeapCellValueTag::CStr, cstr_atom) => { - if n < cstr_atom.len() { + let pstr = PartialString::from(cstr_atom); + let n_offset: usize = pstr.as_str_from(*n) + .chars() + .take(self.s_offset) + .map(|c| c.len_utf8()) + .sum(); + + self.s_offset = 0; + *n += n_offset; + + if *n < cstr_atom.len() { let h_len = self.heap.len(); self.heap.push(pstr_offset_as_cell!(h)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with(n as i64))); + self.heap.push(fixnum_as_cell!(Fixnum::build_with(*n as i64))); pstr_loc_as_cell!(h_len) } else { @@ -1821,30 +1841,6 @@ impl MachineState { Some(Ordering::Equal) } - pub(crate) fn increment_s_ptr(&mut self, rhs: usize) { - match &mut self.s { - HeapPtr::HeapCell(ref mut h) => { - *h += rhs; - } - &mut HeapPtr::PStrChar(h, ref mut n) | &mut HeapPtr::PStrLocation(h, ref mut n) => { - read_heap_cell!(self.heap[h], - (HeapCellValueTag::PStr | HeapCellValueTag::CStr, pstr_atom) => { - let pstr = PartialString::from(pstr_atom); - - for c in pstr.as_str_from(*n).chars().take(rhs) { - *n += c.len_utf8(); - } - - self.s = HeapPtr::PStrLocation(h, *n); - } - _ => { - unreachable!() - } - ) - } - } - } - pub fn match_partial_string(&mut self, value: HeapCellValue, string: Atom, has_tail: bool) { let h = self.heap.len(); self.heap.push(value); @@ -1860,23 +1856,35 @@ impl MachineState { (HeapCellValueTag::PStr | HeapCellValueTag::CStr, pstr_atom) => { if has_tail { self.s = HeapPtr::PStrLocation(focus, offset); + self.s_offset = 0; self.mode = MachineMode::Read; } else if offset == pstr_atom.len() { - let focus_addr = heap_pstr_iter.focus; - unify!(self, focus_addr, empty_list_as_cell!()); + let focus = heap_pstr_iter.focus; + unify!(self, focus, empty_list_as_cell!()); } else { self.fail = true; } } (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, h) => { - if has_tail { - let (h, _) = pstr_loc_and_offset(&self.heap, h); + let (focus, _) = pstr_loc_and_offset(&self.heap, h); + let pstr_atom = read_heap_cell!(self.heap[focus], + (HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => { + pstr_atom + } + _ => { + unreachable!() + } + ); - self.s = HeapPtr::PStrLocation(h, offset); + if has_tail { + self.s = HeapPtr::PStrLocation(focus, offset); + self.s_offset = 0; self.mode = MachineMode::Read; + } else if offset == pstr_atom.len() { + let focus = heap_pstr_iter.focus; + unify!(self, focus, empty_list_as_cell!()); } else { - let end_cell = heap_pstr_iter.focus; - self.fail = end_cell != empty_list_as_cell!(); + self.fail = true; } } _ => { @@ -1884,6 +1892,7 @@ impl MachineState { if has_tail { self.s = HeapPtr::HeapCell(focus); + self.s_offset = 0; self.mode = MachineMode::Read; } else { let focus = heap_pstr_iter.focus; @@ -1900,6 +1909,7 @@ impl MachineState { let target_cell = if has_tail { self.s = HeapPtr::HeapCell(h + 1); + self.s_offset = 0; self.mode = MachineMode::Read; put_partial_string( diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index ed1ad919..42184297 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -499,28 +499,6 @@ impl<'a> Iterator for PStrCharsIter<'a> { } } - /* - if !self.iter.at_string_terminator() { - // at a cycle. emit the final character. - match self.iter.step(self.iter.brent_st.hare) { - Some(PStrIterStep { iteratee: PStrIteratee::Char(_, c), .. }) => { - self.iter.focus = empty_list_as_cell!(); - return Some(c); - } - Some(PStrIterStep { iteratee: PStrIteratee::PStrSegment(_, pstr_atom, _), .. }) => { - self.iter.focus = empty_list_as_cell!(); - - let c = PartialString::from(pstr_atom).as_str_from(0).chars().next().unwrap(); - return Some(c); - } - _ => { - self.iter.focus = empty_list_as_cell!(); - return None; - } - } - } - */ - None } } -- cgit v1.2.3-70-g09d2 From 142ddcd57ab41cb7ebdbd2924dd84f79314cfe71 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 26 Jan 2022 17:34:36 -0700 Subject: use expand_goal directly for existential-qualified goals in all-solutions predicates (#1246) --- src/lib/builtins.pl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index a060a69c..6a70423e 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -698,15 +698,15 @@ rightmost_power(Term, FinalTerm, Xs) :- findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses) :- ( nonvar(Goal), - ( Goal = _ ^ _ - ; Goal = _ : (_ ^ _) - ) -> - rightmost_power(Goal, Goal1, ExistentialVars0), + loader:strip_module(Goal, M, Goal1), + ( Goal1 = _ ^ _ ) -> + rightmost_power(Goal1, Goal2, ExistentialVars0), term_variables(ExistentialVars0, ExistentialVars), sort(Witnesses0, Witnesses1), sort(ExistentialVars, ExistentialVars1), set_difference(Witnesses1, ExistentialVars1, Witnesses), - findall(Witnesses-Template, Goal1, PairedSolutions) + expand_goal(M:Goal2, M, Goal3), + findall(Witnesses-Template, Goal3, PairedSolutions) ; Witnesses = Witnesses0, findall(Witnesses-Template, Goal, PairedSolutions) ). -- cgit v1.2.3-70-g09d2 From b3006f6fd8ebbcca0c5ddc8ba8b83a0c8aa9b81f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 26 Jan 2022 23:03:19 -0700 Subject: inline store & deref calls in '' (#1176) --- src/machine/system_calls.rs | 82 ++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index c9d988f9..f6ec376d 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -211,50 +211,56 @@ impl BrentAlgState { impl MachineState { #[inline(always)] pub fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { - let deref_v = self.deref(self.heap[brent_st.hare]); - let store_v = self.store(deref_v); + loop { + let store_v = self.heap[brent_st.hare]; - if let Some(var) = store_v.as_var() { - return Some(CycleSearchResult::PartialList(brent_st.num_steps(), var)); - } + read_heap_cell!(store_v, + (HeapCellValueTag::PStrLoc, h) => { + return brent_st.add_pstr_chars_and_step(&self.heap, h); + } + (HeapCellValueTag::PStrOffset) => { + return brent_st.add_pstr_chars_and_step(&self.heap, brent_st.hare); + } + (HeapCellValueTag::CStr, cstr_atom) => { + let cstr = PartialString::from(cstr_atom); - if store_v == empty_list_as_cell!() { - return Some(CycleSearchResult::ProperList(brent_st.num_steps())); - } + brent_st.pstr_chars += cstr.as_str_from(0).chars().count(); + return Some(CycleSearchResult::ProperList(brent_st.num_steps())); + } + (HeapCellValueTag::Lis, h) => { + return brent_st.step(h+1); + } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); - read_heap_cell!(store_v, - (HeapCellValueTag::PStrLoc, h) => { - brent_st.add_pstr_chars_and_step(&self.heap, h) - } - (HeapCellValueTag::PStrOffset) => { - brent_st.add_pstr_chars_and_step(&self.heap, brent_st.hare) - } - (HeapCellValueTag::CStr, cstr_atom) => { - let cstr = PartialString::from(cstr_atom); + return if name == atom!(".") && arity == 2 { + brent_st.step(s+2) + } else { + Some(CycleSearchResult::NotList) + }; + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert!(arity == 0); - brent_st.pstr_chars += cstr.as_str_from(0).chars().count(); - Some(CycleSearchResult::ProperList(brent_st.num_steps())) - } - (HeapCellValueTag::Lis, h) => { - brent_st.step(h+1) - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + return if name == atom!("[]") { + Some(CycleSearchResult::ProperList(brent_st.num_steps())) + } else { + Some(CycleSearchResult::NotList) + }; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if brent_st.hare == h { + let r = store_v.as_var().unwrap(); + return Some(CycleSearchResult::PartialList(brent_st.num_steps(), r)); + } - if name == atom!(".") && arity == 2 { - brent_st.step(s+2) - } else { - Some(CycleSearchResult::NotList) + brent_st.hare = h; } - } - (HeapCellValueTag::Atom, (_name, arity)) => { - debug_assert!(arity == 0); - Some(CycleSearchResult::NotList) - } - _ => { - Some(CycleSearchResult::NotList) - } - ) + _ => { + return Some(CycleSearchResult::NotList); + } + ); + } } pub fn detect_cycles(&self, value: HeapCellValue) -> CycleSearchResult { -- cgit v1.2.3-70-g09d2 From 2e57789d107af4882dd1d3f828a9066390fe3ff6 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Fri, 28 Jan 2022 18:47:55 +0100 Subject: ENHANCED: Make toplevel output a Prolog term that can be read back also for "...". This addresses #1240. --- src/toplevel.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toplevel.pl b/src/toplevel.pl index 290b92e9..c72089e9 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -330,7 +330,7 @@ read_input(ThreadedGoals, NewVarList) :- help_message, read_input(ThreadedGoals, NewVarList) ; member(C, ['\n', .]) -> - nl, write('; ...'), nl + nl, write('; ... .'), nl ; read_input(ThreadedGoals, NewVarList) ). -- cgit v1.2.3-70-g09d2 From 0d653a2ce6e7afe3f4cca38b6205ebb636c721fc Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 29 Jan 2022 00:57:39 -0700 Subject: improve '$skip_max_list'/4 and length/2 (#1023, #110) --- src/forms.rs | 8 ++ src/lib/builtins.pl | 18 ++-- src/lib/charsio.pl | 2 +- src/lib/error.pl | 4 +- src/lib/lists.pl | 35 ++++---- src/lib/ordsets.pl | 2 +- src/machine/machine_errors.rs | 3 +- src/machine/partial_string.rs | 5 +- src/machine/system_calls.rs | 190 +++++++++++++++++++++++------------------- 9 files changed, 146 insertions(+), 121 deletions(-) diff --git a/src/forms.rs b/src/forms.rs index 3ccb7575..db9b36dc 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -649,6 +649,14 @@ impl Number { &Number::Rational(ref r) => &**r == &0, } } + + #[inline] + pub(crate) fn is_integer(&self) -> bool { + match self { + Number::Fixnum(_) | Number::Integer(_) => true, + _ => false, + } + } } #[derive(Debug, Clone)] diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 6a70423e..94ff77d0 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -329,7 +329,7 @@ comma_dispatch_call_list([G1]) :- :- non_counted_backtracking univ_errors/3. univ_errors(Term, List, N) :- - '$skip_max_list'(N, -1, List, R), + '$skip_max_list'(N, _, List, R), ( var(R) -> ( var(Term), throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a) @@ -399,7 +399,7 @@ get_args([Arg|Args], Func, I0, N) :- :- meta_predicate parse_options_list(?, 0, ?, ?, ?). parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :- - '$skip_max_list'(_, -1, Options, Tail), + '$skip_max_list'(_, _, Options, Tail), ( Tail == [] -> true ; var(Tail) -> @@ -452,7 +452,7 @@ parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :- ). must_be_var_names_list(VarNames) :- - '$skip_max_list'(_, -1, VarNames, Tail), + '$skip_max_list'(_, _, VarNames, Tail), ( Tail == [] -> must_be_var_names_list_(VarNames, VarNames) ; var(Tail) -> @@ -549,7 +549,7 @@ can_be_list(List, _) :- var(List), !. can_be_list(List, _) :- - '$skip_max_list'(_, -1, List, Tail), + '$skip_max_list'(_, _, List, Tail), ( var(Tail) -> true ; Tail == [] @@ -1196,7 +1196,7 @@ atom_length(Atom, Length) :- ). atom_chars(Atom, List) :- - '$skip_max_list'(_, -1, List, Tail), + '$skip_max_list'(_, _, List, Tail), ( ( Tail == [] ; var(Tail) ) -> true ; throw(error(type_error(list, List), atom_chars/2)) @@ -1214,7 +1214,7 @@ atom_chars(Atom, List) :- ). atom_codes(Atom, List) :- - '$skip_max_list'(_, -1, List, Tail), + '$skip_max_list'(_, _, List, Tail), ( ( Tail == [] ; var(Tail) ) -> true ; throw(error(type_error(list, List), atom_codes/2)) @@ -1271,9 +1271,9 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :- ; atom_chars(Atom, AtomChars), lists:append(BeforeChars, LengthAndAfterChars, AtomChars), lists:append(LengthChars, AfterChars, LengthAndAfterChars), - '$skip_max_list'(Before, -1, BeforeChars, []), - '$skip_max_list'(Length, -1, LengthChars, []), - '$skip_max_list'(After, -1, AfterChars, []), + '$skip_max_list'(Before, _, BeforeChars, []), + '$skip_max_list'(Length, _, LengthChars, []), + '$skip_max_list'(After, _, AfterChars, []), atom_chars(Sub_atom, LengthChars) ). diff --git a/src/lib/charsio.pl b/src/lib/charsio.pl index 3ef732db..33e6e422 100644 --- a/src/lib/charsio.pl +++ b/src/lib/charsio.pl @@ -118,7 +118,7 @@ read_from_chars(Chars, Term) :- instantiation_error(read_from_chars/2) ; nonvar(Term) -> throw(error(uninstantiation_error(Term), read_from_chars/2)) - ; '$skip_max_list'(_, -1, Chars, Chars0), + ; '$skip_max_list'(_, _, Chars, Chars0), Chars0 == [], partial_string(Chars) -> true diff --git a/src/lib/error.pl b/src/lib/error.pl index d5827495..c5af6d7c 100644 --- a/src/lib/error.pl +++ b/src/lib/error.pl @@ -80,7 +80,7 @@ character(C) :- atom_length(C, 1). ilist(Ls) :- - '$skip_max_list'(_, -1, Ls, Rs), + '$skip_max_list'(_, _, Ls, Rs), ( var(Rs) -> instantiation_error(must_be/2) ; Rs == [] @@ -124,7 +124,7 @@ can_(list, Term) :- list_or_partial_list(Term). can_(boolean, Term) :- boolean(Term). list_or_partial_list(Ls) :- - '$skip_max_list'(_, -1, Ls, Rs), + '$skip_max_list'(_, _, Ls, Rs), ( var(Rs) -> true ; Rs == [] ). diff --git a/src/lib/lists.pl b/src/lib/lists.pl index 752e8271..f5a62edb 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -50,27 +50,20 @@ :- meta_predicate foldl(3, ?, ?, ?). :- meta_predicate foldl(4, ?, ?, ?, ?). - -length(Xs, N) :- - var(N), - !, - '$skip_max_list'(M, -1, Xs, Xs0), - ( Xs0 == [] -> N = M - ; var(Xs0) -> length_addendum(Xs0, N, M) - ). -length(Xs, N) :- - integer(N), - N >= 0, - !, - '$skip_max_list'(M, N, Xs, Xs0), - ( Xs0 == [] -> N = M - ; var(Xs0) -> R is N-M, length_rundown(Xs0, R) - ). +length(Xs0, N) :- + '$skip_max_list'(M, N, Xs0,Xs), + !, + ( Xs == [] -> N = M + ; nonvar(Xs) -> var(N), throw(error(resource_error(finite_memory),_)) + ; nonvar(N) -> R is N-M, length_rundown(Xs, R) + ; N == Xs -> throw(error(resource_error(finite_memory),_)) + ; length_addendum(Xs, N, M) + ). length(_, N) :- - integer(N), !, - domain_error(not_less_than_zero, N, length/2). + integer(N), !, + domain_error(not_less_than_zero, N, length/2). length(_, N) :- - type_error(integer, N, length/2). + type_error(integer, N, length/2). length_addendum([], N, N). length_addendum([_|Xs], N, M) :- @@ -288,8 +281,8 @@ list_min_(N, Min0, Min) :- % or partial list. permutation(Xs, Ys) :- - '$skip_max_list'(Xlen, -1, Xs, XTail), - '$skip_max_list'(Ylen, -1, Ys, YTail), + '$skip_max_list'(Xlen, _, Xs, XTail), + '$skip_max_list'(Ylen, _, Ys, YTail), ( XTail == [], YTail == [] % both proper lists -> Xlen == Ylen ; var(XTail), YTail == [] % partial, proper diff --git a/src/lib/ordsets.pl b/src/lib/ordsets.pl index ff080962..b5886d38 100644 --- a/src/lib/ordsets.pl +++ b/src/lib/ordsets.pl @@ -89,7 +89,7 @@ because the order it relies on may have been changed. % setof/3. is_ordset(Term) :- - '$skip_max_list'(_, -1, Term, Tail), Tail == [], %% is_list(Term), + '$skip_max_list'(_, _, Term, Tail), Tail == [], %% is_list(Term), is_ordset2(Term). is_ordset2([]). diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index d2f589df..cd6cb982 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -768,12 +768,13 @@ impl EvalError { // used by '$skip_max_list'. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CycleSearchResult { + Cyclic(usize), EmptyList, NotList, PartialList(usize, Ref), // the list length (up to max), and an offset into the heap. ProperList(usize), // the list length. PStrLocation(usize, usize), // list length (up to max), the heap address of the PStrOffset - UntouchedList(usize), // the address of an uniterated Addr::Lis(address). + UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address). UntouchedCStr(Atom, usize), } diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 42184297..cb26ab1e 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -371,7 +371,10 @@ impl<'a> HeapPStrIter<'a> { match self.brent_st.step(next_hare) { Some(cycle_result) => { - debug_assert!(cycle_result == CycleSearchResult::NotList); + debug_assert!(match cycle_result { + CycleSearchResult::Cyclic(_) => true, + _ => false, + }); self.walk_hare_to_cycle_end(); self.stepper = HeapPStrIter::post_cycle_discovery_stepper; diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index f6ec376d..a9f1b91f 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -133,7 +133,7 @@ impl BrentAlgState { self.lam += 1; if self.tortoise == self.hare { - return Some(CycleSearchResult::NotList); + return Some(CycleSearchResult::Cyclic(self.lam)); } else { self.teleport_tortoise(); } @@ -158,19 +158,22 @@ impl BrentAlgState { let pstr = cell_as_string!(heap[self.hare]); self.pstr_chars += pstr.as_str_from(n).chars().count(); - CycleSearchResult::PStrLocation(self.num_steps(), n) + return CycleSearchResult::PStrLocation(self.num_steps(), n); } (HeapCellValueTag::Atom, (name, arity)) => { - if name == atom!("[]") && arity == 0 { + return if name == atom!("[]") && arity == 0 { CycleSearchResult::ProperList(self.num_steps()) } else { CycleSearchResult::NotList - } + }; + } + (HeapCellValueTag::Lis, l) => { + return CycleSearchResult::UntouchedList(self.num_steps(), l); } _ => { - CycleSearchResult::NotList + return CycleSearchResult::NotList; } - ) + ); } fn add_pstr_chars_and_step(&mut self, heap: &[HeapCellValue], h: usize) -> Option { @@ -218,15 +221,9 @@ impl MachineState { (HeapCellValueTag::PStrLoc, h) => { return brent_st.add_pstr_chars_and_step(&self.heap, h); } - (HeapCellValueTag::PStrOffset) => { + (HeapCellValueTag::CStr | HeapCellValueTag::PStrOffset) => { return brent_st.add_pstr_chars_and_step(&self.heap, brent_st.hare); } - (HeapCellValueTag::CStr, cstr_atom) => { - let cstr = PartialString::from(cstr_atom); - - brent_st.pstr_chars += cstr.as_str_from(0).chars().count(); - return Some(CycleSearchResult::ProperList(brent_st.num_steps())); - } (HeapCellValueTag::Lis, h) => { return brent_st.step(h+1); } @@ -264,9 +261,7 @@ impl MachineState { } pub fn detect_cycles(&self, value: HeapCellValue) -> CycleSearchResult { - let deref_v = self.deref(value); - let store_v = self.store(deref_v); - + let store_v = self.store(self.deref(value)); let mut pstr_chars = 0; let hare = read_heap_cell!(store_v, @@ -310,11 +305,14 @@ impl MachineState { } } (HeapCellValueTag::Atom, (name, arity)) => { - if name == atom!("[]") && arity == 0 { - return CycleSearchResult::EmptyList; + return if name == atom!("[]") && arity == 0 { + CycleSearchResult::EmptyList } else { - return CycleSearchResult::NotList; - } + CycleSearchResult::NotList + }; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { + return CycleSearchResult::PartialList(0, store_v.as_var().unwrap()); } _ => { return CycleSearchResult::NotList; @@ -334,9 +332,7 @@ impl MachineState { } pub fn detect_cycles_with_max(&self, max_steps: usize, value: HeapCellValue) -> CycleSearchResult { - let deref_v = self.deref(value); - let store_v = self.store(deref_v); - + let store_v = self.store(self.deref(value)); let mut pstr_chars = 0; let hare = read_heap_cell!(store_v, @@ -344,7 +340,7 @@ impl MachineState { if max_steps > 0 { offset+1 } else { - return CycleSearchResult::UntouchedList(offset); + return CycleSearchResult::UntouchedList(0, offset); } } (HeapCellValueTag::PStrLoc, h) => { @@ -398,7 +394,7 @@ impl MachineState { if max_steps > 0 { s + 2 } else { - return CycleSearchResult::UntouchedList(s + 1); + return CycleSearchResult::UntouchedList(0, s + 1); } } else { return CycleSearchResult::NotList; @@ -411,6 +407,9 @@ impl MachineState { CycleSearchResult::NotList }; } + (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { + return CycleSearchResult::PartialList(0, store_v.as_var().unwrap()); + } _ => { return CycleSearchResult::NotList; } @@ -422,7 +421,7 @@ impl MachineState { brent_st.pstr_chars = pstr_chars; loop { - if brent_st.num_steps() == max_steps { + if brent_st.num_steps() >= max_steps { return brent_st.to_result(&self.heap); } @@ -432,9 +431,48 @@ impl MachineState { } } - fn finalize_skip_max_list(&mut self, n: usize, value: HeapCellValue) { - let target_n = self.registers[1]; - self.unify_fixnum(Fixnum::build_with(n as i64), target_n); + fn skip_max_list_cycle(&mut self, lam: usize) { + fn step(heap: &Heap, mut value: HeapCellValue) -> usize { + loop { + read_heap_cell!(value, + (HeapCellValueTag::PStrLoc, h) => { + let (h_offset, _) = pstr_loc_and_offset(&heap, h); + return h_offset+1; + } + (HeapCellValueTag::Lis, h) => { + return h+1; + } + (HeapCellValueTag::Str, s) => { + return s+2; + } + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + value = heap[h]; + } + _ => { + unreachable!(); + } + ); + } + } + + let mut hare = step(&self.heap, self.registers[3]); + let mut tortoise = hare; + + for _ in 0 .. lam { + hare = step(&self.heap, self.heap[hare]); + } + + while hare != tortoise { + hare = step(&self.heap, self.heap[hare]); + tortoise = step(&self.heap, self.heap[tortoise]); + } + + unify!(self, self.registers[4], self.heap[hare]); + } + + fn finalize_skip_max_list(&mut self, n: i64, value: HeapCellValue) { + let target_n = self.store(self.deref(self.registers[1])); + self.unify_fixnum(Fixnum::build_with(n), target_n); if !self.fail { let xs = self.registers[4]; @@ -442,94 +480,76 @@ impl MachineState { } } - fn skip_max_list_result(&mut self, max_steps: Option) { - let search_result = if let Some(max_steps) = max_steps { - if max_steps == -1 { - self.detect_cycles(self.registers[3]) - } else { - self.detect_cycles_with_max(max_steps as usize, self.registers[3]) - } - } else { + fn skip_max_list_result(&mut self, max_steps: i64) { + let search_result = if max_steps == -1 { self.detect_cycles(self.registers[3]) + } else { + self.detect_cycles_with_max(max_steps as usize, self.registers[3]) }; match search_result { CycleSearchResult::PStrLocation(steps, pstr_loc) => { - self.finalize_skip_max_list(steps, heap_loc_as_cell!(pstr_loc)); + self.finalize_skip_max_list(steps as i64, pstr_loc_as_cell!(pstr_loc)); } - CycleSearchResult::UntouchedList(l) => { - self.finalize_skip_max_list(0, list_loc_as_cell!(l)); + CycleSearchResult::UntouchedList(n, l) => { + self.finalize_skip_max_list(n as i64, list_loc_as_cell!(l)); } CycleSearchResult::UntouchedCStr(cstr_atom, n) => { - self.finalize_skip_max_list(n, string_as_cstr_cell!(cstr_atom)); + self.finalize_skip_max_list(n as i64, string_as_cstr_cell!(cstr_atom)); } CycleSearchResult::EmptyList => { self.finalize_skip_max_list(0, empty_list_as_cell!()); } CycleSearchResult::PartialList(n, r) => { - self.finalize_skip_max_list(n, r.as_heap_cell_value()); + self.finalize_skip_max_list(n as i64, r.as_heap_cell_value()); } CycleSearchResult::ProperList(steps) => { - self.finalize_skip_max_list(steps, empty_list_as_cell!()) + self.finalize_skip_max_list(steps as i64, empty_list_as_cell!()) } CycleSearchResult::NotList => { - let xs0 = self.registers[3]; - self.finalize_skip_max_list(0, xs0); + let n = self.store(self.deref(self.registers[2])); + + self.unify_fixnum(Fixnum::build_with(max_steps), n); + self.finalize_skip_max_list(max_steps, self.registers[3]); + } + CycleSearchResult::Cyclic(lam) => { + self.skip_max_list_cycle(lam); } }; } pub fn skip_max_list(&mut self) -> CallResult { let max_steps = self.store(self.deref(self.registers[2])); + let mut max_old = -1i64; - if max_steps.is_var() { - let stub = functor_stub(atom!("$skip_max_list"), 4); - let err = self.instantiation_error(); - - return Err(self.error_form(err, stub)); - } - - let max_steps_n = match Number::try_from(max_steps) { - Ok(Number::Fixnum(n)) => Some(n.get_num()), - Ok(Number::Integer(n)) => n.to_i64(), - _ => None, - }; + if !max_steps.is_var() { + let max_steps = Number::try_from(max_steps); - if max_steps_n.map(|i| i >= -1).unwrap_or(false) { - let n = self.store(self.deref(self.registers[1])); - - match Number::try_from(n) { - Ok(Number::Integer(n)) => { - if &*n == &0 { - let xs0 = self.registers[3]; - let xs = self.registers[4]; - - unify!(self, xs0, xs); - } else { - self.skip_max_list_result(max_steps_n); - } - } - Ok(Number::Fixnum(n)) => { - if n.get_num() == 0 { - let xs0 = self.registers[3]; - let xs = self.registers[4]; + let max_steps_n = match max_steps { + Ok(Number::Fixnum(n)) => Some(n.get_num()), + Ok(Number::Integer(n)) => n.to_i64(), + _ => None, + }; - unify!(self, xs0, xs); + if let Some(max_steps) = max_steps_n { + if max_steps.abs() as usize <= 1 << 63 { + if max_steps >= 0 { + max_old = max_steps; } else { - self.skip_max_list_result(max_steps_n); + self.fail = true; + return Ok(()); } + } else if max_steps < 0 { + self.fail = true; + return Ok(()); } - _ => { - self.skip_max_list_result(max_steps_n); - } + } else if !max_steps.map(|n| n.is_integer()).unwrap_or(false) { + self.fail = true; + return Ok(()); } - } else { - let stub = functor_stub(atom!("$skip_max_list"), 4); - let err = self.type_error(ValidType::Integer, max_steps); - - return Err(self.error_form(err, stub)); } + self.skip_max_list_result(max_old); Ok(()) } -- cgit v1.2.3-70-g09d2 From 4ddacc707d5a9afd42ae598ceeb00a9285d8cd17 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 29 Jan 2022 12:50:09 -0700 Subject: add range check to arg/3 (#1250) --- src/machine/machine_state_impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 373f8704..50b5144c 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -2080,7 +2080,7 @@ impl MachineState { let n = match n { Number::Fixnum(n) => n.get_num() as usize, - Number::Integer(n) => n.to_usize().unwrap(), + Number::Integer(n) if *n >= 0 && *n <= std::usize::MAX => n.to_usize().unwrap(), _ => { self.fail = true; return Ok(()); -- cgit v1.2.3-70-g09d2 From e62875ac904d78dd5a358bf47aad9f8b31202cb4 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 31 Jan 2022 18:08:00 -0700 Subject: tag length/2 as the source of finite_memory errors in list.pl (#1259) --- src/lib/lists.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/lists.pl b/src/lib/lists.pl index f5a62edb..22ee8d4b 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -54,9 +54,9 @@ length(Xs0, N) :- '$skip_max_list'(M, N, Xs0,Xs), !, ( Xs == [] -> N = M - ; nonvar(Xs) -> var(N), throw(error(resource_error(finite_memory),_)) + ; nonvar(Xs) -> var(N), throw(error(resource_error(finite_memory),length/2)) ; nonvar(N) -> R is N-M, length_rundown(Xs, R) - ; N == Xs -> throw(error(resource_error(finite_memory),_)) + ; N == Xs -> throw(error(resource_error(finite_memory),length/2)) ; length_addendum(Xs, N, M) ). length(_, N) :- -- cgit v1.2.3-70-g09d2 From 4b71607215eefe15012fe5b7ae81ece79adca79d Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 31 Jan 2022 18:23:16 -0700 Subject: count cycle lengths in skip_max_list_cycle (#1260) --- src/machine/system_calls.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index a9f1b91f..4f3ed651 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -462,12 +462,21 @@ impl MachineState { hare = step(&self.heap, self.heap[hare]); } + let mut count = 1; + while hare != tortoise { hare = step(&self.heap, self.heap[hare]); tortoise = step(&self.heap, self.heap[tortoise]); + + count += 1; } - unify!(self, self.registers[4], self.heap[hare]); + let target_n = self.store(self.deref(self.registers[1])); + self.unify_fixnum(Fixnum::build_with(count), target_n); + + if !self.fail { + unify!(self, self.registers[4], self.heap[hare]); + } } fn finalize_skip_max_list(&mut self, n: i64, value: HeapCellValue) { -- cgit v1.2.3-70-g09d2 From 37e34c5209e48624d5e272c5b1dcf2bea7fdc1d3 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 31 Jan 2022 21:24:19 -0700 Subject: reset instruction pointers with calls, make HCPrinter::range_from safe (#1233) --- src/heap_print.rs | 2 +- src/machine/dispatch.rs | 4 ++++ src/machine/machine_state.rs | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index af9503df..40afdbfc 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -376,7 +376,7 @@ impl HCValueOutputter for PrinterOutputter { } fn range_from(&self, index: RangeFrom) -> &str { - &self.contents.as_str()[index] + &self.contents.as_str().get(index).unwrap_or("") } } diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 4c02ea8b..8663a407 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -962,6 +962,8 @@ impl Machine { match self.find_living_dynamic_else(p) { Some((p, next_i)) => { self.machine_st.p = p; + self.machine_st.oip = 0; + self.machine_st.iip = 0; match self.machine_st.dynamic_mode { FirstOrNext::First if next_i == 0 => { @@ -1044,6 +1046,8 @@ impl Machine { match self.find_living_dynamic_else(p) { Some((p, next_i)) => { self.machine_st.p = p; + self.machine_st.oip = 0; + self.machine_st.iip = 0; match self.machine_st.dynamic_mode { FirstOrNext::First if next_i == 0 => { diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 27a35884..5d8e591d 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -439,15 +439,19 @@ impl MachineState { pub(super) fn call_at_index(&mut self, arity: usize, p: usize) { self.cp = self.p + 1; self.p = p; + self.oip = 0; + self.iip = 0; self.num_of_args = arity; self.b0 = self.b; } #[inline(always)] pub(super) fn execute_at_index(&mut self, arity: usize, p: usize) { + self.p = p; + self.oip = 0; + self.iip = 0; self.num_of_args = arity; self.b0 = self.b; - self.p = p; } pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult { -- cgit v1.2.3-70-g09d2 From 3c022e4332fac701cdb45e0487089a2925218a3e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 3 Feb 2022 19:57:41 -0700 Subject: fix float formatting (#1233, #1258) --- src/heap_print.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index 40afdbfc..8852c3c8 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -938,10 +938,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { fl = 0f64; } - let output_str = format!("{0:<20?}", fl); + let output_str = if fl.fract() == 0f64 { + if fl.abs() >= 1.0e16 { + format!("{:.1e}", fl.trunc()) + } else { + format!("{:.1}", fl.trunc()) + } + } else if 0f64 < fl.fract().abs() && fl.fract().abs() <= 1.0e-16 { + format!("{:>1e}", fl) + } else { + format!("{}", fl) + }; push_space_if_amb!(self, &output_str, { - append_str!(self, &output_str.trim()); + append_str!(self, &output_str); }); } Number::Rational(r) => { -- cgit v1.2.3-70-g09d2 From 7b8001d060df8cfda1754b8bd850a15e9a8071ce Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 4 Feb 2022 21:51:22 -0700 Subject: fix '$skip_max_list'/4 (#1260) --- src/machine/partial_string.rs | 2 +- src/machine/system_calls.rs | 28 ++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index cb26ab1e..0e25d7b5 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -372,7 +372,7 @@ impl<'a> HeapPStrIter<'a> { match self.brent_st.step(next_hare) { Some(cycle_result) => { debug_assert!(match cycle_result { - CycleSearchResult::Cyclic(_) => true, + CycleSearchResult::Cyclic(..) => true, _ => false, }); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 4f3ed651..f2f8edd9 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -432,7 +432,7 @@ impl MachineState { } fn skip_max_list_cycle(&mut self, lam: usize) { - fn step(heap: &Heap, mut value: HeapCellValue) -> usize { + fn step(heap: &[HeapCellValue], mut value: HeapCellValue) -> usize { loop { read_heap_cell!(value, (HeapCellValueTag::PStrLoc, h) => { @@ -455,27 +455,43 @@ impl MachineState { } } - let mut hare = step(&self.heap, self.registers[3]); + let h = self.heap.len(); + self.heap.push(self.registers[3]); + + let mut hare = h; let mut tortoise = hare; for _ in 0 .. lam { hare = step(&self.heap, self.heap[hare]); } - let mut count = 1; + let mut prev_hare = hare; while hare != tortoise { + prev_hare = hare; hare = step(&self.heap, self.heap[hare]); tortoise = step(&self.heap, self.heap[tortoise]); + } + + // now compute the num_steps of the list prefix until hare is + // reached in the fashion of a C do-while loop since hare + // may point to the beginning of a cycle. - count += 1; + let mut brent_st = BrentAlgState::new(h); + + self.brents_alg_step(&mut brent_st); + + while prev_hare != brent_st.hare { + self.brents_alg_step(&mut brent_st); } + self.heap.pop(); + let target_n = self.store(self.deref(self.registers[1])); - self.unify_fixnum(Fixnum::build_with(count), target_n); + self.unify_fixnum(Fixnum::build_with(brent_st.num_steps() as i64), target_n); if !self.fail { - unify!(self, self.registers[4], self.heap[hare]); + unify!(self, self.registers[4], self.heap[prev_hare]); } } -- cgit v1.2.3-70-g09d2 From 2f0718e88545a5d0497ce62d1f84e540479af50d Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 5 Feb 2022 20:40:28 -0700 Subject: fix write_canonical on strings (#1233) --- src/heap_print.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index 8852c3c8..0a664c6a 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1148,10 +1148,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { if end_cell == empty_list_as_cell!() { append_str!(self, "[]"); } else { - if self.outputter.ends_with(",") { - self.outputter.truncate(self.outputter.len() - ','.len_utf8()); - } - self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.iter.push_stack(end_h); } -- cgit v1.2.3-70-g09d2 From f3f3dccf8e36ca2922552b1b27c771a6eb836519 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 6 Feb 2022 15:14:18 -0700 Subject: reference partial strings properly in read_term (#1271) --- src/machine/machine_state.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 5d8e591d..5b859fa9 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -495,9 +495,18 @@ impl MachineState { loop { match self.read(stream, &indices.op_dir) { Ok(term_write_result) => { + let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc], + (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + pstr_loc_as_cell!(term_write_result.heap_loc) + } + _ => { + heap_loc_as_cell!(term_write_result.heap_loc) + } + ); + let term = self.registers[2]; - unify_fn!(*self, heap_loc_as_cell!(term_write_result.heap_loc), term); - let term = heap_loc_as_cell!(term_write_result.heap_loc); + unify_fn!(*self, heap_loc, term); + let term = heap_loc; if self.fail { return Ok(()); -- cgit v1.2.3-70-g09d2 From 9ba503cd6bcf5896b62eddb8b9743973880ed582 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 6 Feb 2022 21:12:54 -0700 Subject: use printer cycle detection when printing partial strings (#1263), refactor skip_max_list functions --- src/heap_print.rs | 83 +++++++++++++++++++++----------------- src/machine/machine_errors.rs | 11 ++--- src/machine/system_calls.rs | 93 ++++++++++++++++++++++++------------------- 3 files changed, 103 insertions(+), 84 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index 0a664c6a..1dfba375 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -13,6 +13,7 @@ use crate::forms::*; use crate::heap_iter::*; use crate::machine::heap::*; use crate::machine::machine_indices::*; +use crate::machine::machine_state::pstr_loc_and_offset; use crate::machine::partial_string::*; use crate::machine::streams::*; use crate::types::*; @@ -203,6 +204,7 @@ impl NumberFocus { enum TokenOrRedirect { Atom(Atom), BarAsOp, + Char(char), Op(Atom, OpDesc), NumberedVar(String), CompositeRedirect(usize, DirectedOp), @@ -1130,20 +1132,23 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { let end_h = heap_pstr_iter.focus(); let end_cell = heap_pstr_iter.focus; - self.remove_list_children(focus); - if self.check_max_depth(&mut max_depth) { + self.remove_list_children(focus); self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); return; } - let at_cdr = self.at_cdr(","); + let at_cdr = self.outputter.ends_with("|"); if !at_cdr && !self.ignore_ops && end_cell.is_string_terminator(&self.iter.heap) { + self.remove_list_children(focus); return self.print_proper_string(focus, max_depth); } if self.ignore_ops { + self.at_cdr(","); + self.remove_list_children(focus); + if !self.print_string_as_functor(focus, max_depth) { if end_cell == empty_list_as_cell!() { append_str!(self, "[]"); @@ -1153,49 +1158,52 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } } else { - let switch = if !at_cdr { - push_char!(self, '['); - true - } else { - false - }; + let value = heap_bound_store( + self.iter.heap, + heap_bound_deref(self.iter.heap, self.iter.heap[focus]), + ); - let heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus); + read_heap_cell!(value, + (HeapCellValueTag::Lis) => { + return self.push_list(max_depth); + } + _ => { + let switch = Rc::new(Cell::new((!at_cdr, 0))); + self.state_stack.push(TokenOrRedirect::CloseList(switch.clone())); - let mut iter = heap_pstr_iter.chars(); - let mut char_count = 0; + let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus); + let pstr = cell_as_string!(self.iter.heap[h]); - while let Some(c) = iter.next() { - print_char!(self, self.quoted, c); - push_char!(self, ','); + let pstr = pstr.as_str_from(offset.get_num() as usize); - char_count += 1; + if max_depth > 0 && pstr.chars().count() + 1 >= max_depth { + if value.get_tag() != HeapCellValueTag::CStr { + self.iter.pop_stack(); + } - if max_depth > 0 && max_depth <= char_count { - break; - } - } + self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); + self.state_stack.push(TokenOrRedirect::HeadTailSeparator); + } else if end_cell != empty_list_as_cell!() { + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); + self.state_stack.push(TokenOrRedirect::HeadTailSeparator); + } - self.state_stack.push(TokenOrRedirect::CloseList(Rc::new(Cell::new((switch, 0))))); + for (char_count, c) in pstr.chars().rev().enumerate() { + if max_depth > 0 && char_count + 1 >= max_depth { + break; + } - if self.max_depth > 0 && iter.next().is_some() { - self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); - self.state_stack.push(TokenOrRedirect::HeadTailSeparator); - } else { - if iter.cycle_detected() { - self.iter.heap[end_h].set_forwarding_bit(true); - } + self.state_stack.push(TokenOrRedirect::Char(c)); + self.state_stack.push(TokenOrRedirect::Comma); + } - if end_cell != empty_list_as_cell!() { - self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); - self.state_stack.push(TokenOrRedirect::HeadTailSeparator); - self.iter.push_stack(end_h); - } - } + if let Some(TokenOrRedirect::Comma) = self.state_stack.last() { + self.state_stack.pop(); + } - if self.outputter.ends_with(",") { - self.outputter.truncate(self.outputter.len() - ','.len_utf8()); - } + self.state_stack.push(TokenOrRedirect::OpenList(switch)); + } + ); } } @@ -1507,6 +1515,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { match loc_data { TokenOrRedirect::Atom(atom) => self.print_atom(atom), TokenOrRedirect::BarAsOp => append_str!(self, " | "), + TokenOrRedirect::Char(c) => print_char!(self, self.quoted, c), TokenOrRedirect::Op(atom, _) => self.print_op(atom.as_str()), TokenOrRedirect::NumberedVar(num_var) => append_str!(self, &num_var), TokenOrRedirect::CompositeRedirect(max_depth, op) => { diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index cd6cb982..718a57b4 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -5,6 +5,7 @@ use crate::forms::*; use crate::machine::heap::*; use crate::machine::loader::CompilationTarget; use crate::machine::machine_state::*; +use crate::machine::system_calls::BrentAlgState; use crate::types::*; pub type MachineStub = Vec; @@ -783,10 +784,10 @@ impl MachineState { pub(super) fn check_sort_errors(&mut self) -> CallResult { let stub_gen = || functor_stub(atom!("sort"), 2); - let list = self.registers[1]; + let list = self.store(self.deref(self.registers[1])); let sorted = self.registers[2]; - match self.detect_cycles(list) { + match BrentAlgState::detect_cycles(&self.heap, list) { CycleSearchResult::PartialList(..) => { let err = self.instantiation_error(); return Err(self.error_form(err, stub_gen())) @@ -798,7 +799,7 @@ impl MachineState { _ => {} }; - match self.detect_cycles(sorted) { + match BrentAlgState::detect_cycles(&self.heap, sorted) { CycleSearchResult::NotList if !sorted.is_var() => { let err = self.type_error(ValidType::List, sorted); Err(self.error_form(err, stub_gen())) @@ -810,7 +811,7 @@ impl MachineState { fn check_for_list_pairs(&mut self, mut list: HeapCellValue) -> CallResult { let stub_gen = || functor_stub(atom!("keysort"), 2); - match self.detect_cycles(list) { + match BrentAlgState::detect_cycles(&self.heap, list) { CycleSearchResult::NotList if !list.is_var() => { let err = self.type_error(ValidType::List, list); Err(self.error_form(err, stub_gen())) @@ -872,7 +873,7 @@ impl MachineState { let pairs = self.store(self.deref(self[temp_v!(1)])); let sorted = self.store(self.deref(self[temp_v!(2)])); - match self.detect_cycles(pairs) { + match BrentAlgState::detect_cycles(&self.heap, pairs) { CycleSearchResult::PartialList(..) => { let err = self.instantiation_error(); Err(self.error_form(err, stub_gen())) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index f2f8edd9..ee4d152d 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -209,29 +209,27 @@ impl BrentAlgState { } ) } -} -impl MachineState { #[inline(always)] - pub fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { + fn cycle_step(&mut self, heap: &[HeapCellValue]) -> Option { loop { - let store_v = self.heap[brent_st.hare]; + let value = heap[self.hare]; - read_heap_cell!(store_v, + read_heap_cell!(value, (HeapCellValueTag::PStrLoc, h) => { - return brent_st.add_pstr_chars_and_step(&self.heap, h); + return self.add_pstr_chars_and_step(&heap, h); } (HeapCellValueTag::CStr | HeapCellValueTag::PStrOffset) => { - return brent_st.add_pstr_chars_and_step(&self.heap, brent_st.hare); + return self.add_pstr_chars_and_step(&heap, self.hare); } (HeapCellValueTag::Lis, h) => { - return brent_st.step(h+1); + return self.step(h+1); } (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); return if name == atom!(".") && arity == 2 { - brent_st.step(s+2) + self.step(s+2) } else { Some(CycleSearchResult::NotList) }; @@ -240,18 +238,18 @@ impl MachineState { debug_assert!(arity == 0); return if name == atom!("[]") { - Some(CycleSearchResult::ProperList(brent_st.num_steps())) + Some(CycleSearchResult::ProperList(self.num_steps())) } else { Some(CycleSearchResult::NotList) }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if brent_st.hare == h { - let r = store_v.as_var().unwrap(); - return Some(CycleSearchResult::PartialList(brent_st.num_steps(), r)); + if self.hare == h { + let r = value.as_var().unwrap(); + return Some(CycleSearchResult::PartialList(self.num_steps(), r)); } - brent_st.hare = h; + self.hare = h; } _ => { return Some(CycleSearchResult::NotList); @@ -260,25 +258,24 @@ impl MachineState { } } - pub fn detect_cycles(&self, value: HeapCellValue) -> CycleSearchResult { - let store_v = self.store(self.deref(value)); + pub fn detect_cycles(heap: &[HeapCellValue], value: HeapCellValue) -> CycleSearchResult { let mut pstr_chars = 0; - let hare = read_heap_cell!(store_v, + let hare = read_heap_cell!(value, (HeapCellValueTag::Lis, offset) => { offset+1 } (HeapCellValueTag::PStrLoc, h) => { - let (h_offset, n) = pstr_loc_and_offset(&self.heap, h); + let (h_offset, n) = pstr_loc_and_offset(&heap, h); let n = n.get_num() as usize; - let pstr = cell_as_string!(self.heap[h_offset]); + let pstr = cell_as_string!(heap[h_offset]); pstr_chars = pstr.as_str_from(n).chars().count() - 1; - if self.heap[h].get_tag() == HeapCellValueTag::PStrOffset { - debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset); + if heap[h].get_tag() == HeapCellValueTag::PStrOffset { + debug_assert!(heap[h].get_tag() == HeapCellValueTag::PStrOffset); - if self.heap[h_offset].get_tag() == HeapCellValueTag::CStr { + if heap[h_offset].get_tag() == HeapCellValueTag::CStr { return CycleSearchResult::ProperList(pstr_chars + 1); } } @@ -293,7 +290,7 @@ impl MachineState { return CycleSearchResult::ProperList(cstr.as_str_from(0).chars().count()); } (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.heap[s]) + let (name, arity) = cell_as_atom_cell!(heap[s]) .get_name_and_arity(); if name == atom!("[]") && arity == 0 { @@ -312,7 +309,7 @@ impl MachineState { }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { - return CycleSearchResult::PartialList(0, store_v.as_var().unwrap()); + return CycleSearchResult::PartialList(0, value.as_var().unwrap()); } _ => { return CycleSearchResult::NotList; @@ -325,17 +322,20 @@ impl MachineState { brent_st.pstr_chars = pstr_chars; loop { - if let Some(result) = self.brents_alg_step(&mut brent_st) { + if let Some(result) = brent_st.cycle_step(heap) { return result; } } } - pub fn detect_cycles_with_max(&self, max_steps: usize, value: HeapCellValue) -> CycleSearchResult { - let store_v = self.store(self.deref(value)); + pub fn detect_cycles_with_max( + heap: &[HeapCellValue], + max_steps: usize, + value: HeapCellValue, + ) -> CycleSearchResult { let mut pstr_chars = 0; - let hare = read_heap_cell!(store_v, + let hare = read_heap_cell!(value, (HeapCellValueTag::Lis, offset) => { if max_steps > 0 { offset+1 @@ -344,16 +344,16 @@ impl MachineState { } } (HeapCellValueTag::PStrLoc, h) => { - let (h_offset, n) = pstr_loc_and_offset(&self.heap, h); + let (h_offset, n) = pstr_loc_and_offset(&heap, h); let n = n.get_num() as usize; - let pstr = cell_as_string!(self.heap[h_offset]); + let pstr = cell_as_string!(heap[h_offset]); pstr_chars = pstr.as_str_from(n).chars().count() - 1; - if self.heap[h].get_tag() == HeapCellValueTag::PStrOffset { - debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset); + if heap[h].get_tag() == HeapCellValueTag::PStrOffset { + debug_assert!(heap[h].get_tag() == HeapCellValueTag::PStrOffset); - if self.heap[h_offset].get_tag() == HeapCellValueTag::CStr { + if heap[h_offset].get_tag() == HeapCellValueTag::CStr { return if pstr_chars + 1 <= max_steps { CycleSearchResult::ProperList(pstr_chars + 1) } else { @@ -386,7 +386,7 @@ impl MachineState { }; } (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); + let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); if name == atom!("[]") && arity == 0 { return CycleSearchResult::EmptyList; @@ -408,7 +408,7 @@ impl MachineState { }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { - return CycleSearchResult::PartialList(0, store_v.as_var().unwrap()); + return CycleSearchResult::PartialList(0, value.as_var().unwrap()); } _ => { return CycleSearchResult::NotList; @@ -422,15 +422,17 @@ impl MachineState { loop { if brent_st.num_steps() >= max_steps { - return brent_st.to_result(&self.heap); + return brent_st.to_result(&heap); } - if let Some(result) = self.brents_alg_step(&mut brent_st) { + if let Some(result) = brent_st.cycle_step(heap) { return result; } } } +} +impl MachineState { fn skip_max_list_cycle(&mut self, lam: usize) { fn step(heap: &[HeapCellValue], mut value: HeapCellValue) -> usize { loop { @@ -479,10 +481,10 @@ impl MachineState { let mut brent_st = BrentAlgState::new(h); - self.brents_alg_step(&mut brent_st); + brent_st.cycle_step(&self.heap); while prev_hare != brent_st.hare { - self.brents_alg_step(&mut brent_st); + brent_st.cycle_step(&self.heap); } self.heap.pop(); @@ -507,9 +509,16 @@ impl MachineState { fn skip_max_list_result(&mut self, max_steps: i64) { let search_result = if max_steps == -1 { - self.detect_cycles(self.registers[3]) + BrentAlgState::detect_cycles( + &self.heap, + self.store(self.deref(self.registers[3])), + ) } else { - self.detect_cycles_with_max(max_steps as usize, self.registers[3]) + BrentAlgState::detect_cycles_with_max( + &self.heap, + max_steps as usize, + self.store(self.deref(self.registers[3])), + ) }; match search_result { -- cgit v1.2.3-70-g09d2 From 33a6c81a078f517c75bb8c2c7921e67768196275 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 6 Feb 2022 21:46:06 -0700 Subject: update setup_call_cleanup tests --- tests/scryer/src_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index 5e7b74a8..1514da93 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -51,7 +51,7 @@ fn rules() { fn setup_call_cleanup_load() { load_module_test( "src/tests/setup_call_cleanup.pl", - "1+21+31+2>_15388+_153891+_139341+2>41+2>_153891+2>31+2>31+2>4ba" + "1+21+31+2>_15785+_157861+_142871+2>41+2>_157861+2>31+2>31+2>4ba" ); } @@ -60,7 +60,7 @@ fn setup_call_cleanup_process() { run_top_level_test_with_args( &["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"], "", - "1+21+31+2>_16835+_168361+_153811+2>41+2>_168361+2>31+2>31+2>4ba" + "1+21+31+2>_17278+_172791+_157801+2>41+2>_172791+2>31+2>31+2>4ba" ); } -- cgit v1.2.3-70-g09d2 From e4ea5476238e8669032b5ba5e0177048db2de4be Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 7 Feb 2022 14:09:22 -0700 Subject: print bounded depth partial strings correctly --- src/heap_print.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index 1dfba375..63e53d73 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1188,15 +1188,19 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } - for (char_count, c) in pstr.chars().rev().enumerate() { + let state_stack_len = self.state_stack.len(); + + for (char_count, c) in pstr.chars().enumerate() { if max_depth > 0 && char_count + 1 >= max_depth { break; } - self.state_stack.push(TokenOrRedirect::Char(c)); self.state_stack.push(TokenOrRedirect::Comma); + self.state_stack.push(TokenOrRedirect::Char(c)); } + self.state_stack[state_stack_len ..].reverse(); + if let Some(TokenOrRedirect::Comma) = self.state_stack.last() { self.state_stack.pop(); } -- cgit v1.2.3-70-g09d2 From 42da543980475b4fc5147fd1b27c820cd06e7043 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 8 Feb 2022 23:34:42 -0700 Subject: group predicate subsequences by first instantiated arg (#1053) --- src/codegen.rs | 113 +++++++++++++++++++++++++++++---------------------------- src/forms.rs | 8 +++- 2 files changed, 64 insertions(+), 57 deletions(-) diff --git a/src/codegen.rs b/src/codegen.rs index a8094841..0b651be9 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -969,68 +969,61 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } } - /// Returns the index of the first instantiated argument. - fn first_instantiated_index(clauses: &[PredicateClause]) -> Option { - let mut optimal_index = None; - let has_args = match clauses.first() { - Some(clause) => match clause.args() { - Some(args) => !args.is_empty(), - None => false, - }, - None => false, - }; - if !has_args { - return optimal_index; - } - for clause in clauses.iter() { - let args = clause.args().unwrap(); - for (i, arg) in args.iter().enumerate() { - if let Some(optimal_index) = optimal_index { - if i >= optimal_index { - break; - } - } - match arg { - Term::AnonVar | Term::Var(..) => (), - _ => { - match optimal_index { - Some(ref mut optimal_i) => *optimal_i = i, - None => optimal_index = Some(i), - } - break; - } - } - } - } - - optimal_index - } - - fn split_predicate(clauses: &[PredicateClause], optimal_index: usize) -> Vec<(usize, usize)> { + fn split_predicate(clauses: &[PredicateClause]) -> Vec { let mut subseqs = Vec::new(); - let mut left_index = 0; + let mut left = 0; + let mut optimal_index = 0; - if clauses.first().unwrap().args().is_some() { - for (right_index, clause) in clauses.iter().enumerate() { - // Can unwrap safely. - if let Some(arg) = clause.args().unwrap().iter().nth(optimal_index) { + 'outer: for (right, clause) in clauses.iter().enumerate() { + if let Some(args) = clause.args() { + for (instantiated_arg_index, arg) in args.iter().enumerate() { match arg { Term::Var(..) | Term::AnonVar => { - if left_index < right_index { - subseqs.push((left_index, right_index)); + } + _ => { + if optimal_index != instantiated_arg_index { + if left >= right { + optimal_index = instantiated_arg_index; + continue 'outer; + } + + subseqs.push(ClauseSpan { + left, + right, + instantiated_arg_index: optimal_index, + }); + + optimal_index = instantiated_arg_index; + left = right; } - subseqs.push((right_index, right_index + 1)); - left_index = right_index + 1; + continue 'outer; } - _ => (), } } } + + if left < right { + subseqs.push(ClauseSpan { left, right, instantiated_arg_index: optimal_index }); + } + + optimal_index = 0; + + subseqs.push(ClauseSpan { + left: right, + right: right + 1, + instantiated_arg_index: optimal_index, + }); + + left = right + 1; } - if left_index < clauses.len() { - subseqs.push((left_index, clauses.len())); + if left < clauses.len() { + subseqs.push(ClauseSpan { + left, + right: clauses.len(), + instantiated_arg_index: optimal_index, + }); } subseqs @@ -1134,28 +1127,36 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { ) -> Result { let mut code = Code::new(); + /* let optimal_index = match Self::first_instantiated_index(&clauses) { Some(index) => index, None => 0, // Default to first argument indexing. }; + */ - let split_pred = Self::split_predicate(&clauses, optimal_index); + let split_pred = Self::split_predicate(&clauses); let multi_seq = split_pred.len() > 1; - for (l, r) in split_pred { + for ClauseSpan { left, right, instantiated_arg_index } in split_pred { let skel_lower_bound = self.skeleton.clauses.len(); let code_segment = if self.settings.is_dynamic() { - self.compile_pred_subseq::(&clauses[l..r], optimal_index)? + self.compile_pred_subseq::( + &clauses[left..right], + instantiated_arg_index, + )? } else { - self.compile_pred_subseq::(&clauses[l..r], optimal_index)? + self.compile_pred_subseq::( + &clauses[left..right], + instantiated_arg_index, + )? }; let clause_start_offset = code.len(); if multi_seq { - let choice = match l { + let choice = match left { 0 => self.settings.try_me_else(code_segment.len() + 1), - _ if r == clauses.len() => self.settings.trust_me(), + _ if right == clauses.len() => self.settings.trust_me(), _ => self.settings.retry_me_else(code_segment.len() + 1), }; diff --git a/src/forms.rs b/src/forms.rs index db9b36dc..aef5ad95 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -219,7 +219,6 @@ pub enum PredicateClause { } impl PredicateClause { - // TODO: add this to `Term` in `crate::parser` like `first_arg`. pub(crate) fn args(&self) -> Option<&[Term]> { match self { PredicateClause::Fact(term, ..) => match term { @@ -237,6 +236,13 @@ impl PredicateClause { } } +#[derive(Debug)] +pub struct ClauseSpan { + pub left: usize, + pub right: usize, + pub instantiated_arg_index: usize, +} + #[derive(Debug, Clone)] pub enum ModuleSource { Library(Atom), -- cgit v1.2.3-70-g09d2 From 60dd47c69601bf2a84bf8bc8a0a6717197dc3413 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 11 Feb 2022 17:25:01 -0700 Subject: add missing fact to beginning of tmember_t/3 (#1275) --- src/lib/reif.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/reif.pl b/src/lib/reif.pl index a1d31419..c0e14989 100644 --- a/src/lib/reif.pl +++ b/src/lib/reif.pl @@ -79,5 +79,6 @@ tmember(P_2, [X|Xs]) :- :- meta_predicate(tmember_t(2, ?, ?)). +tmember_t(_P_2, [], false). tmember_t(P_2, [X|Xs], T) :- if_( call(P_2, X), T = true, tmember_t(P_2, Xs, T) ). -- cgit v1.2.3-70-g09d2 From db20cda27aff6a13dc7f60b87549359b59b36f6e Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 11 Feb 2022 19:23:43 -0700 Subject: use VecDeque for generating indices during code generation (#1053) --- crates/instructions-template/src/lib.rs | 8 ++- src/indexing.rs | 99 +++++++++++++++++---------------- 2 files changed, 55 insertions(+), 52 deletions(-) diff --git a/crates/instructions-template/src/lib.rs b/crates/instructions-template/src/lib.rs index c4c821b4..774bf40d 100644 --- a/crates/instructions-template/src/lib.rs +++ b/crates/instructions-template/src/lib.rs @@ -805,6 +805,8 @@ fn generate_instruction_preface() -> TokenStream { use indexmap::IndexMap; use slice_deque::SliceDeque; + use std::collections::VecDeque; + fn reg_type_into_functor(r: RegType) -> MachineStub { match r { RegType::Temp(r) => functor!(atom!("x"), [fixnum(r)]), @@ -1035,10 +1037,10 @@ fn generate_instruction_preface() -> TokenStream { } } - impl From> for IndexingLine { + impl From> for IndexingLine { #[inline] - fn from(instrs: SliceDeque) -> Self { - IndexingLine::IndexedChoice(instrs) + fn from(instrs: VecDeque) -> Self { + IndexingLine::IndexedChoice(instrs.into_iter().collect()) } } diff --git a/src/indexing.rs b/src/indexing.rs index 6d63ff79..5deccb80 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -7,6 +7,7 @@ use crate::instructions::*; use indexmap::IndexMap; use slice_deque::{sdeq, SliceDeque}; +use std::collections::VecDeque; use std::hash::Hash; use std::iter::once; use std::mem; @@ -1138,16 +1139,16 @@ pub(crate) fn constant_key_alternatives( #[derive(Debug)] pub(crate) struct StaticCodeIndices { - constants: IndexMap>, - lists: SliceDeque, - structures: IndexMap<(Atom, usize), SliceDeque>, + constants: IndexMap>, + lists: VecDeque, + structures: IndexMap<(Atom, usize), VecDeque>, } #[derive(Debug)] pub(crate) struct DynamicCodeIndices { - constants: IndexMap>, - lists: SliceDeque, - structures: IndexMap<(Atom, usize), SliceDeque>, + constants: IndexMap>, + lists: VecDeque, + structures: IndexMap<(Atom, usize), VecDeque>, } pub(crate) trait Indexer { @@ -1155,26 +1156,26 @@ pub(crate) trait Indexer { fn new() -> Self; - fn constants(&mut self) -> &mut IndexMap>; - fn lists(&mut self) -> &mut SliceDeque; - fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque>; + fn constants(&mut self) -> &mut IndexMap>; + fn lists(&mut self) -> &mut VecDeque; + fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque>; fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex; fn second_level_index( - indices: IndexMap>, - prelude: &mut SliceDeque, + indices: IndexMap>, + prelude: &mut VecDeque, ) -> IndexMap; fn switch_on( instr_fn: impl FnMut(IndexMap) -> IndexingInstruction, - index: &mut IndexMap>, - prelude: &mut SliceDeque, + index: &mut IndexMap>, + prelude: &mut VecDeque, ) -> IndexingCodePtr; fn switch_on_list( - lists: &mut SliceDeque, - prelude: &mut SliceDeque, + lists: &mut VecDeque, + prelude: &mut VecDeque, ) -> IndexingCodePtr; fn remove_instruction_with_offset(code: &mut SliceDeque, offset: usize); @@ -1189,23 +1190,23 @@ impl Indexer for StaticCodeIndices { fn new() -> Self { Self { constants: IndexMap::new(), - lists: sdeq![], + lists: VecDeque::new(), structures: IndexMap::new(), } } #[inline] - fn constants(&mut self) -> &mut IndexMap> { + fn constants(&mut self) -> &mut IndexMap> { &mut self.constants } #[inline] - fn lists(&mut self) -> &mut SliceDeque { + fn lists(&mut self) -> &mut VecDeque { &mut self.lists } #[inline] - fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque> { + fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque> { &mut self.structures } @@ -1218,18 +1219,18 @@ impl Indexer for StaticCodeIndices { } fn second_level_index( - indices: IndexMap>, - prelude: &mut SliceDeque, + indices: IndexMap>, + prelude: &mut VecDeque, ) -> IndexMap { let mut index_locs = IndexMap::new(); for (key, mut code) in indices.into_iter() { if code.len() > 1 { index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1)); - cap_choice_seq_with_trust(&mut code); + cap_choice_seq_with_trust(code.make_contiguous()); prelude.push_back(IndexingLine::from(code)); } else { - code.first().map(|i| { + code.front().map(|i| { index_locs.insert(key, IndexingCodePtr::External(i.offset())); }); } @@ -1240,8 +1241,8 @@ impl Indexer for StaticCodeIndices { fn switch_on( mut instr_fn: impl FnMut(IndexMap) -> IndexingInstruction, - index: &mut IndexMap>, - prelude: &mut SliceDeque, + index: &mut IndexMap>, + prelude: &mut VecDeque, ) -> IndexingCodePtr { let index = mem::replace(index, IndexMap::new()); let index = Self::second_level_index(index, prelude); @@ -1261,18 +1262,18 @@ impl Indexer for StaticCodeIndices { } fn switch_on_list( - lists: &mut SliceDeque, - prelude: &mut SliceDeque, + lists: &mut VecDeque, + prelude: &mut VecDeque, ) -> IndexingCodePtr { if lists.len() > 1 { - cap_choice_seq_with_trust(lists); - let lists = mem::replace(lists, sdeq![]); + cap_choice_seq_with_trust(lists.make_contiguous()); + let lists = mem::replace(lists, VecDeque::new()); prelude.push_back(IndexingLine::from(lists)); IndexingCodePtr::Internal(1) } else { lists - .first() + .front() .map(|i| IndexingCodePtr::External(i.offset())) .unwrap_or(IndexingCodePtr::Fail) } @@ -1305,23 +1306,23 @@ impl Indexer for DynamicCodeIndices { fn new() -> Self { Self { constants: IndexMap::new(), - lists: sdeq![], + lists: VecDeque::new(), structures: IndexMap::new(), } } #[inline] - fn constants(&mut self) -> &mut IndexMap> { + fn constants(&mut self) -> &mut IndexMap> { &mut self.constants } #[inline] - fn lists(&mut self) -> &mut SliceDeque { + fn lists(&mut self) -> &mut VecDeque { &mut self.lists } #[inline] - fn structures(&mut self) -> &mut IndexMap<(Atom, usize), SliceDeque> { + fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque> { &mut self.structures } @@ -1331,17 +1332,17 @@ impl Indexer for DynamicCodeIndices { } fn second_level_index( - indices: IndexMap>, - prelude: &mut SliceDeque, + indices: IndexMap>, + prelude: &mut VecDeque, ) -> IndexMap { let mut index_locs = IndexMap::new(); for (key, code) in indices.into_iter() { if code.len() > 1 { index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1)); - prelude.push_back(IndexingLine::DynamicIndexedChoice(code)); + prelude.push_back(IndexingLine::DynamicIndexedChoice(code.into_iter().collect())); } else { - code.first().map(|i| { + code.front().map(|i| { index_locs.insert(key, IndexingCodePtr::DynamicExternal(*i)); }); } @@ -1352,8 +1353,8 @@ impl Indexer for DynamicCodeIndices { fn switch_on( mut instr_fn: impl FnMut(IndexMap) -> IndexingInstruction, - index: &mut IndexMap>, - prelude: &mut SliceDeque, + index: &mut IndexMap>, + prelude: &mut VecDeque, ) -> IndexingCodePtr { let index = mem::replace(index, IndexMap::new()); let index = Self::second_level_index(index, prelude); @@ -1373,16 +1374,16 @@ impl Indexer for DynamicCodeIndices { } fn switch_on_list( - lists: &mut SliceDeque, - prelude: &mut SliceDeque, + lists: &mut VecDeque, + prelude: &mut VecDeque, ) -> IndexingCodePtr { if lists.len() > 1 { - let lists = mem::replace(lists, sdeq![]); - prelude.push_back(IndexingLine::DynamicIndexedChoice(lists)); + let lists = mem::replace(lists, VecDeque::new()); + prelude.push_back(IndexingLine::DynamicIndexedChoice(lists.into_iter().collect())); IndexingCodePtr::Internal(1) } else { lists - .first() + .front() .map(|i| IndexingCodePtr::DynamicExternal(*i)) .unwrap_or(IndexingCodePtr::Fail) } @@ -1431,7 +1432,7 @@ impl CodeOffsets { index: usize, ) -> Vec { let overlapping_constants = constant_key_alternatives(constant, atom_tbl); - let code = self.indices.constants().entry(constant).or_insert(sdeq![]); + let code = self.indices.constants().entry(constant).or_insert(VecDeque::new()); let is_initial_index = code.is_empty(); code.push_back(I::compute_index(is_initial_index, index)); @@ -1441,7 +1442,7 @@ impl CodeOffsets { .indices .constants() .entry(*constant) - .or_insert(sdeq![]); + .or_insert(VecDeque::new()); let is_initial_index = code.is_empty(); let index = I::compute_index(is_initial_index, index); @@ -1457,7 +1458,7 @@ impl CodeOffsets { .indices .structures() .entry((name.clone(), arity)) - .or_insert(sdeq![]); + .or_insert(VecDeque::new()); let code_len = code.len(); let is_initial_index = code.is_empty(); @@ -1508,7 +1509,7 @@ impl CodeOffsets { return vec![]; } - let mut prelude = sdeq![]; + let mut prelude = VecDeque::new(); let mut emitted_switch_on_structure = false; let mut emitted_switch_on_constant = false; -- cgit v1.2.3-70-g09d2 From 68ac92a616478ed581a3279aa55030df338643cf Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 14 Feb 2022 18:46:15 -0700 Subject: don't unify module-qualified variables to ! (#1281) --- src/lib/builtins.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 94ff77d0..f88fef3a 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -240,7 +240,7 @@ comma_dispatch_prep(Gs, B, [Cont|Conts]) :- comma_dispatch_prep(G1, B, IConts1), cont_list_goal(IConts1, Cont), comma_dispatch_prep(G2, B, Conts) - ; ( Gs = ! ; Gs = _:! ) -> + ; Gs == ! -> Cont = builtins:set_cp(B), Conts = [] ; functor(Gs, ';', 2) -> -- cgit v1.2.3-70-g09d2 From 5b829636cb270b0de5214ecb13813a55ffb91cd1 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 15 Feb 2022 22:22:36 -0700 Subject: build CStr's to vars in write_literal_to_var (#1284) --- src/machine/machine_state_impl.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 50b5144c..931f0f11 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1973,6 +1973,10 @@ impl MachineState { | HeapCellValueTag::Str => { self.match_partial_string(store_v, cstr_atom, false); } + HeapCellValueTag::AttrVar | HeapCellValueTag::Var => { + let r = store_v.as_var().unwrap(); + self.bind(r, lit); + } _ => { self.fail = true; } -- cgit v1.2.3-70-g09d2 From 55d8de1b237b0cfc5c562b78ffcbfae3ef9b3277 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 17 Feb 2022 20:26:30 -0700 Subject: delay callable errors in control predicates (#1282) --- src/lib/builtins.pl | 115 ++++++++++++++++++++++++++++++-------------- src/loader.pl | 37 ++++++++------ src/machine/system_calls.rs | 26 +++++----- 3 files changed, 117 insertions(+), 61 deletions(-) diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index f88fef3a..c381b313 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -208,70 +208,115 @@ repeat :- repeat. :- meta_predicate ->(0,0). -! :- '$get_staggered_cp'(B), '$set_cp'(B). -G1 -> G2 :- '$get_staggered_cp'(B), call('$call'(G1)), '$set_cp'(B), call('$call'(G2)). +G1 -> G2 :- control_entry_point((G1 -> G2)). -G ; _ :- call('$call'(G)). -_ ; G :- call('$call'(G)). -','(G1, G2) :- '$get_staggered_cp'(B), comma_dispatch(G1,G2,B). +:- non_counted_backtracking staggered_if_then/2. + +staggered_if_then(G1, G2) :- + '$get_staggered_cp'(B), + call('$call'(G1)), + '$set_cp'(B), + call('$call'(G2)). + +G1 ; G2 :- control_entry_point((G1 ; G2)). + + +:- non_counted_backtracking staggered_sc/2. + +staggered_sc(G, _) :- call('$call'(G)). +staggered_sc(_, G) :- call('$call'(G)). + + +! :- !. + +:- non_counted_backtracking set_cp/1. set_cp(B) :- '$set_cp'(B). -:- non_counted_backtracking comma_dispatch/3. +','(G1, G2) :- control_entry_point((G1, G2)). + +:- non_counted_backtracking control_entry_point/1. + +control_entry_point(G) :- + functor(G, Name, Arity), + catch(builtins:control_entry_point_(G), + dispatch_prep_error, + builtins:throw(error(type_error(callable, G), Name/Arity))). + + +:- non_counted_backtracking control_entry_point_/1. + +control_entry_point_(G) :- + '$get_cp'(B), + dispatch_prep(G,B,Conts), + dispatch_call_list(Conts). -comma_dispatch(G1, G2, B) :- - comma_dispatch_prep((G1, G2), B, Conts), - comma_dispatch_call_list(Conts). :- non_counted_backtracking cont_list_to_goal/2. cont_list_goal([Cont], Cont) :- !. -cont_list_goal(Conts, builtins:comma_dispatch_call_list(Conts)). +cont_list_goal(Conts, builtins:dispatch_call_list(Conts)). + + +:- non_counted_backtracking module_qualified_cut/1. + +module_qualified_cut(Gs) :- + ( functor(Gs, call, 1) -> + arg(1, Gs, G1) + ; Gs = G1 + ), + functor(G1, (:), 2), + arg(2, G1, G2), + G2 == !. + -:- non_counted_backtracking comma_dispatch_prep/3. +:- non_counted_backtracking dispatch_prep/3. -comma_dispatch_prep(Gs, B, [Cont|Conts]) :- +dispatch_prep(Gs, B, [Cont|Conts]) :- ( callable(Gs) -> ( functor(Gs, ',', 2) -> arg(1, Gs, G1), arg(2, Gs, G2), - comma_dispatch_prep(G1, B, IConts1), + dispatch_prep(G1, B, IConts1), cont_list_goal(IConts1, Cont), - comma_dispatch_prep(G2, B, Conts) - ; Gs == ! -> - Cont = builtins:set_cp(B), - Conts = [] + dispatch_prep(G2, B, Conts) ; functor(Gs, ';', 2) -> arg(1, Gs, G1), arg(2, Gs, G2), - comma_dispatch_prep(G1, B, IConts0), - comma_dispatch_prep(G2, B, IConts1), + dispatch_prep(G1, B, IConts0), + dispatch_prep(G2, B, IConts1), cont_list_goal(IConts0, Cont0), cont_list_goal(IConts1, Cont1), - Cont = ( Cont0 ; Cont1 ), + Cont = builtins:staggered_sc(Cont0, Cont1), Conts = [] ; functor(Gs, ->, 2) -> arg(1, Gs, G1), arg(2, Gs, G2), - comma_dispatch_prep(G1, B, IConts1), - comma_dispatch_prep(G2, B, IConts2), + dispatch_prep(G1, B, IConts1), + dispatch_prep(G2, B, IConts2), cont_list_goal(IConts1, Cont1), cont_list_goal(IConts2, Cont2), - Cont = (Cont1 -> Cont2), + Cont = builtins:staggered_if_then(Cont1, Cont2), + Conts = [] + ; ( Gs == ! ; module_qualified_cut(Gs) ) -> + Cont = builtins:set_cp(B), Conts = [] ; Cont = Gs, Conts = [] ) - ; Cont = Gs, + ; var(Gs) -> + Cont = Gs, Conts = [] + ; throw(dispatch_prep_error) ). -:- non_counted_backtracking comma_dispatch_call_list/1. -comma_dispatch_call_list([]). -comma_dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :- +:- non_counted_backtracking dispatch_call_list/1. + +dispatch_call_list([]). +dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :- !, '$call'(G1), '$call'(G2), @@ -281,8 +326,8 @@ comma_dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :- '$call'(G6), '$call'(G7), '$call'(G8), - '$call_with_default_policy'(comma_dispatch_call_list(Gs)). -comma_dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :- + '$call_with_default_policy'(dispatch_call_list(Gs)). +dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :- !, '$call'(G1), '$call'(G2), @@ -291,7 +336,7 @@ comma_dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :- '$call'(G5), '$call'(G6), '$call'(G7). -comma_dispatch_call_list([G1,G2,G3,G4,G5,G6]) :- +dispatch_call_list([G1,G2,G3,G4,G5,G6]) :- !, '$call'(G1), '$call'(G2), @@ -299,29 +344,29 @@ comma_dispatch_call_list([G1,G2,G3,G4,G5,G6]) :- '$call'(G4), '$call'(G5), '$call'(G6). -comma_dispatch_call_list([G1,G2,G3,G4,G5]) :- +dispatch_call_list([G1,G2,G3,G4,G5]) :- !, '$call'(G1), '$call'(G2), '$call'(G3), '$call'(G4), '$call'(G5). -comma_dispatch_call_list([G1,G2,G3,G4]) :- +dispatch_call_list([G1,G2,G3,G4]) :- !, '$call'(G1), '$call'(G2), '$call'(G3), '$call'(G4). -comma_dispatch_call_list([G1,G2,G3]) :- +dispatch_call_list([G1,G2,G3]) :- !, '$call'(G1), '$call'(G2), '$call'(G3). -comma_dispatch_call_list([G1,G2]) :- +dispatch_call_list([G1,G2]) :- !, '$call'(G1), '$call'(G2). -comma_dispatch_call_list([G1]) :- +dispatch_call_list([G1]) :- '$call'(G1). diff --git a/src/loader.pl b/src/loader.pl index c5228d1f..3d3e8bd2 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -671,7 +671,10 @@ expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :- expand_goal(UnexpandedGoals, Module, ExpandedGoals) :- - expand_goal(UnexpandedGoals, Module, ExpandedGoals, []), + % if a goal isn't callable, defer to call/N to report the error. + catch('$call'(loader:expand_goal(UnexpandedGoals, Module, ExpandedGoals, [])), + error(type_error(callable, _), _), + '$call'(UnexpandedGoals = ExpandedGoals)), !. expand_goal_cases((Goal0, Goals0), Module, ExpandedGoals, HeadVars) :- @@ -716,27 +719,25 @@ expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :- thread_goals(Goals0, Goals1, Hole, Functor) :- ( var(Goals0) -> Goals1 =.. [Functor, Goals0, Hole] - ; ( Goals0 = [G | Gs] -> - ( Gs == [] -> - Goals1 =.. [Functor, G, Hole] - ; Goals1 =.. [Functor, G, Goals2], - thread_goals(Gs, Goals2, Hole, Functor) - ) - ; Goals1 =.. [Functor, Goals0, Hole] + ; Goals0 = [G | Gs] -> + ( Gs == [] -> + Goals1 =.. [Functor, G, Hole] + ; Goals1 =.. [Functor, G, Goals2], + thread_goals(Gs, Goals2, Hole, Functor) ) + ; Goals1 =.. [Functor, Goals0, Hole] ). thread_goals(Goals0, Goals1, Functor) :- ( var(Goals0) -> Goals0 = Goals1 - ; ( Goals0 = [G | Gs] -> - ( Gs = [] -> - Goals1 = G - ; Goals1 =.. [Functor, G, Goals2], - thread_goals(Gs, Goals2, Functor) - ) - ; Goals1 = Goals0 + ; Goals0 = [G | Gs] -> + ( Gs = [] -> + Goals1 = G + ; Goals1 =.. [Functor, G, Goals2], + thread_goals(Gs, Goals2, Functor) ) + ; Goals1 = Goals0 ). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -780,12 +781,14 @@ call_clause('$call'(G), G0) :- instantiation_error(call/1) ; G = M:G1, !, + callable(G1), functor(G1, F, _), atom(F), atom(M), F \== [], G0 = M:G1 ; !, + callable(G), functor(G, F, _), atom(F), F \== [], @@ -795,6 +798,7 @@ call_clause('$call'(G), G0) :- call_clause(G, G0) :- strip_module(G, M, G1), + callable(G1), functor(G1, F, _), atom(F), F \== [], @@ -825,6 +829,7 @@ call_clause('$call'(G1), Args, N, G0) :- F \== [], append(As, Args, As1), G3 =.. [F | As1], + callable(G3), G0 = M:G3 ; !, G1 =.. [F | As], @@ -833,6 +838,7 @@ call_clause('$call'(G1), Args, N, G0) :- load_context(M), append(As, Args, As1), G2 =.. [F | As1], + callable(G2), G0 = M:G2 ). @@ -847,6 +853,7 @@ call_clause(G, Args, _, G0) :- ), append(As, Args, As1), G2 =.. [F | As1], + callable(G2), expand_goal(call(M:G2), M, call(G0)). diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index ee4d152d..ef548a2e 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -3929,20 +3929,24 @@ impl Machine { let semicolon_second_clause_p = unsafe { LOC_INIT.call_once(|| { - match self.indices.code_dir.get(&(atom!(";"), 2)).map(|cell| cell.get()) { - Some(IndexPtr::Index(p)) => { - match &self.code[p] { - &Instruction::TryMeElse(o) => { - SEMICOLON_SECOND_BRANCH_LOC = p + o; - } - _ => { - unreachable!(); + if let Some(builtins) = self.indices.modules.get(&atom!("builtins")) { + match builtins.code_dir.get(&(atom!("staggered_sc"), 2)).map(|cell| cell.get()) { + Some(IndexPtr::Index(p)) => { + match &self.code[p] { + &Instruction::TryMeElse(o) => { + SEMICOLON_SECOND_BRANCH_LOC = p + o; + } + _ => { + unreachable!(); + } } } + _ => { + unreachable!(); + } } - _ => { - unreachable!(); - } + } else { + unreachable!(); } }); -- cgit v1.2.3-70-g09d2 From d3583276b3f741f39408631cfcc6d4227da17b0f Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 18 Feb 2022 19:33:16 -0700 Subject: throw instantiation_error on variables from (#1283) --- src/machine/system_calls.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index ef548a2e..647d4d14 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2925,8 +2925,14 @@ impl Machine { let key = (self.machine_st.atom_tbl.build_with(&c.to_string()), narity); Ok((module_name, key)) } + (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { + let stub = functor_stub(atom!("call"), 1); + let err = self.machine_st.instantiation_error(); + + Err(self.machine_st.error_form(err, stub)) + } _ => { - let stub = functor_stub(atom!("(:)"), 2); + let stub = functor_stub(atom!("call"), narity); let err = self.machine_st.type_error(ValidType::Callable, addr); Err(self.machine_st.error_form(err, stub)) -- cgit v1.2.3-70-g09d2 From a5adcfff4cf72e0a8c89b334924ebe4e6701d170 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 18 Feb 2022 19:49:16 -0700 Subject: adjust dynamic external indices upon retraction, reset dynamic_mode to Next regardless of success or failure --- src/machine/compile.rs | 12 +++++++----- src/machine/dispatch.rs | 14 ++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/machine/compile.rs b/src/machine/compile.rs index e11466fc..157f16ae 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1769,11 +1769,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { .opt_arg_index_key .switch_on_term_loc() { - Some(index_loc) => find_inner_choice_instr( - &self.wam_prelude.code, - skeleton.clauses[target_pos].clause_start, - index_loc, - ), + Some(index_loc) => { + find_inner_choice_instr( + &self.wam_prelude.code, + skeleton.clauses[target_pos].clause_start, + index_loc, + ) + } None => skeleton.clauses[target_pos].clause_start, }; diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 8663a407..fe22678d 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -1033,12 +1033,11 @@ impl Machine { } } + self.machine_st.dynamic_mode = FirstOrNext::Next; + if self.machine_st.fail { self.machine_st.backtrack(); - continue; } - - self.machine_st.dynamic_mode = FirstOrNext::Next; } &Instruction::DynamicInternalElse(..) => { let p = self.machine_st.p; @@ -1115,12 +1114,11 @@ impl Machine { } } + self.machine_st.dynamic_mode = FirstOrNext::Next; + if self.machine_st.fail { self.machine_st.backtrack(); - continue; } - - self.machine_st.dynamic_mode = FirstOrNext::Next; } &Instruction::TryMeElse(offset) => { self.machine_st.try_me_else(offset); @@ -3129,10 +3127,10 @@ impl Machine { } } + self.machine_st.dynamic_mode = FirstOrNext::Next; + if self.machine_st.fail { self.machine_st.backtrack(); - } else { - self.machine_st.dynamic_mode = FirstOrNext::Next; } } } -- cgit v1.2.3-70-g09d2 From c89324710708671586b70c7bcb9c005832d11060 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 18 Feb 2022 22:17:15 -0700 Subject: update setup_call_cleanup tests --- tests/scryer/src_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/scryer/src_tests.rs b/tests/scryer/src_tests.rs index 1514da93..b0b9efb5 100644 --- a/tests/scryer/src_tests.rs +++ b/tests/scryer/src_tests.rs @@ -51,7 +51,7 @@ fn rules() { fn setup_call_cleanup_load() { load_module_test( "src/tests/setup_call_cleanup.pl", - "1+21+31+2>_15785+_157861+_142871+2>41+2>_157861+2>31+2>31+2>4ba" + "1+21+31+2>_17737+_177381+_158071+2>41+2>_177381+2>31+2>31+2>4ba" ); } @@ -60,7 +60,7 @@ fn setup_call_cleanup_process() { run_top_level_test_with_args( &["src/tests/setup_call_cleanup.pl", "-f", "-g", "halt"], "", - "1+21+31+2>_17278+_172791+_157801+2>41+2>_172791+2>31+2>31+2>4ba" + "1+21+31+2>_19590+_195911+_176601+2>41+2>_195911+2>31+2>31+2>4ba" ); } -- cgit v1.2.3-70-g09d2 From 063f0da565c71af47f12345264050073e83b48af Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 20 Feb 2022 23:44:18 -0700 Subject: correct '$skip_max_list/4' for non-lists (#1276) --- src/machine/machine_errors.rs | 10 +++++----- src/machine/system_calls.rs | 29 +++++++++++++---------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 718a57b4..889eb7ee 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -771,7 +771,7 @@ impl EvalError { pub enum CycleSearchResult { Cyclic(usize), EmptyList, - NotList, + NotList(usize, HeapCellValue), // the list length until the second argument in the heap PartialList(usize, Ref), // the list length (up to max), and an offset into the heap. ProperList(usize), // the list length. PStrLocation(usize, usize), // list length (up to max), the heap address of the PStrOffset @@ -792,7 +792,7 @@ impl MachineState { let err = self.instantiation_error(); return Err(self.error_form(err, stub_gen())) } - CycleSearchResult::NotList => { + CycleSearchResult::NotList(..) => { let err = self.type_error(ValidType::List, list); return Err(self.error_form(err, stub_gen())); } @@ -800,7 +800,7 @@ impl MachineState { }; match BrentAlgState::detect_cycles(&self.heap, sorted) { - CycleSearchResult::NotList if !sorted.is_var() => { + CycleSearchResult::NotList(..) if !sorted.is_var() => { let err = self.type_error(ValidType::List, sorted); Err(self.error_form(err, stub_gen())) } @@ -812,7 +812,7 @@ impl MachineState { let stub_gen = || functor_stub(atom!("keysort"), 2); match BrentAlgState::detect_cycles(&self.heap, list) { - CycleSearchResult::NotList if !list.is_var() => { + CycleSearchResult::NotList(..) if !list.is_var() => { let err = self.type_error(ValidType::List, list); Err(self.error_form(err, stub_gen())) } @@ -878,7 +878,7 @@ impl MachineState { let err = self.instantiation_error(); Err(self.error_form(err, stub_gen())) } - CycleSearchResult::NotList => { + CycleSearchResult::NotList(..) => { let err = self.type_error(ValidType::List, pairs); Err(self.error_form(err, stub_gen())) } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 647d4d14..314a35d4 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -164,14 +164,14 @@ impl BrentAlgState { return if name == atom!("[]") && arity == 0 { CycleSearchResult::ProperList(self.num_steps()) } else { - CycleSearchResult::NotList + CycleSearchResult::NotList(self.num_steps(), heap[self.hare]) }; } (HeapCellValueTag::Lis, l) => { return CycleSearchResult::UntouchedList(self.num_steps(), l); } _ => { - return CycleSearchResult::NotList; + return CycleSearchResult::NotList(self.num_steps(), heap[self.hare]); } ); } @@ -231,7 +231,7 @@ impl BrentAlgState { return if name == atom!(".") && arity == 2 { self.step(s+2) } else { - Some(CycleSearchResult::NotList) + Some(CycleSearchResult::NotList(self.num_steps(), value)) }; } (HeapCellValueTag::Atom, (name, arity)) => { @@ -240,7 +240,7 @@ impl BrentAlgState { return if name == atom!("[]") { Some(CycleSearchResult::ProperList(self.num_steps())) } else { - Some(CycleSearchResult::NotList) + Some(CycleSearchResult::NotList(self.num_steps(), value)) }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { @@ -252,7 +252,7 @@ impl BrentAlgState { self.hare = h; } _ => { - return Some(CycleSearchResult::NotList); + return Some(CycleSearchResult::NotList(self.num_steps(), value)); } ); } @@ -298,21 +298,21 @@ impl BrentAlgState { } else if name == atom!(".") && arity == 2 { s + 2 } else { - return CycleSearchResult::NotList; + return CycleSearchResult::NotList(0, value); } } (HeapCellValueTag::Atom, (name, arity)) => { return if name == atom!("[]") && arity == 0 { CycleSearchResult::EmptyList } else { - CycleSearchResult::NotList + CycleSearchResult::NotList(0, value) }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { return CycleSearchResult::PartialList(0, value.as_var().unwrap()); } _ => { - return CycleSearchResult::NotList; + return CycleSearchResult::NotList(0, value); } ); @@ -397,21 +397,21 @@ impl BrentAlgState { return CycleSearchResult::UntouchedList(0, s + 1); } } else { - return CycleSearchResult::NotList; + return CycleSearchResult::NotList(0, value); } } (HeapCellValueTag::Atom, (name, arity)) => { return if name == atom!("[]") && arity == 0 { CycleSearchResult::EmptyList } else { - CycleSearchResult::NotList + CycleSearchResult::NotList(0, value) }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { return CycleSearchResult::PartialList(0, value.as_var().unwrap()); } _ => { - return CycleSearchResult::NotList; + return CycleSearchResult::NotList(0, value); } ); @@ -540,11 +540,8 @@ impl MachineState { CycleSearchResult::ProperList(steps) => { self.finalize_skip_max_list(steps as i64, empty_list_as_cell!()) } - CycleSearchResult::NotList => { - let n = self.store(self.deref(self.registers[2])); - - self.unify_fixnum(Fixnum::build_with(max_steps), n); - self.finalize_skip_max_list(max_steps, self.registers[3]); + CycleSearchResult::NotList(n, value) => { + self.finalize_skip_max_list(n as i64, value); } CycleSearchResult::Cyclic(lam) => { self.skip_max_list_cycle(lam); -- cgit v1.2.3-70-g09d2 From d1372d9b3bfdb8835d7cdcc383a4e7ee6f42d97a Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 22 Feb 2022 23:49:01 +0100 Subject: FIXED: library(sgml): load_html/3 and load_xml/3 now both work again. This addresses #1249. --- src/machine/system_calls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 314a35d4..becc644e 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -6003,7 +6003,7 @@ impl Machine { let tag = self.machine_st.atom_tbl.build_with(node.tag_name().name()); - let result = heap_loc_as_cell!(self.machine_st.heap.len()); + let result = str_loc_as_cell!(self.machine_st.heap.len()); self.machine_st.heap.push(atom_as_cell!(atom!("element"), 3)); self.machine_st.heap.push(atom_as_cell!(tag)); @@ -6056,7 +6056,7 @@ impl Machine { ); let tag = self.machine_st.atom_tbl.build_with(name); - let result = heap_loc_as_cell!(self.machine_st.heap.len()); + let result = str_loc_as_cell!(self.machine_st.heap.len()); self.machine_st.heap.push(atom_as_cell!(atom!("element"), 3)); self.machine_st.heap.push(atom_as_cell!(tag)); -- cgit v1.2.3-70-g09d2 From 8fb673e93e59b9876ce72c61dac66766fd88ea59 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 22 Feb 2022 23:51:01 +0100 Subject: use newly available get_n_chars/3 from library(charsio) --- src/lib/sgml.pl | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/lib/sgml.pl b/src/lib/sgml.pl index 507da1c6..0289278e 100644 --- a/src/lib/sgml.pl +++ b/src/lib/sgml.pl @@ -58,6 +58,7 @@ :- use_module(library(error)). :- use_module(library(dcgs)). :- use_module(library(pio)). +:- use_module(library(charsio)). load_html(Source, Es, Options) :- load_structure_(Source, Es, Options, html). @@ -75,15 +76,8 @@ load_structure_(file(Fs), [E], Options, What) :- load_(What, Cs, E, Options). load_structure_(stream(Stream), [E], Options, What) :- must_be(list, Options), - read_to_end(Stream, Cs), + get_n_chars(Stream, _, Cs), load_(What, Cs, E, Options). load_(html, Cs, E, Options) :- '$load_html'(Cs, E, Options). load_(xml, Cs, E, Options) :- '$load_xml'(Cs, E, Options). - -read_to_end(Stream, Cs) :- - '$get_n_chars'(Stream, 4096, Cs0), - ( Cs0 = [] -> Cs = [] - ; partial_string(Cs0, Cs, Rest), - read_to_end(Stream, Rest) - ). -- cgit v1.2.3-70-g09d2 From d92d8bce898d54a07321236108878b5dcd7f12ad Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 22 Feb 2022 23:45:04 -0700 Subject: recognize [] as equivalent to "" in unify_atom (#1288) --- src/machine/machine_state_impl.rs | 3 +++ src/machine/system_calls.rs | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 931f0f11..85fac031 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -544,6 +544,9 @@ impl MachineState { (HeapCellValueTag::Atom, (name, arity)) => { self.fail = !(arity == 0 && name == atom); } + (HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => { + self.fail = cstr_atom != atom!(""); + } (HeapCellValueTag::Char, c1) => { if let Some(c2) = atom.as_char() { self.fail = c1 != c2; diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index becc644e..a407d7fa 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2494,9 +2494,10 @@ impl Machine { } }; + let output = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])); let atom = self.machine_st.atom_tbl.build_with(&string); - self.machine_st.unify_complete_string(atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]))); + self.machine_st.unify_complete_string(atom, output); Ok(()) } -- cgit v1.2.3-70-g09d2 From 775bd3a08bcc42acaf6fcc790a9cd444a41469ed Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 25 Feb 2022 23:01:08 -0700 Subject: unify '' to [] in unify_complete_string (#1292, #1288) --- src/machine/machine_state_impl.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 85fac031..5003d14a 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -333,11 +333,20 @@ impl MachineState { pub fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) { if let Some(r) = value.as_var() { - self.bind(r, atom_as_cstr_cell!(atom)); + if atom == atom!("") { + self.bind(r, atom_as_cell!(atom!("[]"))); + } else { + self.bind(r, atom_as_cstr_cell!(atom)); + } + return; } read_heap_cell!(value, + (HeapCellValueTag::Atom, (cstr_atom, arity)) if atom == atom!("") => { + debug_assert_eq!(arity, 0); + self.fail = cstr_atom != atom!("[]"); + } (HeapCellValueTag::CStr, cstr_atom) => { self.fail = atom != cstr_atom; } @@ -713,7 +722,6 @@ impl MachineState { pub fn unify(&mut self) { let mut tabu_list: IndexSet<(usize, usize)> = IndexSet::new(); - // self.fail = false; while !(self.pdl.is_empty() || self.fail) { let s1 = self.pdl.pop().unwrap(); -- cgit v1.2.3-70-g09d2 From 26e4560429bb6601fd5ffeaeac1ce0c71304bfff Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 25 Feb 2022 23:36:26 -0700 Subject: pop pstr offsets from iterator stack in printer (#1290) --- src/heap_print.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/heap_print.rs b/src/heap_print.rs index 63e53d73..a0231848 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1184,6 +1184,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.state_stack.push(TokenOrRedirect::Atom(atom!("..."))); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } else if end_cell != empty_list_as_cell!() { + if value.get_tag() != HeapCellValueTag::CStr { + self.iter.pop_stack(); + self.iter.push_stack(h+1); + } + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth)); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } @@ -1447,10 +1452,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { (HeapCellValueTag::F64, f) => { self.print_number(NumberFocus::Unfocused(Number::Float(**f)), &op); } - (HeapCellValueTag::PStrOffset) => { - self.print_list_like(max_depth); - } - (HeapCellValueTag::PStr | HeapCellValueTag::CStr) => { + (HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { self.print_list_like(max_depth); } (HeapCellValueTag::Lis) => { -- cgit v1.2.3-70-g09d2 From d55d5f15ae9eadffd8f73f6af5635987a740eb2d Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Fri, 25 Feb 2022 23:57:27 -0700 Subject: compare '[]' in pstr_comparator of compare_term_test (#1299) --- src/machine/machine_state_impl.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 5003d14a..fc60afcc 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1641,8 +1641,8 @@ impl MachineState { PStrCmpResult::Ordered(ordering) => Some(ordering), _ => { if iter1.num_steps() == 0 && iter2.num_steps() == 0 { - return match iter2.focus.get_tag() { - HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc => { + return read_heap_cell!(iter2.focus, + (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { let result = stalled_pstr_iter_handler(iter2, iter1, pdl); if let Some(ordering) = result { @@ -1653,10 +1653,17 @@ impl MachineState { result } } + (HeapCellValueTag::Atom, (name, arity)) => { + if name == atom!("[]") && arity == 0 { + return Some(Ordering::Greater); + } else { + stalled_pstr_iter_handler(iter1, iter2, pdl) + } + } _ => { stalled_pstr_iter_handler(iter1, iter2, pdl) } - }; + ); } pdl.push(iter2.focus); -- cgit v1.2.3-70-g09d2 From 96faad1c0147565ebd86f313adef4f857fc9e102 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 26 Feb 2022 10:57:52 -0700 Subject: add proper error throwing for call_with_inference_limit/3 (#1296) --- src/lib/iso_ext.pl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index 37044a40..e614b1f6 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -137,6 +137,15 @@ handle_ile(B, E, _) :- :- meta_predicate(call_with_inference_limit(0, ?, ?)). call_with_inference_limit(G, L, R) :- + ( integer(L) -> + ( L < 0 -> + domain_error(not_less_than_zero, L, call_with_inference_limit/3) + ; true + ) + ; var(L) -> + instantiation_error(call_with_inference_limit/3) + ; type_error(integer, L, call_with_inference_limit/3) + ), '$get_current_block'(Bb), '$get_b_value'(B), '$call_with_default_policy'(call_with_inference_limit(G, L, R, Bb, B)), -- cgit v1.2.3-70-g09d2 From d4d135f2a9b736966fa274b7a0c4d907b1e68f06 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 26 Feb 2022 11:07:38 -0700 Subject: fix unexpected error in length/2 (#1303) --- src/lib/lists.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/lists.pl b/src/lib/lists.pl index 22ee8d4b..964280d7 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -54,7 +54,7 @@ length(Xs0, N) :- '$skip_max_list'(M, N, Xs0,Xs), !, ( Xs == [] -> N = M - ; nonvar(Xs) -> var(N), throw(error(resource_error(finite_memory),length/2)) + ; nonvar(Xs) -> var(N), Xs = [_|_], throw(error(resource_error(finite_memory),length/2)) ; nonvar(N) -> R is N-M, length_rundown(Xs, R) ; N == Xs -> throw(error(resource_error(finite_memory),length/2)) ; length_addendum(Xs, N, M) -- cgit v1.2.3-70-g09d2 From 1b4b4807a5ee1c56b63be8d7616a37189f1270d9 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Mon, 28 Feb 2022 18:28:13 -0700 Subject: refer to structures using str_loc_as_cell! (#1311) --- src/machine/system_calls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index a407d7fa..a8fdb872 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -5981,7 +5981,7 @@ impl Machine { &mut self.machine_st.atom_tbl, ); - avec.push(heap_loc_as_cell!(self.machine_st.heap.len())); + avec.push(str_loc_as_cell!(self.machine_st.heap.len())); self.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); self.machine_st.heap.push(atom_as_cell!(name)); -- cgit v1.2.3-70-g09d2 From 1bec1b700227d2eac8ff603fbc414a07d92c0573 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 1 Mar 2022 20:20:51 +0100 Subject: FIXED: load_html/3: use str_loc_as_cell! to store attribute structures --- src/machine/system_calls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index a8fdb872..88c85772 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -6035,7 +6035,7 @@ impl Machine { &mut self.machine_st.atom_tbl, ); - avec.push(heap_loc_as_cell!(self.machine_st.heap.len())); + avec.push(str_loc_as_cell!(self.machine_st.heap.len())); self.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); self.machine_st.heap.push(atom_as_cell!(name)); -- cgit v1.2.3-70-g09d2 From 102adb3544693b8042e3806fc9ab418b60d46853 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Tue, 1 Mar 2022 23:52:51 +0100 Subject: ADDED: "a" to enumerate all solutions Example: ?- member(X, "hello"). %@ X = h <-- press "a" %@ ; X = e %@ ; X = l %@ ; X = l %@ ; X = o %@ ; false. --- src/toplevel.pl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/toplevel.pl b/src/toplevel.pl index c72089e9..72e59886 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -173,6 +173,7 @@ instruction_match(Term, VarList) :- submit_query_and_print_results_(Term, VarList) :- '$get_b_value'(B), + bb_put('$report_all', false), '$call'(Term), write_eqs_and_read_input(B, VarList), !. @@ -313,7 +314,10 @@ write_eqs_and_read_input(B, VarList) :- ). read_input(ThreadedGoals, NewVarList) :- - get_single_char(C), + ( bb_get('$report_all', true) -> + C = n + ; get_single_char(C) + ), ( C = w -> nl, write(' '), @@ -331,6 +335,9 @@ read_input(ThreadedGoals, NewVarList) :- read_input(ThreadedGoals, NewVarList) ; member(C, ['\n', .]) -> nl, write('; ... .'), nl + ; C = a -> + bb_put('$report_all', true), + nl, write('; '), false ; read_input(ThreadedGoals, NewVarList) ). @@ -338,6 +345,7 @@ help_message :- nl, nl, write('SPACE, "n" or ";": next solution, if any\n'), write('RETURN or ".": stop enumeration\n'), + write('"a": enumerate all solutions\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'). -- cgit v1.2.3-70-g09d2 From a38f7c852461c8b27452f2425080ec63a26ae68c Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 1 Mar 2022 23:59:33 -0700 Subject: save arguments to delayed goal before calling verify_attrs (#1304) --- src/machine/attributed_variables.rs | 12 ++++++------ src/machine/dispatch.rs | 4 +++- src/machine/mod.rs | 6 ++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index a158d3af..f74d3981 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -108,21 +108,21 @@ impl MachineState { attr_vars.into_iter() } - pub(super) fn verify_attr_interrupt(&mut self, p: usize) { - self.allocate(self.num_of_args + 3); + pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) { + self.allocate(arity + 3); let e = self.e; let and_frame = self.stack.index_and_frame_mut(e); - for i in 1..self.num_of_args + 1 { + for i in 1..arity + 1 { and_frame[i] = self.registers[i]; } - and_frame[self.num_of_args + 1] = + and_frame[arity + 1] = fixnum_as_cell!(Fixnum::build_with(self.b0 as i64)); - and_frame[self.num_of_args + 2] = + and_frame[arity + 2] = fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64)); - and_frame[self.num_of_args + 3] = + and_frame[arity + 3] = fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64)); self.verify_attributes(); diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index fe22678d..830eedb7 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -576,7 +576,9 @@ impl Machine { self.machine_st.attr_var_init.cp = p; } &Instruction::VerifyAttrInterrupt => { - self.run_verify_attr_interrupt(); + let (_, arity) = self.code[VERIFY_ATTR_INTERRUPT_LOC].to_name_and_arity(); + let arity = std::cmp::max(arity, self.machine_st.num_of_args); + self.run_verify_attr_interrupt(arity); } &Instruction::Add(ref a1, ref a2, t) => { let stub_gen = || functor_stub(atom!("is"), 2); diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 7c2be32d..6ce7a7d7 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -511,11 +511,9 @@ impl Machine { } #[inline(always)] - pub(crate) fn run_verify_attr_interrupt(&mut self) { //, cp: usize) { + pub(crate) fn run_verify_attr_interrupt(&mut self, arity: usize) { let p = self.machine_st.attr_var_init.verify_attrs_loc; - - // self.machine_st.attr_var_init.cp = cp; - self.machine_st.verify_attr_interrupt(p); + self.machine_st.verify_attr_interrupt(p, arity); } #[inline(always)] -- cgit v1.2.3-70-g09d2 From 9f864574de79d0cf26ad5ae72c47365daba193e9 Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Wed, 2 Mar 2022 21:02:19 +0100 Subject: ADDED: "f" to enumerate the next 5 solutions, similar to GUPU. --- README.md | 7 ++++--- src/toplevel.pl | 9 +++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 105069ac..f2135168 100644 --- a/README.md +++ b/README.md @@ -224,9 +224,10 @@ predicates it defines. For example, with the program shown above: ; What = pure_world. ``` -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. +Press `SPACE` to show further answers, if any exist. Press `RETURN` +or `.` to abort the search and return to the +toplevel prompt. Press `f` to see the next 5 answers, and +`a` to see all answers. Press `h` to show a help message. To quit Scryer Prolog, use the standard predicate `halt/0`: diff --git a/src/toplevel.pl b/src/toplevel.pl index 72e59886..90e0a3a8 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -174,6 +174,7 @@ instruction_match(Term, VarList) :- submit_query_and_print_results_(Term, VarList) :- '$get_b_value'(B), bb_put('$report_all', false), + bb_put('$report_n_more', 0), '$call'(Term), write_eqs_and_read_input(B, VarList), !. @@ -316,6 +317,10 @@ write_eqs_and_read_input(B, VarList) :- read_input(ThreadedGoals, NewVarList) :- ( bb_get('$report_all', true) -> C = n + ; bb_get('$report_n_more', N), N > 1 -> + N1 is N - 1, + bb_put('$report_n_more', N1), + C = n ; get_single_char(C) ), ( C = w -> @@ -338,6 +343,9 @@ read_input(ThreadedGoals, NewVarList) :- ; C = a -> bb_put('$report_all', true), nl, write('; '), false + ; C = f -> + bb_put('$report_n_more', 5), + nl, write('; '), false ; read_input(ThreadedGoals, NewVarList) ). @@ -346,6 +354,7 @@ help_message :- write('SPACE, "n" or ";": next solution, if any\n'), write('RETURN or ".": stop enumeration\n'), write('"a": enumerate all solutions\n'), + write('"f": enumerate the next 5 solutions\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'). -- cgit v1.2.3-70-g09d2 From 0c25ffc26e61b46c8cf19b90da3be4ee184f8fb6 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 3 Mar 2022 23:22:36 -0700 Subject: dereference list link in delete_attribute (#1148) --- src/machine/mod.rs | 32 +++++++++++++++++++------------- src/machine/system_calls.rs | 4 ++-- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 6ce7a7d7..19e6d5a1 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -539,7 +539,7 @@ impl Machine { self.machine_st.tr = or_frame.prelude.tr; self.reset_attr_var_state(); - self.machine_st.hb = self.machine_st.heap.len(); + self.machine_st.hb = target_h; self.unwind_trail(old_tr, curr_tr); @@ -563,7 +563,6 @@ impl Machine { self.machine_st.e = or_frame.prelude.e; self.machine_st.cp = or_frame.prelude.cp; - // WAS: or_frame.prelude.bp = self.machine_st.p + 1; or_frame.prelude.biip += 1; let old_tr = or_frame.prelude.tr; @@ -573,14 +572,14 @@ impl Machine { self.machine_st.tr = or_frame.prelude.tr; self.reset_attr_var_state(); + self.machine_st.hb = target_h; + self.machine_st.p = self.machine_st.p + offset; + self.unwind_trail(old_tr, curr_tr); self.machine_st.trail.truncate(self.machine_st.tr); self.machine_st.heap.truncate(target_h); - self.machine_st.hb = self.machine_st.heap.len(); - self.machine_st.p = self.machine_st.p + offset; - self.machine_st.oip = 0; self.machine_st.iip = 0; } @@ -607,15 +606,16 @@ impl Machine { self.machine_st.b = or_frame.prelude.b; self.reset_attr_var_state(); + + self.machine_st.hb = target_h; + self.machine_st.p = self.machine_st.p + offset; + self.unwind_trail(old_tr, curr_tr); self.machine_st.trail.truncate(self.machine_st.tr); self.machine_st.stack.truncate(b); self.machine_st.heap.truncate(target_h); - self.machine_st.hb = self.machine_st.heap.len(); - self.machine_st.p = self.machine_st.p + offset; - self.machine_st.oip = 0; self.machine_st.iip = 0; } @@ -642,14 +642,15 @@ impl Machine { self.machine_st.b = or_frame.prelude.b; self.reset_attr_var_state(); + + self.machine_st.hb = target_h; + self.machine_st.p += 1; + self.unwind_trail(old_tr, curr_tr); self.machine_st.trail.truncate(self.machine_st.tr); self.machine_st.stack.truncate(b); self.machine_st.heap.truncate(target_h); - - self.machine_st.hb = self.machine_st.heap.len(); - self.machine_st.p += 1; } #[inline(always)] @@ -825,8 +826,13 @@ impl Machine { self.machine_st.heap[h] = heap_loc_as_cell!(h); } TrailEntryTag::TrailedAttrVarListLink => { - let l = self.machine_st.trail[i + 1].get_value(); - self.machine_st.heap[h] = list_loc_as_cell!(l); + let value = HeapCellValue::from_bytes( + self.machine_st.trail[i + 1].into_bytes() + ); + + if value.get_value() < self.machine_st.hb { + self.machine_st.heap[h] = value; + } } TrailEntryTag::TrailedBlackboardEntry => { let key = Atom::from(h); diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 88c85772..b8bd9063 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -2833,7 +2833,7 @@ impl Machine { if let HeapCellValueTag::Lis = ls1.get_tag() { let l2 = ls1.get_value(); - let old_addr = self.machine_st.heap[l1+1]; + let old_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[l1+1])); let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1))); let tail = if tail.is_var() { @@ -3709,7 +3709,7 @@ impl Machine { } #[inline(always)] - pub(crate) fn reset_attr_var_state(&mut self) { // 1344! That's the value of self.b we need to pop this. + pub(crate) fn reset_attr_var_state(&mut self) { self.restore_instr_at_verify_attr_interrupt(); self.machine_st.attr_var_init.reset(); } -- cgit v1.2.3-70-g09d2 From d7a3ed2d4abcf6fafe3506c33367b879ffcb3839 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Thu, 3 Mar 2022 23:24:26 -0700 Subject: change domain_error(integer, ..) to type_error(integer, ..) in random.pl (#1310) --- src/lib/random.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/random.pl b/src/lib/random.pl index 2fb21279..d678aff2 100644 --- a/src/lib/random.pl +++ b/src/lib/random.pl @@ -22,11 +22,11 @@ random(R) :- random_integer(Lower, Upper, R) :- var(R), ( (var(Lower) ; var(Upper)) -> - instantiation_error(random_integer/3) + instantiation_error(random_integer/3) ; \+ integer(Lower) -> - domain_error(integer, Lower, random_integer/3) + type_error(integer, Lower, random_integer/3) ; \+ integer(Upper) -> - domain_error(integer, Upper, random_integer/3) + type_error(integer, Upper, random_integer/3) ; Upper > Lower, random(R0), R is floor((Upper - Lower) * R0 + Lower) -- cgit v1.2.3-70-g09d2 From 66c209f9e4b617c8ff52b5a6c4b9b86fdc34c2a1 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 5 Mar 2022 10:38:16 -0700 Subject: reset ReadlineStream from read_query_line (#1317, #1285) --- src/machine/streams.rs | 3 ++- src/read.rs | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 1b512e51..9d76c898 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1053,7 +1053,8 @@ impl Stream { file_stream.stream.get_mut().file.seek(SeekFrom::Start(0)).unwrap(); return true; } - Stream::Readline(_) => { + Stream::Readline(ref mut readline_stream) => { + readline_stream.reset(); return true; } _ => { diff --git a/src/read.rs b/src/read.rs index def66b10..72dc9900 100644 --- a/src/read.rs +++ b/src/read.rs @@ -111,6 +111,12 @@ impl ReadlineStream { } } + #[inline] + pub fn reset(&mut self) { + self.pending_input.get_mut().clear(); + self.pending_input.set_position(0); + } + fn call_readline(&mut self) -> std::io::Result { match self.rl.readline(get_prompt()) { Ok(text) => { -- cgit v1.2.3-70-g09d2 From de35baadf360ef46813750b2c8ecdfeaae13bafa Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 5 Mar 2022 11:14:24 -0700 Subject: use must_be(chars) in read_from_chars/2 (#1305) --- src/lib/charsio.pl | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/lib/charsio.pl b/src/lib/charsio.pl index 33e6e422..4ac7df2b 100644 --- a/src/lib/charsio.pl +++ b/src/lib/charsio.pl @@ -114,17 +114,7 @@ get_single_char(C) :- read_from_chars(Chars, Term) :- - ( var(Chars) -> - instantiation_error(read_from_chars/2) - ; nonvar(Term) -> - throw(error(uninstantiation_error(Term), read_from_chars/2)) - ; '$skip_max_list'(_, _, Chars, Chars0), - Chars0 == [], - partial_string(Chars) -> - true - ; - type_error(complete_string, Chars, read_from_chars/2) - ), + must_be(chars, Chars), '$read_term_from_chars'(Chars, Term). -- cgit v1.2.3-70-g09d2 From 0c19c5690978b7ddbc180e9886f75ee25a5e1257 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 5 Mar 2022 15:27:36 -0700 Subject: mark variables in ArithmeticEvaluator (#690) --- src/allocator.rs | 66 ++++++++++++++------------- src/arithmetic.rs | 60 ++++++++++++++++++------ src/codegen.rs | 119 ++++++++++++++++++++---------------------------- src/debray_allocator.rs | 66 +++++++++++++-------------- src/lib/builtins.pl | 2 +- 5 files changed, 161 insertions(+), 152 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index 7a3b43a0..a8fbc693 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -5,48 +5,52 @@ use crate::fixtures::*; use crate::forms::*; use crate::instructions::*; use crate::machine::machine_indices::*; +use crate::targets::*; use std::cell::Cell; use std::rc::Rc; -pub(crate) trait Allocator<'a> { +pub(crate) trait Allocator { fn new() -> Self; - fn mark_anon_var(&mut self, _: Level, _: GenContext, _: &mut Code) - where - Target: crate::targets::CompilationTarget<'a>; - fn mark_non_var( + fn mark_anon_var<'a, Target: CompilationTarget<'a>>( &mut self, - _: Level, - _: GenContext, - _: &'a Cell, - _: &mut Code, - ) where - Target: crate::targets::CompilationTarget<'a>; - fn mark_reserved_var( + lvl: Level, + context: GenContext, + code: &mut Code, + ); + + fn mark_non_var<'a, Target: CompilationTarget<'a>>( + &mut self, + lvl: Level, + context: GenContext, + cell: &'a Cell, + code: &mut Code, + ); + + fn mark_reserved_var<'a, Target: CompilationTarget<'a>>( &mut self, - _: Rc, - _: Level, - _: &'a Cell, - _: GenContext, - _: &mut Code, - _: RegType, - _: bool, - ) where - Target: crate::targets::CompilationTarget<'a>; - fn mark_var( + var_name: Rc, + lvl: Level, + cell: &'a Cell, + term_loc: GenContext, + code: &mut Code, + r: RegType, + is_new_var: bool, + ); + + fn mark_var<'a, Target: CompilationTarget<'a>>( &mut self, - _: Rc, - _: Level, - _: &'a Cell, - _: GenContext, - _: &mut Code, - ) where - Target: crate::targets::CompilationTarget<'a>; + var_name: Rc, + lvl: Level, + cell: &'a Cell, + context: GenContext, + code: &mut Code, + ); fn reset(&mut self); fn reset_contents(&mut self) {} - fn reset_arg(&mut self, _: usize); + fn reset_arg(&mut self, arg_num: usize); fn reset_at_head(&mut self, args: &Vec); fn advance_arg(&mut self); @@ -56,7 +60,7 @@ pub(crate) trait Allocator<'a> { fn take_bindings(self) -> AllocVarDict; - fn drain_var_data( + fn drain_var_data<'a>( &mut self, vs: VariableFixtures<'a>, num_of_chunks: usize, diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 82212522..894e9d1f 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -1,3 +1,4 @@ +use crate::allocator::*; use crate::arena::*; use crate::atom_table::*; use crate::fixtures::*; @@ -96,7 +97,7 @@ impl<'a> ArithInstructionIterator<'a> { pub(crate) enum ArithTermRef<'a> { Literal(&'a Literal), Op(Atom, usize), // name, arity. - Var(&'a Cell, Rc), + Var(Level, &'a Cell, Rc), } impl<'a> Iterator for ArithInstructionIterator<'a> { @@ -124,8 +125,11 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { } } TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))), - TermIterState::Var(_, cell, var) => { - return Some(Ok(ArithTermRef::Var(cell, var.clone()))); + TermIterState::Var(lvl, cell, var) => { + // the expression is the second argument of an + // is/2 but the iterator can't see that, so the + // level needs to be demoted manually. + return Some(Ok(ArithTermRef::Var(lvl.child_level(), cell, var.clone()))); } _ => { return Some(Err(ArithmeticError::NonEvaluableFunctor( @@ -141,8 +145,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> { } #[derive(Debug)] -pub(crate) struct ArithmeticEvaluator<'a> { - bindings: &'a AllocVarDict, +pub(crate) struct ArithmeticEvaluator<'a, TermMarker> { + marker: &'a mut TermMarker, interm: Vec, interm_c: usize, } @@ -182,10 +186,10 @@ fn push_literal(interm: &mut Vec, c: &Literal) -> Result<(), Ari Ok(()) } -impl<'a> ArithmeticEvaluator<'a> { - pub(crate) fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self { +impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> { + pub(crate) fn new(marker: &'a mut TermMarker, target_int: usize) -> Self { ArithmeticEvaluator { - bindings, + marker, interm: Vec::new(), interm_c: target_int, } @@ -311,20 +315,46 @@ impl<'a> ArithmeticEvaluator<'a> { } } - pub(crate) fn eval(&mut self, src: &'a Term) -> Result { + pub(crate) fn eval( + &mut self, + src: &'a Term, + term_loc: GenContext, + ) -> Result + { let mut code = vec![]; let mut iter = src.iter()?; while let Some(term_ref) = iter.next() { match term_ref? { ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?, - ArithTermRef::Var(cell, name) => { + ArithTermRef::Var(lvl, cell, name) => { let r = if cell.get().norm().reg_num() == 0 { - match self.bindings.get(&name) { - Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t), - Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p), - _ => return Err(ArithmeticError::UninstantiatedVar), - } + let mut getter = || { + use crate::targets::QueryInstruction; + + loop { + match self.marker.bindings().get(&name) { + Some(&VarData::Temp(_, t, _)) if t != 0 => + return RegType::Temp(t), + Some(&VarData::Perm(p)) if p != 0 => + return RegType::Perm(p), + _ => { + self.marker.mark_var::( + name.clone(), + lvl, + cell, + term_loc, + &mut code, + ); + } + } + } + }; + + getter() + /* + _ => return Err(ArithmeticError::UninstantiatedVar), + */ } else { cell.get().norm() }; diff --git a/src/codegen.rs b/src/codegen.rs index 0b651be9..61390257 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -208,7 +208,7 @@ pub(crate) struct CodeGenerator<'a, TermMarker> { global_jmp_by_locs_offset: usize, } -impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { +impl<'b, TermMarker: Allocator> CodeGenerator<'b, TermMarker> { pub(crate) fn new(atom_tbl: &'b mut AtomTable, settings: CodeGenSettings) -> Self { CodeGenerator { atom_tbl, @@ -221,7 +221,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } } - fn update_var_count>>(&mut self, iter: Iter) { + fn update_var_count<'a, Iter: Iterator>>(&mut self, iter: Iter) { for term in iter { if let TermRef::Var(_, _, var) = term { let entry = self.var_count.entry(var).or_insert(0); @@ -230,7 +230,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } } - fn get_var_count(&self, var: &'a String) -> usize { + fn get_var_count(&self, var: &String) -> usize { *self.var_count.get(var).unwrap() } @@ -238,7 +238,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { &mut self, name: Rc, term_loc: GenContext, - vr: &'a Cell, + vr: &Cell, code: &mut Code, ) -> RegType { let mut target = Code::new(); @@ -256,7 +256,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { name: Rc, arg: usize, term_loc: GenContext, - vr: &'a Cell, + vr: &Cell, code: &mut Code, ) -> RegType { match self.marker.bindings().get(&name) { @@ -273,7 +273,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } } - fn add_or_increment_void_instr(target: &mut Code) + fn add_or_increment_void_instr<'a, Target>(target: &mut Code) where Target: crate::targets::CompilationTarget<'a>, { @@ -287,10 +287,10 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { target.push(Target::to_void(1)); } - fn deep_var_instr>( + fn deep_var_instr<'a, Target: crate::targets::CompilationTarget<'a>>( &mut self, cell: &'a Cell, - var: &'a Rc, + var: &Rc, term_loc: GenContext, is_exposed: bool, target: &mut Code, @@ -302,7 +302,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } } - fn subterm_to_instr>( + fn subterm_to_instr<'a, Target: crate::targets::CompilationTarget<'a>>( &mut self, subterm: &'a Term, term_loc: GenContext, @@ -331,7 +331,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { }; } - fn compile_target( + fn compile_target<'a, Target, Iter>( &mut self, iter: Iter, term_loc: GenContext, @@ -413,7 +413,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { target } - fn collect_var_data(&mut self, mut iter: ChunkedIterator<'a>) -> ConjunctInfo<'a> { + fn collect_var_data<'a>(&mut self, mut iter: ChunkedIterator<'a>) -> ConjunctInfo<'a> { let mut vs = VariableFixtures::new(); while let Some((chunk_num, lt_arity, chunked_terms)) = iter.next() { @@ -490,7 +490,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { dealloc_index } - fn compile_inlined( + fn compile_inlined<'a>( &mut self, ct: &InlinedClauseType, terms: &'a Vec, @@ -501,8 +501,8 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { &InlinedClauseType::CompareNumber(mut cmp) => { self.marker.reset_arg(2); - let (mut lcode, at_1) = self.call_arith_eval(&terms[0], 1)?; - let (mut rcode, at_2) = self.call_arith_eval(&terms[1], 2)?; + let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc)?; + let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc)?; let at_1 = if let &Term::Var(ref vr, ref name) = &terms[0] { ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 1, term_loc, vr, code)) @@ -655,74 +655,63 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { Ok(()) } - fn call_arith_eval( + fn compile_arith_expr( &mut self, - term: &'a Term, + term: &Term, target_int: usize, + term_loc: GenContext, ) -> Result { - let mut evaluator = ArithmeticEvaluator::new(&self.marker.bindings(), target_int); - evaluator.eval(term) + let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int); + evaluator.eval(term, term_loc) } fn compile_is_call( &mut self, - terms: &'a Vec, + terms: &Vec, code: &mut Code, term_loc: GenContext, use_default_call_policy: bool, ) -> Result<(), CompilationError> { - let (mut acode, at) = self.call_arith_eval(&terms[1], 1)?; - code.append(&mut acode); + macro_rules! compile_expr { + ($self:expr, $terms:expr, $term_loc:expr, $code:expr) => ({ + let (acode, at) = $self.compile_arith_expr(&$terms[1], 1, $term_loc)?; + $code.extend(acode.into_iter()); + at + }); + } self.marker.reset_arg(2); - match &terms[0] { + let at = match &terms[0] { &Term::Var(ref vr, ref name) => { - let mut target = vec![]; - self.marker.mark_var::( name.clone(), Level::Shallow, vr, term_loc, - &mut target, + code, ); - if !target.is_empty() { - code.extend(target.into_iter()); - } - } - &Term::Literal(_, c @ Literal::Integer(_)) - | &Term::Literal(_, c @ Literal::Fixnum(_)) => { - let v = HeapCellValue::from(c); - code.push(instr!("put_constant", Level::Shallow, v, temp_v!(1))); - - self.marker.advance_arg(); - } - &Term::Literal(_, c @ Literal::Float(_)) => { - let v = HeapCellValue::from(c); - code.push(instr!("put_constant", Level::Shallow, v, temp_v!(1))); - - self.marker.advance_arg(); + compile_expr!(self, terms, term_loc, code) } - &Term::Literal(_, c @ Literal::Rational(_)) => { + &Term::Literal(_, c @ Literal::Integer(_) | + c @ Literal::Float(_) | + c @ Literal::Rational(_) | + c @ Literal::Fixnum(_)) => { let v = HeapCellValue::from(c); code.push(instr!("put_constant", Level::Shallow, v, temp_v!(1))); self.marker.advance_arg(); + compile_expr!(self, terms, term_loc, code) } _ => { code.push(instr!("$fail", 0)); return Ok(()); } - } - - let at = if let &Term::Var(ref vr, ref name) = &terms[1] { - ArithmeticTerm::Reg(self.mark_non_callable(name.clone(), 2, term_loc, vr, code)) - } else { - at.unwrap_or(interm!(1)) }; + let at = at.unwrap_or(interm!(1)); + Ok(if use_default_call_policy { code.push(instr!("is", default, temp_v!(1), at, 0)); } else { @@ -731,7 +720,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } #[inline] - fn compile_unblocked_cut(&mut self, code: &mut Code, cell: &'a Cell) { + fn compile_unblocked_cut(&mut self, code: &mut Code, cell: &Cell) { let r = self.marker.get(Rc::new(String::from("!"))); cell.set(VarReg::Norm(r)); code.push(instr!("$set_cp", cell.get().norm(), 0)); @@ -740,7 +729,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { fn compile_get_level_and_unify( &mut self, code: &mut Code, - cell: &'a Cell, + cell: &Cell, var: Rc, term_loc: GenContext, ) { @@ -756,7 +745,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { code.push(instr!("get_level_and_unify", cell.get().norm())); } - fn compile_seq( + fn compile_seq<'a>( &mut self, iter: ChunkedIterator<'a>, conjunct_info: &ConjunctInfo<'a>, @@ -820,10 +809,10 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } } - fn compile_cleanup( + fn compile_cleanup<'a>( &mut self, code: &mut Code, - conjunct_info: &ConjunctInfo, + conjunct_info: &ConjunctInfo<'a>, toc: &'a QueryTerm, ) { // add a proceed to bookend any trailing cuts. @@ -850,10 +839,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { } } - pub(crate) fn compile_rule<'c: 'a>( - &mut self, - rule: &'c Rule, - ) -> Result { + pub(crate) fn compile_rule(&mut self, rule: &Rule) -> Result { let iter = ChunkedIterator::from_rule(rule); let conjunct_info = self.collect_var_data(iter); @@ -907,7 +893,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { UnsafeVarMarker::from_safe_vars(safe_vars) } - pub(crate) fn compile_fact<'c: 'a>(&mut self, term: &'c Term) -> Code { + pub(crate) fn compile_fact(&mut self, term: &Term) -> Code { self.update_var_count(post_order_iter(term)); let mut vs = VariableFixtures::new(); @@ -942,7 +928,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { fn compile_query_line( &mut self, - term: &'a QueryTerm, + term: &QueryTerm, term_loc: GenContext, code: &mut Code, num_perm_vars_left: usize, @@ -1029,9 +1015,9 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { subseqs } - fn compile_pred_subseq<'c: 'a, I: Indexer>( + fn compile_pred_subseq( &mut self, - clauses: &'c [PredicateClause], + clauses: &[PredicateClause], optimal_index: usize, ) -> Result { let mut code = VecDeque::new(); @@ -1121,19 +1107,12 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> { Ok(Vec::from(code)) } - pub(crate) fn compile_predicate<'c: 'a>( + pub(crate) fn compile_predicate( &mut self, - clauses: &'c Vec, + clauses: &Vec, ) -> Result { let mut code = Code::new(); - /* - let optimal_index = match Self::first_instantiated_index(&clauses) { - Some(index) => index, - None => 0, // Default to first argument indexing. - }; - */ - let split_pred = Self::split_predicate(&clauses); let multi_seq = split_pred.len() > 1; diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 9c688858..2161d20e 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -126,10 +126,11 @@ impl DebrayAllocator { } } - fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec) - where - Target: CompilationTarget<'a>, - { + fn evacuate_arg<'a, Target: CompilationTarget<'a>>( + &mut self, + chunk_num: usize, + code: &mut Code, + ) { match self.alloc_in_last_goal_hint(chunk_num) { Some((var, r)) => { let k = self.arg_c; @@ -137,7 +138,7 @@ impl DebrayAllocator { if r != k { let r = RegType::Temp(r); - target.push(Target::move_to_register(r, k)); + code.push(Target::move_to_register(r, k)); self.contents.swap_remove(&k); self.contents.insert(r.reg_num(), var.clone()); @@ -207,7 +208,7 @@ impl DebrayAllocator { } } -impl<'a> Allocator<'a> for DebrayAllocator { +impl Allocator for DebrayAllocator { fn new() -> DebrayAllocator { DebrayAllocator { arity: 0, @@ -219,42 +220,37 @@ impl<'a> Allocator<'a> for DebrayAllocator { } } - fn mark_anon_var( + fn mark_anon_var<'a, Target: CompilationTarget<'a>>( &mut self, lvl: Level, term_loc: GenContext, - target: &mut Vec, - ) - where - Target: CompilationTarget<'a>, - { + code: &mut Code, + ) { let r = RegType::Temp(self.alloc_reg_to_non_var()); match lvl { - Level::Deep => target.push(Target::subterm_to_variable(r)), + Level::Deep => code.push(Target::subterm_to_variable(r)), Level::Root | Level::Shallow => { let k = self.arg_c; if let GenContext::Last(chunk_num) = term_loc { - self.evacuate_arg::(chunk_num, target); + self.evacuate_arg::(chunk_num, code); } self.arg_c += 1; - target.push(Target::argument_to_variable(r, k)); + code.push(Target::argument_to_variable(r, k)); } }; } - fn mark_non_var( + fn mark_non_var<'a, Target: CompilationTarget<'a>>( &mut self, lvl: Level, term_loc: GenContext, - cell: &Cell, - target: &mut Vec, - ) where - Target: CompilationTarget<'a>, - { + cell: &'a Cell, + code: &mut Code, + ) { let r = cell.get(); let r = match lvl { @@ -262,7 +258,7 @@ impl<'a> Allocator<'a> for DebrayAllocator { let k = self.arg_c; if let GenContext::Last(chunk_num) = term_loc { - self.evacuate_arg::(chunk_num, target); + self.evacuate_arg::(chunk_num, code); } self.arg_c += 1; @@ -278,18 +274,18 @@ impl<'a> Allocator<'a> for DebrayAllocator { cell.set(r); } - fn mark_var>( + fn mark_var<'a, Target: CompilationTarget<'a>>( &mut self, var: Rc, lvl: Level, cell: &'a Cell, term_loc: GenContext, - target: &mut Vec, + code: &mut Code, ) { let (r, is_new_var) = match self.get(var.clone()) { RegType::Temp(0) => { // here, r is temporary *and* unassigned. - let o = self.alloc_reg_to_var::(&var, lvl, term_loc, target); + let o = self.alloc_reg_to_var::(&var, lvl, term_loc, code); cell.set(VarReg::Norm(RegType::Temp(o))); (RegType::Temp(o), true) @@ -303,16 +299,16 @@ impl<'a> Allocator<'a> for DebrayAllocator { r => (r, false), }; - self.mark_reserved_var::(var, lvl, cell, term_loc, target, r, is_new_var); + self.mark_reserved_var::(var, lvl, cell, term_loc, code, r, is_new_var); } - fn mark_reserved_var>( + fn mark_reserved_var<'a, Target: CompilationTarget<'a>>( &mut self, var: Rc, lvl: Level, cell: &'a Cell, term_loc: GenContext, - target: &mut Vec, + code: &mut Code, r: RegType, is_new_var: bool, ) { @@ -321,7 +317,7 @@ impl<'a> Allocator<'a> for DebrayAllocator { let k = self.arg_c; if self.is_curr_arg_distinct_from(&var) { - self.evacuate_arg::(term_loc.chunk_num(), target); + self.evacuate_arg::(term_loc.chunk_num(), code); } self.arg_c += 1; @@ -330,24 +326,24 @@ impl<'a> Allocator<'a> for DebrayAllocator { if !self.in_place(&var, term_loc, r, k) { if is_new_var { - target.push(Target::argument_to_variable(r, k)); + code.push(Target::argument_to_variable(r, k)); } else { - target.push(Target::argument_to_value(r, k)); + code.push(Target::argument_to_value(r, k)); } } } Level::Deep if is_new_var => { if let GenContext::Head = term_loc { if self.occurs_shallowly_in_head(&var, r.reg_num()) { - target.push(Target::subterm_to_value(r)); + code.push(Target::subterm_to_value(r)); } else { - target.push(Target::subterm_to_variable(r)); + code.push(Target::subterm_to_variable(r)); } } else { - target.push(Target::subterm_to_variable(r)); + code.push(Target::subterm_to_variable(r)); } } - Level::Deep => target.push(Target::subterm_to_value(r)), + Level::Deep => code.push(Target::subterm_to_value(r)), }; if !r.is_perm() { diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index c381b313..e21d441e 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -229,7 +229,7 @@ staggered_sc(G, _) :- call('$call'(G)). staggered_sc(_, G) :- call('$call'(G)). -! :- !. +!. :- non_counted_backtracking set_cp/1. -- cgit v1.2.3-70-g09d2