View Javadoc

1   /*
2    * #%L
3    * prolobjectlink-jpi-jtrolog
4    * %%
5    * Copyright (C) 2012 - 2018 WorkLogic Project
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as
9    * published by the Free Software Foundation, either version 2.1 of the
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-2.1.html>.
20   * #L%
21   */
22  package jTrolog.terms;
23  
24  import jTrolog.parser.Parser;
25  import jTrolog.terms.EvaluableTerm;
26  import jTrolog.engine.Prolog;
27  
28  import java.util.*;
29  
30  /**
31   * Struct class represents both compound prolog term and atom term (considered
32   * as 0-arity compound).
33   */
34  @SuppressWarnings({ "rawtypes", "unchecked","serial","unused" })
35  public class Struct extends EvaluableTerm {
36  
37  	public final String name;
38  	public final String predicateIndicator;
39  	/** speedup hash map operation */
40  	public final int arity;
41  	public int operatorType = -1; // see Prolog.FX, Prolog.XFX etc.
42  
43  	private Term[] args;
44  	private Var[] varList;
45  
46  	public Var[] getVarList() {
47  		return varList;
48  	}
49  
50  	Struct(String n, int arity, String predIndic) {
51  		type = Term.STRUCT;
52  		name = n;
53  		this.arity = arity;
54  		predicateIndicator = predIndic;
55  	}
56  
57  	/**
58  	 * Struct representing an operator
59  	 */
60  	public Struct(String f, Term[] argList, int opType) {
61  		this(f, argList);
62  		operatorType = opType;
63  	}
64  
65  	/**
66  	 * Compound struct with an array of arguments
67  	 */
68  	public Struct(String f, Term[] argList) {
69  		this((Parser.removeApices(f)).intern(), argList.length, (Parser.wrapAtom(f) + "/" + argList.length).intern());
70  		args = argList;
71  		varList = (Var[]) getChildrenVarList(args).toArray(new Var[0]);
72  		// prepArrays();
73  	}
74  
75  	/**
76  	 * Gets the i-th element of this structure
77  	 * 
78  	 * No bound check is done
79  	 */
80  	public Term getArg(int index) {
81  		return args[index];
82  	}
83  
84  	public int getOperatorType() {
85  		return operatorType;
86  	}
87  
88  	private static List getChildrenVarList(Term[] args) {
89  		List findings = new ArrayList();
90  		for (int i = 0; i < args.length; i++) {
91  			Term arg = args[i];
92  			if (arg instanceof Var)
93  				findings.add(arg);
94  			else if (arg instanceof Struct) {
95  				Var[] childsVars = ((Struct) arg).varList;
96  				if (childsVars != null && childsVars.length > 0)
97  					findings.addAll(Arrays.asList(childsVars));
98  			}
99  		}
100 		return findings;
101 	}
102 
103 	/**
104 	 * Gets the string representation of this structure
105 	 * 
106 	 * Specific representations are provided for lists and atoms. Names starting
107 	 * with upper case letter are enclosed in apices.
108 	 */
109 	public String toString() {
110 		return predicateIndicator == Parser.listSignature ? toStringList(false) : toStringImpl(false);
111 	}
112 
113 	public String toStringList(boolean small) {
114 		StringBuffer res = new StringBuffer("[");
115 		boolean firstPass = true;
116 		int stopPrinting = Integer.MAX_VALUE;
117 		for (Iterator it = iterator(this); it.hasNext();) {
118 			if (small) {
119 				if (stopPrinting-- == 0) {
120 					Term last = (Term) it.next();
121 					for (; it.hasNext(); last = (Term) it.next())
122 						;
123 					if (last.equals(emptyList))
124 						return res.append(" ... ").append("]").toString();
125 					return res.append(" ... ").append("|").append(last.toStringSmall()).append("]").toString();
126 				}
127 			}
128 			Term child = (Term) it.next();
129 			if (!it.hasNext()) { // last child
130 				if (child.equals(emptyList))
131 					return res.append(']').toString();
132 				return res.append('|').append(small ? child.toStringSmall() : child.toString()).append(']').toString();
133 			}
134 			if (firstPass)
135 				firstPass = false;
136 			else
137 				res.append(", ");
138 			res.append(small ? child.toStringSmall() : child.toString());
139 		}
140 		throw new RuntimeException("bug");
141 	}
142 
143 	public String toStringSmall() {
144 		return predicateIndicator == Parser.listSignature ? toStringList(true) : toStringImpl(true);
145 	}
146 
147 	private String toStringImpl(boolean small) {
148 
149 		if (predicateIndicator == Parser.commaSignature) {
150 			String a = small ? getArg(0).toStringSmall() : getArg(0).toString();
151 			String b = small ? getArg(1).toStringSmall() : getArg(1).toString();
152 			return a + name + " " + b;
153 		}
154 
155 		int opType = getOperatorType();
156 		if (opType == Prolog.XFX || opType == Prolog.YFX || opType == Prolog.XFY) {
157 			String a = small ? getArg(0).toStringSmall() : getArg(0).toString();
158 			String b = small ? getArg(1).toStringSmall() : getArg(1).toString();
159 			return a + " " + name + " " + b;
160 		}
161 		if (opType == Prolog.XF || opType == Prolog.YF) {
162 			String a = small ? getArg(0).toStringSmall() : getArg(0).toString();
163 			return a + " " + name;
164 		}
165 		if (opType == Prolog.FX || opType == Prolog.FY) {
166 			String a = small ? getArg(0).toStringSmall() : getArg(0).toString();
167 			return name + " " + a;
168 		}
169 
170 		if (name.equals("{}")) {
171 			if (arity == 0)
172 				return name;
173 			if (arity == 1)
174 				return "{" + (small ? getArg(0).toStringSmall() : getArg(0).toString()) + "}";
175 		}
176 		StringBuffer res = new StringBuffer(Parser.wrapAtom(name));
177 		res.append("(");
178 		for (int i = 0; i < arity; i++) {
179 			Term arg = getArg(i);
180 			if (arg instanceof Struct && ((Struct) arg).predicateIndicator == Parser.commaSignature)
181 				res.append("(").append(small ? arg.toStringSmall() : arg.toString()).append(")");
182 			else
183 				res.append(small ? arg.toStringSmall() : arg.toString());
184 			if (i < arity - 1)
185 				res.append(", ");
186 		}
187 		res.append(")");
188 		return res.toString();
189 	}
190 
191 	public boolean equals(Object t) {
192 		if (!(t instanceof Struct))
193 			return false;
194 		Struct other = (Struct) t;
195 		if (!predicateIndicator.equals(other.predicateIndicator))
196 			return false;
197 		// return true;
198 		Struct s1 = (Struct) t;
199 		if (arity != s1.arity)
200 			return false;
201 		for (int i = 0; i < s1.arity; i++) {
202 			if (!getArg(i).equals(s1.getArg(i)))
203 				return false;
204 		}
205 		return true;
206 	}
207 
208 	public static Iterator iterator(Struct structList) {
209 		final Struct origin = (Struct) (structList instanceof Wrapper ? ((Wrapper) structList).getBasis() : structList);
210 		Iterator it = new ListIterator(origin);
211 		if (structList instanceof Wrapper)
212 			return new Wrapper.WrappedIterator(it, ((Wrapper) structList).getContext());
213 		return it;
214 	}
215 
216 	private void prepArrays() {
217 
218 		// give me my sizzzzze!
219 		int size = 1; // count me in
220 		for (int i = 0; i < arity; i++) {
221 			Term arg = args[i];
222 			if (arg instanceof Struct && ((Struct) arg).arity > 0)
223 				size += ((Struct) arg).prePost.length;
224 			else
225 				size++;
226 		}
227 		prePost = new int[size];
228 		tree = new Term[size];
229 
230 		int pos = 0;
231 
232 		prePost[pos] = size - 1;
233 		tree[pos] = this;
234 		upDateChild(pos++);
235 
236 		int position = 0;
237 		for (int i = 0; i < arity; i++) {
238 			Term child = getArg(i);
239 			if (child instanceof Struct && ((Struct) child).arity > 0) {
240 				Struct cs1 = (Struct) child;
241 				Term[] valuesArr = cs1.tree;
242 				int[] prePostArr = cs1.prePost;
243 				int childSize = valuesArr.length;
244 
245 				for (int j = 0; j < childSize; j++) {
246 					this.prePost[pos] = prePostArr[j] + position;
247 					this.tree[pos] = valuesArr[j];
248 					upDateChild(pos++);
249 				}
250 				position += childSize;
251 			} else { // atoms and numbers and vars
252 				prePost[pos] = position++;
253 				tree[pos] = child;
254 				upDateChild(pos++);
255 			}
256 		}
257 	}
258 
259 	private void upDateChild(int i) {
260 		Term child = tree[i];
261 		child.tree = tree;
262 		child.prePost = prePost;
263 		child.pos = i;
264 	}
265 }