View Javadoc
1   package org.metricshub.jawk.intermediate;
2   
3   /*-
4    * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5    * Jawk
6    * ჻჻჻჻჻჻
7    * Copyright (C) 2006 - 2025 MetricsHub
8    * ჻჻჻჻჻჻
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   *
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23   */
24  
25  import java.io.Serializable;
26  import java.util.function.Supplier;
27  import org.metricshub.jawk.ext.ExtensionFunction;
28  
29  /**
30   * Represents a single opcode and its arguments within the tuple stream produced
31   * by {@link AwkTuples}. While {@code AwkTuples} manages the list of tuples, this
32   * class models one instruction and up to four typed operands.
33   * <p>
34   * Some tuples defer resolution of a function address until the tuple list is
35   * finalized; such tuples hold a {@link Supplier} that provides the
36   * {@link Address} when needed.
37   *
38   * @author Danny Daglas
39   * @see AwkTuples
40   */
41  class Tuple implements Serializable {
42  
43  	private static final long serialVersionUID = 8105941219003992817L;
44  	private Opcode opcode;
45  	private long[] ints = new long[4];
46  	private boolean[] bools = new boolean[4];
47  	private double[] doubles = new double[4];
48  	private String[] strings = new String[4];
49  	private Class<?>[] types = new Class[4];
50  	private Address address = null;
51  	private Class<?> cls = null;
52  	private transient Supplier<Address> addressSupplier = null;
53  	private int lineno = -1;
54  	private Tuple next = null;
55  	private ExtensionFunction extensionFunction;
56  
57  	Tuple(Opcode opcode) {
58  		this.opcode = opcode;
59  	}
60  
61  	Tuple(Opcode opcode, long i1) {
62  		this(opcode);
63  		ints[0] = i1;
64  		types[0] = Long.class;
65  	}
66  
67  	Tuple(Opcode opcode, long i1, long i2) {
68  		this(opcode, i1);
69  		ints[1] = i2;
70  		types[1] = Long.class;
71  	}
72  
73  	Tuple(Opcode opcode, long i1, boolean b2) {
74  		this(opcode, i1);
75  		bools[1] = b2;
76  		types[1] = Boolean.class;
77  	}
78  
79  	Tuple(Opcode opcode, long i1, boolean b2, boolean b3) {
80  		this(opcode, i1, b2);
81  		bools[2] = b3;
82  		types[2] = Boolean.class;
83  	}
84  
85  	Tuple(Opcode opcode, double d1) {
86  		this(opcode);
87  		doubles[0] = d1;
88  		types[0] = Double.class;
89  	}
90  
91  	Tuple(Opcode opcode, String s1) {
92  		this(opcode);
93  		strings[0] = s1;
94  		types[0] = String.class;
95  	}
96  
97  	Tuple(Opcode opcode, boolean b1) {
98  		this(opcode);
99  		bools[0] = b1;
100 		types[0] = Boolean.class;
101 	}
102 
103 	Tuple(Opcode opcode, String s1, long i2) {
104 		this(opcode, s1);
105 		ints[1] = i2;
106 		types[1] = Long.class;
107 	}
108 
109 	Tuple(Opcode opcode, Address address) {
110 		this(opcode);
111 		this.address = address;
112 		types[0] = Address.class;
113 	}
114 
115 	Tuple(Opcode opcode, String strarg, long intarg, boolean boolarg) {
116 		this(opcode, strarg, intarg);
117 		bools[2] = boolarg;
118 		types[2] = Boolean.class;
119 	}
120 
121 	Tuple(Opcode opcode, ExtensionFunction function, long intarg, boolean boolarg) {
122 		this(opcode);
123 		this.extensionFunction = function;
124 		types[0] = ExtensionFunction.class;
125 		ints[1] = intarg;
126 		types[1] = Long.class;
127 		bools[2] = boolarg;
128 		types[2] = Boolean.class;
129 	}
130 
131 	Tuple(Opcode opcode, Supplier<Address> addressSupplier, String s2, long i3, long i4) {
132 		this(opcode);
133 		this.addressSupplier = addressSupplier;
134 		strings[1] = s2;
135 		types[1] = String.class;
136 		ints[2] = i3;
137 		types[2] = Long.class;
138 		ints[3] = i4;
139 		types[3] = Long.class;
140 	}
141 
142 	Tuple(Opcode opcode, Class<?> cls) {
143 		this(opcode);
144 		this.cls = cls;
145 		types[0] = Class.class;
146 	}
147 
148 	Tuple(Opcode opcode, String s1, String s2) {
149 		this(opcode, s1);
150 		strings[1] = s2;
151 		types[1] = String.class;
152 	}
153 
154 	boolean hasNext() {
155 		return next != null;
156 	}
157 
158 	Tuple getNext() {
159 		return next;
160 	}
161 
162 	void setNext(Tuple next) {
163 		this.next = next;
164 	}
165 
166 	void setLineNumber(int lineNumber) {
167 		assert this.lineno == -1 : "The line number was already set to " + this.lineno + ". Later lineno = "
168 				+ lineNumber + ".";
169 		this.lineno = lineNumber;
170 	}
171 
172 	@Override
173 	public String toString() {
174 		StringBuilder sb = new StringBuilder();
175 		sb.append(opcode.name());
176 		int idx = 0;
177 		while ((idx < types.length) && (types[idx] != null)) {
178 			sb.append(", ");
179 			Class<?> type = types[idx];
180 			if (type == Long.class) {
181 				sb.append(ints[idx]);
182 			} else if (type == Boolean.class) {
183 				sb.append(bools[idx]);
184 			} else if (type == Double.class) {
185 				sb.append(doubles[idx]);
186 			} else if (type == String.class) {
187 				sb.append('"').append(strings[idx]).append('"');
188 			} else if (type == Address.class) {
189 				assert idx == 0;
190 				sb.append(address);
191 			} else if (type == ExtensionFunction.class) {
192 				assert idx == 0;
193 				sb.append(extensionFunction.getKeyword());
194 			} else if (type == Class.class) {
195 				assert idx == 0;
196 				sb.append(cls);
197 			} else {
198 				throw new Error("Unknown param type (" + idx + "): " + type);
199 			}
200 			++idx;
201 		}
202 		return sb.toString();
203 	}
204 
205 	public void touch(java.util.List<Tuple> queue) {
206 		assert lineno != -1 : "The line number should have been set by queue.add(), but was not.";
207 		if (addressSupplier != null) {
208 			address = addressSupplier.get();
209 			types[0] = Address.class;
210 		}
211 		if (address != null) {
212 			if (address.index() == -1) {
213 				throw new Error("address " + address + " is unresolved");
214 			}
215 			if (address.index() >= queue.size()) {
216 				throw new Error("address " + address + " doesn't resolve to an actual list element");
217 			}
218 		}
219 	}
220 
221 	Opcode getOpcode() {
222 		return opcode;
223 	}
224 
225 	long[] getInts() {
226 		return ints;
227 	}
228 
229 	boolean[] getBools() {
230 		return bools;
231 	}
232 
233 	double[] getDoubles() {
234 		return doubles;
235 	}
236 
237 	String[] getStrings() {
238 		return strings;
239 	}
240 
241 	Class<?>[] getTypes() {
242 		return types;
243 	}
244 
245 	Address getAddress() {
246 		return address;
247 	}
248 
249 	Class<?> getCls() {
250 		return cls;
251 	}
252 
253 	Supplier<Address> getAddressSupplier() {
254 		return addressSupplier;
255 	}
256 
257 	ExtensionFunction getExtensionFunction() {
258 		return extensionFunction;
259 	}
260 
261 	void setAddress(Address address) {
262 		this.address = address;
263 	}
264 
265 	int getLineno() {
266 		return lineno;
267 	}
268 }