Skip to content
Browse files

Closer, ... can get otp to load first module [error_handler],

but that one has verifier error. Darn.
  • Loading branch information...
1 parent 577e73a commit 1ff3f2a2717e44ee33b67332dc21ac3fbdacd220 @krestenkrab krestenkrab committed
Showing with 2,265 additions and 220 deletions.
  1. +1 −1 .classpath
  2. BIN erjang-0.1.jar
  3. BIN lib/kilim-0.6-krab.jar
  4. +23 −0 src/main/java/erjang/EAtom.java
  5. +40 −6 src/main/java/erjang/EBinList.java
  6. +1 −1 src/main/java/erjang/EBinMatchState.java
  7. +32 −0 src/main/java/erjang/EBinary.java
  8. +12 −2 src/main/java/erjang/EBitString.java
  9. +31 −5 src/main/java/erjang/EBitStringBuilder.java
  10. +1 −0 src/main/java/erjang/ECons.java
  11. +4 −0 src/main/java/erjang/EDouble.java
  12. +105 −0 src/main/java/erjang/EExternal.java
  13. +49 −0 src/main/java/erjang/EFun.java
  14. +4 −0 src/main/java/erjang/EHandle.java
  15. +1,189 −0 src/main/java/erjang/EInputStream.java
  16. +4 −0 src/main/java/erjang/EInteger.java
  17. +7 −1 src/main/java/erjang/EInternalPID.java
  18. +38 −0 src/main/java/erjang/EList.java
  19. +20 −43 src/main/java/erjang/EModule.java
  20. +1 −1 src/main/java/erjang/EObject.java
  21. +15 −0 src/main/java/erjang/EPID.java
  22. +13 −0 src/main/java/erjang/EPort.java
  23. +15 −7 src/main/java/erjang/EProc.java
  24. +85 −45 src/main/java/erjang/ERT.java
  25. +16 −0 src/main/java/erjang/ERef.java
  26. +43 −8 src/main/java/erjang/EString.java
  27. +21 −9 src/main/java/erjang/ETask.java
  28. +55 −33 src/main/java/erjang/ETuple.java
  29. +1 −1 src/main/java/erjang/Erj.java
  30. +1 −1 src/main/java/erjang/ErlangError.java
  31. +7 −1 src/main/java/erjang/ErlangExitSignal.java
  32. +1 −1 src/main/java/erjang/ErlangUndefined.java
  33. +51 −0 src/main/java/erjang/IOListBuilder.java
  34. +2 −2 src/main/java/erjang/OTPMain.java
  35. +1 −1 src/main/java/erjang/beam/Compiler.java
  36. +13 −8 src/main/java/erjang/beam/CompilerVisitor.java
  37. +31 −1 src/main/java/erjang/beam/analysis/BeamTypeAnalysis.java
  38. +27 −0 src/main/java/erjang/driver/EDriverInstance.java
  39. +11 −2 src/main/java/erjang/driver/EDriverTask.java
  40. +13 −1 src/main/java/erjang/driver/EExecDriverTask.java
  41. +37 −18 src/main/java/erjang/driver/IO.java
  42. +195 −14 src/main/java/erjang/driver/efile/EFile.java
  43. +8 −4 src/main/java/erjang/driver/efile/Posix.java
  44. +16 −1 src/main/java/erjang/m/erlang/ErlBif.java
  45. +12 −2 src/main/java/erjang/m/erlang/ErlConvert.java
  46. +13 −0 src/main/java/erjang/m/erlang/ErlProc.java
View
2 .classpath
@@ -6,6 +6,6 @@
<classpathentry kind="lib" path="lib/OtpErlang.jar"/>
<classpathentry kind="lib" path="lib/antlr-3.2.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
- <classpathentry kind="lib" path="lib/kilim-0.6-krab.jar"/>
+ <classpathentry kind="lib" path="lib/kilim-0.6-krab.jar" sourcepath="/kilim/src"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
View
BIN erjang-0.1.jar
Binary file not shown.
View
BIN lib/kilim-0.6-krab.jar
Binary file not shown.
View
23 src/main/java/erjang/EAtom.java
@@ -18,6 +18,7 @@
package erjang;
+import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
@@ -25,6 +26,8 @@
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
+import erjang.driver.IO;
+
public class EAtom extends EObject implements CharSequence {
public EAtom testAtom() {
@@ -176,5 +179,25 @@ public String getName() {
public int compareTo(EAtom other) {
return value.compareTo(other.value);
}
+
+ /* (non-Javadoc)
+ * @see erjang.EObject#equalsExactly(erjang.EObject)
+ */
+ @Override
+ public boolean equalsExactly(EObject rhs) {
+ return rhs == this;
+ }
+
+ /**
+ * @param strbuf
+ * @return
+ */
+ public static EAtom intern(byte[] strbuf) {
+ return intern(new String(strbuf, IO.ISO_LATIN_1));
+ }
+
+ public static EAtom read(EInputStream ei) throws IOException {
+ return ei.read_atom();
+ }
}
View
46 src/main/java/erjang/EBinList.java
@@ -34,16 +34,16 @@
// synchronized access
private boolean shared;
- private EBinList(byte[] data, int off, int len, EObject tail) {
+ private EBinList(byte[] data, int off, int len, EObject tail, boolean shared) {
this.data = data;
this.off = off;
this.len = len;
this.tail = tail;
+ this.shared = shared;
if (len < 1 || off + len > data.length)
throw ERT.badarg();
- System.err.println("MADE: "+this);
}
public EBinList(byte value, EObject tail) {
@@ -51,9 +51,39 @@ public EBinList(byte value, EObject tail) {
this.off = 9;
this.len = 1;
this.tail = tail;
+ this.shared = false;
data[off] = value;
}
+
+ public ECons testNonEmptyList() {
+ return this;
+ }
+
+ public ESeq testWellformedList() {
+ if (tail.testWellformedList() != null) {
+ return this.seq();
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * @param header
+ * @param out
+ */
+ public EBinList(byte[] header, EObject out) {
+ this(header, 0, header.length, out, true);
+ }
+
+ /**
+ * @param header
+ * @param tail2
+ */
+ public EBinList(ByteBuffer buf, EObject tail) {
+ this(buf.array(), buf.arrayOffset()+buf.position(), buf.remaining(), tail, true);
+ }
@Override
public ECons cons(EObject h) {
@@ -75,7 +105,7 @@ public ECons cons(EObject h) {
}
res_data[--res_off] = (byte) sm.value;
- return new EBinList(res_data, res_off, res_len, tail);
+ return new EBinList(res_data, res_off, res_len, tail, res_data==data);
} else {
return new EPair(h, this);
@@ -98,8 +128,7 @@ public EObject tail() {
if (len == 1)
return tail;
- shared = true;
- return new EBinList(data, off + 1, len - 1, tail);
+ return new EBinList(data, off + 1, len - 1, tail, true);
}
@Override
@@ -152,7 +181,8 @@ public EObject head() {
public String toString() {
StringBuilder sb = new StringBuilder("[");
- for (int i = 0; i < len; i++) {
+ int max = Math.min(len, 40);
+ for (int i = 0; i < max; i++) {
if (i != 0) { sb.append(","); }
byte val = data[off+i];
if (val > ' ' && val < 127) {
@@ -163,6 +193,10 @@ public String toString() {
}
}
+ if (max!=len) {
+ sb.append("...");
+ }
+
if (!tail.isNil()) {
sb.append('|');
sb.append(tail);
View
2 src/main/java/erjang/EBinMatchState.java
@@ -35,7 +35,7 @@ public EBitString binary() {
public static EBinMatchState bs_start_match2(EObject obj) {
EBitString bs;
- if ((bs = obj.testBinString()) == null)
+ if ((bs = obj.testBitString()) == null)
return null;
return new EBinMatchState(bs);
}
View
32 src/main/java/erjang/EBinary.java
@@ -177,7 +177,39 @@ public void writeTo(ByteArrayOutputStream o) {
* @return
*/
public static EBinary make(ByteBuffer data) {
+ if (data == null || data.remaining()==0) return EMPTY;
return new EBinary(data.array(), data.arrayOffset()+data.position(), data.remaining());
}
+ /**
+ * @return
+ */
+ public ByteBuffer toByteBuffer() {
+ return ByteBuffer.wrap(this.data, this.bitOff/8, (int)(this.bits/8));
+ }
+
+ /**
+ * @param eInputStream
+ * @return
+ */
+ public static EBinary read(EInputStream eInputStream) {
+ throw new NotImplemented();
+ }
+
+ /**
+ * @return
+ */
+ public EInputStream getInputStream() {
+ int octets = (int) (bitCount() / 8);
+ if ((bitOff % 8) == 0) {
+ return new EInputStream(data, bitOff / 8, octets, EInputStream.DECODE_INT_LISTS_AS_STRINGS);
+ } else {
+ byte[] res = new byte[octets];
+ for (int i = 0; i < octets; i++) {
+ res[i] = (byte) octetAt(i);
+ }
+ return new EInputStream(res);
+ }
+ }
+
}
View
14 src/main/java/erjang/EBitString.java
@@ -42,7 +42,7 @@ public EBitString(byte[] data) {
this(data.clone(), 0, data.length * 8);
}
- public EBitString testBinString() {
+ public EBitString testBitString() {
return this;
}
@@ -374,10 +374,12 @@ public String toString() {
StringBuilder sb = new StringBuilder("<<");
int i = 0;
- for (; i < bits - 8; i += 8) {
+ long max = Math.min(bits-8, 20*8);
+ for (; i < max; i += 8) {
sb.append(0xff & intBitsAt(i, 8));
sb.append(',');
}
+ if (max != bits-8) { sb.append("...,"); i = (int) (bits-8); }
int lastBitLength = (int) (bits - i);
sb.append(0xff & intBitsAt(i, lastBitLength));
@@ -421,4 +423,12 @@ public boolean collectIOList(List<ByteBuffer> out) {
return true;
}
+ /**
+ * @param eInputStream
+ * @return
+ */
+ public static EBitString read(EInputStream eInputStream) {
+ throw new NotImplemented();
+ }
+
}
View
36 src/main/java/erjang/EBitStringBuilder.java
@@ -24,29 +24,55 @@
*/
public class EBitStringBuilder {
+ EBitString bs;
+ int bpos;
+ int extraBits;
+ byte[] data;
+
/**
* @param size
* @param flags
*/
public EBitStringBuilder(int size, int flags) {
- // TODO Auto-generated constructor stub
+ if (flags != 0) throw new NotImplemented("flags="+flags);
+ data = new byte[size];
+ bs = new EBitString(data, 0, size*8L);
}
/** return bitstring under construction */
public EBitString bitstring() {
- throw new NotImplemented();
+ return bs;
}
public void put_integer(EObject value, int flags) {
- throw new NotImplemented();
+ throw new NotImplemented("val="+value+";flags="+flags);
}
public void put_integer(EObject value, int size, int flags) {
- throw new NotImplemented();
+
+ if (extraBits != 0)
+ throw new NotImplemented();
+
+ if (size==8) {
+ ESmall sm = value.testSmall();
+ if (sm==null) { throw ERT.badarg(value); }
+ int val = sm.value;
+
+ if ((flags & 0x01) == 0x01) // unsigned
+ val &= 0xff;
+
+ data[bpos++] = (byte)val;
+ return;
+ }
+
+ throw new NotImplemented("val="+value+";size="+size+";flags="+flags);
}
public void put_string(EString str) {
- throw new NotImplemented();
+ if (extraBits != 0)
+ throw new NotImplemented();
+ System.arraycopy(str.data, str.off, data, bpos, str.length());
+ bpos += str.length();
}
public void put_bitstring(EBitString str, EAtom how, int flags) {
View
1 src/main/java/erjang/ECons.java
@@ -31,6 +31,7 @@ int cmp_order() {
@Override
int compare_same(EObject rhs) {
+ if (rhs.isNil()) return 1;
ECons other = rhs.testCons();
int cmp1 = head().compareTo(other.head());
if (cmp1 != 0)
View
4 src/main/java/erjang/EDouble.java
@@ -208,4 +208,8 @@ public ENumber add(int rhs, boolean guard) {
return ERT.box(value + rhs);
}
+ public static EDouble read(EInputStream ei) {
+ throw new NotImplemented();
+ }
+
}
View
105 src/main/java/erjang/EExternal.java
@@ -0,0 +1,105 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2000-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+package erjang;
+
+/**
+ * Provides a collection of constants used when encoding and decoding Erlang
+ * terms.
+ */
+public class EExternal {
+ // no constructor
+ private EExternal() {
+ }
+
+ /** The tag used for small integers */
+ public static final int smallIntTag = 97;
+
+ /** The tag used for integers */
+ public static final int intTag = 98;
+
+ /** The tag used for floating point numbers */
+ public static final int floatTag = 99;
+ public static final int newFloatTag = 70;
+
+ /** The tag used for atoms */
+ public static final int atomTag = 100;
+
+ /** The tag used for old stype references */
+ public static final int refTag = 101;
+
+ /** The tag used for ports */
+ public static final int portTag = 102;
+
+ /** The tag used for PIDs */
+ public static final int pidTag = 103;
+
+ /** The tag used for small tuples */
+ public static final int smallTupleTag = 104;
+
+ /** The tag used for large tuples */
+ public static final int largeTupleTag = 105;
+
+ /** The tag used for empty lists */
+ public static final int nilTag = 106;
+
+ /** The tag used for strings and lists of small integers */
+ public static final int stringTag = 107;
+
+ /** The tag used for non-empty lists */
+ public static final int listTag = 108;
+
+ /** The tag used for binaries */
+ public static final int binTag = 109;
+
+ /** The tag used for bitstrs */
+ public static final int bitBinTag = 77;
+
+ /** The tag used for small bignums */
+ public static final int smallBigTag = 110;
+
+ /** The tag used for large bignums */
+ public static final int largeBigTag = 111;
+
+ /** The tag used for old new Funs */
+ public static final int newFunTag = 112;
+
+ /** The tag used for external Funs (M:F/A) */
+ public static final int externalFunTag = 113;
+
+ /** The tag used for new style references */
+ public static final int newRefTag = 114;
+
+ /** The tag used for old Funs */
+ public static final int funTag = 117;
+
+ /** The tag used for compressed terms */
+ public static final int compressedTag = 80;
+
+ /** The version number used to mark serialized Erlang terms */
+ public static final int versionTag = 131;
+
+ /** The largest value that can be encoded as an integer */
+ public static final int erlMax = (1 << 27) - 1;
+
+ /** The smallest value that can be encoded as an integer */
+ public static final int erlMin = -(1 << 27);
+
+ /** The longest allowed Erlang atom */
+ public static final int maxAtomLength = 255;
+}
View
49 src/main/java/erjang/EFun.java
@@ -437,4 +437,53 @@ public static void ensure(int arity) {
get_fun_class(arity);
}
+ /**
+ * Create external function
+ *
+ * @param module
+ * @param function
+ * @param arity
+ * @return
+ */
+ public static EFun make(EAtom module, EAtom function, int arity) {
+ throw new NotImplemented();
+ }
+
+ /**
+ * @param pid
+ * @param module
+ * @param index
+ * @param uniq
+ * @param freeVars
+ * @return
+ */
+ public static EFun make(EPID pid, EAtom module, long index, long uniq,
+ EObject[] freeVars) {
+ throw new NotImplemented();
+ }
+
+ /**
+ * @param pid
+ * @param module
+ * @param arity
+ * @param md5
+ * @param index
+ * @param oldIndex
+ * @param uniq
+ * @param freeVars
+ * @return
+ */
+ public static EFun make(EPID pid, EAtom module, int arity, byte[] md5,
+ int index, long oldIndex, long uniq, EObject[] freeVars) {
+ throw new NotImplemented();
+ }
+
+ /**
+ * @param eInputStream
+ * @return
+ */
+ public static EFun read(EInputStream eInputStream) {
+ throw new NotImplemented();
+ }
+
}
View
4 src/main/java/erjang/EHandle.java
@@ -46,6 +46,10 @@ public void send(EObject msg) throws Pausable {
task().mbox_send(msg);
}
+ public void sendb(EObject msg) {
+ task().mbox().putb(msg);
+ }
+
/**
* @param self
* @param result
View
1,189 src/main/java/erjang/EInputStream.java
@@ -0,0 +1,1189 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2000-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/**
+ * This is derived from com.ericsson.otp.erlang.OtpInputStream
+ */
+package erjang;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigDecimal;
+
+import erjang.driver.IO;
+
+/**
+ * Provides a stream for decoding Erlang terms from external format.
+ *
+ * <p>
+ * Note that this class is not synchronized, if you need synchronization you
+ * must provide it yourself.
+ */
+public class EInputStream extends ByteArrayInputStream {
+
+ public static int DECODE_INT_LISTS_AS_STRINGS = 1;
+
+ private final int flags;
+
+ /**
+ * @param buf
+ */
+ public EInputStream(final byte[] buf) {
+ this(buf, 0);
+ }
+
+ /**
+ * Create a stream from a buffer containing encoded Erlang terms.
+ *
+ * @param flags
+ */
+ public EInputStream(final byte[] buf, final int flags) {
+ super(buf);
+ this.flags = flags;
+ }
+
+ /**
+ * Create a stream from a buffer containing encoded Erlang terms at the
+ * given offset and length.
+ *
+ * @param flags
+ */
+ public EInputStream(final byte[] buf, final int offset, final int length,
+ final int flags) {
+ super(buf, offset, length);
+ this.flags = flags;
+ }
+
+ /**
+ * Get the current position in the stream.
+ *
+ * @return the current position in the stream.
+ */
+ public int getPos() {
+ return super.pos;
+ }
+
+ /**
+ * Set the current position in the stream.
+ *
+ * @param pos
+ * the position to move to in the stream. If pos indicates a
+ * position beyond the end of the stream, the position is move to
+ * the end of the stream instead. If pos is negative, the
+ * position is moved to the beginning of the stream instead.
+ *
+ * @return the previous position in the stream.
+ */
+ public int setPos(int pos) {
+ final int oldpos = super.pos;
+
+ if (pos > super.count) {
+ pos = super.count;
+ } else if (pos < 0) {
+ pos = 0;
+ }
+
+ super.pos = pos;
+
+ return oldpos;
+ }
+
+ /**
+ * Read an array of bytes from the stream. The method reads at most
+ * buf.length bytes from the input stream.
+ *
+ * @return the number of bytes read.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public int readN(final byte[] buf) throws IOException {
+ return this.readN(buf, 0, buf.length);
+ }
+
+ /**
+ * Read an array of bytes from the stream. The method reads at most len
+ * bytes from the input stream into offset off of the buffer.
+ *
+ * @return the number of bytes read.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public int readN(final byte[] buf, final int off, final int len)
+ throws IOException {
+ if (len == 0 && available() == 0) {
+ return 0;
+ }
+ final int i = super.read(buf, off, len);
+ if (i < 0) {
+ throw new IOException("Cannot read from input stream");
+ }
+ return i;
+ }
+
+ /**
+ * Alias for peek1()
+ */
+ public int peek() throws IOException {
+ return peek1();
+ }
+
+ /**
+ * Look ahead one position in the stream without consuming the byte found
+ * there.
+ *
+ * @return the next byte in the stream, as an integer.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public int peek1() throws IOException {
+ int i;
+ try {
+ i = super.buf[super.pos];
+ if (i < 0) {
+ i += 256;
+ }
+
+ return i;
+ } catch (final Exception e) {
+ throw new IOException("Cannot read from input stream");
+ }
+ }
+
+ public int peek1skip_version() throws IOException {
+ int i = peek1();
+ if (i == EExternal.versionTag) {
+ read1();
+ i = peek1();
+ }
+ return i;
+ }
+
+ /**
+ * Read a one byte integer from the stream.
+ *
+ * @return the byte read, as an integer.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public int read1() throws IOException {
+ int i;
+ i = super.read();
+
+ if (i < 0) {
+ throw new IOException("Cannot read from input stream");
+ }
+
+ return i;
+ }
+
+ public int read1skip_version() throws IOException {
+ int tag = read1();
+ if (tag == EExternal.versionTag) {
+ tag = read1();
+ }
+ return tag;
+ }
+
+ /**
+ * Read a two byte big endian integer from the stream.
+ *
+ * @return the bytes read, converted from big endian to an integer.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public int read2BE() throws IOException {
+ final byte[] b = new byte[2];
+ try {
+ super.read(b);
+ } catch (final IOException e) {
+ throw new IOException("Cannot read from input stream");
+ }
+ ;
+ return (b[0] << 8 & 0xff00) + (b[1] & 0xff);
+ }
+
+ /**
+ * Read a four byte big endian integer from the stream.
+ *
+ * @return the bytes read, converted from big endian to an integer.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public int read4BE() throws IOException {
+ final byte[] b = new byte[4];
+ try {
+ super.read(b);
+ } catch (final IOException e) {
+ throw new IOException("Cannot read from input stream");
+ }
+ ;
+ return (b[0] << 24 & 0xff000000) + (b[1] << 16 & 0xff0000)
+ + (b[2] << 8 & 0xff00) + (b[3] & 0xff);
+ }
+
+ /**
+ * Read a two byte little endian integer from the stream.
+ *
+ * @return the bytes read, converted from little endian to an integer.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public int read2LE() throws IOException {
+ final byte[] b = new byte[2];
+ try {
+ super.read(b);
+ } catch (final IOException e) {
+ throw new IOException("Cannot read from input stream");
+ }
+ ;
+ return (b[1] << 8 & 0xff00) + (b[0] & 0xff);
+ }
+
+ /**
+ * Read a four byte little endian integer from the stream.
+ *
+ * @return the bytes read, converted from little endian to an integer.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public int read4LE() throws IOException {
+ final byte[] b = new byte[4];
+ try {
+ super.read(b);
+ } catch (final IOException e) {
+ throw new IOException("Cannot read from input stream");
+ }
+ ;
+ return (b[3] << 24 & 0xff000000) + (b[2] << 16 & 0xff0000)
+ + (b[1] << 8 & 0xff00) + (b[0] & 0xff);
+ }
+
+ /**
+ * Read a little endian integer from the stream.
+ *
+ * @param n
+ * the number of bytes to read
+ *
+ * @return the bytes read, converted from little endian to an integer.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public long readLE(int n) throws IOException {
+ final byte[] b = new byte[n];
+ try {
+ super.read(b);
+ } catch (final IOException e) {
+ throw new IOException("Cannot read from input stream");
+ }
+ ;
+ long v = 0;
+ while (n-- > 0) {
+ v = v << 8 | (long) b[n] & 0xff;
+ }
+ return v;
+ }
+
+ /**
+ * Read a bigendian integer from the stream.
+ *
+ * @param n
+ * the number of bytes to read
+ *
+ * @return the bytes read, converted from big endian to an integer.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public long readBE(final int n) throws IOException {
+ final byte[] b = new byte[n];
+ try {
+ super.read(b);
+ } catch (final IOException e) {
+ throw new IOException("Cannot read from input stream");
+ }
+ ;
+ long v = 0;
+ for (int i = 0; i < n; i++) {
+ v = v << 8 | (long) b[i] & 0xff;
+ }
+ return v;
+ }
+
+ /**
+ * Read an Erlang atom from the stream and interpret the value as a boolean.
+ *
+ * @return true if the atom at the current position in the stream contains
+ * the value 'true' (ignoring case), false otherwise.
+ *
+ * @exception IOException
+ * if the next term in the stream is not an atom.
+ */
+ public boolean read_boolean() throws IOException {
+ return read_atom() == ERT.TRUE;
+ }
+
+ /**
+ * Read an Erlang atom from the stream.
+ *
+ * @return a String containing the value of the atom.
+ *
+ * @exception IOException
+ * if the next term in the stream is not an atom.
+ */
+ public EAtom read_atom() throws IOException {
+ int tag;
+ int len;
+ byte[] strbuf;
+ String atom;
+
+ tag = read1skip_version();
+
+ if (tag != EExternal.atomTag) {
+ throw new IOException("wrong tag encountered, expected "
+ + EExternal.atomTag + ", got " + tag);
+ }
+
+ len = read2BE();
+
+ strbuf = new byte[len];
+ this.readN(strbuf);
+ atom = new String(strbuf, IO.ISO_LATIN_1);
+
+ if (atom.length() > EExternal.maxAtomLength) {
+ atom = atom.substring(0, EExternal.maxAtomLength);
+ }
+
+ return EAtom.intern(atom);
+ }
+
+ /**
+ * Read an Erlang binary from the stream.
+ *
+ * @return a byte array containing the value of the binary.
+ *
+ * @exception IOException
+ * if the next term in the stream is not a binary.
+ */
+ public byte[] read_binary() throws IOException {
+ int tag;
+ int len;
+ byte[] bin;
+
+ tag = read1skip_version();
+
+ if (tag != EExternal.binTag) {
+ throw new IOException("Wrong tag encountered, expected "
+ + EExternal.binTag + ", got " + tag);
+ }
+
+ len = read4BE();
+
+ bin = new byte[len];
+ this.readN(bin);
+
+ return bin;
+ }
+
+ /**
+ * Read an Erlang bitstr from the stream.
+ *
+ * @param pad_bits
+ * an int array whose first element will be set to the number of
+ * pad bits in the last byte.
+ *
+ * @return a byte array containing the value of the bitstr.
+ *
+ * @exception IOException
+ * if the next term in the stream is not a bitstr.
+ */
+ public byte[] read_bitstr(final int pad_bits[]) throws IOException {
+ int tag;
+ int len;
+ byte[] bin;
+
+ tag = read1skip_version();
+
+ if (tag != EExternal.bitBinTag) {
+ throw new IOException("Wrong tag encountered, expected "
+ + EExternal.bitBinTag + ", got " + tag);
+ }
+
+ len = read4BE();
+ bin = new byte[len];
+ final int tail_bits = read1();
+ if (tail_bits < 0 || 7 < tail_bits) {
+ throw new IOException("Wrong tail bit count in bitstr: "
+ + tail_bits);
+ }
+ if (len == 0 && tail_bits != 0) {
+ throw new IOException("Length 0 on bitstr with tail bit count: "
+ + tail_bits);
+ }
+ this.readN(bin);
+
+ pad_bits[0] = 8 - tail_bits;
+ return bin;
+ }
+
+ /**
+ * Read an Erlang float from the stream.
+ *
+ * @return the float value.
+ *
+ * @exception IOException
+ * if the next term in the stream is not a float.
+ */
+ public float read_float() throws IOException {
+ final double d = read_double();
+ return (float) d;
+ }
+
+ /**
+ * Read an Erlang float from the stream.
+ *
+ * @return the float value, as a double.
+ *
+ * @exception IOException
+ * if the next term in the stream is not a float.
+ */
+ public double read_double() throws IOException {
+ int tag;
+
+ // parse the stream
+ tag = read1skip_version();
+
+ switch (tag) {
+ case EExternal.newFloatTag: {
+ return Double.longBitsToDouble(readBE(8));
+ }
+ case EExternal.floatTag: {
+ BigDecimal val;
+ int epos;
+ int exp;
+ final byte[] strbuf = new byte[31];
+ String str;
+
+ // get the string
+ this.readN(strbuf);
+ str = new String(strbuf, IO.ISO_LATIN_1);
+
+ // find the exponent prefix 'e' in the string
+ epos = str.indexOf('e', 0);
+
+ if (epos < 0) {
+ throw new IOException("Invalid float format: '" + str + "'");
+ }
+
+ // remove the sign from the exponent, if positive
+ String estr = str.substring(epos + 1).trim();
+
+ if (estr.substring(0, 1).equals("+")) {
+ estr = estr.substring(1);
+ }
+
+ // now put the mantissa and exponent together
+ exp = Integer.valueOf(estr).intValue();
+ val = new BigDecimal(str.substring(0, epos)).movePointRight(exp);
+
+ return val.doubleValue();
+ }
+ default:
+ throw new IOException("Wrong tag encountered, expected "
+ + EExternal.newFloatTag + ", got " + tag);
+ }
+ }
+
+ /**
+ * Read one byte from the stream.
+ *
+ * @return the byte read.
+ *
+ * @exception IOException
+ * if the next byte cannot be read.
+ */
+ public byte read_byte() throws IOException {
+ final long l = this.read_long(false);
+ final byte i = (byte) l;
+
+ if (l != i) {
+ throw new IOException("Value does not fit in byte: " + l);
+ }
+
+ return i;
+ }
+
+ /**
+ * Read a character from the stream.
+ *
+ * @return the character value.
+ *
+ * @exception IOException
+ * if the next term in the stream is not an integer that can
+ * be represented as a char.
+ */
+ public char read_char() throws IOException {
+ final long l = this.read_long(true);
+ final char i = (char) l;
+
+ if (l != (i & 0xffffL)) {
+ throw new IOException("Value does not fit in char: " + l);
+ }
+
+ return i;
+ }
+
+ /**
+ * Read an unsigned integer from the stream.
+ *
+ * @return the integer value.
+ *
+ * @exception IOException
+ * if the next term in the stream can not be represented as a
+ * positive integer.
+ */
+ public int read_uint() throws IOException {
+ final long l = this.read_long(true);
+ final int i = (int) l;
+
+ if (l != (i & 0xFFFFffffL)) {
+ throw new IOException("Value does not fit in uint: " + l);
+ }
+
+ return i;
+ }
+
+ /**
+ * Read an integer from the stream.
+ *
+ * @return the integer value.
+ *
+ * @exception IOException
+ * if the next term in the stream can not be represented as
+ * an integer.
+ */
+ public int read_int() throws IOException {
+ final long l = this.read_long(false);
+ final int i = (int) l;
+
+ if (l != i) {
+ throw new IOException("Value does not fit in int: " + l);
+ }
+
+ return i;
+ }
+
+ /**
+ * Read an unsigned short from the stream.
+ *
+ * @return the short value.
+ *
+ * @exception IOException
+ * if the next term in the stream can not be represented as a
+ * positive short.
+ */
+ public short read_ushort() throws IOException {
+ final long l = this.read_long(true);
+ final short i = (short) l;
+
+ if (l != (i & 0xffffL)) {
+ throw new IOException("Value does not fit in ushort: " + l);
+ }
+
+ return i;
+ }
+
+ /**
+ * Read a short from the stream.
+ *
+ * @return the short value.
+ *
+ * @exception IOException
+ * if the next term in the stream can not be represented as a
+ * short.
+ */
+ public short read_short() throws IOException {
+ final long l = this.read_long(false);
+ final short i = (short) l;
+
+ if (l != i) {
+ throw new IOException("Value does not fit in short: " + l);
+ }
+
+ return i;
+ }
+
+ /**
+ * Read an unsigned long from the stream.
+ *
+ * @return the long value.
+ *
+ * @exception IOException
+ * if the next term in the stream can not be represented as a
+ * positive long.
+ */
+ public long read_ulong() throws IOException {
+ return this.read_long(true);
+ }
+
+ /**
+ * Read a long from the stream.
+ *
+ * @return the long value.
+ *
+ * @exception IOException
+ * if the next term in the stream can not be represented as a
+ * long.
+ */
+ public long read_long() throws IOException {
+ return this.read_long(false);
+ }
+
+ public long read_long(final boolean unsigned) throws IOException {
+ final byte[] b = read_integer_byte_array();
+ return EInputStream.byte_array_to_long(b, unsigned);
+ }
+
+ /**
+ * Read an integer from the stream.
+ *
+ * @return the value as a big endian 2's complement byte array.
+ *
+ * @exception IOException
+ * if the next term in the stream is not an integer.
+ */
+ public byte[] read_integer_byte_array() throws IOException {
+ int tag;
+ byte[] nb;
+
+ tag = read1skip_version();
+
+ switch (tag) {
+ case EExternal.smallIntTag:
+ nb = new byte[2];
+ nb[0] = 0;
+ nb[1] = (byte) read1();
+ break;
+
+ case EExternal.intTag:
+ nb = new byte[4];
+ if (this.readN(nb) != 4) { // Big endian
+ throw new IOException("Cannot read from intput stream");
+ }
+ break;
+
+ case EExternal.smallBigTag:
+ case EExternal.largeBigTag:
+ int arity;
+ int sign;
+ if (tag == EExternal.smallBigTag) {
+ arity = read1();
+ sign = read1();
+ } else {
+ arity = read4BE();
+ sign = read1();
+ if (arity + 1 < 0) {
+ throw new IOException(
+ "Value of largeBig does not fit in BigInteger, arity "
+ + arity + " sign " + sign);
+ }
+ }
+ nb = new byte[arity + 1];
+ // Value is read as little endian. The big end is augumented
+ // with one zero byte to make the value 2's complement positive.
+ if (this.readN(nb, 0, arity) != arity) {
+ throw new IOException("Cannot read from intput stream");
+ }
+ // Reverse the array to make it big endian.
+ for (int i = 0, j = nb.length; i < j--; i++) {
+ // Swap [i] with [j]
+ final byte b = nb[i];
+ nb[i] = nb[j];
+ nb[j] = b;
+ }
+ if (sign != 0) {
+ // 2's complement negate the big endian value in the array
+ int c = 1; // Carry
+ for (int j = nb.length; j-- > 0;) {
+ c = (~nb[j] & 0xFF) + c;
+ nb[j] = (byte) c;
+ c >>= 8;
+ }
+ }
+ break;
+
+ default:
+ throw new IOException("Not valid integer tag: " + tag);
+ }
+
+ return nb;
+ }
+
+ public static long byte_array_to_long(final byte[] b, final boolean unsigned)
+ throws IOException {
+ long v;
+ switch (b.length) {
+ case 0:
+ v = 0;
+ break;
+ case 2:
+ v = ((b[0] & 0xFF) << 8) + (b[1] & 0xFF);
+ v = (short) v; // Sign extend
+ if (v < 0 && unsigned) {
+ throw new IOException("Value not unsigned: " + v);
+ }
+ break;
+ case 4:
+ v = ((b[0] & 0xFF) << 24) + ((b[1] & 0xFF) << 16)
+ + ((b[2] & 0xFF) << 8) + (b[3] & 0xFF);
+ v = (int) v; // Sign extend
+ if (v < 0 && unsigned) {
+ throw new IOException("Value not unsigned: " + v);
+ }
+ break;
+ default:
+ int i = 0;
+ final byte c = b[i];
+ // Skip non-essential leading bytes
+ if (unsigned) {
+ if (c < 0) {
+ throw new IOException("Value not unsigned: " + b);
+ }
+ while (b[i] == 0) {
+ i++; // Skip leading zero sign bytes
+ }
+ } else {
+ if (c == 0 || c == -1) { // Leading sign byte
+ i = 1;
+ // Skip all leading sign bytes
+ while (i < b.length && b[i] == c) {
+ i++;
+ }
+ if (i < b.length) {
+ // Check first non-sign byte to see if its sign
+ // matches the whole number's sign. If not one more
+ // byte is needed to represent the value.
+ if (((c ^ b[i]) & 0x80) != 0) {
+ i--;
+ }
+ }
+ }
+ }
+ if (b.length - i > 8) {
+ // More than 64 bits of value
+ throw new IOException("Value does not fit in long: " + b);
+ }
+ // Convert the necessary bytes
+ for (v = c < 0 ? -1 : 0; i < b.length; i++) {
+ v = v << 8 | b[i] & 0xFF;
+ }
+ }
+ return v;
+ }
+
+ /**
+ * Read a list header from the stream.
+ *
+ * @return the arity of the list.
+ *
+ * @exception IOException
+ * if the next term in the stream is not a list.
+ */
+ public int read_list_head() throws IOException {
+ int arity = 0;
+ final int tag = read1skip_version();
+
+ switch (tag) {
+ case EExternal.nilTag:
+ arity = 0;
+ break;
+
+ case EExternal.stringTag:
+ arity = read2BE();
+ break;
+
+ case EExternal.listTag:
+ arity = read4BE();
+ break;
+
+ default:
+ throw new IOException("Not valid list tag: " + tag);
+ }
+
+ return arity;
+ }
+
+ /**
+ * Read a tuple header from the stream.
+ *
+ * @return the arity of the tuple.
+ *
+ * @exception IOException
+ * if the next term in the stream is not a tuple.
+ */
+ public int read_tuple_head() throws IOException {
+ int arity = 0;
+ final int tag = read1skip_version();
+
+ // decode the tuple header and get arity
+ switch (tag) {
+ case EExternal.smallTupleTag:
+ arity = read1();
+ break;
+
+ case EExternal.largeTupleTag:
+ arity = read4BE();
+ break;
+
+ default:
+ throw new IOException("Not valid tuple tag: " + tag);
+ }
+
+ return arity;
+ }
+
+ /**
+ * Read an empty list from the stream.
+ *
+ * @return zero (the arity of the list).
+ *
+ * @exception IOException
+ * if the next term in the stream is not an empty list.
+ */
+ public int read_nil() throws IOException {
+ int arity = 0;
+ final int tag = read1skip_version();
+
+ switch (tag) {
+ case EExternal.nilTag:
+ arity = 0;
+ break;
+
+ default:
+ throw new IOException("Not valid nil tag: " + tag);
+ }
+
+ return arity;
+ }
+
+ /**
+ * Read an Erlang PID from the stream.
+ *
+ * @return the value of the PID.
+ *
+ * @exception IOException
+ * if the next term in the stream is not an Erlang PID.
+ */
+ public EPID read_pid() throws IOException {
+ EAtom node;
+ int id;
+ int serial;
+ int creation;
+ int tag;
+
+ tag = read1skip_version();
+
+ if (tag != EExternal.pidTag) {
+ throw new IOException("Wrong tag encountered, expected "
+ + EExternal.pidTag + ", got " + tag);
+ }
+
+ node = read_atom();
+ id = read4BE() & 0x7fff; // 15 bits
+ serial = read4BE() & 0x1fff; // 13 bits
+ creation = read1() & 0x03; // 2 bits
+
+ return EPID.make(node, id, serial, creation);
+ }
+
+ /**
+ * Read an Erlang port from the stream.
+ *
+ * @return the value of the port.
+ *
+ * @exception IOException
+ * if the next term in the stream is not an Erlang port.
+ */
+ public EPort read_port() throws IOException {
+ EAtom node;
+ int id;
+ int creation;
+ int tag;
+
+ tag = read1skip_version();
+
+ if (tag != EExternal.portTag) {
+ throw new IOException("Wrong tag encountered, expected "
+ + EExternal.portTag + ", got " + tag);
+ }
+
+ node = read_atom();
+ id = read4BE() & 0xfffffff; // 28 bits
+ creation = read1() & 0x03; // 2 bits
+
+ return EPort.make(node, id, creation);
+ }
+
+ /**
+ * Read an Erlang reference from the stream.
+ *
+ * @return the value of the reference
+ *
+ * @exception IOException
+ * if the next term in the stream is not an Erlang reference.
+ */
+ public ERef read_ref() throws IOException {
+ EAtom node;
+ int id;
+ int creation;
+ int tag;
+
+ tag = read1skip_version();
+
+ switch (tag) {
+ case EExternal.refTag:
+ node = read_atom();
+ id = read4BE() & 0x3ffff; // 18 bits
+ creation = read1() & 0x03; // 2 bits
+ return new ERef(node, id, creation);
+
+ case EExternal.newRefTag:
+ final int arity = read2BE();
+ node = read_atom();
+ creation = read1() & 0x03; // 2 bits
+
+ final int[] ids = new int[arity];
+ for (int i = 0; i < arity; i++) {
+ ids[i] = read4BE();
+ }
+ ids[0] &= 0x3ffff; // first id gets truncated to 18 bits
+ return new ERef(node, ids, creation);
+
+ default:
+ throw new IOException("Wrong tag encountered, expected ref, got "
+ + tag);
+ }
+ }
+
+ public EFun read_fun() throws IOException {
+ final int tag = read1skip_version();
+ if (tag == EExternal.funTag) {
+ final int nFreeVars = read4BE();
+ final EPID pid = read_pid();
+ final EAtom module = read_atom();
+ final long index = read_long();
+ final long uniq = read_long();
+ final EObject[] freeVars = new EObject[nFreeVars];
+ for (int i = 0; i < nFreeVars; ++i) {
+ freeVars[i] = read_any();
+ }
+ return EFun.make(pid, module, index, uniq, freeVars);
+ } else if (tag == EExternal.newFunTag) {
+ final int n = read4BE();
+ final int arity = read1();
+ final byte[] md5 = new byte[16];
+ readN(md5);
+ final int index = read4BE();
+ final int nFreeVars = read4BE();
+ final EAtom module = read_atom();
+ final long oldIndex = read_long();
+ final long uniq = read_long();
+ final EPID pid = read_pid();
+ final EObject[] freeVars = new EObject[nFreeVars];
+ for (int i = 0; i < nFreeVars; ++i) {
+ freeVars[i] = read_any();
+ }
+ return EFun.make(pid, module, arity, md5, index, oldIndex, uniq,
+ freeVars);
+ } else {
+ throw new IOException("Wrong tag encountered, expected fun, got "
+ + tag);
+ }
+ }
+
+ public EFun read_external_fun() throws IOException {
+ final int tag = read1skip_version();
+ if (tag != EExternal.externalFunTag) {
+ throw new IOException(
+ "Wrong tag encountered, expected external fun, got " + tag);
+ }
+ final EAtom module = read_atom();
+ final EAtom function = read_atom();
+ final int arity = (int) read_long();
+ return EFun.make(module, function, arity);
+ }
+
+ /**
+ * Read a string from the stream.
+ *
+ * @return the value of the string.
+ *
+ * @exception IOException
+ * if the next term in the stream is not a string.
+ */
+ public ESeq read_string() throws IOException {
+ int tag;
+ int len;
+ byte[] strbuf;
+ int[] intbuf;
+ tag = read1skip_version();
+ switch (tag) {
+ case EExternal.stringTag:
+ len = read2BE();
+ strbuf = new byte[len];
+ this.readN(strbuf);
+ return EString.make(strbuf);
+ case EExternal.nilTag:
+ return ERT.NIL;
+ case EExternal.listTag: // List when unicode +
+ len = read4BE();
+ intbuf = new int[len];
+ boolean unicode = false;
+ for (int i = 0; i < len; i++) {
+ intbuf[i] = read_int();
+ unicode |= intbuf[i] > 0xff;
+ if (!EString.isValidCodePoint(intbuf[i])) {
+ throw new IOException("Invalid CodePoint: " + intbuf[i]);
+ }
+ }
+ read_nil();
+ return EList.make(intbuf);
+ default:
+ throw new IOException("Wrong tag encountered, expected "
+ + EExternal.stringTag + " or " + EExternal.listTag
+ + ", got " + tag);
+ }
+ }
+
+ /**
+ * Read a compressed term from the stream
+ *
+ * @return the resulting uncompressed term.
+ *
+ * @exception IOException
+ * if the next term in the stream is not a compressed term.
+ */
+ public EObject read_compressed() throws IOException {
+ final int tag = read1skip_version();
+
+ if (tag != EExternal.compressedTag) {
+ throw new IOException("Wrong tag encountered, expected "
+ + EExternal.compressedTag + ", got " + tag);
+ }
+
+ final int size = read4BE();
+ final byte[] buf = new byte[size];
+ final java.util.zip.InflaterInputStream is = new java.util.zip.InflaterInputStream(
+ this);
+ try {
+ final int dsize = is.read(buf, 0, size);
+ if (dsize != size) {
+ throw new IOException("Decompression gave " + dsize
+ + " bytes, not " + size);
+ }
+ } catch (final IOException e) {
+ throw new IOException("Cannot read from input stream");
+ }
+
+ final EInputStream ois = new EInputStream(buf, flags);
+ return ois.read_any();
+ }
+
+ /**
+ * Read an arbitrary Erlang term from the stream.
+ *
+ * @return the Erlang term.
+ *
+ * @exception IOException
+ * if the stream does not contain a known Erlang type at the
+ * next position.
+ */
+ public EObject read_any() throws IOException {
+ // calls one of the above functions, depending on o
+ final int tag = peek1skip_version();
+
+ switch (tag) {
+ case EExternal.smallIntTag:
+ case EExternal.intTag:
+ case EExternal.smallBigTag:
+ case EExternal.largeBigTag:
+ return EInteger.read(this);
+
+ case EExternal.atomTag:
+ return EAtom.read(this);
+
+ case EExternal.floatTag:
+ case EExternal.newFloatTag:
+ return EDouble.read(this);
+
+ case EExternal.refTag:
+ case EExternal.newRefTag:
+ return ERef.read(this);
+
+ case EExternal.portTag:
+ return EPort.read(this);
+
+ case EExternal.pidTag:
+ return EPID.read(this);
+
+ case EExternal.stringTag:
+ return EString.read(this);
+
+ case EExternal.listTag:
+ case EExternal.nilTag:
+ if ((flags & DECODE_INT_LISTS_AS_STRINGS) != 0) {
+ final int savePos = getPos();
+ try {
+ return EString.read(this);
+ } catch (final IOException e) {
+ }
+ setPos(savePos);
+ }
+ return EList.read(this);
+
+ case EExternal.smallTupleTag:
+ case EExternal.largeTupleTag:
+ return ETuple.read(this);
+
+ case EExternal.binTag:
+ return EBinary.read(this);
+
+ case EExternal.bitBinTag:
+ return EBitString.read(this);
+
+ case EExternal.compressedTag:
+ return read_compressed();
+
+ case EExternal.newFunTag:
+ case EExternal.funTag:
+ return EFun.read(this);
+
+ default:
+ throw new IOException("Uknown data type: " + tag);
+ }
+ }
+}
View
4 src/main/java/erjang/EInteger.java
@@ -40,4 +40,8 @@ public long longValue() {
return bigintValue().longValue();
}
+ public static EInteger read(EInputStream ei) {
+ throw new NotImplemented();
+ }
+
}
View
8 src/main/java/erjang/EInternalPID.java
@@ -114,5 +114,11 @@ public EObject process_info(EObject spec) {
return task.process_info(spec);
}
-
+ /* (non-Javadoc)
+ * @see erjang.EObject#equalsExactly(erjang.EObject)
+ */
+ @Override
+ public boolean equalsExactly(EObject rhs) {
+ return rhs==this;
+ }
}
View
38 src/main/java/erjang/EList.java
@@ -18,6 +18,8 @@
package erjang;
+import java.io.IOException;
+
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@@ -119,5 +121,41 @@ public static ESeq make(Object... messages) {
return result;
}
+ public static ESeq make(int... messages) {
+ ESeq result = ERT.NIL;
+ for (int i = messages.length-1; i >= 0; i--) {
+ result = result.cons(ERT.box( messages[i] ));
+ }
+ return result;
+ }
+
+ public static EObject read(EInputStream buf) throws IOException {
+ final int arity = buf.read_list_head();
+ EObject[] elems;
+ EObject tail;
+ if (arity > 0) {
+ elems = new EObject[arity];
+ for (int i = 0; i < arity; i++) {
+ elems[i] = buf.read_any();
+ }
+ /* discard the terminating nil (empty list) or read tail */
+ if (buf.peek1() == EExternal.nilTag) {
+ buf.read_nil();
+ tail = ERT.NIL;
+ } else {
+ tail = buf.read_any();
+ }
+
+ EObject res = tail;
+ for (int i = arity-1; i >= 0; i--) {
+ res = res.cons(elems[i]);
+ }
+
+ return res;
+ } else {
+ return ERT.NIL;
+ }
+ }
+
}
View
63 src/main/java/erjang/EModule.java
@@ -88,11 +88,11 @@ public EObject invoke(EProc proc, EObject[] args)
{
EFun found = null;
boolean has_loaded_module =
- EModule.get_module_info(fun.module).module != null;
+ EModule.get_module_info(fun.module).resident != null;
if (!has_loaded_module) {
try {
- ERT.load(fun.module);
+ ERT.load_module(fun.module);
has_loaded_module = true;
} catch (Throwable ex) {
System.out.println("unable to load module for "+fun);
@@ -154,7 +154,7 @@ public boolean exported() {
static class ModuleInfo {
private final EAtom name;
- private EModule module;
+ private EModule resident;
/**
* @param module
@@ -198,7 +198,7 @@ public void add_export(EModule definer, FunID fun, EFun value)
* @param eModule
*/
public void setModule(EModule eModule) {
- this.module = eModule;
+ this.resident = eModule;
}
/**
@@ -217,6 +217,13 @@ public boolean exports(FunID fun) {
return get_function_info(fun).exported();
}
+ /**
+ * @return
+ */
+ public boolean is_loaded() {
+ return resident != null;
+ }
+
}
boolean add_import(FunID fun, Field ref) throws Exception {
@@ -399,45 +406,6 @@ private void process_native_annotations(Class nat) throws Exception {
*/
public abstract String module_name();
- /**
- * @param mod
- * @param classData
- */
- @SuppressWarnings("unchecked")
- public static void load_module(EAtom mod, EBinary bin) {
-
- File dir = new File("out");
- ClassRepo repo = new DirClassRepo(dir);
-
- URL url;
- try {
- Compiler.compile(bin, repo);
- repo.close();
- url = dir.toURI().toURL();
- } catch (IOException e) {
- throw new ErlangError(e);
- }
-
- String internalName = erjang.beam.Compiler.moduleClassName(mod
- .getName());
- String java_name = internalName.replace('/', '.');
- EModuleLoader loader = new EModuleLoader(url);
- Class<? extends EModule> clazz;
- try {
- clazz = (Class<? extends EModule>) loader.loadClass(java_name);
- } catch (ClassNotFoundException e1) {
- throw new Error(e1);
- }
- EModule mi;
- try {
- mi = clazz.newInstance();
- } catch (Exception e) {
- throw new ErlangError(AM_BADARG, mod, bin);
- }
-
- // mi.read_annotations();
-
- }
public static EModule load_module(EAtom mod, URL url) {
String internalName = erjang.beam.Compiler.moduleClassName(mod
@@ -481,4 +449,13 @@ public static boolean function_exported(EAtom m, EAtom f, int a) {
return get_module_info(m).exports(fun);
}
+ /**
+ * @param m
+ * @return
+ */
+ public static boolean module_loaded(EAtom m) {
+ ModuleInfo mi = get_module_info(m);
+ return mi.is_loaded();
+ }
+
}
View
2 src/main/java/erjang/EObject.java
@@ -291,7 +291,7 @@ public EAtom ge(EObject o2) {
/**
* @return
*/
- public EBitString testBinString() {
+ public EBitString testBitString() {
return null;
}
View
15 src/main/java/erjang/EPID.java
@@ -57,4 +57,19 @@ int compare_same(EObject rhs) {
*/
public abstract EObject process_info(EObject spec);
+ public static EPID read(EInputStream ei) {
+ throw new NotImplemented();
+ }
+
+ /**
+ * @param node
+ * @param id
+ * @param serial
+ * @param creation
+ * @return
+ */
+ public static EPID make(EAtom node, int id, int serial, int creation) {
+ throw new NotImplemented();
+ }
+
}
View
13 src/main/java/erjang/EPort.java
@@ -72,4 +72,17 @@ public EPort testPort() {
* @return
*/
public abstract boolean isOpen();
+
+ public static EPort read(EInputStream ei) {
+ throw new NotImplemented();
+ }
+ /**
+ * @param node
+ * @param id
+ * @param creation
+ * @return
+ */
+ public static EPort make(EAtom node, int id, int creation) {
+ throw new NotImplemented();
+ }
}
View
22 src/main/java/erjang/EProc.java
@@ -42,7 +42,7 @@
private static final EAtom am_registered_name = EAtom.intern("registered_name");
public EFun tail;
- public EObject arg0, arg1, arg2, arg3, arg4, arg5, arg6;
+ public EObject arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
private EInternalPID self;
@@ -111,6 +111,8 @@ public EInternalPID self() {
private EAtom trap_exit = ERT.FALSE;
+ public int midx;
+
protected void link_failure(EHandle h) throws Pausable {
if (trap_exit == ERT.TRUE || h.testLocalHandle()==null) {
send_exit(h, ERT.am_noproc);
@@ -125,17 +127,17 @@ protected void process_incoming_exit(EHandle from, EObject reason) throws Pausab
if (trap_exit == ERT.TRUE) {
// we're trapping exits, so we in stead send an {'EXIT', from,
// reason} to self
- System.err.println("kill message");
- mbox_send(ETuple.make(ERT.EXIT, from, reason));
+ ETuple msg = ETuple.make(ERT.EXIT, from, reason);
+ System.err.println("kill message to self: "+msg);
+ mbox_send(msg);
} else {
- System.err.println("kill signal");
+ System.err.println("kill signal: " +reason);
// try to kill this thread
this.exit_reason = reason;
this.pstate = State.EXIT_SIG;
- this.kill(new ErlangExitSignal(reason));
}
}
-
+
// private Thread runner;
public EObject put(EObject key, EObject value) {
@@ -322,7 +324,13 @@ public EObject process_info(EObject spec) {
throw new NotImplemented();
}
-
+ /* (non-Javadoc)
+ * @see kilim.Task#toString()
+ */
+ @Override
+ public String toString() {
+ return self.toString() + super.toString();
+ }
}
class ETailMarker extends EObject {
View
130 src/main/java/erjang/ERT.java
@@ -175,16 +175,6 @@ public static EPID loopkup_pid(EString name) {
return res;
}
- /**
- * @param mod
- * @param bin
- */
- public static ETuple2 load_module(EAtom mod, EBinary bin) {
-
- EModule.load_module(mod, bin);
-
- return (ETuple2) ETuple.make(AM_MODULE, mod);
- }
public static ESmall box(int i) {
return new ESmall(i);
@@ -235,7 +225,7 @@ public static EDouble box(double doubleVal) {
static BigInteger INT_MIN_AS_BIG = BigInteger.valueOf(Integer.MIN_VALUE);
static BigInteger INT_MAX_AS_BIG = BigInteger.valueOf(Integer.MAX_VALUE);
- private static ENode localNode;
+ private static ENode localNode = new ENode();
/**
* @param add
@@ -288,6 +278,7 @@ public static EAtom guard(boolean bool) {
public static final ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0);
public static final EAtom am_infinity = EAtom.intern("infinity");
public static final EAtom am_noproc = EAtom.intern("noproc");
+ public static final EAtom am_error = EAtom.intern("error");
public static EBitStringBuilder bs_init(int size, int flags) {
return new EBitStringBuilder(size, flags);
@@ -331,9 +322,9 @@ public static EObject send(EProc proc, EObject pid, EObject msg)
p.send(msg);
return msg;
}
-
- EObject val = whereis(pid);
- if ((p = val.testHandle()) != null) {
+
+ p = register.get(pid);
+ if (p != null) {
p.send(msg);
return msg;
}
@@ -397,6 +388,23 @@ public static EObject apply(EProc proc, EObject mod, EObject fun)
// .invoke(proc, NIL.cons(arg1).toArray());
}
+ public static EObject apply$last(EProc proc, EObject arg2, EObject arg1, EObject arg0, EObject mod,
+ EObject fun) {
+ EAtom m = mod.testAtom();
+ EAtom f = fun.testAtom();
+
+ if (m == null || f == null)
+ throw ERT.badarg(mod, fun, arg0, arg1, arg2);
+
+ proc.arg0 = arg0;
+ proc.arg1 = arg1;
+ proc.arg2 = arg2;
+ proc.tail = EModule.resolve(new FunID(m, f, 3));
+ return EProc.TAIL_MARKER;
+
+ // .invoke(proc, NIL.cons(arg1).toArray());
+ }
+
static Map<EAtom, EHandle> register = new ConcurrentHashMap<EAtom, EHandle>();
/**
@@ -415,10 +423,10 @@ public static void register(EAtom aname, EHandle handle) {
public static EObject whereis(EObject regname) {
EObject result = register.get(regname);
if (result == null) {
- //System.out.println(regname + " => " + am_undefined);
+ // System.out.println(regname + " => " + am_undefined);
return am_undefined;
} else {
- //System.out.println(regname + " => " + result);
+ // System.out.println(regname + " => " + result);
return result;
}
}
@@ -448,6 +456,7 @@ public static EObject try_case_end(EObject val) {
}
static kilim.Scheduler scheduler = new kilim.Scheduler(4);
+ public static EAtom am_io = EAtom.intern("io");
public static void run(Task task) {
task.setScheduler(scheduler);
@@ -456,26 +465,68 @@ public static void run(Task task) {
/** peek mbox */
public static EObject receive_peek(EProc proc) {
- return proc.mbox.peek();
+ if (proc.midx == -1024) { proc.midx = 0; }
+ return proc.mbox.peek(proc.midx);
}
public static void remove_message(EProc proc) throws Pausable {
- proc.mbox.get();
+ proc.mbox.remove(proc.midx);
+ proc.midx = -1024;
+ }
+
+ public static boolean wait_timeout(EProc proc, EObject howlong)
+ throws Pausable {
+ if (proc.midx == -1024) {
+ if (howlong == am_infinity) {
+ proc.mbox.untilHasMessage();
+ return false;
+ } else {
+ EInteger ei;
+ if ((ei = howlong.testInteger()) == null)
+ throw badarg(howlong);
+
+ proc.mbox.untilHasMessage(ei.longValue());
+ return false;
+ }
+ } else {
+ if (howlong == am_infinity) {
+ proc.mbox.untilHasMessages(proc.midx+1);
+ return true;
+ } else {
+ EInteger ei;
+ if ((ei = howlong.testInteger()) == null)
+ throw badarg(howlong);
+
+ return proc.mbox.untilHasMessages(proc.midx+1, ei.longValue());
+ }
+ }
}
public static void wait_forever(EProc proc) throws Pausable {
- proc.mbox.untilHasMessage();
+ if (proc.midx == -1024) {
+ proc.mbox.untilHasMessage();
+ } else {
+ proc.mbox.untilHasMessages(proc.midx + 1);
+ }
}
- public static EObject loop_rec_end(EProc proc) {
- EObject msg = proc.mbox.peek();
- throw new ErlangError(am_receive_clause, proc.self(), msg);
+ // this will be followed by a goto the receive
+ public static void loop_rec_end(EProc proc) {
+ proc.midx += 1;
+ }
+
+
+ public static void timeout() {
}
public static int unboxToInt(EInteger i) {
return i.intValue();
}
+ public static int unboxToInt(ENumber i) {
+ return i.intValue();
+ }
+
public static double unboxToDouble(ENumber i) {
return i.doubleValue();
}
@@ -499,25 +550,13 @@ public static EObject func_info(EAtom mod, EAtom fun, int arity) {
throw new ErlangError(AM_BADMATCH);
}
- public static boolean wait_timeout(EProc proc, EObject howlong)
- throws Pausable {
- if (howlong == am_infinity) {
- proc.mbox.untilHasMessage();
- return true;
- } else {
- EInteger ei;
- if ((ei = howlong.testInteger()) == null)
- throw badarg(howlong);
- return proc.mbox.untilHasMessage(ei.longValue());
- }
- }
-
- public static void timeout() {
- // skip //
+ static void load_module(EAtom module) throws IOException {
+ File f = Compiler.find_and_compile(module.getName());
+ EModule.load_module(module, f.toURI().toURL());
}
- static void load(EAtom module) throws IOException {
- File f = Compiler