001: /*
002: * @(#)NodeUtil.java 1.2 05/06/27
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package org.pnuts.lang;
010:
011: import java.io.*;
012: import java.nio.*;
013: import java.util.*;
014: import pnuts.lang.SimpleNode;
015: import pnuts.lang.Runtime;
016: import pnuts.lang.ParseException;
017: import pnuts.lang.PnutsParserTreeConstants;
018:
019: public class NodeUtil {
020: static String ENCODING = "UTF-8";
021:
022: public static void writeNode(ObjectOutputStream o, SimpleNode node)
023: throws IOException {
024: ByteArray ba = new ByteArray();
025: save(node, ba);
026: byte[] bytes = ba.getByteArray();
027: int count = ba.size();
028: o.writeInt(count);
029: o.write(bytes, 0, count);
030: o.flush();
031: }
032:
033: public static SimpleNode readNode(ObjectInputStream in)
034: throws IOException, ParseException {
035: int len = in.readInt();
036: byte[] buf = new byte[len];
037: in.readFully(buf);
038: return parseNode(new ByteArrayInputStream(buf));
039: }
040:
041: static SimpleNode parseNode(InputStream in) throws IOException,
042: ParseException {
043: return parseNode(new BufferedReader(new InputStreamReader(in,
044: ENCODING)));
045: }
046:
047: public static SimpleNode parseNode(String str) {
048: try {
049: return parseNode(new StringReader(str));
050: } catch (Exception e) {
051: e.printStackTrace();
052: return null;
053: }
054: }
055:
056: static SimpleNode parseNode(Reader in) throws IOException,
057: ParseException {
058: int id = 0;
059: int line = 0;
060: int column = 0;
061: String image = null;
062: String info = null;
063: Character c = null;
064: ArrayList nodes = new ArrayList();
065: int ch = in.read();
066: int state = 0;
067: StringBuffer sb = new StringBuffer();
068: loop: while (ch != -1) {
069: switch (state) {
070: case 0:
071: if (ch == '(') {
072: state = 1;
073: break;
074: } else if (ch == ')') {
075: return null;
076: } else {
077: throw new RuntimeException(String.valueOf(ch));
078: }
079: case 1: // id
080: if (ch == ',') {
081: id = Integer.parseInt(sb.toString());
082: sb.setLength(0);
083: if (id == PnutsParserTreeConstants.JJTSTRINGNODE) {
084: int len = readInt(in);
085: for (int i = 0; i < len; i++) {
086: sb.append((char) in.read());
087: }
088: if (len >= 0) {
089: image = sb.toString();
090: }
091: sb.setLength(0);
092: in.read();
093: state = 3;
094: } else {
095: state = 2;
096: }
097: } else {
098: sb.append((char) ch);
099: }
100: break;
101: case 2: // image
102: if (ch == ',') {
103: image = sb.toString();
104: sb.setLength(0);
105: state = 3;
106: } else {
107: sb.append((char) ch);
108: }
109: break;
110: case 3: // line
111: if (ch == ',') {
112: line = Integer.parseInt(sb.toString());
113: sb.setLength(0);
114: state = 4;
115: } else {
116: sb.append((char) ch);
117: }
118: break;
119: case 4: // column
120: if (ch == ',') {
121: column = Integer.parseInt(sb.toString());
122: sb.setLength(0);
123: state = 5;
124: } else {
125: sb.append((char) ch);
126: }
127: break;
128: case 5: // info
129: if (id == PnutsParserTreeConstants.JJTCHARACTERNODE) {
130: c = new Character((char) ch);
131: in.read();
132: state = 6;
133: break;
134: } else {
135: if (ch == ',') {
136: String str = sb.toString();
137: if (!str.startsWith("{")) {
138: info = str;
139: }
140: sb.setLength(0);
141: state = 6;
142: } else {
143: sb.append((char) ch);
144: break;
145: }
146: }
147: case 6: // children
148: if (ch == ')') {
149: break loop;
150: } else {
151: SimpleNode n = parseNode(in);
152: if (n != null) {
153: nodes.add(n);
154: } else {
155: break loop;
156: }
157: }
158: break;
159: }
160: ch = in.read();
161: }
162: SimpleNode n = new SimpleNode(id);
163: if (image != null) {
164: n.str = image.intern();
165: }
166: if (id == PnutsParserTreeConstants.JJTINTEGERNODE) {
167: n.info = Runtime.parseInt(image);
168: } else if (id == PnutsParserTreeConstants.JJTFLOATINGNODE) {
169: n.info = Runtime.parseFloat(image);
170: } else if (id == PnutsParserTreeConstants.JJTCHARACTERNODE) {
171: n.info = c;
172: } else if (id == PnutsParserTreeConstants.JJTBEANPROPERTYDEF) {
173: n.info = info;
174: }
175: n.beginLine = line;
176: n.beginColumn = column;
177: int size = nodes.size();
178: for (int i = size; i > 0; i--) {
179: SimpleNode cn = (SimpleNode) nodes.get(i - 1);
180: cn.jjtSetParent(n);
181: n.jjtAddChild(cn, i - 1);
182: }
183: return n;
184: }
185:
186: public static String saveNode(SimpleNode node, StringBuffer sb) {
187: try {
188: sb.setLength(0);
189: ByteArray ba = new ByteArray();
190: save(node, ba);
191: byte[] bytes = ba.getByteArray();
192: int count = ba.size();
193: return byteArrayToString(bytes, count, sb);
194: } catch (IOException e) {
195: e.printStackTrace();
196: return null;
197: }
198: }
199:
200: public static String saveNode(SimpleNode node) {
201: return saveNode(node, new StringBuffer());
202: }
203:
204: static void writeDigits(OutputStream os, int d) throws IOException {
205: writeString(os, Integer.toString(d));
206: }
207:
208: static void writeInt(OutputStream out, int v) throws IOException {
209: out.write((v >>> 24) & 0xFF);
210: out.write((v >>> 16) & 0xFF);
211: out.write((v >>> 8) & 0xFF);
212: out.write((v >>> 0) & 0xFF);
213: }
214:
215: static int readInt(Reader in) throws IOException {
216: int ch1 = in.read();
217: int ch2 = in.read();
218: int ch3 = in.read();
219: int ch4 = in.read();
220:
221: return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
222: }
223:
224: static void writeString(OutputStream os, String s)
225: throws IOException {
226:
227: int n = s.length();
228:
229: for (int i = 0; i < n; i++) {
230: char c = s.charAt(i);
231:
232: if (c < 0x80) {
233: os.write(c);
234: } else if (c < 0x800) {
235: os.write(0xc0 + (c >> 6));
236: os.write(0x80 + (c & 0x3f));
237: } else {
238: os.write(0xe0 + (c >> 12));
239: os.write(0x80 + ((c >> 6) & 0x3f));
240: os.write(0x80 + (c & 0x3f));
241: }
242: }
243: }
244:
245: /*
246: * (id,image,beginLine,endLine,{literal:offset},...
247: * (id,image,beginLine,endLine,char,...
248: */
249: static void save(SimpleNode node, OutputStream w)
250: throws IOException {
251: w.write('(');
252: writeDigits(w, node.id);
253: w.write(',');
254: if (node.str != null) {
255: if (node.id == PnutsParserTreeConstants.JJTSTRINGNODE) {
256: writeInt(w, node.str.length());
257: writeString(w, node.str);
258: } else if (node.id != PnutsParserTreeConstants.JJTCHARACTERNODE) {
259: writeString(w, node.str);
260: }
261: } else {
262: if (node.id == PnutsParserTreeConstants.JJTSTRINGNODE) {
263: writeInt(w, -1);
264: }
265: }
266: w.write(',');
267: writeDigits(w, node.beginLine);
268: w.write(',');
269: writeDigits(w, node.beginColumn);
270: w.write(',');
271: if (node.info instanceof String) {
272: writeString(w, (String) node.info);
273: } else {
274: if (node.id == PnutsParserTreeConstants.JJTINTEGERNODE
275: || node.id == PnutsParserTreeConstants.JJTFLOATINGNODE) {
276: Object[] info = (Object[]) node.info;
277: Number n = (Number) info[0];
278: int[] offset = (int[]) info[1];
279: w.write('{');
280: writeString(w, n.toString());
281: w.write(':');
282: if (offset != null) {
283: writeDigits(w, offset[0]);
284: }
285: w.write('}');
286: } else if (node.id == PnutsParserTreeConstants.JJTCHARACTERNODE) {
287: Character ch = (Character) node.info;
288: writeString(w, String.valueOf(ch.charValue()));
289: }
290: }
291: w.write(',');
292: int nchildren = node.jjtGetNumChildren();
293: if (nchildren > 0) {
294: save(node.jjtGetChild(0), w);
295: }
296: for (int i = 1; i < nchildren; i++) {
297: w.write(',');
298: save(node.jjtGetChild(i), w);
299: }
300: w.write(')');
301: }
302:
303: public static SimpleNode loadNode(String str) {
304: byte[] b = stringToByteArray(str);
305: /**
306: b = ZipUtil.unzipByteArray(b);
307: **/
308: InputStream in = new ByteArrayInputStream(b);
309: try {
310: Reader r = new BufferedReader(new InputStreamReader(in,
311: ENCODING));
312: return parseNode(r);
313: } catch (Exception e) {
314: e.printStackTrace();
315: return null;
316: }
317: }
318:
319: static String byteArrayToString(byte[] array, int len,
320: StringBuffer sbuf) {
321: int i = 0;
322: if ((len % 2) == 0) {
323: sbuf.append('\0');
324: } else {
325: sbuf.append('\uffff');
326: }
327: for (; i < len / 2; i++) {
328: sbuf
329: .append((char) ((array[i * 2] << 8) | (array[i * 2 + 1] & 0xff)));
330: }
331: if (i * 2 < len) {
332: sbuf.append((char) (array[i * 2] << 8));
333: }
334: return sbuf.toString();
335: }
336:
337: public static String byteArrayToString(byte[] array, int len) {
338: StringBuffer sbuf = new StringBuffer(len / 2 + 1);
339: int i = 0;
340: if ((len % 2) == 0) {
341: sbuf.append('\0');
342: } else {
343: sbuf.append('\uffff');
344: }
345: for (; i < len / 2; i++) {
346: sbuf
347: .append((char) ((array[i * 2] << 8) | (array[i * 2 + 1] & 0xff)));
348: }
349: if (i * 2 < len) {
350: sbuf.append((char) (array[i * 2] << 8));
351: }
352: return sbuf.toString();
353: }
354:
355: public static byte[] stringToByteArray(String s) {
356: return charArrayToByteArray(s.toCharArray());
357: }
358:
359: static byte[] charArrayToByteArray(char[] c) {
360: int i = 1;
361: int j = 0;
362: int len = c.length;
363: if (c[0] == '\0') { // even length
364: byte[] bytes = new byte[(len - 1) * 2];
365: for (; i < len; i++) {
366: char ch = c[i];
367: bytes[j++] = (byte) ((ch >> 8) & 255);
368: bytes[j++] = (byte) (ch & 255);
369: }
370: return bytes;
371: } else { // odd length
372: byte[] bytes = new byte[(len - 1) * 2 - 1];
373: for (; i < len - 1; i++) {
374: char ch = c[i];
375: bytes[j++] = (byte) ((ch >> 8) & 255);
376: bytes[j++] = (byte) (ch & 255);
377: }
378: bytes[j++] = (byte) ((c[i] >> 8) % 255);
379: return bytes;
380: }
381: }
382:
383: public static String unparseNode(SimpleNode node) {
384: StringBuffer sbuf = new StringBuffer();
385: node.accept(new org.pnuts.lang.UnparseVisitor(sbuf), null);
386: return sbuf.toString();
387: }
388:
389: public static void setPackage(String pkg, SimpleNode ss) {
390: SimpleNode el = new SimpleNode(
391: PnutsParserTreeConstants.JJTEXPRESSIONLIST);
392: ss.jjtAddChild(el, ss.jjtGetNumChildren());
393: el.jjtSetParent(ss);
394:
395: SimpleNode an = new SimpleNode(
396: PnutsParserTreeConstants.JJTAPPLICATIONNODE);
397: el.jjtAddChild(an, 0);
398: an.jjtSetParent(el);
399:
400: SimpleNode in = new SimpleNode(
401: PnutsParserTreeConstants.JJTIDNODE);
402: in.str = "package".intern();
403:
404: an.jjtAddChild(in, 0);
405: in.jjtSetParent(an);
406:
407: SimpleNode le = new SimpleNode(
408: PnutsParserTreeConstants.JJTLISTELEMENTS);
409: an.jjtAddChild(le, 1);
410:
411: SimpleNode sn;
412: if (pkg != null) {
413: sn = new SimpleNode(PnutsParserTreeConstants.JJTSTRINGNODE);
414: sn.str = pkg;
415: } else {
416: sn = new SimpleNode(PnutsParserTreeConstants.JJTNULLNODE);
417: }
418: le.jjtAddChild(sn, 0);
419: sn.jjtSetParent(le);
420: }
421:
422: public static void addImportNode(String def, SimpleNode ss) {
423: SimpleNode el = new SimpleNode(
424: PnutsParserTreeConstants.JJTEXPRESSIONLIST);
425: ss.jjtAddChild(el, ss.jjtGetNumChildren());
426: el.jjtSetParent(ss);
427:
428: SimpleNode im = new SimpleNode(
429: PnutsParserTreeConstants.JJTIMPORT);
430: el.jjtAddChild(im, 0);
431: im.jjtSetParent(el);
432:
433: SimpleNode sn = new SimpleNode(
434: PnutsParserTreeConstants.JJTSTRINGNODE);
435: im.jjtAddChild(sn, 0);
436: sn.jjtSetParent(im);
437: sn.str = def;
438: }
439:
440: public static void addFunction(SimpleNode fnode, SimpleNode ss) {
441: SimpleNode el = new SimpleNode(
442: PnutsParserTreeConstants.JJTEXPRESSIONLIST);
443: ss.jjtAddChild(el, ss.jjtGetNumChildren());
444: el.jjtSetParent(ss);
445:
446: el.jjtAddChild(fnode, 0);
447: fnode.jjtSetParent(el);
448: }
449:
450: static class ByteArray extends OutputStream {
451:
452: protected byte buf[];
453:
454: protected int count;
455:
456: public ByteArray() {
457: this (1024);
458: }
459:
460: public ByteArray(int size) {
461: if (size < 0) {
462: throw new IllegalArgumentException(
463: "Negative initial size: " + size);
464: }
465: buf = new byte[size];
466: }
467:
468: public void write(int b) {
469: int newcount = count + 1;
470: if (newcount > buf.length) {
471: byte newbuf[] = new byte[Math.max(buf.length << 1,
472: newcount)];
473: System.arraycopy(buf, 0, newbuf, 0, count);
474: buf = newbuf;
475: }
476: buf[count] = (byte) b;
477: count = newcount;
478: }
479:
480: public void write(byte b[], int off, int len) {
481: if ((off < 0) || (off > b.length) || (len < 0)
482: || ((off + len) > b.length) || ((off + len) < 0)) {
483: throw new IndexOutOfBoundsException();
484: } else if (len == 0) {
485: return;
486: }
487: int newcount = count + len;
488: if (newcount > buf.length) {
489: byte newbuf[] = new byte[Math.max(buf.length << 1,
490: newcount)];
491: System.arraycopy(buf, 0, newbuf, 0, count);
492: buf = newbuf;
493: }
494: System.arraycopy(b, off, buf, count, len);
495: count = newcount;
496: }
497:
498: public void writeTo(OutputStream out) throws IOException {
499: out.write(buf, 0, count);
500: }
501:
502: public void reset() {
503: count = 0;
504: }
505:
506: public byte toByteArray()[] {
507: byte newbuf[] = new byte[count];
508: System.arraycopy(buf, 0, newbuf, 0, count);
509: return newbuf;
510: }
511:
512: public int size() {
513: return count;
514: }
515:
516: public String toString() {
517: return new String(buf, 0, count);
518: }
519:
520: public String toString(String enc)
521: throws UnsupportedEncodingException {
522: return new String(buf, 0, count, enc);
523: }
524:
525: public void close() throws IOException {
526: }
527:
528: public byte[] getByteArray() {
529: return buf;
530: }
531: }
532: }
|