diff --git a/src/main/java/me/topchetoeu/jscript/common/Buffer.java b/src/main/java/me/topchetoeu/jscript/common/Buffer.java deleted file mode 100644 index 0840177..0000000 --- a/src/main/java/me/topchetoeu/jscript/common/Buffer.java +++ /dev/null @@ -1,58 +0,0 @@ -package me.topchetoeu.jscript.common; - -public class Buffer { - private byte[] data; - private int length; - - public void write(int i, byte[] val) { - if (i + val.length > data.length) { - var newCap = i + val.length + 1; - if (newCap < data.length * 2) newCap = data.length * 2; - - var tmp = new byte[newCap]; - System.arraycopy(this.data, 0, tmp, 0, length); - this.data = tmp; - } - - System.arraycopy(val, 0, data, i, val.length); - if (i + val.length > length) length = i + val.length; - } - public int read(int i, byte[] buff) { - int n = buff.length; - if (i + n > length) n = length - i; - System.arraycopy(data, i, buff, 0, n); - return n; - } - - public void clear() { - data = new byte[128]; - length = 0; - } - - public void append(byte b) { - write(length, new byte[] { b }); - } - - public byte[] data() { - var res = new byte[length]; - System.arraycopy(this.data, 0, res, 0, length); - return res; - } - public int length() { - return length; - } - - public Buffer(byte[] data) { - this.data = new byte[data.length]; - this.length = data.length; - System.arraycopy(data, 0, this.data, 0, data.length); - } - public Buffer(int capacity) { - this.data = new byte[capacity]; - this.length = 0; - } - public Buffer() { - this.data = new byte[128]; - this.length = 0; - } -} diff --git a/src/main/java/me/topchetoeu/jscript/common/FunctionBody.java b/src/main/java/me/topchetoeu/jscript/common/FunctionBody.java index e46f9c0..b367ba3 100644 --- a/src/main/java/me/topchetoeu/jscript/common/FunctionBody.java +++ b/src/main/java/me/topchetoeu/jscript/common/FunctionBody.java @@ -1,16 +1,16 @@ package me.topchetoeu.jscript.common; public class FunctionBody { - public final FunctionBody[] children; - public final Instruction[] instructions; - public final int localsN, capturablesN, capturesN, length; + public final FunctionBody[] children; + public final Instruction[] instructions; + public final int localsN, capturablesN, capturesN, length; - public FunctionBody(int localsN, int capturablesN, int capturesN, int length, Instruction[] instructions, FunctionBody[] children) { - this.children = children; - this.length = length; - this.localsN = localsN; - this.capturablesN = capturablesN; - this.capturesN = capturesN; - this.instructions = instructions; - } + public FunctionBody(int localsN, int capturablesN, int capturesN, int length, Instruction[] instructions, FunctionBody[] children) { + this.children = children; + this.length = length; + this.localsN = localsN; + this.capturablesN = capturablesN; + this.capturesN = capturesN; + this.instructions = instructions; + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/Instruction.java b/src/main/java/me/topchetoeu/jscript/common/Instruction.java index f5cabb0..00cdeae 100644 --- a/src/main/java/me/topchetoeu/jscript/common/Instruction.java +++ b/src/main/java/me/topchetoeu/jscript/common/Instruction.java @@ -7,233 +7,115 @@ import java.util.function.IntSupplier; import me.topchetoeu.jscript.common.parsing.Location; public class Instruction { - public static enum Type { - RETURN(0x00), - NOP(0x01), - THROW(0x02), - THROW_SYNTAX(0x03), - DELETE(0x04), - TRY_START(0x05), - TRY_END(0x06), + public static enum Type { + RETURN(0x00), + NOP(0x01), + THROW(0x02), + THROW_SYNTAX(0x03), + DELETE(0x04), + TRY_START(0x05), + TRY_END(0x06), - CALL(0x10), - CALL_NEW(0x12), - JMP_IF(0x18), - JMP_IFN(0x19), - JMP(0x1A), + CALL(0x10), + CALL_NEW(0x12), + JMP_IF(0x18), + JMP_IFN(0x19), + JMP(0x1A), - PUSH_UNDEFINED(0x20), - PUSH_NULL(0x21), - PUSH_BOOL(0x22), - PUSH_NUMBER(0x23), - PUSH_STRING(0x24), - DUP(0x25), - DISCARD(0x26), + PUSH_UNDEFINED(0x20), + PUSH_NULL(0x21), + PUSH_BOOL(0x22), + PUSH_NUMBER(0x23), + PUSH_STRING(0x24), + DUP(0x25), + DISCARD(0x26), - LOAD_FUNC(0x30), - LOAD_ARR(0x31), - LOAD_OBJ(0x32), - LOAD_REGEX(0x33), + LOAD_FUNC(0x30), + LOAD_ARR(0x31), + LOAD_OBJ(0x32), + LOAD_REGEX(0x33), - LOAD_GLOB(0x38), - LOAD_INTRINSICS(0x39), - LOAD_ARG(0x3A), - LOAD_ARGS_N(0x3B), - LOAD_ARGS(0x3C), - LOAD_CALLED(0x3D), - LOAD_THIS(0x3E), - LOAD_ERROR(0x3F), + LOAD_GLOB(0x38), + LOAD_INTRINSICS(0x39), + LOAD_ARG(0x3A), + LOAD_ARGS_N(0x3B), + LOAD_ARGS(0x3C), + LOAD_CALLED(0x3D), + LOAD_THIS(0x3E), + LOAD_ERROR(0x3F), - LOAD_VAR(0x40), - LOAD_MEMBER(0x41), - LOAD_MEMBER_INT(0x42), - LOAD_MEMBER_STR(0x43), + LOAD_VAR(0x40), + LOAD_MEMBER(0x41), + LOAD_MEMBER_INT(0x42), + LOAD_MEMBER_STR(0x43), - STORE_VAR(0x48), - STORE_MEMBER(0x49), - STORE_MEMBER_INT(0x4A), - STORE_MEMBER_STR(0x4B), + STORE_VAR(0x48), + STORE_MEMBER(0x49), + STORE_MEMBER_INT(0x4A), + STORE_MEMBER_STR(0x4B), - DEF_PROP(0x50), - DEF_FIELD(0x51), - KEYS(0x52), - TYPEOF(0x53), - OPERATION(0x54), + DEF_PROP(0x50), + DEF_FIELD(0x51), + KEYS(0x52), + TYPEOF(0x53), + OPERATION(0x54), - GLOB_GET(0x60), - GLOB_SET(0x61), - GLOB_DEF(0x62); + GLOB_GET(0x60), + GLOB_SET(0x61), + GLOB_DEF(0x62); - private static final HashMap types = new HashMap<>(); - public final int numeric; + private static final HashMap types = new HashMap<>(); + public final int numeric; - static { - for (var val : Type.values()) types.put(val.numeric, val); - } + static { + for (var val : Type.values()) types.put(val.numeric, val); + } - private Type(int numeric) { - this.numeric = numeric; - } + private Type(int numeric) { + this.numeric = numeric; + } - public static Type fromNumeric(int i) { - return types.get(i); - } - } - public static enum BreakpointType { + public static Type fromNumeric(int i) { + return types.get(i); + } + } + public static enum BreakpointType { /** * A debugger should never stop at such instruction, unless a breakpoint has been set on it */ - NONE, + NONE, /** * Debuggers should pause at instructions marked with this breakpoint type * after any step command */ - STEP_OVER, + STEP_OVER, /** * Debuggers should pause at instructions marked with this breakpoint type * only after a step-in command */ - STEP_IN; + STEP_IN; - public boolean shouldStepIn() { - return this != NONE; - } - public boolean shouldStepOver() { - return this == STEP_OVER; - } - } + public boolean shouldStepIn() { + return this != NONE; + } + public boolean shouldStepOver() { + return this == STEP_OVER; + } + } - public final Type type; - public final Object[] params; + public final Type type; + public final Object[] params; - @SuppressWarnings("unchecked") - public T get(int i) { - if (i >= params.length || i < 0) return null; - return (T)params[i]; - } + @SuppressWarnings("unchecked") + public T get(int i) { + if (i >= params.length || i < 0) return null; + return (T)params[i]; + } - // public void write(DataOutputStream writer) throws IOException { - // var rawType = type.numeric; - - // switch (type) { - // case KEYS: - // case PUSH_BOOL: - // case STORE_MEMBER: - // case GLOB_SET: - // rawType |= (boolean)get(0) ? 128 : 0; break; - // case TYPEOF: rawType |= params.length > 0 ? 128 : 0; break; - // default: - // } - - // writer.writeByte(rawType); - - // switch (type) { - // case CALL: - // case CALL_NEW: - // case CALL_MEMBER: - // writer.writeInt(get(0)); - // writer.writeUTF(get(1)); - // break; - // case DUP: writer.writeInt(get(0)); break; - // case JMP: writer.writeInt(get(0)); break; - // case JMP_IF: writer.writeInt(get(0)); break; - // case JMP_IFN: writer.writeInt(get(0)); break; - // case LOAD_ARR: writer.writeInt(get(0)); break; - // case LOAD_FUNC: { - // writer.writeInt(params.length - 1); - - // for (var i = 0; i < params.length; i++) { - // writer.writeInt(get(i + 1)); - // } - - // writer.writeInt(get(0)); - // writer.writeUTF(get(0)); - // break; - // } - // case LOAD_REGEX: writer.writeUTF(get(0)); break; - // case LOAD_VAR: writer.writeInt(get(0)); break; - // case GLOB_DEF: writer.writeUTF(get(0)); break; - // case GLOB_GET: writer.writeUTF(get(0)); break; - // case GLOB_SET: - // writer.writeUTF(get(0)); - // break; - // case OPERATION: writer.writeByte(((Operation)get(0)).numeric); break; - // case PUSH_NUMBER: writer.writeDouble(get(0)); break; - // case PUSH_STRING: writer.writeUTF(get(0)); break; - // case STORE_VAR: writer.writeInt(get(0)); break; - // case THROW_SYNTAX: writer.writeUTF(get(0)); - // case TRY_START: - // writer.writeInt(get(0)); - // writer.writeInt(get(1)); - // writer.writeInt(get(2)); - // break; - // case TYPEOF: - // if (params.length > 0) writer.writeUTF(get(0)); - // break; - // default: - // } - // } - - private Instruction(Type type, Object ...params) { - this.type = type; - this.params = params; - } - - // public static Instruction read(DataInputStream stream) throws IOException { - // var rawType = stream.readUnsignedByte(); - // var type = Type.fromNumeric(rawType & 127); - // var flag = (rawType & 128) != 0; - - // switch (type) { - // case CALL: return call(stream.readInt(), stream.readUTF()); - // case CALL_NEW: return callNew(stream.readInt(), stream.readUTF()); - // case CALL_MEMBER: return callNew(stream.readInt(), stream.readUTF()); - // case DEF_PROP: return defProp(); - // case DELETE: return delete(); - // case DISCARD: return discard(); - // case DUP: return dup(stream.readInt()); - // case JMP: return jmp(stream.readInt()); - // case JMP_IF: return jmpIf(stream.readInt()); - // case JMP_IFN: return jmpIfNot(stream.readInt()); - // case KEYS: return keys(flag); - // case LOAD_ARR: return loadArr(stream.readInt()); - // case LOAD_FUNC: { - // var captures = new int[stream.readInt()]; - - // for (var i = 0; i < captures.length; i++) { - // captures[i] = stream.readInt(); - // } - - // return loadFunc(stream.readInt(), stream.readUTF(), captures); - // } - // case LOAD_GLOB: return loadGlob(); - // case LOAD_MEMBER: return loadMember(); - // case LOAD_OBJ: return loadObj(); - // case LOAD_REGEX: return loadRegex(stream.readUTF(), null); - // case LOAD_VAR: return loadVar(stream.readInt()); - // case GLOB_DEF: return globDef(stream.readUTF()); - // case GLOB_GET: return globGet(stream.readUTF()); - // case GLOB_SET: return globSet(stream.readUTF(), flag); - // case OPERATION: return operation(Operation.fromNumeric(stream.readUnsignedByte())); - // case PUSH_NULL: return pushNull(); - // case PUSH_UNDEFINED: return pushUndefined(); - // case PUSH_BOOL: return pushValue(flag); - // case PUSH_NUMBER: return pushValue(stream.readDouble()); - // case PUSH_STRING: return pushValue(stream.readUTF()); - // case RETURN: return ret(); - // case STORE_MEMBER: return storeMember(flag); - // case STORE_VAR: return storeVar(stream.readInt(), flag); - // case THROW: return throwInstr(); - // case THROW_SYNTAX: return throwSyntax(stream.readUTF()); - // case TRY_END: return tryEnd(); - // case TRY_START: return tryStart(stream.readInt(), stream.readInt(), stream.readInt(), stream.readInt()); - // case TYPEOF: return flag ? typeof(stream.readUTF()) : typeof(); - // case NOP: - // if (flag) return null; - // else return nop(); - // default: return null; - // } - // } + private Instruction(Type type, Object ...params) { + this.type = type; + this.params = params; + } /** * Signals the start of a protected context @@ -241,257 +123,254 @@ public class Instruction { * @param finallyStart The point to witch to jump after either the try or catch bodies have exited * @param end The point to which to jump after exiting the whole protected context */ - public static Instruction tryStart(int catchStart, int finallyStart, int end) { - return new Instruction(Type.TRY_START, catchStart, finallyStart, end); - } + public static Instruction tryStart(int catchStart, int finallyStart, int end) { + return new Instruction(Type.TRY_START, catchStart, finallyStart, end); + } /** * Signifies that the current protected section (try, catch or finally) has ended */ - public static Instruction tryEnd() { - return new Instruction(Type.TRY_END); - } + public static Instruction tryEnd() { + return new Instruction(Type.TRY_END); + } /** * Throws the top stack value */ - public static Instruction throwInstr() { - return new Instruction(Type.THROW); - } + public static Instruction throwInstr() { + return new Instruction(Type.THROW); + } /** * Converts the given exception to a runtime syntax error and throws it */ - public static Instruction throwSyntax(SyntaxException err) { - return new Instruction(Type.THROW_SYNTAX, err.getMessage()); - } + public static Instruction throwSyntax(SyntaxException err) { + return new Instruction(Type.THROW_SYNTAX, err.getMessage()); + } /** * Converts the given exception to a runtime syntax error and throws it */ - public static Instruction throwSyntax(String err) { - return new Instruction(Type.THROW_SYNTAX, err); - } + public static Instruction throwSyntax(String err) { + return new Instruction(Type.THROW_SYNTAX, err); + } /** * Converts the given exception to a runtime syntax error and throws it */ - public static Instruction throwSyntax(Location loc, String err) { - return new Instruction(Type.THROW_SYNTAX, new SyntaxException(loc, err).getMessage()); - } + public static Instruction throwSyntax(Location loc, String err) { + return new Instruction(Type.THROW_SYNTAX, new SyntaxException(loc, err).getMessage()); + } /** * Performs a JS object property deletion. * Operands: * 1. Object to manipulate * 2. Key to delete */ - public static Instruction delete() { - return new Instruction(Type.DELETE); - } + public static Instruction delete() { + return new Instruction(Type.DELETE); + } /** * Returns the top stack value */ - public static Instruction ret() { - return new Instruction(Type.RETURN); - } + public static Instruction ret() { + return new Instruction(Type.RETURN); + } /** * A special NOP instruction telling any debugger to pause */ - public static Instruction debug() { - return new Instruction(Type.NOP, "debug"); - } + public static Instruction debug() { + return new Instruction(Type.NOP, "debug"); + } /** * Does nothing. May be used for metadata or implementation-specific instructions that don't alter the behavior */ - public static Instruction nop(Object ...params) { - return new Instruction(Type.NOP, params); - } + public static Instruction nop(Object ...params) { + return new Instruction(Type.NOP, params); + } - public static Instruction call(int argn, boolean hasSelf) { - return new Instruction(Type.CALL, argn, hasSelf); - } - public static Instruction callNew(int argn) { - return new Instruction(Type.CALL_NEW, argn); - } + public static Instruction call(int argn, boolean hasSelf) { + return new Instruction(Type.CALL, argn, hasSelf); + } + public static Instruction callNew(int argn) { + return new Instruction(Type.CALL_NEW, argn); + } - public static Instruction jmp(int offset) { - return new Instruction(Type.JMP, offset); - } - public static Instruction jmpIf(int offset) { - return new Instruction(Type.JMP_IF, offset); - } - public static Instruction jmpIfNot(int offset) { - return new Instruction(Type.JMP_IFN, offset); - } + public static Instruction jmp(int offset) { + return new Instruction(Type.JMP, offset); + } + public static Instruction jmpIf(int offset) { + return new Instruction(Type.JMP_IF, offset); + } + public static Instruction jmpIfNot(int offset) { + return new Instruction(Type.JMP_IFN, offset); + } - public static IntFunction jmp(IntSupplier pos) { - return i -> new Instruction(Type.JMP, pos.getAsInt() - i); - } - public static IntFunction jmpIf(IntSupplier pos) { - return i -> new Instruction(Type.JMP_IF, pos.getAsInt() - i); - } - public static IntFunction jmpIfNot(IntSupplier pos) { - return i -> new Instruction(Type.JMP_IFN, pos.getAsInt() - i); - } + public static IntFunction jmp(IntSupplier pos) { + return i -> new Instruction(Type.JMP, pos.getAsInt() - i); + } + public static IntFunction jmpIf(IntSupplier pos) { + return i -> new Instruction(Type.JMP_IF, pos.getAsInt() - i); + } + public static IntFunction jmpIfNot(IntSupplier pos) { + return i -> new Instruction(Type.JMP_IFN, pos.getAsInt() - i); + } - public static Instruction pushUndefined() { - return new Instruction(Type.PUSH_UNDEFINED); - } - public static Instruction pushNull() { - return new Instruction(Type.PUSH_NULL); - } - public static Instruction pushValue(boolean val) { - return new Instruction(Type.PUSH_BOOL, val); - } - public static Instruction pushValue(double val) { - return new Instruction(Type.PUSH_NUMBER, val); - } - public static Instruction pushValue(String val) { - return new Instruction(Type.PUSH_STRING, val); - } + public static Instruction pushUndefined() { + return new Instruction(Type.PUSH_UNDEFINED); + } + public static Instruction pushNull() { + return new Instruction(Type.PUSH_NULL); + } + public static Instruction pushValue(boolean val) { + return new Instruction(Type.PUSH_BOOL, val); + } + public static Instruction pushValue(double val) { + return new Instruction(Type.PUSH_NUMBER, val); + } + public static Instruction pushValue(String val) { + return new Instruction(Type.PUSH_STRING, val); + } - public static Instruction globDef(String name) { - return new Instruction(Type.GLOB_DEF, name); - } - - public static Instruction globGet(String name, boolean force) { - return new Instruction(Type.GLOB_GET, name, force); - } - public static Instruction globSet(String name, boolean keep, boolean define) { - return new Instruction(Type.GLOB_SET, name, keep, define); - } + public static Instruction globDef(String name) { + return new Instruction(Type.GLOB_DEF, name); + } + + public static Instruction globGet(String name, boolean force) { + return new Instruction(Type.GLOB_GET, name, force); + } + public static Instruction globSet(String name, boolean keep, boolean define) { + return new Instruction(Type.GLOB_SET, name, keep, define); + } - public static Instruction loadVar(int i) { - return new Instruction(Type.LOAD_VAR, i); - } - public static Instruction loadThis() { - return new Instruction(Type.LOAD_THIS); - } + public static Instruction loadVar(int i) { + return new Instruction(Type.LOAD_VAR, i); + } + public static Instruction loadThis() { + return new Instruction(Type.LOAD_THIS); + } /** * Loads the given argument * @param i The index of the argument to load. If -1, will get the index from the stack instead */ - public static Instruction loadArg(int i) { - return new Instruction(Type.LOAD_ARG, i); - } + public static Instruction loadArg(int i) { + return new Instruction(Type.LOAD_ARG, i); + } /** * Pushes the amount of arguments to the stack */ - public static Instruction loadArgsN() { - return new Instruction(Type.LOAD_ARGS_N); - } + public static Instruction loadArgsN() { + return new Instruction(Type.LOAD_ARGS_N); + } /** * Pushes the arguments object to the stack */ - public static Instruction loadArgs() { - return new Instruction(Type.LOAD_ARGS); - } + public static Instruction loadArgs() { + return new Instruction(Type.LOAD_ARGS); + } /** * Loads a reference to the function being called */ - public static Instruction loadCalled() { - return new Instruction(Type.LOAD_CALLED); - } - public static Instruction loadGlob() { - return new Instruction(Type.LOAD_GLOB); - } - public static Instruction loadIntrinsics(String key) { - return new Instruction(Type.LOAD_INTRINSICS, key); - } - public static Instruction loadError() { - return new Instruction(Type.LOAD_ERROR); - } - public static Instruction loadMember() { - return new Instruction(Type.LOAD_MEMBER); - } - public static Instruction loadMember(int member) { - return new Instruction(Type.LOAD_MEMBER_INT, member); - } - public static Instruction loadMember(String member) { - return new Instruction(Type.LOAD_MEMBER_STR, member); - } + public static Instruction loadCalled() { + return new Instruction(Type.LOAD_CALLED); + } + public static Instruction loadGlob() { + return new Instruction(Type.LOAD_GLOB); + } + public static Instruction loadIntrinsics(String key) { + return new Instruction(Type.LOAD_INTRINSICS, key); + } + public static Instruction loadError() { + return new Instruction(Type.LOAD_ERROR); + } + public static Instruction loadMember() { + return new Instruction(Type.LOAD_MEMBER); + } + public static Instruction loadMember(int member) { + return new Instruction(Type.LOAD_MEMBER_INT, member); + } + public static Instruction loadMember(String member) { + return new Instruction(Type.LOAD_MEMBER_STR, member); + } - public static Instruction loadRegex(String pattern, String flags) { - return new Instruction(Type.LOAD_REGEX, pattern, flags); - } - // TODO: make this capturing a concern of the compiler - public static Instruction loadFunc(int id, String name, int[] captures) { - var args = new Object[2 + captures.length]; - args[0] = id; - args[1] = name; - for (var i = 0; i < captures.length; i++) args[i + 2] = captures[i]; - return new Instruction(Type.LOAD_FUNC, args); - } - public static Instruction loadObj() { - return new Instruction(Type.LOAD_OBJ); - } - public static Instruction loadArr(int count) { - return new Instruction(Type.LOAD_ARR, count); - } - public static Instruction dup() { - return new Instruction(Type.DUP, 1, 0); - } - public static Instruction dup(int count, int offset) { - return new Instruction(Type.DUP, count, offset); - } + public static Instruction loadRegex(String pattern, String flags) { + return new Instruction(Type.LOAD_REGEX, pattern, flags); + } + // TODO: make this capturing a concern of the compiler + public static Instruction loadFunc(int id, String name, int[] captures) { + var args = new Object[2 + captures.length]; + args[0] = id; + args[1] = name; + for (var i = 0; i < captures.length; i++) args[i + 2] = captures[i]; + return new Instruction(Type.LOAD_FUNC, args); + } + public static Instruction loadObj() { + return new Instruction(Type.LOAD_OBJ); + } + public static Instruction loadArr(int count) { + return new Instruction(Type.LOAD_ARR, count); + } + public static Instruction dup() { + return new Instruction(Type.DUP, 1, 0); + } + public static Instruction dup(int count, int offset) { + return new Instruction(Type.DUP, count, offset); + } - // public static Instruction storeVar(int i) { - // return new Instruction(Type.STORE_VAR, i, false); - // } - public static Instruction storeVar(int i, boolean keep, boolean initialize) { - return new Instruction(Type.STORE_VAR, i, keep, initialize); - } + public static Instruction storeVar(int i, boolean keep, boolean initialize) { + return new Instruction(Type.STORE_VAR, i, keep, initialize); + } - public static Instruction storeMember() { - return new Instruction(Type.STORE_MEMBER, false); - } - public static Instruction storeMember(boolean keep) { - return new Instruction(Type.STORE_MEMBER, keep); - } + public static Instruction storeMember() { + return new Instruction(Type.STORE_MEMBER, false); + } + public static Instruction storeMember(boolean keep) { + return new Instruction(Type.STORE_MEMBER, keep); + } - public static Instruction storeMember(String key) { - return new Instruction(Type.STORE_MEMBER_STR, key, false); - } - public static Instruction storeMember(String key, boolean keep) { - return new Instruction(Type.STORE_MEMBER_STR, key, keep); - } + public static Instruction storeMember(String key) { + return new Instruction(Type.STORE_MEMBER_STR, key, false); + } + public static Instruction storeMember(String key, boolean keep) { + return new Instruction(Type.STORE_MEMBER_STR, key, keep); + } - public static Instruction storeMember(int key) { - return new Instruction(Type.STORE_MEMBER_INT, key, false); - } - public static Instruction storeMember(int key, boolean keep) { - return new Instruction(Type.STORE_MEMBER_INT, key, keep); - } + public static Instruction storeMember(int key) { + return new Instruction(Type.STORE_MEMBER_INT, key, false); + } + public static Instruction storeMember(int key, boolean keep) { + return new Instruction(Type.STORE_MEMBER_INT, key, keep); + } - public static Instruction discard() { - return new Instruction(Type.DISCARD); - } + public static Instruction discard() { + return new Instruction(Type.DISCARD); + } - public static Instruction typeof() { - return new Instruction(Type.TYPEOF); - } - public static Instruction typeof(String varName) { - return new Instruction(Type.TYPEOF, varName); - } + public static Instruction typeof() { + return new Instruction(Type.TYPEOF); + } + public static Instruction typeof(String varName) { + return new Instruction(Type.TYPEOF, varName); + } - public static Instruction keys(boolean own, boolean onlyEnumerable) { - return new Instruction(Type.KEYS, own, onlyEnumerable); - } + public static Instruction keys(boolean own, boolean onlyEnumerable) { + return new Instruction(Type.KEYS, own, onlyEnumerable); + } - public static Instruction defProp(boolean setter) { - return new Instruction(Type.DEF_PROP, setter); - } - public static Instruction defField() { - return new Instruction(Type.DEF_FIELD); - } + public static Instruction defProp(boolean setter) { + return new Instruction(Type.DEF_PROP, setter); + } + public static Instruction defField() { + return new Instruction(Type.DEF_FIELD); + } - public static Instruction operation(Operation op) { - return new Instruction(Type.OPERATION, op); - } + public static Instruction operation(Operation op) { + return new Instruction(Type.OPERATION, op); + } - @Override public String toString() { - var res = type.toString(); + @Override public String toString() { + var res = type.toString(); - for (int i = 0; i < params.length; i++) { - res += " " + params[i]; - } + for (int i = 0; i < params.length; i++) { + res += " " + params[i]; + } - return res; - } + return res; + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/Metadata.java b/src/main/java/me/topchetoeu/jscript/common/Metadata.java index efc33dd..fbd9f7c 100644 --- a/src/main/java/me/topchetoeu/jscript/common/Metadata.java +++ b/src/main/java/me/topchetoeu/jscript/common/Metadata.java @@ -3,27 +3,27 @@ package me.topchetoeu.jscript.common; import me.topchetoeu.jscript.common.json.JSON; public class Metadata { - private static final String VERSION; - private static final String AUTHOR; - private static final String NAME; + private static final String VERSION; + private static final String AUTHOR; + private static final String NAME; - static { - var data = JSON.parse(null, Reading.resourceToString("metadata.json")).map(); - VERSION = data.string("version"); - AUTHOR = data.string("author"); - NAME = data.string("name"); - } + static { + var data = JSON.parse(null, Reading.resourceToString("metadata.json")).map(); + VERSION = data.string("version"); + AUTHOR = data.string("author"); + NAME = data.string("name"); + } - public static String version() { - if (VERSION.equals("$" + "{VERSION}")) return "1337-devel"; - else return VERSION; - } - public static String author() { - if (AUTHOR.equals("$" + "{AUTHOR}")) return "anonymous"; - else return AUTHOR; - } - public static String name() { - if (NAME.equals("$" + "{NAME}")) return "some-product"; - else return NAME; - } + public static String version() { + if (VERSION.equals("$" + "{VERSION}")) return "1337-devel"; + else return VERSION; + } + public static String author() { + if (AUTHOR.equals("$" + "{AUTHOR}")) return "anonymous"; + else return AUTHOR; + } + public static String name() { + if (NAME.equals("$" + "{NAME}")) return "some-product"; + else return NAME; + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/Operation.java b/src/main/java/me/topchetoeu/jscript/common/Operation.java index 262e99b..d616b3c 100644 --- a/src/main/java/me/topchetoeu/jscript/common/Operation.java +++ b/src/main/java/me/topchetoeu/jscript/common/Operation.java @@ -3,52 +3,52 @@ package me.topchetoeu.jscript.common; import java.util.HashMap; public enum Operation { - INSTANCEOF(1, 2), - IN(2, 2), + INSTANCEOF(1, 2), + IN(2, 2), - MULTIPLY(3, 2), - DIVIDE(4, 2), - MODULO(5, 2), - ADD(6, 2), - SUBTRACT(7, 2), + MULTIPLY(3, 2), + DIVIDE(4, 2), + MODULO(5, 2), + ADD(6, 2), + SUBTRACT(7, 2), - USHIFT_RIGHT(8, 2), - SHIFT_RIGHT(9, 2), - SHIFT_LEFT(10, 2), + USHIFT_RIGHT(8, 2), + SHIFT_RIGHT(9, 2), + SHIFT_LEFT(10, 2), - GREATER(11, 2), - LESS(12, 2), - GREATER_EQUALS(13, 2), - LESS_EQUALS(14, 2), - LOOSE_EQUALS(15, 2), - LOOSE_NOT_EQUALS(16, 2), - EQUALS(17, 2), - NOT_EQUALS(18, 2), + GREATER(11, 2), + LESS(12, 2), + GREATER_EQUALS(13, 2), + LESS_EQUALS(14, 2), + LOOSE_EQUALS(15, 2), + LOOSE_NOT_EQUALS(16, 2), + EQUALS(17, 2), + NOT_EQUALS(18, 2), - AND(19, 2), - OR(20, 2), - XOR(21, 2), + AND(19, 2), + OR(20, 2), + XOR(21, 2), - NEG(23, 1), - POS(24, 1), - NOT(25, 1), - INVERSE(26, 1); + NEG(23, 1), + POS(24, 1), + NOT(25, 1), + INVERSE(26, 1); - private static final HashMap operations = new HashMap<>(); + private static final HashMap operations = new HashMap<>(); - static { - for (var val : Operation.values()) operations.put(val.numeric, val); - } + static { + for (var val : Operation.values()) operations.put(val.numeric, val); + } - public final int numeric; - public final int operands; + public final int numeric; + public final int operands; - private Operation(int numeric, int n) { - this.numeric = numeric; - this.operands = n; - } + private Operation(int numeric, int n) { + this.numeric = numeric; + this.operands = n; + } - public static Operation fromNumeric(int i) { - return operations.get(i); - } + public static Operation fromNumeric(int i) { + return operations.get(i); + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/Reading.java b/src/main/java/me/topchetoeu/jscript/common/Reading.java index 6c6e6e8..61c61bb 100644 --- a/src/main/java/me/topchetoeu/jscript/common/Reading.java +++ b/src/main/java/me/topchetoeu/jscript/common/Reading.java @@ -10,76 +10,76 @@ import java.util.Arrays; import java.util.List; public class Reading { - private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); - public static synchronized String readline() throws IOException { - return reader.readLine(); - } + public static synchronized String readline() throws IOException { + return reader.readLine(); + } - public static byte[] streamToBytes(InputStream in) { - try { - List bufs = null; - byte[] result = null; - int total = 0; - int n; + public static byte[] streamToBytes(InputStream in) { + try { + List bufs = null; + byte[] result = null; + int total = 0; + int n; - do { - var buf = new byte[8192]; - int nread = 0; + do { + var buf = new byte[8192]; + int nread = 0; - // read to EOF which may read more or less than buffer size - while ((n = in.read(buf, nread, buf.length - nread)) > 0) { - nread += n; - } + // read to EOF which may read more or less than buffer size + while ((n = in.read(buf, nread, buf.length - nread)) > 0) { + nread += n; + } - if (nread > 0) { - if (Integer.MAX_VALUE - 8 - total < nread) throw new OutOfMemoryError("Required array size too large"); - if (nread < buf.length) buf = Arrays.copyOfRange(buf, 0, nread); - total += nread; + if (nread > 0) { + if (Integer.MAX_VALUE - 8 - total < nread) throw new OutOfMemoryError("Required array size too large"); + if (nread < buf.length) buf = Arrays.copyOfRange(buf, 0, nread); + total += nread; - if (result == null) result = buf; - else { - if (bufs == null) { - bufs = new ArrayList<>(); - bufs.add(result); - } + if (result == null) result = buf; + else { + if (bufs == null) { + bufs = new ArrayList<>(); + bufs.add(result); + } - bufs.add(buf); - } - } - // if the last call to read returned -1 or the number of bytes - // requested have been read then break - } while (n >= 0); + bufs.add(buf); + } + } + // if the last call to read returned -1 or the number of bytes + // requested have been read then break + } while (n >= 0); - if (bufs == null) { - if (result == null) return new byte[0]; - return result.length == total ? result : Arrays.copyOf(result, total); - } + if (bufs == null) { + if (result == null) return new byte[0]; + return result.length == total ? result : Arrays.copyOf(result, total); + } - result = new byte[total]; + result = new byte[total]; - int offset = 0; - int remaining = total; + int offset = 0; + int remaining = total; - for (byte[] b : bufs) { - int count = Math.min(b.length, remaining); - System.arraycopy(b, 0, result, offset, count); - offset += count; - remaining -= count; - } + for (byte[] b : bufs) { + int count = Math.min(b.length, remaining); + System.arraycopy(b, 0, result, offset, count); + offset += count; + remaining -= count; + } - return result; - } - catch (IOException e) { throw new UncheckedIOException(e); } - } - public static String streamToString(InputStream in) { - return new String(streamToBytes(in)); - } - - public static InputStream resourceToStream(String name) { - return Reading.class.getResourceAsStream("/" + name); - } - public static String resourceToString(String name) { - return streamToString(resourceToStream(name)); - } + return result; + } + catch (IOException e) { throw new UncheckedIOException(e); } + } + public static String streamToString(InputStream in) { + return new String(streamToBytes(in)); + } + + public static InputStream resourceToStream(String name) { + return Reading.class.getResourceAsStream("/" + name); + } + public static String resourceToString(String name) { + return streamToString(resourceToStream(name)); + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/SyntaxException.java b/src/main/java/me/topchetoeu/jscript/common/SyntaxException.java index 2483e6f..a510d77 100644 --- a/src/main/java/me/topchetoeu/jscript/common/SyntaxException.java +++ b/src/main/java/me/topchetoeu/jscript/common/SyntaxException.java @@ -3,12 +3,12 @@ package me.topchetoeu.jscript.common; import me.topchetoeu.jscript.common.parsing.Location; public class SyntaxException extends RuntimeException { - public final Location loc; - public final String msg; + public final Location loc; + public final String msg; - public SyntaxException(Location loc, String msg) { - super(String.format("Syntax error %s: %s", loc, msg)); - this.loc = loc; - this.msg = msg; - } + public SyntaxException(Location loc, String msg) { + super(String.format("Syntax error %s: %s", loc, msg)); + this.loc = loc; + this.msg = msg; + } } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/common/environment/Environment.java b/src/main/java/me/topchetoeu/jscript/common/environment/Environment.java index 74be652..33a77d4 100644 --- a/src/main/java/me/topchetoeu/jscript/common/environment/Environment.java +++ b/src/main/java/me/topchetoeu/jscript/common/environment/Environment.java @@ -7,91 +7,91 @@ import java.util.Set; import java.util.function.Supplier; public class Environment { - public final Environment parent; - private final Map, Object> map = new HashMap<>(); - private final Set> hidden = new HashSet<>(); + public final Environment parent; + private final Map, Object> map = new HashMap<>(); + private final Set> hidden = new HashSet<>(); - @SuppressWarnings("unchecked") - public T get(Key key) { - if (map.containsKey(key)) return (T)map.get(key); - else if (!hidden.contains(key) && parent != null) return parent.get(key); - else return null; - } - public boolean has(Key key) { - if (map.containsKey(key)) return true; - else if (!hidden.contains(key) && parent != null) return parent.has(key); - else return false; - } + @SuppressWarnings("unchecked") + public T get(Key key) { + if (map.containsKey(key)) return (T)map.get(key); + else if (!hidden.contains(key) && parent != null) return parent.get(key); + else return null; + } + public boolean has(Key key) { + if (map.containsKey(key)) return true; + else if (!hidden.contains(key) && parent != null) return parent.has(key); + else return false; + } - public boolean hasNotNull(Key key) { - return get(key) != null; - } + public boolean hasNotNull(Key key) { + return get(key) != null; + } - public T get(Key key, T defaultVal) { - if (has(key)) return get(key); - else return defaultVal; - } - public T getWith(Key key, Supplier defaultVal) { - if (has(key)) return get(key); - else return defaultVal.get(); - } + public T get(Key key, T defaultVal) { + if (has(key)) return get(key); + else return defaultVal; + } + public T getWith(Key key, Supplier defaultVal) { + if (has(key)) return get(key); + else return defaultVal.get(); + } - @SuppressWarnings("unchecked") - public Environment add(Key key, T val) { - map.put((Key)key, val); - hidden.remove(key); - return this; - } - public Environment add(Key key) { - return add(key, null); - } - @SuppressWarnings("all") - public Environment addAll(Map, ?> map, boolean iterableAsMulti) { - map.putAll((Map)map); - hidden.removeAll(map.keySet()); - return this; - } - public Environment addAll(Map, ?> map) { - return addAll(map, true); - } + @SuppressWarnings("unchecked") + public Environment add(Key key, T val) { + map.put((Key)key, val); + hidden.remove(key); + return this; + } + public Environment add(Key key) { + return add(key, null); + } + @SuppressWarnings("all") + public Environment addAll(Map, ?> map, boolean iterableAsMulti) { + map.putAll((Map)map); + hidden.removeAll(map.keySet()); + return this; + } + public Environment addAll(Map, ?> map) { + return addAll(map, true); + } - @SuppressWarnings("unchecked") - public Environment remove(Key key) { - map.remove(key); - hidden.add((Key)key); - return this; - } + @SuppressWarnings("unchecked") + public Environment remove(Key key) { + map.remove(key); + hidden.add((Key)key); + return this; + } - public T init(Key key, T val) { - if (!has(key)) this.add(key, val); - return val; - } - public T initFrom(Key key, Supplier val) { - if (!has(key)) { - var res = val.get(); - this.add(key, res); - return res; - } - else return get(key); - } + public T init(Key key, T val) { + if (!has(key)) this.add(key, val); + return val; + } + public T initFrom(Key key, Supplier val) { + if (!has(key)) { + var res = val.get(); + this.add(key, res); + return res; + } + else return get(key); + } - public Environment child() { - return new Environment(this); - } + public Environment child() { + return new Environment(this); + } - public Environment(Environment parent) { - this.parent = parent; - } - public Environment() { - this.parent = null; - } + public Environment(Environment parent) { + this.parent = parent; + } + public Environment() { + this.parent = null; + } - public static Environment wrap(Environment env) { - if (env == null) return empty(); - else return env; - } + public static Environment wrap(Environment env) { + if (env == null) return empty(); + else return env; + } - public static Environment empty() { - return new Environment(); - } + public static Environment empty() { + return new Environment(); + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/environment/Key.java b/src/main/java/me/topchetoeu/jscript/common/environment/Key.java index 60470dd..1ffb92a 100644 --- a/src/main/java/me/topchetoeu/jscript/common/environment/Key.java +++ b/src/main/java/me/topchetoeu/jscript/common/environment/Key.java @@ -1,7 +1,3 @@ package me.topchetoeu.jscript.common.environment; -public final class Key { - public static Key of() { - return new Key<>(); - } -} +public final class Key { } diff --git a/src/main/java/me/topchetoeu/jscript/common/json/JSON.java b/src/main/java/me/topchetoeu/jscript/common/json/JSON.java index e5dcce0..7e10b62 100644 --- a/src/main/java/me/topchetoeu/jscript/common/json/JSON.java +++ b/src/main/java/me/topchetoeu/jscript/common/json/JSON.java @@ -11,162 +11,162 @@ import me.topchetoeu.jscript.common.parsing.Parsing; import me.topchetoeu.jscript.common.parsing.Source; public class JSON { - public static ParseRes parseString(Source src, int i) { - var res = Parsing.parseString(src, i); - if (!res.isSuccess()) return res.chainError(); - return ParseRes.res(JSONElement.string(res.result), res.n); - } - public static ParseRes parseNumber(Source src, int i) { - var res = Parsing.parseNumber(src, i, true); - if (!res.isSuccess()) return res.chainError(); - else return ParseRes.res(JSONElement.number(res.result), res.n); - } - public static ParseRes parseLiteral(Source src, int i) { - var id = Parsing.parseIdentifier(src, i); + public static ParseRes parseString(Source src, int i) { + var res = Parsing.parseString(src, i); + if (!res.isSuccess()) return res.chainError(); + return ParseRes.res(JSONElement.string(res.result), res.n); + } + public static ParseRes parseNumber(Source src, int i) { + var res = Parsing.parseNumber(src, i, true); + if (!res.isSuccess()) return res.chainError(); + else return ParseRes.res(JSONElement.number(res.result), res.n); + } + public static ParseRes parseLiteral(Source src, int i) { + var id = Parsing.parseIdentifier(src, i); - if (!id.isSuccess()) return ParseRes.failed(); - else if (id.result.equals("true")) return ParseRes.res(JSONElement.bool(true), id.n); - else if (id.result.equals("false")) return ParseRes.res(JSONElement.bool(false), id.n); - else if (id.result.equals("null")) return ParseRes.res(JSONElement.NULL, id.n); - else return ParseRes.failed(); - } + if (!id.isSuccess()) return ParseRes.failed(); + else if (id.result.equals("true")) return ParseRes.res(JSONElement.bool(true), id.n); + else if (id.result.equals("false")) return ParseRes.res(JSONElement.bool(false), id.n); + else if (id.result.equals("null")) return ParseRes.res(JSONElement.NULL, id.n); + else return ParseRes.failed(); + } - public static ParseRes parseValue(Source src, int i) { - return ParseRes.first(src, i, - JSON::parseString, - JSON::parseNumber, - JSON::parseLiteral, - JSON::parseMap, - JSON::parseList - ); - } + public static ParseRes parseValue(Source src, int i) { + return ParseRes.first(src, i, + JSON::parseString, + JSON::parseNumber, + JSON::parseLiteral, + JSON::parseMap, + JSON::parseList + ); + } - public static ParseRes parseMap(Source src, int i) { - var n = Parsing.skipEmpty(src, i); + public static ParseRes parseMap(Source src, int i) { + var n = Parsing.skipEmpty(src, i); - if (!src.is(i + n, "{")) return ParseRes.failed(); - n++; + if (!src.is(i + n, "{")) return ParseRes.failed(); + n++; - var values = new JSONMap(); + var values = new JSONMap(); - if (src.is(i + n, "}")) return ParseRes.res(new JSONMap(new HashMap<>()), n + 1); - while (true) { - var name = parseString(src, i + n); - if (!name.isSuccess()) return name.chainError(src.loc(i + n), "Expected an index"); - n += name.n; - n += Parsing.skipEmpty(src, i + n); + if (src.is(i + n, "}")) return ParseRes.res(new JSONMap(new HashMap<>()), n + 1); + while (true) { + var name = parseString(src, i + n); + if (!name.isSuccess()) return name.chainError(src.loc(i + n), "Expected an index"); + n += name.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ":")) return name.chainError(src.loc(i + n), "Expected a colon"); - n++; + if (!src.is(i + n, ":")) return name.chainError(src.loc(i + n), "Expected a colon"); + n++; - var res = parseValue(src, i + n); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected a list element"); - values.put(name.result.toString(), res.result); - n += res.n; - n += Parsing.skipEmpty(src, i + n); + var res = parseValue(src, i + n); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected a list element"); + values.put(name.result.toString(), res.result); + n += res.n; + n += Parsing.skipEmpty(src, i + n); - if (src.is(i + n, ",")) n++; - else if (src.is(i + n, "}")) { - n++; - break; - } - } + if (src.is(i + n, ",")) n++; + else if (src.is(i + n, "}")) { + n++; + break; + } + } - return ParseRes.res(values, n); - } - public static ParseRes parseList(Source src, int i) { - var n = Parsing.skipEmpty(src, i); + return ParseRes.res(values, n); + } + public static ParseRes parseList(Source src, int i) { + var n = Parsing.skipEmpty(src, i); - if (!src.is(i + n++, "[]")) return ParseRes.failed(); + if (!src.is(i + n++, "[]")) return ParseRes.failed(); - var values = new JSONList(); + var values = new JSONList(); - if (src.is(i + n, "]")) return ParseRes.res(new JSONList(), n + 1); - while (true) { - var res = parseValue(src, i + n); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected a list element"); - values.add(res.result); - n += res.n; - n += Parsing.skipEmpty(src, i + n); + if (src.is(i + n, "]")) return ParseRes.res(new JSONList(), n + 1); + while (true) { + var res = parseValue(src, i + n); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected a list element"); + values.add(res.result); + n += res.n; + n += Parsing.skipEmpty(src, i + n); - if (src.is(i + n, ",")) n++; - else if (src.is(i + n, "]")) { - n++; - break; - } - } + if (src.is(i + n, ",")) n++; + else if (src.is(i + n, "]")) { + n++; + break; + } + } - return ParseRes.res(values, n); - } - public static JSONElement parse(Filename filename, String raw) { - if (filename == null) filename = new Filename("jscript", "json"); + return ParseRes.res(values, n); + } + public static JSONElement parse(Filename filename, String raw) { + if (filename == null) filename = new Filename("jscript", "json"); - var res = parseValue(new Source(null, filename, raw), 0); - if (res.isFailed()) throw new SyntaxException(null, "Invalid JSON given"); - else if (res.isError()) throw new SyntaxException(null, res.error); - else return JSONElement.of(res.result); - } + var res = parseValue(new Source(null, filename, raw), 0); + if (res.isFailed()) throw new SyntaxException(null, "Invalid JSON given"); + else if (res.isError()) throw new SyntaxException(null, res.error); + else return JSONElement.of(res.result); + } - public static String stringify(JSONElement el) { - if (el.isNumber()) { - var d = el.number(); - if (d == Double.NEGATIVE_INFINITY) return "-Infinity"; - if (d == Double.POSITIVE_INFINITY) return "Infinity"; - if (Double.isNaN(d)) return "NaN"; - return BigDecimal.valueOf(d).stripTrailingZeros().toPlainString(); - } - if (el.isBoolean()) return el.bool() ? "true" : "false"; - if (el.isNull()) return "null"; - if (el.isString()) { - var res = new StringBuilder("\""); - var alphabet = "0123456789ABCDEF".toCharArray(); + public static String stringify(JSONElement el) { + if (el.isNumber()) { + var d = el.number(); + if (d == Double.NEGATIVE_INFINITY) return "-Infinity"; + if (d == Double.POSITIVE_INFINITY) return "Infinity"; + if (Double.isNaN(d)) return "NaN"; + return BigDecimal.valueOf(d).stripTrailingZeros().toPlainString(); + } + if (el.isBoolean()) return el.bool() ? "true" : "false"; + if (el.isNull()) return "null"; + if (el.isString()) { + var res = new StringBuilder("\""); + var alphabet = "0123456789ABCDEF".toCharArray(); - for (var c : el.string().toCharArray()) { - if (c < 32 || c >= 127) { - res - .append("\\u") - .append(alphabet[(c >> 12) & 0xF]) - .append(alphabet[(c >> 8) & 0xF]) - .append(alphabet[(c >> 4) & 0xF]) - .append(alphabet[(c >> 0) & 0xF]); - } - else if (c == '\\') - res.append("\\\\"); - else if (c == '"') - res.append("\\\""); - else res.append(c); - } + for (var c : el.string().toCharArray()) { + if (c < 32 || c >= 127) { + res + .append("\\u") + .append(alphabet[(c >> 12) & 0xF]) + .append(alphabet[(c >> 8) & 0xF]) + .append(alphabet[(c >> 4) & 0xF]) + .append(alphabet[(c >> 0) & 0xF]); + } + else if (c == '\\') + res.append("\\\\"); + else if (c == '"') + res.append("\\\""); + else res.append(c); + } - return res.append('"').toString(); - } - if (el.isList()) { - var res = new StringBuilder().append("["); - for (int i = 0; i < el.list().size(); i++) { - if (i != 0) res.append(","); - res.append(stringify(el.list().get(i))); - } - res.append("]"); - return res.toString(); - } - if (el.isMap()) { - var res = new StringBuilder().append("{"); - var entries = el.map().entrySet().stream().collect(Collectors.toList()); + return res.append('"').toString(); + } + if (el.isList()) { + var res = new StringBuilder().append("["); + for (int i = 0; i < el.list().size(); i++) { + if (i != 0) res.append(","); + res.append(stringify(el.list().get(i))); + } + res.append("]"); + return res.toString(); + } + if (el.isMap()) { + var res = new StringBuilder().append("{"); + var entries = el.map().entrySet().stream().collect(Collectors.toList()); - for (int i = 0; i < entries.size(); i++) { - if (i != 0) res.append(","); - res.append(stringify(JSONElement.string(entries.get(i).getKey()))); - res.append(":"); - res.append(stringify(entries.get(i).getValue())); - } - res.append("}"); - return res.toString(); - } - return null; - } - public static String stringify(JSONMap map) { - return stringify(JSONElement.of(map)); - } - public static String stringify(JSONList list) { - return stringify(JSONElement.of(list)); - } + for (int i = 0; i < entries.size(); i++) { + if (i != 0) res.append(","); + res.append(stringify(JSONElement.string(entries.get(i).getKey()))); + res.append(":"); + res.append(stringify(entries.get(i).getValue())); + } + res.append("}"); + return res.toString(); + } + return null; + } + public static String stringify(JSONMap map) { + return stringify(JSONElement.of(map)); + } + public static String stringify(JSONList list) { + return stringify(JSONElement.of(list)); + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/json/JSONElement.java b/src/main/java/me/topchetoeu/jscript/common/json/JSONElement.java index 258497e..a504663 100644 --- a/src/main/java/me/topchetoeu/jscript/common/json/JSONElement.java +++ b/src/main/java/me/topchetoeu/jscript/common/json/JSONElement.java @@ -1,87 +1,87 @@ package me.topchetoeu.jscript.common.json; public class JSONElement { - public static enum Type { - STRING, - NUMBER, - BOOLEAN, - NULL, - LIST, - MAP, - } + public static enum Type { + STRING, + NUMBER, + BOOLEAN, + NULL, + LIST, + MAP, + } - public static final JSONElement NULL = new JSONElement(Type.NULL, null); + public static final JSONElement NULL = new JSONElement(Type.NULL, null); - public static JSONElement map(JSONMap val) { - return new JSONElement(Type.MAP, val); - } - public static JSONElement list(JSONList val) { - return new JSONElement(Type.LIST, val); - } - public static JSONElement string(String val) { - return new JSONElement(Type.STRING, val); - } - public static JSONElement number(double val) { - return new JSONElement(Type.NUMBER, val); - } - public static JSONElement bool(boolean val) { - return new JSONElement(Type.BOOLEAN, val); - } + public static JSONElement map(JSONMap val) { + return new JSONElement(Type.MAP, val); + } + public static JSONElement list(JSONList val) { + return new JSONElement(Type.LIST, val); + } + public static JSONElement string(String val) { + return new JSONElement(Type.STRING, val); + } + public static JSONElement number(double val) { + return new JSONElement(Type.NUMBER, val); + } + public static JSONElement bool(boolean val) { + return new JSONElement(Type.BOOLEAN, val); + } - public static JSONElement of(Object val) { - if (val instanceof JSONMap) return map((JSONMap)val); - else if (val instanceof JSONList) return list((JSONList)val); - else if (val instanceof String) return string((String)val); - else if (val instanceof Boolean) return bool((Boolean)val); - else if (val instanceof Number) return number(((Number)val).doubleValue()); - else if (val == null) return NULL; - else throw new IllegalArgumentException("val must be: String, Boolean, Number, JSONList or JSONMap"); - } + public static JSONElement of(Object val) { + if (val instanceof JSONMap) return map((JSONMap)val); + else if (val instanceof JSONList) return list((JSONList)val); + else if (val instanceof String) return string((String)val); + else if (val instanceof Boolean) return bool((Boolean)val); + else if (val instanceof Number) return number(((Number)val).doubleValue()); + else if (val == null) return NULL; + else throw new IllegalArgumentException("val must be: String, Boolean, Number, JSONList or JSONMap"); + } - public final Type type; - private final Object value; + public final Type type; + private final Object value; - public boolean isMap() { return type == Type.MAP; } - public boolean isList() { return type == Type.LIST; } - public boolean isString() { return type == Type.STRING; } - public boolean isNumber() { return type == Type.NUMBER; } - public boolean isBoolean() { return type == Type.BOOLEAN; } - public boolean isNull() { return type == Type.NULL; } + public boolean isMap() { return type == Type.MAP; } + public boolean isList() { return type == Type.LIST; } + public boolean isString() { return type == Type.STRING; } + public boolean isNumber() { return type == Type.NUMBER; } + public boolean isBoolean() { return type == Type.BOOLEAN; } + public boolean isNull() { return type == Type.NULL; } - public JSONMap map() { - if (!isMap()) throw new IllegalStateException("Element is not a map"); - return (JSONMap)value; - } - public JSONList list() { - if (!isList()) throw new IllegalStateException("Element is not a map"); - return (JSONList)value; - } - public String string() { - if (!isString()) throw new IllegalStateException("Element is not a string"); - return (String)value; - } - public double number() { - if (!isNumber()) throw new IllegalStateException("Element is not a number"); - return (double)value; - } - public boolean bool() { - if (!isBoolean()) throw new IllegalStateException("Element is not a boolean"); - return (boolean)value; - } + public JSONMap map() { + if (!isMap()) throw new IllegalStateException("Element is not a map"); + return (JSONMap)value; + } + public JSONList list() { + if (!isList()) throw new IllegalStateException("Element is not a map"); + return (JSONList)value; + } + public String string() { + if (!isString()) throw new IllegalStateException("Element is not a string"); + return (String)value; + } + public double number() { + if (!isNumber()) throw new IllegalStateException("Element is not a number"); + return (double)value; + } + public boolean bool() { + if (!isBoolean()) throw new IllegalStateException("Element is not a boolean"); + return (boolean)value; + } - @Override public String toString() { - if (isMap()) return "{...}"; - if (isList()) return "[...]"; - if (isString()) return (String)value; - if (isString()) return (String)value; - if (isNumber()) return (double)value + ""; - if (isBoolean()) return (boolean)value + ""; - if (isNull()) return "null"; - return ""; - } + @Override public String toString() { + if (isMap()) return "{...}"; + if (isList()) return "[...]"; + if (isString()) return (String)value; + if (isString()) return (String)value; + if (isNumber()) return (double)value + ""; + if (isBoolean()) return (boolean)value + ""; + if (isNull()) return "null"; + return ""; + } - private JSONElement(Type type, Object val) { - this.type = type; - this.value = val; - } + private JSONElement(Type type, Object val) { + this.type = type; + this.value = val; + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/json/JSONList.java b/src/main/java/me/topchetoeu/jscript/common/json/JSONList.java index e18ba73..fb6c907 100644 --- a/src/main/java/me/topchetoeu/jscript/common/json/JSONList.java +++ b/src/main/java/me/topchetoeu/jscript/common/json/JSONList.java @@ -6,21 +6,21 @@ import java.util.Collection; import java.util.Map; public class JSONList extends ArrayList { - public JSONList() {} - public JSONList(JSONElement ...els) { - super(Arrays.asList(els)); - } - public JSONList(Collection els) { - super(els); - } + public JSONList() {} + public JSONList(JSONElement ...els) { + super(Arrays.asList(els)); + } + public JSONList(Collection els) { + super(els); + } - public JSONList addNull() { this.add(JSONElement.NULL); return this; } - public JSONList add(String val) { this.add(JSONElement.of(val)); return this; } - public JSONList add(double val) { this.add(JSONElement.of(val)); return this; } - public JSONList add(boolean val) { this.add(JSONElement.of(val)); return this; } - public JSONList add(Map val) { this.add(JSONElement.of(val)); return this; } - public JSONList add(Collection val) { this.add(JSONElement.of(val)); return this; } - public JSONList add(JSONMap val) { this.add(JSONElement.of(val)); return this; } - public JSONList add(JSONList val) { this.add(JSONElement.of(val)); return this; } + public JSONList addNull() { this.add(JSONElement.NULL); return this; } + public JSONList add(String val) { this.add(JSONElement.of(val)); return this; } + public JSONList add(double val) { this.add(JSONElement.of(val)); return this; } + public JSONList add(boolean val) { this.add(JSONElement.of(val)); return this; } + public JSONList add(Map val) { this.add(JSONElement.of(val)); return this; } + public JSONList add(Collection val) { this.add(JSONElement.of(val)); return this; } + public JSONList add(JSONMap val) { this.add(JSONElement.of(val)); return this; } + public JSONList add(JSONList val) { this.add(JSONElement.of(val)); return this; } } diff --git a/src/main/java/me/topchetoeu/jscript/common/json/JSONMap.java b/src/main/java/me/topchetoeu/jscript/common/json/JSONMap.java index 2906910..3659348 100644 --- a/src/main/java/me/topchetoeu/jscript/common/json/JSONMap.java +++ b/src/main/java/me/topchetoeu/jscript/common/json/JSONMap.java @@ -6,133 +6,131 @@ import java.util.Map; import java.util.Set; public class JSONMap implements Map { - private Map elements = new HashMap<>(); + private Map elements = new HashMap<>(); - public JSONElement get(String path) { - var curr = this; - var segs = path.split("\\."); - var i = 0; + public JSONElement get(String path) { + JSONElement curr = JSONElement.map(this); - while (true) { - var tmp = curr.elements.get(segs[i++]); - if (i == segs.length) return tmp; - if (!tmp.isMap()) return null; - curr = tmp.map(); - } - } + for (var seg : path.split("\\.")) { + if (!curr.isMap()) return null; + curr = curr.map().elements.get(seg); + } - public boolean isMap(String path) { - var el = get(path); - return el != null && el.isMap(); - } - public boolean isList(String path) { - var el = get(path); - return el != null && el.isList(); - } - public boolean isString(String path) { - var el = get(path); - return el != null && el.isString(); - } - public boolean isNumber(String path) { - var el = get(path); - return el != null && el.isNumber(); - } - public boolean isBoolean(String path) { - var el = get(path); - return el != null && el.isBoolean(); - } - public boolean isNull(String path) { - var el = get(path); - return el != null && el.isNull(); - } - public boolean contains(String path) { - return get(path) != null; - } + return curr; + } - public JSONMap map(String path) { - var el = get(path); - if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist", path)); - return el.map(); - } - public JSONMap map(String path, JSONMap defaultVal) { - var el = get(path); - if (el == null) return defaultVal; - if (el.isMap()) return el.map(); - return defaultVal; - } + public boolean isMap(String path) { + var el = get(path); + return el != null && el.isMap(); + } + public boolean isList(String path) { + var el = get(path); + return el != null && el.isList(); + } + public boolean isString(String path) { + var el = get(path); + return el != null && el.isString(); + } + public boolean isNumber(String path) { + var el = get(path); + return el != null && el.isNumber(); + } + public boolean isBoolean(String path) { + var el = get(path); + return el != null && el.isBoolean(); + } + public boolean isNull(String path) { + var el = get(path); + return el != null && el.isNull(); + } + public boolean contains(String path) { + return get(path) != null; + } - public JSONList list(String path) { - var el = get(path); - if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist", path)); - return el.list(); - } - public JSONList list(String path, JSONList defaultVal) { - var el = get(path); - if (el == null) return defaultVal; - if (el.isList()) return el.list(); - return defaultVal; - } + public JSONMap map(String path) { + var el = get(path); + if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist", path)); + return el.map(); + } + public JSONMap map(String path, JSONMap defaultVal) { + var el = get(path); + if (el == null) return defaultVal; + if (el.isMap()) return el.map(); + return defaultVal; + } - public String string(String path) { - var el = get(path); - if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist", path)); - return el.string(); - } - public String string(String path, String defaultVal) { - var el = get(path); - if (el == null) return defaultVal; - if (el.isString()) return el.string(); - return defaultVal; - } + public JSONList list(String path) { + var el = get(path); + if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist", path)); + return el.list(); + } + public JSONList list(String path, JSONList defaultVal) { + var el = get(path); + if (el == null) return defaultVal; + if (el.isList()) return el.list(); + return defaultVal; + } - public double number(String path) { - var el = get(path); - if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist", path)); - return el.number(); - } - public double number(String path, double defaultVal) { - var el = get(path); - if (el == null) return defaultVal; - if (el.isNumber()) return el.number(); - return defaultVal; - } + public String string(String path) { + var el = get(path); + if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist", path)); + return el.string(); + } + public String string(String path, String defaultVal) { + var el = get(path); + if (el == null) return defaultVal; + if (el.isString()) return el.string(); + return defaultVal; + } - public boolean bool(String path) { - var el = get(path); - if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist", path)); - return el.bool(); - } - public boolean bool(String path, boolean defaultVal) { - var el = get(path); - if (el == null) return defaultVal; - if (el.isBoolean()) return el.bool(); - return defaultVal; - } + public double number(String path) { + var el = get(path); + if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist", path)); + return el.number(); + } + public double number(String path, double defaultVal) { + var el = get(path); + if (el == null) return defaultVal; + if (el.isNumber()) return el.number(); + return defaultVal; + } - public JSONMap setNull(String key) { elements.put(key, JSONElement.NULL); return this; } - public JSONMap set(String key, String val) { elements.put(key, JSONElement.of(val)); return this; } - public JSONMap set(String key, double val) { elements.put(key, JSONElement.of(val)); return this; } - public JSONMap set(String key, boolean val) { elements.put(key, JSONElement.of(val)); return this; } - public JSONMap set(String key, Map val) { elements.put(key, JSONElement.of(val)); return this; } - public JSONMap set(String key, Collection val) { elements.put(key, JSONElement.of(val)); return this; } + public boolean bool(String path) { + var el = get(path); + if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist", path)); + return el.bool(); + } + public boolean bool(String path, boolean defaultVal) { + var el = get(path); + if (el == null) return defaultVal; + if (el.isBoolean()) return el.bool(); + return defaultVal; + } - @Override public int size() { return elements.size(); } - @Override public boolean isEmpty() { return elements.isEmpty(); } - @Override public boolean containsKey(Object key) { return elements.containsKey(key); } - @Override public boolean containsValue(Object value) { return elements.containsValue(value); } - @Override public JSONElement get(Object key) { return elements.get(key); } - @Override public JSONElement put(String key, JSONElement value) { return elements.put(key, value); } - @Override public JSONElement remove(Object key) { return elements.remove(key); } - @Override public void putAll(Map m) { elements.putAll(m); } + public JSONMap setNull(String key) { elements.put(key, JSONElement.NULL); return this; } + public JSONMap set(String key, String val) { elements.put(key, JSONElement.of(val)); return this; } + public JSONMap set(String key, double val) { elements.put(key, JSONElement.of(val)); return this; } + public JSONMap set(String key, boolean val) { elements.put(key, JSONElement.of(val)); return this; } + public JSONMap set(String key, Map val) { elements.put(key, JSONElement.of(val)); return this; } + public JSONMap set(String key, Collection val) { elements.put(key, JSONElement.of(val)); return this; } - @Override public void clear() { elements.clear(); } + @Override public int size() { return elements.size(); } + @Override public boolean isEmpty() { return elements.isEmpty(); } + @Override public boolean containsKey(Object key) { return elements.containsKey(key); } + @Override public boolean containsValue(Object value) { return elements.containsValue(value); } + @Override public JSONElement get(Object key) { return elements.get(key); } + @Override public JSONElement put(String key, JSONElement value) { return elements.put(key, value); } + @Override public JSONElement remove(Object key) { return elements.remove(key); } + @Override public void putAll(Map m) { elements.putAll(m); } - @Override public Set keySet() { return elements.keySet(); } - @Override public Collection values() { return elements.values(); } - @Override public Set> entrySet() { return elements.entrySet(); } + @Override public void clear() { elements.clear(); } - public JSONMap() { } - public JSONMap(Map els) { - this.elements = new HashMap<>(els); - } + @Override public Set keySet() { return elements.keySet(); } + @Override public Collection values() { return elements.values(); } + @Override public Set> entrySet() { return elements.entrySet(); } + + public JSONMap() { } + public JSONMap(Map els) { + this.elements = new HashMap<>(els); + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/mapping/ConvertType.java b/src/main/java/me/topchetoeu/jscript/common/mapping/ConvertType.java deleted file mode 100644 index 22ff59b..0000000 --- a/src/main/java/me/topchetoeu/jscript/common/mapping/ConvertType.java +++ /dev/null @@ -1,8 +0,0 @@ -package me.topchetoeu.jscript.common.mapping; - -public enum ConvertType { - Exact, - Lower, - Upper, - Both, -} diff --git a/src/main/java/me/topchetoeu/jscript/common/mapping/FunctionMap.java b/src/main/java/me/topchetoeu/jscript/common/mapping/FunctionMap.java index 07f301c..71fe2ac 100644 --- a/src/main/java/me/topchetoeu/jscript/common/mapping/FunctionMap.java +++ b/src/main/java/me/topchetoeu/jscript/common/mapping/FunctionMap.java @@ -17,172 +17,150 @@ import me.topchetoeu.jscript.common.parsing.Filename; import me.topchetoeu.jscript.common.parsing.Location; public class FunctionMap { - public static class FunctionMapBuilder { - private final TreeMap sourceMap = new TreeMap<>(); - private final HashMap breakpoints = new HashMap<>(); + public static class FunctionMapBuilder { + private final TreeMap sourceMap = new TreeMap<>(); + private final HashMap breakpoints = new HashMap<>(); - public Location toLocation(int pc) { - return sourceMap.headMap(pc, true).firstEntry().getValue(); - } + public Location toLocation(int pc) { + return sourceMap.headMap(pc, true).firstEntry().getValue(); + } - public FunctionMapBuilder setDebug(Location loc, BreakpointType type) { - if (loc == null || type == null || type == BreakpointType.NONE) return this; - breakpoints.put(loc, type); - return this; - } - public FunctionMapBuilder setLocation(int i, Location loc) { - if (loc == null || i < 0) return this; - sourceMap.put(i, loc); - return this; - } - public FunctionMapBuilder setLocationAndDebug(int i, Location loc, BreakpointType type) { - setDebug(loc, type); - setLocation(i, loc); - return this; - } + public FunctionMapBuilder setDebug(Location loc, BreakpointType type) { + if (loc == null || type == null || type == BreakpointType.NONE) return this; + breakpoints.put(loc, type); + return this; + } + public FunctionMapBuilder setLocation(int i, Location loc) { + if (loc == null || i < 0) return this; + sourceMap.put(i, loc); + return this; + } + public FunctionMapBuilder setLocationAndDebug(int i, Location loc, BreakpointType type) { + setDebug(loc, type); + setLocation(i, loc); + return this; + } - public Location first() { - if (sourceMap.size() == 0) return null; - return sourceMap.firstEntry().getValue(); - } - public Location last() { - if (sourceMap.size() == 0) return null; - return sourceMap.lastEntry().getValue(); - } + public Location first() { + if (sourceMap.size() == 0) return null; + return sourceMap.firstEntry().getValue(); + } + public Location last() { + if (sourceMap.size() == 0) return null; + return sourceMap.lastEntry().getValue(); + } - public FunctionMap build(String[] localNames, String[] captureNames) { - return new FunctionMap(sourceMap, breakpoints, localNames, captureNames); - } - public FunctionMap build() { - return new FunctionMap(sourceMap, breakpoints, new String[0], new String[0]); - } + public FunctionMap build(String[] localNames, String[] captureNames) { + return new FunctionMap(sourceMap, breakpoints, localNames, captureNames); + } + public FunctionMap build() { + return new FunctionMap(sourceMap, breakpoints, new String[0], new String[0]); + } - private FunctionMapBuilder() { } - } + private FunctionMapBuilder() { } + } - public static final FunctionMap EMPTY = new FunctionMap(); + public static final FunctionMap EMPTY = new FunctionMap(); - private final HashMap bps = new HashMap<>(); - private final HashMap> bpLocs = new HashMap<>(); + private final HashMap bps = new HashMap<>(); + private final HashMap> bpLocs = new HashMap<>(); - private final TreeMap pcToLoc = new TreeMap<>(); + private final TreeMap pcToLoc = new TreeMap<>(); - public final String[] localNames, captureNames; + public final String[] localNames, captureNames; - public Location toLocation(int pc, boolean approxiamte) { - if (pcToLoc.size() == 0 || pc < 0 || pc > pcToLoc.lastKey()) return null; - var res = pcToLoc.get(pc); - if (!approxiamte || res != null) return res; - var entry = pcToLoc.headMap(pc, true).lastEntry(); - if (entry == null) return null; - else return entry.getValue(); - } - public Location toLocation(int pc) { - return toLocation(pc, false); - } + public Location toLocation(int pc, boolean approxiamte) { + if (pcToLoc.size() == 0 || pc < 0 || pc > pcToLoc.lastKey()) return null; + var res = pcToLoc.get(pc); + if (!approxiamte || res != null) return res; + var entry = pcToLoc.headMap(pc, true).lastEntry(); + if (entry == null) return null; + else return entry.getValue(); + } + public Location toLocation(int pc) { + return toLocation(pc, false); + } - public BreakpointType getBreakpoint(int pc) { - return bps.getOrDefault(pc, BreakpointType.NONE); - } - public Location correctBreakpoint(Location loc) { - var set = bpLocs.get(loc.filename()); - if (set == null) return null; - else return set.ceiling(loc); - } - public List correctBreakpoint(Pattern filename, int line, int column) { - var candidates = new HashMap>(); + public BreakpointType getBreakpoint(int pc) { + return bps.getOrDefault(pc, BreakpointType.NONE); + } + public Location correctBreakpoint(Location loc) { + var set = bpLocs.get(loc.filename()); + if (set == null) return null; + else return set.ceiling(loc); + } + public List correctBreakpoint(Pattern filename, int line, int column) { + var candidates = new HashMap>(); - for (var name : bpLocs.keySet()) { - if (filename.matcher(name.toString()).matches()) { - candidates.put(name, bpLocs.get(name)); - } - } + for (var name : bpLocs.keySet()) { + if (filename.matcher(name.toString()).matches()) { + candidates.put(name, bpLocs.get(name)); + } + } - var res = new ArrayList(candidates.size()); - for (var candidate : candidates.entrySet()) { - var val = correctBreakpoint(Location.of(candidate.getKey(), line, column)); - if (val == null) continue; - res.add(val); - } + var res = new ArrayList(candidates.size()); + for (var candidate : candidates.entrySet()) { + var val = correctBreakpoint(Location.of(candidate.getKey(), line, column)); + if (val == null) continue; + res.add(val); + } - return res; - } - public List breakpoints(Location start, Location end) { - if (!Objects.equals(start.filename(), end.filename())) return Arrays.asList(); - NavigableSet set = bpLocs.get(start.filename()); - if (set == null) return Arrays.asList(); + return res; + } + public List breakpoints(Location start, Location end) { + if (!Objects.equals(start.filename(), end.filename())) return Arrays.asList(); + NavigableSet set = bpLocs.get(start.filename()); + if (set == null) return Arrays.asList(); - if (start != null) set = set.tailSet(start, true); - if (end != null) set = set.headSet(end, true); + if (start != null) set = set.tailSet(start, true); + if (end != null) set = set.headSet(end, true); - return set.stream().collect(Collectors.toList()); - } + return set.stream().collect(Collectors.toList()); + } - public Location start() { - if (pcToLoc.size() == 0) return null; - return pcToLoc.firstEntry().getValue(); - } - public Location end() { - if (pcToLoc.size() == 0) return null; - return pcToLoc.lastEntry().getValue(); - } + public Location start() { + if (pcToLoc.size() == 0) return null; + return pcToLoc.firstEntry().getValue(); + } + public Location end() { + if (pcToLoc.size() == 0) return null; + return pcToLoc.lastEntry().getValue(); + } - // public static FunctionMap apply(FunctionMap funcMap, SourceMap map) { - // var res = new FunctionMap(Map.of(), Map.of(), funcMap.localNames, funcMap.captureNames); + public FunctionMap clone() { + var res = new FunctionMap(new HashMap<>(), new HashMap<>(), localNames, captureNames); + res.pcToLoc.putAll(this.pcToLoc); + res.bps.putAll(bps); + res.bpLocs.putAll(bpLocs); + res.pcToLoc.putAll(pcToLoc); + return res; + } - // for (var el : funcMap.pcToLoc.entrySet()) { - // res.pcToLoc.put(el.getKey(), map.toCompiled(el.getValue())); - // } + public FunctionMap(Map map, Map breakpoints, String[] localNames, String[] captureNames) { + var locToPc = new HashMap(); - // res.bps.putAll(bps); + for (var el : map.entrySet()) { + pcToLoc.put(el.getKey(), el.getValue()); + locToPc.putIfAbsent(el.getValue(), el.getKey()); + } - // for (var el : bpLocs.entrySet()) { - // for (var loc : el.getValue()) { - // loc = map.toCompiled(loc); - // if (loc == null) continue; + for (var el : breakpoints.entrySet()) { + if (el.getValue() == null || el.getValue() == BreakpointType.NONE) continue; + bps.put(locToPc.get(el.getKey()), el.getValue()); - // if (!res.bpLocs.containsKey(loc.filename())) res.bpLocs.put(loc.filename(), new TreeSet<>()); - // res.bpLocs.get(loc.filename()).add(loc); - // } - // } + if (!bpLocs.containsKey(el.getKey().filename())) bpLocs.put(el.getKey().filename(), new TreeSet<>()); + bpLocs.get(el.getKey().filename()).add(el.getKey()); + } - // return res; - // } + this.localNames = localNames; + this.captureNames = captureNames; + } + private FunctionMap() { + localNames = new String[0]; + captureNames = new String[0]; + } - public FunctionMap clone() { - var res = new FunctionMap(new HashMap<>(), new HashMap<>(), localNames, captureNames); - res.pcToLoc.putAll(this.pcToLoc); - res.bps.putAll(bps); - res.bpLocs.putAll(bpLocs); - res.pcToLoc.putAll(pcToLoc); - return res; - } - - public FunctionMap(Map map, Map breakpoints, String[] localNames, String[] captureNames) { - var locToPc = new HashMap(); - - for (var el : map.entrySet()) { - pcToLoc.put(el.getKey(), el.getValue()); - locToPc.putIfAbsent(el.getValue(), el.getKey()); - } - - for (var el : breakpoints.entrySet()) { - if (el.getValue() == null || el.getValue() == BreakpointType.NONE) continue; - bps.put(locToPc.get(el.getKey()), el.getValue()); - - if (!bpLocs.containsKey(el.getKey().filename())) bpLocs.put(el.getKey().filename(), new TreeSet<>()); - bpLocs.get(el.getKey().filename()).add(el.getKey()); - } - - this.localNames = localNames; - this.captureNames = captureNames; - } - private FunctionMap() { - localNames = new String[0]; - captureNames = new String[0]; - } - - public static FunctionMapBuilder builder() { - return new FunctionMapBuilder(); - } + public static FunctionMapBuilder builder() { + return new FunctionMapBuilder(); + } } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/common/parsing/Filename.java b/src/main/java/me/topchetoeu/jscript/common/parsing/Filename.java index 890b8e9..39902e2 100644 --- a/src/main/java/me/topchetoeu/jscript/common/parsing/Filename.java +++ b/src/main/java/me/topchetoeu/jscript/common/parsing/Filename.java @@ -3,57 +3,51 @@ package me.topchetoeu.jscript.common.parsing; import java.io.File; public class Filename { - public final String protocol; - public final String path; + public final String protocol; + public final String path; - @Override public String toString() { - return protocol + "://" + path; - } - @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + protocol.hashCode(); - result = prime * result + path.hashCode(); - return result; - } - @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; + @Override public String toString() { + return protocol + "://" + path; + } + @Override public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + protocol.hashCode(); + result = prime * result + path.hashCode(); + return result; + } + @Override public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; - var other = (Filename) obj; + var other = (Filename) obj; - if (protocol == null) { - if (other.protocol != null) return false; - } - else if (!protocol.equals(other.protocol)) return false; + if (protocol == null) { + if (other.protocol != null) return false; + } + else if (!protocol.equals(other.protocol)) return false; - if (path == null) { - if (other.path != null) return false; - } - else if (!path.equals(other.path)) return false; - return true; - } + if (path == null) { + if (other.path != null) return false; + } + else if (!path.equals(other.path)) return false; + return true; + } - public Filename(String protocol, String path) { - path = path.trim(); - protocol = protocol.trim(); - this.protocol = protocol; - this.path = path; - } + public Filename(String protocol, String path) { + path = path.trim(); + protocol = protocol.trim(); + this.protocol = protocol; + this.path = path; + } - public static Filename parse(String val) { - var i = val.indexOf("://"); - if (i >= 0) return new Filename(val.substring(0, i).trim(), val.substring(i + 3).trim()); - else return new Filename("file", val.trim()); - } - // public static Path normalize(String path) { - // // File file = new File("/" + path.trim().replace("\\", "/")); - // // String normalizedPath = new File("/" + path.trim().replace("\\", "/")).getAbsolutePath().replaceFirst("^/", "").replace("\\", "/"); - // // return normalizedPath; - // return Path.of(Path.of("/" + path.trim().replace("\\", "/")).normalize().toString().substring(1)); - // } - public static Filename fromFile(File file) { - return new Filename("file", file.getAbsolutePath()); - } + public static Filename parse(String val) { + var i = val.indexOf("://"); + if (i >= 0) return new Filename(val.substring(0, i).trim(), val.substring(i + 3).trim()); + else return new Filename("file", val.trim()); + } + public static Filename fromFile(File file) { + return new Filename("file", file.getAbsolutePath()); + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/parsing/Location.java b/src/main/java/me/topchetoeu/jscript/common/parsing/Location.java index 1d86866..0bdf048 100644 --- a/src/main/java/me/topchetoeu/jscript/common/parsing/Location.java +++ b/src/main/java/me/topchetoeu/jscript/common/parsing/Location.java @@ -4,105 +4,105 @@ import java.util.ArrayList; import java.util.Objects; public abstract class Location implements Comparable { - public static final Location INTERNAL = Location.of(new Filename("jscript", "native"), -1, -1); + public static final Location INTERNAL = Location.of(new Filename("jscript", "native"), -1, -1); - public abstract int line(); - public abstract int start(); - public abstract Filename filename(); + public abstract int line(); + public abstract int start(); + public abstract Filename filename(); - public final String toString() { - var res = new ArrayList(); + public final String toString() { + var res = new ArrayList(); - if (filename() != null) res.add(filename().toString()); - if (line() >= 0) res.add(line() + 1 + ""); - if (start() >= 0) res.add(start() + 1 + ""); + if (filename() != null) res.add(filename().toString()); + if (line() >= 0) res.add(line() + 1 + ""); + if (start() >= 0) res.add(start() + 1 + ""); - return String.join(":", res); - } + return String.join(":", res); + } - public final Location add(int n) { - var self = this; + public final Location add(int n) { + var self = this; - return new Location() { - @Override public Filename filename() { return self.filename(); } - @Override public int start() { return self.start() + n; } - @Override public int line() { return self.line(); } - }; - } - public final Location nextLine() { - var self = this; + return new Location() { + @Override public Filename filename() { return self.filename(); } + @Override public int start() { return self.start() + n; } + @Override public int line() { return self.line(); } + }; + } + public final Location nextLine() { + var self = this; - return new Location() { - @Override public Filename filename() { return self.filename(); } - @Override public int start() { return 0; } - @Override public int line() { return self.line() + 1; } - }; - } + return new Location() { + @Override public Filename filename() { return self.filename(); } + @Override public int start() { return 0; } + @Override public int line() { return self.line() + 1; } + }; + } - @Override public int hashCode() { - return Objects.hash(line(), start(), filename()); - } - @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof Location)) return false; - var other = (Location)obj; + @Override public int hashCode() { + return Objects.hash(line(), start(), filename()); + } + @Override public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof Location)) return false; + var other = (Location)obj; - if (!Objects.equals(this.start(), other.start())) return false; - if (!Objects.equals(this.line(), other.line())) return false; - if (!Objects.equals(this.filename(), other.filename())) return false; + if (!Objects.equals(this.start(), other.start())) return false; + if (!Objects.equals(this.line(), other.line())) return false; + if (!Objects.equals(this.filename(), other.filename())) return false; - return true; - } + return true; + } - @Override public int compareTo(Location other) { - int a = filename().toString().compareTo(other.filename().toString()); - int b = Integer.compare(line(), other.line()); - int c = Integer.compare(start(), other.start()); + @Override public int compareTo(Location other) { + int a = filename().toString().compareTo(other.filename().toString()); + int b = Integer.compare(line(), other.line()); + int c = Integer.compare(start(), other.start()); - if (a != 0) return a; - if (b != 0) return b; + if (a != 0) return a; + if (b != 0) return b; - return c; - } + return c; + } - public static Location of(Filename filename, int line, int start) { - return new Location() { - @Override public Filename filename() { return filename; } - @Override public int start() { return start; } - @Override public int line() { return line; } - }; - } + public static Location of(Filename filename, int line, int start) { + return new Location() { + @Override public Filename filename() { return filename; } + @Override public int start() { return start; } + @Override public int line() { return line; } + }; + } - public static Location of(String raw) { - var i0 = raw.lastIndexOf(':'); - if (i0 < 0) return Location.of(Filename.parse(raw), -1, -1); + public static Location of(String raw) { + var i0 = raw.lastIndexOf(':'); + if (i0 < 0) return Location.of(Filename.parse(raw), -1, -1); - var i1 = raw.lastIndexOf(':', i0); - if (i0 < 0) { - try { - return Location.of(Filename.parse(raw.substring(0, i0)), Integer.parseInt(raw.substring(i0 + 1)), -1); - } - catch (NumberFormatException e) { - return Location.of(Filename.parse(raw), -1, -1); - } - } + var i1 = raw.lastIndexOf(':', i0); + if (i0 < 0) { + try { + return Location.of(Filename.parse(raw.substring(0, i0)), Integer.parseInt(raw.substring(i0 + 1)), -1); + } + catch (NumberFormatException e) { + return Location.of(Filename.parse(raw), -1, -1); + } + } - int start, line; + int start, line; - try { - start = Integer.parseInt(raw.substring(i1 + 1)); - } - catch (NumberFormatException e) { - return Location.of(Filename.parse(raw), -1, -1); - } + try { + start = Integer.parseInt(raw.substring(i1 + 1)); + } + catch (NumberFormatException e) { + return Location.of(Filename.parse(raw), -1, -1); + } - try { - line = Integer.parseInt(raw.substring(i0 + 1, i1)); - } - catch (NumberFormatException e) { - return Location.of(Filename.parse(raw.substring(i1 + 1)), start, -1); - } + try { + line = Integer.parseInt(raw.substring(i0 + 1, i1)); + } + catch (NumberFormatException e) { + return Location.of(Filename.parse(raw.substring(i1 + 1)), start, -1); + } - return Location.of(Filename.parse(raw.substring(0, i0)), start, line); - } + return Location.of(Filename.parse(raw.substring(0, i0)), start, line); + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/parsing/ParseRes.java b/src/main/java/me/topchetoeu/jscript/common/parsing/ParseRes.java index 11502e8..05ec4a1 100644 --- a/src/main/java/me/topchetoeu/jscript/common/parsing/ParseRes.java +++ b/src/main/java/me/topchetoeu/jscript/common/parsing/ParseRes.java @@ -1,80 +1,80 @@ package me.topchetoeu.jscript.common.parsing; public class ParseRes { - public static enum State { - SUCCESS, - FAILED, - ERROR; + public static enum State { + SUCCESS, + FAILED, + ERROR; - public boolean isSuccess() { return this == SUCCESS; } - public boolean isFailed() { return this == FAILED; } - public boolean isError() { return this == ERROR; } - } + public boolean isSuccess() { return this == SUCCESS; } + public boolean isFailed() { return this == FAILED; } + public boolean isError() { return this == ERROR; } + } - public final ParseRes.State state; - public final Location errorLocation; - public final String error; - public final T result; - public final int n; + public final ParseRes.State state; + public final Location errorLocation; + public final String error; + public final T result; + public final int n; - private ParseRes(ParseRes.State state, Location errorLocation, String error, T result, int readN) { - this.result = result; - this.n = readN; - this.state = state; - this.error = error; - this.errorLocation = errorLocation; - } + private ParseRes(ParseRes.State state, Location errorLocation, String error, T result, int readN) { + this.result = result; + this.n = readN; + this.state = state; + this.error = error; + this.errorLocation = errorLocation; + } - public ParseRes setN(int i) { - if (!state.isSuccess()) return this; - return new ParseRes<>(state, null, null, result, i); - } - public ParseRes addN(int n) { - if (!state.isSuccess()) return this; - return new ParseRes<>(state, null, null, result, this.n + n); - } - public ParseRes chainError() { - if (isSuccess()) throw new RuntimeException("Can't transform a ParseRes that hasn't failed"); - return new ParseRes<>(state, errorLocation, error, null, 0); - } - @SuppressWarnings("unchecked") - public ParseRes chainError(ParseRes other) { - if (!this.isError()) return other.chainError(); - return (ParseRes) this; - } - @SuppressWarnings("unchecked") - public ParseRes chainError(Location loc, String error) { - if (!this.isError()) return new ParseRes<>(State.ERROR, loc, error, null, 0); - return (ParseRes) this; - } + public ParseRes setN(int i) { + if (!state.isSuccess()) return this; + return new ParseRes<>(state, null, null, result, i); + } + public ParseRes addN(int n) { + if (!state.isSuccess()) return this; + return new ParseRes<>(state, null, null, result, this.n + n); + } + public ParseRes chainError() { + if (isSuccess()) throw new RuntimeException("Can't transform a ParseRes that hasn't failed"); + return new ParseRes<>(state, errorLocation, error, null, 0); + } + @SuppressWarnings("unchecked") + public ParseRes chainError(ParseRes other) { + if (!this.isError()) return other.chainError(); + return (ParseRes) this; + } + @SuppressWarnings("unchecked") + public ParseRes chainError(Location loc, String error) { + if (!this.isError()) return new ParseRes<>(State.ERROR, loc, error, null, 0); + return (ParseRes) this; + } - public boolean isSuccess() { return state.isSuccess(); } - public boolean isFailed() { return state.isFailed(); } - public boolean isError() { return state.isError(); } + public boolean isSuccess() { return state.isSuccess(); } + public boolean isFailed() { return state.isFailed(); } + public boolean isError() { return state.isError(); } - public static ParseRes failed() { - return new ParseRes(State.FAILED, null, null, null, 0); - } - public static ParseRes error(Location loc, String error) { - // TODO: differentiate definitive and probable errors - return new ParseRes<>(State.ERROR, loc, error, null, 0); - } - public static ParseRes res(T val, int i) { - return new ParseRes<>(State.SUCCESS, null, null, val, i); - } + public static ParseRes failed() { + return new ParseRes(State.FAILED, null, null, null, 0); + } + public static ParseRes error(Location loc, String error) { + // TODO: differentiate definitive and probable errors + return new ParseRes<>(State.ERROR, loc, error, null, 0); + } + public static ParseRes res(T val, int i) { + return new ParseRes<>(State.SUCCESS, null, null, val, i); + } - @SafeVarargs - @SuppressWarnings("all") - public static ParseRes first(Source src, int i, Parser ...parsers) { - int n = Parsing.skipEmpty(src, i); - ParseRes error = ParseRes.failed(); + @SafeVarargs + @SuppressWarnings("all") + public static ParseRes first(Source src, int i, Parser ...parsers) { + int n = Parsing.skipEmpty(src, i); + ParseRes error = ParseRes.failed(); - for (var parser : parsers) { - var res = parser.parse(src, i + n); - if (res.isSuccess()) return res.addN(n); - if (res.isError() && error.isFailed()) error = res.chainError(); - } + for (var parser : parsers) { + var res = parser.parse(src, i + n); + if (res.isSuccess()) return res.addN(n); + if (res.isError() && error.isFailed()) error = res.chainError(); + } - return error; - } + return error; + } } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/common/parsing/Parser.java b/src/main/java/me/topchetoeu/jscript/common/parsing/Parser.java index d40f4f4..6d298c2 100644 --- a/src/main/java/me/topchetoeu/jscript/common/parsing/Parser.java +++ b/src/main/java/me/topchetoeu/jscript/common/parsing/Parser.java @@ -1,5 +1,5 @@ package me.topchetoeu.jscript.common.parsing; public interface Parser { - public ParseRes parse(Source src, int i); + public ParseRes parse(Source src, int i); } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/common/parsing/Parsing.java b/src/main/java/me/topchetoeu/jscript/common/parsing/Parsing.java index 1af3a10..ef2b62e 100644 --- a/src/main/java/me/topchetoeu/jscript/common/parsing/Parsing.java +++ b/src/main/java/me/topchetoeu/jscript/common/parsing/Parsing.java @@ -4,418 +4,418 @@ import me.topchetoeu.jscript.common.SyntaxException; import me.topchetoeu.jscript.compilation.values.constants.NumberNode; public class Parsing { - public static boolean isDigit(Character c) { - return c != null && c >= '0' && c <= '9'; - } - public static boolean isAny(char c, String alphabet) { - return alphabet.contains(Character.toString(c)); - } + public static boolean isDigit(Character c) { + return c != null && c >= '0' && c <= '9'; + } + public static boolean isAny(char c, String alphabet) { + return alphabet.contains(Character.toString(c)); + } - public static int fromHex(char c) { - if (c >= 'A' && c <= 'F') return c - 'A' + 10; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; - if (c >= '0' && c <= '9') return c - '0'; - return -1; - } + public static int fromHex(char c) { + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= '0' && c <= '9') return c - '0'; + return -1; + } - public static int skipEmpty(Source src, int i) { - return skipEmpty(src, i, true); - } + public static int skipEmpty(Source src, int i) { + return skipEmpty(src, i, true); + } - public static int skipEmpty(Source src, int i, boolean noComments) { - int n = 0; + public static int skipEmpty(Source src, int i, boolean noComments) { + int n = 0; - if (i == 0 && src.is(0, "#!")) { - while (!src.is(n, '\n')) n++; - n++; - } + if (i == 0 && src.is(0, "#!")) { + while (!src.is(n, '\n')) n++; + n++; + } - var isSingle = false; - var isMulti = false; + var isSingle = false; + var isMulti = false; - while (i + n < src.size()) { - if (isSingle) { - if (src.is(i + n, '\n')) { - n++; - isSingle = false; - } - else n++; - } - else if (isMulti) { - if (src.is(i + n, "*/")) { - n += 2; - isMulti = false; - } - else n++; - } - else if (src.is(i + n, "//")) { - n += 2; - isSingle = true; - } - else if (src.is(i + n, "/*")) { - n += 2; - isMulti = true; - } - else if (src.is(i + n, Character::isWhitespace)) { - n++; - } - else break; - } + while (i + n < src.size()) { + if (isSingle) { + if (src.is(i + n, '\n')) { + n++; + isSingle = false; + } + else n++; + } + else if (isMulti) { + if (src.is(i + n, "*/")) { + n += 2; + isMulti = false; + } + else n++; + } + else if (src.is(i + n, "//")) { + n += 2; + isSingle = true; + } + else if (src.is(i + n, "/*")) { + n += 2; + isMulti = true; + } + else if (src.is(i + n, Character::isWhitespace)) { + n++; + } + else break; + } - return n; - } + return n; + } - public static ParseRes parseChar(Source src, int i) { - int n = 0; + public static ParseRes parseChar(Source src, int i) { + int n = 0; - if (src.is(i + n, '\\')) { - n++; - char c = src.at(i + n++); + if (src.is(i + n, '\\')) { + n++; + char c = src.at(i + n++); - if (c == 'b') return ParseRes.res('\b', n); - else if (c == 't') return ParseRes.res('\t', n); - else if (c == 'n') return ParseRes.res('\n', n); - else if (c == 'f') return ParseRes.res('\f', n); - else if (c == 'r') return ParseRes.res('\r', n); - else if (c == '0') { - if (src.is(i + n, Parsing::isDigit)) return ParseRes.error(src.loc(i), "Octal escape sequences are not allowed"); - else return ParseRes.res('\0', n); - } - else if (c >= '1' && c <= '9') return ParseRes.error(src.loc(i), "Octal escape sequences are not allowed"); - else if (c == 'x') { - var newC = 0; + if (c == 'b') return ParseRes.res('\b', n); + else if (c == 't') return ParseRes.res('\t', n); + else if (c == 'n') return ParseRes.res('\n', n); + else if (c == 'f') return ParseRes.res('\f', n); + else if (c == 'r') return ParseRes.res('\r', n); + else if (c == '0') { + if (src.is(i + n, Parsing::isDigit)) return ParseRes.error(src.loc(i), "Octal escape sequences are not allowed"); + else return ParseRes.res('\0', n); + } + else if (c >= '1' && c <= '9') return ParseRes.error(src.loc(i), "Octal escape sequences are not allowed"); + else if (c == 'x') { + var newC = 0; - for (var j = 0; j < 2; j++) { - if (i + n >= src.size()) return ParseRes.error(src.loc(i), "Invalid hexadecimal escape sequence"); + for (var j = 0; j < 2; j++) { + if (i + n >= src.size()) return ParseRes.error(src.loc(i), "Invalid hexadecimal escape sequence"); - int val = fromHex(src.at(i + n)); - if (val == -1) throw new SyntaxException(src.loc(i + n), "Invalid hexadecimal escape sequence"); - n++; + int val = fromHex(src.at(i + n)); + if (val == -1) throw new SyntaxException(src.loc(i + n), "Invalid hexadecimal escape sequence"); + n++; - newC = (newC << 4) | val; - } + newC = (newC << 4) | val; + } - return ParseRes.res((char)newC, n); - } - else if (c == 'u') { - var newC = 0; + return ParseRes.res((char)newC, n); + } + else if (c == 'u') { + var newC = 0; - for (var j = 0; j < 4; j++) { - if (i + n >= src.size()) return ParseRes.error(src.loc(i), "Invalid Unicode escape sequence"); + for (var j = 0; j < 4; j++) { + if (i + n >= src.size()) return ParseRes.error(src.loc(i), "Invalid Unicode escape sequence"); - int val = fromHex(src.at(i + n)); - if (val == -1) throw new SyntaxException(src.loc(i + n), "Invalid Unicode escape sequence"); - n++; + int val = fromHex(src.at(i + n)); + if (val == -1) throw new SyntaxException(src.loc(i + n), "Invalid Unicode escape sequence"); + n++; - newC = (newC << 4) | val; - } + newC = (newC << 4) | val; + } - return ParseRes.res((char)newC, n); - } - else if (c == '\n') return ParseRes.res(null, n); + return ParseRes.res((char)newC, n); + } + else if (c == '\n') return ParseRes.res(null, n); else n--; - } + } - return ParseRes.res(src.at(i + n), n + 1); - } + return ParseRes.res(src.at(i + n), n + 1); + } - public static ParseRes parseIdentifier(Source src, int i) { - var n = skipEmpty(src, i); - var res = new StringBuilder(); - var first = true; + public static ParseRes parseIdentifier(Source src, int i) { + var n = skipEmpty(src, i); + var res = new StringBuilder(); + var first = true; - while (true) { - if (i + n > src.size()) break; - char c = src.at(i + n, '\0'); + while (true) { + if (i + n > src.size()) break; + char c = src.at(i + n, '\0'); - if (first && Parsing.isDigit(c)) break; - if (!Character.isLetterOrDigit(c) && c != '_' && c != '$') break; - res.append(c); - n++; - first = false; - } + if (first && Parsing.isDigit(c)) break; + if (!Character.isLetterOrDigit(c) && c != '_' && c != '$') break; + res.append(c); + n++; + first = false; + } - if (res.length() <= 0) return ParseRes.failed(); - else return ParseRes.res(res.toString(), n); - } - public static ParseRes parseIdentifier(Source src, int i, String test) { - var n = skipEmpty(src, i); - var res = new StringBuilder(); - var first = true; + if (res.length() <= 0) return ParseRes.failed(); + else return ParseRes.res(res.toString(), n); + } + public static ParseRes parseIdentifier(Source src, int i, String test) { + var n = skipEmpty(src, i); + var res = new StringBuilder(); + var first = true; - while (true) { - if (i + n > src.size()) break; - char c = src.at(i + n, '\0'); + while (true) { + if (i + n > src.size()) break; + char c = src.at(i + n, '\0'); - if (first && Parsing.isDigit(c)) break; - if (!Character.isLetterOrDigit(c) && c != '_' && c != '$') break; - res.append(c); - n++; - first = false; - } + if (first && Parsing.isDigit(c)) break; + if (!Character.isLetterOrDigit(c) && c != '_' && c != '$') break; + res.append(c); + n++; + first = false; + } - if (res.length() <= 0) return ParseRes.failed(); - else if (test == null || res.toString().equals(test)) return ParseRes.res(res.toString(), n); - else return ParseRes.failed(); - } - public static boolean isIdentifier(Source src, int i, String test) { - return parseIdentifier(src, i, test).isSuccess(); - } + if (res.length() <= 0) return ParseRes.failed(); + else if (test == null || res.toString().equals(test)) return ParseRes.res(res.toString(), n); + else return ParseRes.failed(); + } + public static boolean isIdentifier(Source src, int i, String test) { + return parseIdentifier(src, i, test).isSuccess(); + } - public static ParseRes parseOperator(Source src, int i, String op) { - var n = skipEmpty(src, i); + public static ParseRes parseOperator(Source src, int i, String op) { + var n = skipEmpty(src, i); - if (src.is(i + n, op)) return ParseRes.res(op, n + op.length()); - else return ParseRes.failed(); - } + if (src.is(i + n, op)) return ParseRes.res(op, n + op.length()); + else return ParseRes.failed(); + } - private static ParseRes parseHex(Source src, int i) { - int n = 0; - double res = 0; + private static ParseRes parseHex(Source src, int i) { + int n = 0; + double res = 0; - while (true) { - int digit = Parsing.fromHex(src.at(i + n, '\0')); - if (digit < 0) { - if (n <= 0) return ParseRes.failed(); - else return ParseRes.res(res, n); - } - n++; + while (true) { + int digit = Parsing.fromHex(src.at(i + n, '\0')); + if (digit < 0) { + if (n <= 0) return ParseRes.failed(); + else return ParseRes.res(res, n); + } + n++; - res *= 16; - res += digit; - } - } - private static ParseRes parseOct(Source src, int i) { - int n = 0; - double res = 0; + res *= 16; + res += digit; + } + } + private static ParseRes parseOct(Source src, int i) { + int n = 0; + double res = 0; - while (true) { - int digit = src.at(i + n, '\0') - '0'; - if (digit < 0 || digit > 9) break; - if (digit > 7) return ParseRes.error(src.loc(i + n), "Digits in octal literals must be from 0 to 7, encountered " + digit); + while (true) { + int digit = src.at(i + n, '\0') - '0'; + if (digit < 0 || digit > 9) break; + if (digit > 7) return ParseRes.error(src.loc(i + n), "Digits in octal literals must be from 0 to 7, encountered " + digit); - if (digit < 0) { - if (n <= 0) return ParseRes.failed(); - else return ParseRes.res(res, n); - } - n++; + if (digit < 0) { + if (n <= 0) return ParseRes.failed(); + else return ParseRes.res(res, n); + } + n++; - res *= 8; - res += digit; - } + res *= 8; + res += digit; + } - return ParseRes.res(res, n); - } + return ParseRes.res(res, n); + } - public static ParseRes parseString(Source src, int i) { - var n = skipEmpty(src, i); - - char quote; - - if (src.is(i + n, '\'')) quote = '\''; - else if (src.is(i + n, '"')) quote = '"'; - else return ParseRes.failed(); - n++; - - var res = new StringBuilder(); - - while (true) { - if (i + n >= src.size()) return ParseRes.error(src.loc(i + n), "Unterminated string literal"); - if (src.is(i + n, quote)) { - n++; - return ParseRes.res(res.toString(), n); - } + public static ParseRes parseString(Source src, int i) { + var n = skipEmpty(src, i); + + char quote; + + if (src.is(i + n, '\'')) quote = '\''; + else if (src.is(i + n, '"')) quote = '"'; + else return ParseRes.failed(); + n++; + + var res = new StringBuilder(); + + while (true) { + if (i + n >= src.size()) return ParseRes.error(src.loc(i + n), "Unterminated string literal"); + if (src.is(i + n, quote)) { + n++; + return ParseRes.res(res.toString(), n); + } - var charRes = parseChar(src, i + n); - if (!charRes.isSuccess()) return charRes.chainError(src.loc(i + n), "Invalid character"); - n += charRes.n; + var charRes = parseChar(src, i + n); + if (!charRes.isSuccess()) return charRes.chainError(src.loc(i + n), "Invalid character"); + n += charRes.n; - if (charRes.result != null) res.append(charRes.result); - } - } - public static ParseRes parseNumber(Source src, int i, boolean withMinus) { - var n = skipEmpty(src, i); + if (charRes.result != null) res.append(charRes.result); + } + } + public static ParseRes parseNumber(Source src, int i, boolean withMinus) { + var n = skipEmpty(src, i); - double whole = 0; - double fract = 0; - long exponent = 0; - boolean parsedAny = false; - boolean negative = false; + double whole = 0; + double fract = 0; + long exponent = 0; + boolean parsedAny = false; + boolean negative = false; - if (withMinus && src.is(i + n, "-")) { - negative = true; - n++; - } + if (withMinus && src.is(i + n, "-")) { + negative = true; + n++; + } - if (src.is(i + n, "0x") || src.is(i + n, "0X")) { - n += 2; + if (src.is(i + n, "0x") || src.is(i + n, "0X")) { + n += 2; - var res = parseHex(src, i + n); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Incomplete hexadecimal literal"); - n += res.n; + var res = parseHex(src, i + n); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Incomplete hexadecimal literal"); + n += res.n; - if (negative) return ParseRes.res(-res.result, n); - else return ParseRes.res(res.result, n); - } - else if (src.is(i + n, "0o") || src.is(i + n, "0O")) { - n += 2; + if (negative) return ParseRes.res(-res.result, n); + else return ParseRes.res(res.result, n); + } + else if (src.is(i + n, "0o") || src.is(i + n, "0O")) { + n += 2; - var res = parseOct(src, i + n); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Incomplete octal literal"); - n += res.n; + var res = parseOct(src, i + n); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Incomplete octal literal"); + n += res.n; - if (negative) return ParseRes.res(-res.result, n); - else return ParseRes.res(res.result, n); - } - else if (src.is(i + n, '0')) { - n++; - parsedAny = true; - if (src.is(i + n, Parsing::isDigit)) return ParseRes.error(src.loc(i + n), "Decimals with leading zeroes are not allowed"); - } + if (negative) return ParseRes.res(-res.result, n); + else return ParseRes.res(res.result, n); + } + else if (src.is(i + n, '0')) { + n++; + parsedAny = true; + if (src.is(i + n, Parsing::isDigit)) return ParseRes.error(src.loc(i + n), "Decimals with leading zeroes are not allowed"); + } - while (src.is(i + n, Parsing::isDigit)) { - parsedAny = true; - whole *= 10; - whole += src.at(i + n++) - '0'; - } + while (src.is(i + n, Parsing::isDigit)) { + parsedAny = true; + whole *= 10; + whole += src.at(i + n++) - '0'; + } - if (src.is(i + n, '.')) { - parsedAny = true; - n++; + if (src.is(i + n, '.')) { + parsedAny = true; + n++; - while (src.is(i + n, Parsing::isDigit)) { - fract += src.at(i + n++) - '0'; - fract /= 10; - } - } + while (src.is(i + n, Parsing::isDigit)) { + fract += src.at(i + n++) - '0'; + fract /= 10; + } + } - if (src.is(i + n, 'e') || src.is(i + n, 'E')) { - n++; - parsedAny = true; - boolean expNegative = false; - boolean parsedE = false; + if (src.is(i + n, 'e') || src.is(i + n, 'E')) { + n++; + parsedAny = true; + boolean expNegative = false; + boolean parsedE = false; - if (src.is(i + n, '-')) { - expNegative = true; - n++; - } - else if (src.is(i + n, '+')) n++; + if (src.is(i + n, '-')) { + expNegative = true; + n++; + } + else if (src.is(i + n, '+')) n++; - while (src.is(i + n, Parsing::isDigit)) { - parsedE = true; - exponent *= 10; + while (src.is(i + n, Parsing::isDigit)) { + parsedE = true; + exponent *= 10; - if (expNegative) exponent -= src.at(i + n++) - '0'; - else exponent += src.at(i + n++) - '0'; - } + if (expNegative) exponent -= src.at(i + n++) - '0'; + else exponent += src.at(i + n++) - '0'; + } - if (!parsedE) return ParseRes.error(src.loc(i + n), "Incomplete number exponent"); - } + if (!parsedE) return ParseRes.error(src.loc(i + n), "Incomplete number exponent"); + } - if (!parsedAny) { - if (negative) return ParseRes.error(src.loc(i + n), "Expected number immediatly after minus"); - return ParseRes.failed(); - } - else if (negative) return ParseRes.res(-(whole + fract) * NumberNode.power(10, exponent), n); - else return ParseRes.res((whole + fract) * NumberNode.power(10, exponent), n); - } - public static ParseRes parseFloat(Source src, int i, boolean withMinus) { - var n = skipEmpty(src, i); + if (!parsedAny) { + if (negative) return ParseRes.error(src.loc(i + n), "Expected number immediatly after minus"); + return ParseRes.failed(); + } + else if (negative) return ParseRes.res(-(whole + fract) * NumberNode.power(10, exponent), n); + else return ParseRes.res((whole + fract) * NumberNode.power(10, exponent), n); + } + public static ParseRes parseFloat(Source src, int i, boolean withMinus) { + var n = skipEmpty(src, i); - double whole = 0; - double fract = 0; - long exponent = 0; - boolean parsedAny = false; - boolean negative = false; + double whole = 0; + double fract = 0; + long exponent = 0; + boolean parsedAny = false; + boolean negative = false; - if (withMinus && src.is(i + n, "-")) { - negative = true; - n++; - } + if (withMinus && src.is(i + n, "-")) { + negative = true; + n++; + } - while (src.is(i + n, Parsing::isDigit)) { - parsedAny = true; - whole *= 10; - whole += src.at(i + n++) - '0'; - } + while (src.is(i + n, Parsing::isDigit)) { + parsedAny = true; + whole *= 10; + whole += src.at(i + n++) - '0'; + } - if (src.is(i + n, '.')) { - parsedAny = true; - n++; + if (src.is(i + n, '.')) { + parsedAny = true; + n++; - while (src.is(i + n, Parsing::isDigit)) { - fract += src.at(i + n++) - '0'; - fract /= 10; - } - } + while (src.is(i + n, Parsing::isDigit)) { + fract += src.at(i + n++) - '0'; + fract /= 10; + } + } - if (src.is(i + n, 'e') || src.is(i + n, 'E')) { - n++; - parsedAny = true; - boolean expNegative = false; - boolean parsedE = false; + if (src.is(i + n, 'e') || src.is(i + n, 'E')) { + n++; + parsedAny = true; + boolean expNegative = false; + boolean parsedE = false; - if (src.is(i + n, '-')) { - expNegative = true; - n++; - } - else if (src.is(i + n, '+')) n++; + if (src.is(i + n, '-')) { + expNegative = true; + n++; + } + else if (src.is(i + n, '+')) n++; - while (src.is(i + n, Parsing::isDigit)) { - parsedE = true; - exponent *= 10; + while (src.is(i + n, Parsing::isDigit)) { + parsedE = true; + exponent *= 10; - if (expNegative) exponent -= src.at(i + n++) - '0'; - else exponent += src.at(i + n++) - '0'; - } + if (expNegative) exponent -= src.at(i + n++) - '0'; + else exponent += src.at(i + n++) - '0'; + } - if (!parsedE) return ParseRes.error(src.loc(i + n), "Incomplete number exponent"); - } + if (!parsedE) return ParseRes.error(src.loc(i + n), "Incomplete number exponent"); + } - if (!parsedAny) { - if (negative) return ParseRes.error(src.loc(i + n), "Expected number immediatly after minus"); - return ParseRes.failed(); - } - else if (negative) return ParseRes.res(-(whole + fract) * NumberNode.power(10, exponent), n); - else return ParseRes.res((whole + fract) * NumberNode.power(10, exponent), n); - } - public static ParseRes parseInt(Source src, int i, String alphabet, boolean withMinus) { - var n = skipEmpty(src, i); + if (!parsedAny) { + if (negative) return ParseRes.error(src.loc(i + n), "Expected number immediatly after minus"); + return ParseRes.failed(); + } + else if (negative) return ParseRes.res(-(whole + fract) * NumberNode.power(10, exponent), n); + else return ParseRes.res((whole + fract) * NumberNode.power(10, exponent), n); + } + public static ParseRes parseInt(Source src, int i, String alphabet, boolean withMinus) { + var n = skipEmpty(src, i); - double result = 0; - boolean parsedAny = false; - boolean negative = false; + double result = 0; + boolean parsedAny = false; + boolean negative = false; - if (withMinus && src.is(i + n, "-")) { - negative = true; - n++; - } + if (withMinus && src.is(i + n, "-")) { + negative = true; + n++; + } - if (alphabet == null && src.is(i + n, "0x") || src.is(i + n, "0X")) { - n += 2; + if (alphabet == null && src.is(i + n, "0x") || src.is(i + n, "0X")) { + n += 2; - var res = parseHex(src, i); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Incomplete hexadecimal literal"); - n += res.n; + var res = parseHex(src, i); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Incomplete hexadecimal literal"); + n += res.n; - if (negative) return ParseRes.res(-res.result, n); - else return ParseRes.res(res.result, n); - } + if (negative) return ParseRes.res(-res.result, n); + else return ParseRes.res(res.result, n); + } - while (true) { - var digit = alphabet.indexOf(Character.toLowerCase(src.at(i + n))); - if (digit < 0) break; + while (true) { + var digit = alphabet.indexOf(Character.toLowerCase(src.at(i + n))); + if (digit < 0) break; - parsedAny = true; - result += digit; - result *= alphabet.length(); - } + parsedAny = true; + result += digit; + result *= alphabet.length(); + } - if (!parsedAny) { - if (negative) return ParseRes.error(src.loc(i + n), "Expected number immediatly after minus"); - return ParseRes.failed(); - } - else if (negative) return ParseRes.res(-result, n); - else return ParseRes.res(-result, n); - } + if (!parsedAny) { + if (negative) return ParseRes.error(src.loc(i + n), "Expected number immediatly after minus"); + return ParseRes.failed(); + } + else if (negative) return ParseRes.res(-result, n); + else return ParseRes.res(-result, n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/parsing/Source.java b/src/main/java/me/topchetoeu/jscript/common/parsing/Source.java index d04c1e4..e744d4d 100644 --- a/src/main/java/me/topchetoeu/jscript/common/parsing/Source.java +++ b/src/main/java/me/topchetoeu/jscript/common/parsing/Source.java @@ -5,71 +5,71 @@ import java.util.function.Predicate; import me.topchetoeu.jscript.common.environment.Environment; public class Source { - public final Environment env; - public final Filename filename; - public final String src; + public final Environment env; + public final Filename filename; + public final String src; - private int[] lineStarts; + private int[] lineStarts; - public Location loc(int offset) { - return new SourceLocation(filename, lineStarts, offset); - } - public boolean is(int i, char c) { - return i >= 0 && i < src.length() && src.charAt(i) == c; - } - public boolean is(int i, String src) { - if (i < 0 || i + src.length() > size()) return false; + public Location loc(int offset) { + return new SourceLocation(filename, lineStarts, offset); + } + public boolean is(int i, char c) { + return i >= 0 && i < src.length() && src.charAt(i) == c; + } + public boolean is(int i, String src) { + if (i < 0 || i + src.length() > size()) return false; - for (int j = 0; j < src.length(); j++) { - if (at(i + j) != src.charAt(j)) return false; - } + for (int j = 0; j < src.length(); j++) { + if (at(i + j) != src.charAt(j)) return false; + } - return true; - } - public boolean is(int i, Predicate predicate) { - if (i < 0 || i >= src.length()) return false; - return predicate.test(at(i)); - } - public char at(int i) { - return src.charAt(i); - } - public char at(int i, char defaultVal) { - if (i < 0 || i >= src.length()) return defaultVal; - else return src.charAt(i); - } - public int size() { - return src.length(); - } - public String slice(int start, int end) { - return src.substring(start, end); - } + return true; + } + public boolean is(int i, Predicate predicate) { + if (i < 0 || i >= src.length()) return false; + return predicate.test(at(i)); + } + public char at(int i) { + return src.charAt(i); + } + public char at(int i, char defaultVal) { + if (i < 0 || i >= src.length()) return defaultVal; + else return src.charAt(i); + } + public int size() { + return src.length(); + } + public String slice(int start, int end) { + return src.substring(start, end); + } - public Source(Environment env, Filename filename, String src) { - if (env == null) this.env = new Environment(); - else this.env = env; + public Source(Environment env, Filename filename, String src) { + if (env == null) this.env = new Environment(); + else this.env = env; - this.filename = filename; - this.src = src; + this.filename = filename; + this.src = src; - int n = 1; - lineStarts = new int[16]; - lineStarts[0] = 0; + int n = 1; + lineStarts = new int[16]; + lineStarts[0] = 0; - for (int i = src.indexOf("\n"); i > 0; i = src.indexOf("\n", i + 1)) { - if (n >= lineStarts.length) { - var newArr = new int[lineStarts.length * 2]; - System.arraycopy(lineStarts, 0, newArr, 0, n); - lineStarts = newArr; - } + for (int i = src.indexOf("\n"); i > 0; i = src.indexOf("\n", i + 1)) { + if (n >= lineStarts.length) { + var newArr = new int[lineStarts.length * 2]; + System.arraycopy(lineStarts, 0, newArr, 0, n); + lineStarts = newArr; + } - lineStarts[n++] = i + 1; - } + lineStarts[n++] = i + 1; + } - var newArr = new int[n]; - System.arraycopy(lineStarts, 0, newArr, 0, n); - lineStarts = newArr; - } - public Source(String src) { - this(null, null, src); - } + var newArr = new int[n]; + System.arraycopy(lineStarts, 0, newArr, 0, n); + lineStarts = newArr; + } + public Source(String src) { + this(null, null, src); + } } diff --git a/src/main/java/me/topchetoeu/jscript/common/parsing/SourceLocation.java b/src/main/java/me/topchetoeu/jscript/common/parsing/SourceLocation.java index 5819565..c362f78 100644 --- a/src/main/java/me/topchetoeu/jscript/common/parsing/SourceLocation.java +++ b/src/main/java/me/topchetoeu/jscript/common/parsing/SourceLocation.java @@ -3,64 +3,64 @@ package me.topchetoeu.jscript.common.parsing; import java.util.Objects; public class SourceLocation extends Location { - private int[] lineStarts; - private int line; - private int start; - private final Filename filename; - private final int offset; + private int[] lineStarts; + private int line; + private int start; + private final Filename filename; + private final int offset; - private void update() { - if (lineStarts == null) return; + private void update() { + if (lineStarts == null) return; - int a = 0; - int b = lineStarts.length; + int a = 0; + int b = lineStarts.length; - while (true) { - if (a + 1 >= b) break; - var mid = -((-a - b) >> 1); - var el = lineStarts[mid]; + while (true) { + if (a + 1 >= b) break; + var mid = -((-a - b) >> 1); + var el = lineStarts[mid]; - if (el < offset) a = mid; - else if (el > offset) b = mid; - else { - this.line = mid; - this.start = 0; - this.lineStarts = null; - return; - } - } + if (el < offset) a = mid; + else if (el > offset) b = mid; + else { + this.line = mid; + this.start = 0; + this.lineStarts = null; + return; + } + } - this.line = a; - this.start = offset - lineStarts[a]; - this.lineStarts = null; - return; - } + this.line = a; + this.start = offset - lineStarts[a]; + this.lineStarts = null; + return; + } - @Override public Filename filename() { return filename; } - @Override public int line() { - update(); - return line; - } - @Override public int start() { - update(); - return start; - } + @Override public Filename filename() { return filename; } + @Override public int line() { + update(); + return line; + } + @Override public int start() { + update(); + return start; + } - @Override public int hashCode() { - return Objects.hash(offset); - } - @Override public int compareTo(Location other) { - if (other instanceof SourceLocation srcLoc) return Integer.compare(offset, srcLoc.offset); - else return super.compareTo(other); - } - @Override public boolean equals(Object obj) { - if (obj instanceof SourceLocation other) return this.offset == other.offset; - else return super.equals(obj); - } + @Override public int hashCode() { + return Objects.hash(offset); + } + @Override public int compareTo(Location other) { + if (other instanceof SourceLocation srcLoc) return Integer.compare(offset, srcLoc.offset); + else return super.compareTo(other); + } + @Override public boolean equals(Object obj) { + if (obj instanceof SourceLocation other) return this.offset == other.offset; + else return super.equals(obj); + } - public SourceLocation(Filename filename, int[] lineStarts, int offset) { - this.filename = filename; - this.lineStarts = lineStarts; - this.offset = offset; - } + public SourceLocation(Filename filename, int[] lineStarts, int offset) { + this.filename = filename; + this.lineStarts = lineStarts; + this.offset = offset; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/CompileResult.java b/src/main/java/me/topchetoeu/jscript/compilation/CompileResult.java index b70178d..367ed38 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/CompileResult.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/CompileResult.java @@ -20,69 +20,69 @@ import me.topchetoeu.jscript.compilation.scope.FunctionScope; public final class CompileResult { public static final Key DEBUG_LOG = new Key<>(); - public final List instructions; - public final List children; + public final List instructions; + public final List children; public final Map childrenMap = new HashMap<>(); public final Map childrenIndices = new HashMap<>(); - public final FunctionMapBuilder map; - public final Environment env; - public int length; - public final FunctionScope scope; + public final FunctionMapBuilder map; + public final Environment env; + public int length; + public final FunctionScope scope; - public int temp() { - instructions.add(null); - return instructions.size() - 1; - } + public int temp() { + instructions.add(null); + return instructions.size() - 1; + } - public CompileResult add(Instruction instr) { - instructions.add(instr); - return this; - } - public CompileResult set(int i, Instruction instr) { - instructions.set(i, instr); - return this; - } + public CompileResult add(Instruction instr) { + instructions.add(instr); + return this; + } + public CompileResult set(int i, Instruction instr) { + instructions.set(i, instr); + return this; + } - public int size() { return instructions.size(); } + public int size() { return instructions.size(); } - public void setDebug(Location loc, BreakpointType type) { - map.setDebug(loc, type); - } - public void setLocation(int i, Location loc) { - map.setLocation(i, loc); - } - public void setLocationAndDebug(int i, Location loc, BreakpointType type) { - map.setLocationAndDebug(i, loc, type); - } - public void setDebug(BreakpointType type) { - setDebug(map.last(), type); - } - public void setLocation(Location type) { - setLocation(instructions.size() - 1, type); - } - public void setLocationAndDebug(Location loc, BreakpointType type) { - setLocationAndDebug(instructions.size() - 1, loc, type); - } + public void setDebug(Location loc, BreakpointType type) { + map.setDebug(loc, type); + } + public void setLocation(int i, Location loc) { + map.setLocation(i, loc); + } + public void setLocationAndDebug(int i, Location loc, BreakpointType type) { + map.setLocationAndDebug(i, loc, type); + } + public void setDebug(BreakpointType type) { + setDebug(map.last(), type); + } + public void setLocation(Location type) { + setLocation(instructions.size() - 1, type); + } + public void setLocationAndDebug(Location loc, BreakpointType type) { + setLocationAndDebug(instructions.size() - 1, loc, type); + } - public CompileResult addChild(FunctionNode node, CompileResult res) { - this.children.add(res); + public CompileResult addChild(FunctionNode node, CompileResult res) { + this.children.add(res); this.childrenMap.put(node, res); this.childrenIndices.put(node, this.children.size() - 1); - return res; - } + return res; + } - public Instruction[] instructions() { + public Instruction[] instructions() { return instructions.toArray(new Instruction[0]); - } + } - public FunctionMap map() { - return map.build(scope.localNames(), scope.captureNames()); - } - public FunctionBody body() { - var builtChildren = new FunctionBody[children.size()]; - for (var i = 0; i < children.size(); i++) builtChildren[i] = children.get(i).body(); + public FunctionMap map() { + return map.build(scope.localNames(), scope.captureNames()); + } + public FunctionBody body() { + var builtChildren = new FunctionBody[children.size()]; + for (var i = 0; i < children.size(); i++) builtChildren[i] = children.get(i).body(); - var instrRes = instructions(); + var instrRes = instructions(); if (env.has(DEBUG_LOG)) { System.out.println("================= BODY ================="); @@ -93,43 +93,43 @@ public final class CompileResult { for (var instr : instrRes) System.out.println(instr); } - return new FunctionBody( - scope.localsCount(), scope.capturablesCount(), scope.capturesCount(), - length, instrRes, builtChildren - ); - } + return new FunctionBody( + scope.localsCount(), scope.capturablesCount(), scope.capturesCount(), + length, instrRes, builtChildren + ); + } - public CompileResult subtarget() { - return new CompileResult(env, new FunctionScope(scope), this); - } + public CompileResult subtarget() { + return new CompileResult(env, new FunctionScope(scope), this); + } - public CompileResult setEnvironment(Environment env) { - return new CompileResult(env, scope, this); - } - /** - * Returns a compile result with a child of the environment that relates to the given key. - * In essence, this is used to create a compile result which is back at the root environment of the compilation - */ - public CompileResult rootEnvironment(Key env) { - return new CompileResult(this.env.get(env).child(), scope, this); - } - public CompileResult subEnvironment() { - return new CompileResult(env.child(), scope, this); - } + public CompileResult setEnvironment(Environment env) { + return new CompileResult(env, scope, this); + } + /** + * Returns a compile result with a child of the environment that relates to the given key. + * In essence, this is used to create a compile result which is back at the root environment of the compilation + */ + public CompileResult rootEnvironment(Key env) { + return new CompileResult(this.env.get(env).child(), scope, this); + } + public CompileResult subEnvironment() { + return new CompileResult(env.child(), scope, this); + } - public CompileResult(Environment env, FunctionScope scope, int length) { - this.scope = scope; - this.instructions = new ArrayList<>(); - this.children = new LinkedList<>(); - this.map = FunctionMap.builder(); - this.env = env; - this.length = length; - } - private CompileResult(Environment env, FunctionScope scope, CompileResult parent) { - this.scope = scope; - this.instructions = parent.instructions; - this.children = parent.children; - this.map = parent.map; - this.env = env; - } + public CompileResult(Environment env, FunctionScope scope, int length) { + this.scope = scope; + this.instructions = new ArrayList<>(); + this.children = new LinkedList<>(); + this.map = FunctionMap.builder(); + this.env = env; + this.length = length; + } + private CompileResult(Environment env, FunctionScope scope, CompileResult parent) { + this.scope = scope; + this.instructions = parent.instructions; + this.children = parent.children; + this.map = parent.map; + this.env = env; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/CompoundNode.java b/src/main/java/me/topchetoeu/jscript/compilation/CompoundNode.java index 0754795..c347bab 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/CompoundNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/CompoundNode.java @@ -13,100 +13,100 @@ import me.topchetoeu.jscript.common.parsing.Source; public class CompoundNode extends Node { - public final Node[] statements; - public Location end; + public final Node[] statements; + public Location end; - @Override public void resolve(CompileResult target) { - for (var stm : statements) stm.resolve(target); - } + @Override public void resolve(CompileResult target) { + for (var stm : statements) stm.resolve(target); + } @Override public void compileFunctions(CompileResult target) { - for (var stm : statements) stm.compileFunctions(target); + for (var stm : statements) stm.compileFunctions(target); } - public void compile(CompileResult target, boolean pollute, BreakpointType type) { - List statements = new ArrayList(); + public void compile(CompileResult target, boolean pollute, BreakpointType type) { + List statements = new ArrayList(); - for (var stm : this.statements) { - if (stm instanceof FunctionStatementNode func) { - func.compile(target, false); - } - else statements.add(stm); - } + for (var stm : this.statements) { + if (stm instanceof FunctionStatementNode func) { + func.compile(target, false); + } + else statements.add(stm); + } - var polluted = false; + var polluted = false; - for (var i = 0; i < statements.size(); i++) { - var stm = statements.get(i); + for (var i = 0; i < statements.size(); i++) { + var stm = statements.get(i); - if (i != statements.size() - 1) stm.compile(target, false, BreakpointType.STEP_OVER); - else stm.compile(target, polluted = pollute, BreakpointType.STEP_OVER); - } + if (i != statements.size() - 1) stm.compile(target, false, BreakpointType.STEP_OVER); + else stm.compile(target, polluted = pollute, BreakpointType.STEP_OVER); + } - if (!polluted && pollute) { - target.add(Instruction.pushUndefined()); - } - } + if (!polluted && pollute) { + target.add(Instruction.pushUndefined()); + } + } - public CompoundNode setEnd(Location loc) { - this.end = loc; - return this; - } + public CompoundNode setEnd(Location loc) { + this.end = loc; + return this; + } - public CompoundNode(Location loc, Node ...statements) { - super(loc); - this.statements = statements; - } + public CompoundNode(Location loc, Node ...statements) { + super(loc); + this.statements = statements; + } - public static ParseRes parseComma(Source src, int i, Node prev, int precedence) { - if (precedence > 1) return ParseRes.failed(); + public static ParseRes parseComma(Source src, int i, Node prev, int precedence) { + if (precedence > 1) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, ",")) return ParseRes.failed(); - n++; + if (!src.is(i + n, ",")) return ParseRes.failed(); + n++; - var curr = JavaScript.parseExpression(src, i + n, 2); - if (!curr.isSuccess()) return curr.chainError(src.loc(i + n), "Expected a value after the comma"); - n += curr.n; + var curr = JavaScript.parseExpression(src, i + n, 2); + if (!curr.isSuccess()) return curr.chainError(src.loc(i + n), "Expected a value after the comma"); + n += curr.n; - if (prev instanceof CompoundNode comp) { - var children = new ArrayList(); - children.addAll(Arrays.asList(comp.statements)); - children.add(curr.result); + if (prev instanceof CompoundNode comp) { + var children = new ArrayList(); + children.addAll(Arrays.asList(comp.statements)); + children.add(curr.result); - return ParseRes.res(new CompoundNode(loc, children.toArray(new Node[0])), n); - } - else return ParseRes.res(new CompoundNode(loc, prev, curr.result), n); - } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + return ParseRes.res(new CompoundNode(loc, children.toArray(new Node[0])), n); + } + else return ParseRes.res(new CompoundNode(loc, prev, curr.result), n); + } + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, "{")) return ParseRes.failed(); - n++; + if (!src.is(i + n, "{")) return ParseRes.failed(); + n++; - var statements = new ArrayList(); + var statements = new ArrayList(); - while (true) { - n += Parsing.skipEmpty(src, i + n); + while (true) { + n += Parsing.skipEmpty(src, i + n); - if (src.is(i + n, "}")) { - n++; - break; - } - if (src.is(i + n, ";")) { - n++; - continue; - } + if (src.is(i + n, "}")) { + n++; + break; + } + if (src.is(i + n, ";")) { + n++; + continue; + } - var res = JavaScript.parseStatement(src, i + n); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected a statement"); - n += res.n; + var res = JavaScript.parseStatement(src, i + n); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected a statement"); + n += res.n; - statements.add(res.result); - } + statements.add(res.result); + } - return ParseRes.res(new CompoundNode(loc, statements.toArray(new Node[0])).setEnd(src.loc(i + n - 1)), n); - } + return ParseRes.res(new CompoundNode(loc, statements.toArray(new Node[0])).setEnd(src.loc(i + n - 1)), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/DeferredIntSupplier.java b/src/main/java/me/topchetoeu/jscript/compilation/DeferredIntSupplier.java index e0cb484..dbb7eed 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/DeferredIntSupplier.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/DeferredIntSupplier.java @@ -3,17 +3,17 @@ package me.topchetoeu.jscript.compilation; import java.util.function.IntSupplier; public final class DeferredIntSupplier implements IntSupplier { - private int value; - private boolean set; + private int value; + private boolean set; - public void set(int val) { - if (set) throw new RuntimeException("A deferred int supplier may be set only once"); - value = val; - set = true; - } + public void set(int val) { + if (set) throw new RuntimeException("A deferred int supplier may be set only once"); + value = val; + set = true; + } - @Override public int getAsInt() { - if (!set) throw new RuntimeException("Deferred int supplier accessed too early"); - return value; - } + @Override public int getAsInt() { + if (!set) throw new RuntimeException("Deferred int supplier accessed too early"); + return value; + } } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/compilation/FunctionNode.java b/src/main/java/me/topchetoeu/jscript/compilation/FunctionNode.java index 107d0d5..8bfbcc0 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/FunctionNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/FunctionNode.java @@ -13,38 +13,38 @@ import me.topchetoeu.jscript.compilation.scope.FunctionScope; import me.topchetoeu.jscript.compilation.values.VariableNode; public abstract class FunctionNode extends Node { - public final CompoundNode body; - public final List params; - public final Location end; + public final CompoundNode body; + public final List params; + public final Location end; - public abstract String name(); + public abstract String name(); public final String name(String fallback) { - return this.name() != null ? this.name() : fallback; + return this.name() != null ? this.name() : fallback; + } + protected final int[] captures(CompileResult target) { + return target.childrenMap.get(this).scope.getCaptureIndices(); } - protected final int[] captures(CompileResult target) { - return target.childrenMap.get(this).scope.getCaptureIndices(); - } - protected final Environment rootEnv(Environment env) { - return env.get(JavaScript.COMPILE_ROOT); - } + protected final Environment rootEnv(Environment env) { + return env.get(JavaScript.COMPILE_ROOT); + } - @Override public void resolve(CompileResult target) { } + @Override public void resolve(CompileResult target) { } - public final CompileResult compileBody(Environment env, FunctionScope scope, boolean lastReturn, String selfName) { - var target = new CompileResult(env, scope, params.size()); + public final CompileResult compileBody(Environment env, FunctionScope scope, boolean lastReturn, String selfName) { + var target = new CompileResult(env, scope, params.size()); var i = 0; body.resolve(target); for (var param : params) scope.define(param.name); - // if (selfName != null && !scope.has(selfName, false)) { - // var i = scope.defineSpecial(new Variable(selfName, true), end); + var hasSelf = false; - // t.add(Instruction.loadCalled()); - // t.add(_i -> i.index().toInit()); - // } + if (selfName != null && !scope.has(selfName, false)) { + hasSelf = true; + scope.define(selfName); + } body.compileFunctions(target); @@ -52,70 +52,74 @@ public abstract class FunctionNode extends Node { target.add(Instruction.loadArg(i++)).setLocation(param.loc()); target.add(scope.define(param.name).index().toSet(false)).setLocation(param.loc()); } + if (hasSelf) { + target.add(Instruction.loadCalled()); + target.add(scope.define(selfName).index().toSet(false)); + } body.compile(target, lastReturn, BreakpointType.NONE); return target; } - public final CompileResult compileBody(CompileResult parent, String selfName) { - return compileBody(rootEnv(parent.env).child(), new FunctionScope(parent.scope), false, selfName); - } + public final CompileResult compileBody(CompileResult parent, String selfName) { + return compileBody(rootEnv(parent.env).child(), new FunctionScope(parent.scope), false, selfName); + } - public abstract void compile(CompileResult target, boolean pollute, String name, BreakpointType bp); - public void compile(CompileResult target, boolean pollute, String name) { - compile(target, pollute, name, BreakpointType.NONE); - } - @Override public void compile(CompileResult target, boolean pollute, BreakpointType bp) { - compile(target, pollute, (String)null, bp); - } - @Override public void compile(CompileResult target, boolean pollute) { - compile(target, pollute, (String)null, BreakpointType.NONE); - } + public abstract void compile(CompileResult target, boolean pollute, String name, BreakpointType bp); + public void compile(CompileResult target, boolean pollute, String name) { + compile(target, pollute, name, BreakpointType.NONE); + } + @Override public void compile(CompileResult target, boolean pollute, BreakpointType bp) { + compile(target, pollute, (String)null, bp); + } + @Override public void compile(CompileResult target, boolean pollute) { + compile(target, pollute, (String)null, BreakpointType.NONE); + } - public FunctionNode(Location loc, Location end, List params, CompoundNode body) { - super(loc); + public FunctionNode(Location loc, Location end, List params, CompoundNode body) { + super(loc); - this.end = end; - this.params = params; - this.body = body; - } + this.end = end; + this.params = params; + this.body = body; + } - public static void compileWithName(Node stm, CompileResult target, boolean pollute, String name) { - if (stm instanceof FunctionNode) ((FunctionNode)stm).compile(target, pollute, name); - else stm.compile(target, pollute); - } - public static void compileWithName(Node stm, CompileResult target, boolean pollute, String name, BreakpointType bp) { - if (stm instanceof FunctionNode) ((FunctionNode)stm).compile(target, pollute, name, bp); - else stm.compile(target, pollute, bp); - } + public static void compileWithName(Node stm, CompileResult target, boolean pollute, String name) { + if (stm instanceof FunctionNode) ((FunctionNode)stm).compile(target, pollute, name); + else stm.compile(target, pollute); + } + public static void compileWithName(Node stm, CompileResult target, boolean pollute, String name, BreakpointType bp) { + if (stm instanceof FunctionNode) ((FunctionNode)stm).compile(target, pollute, name, bp); + else stm.compile(target, pollute, bp); + } - public static ParseRes parseFunction(Source src, int i, boolean statement) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parseFunction(Source src, int i, boolean statement) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!Parsing.isIdentifier(src, i + n, "function")) return ParseRes.failed(); - n += 8; + if (!Parsing.isIdentifier(src, i + n, "function")) return ParseRes.failed(); + n += 8; - var name = Parsing.parseIdentifier(src, i + n); - if (!name.isSuccess() && statement) return ParseRes.error(src.loc(i + n), "A statement function requires a name"); - n += name.n; - n += Parsing.skipEmpty(src, i + n); + var name = Parsing.parseIdentifier(src, i + n); + if (!name.isSuccess() && statement) return ParseRes.error(src.loc(i + n), "A statement function requires a name"); + n += name.n; + n += Parsing.skipEmpty(src, i + n); - var params = JavaScript.parseParameters(src, i + n); - if (!params.isSuccess()) return params.chainError(src.loc(i + n), "Expected a parameter list"); - n += params.n; + var params = JavaScript.parseParameters(src, i + n); + if (!params.isSuccess()) return params.chainError(src.loc(i + n), "Expected a parameter list"); + n += params.n; - var body = CompoundNode.parse(src, i + n); - if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a compound statement for function"); - n += body.n; + var body = CompoundNode.parse(src, i + n); + if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a compound statement for function"); + n += body.n; - if (statement) return ParseRes.res(new FunctionStatementNode( - loc, src.loc(i + n - 1), - params.result, body.result, name.result - ), n); - else return ParseRes.res(new FunctionValueNode( - loc, src.loc(i + n - 1), - params.result, body.result, name.result - ), n); - } + if (statement) return ParseRes.res(new FunctionStatementNode( + loc, src.loc(i + n - 1), + params.result, body.result, name.result + ), n); + else return ParseRes.res(new FunctionValueNode( + loc, src.loc(i + n - 1), + params.result, body.result, name.result + ), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/FunctionStatementNode.java b/src/main/java/me/topchetoeu/jscript/compilation/FunctionStatementNode.java index 97a4e09..b1f7230 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/FunctionStatementNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/FunctionStatementNode.java @@ -9,25 +9,25 @@ import me.topchetoeu.jscript.compilation.scope.Variable; import me.topchetoeu.jscript.compilation.values.VariableNode; public class FunctionStatementNode extends FunctionNode { - public final String name; + public final String name; - @Override public String name() { return name; } + @Override public String name() { return name; } - @Override public void resolve(CompileResult target) { - target.scope.define(new Variable(name, false)); - } + @Override public void resolve(CompileResult target) { + target.scope.define(new Variable(name, false)); + } @Override public void compileFunctions(CompileResult target) { target.addChild(this, compileBody(target, name())); } - @Override public void compile(CompileResult target, boolean pollute, String name, BreakpointType bp) { - target.add(Instruction.loadFunc(target.childrenIndices.get(this), name(name), captures(target))).setLocation(loc()); - target.add(VariableNode.toSet(target, end, this.name, false, true)).setLocation(loc()); - if (pollute) target.add(Instruction.pushUndefined()); - } + @Override public void compile(CompileResult target, boolean pollute, String name, BreakpointType bp) { + target.add(Instruction.loadFunc(target.childrenIndices.get(this), name(name), captures(target))).setLocation(loc()); + target.add(VariableNode.toSet(target, end, this.name, false, true)).setLocation(loc()); + if (pollute) target.add(Instruction.pushUndefined()); + } - public FunctionStatementNode(Location loc, Location end, List params, CompoundNode body, String name) { - super(loc, end, params, body); - this.name = name; - } + public FunctionStatementNode(Location loc, Location end, List params, CompoundNode body, String name) { + super(loc, end, params, body); + this.name = name; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/FunctionValueNode.java b/src/main/java/me/topchetoeu/jscript/compilation/FunctionValueNode.java index 05f2db3..dbc2787 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/FunctionValueNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/FunctionValueNode.java @@ -8,21 +8,21 @@ import me.topchetoeu.jscript.common.parsing.Location; import me.topchetoeu.jscript.compilation.values.VariableNode; public class FunctionValueNode extends FunctionNode { - public final String name; + public final String name; - @Override public String name() { return name; } + @Override public String name() { return name; } @Override public void compileFunctions(CompileResult target) { target.addChild(this, compileBody(target, name())); } - @Override public void compile(CompileResult target, boolean pollute, String name, BreakpointType bp) { - target.add(Instruction.loadFunc(target.childrenIndices.get(this), name(name), captures(target))).setLocation(loc()); - if (!pollute) target.add(Instruction.discard()); - } + @Override public void compile(CompileResult target, boolean pollute, String name, BreakpointType bp) { + target.add(Instruction.loadFunc(target.childrenIndices.get(this), name(name), captures(target))).setLocation(loc()); + if (!pollute) target.add(Instruction.discard()); + } - public FunctionValueNode(Location loc, Location end, List params, CompoundNode body, String name) { - super(loc, end, params, body); - this.name = name; - } + public FunctionValueNode(Location loc, Location end, List params, CompoundNode body, String name) { + super(loc, end, params, body); + this.name = name; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/JavaScript.java b/src/main/java/me/topchetoeu/jscript/compilation/JavaScript.java index 829d1f0..2fd20e0 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/JavaScript.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/JavaScript.java @@ -47,242 +47,242 @@ import me.topchetoeu.jscript.compilation.values.operations.PostfixNode; import me.topchetoeu.jscript.compilation.values.operations.TypeofNode; public final class JavaScript { - public static enum DeclarationType { + public static enum DeclarationType { @Deprecated - VAR; - } + VAR; + } - public static final Key COMPILE_ROOT = Key.of(); + public static final Key COMPILE_ROOT = new Key<>(); - static final Set reserved = new HashSet<>(Arrays.asList( - "true", "false", "void", "null", "this", "if", "else", "try", "catch", - "finally", "for", "do", "while", "switch", "case", "default", "new", - "function", "var", "return", "throw", "typeof", "delete", "break", - "continue", "debugger", "implements", "interface", "package", "private", - "protected", "public", "static", "arguments", "class", "extends" - )); + static final Set reserved = new HashSet<>(Arrays.asList( + "true", "false", "void", "null", "this", "if", "else", "try", "catch", + "finally", "for", "do", "while", "switch", "case", "default", "new", + "function", "var", "return", "throw", "typeof", "delete", "break", + "continue", "debugger", "implements", "interface", "package", "private", + "protected", "public", "static", "arguments", "class", "extends" + )); - public static ParseRes parseParens(Source src, int i) { - int n = 0; + public static ParseRes parseParens(Source src, int i) { + int n = 0; - var openParen = Parsing.parseOperator(src, i + n, "("); - if (!openParen.isSuccess()) return openParen.chainError(); - n += openParen.n; + var openParen = Parsing.parseOperator(src, i + n, "("); + if (!openParen.isSuccess()) return openParen.chainError(); + n += openParen.n; - var res = JavaScript.parseExpression(src, i + n, 0); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected an expression in parens"); - n += res.n; + var res = JavaScript.parseExpression(src, i + n, 0); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected an expression in parens"); + n += res.n; - var closeParen = Parsing.parseOperator(src, i + n, ")"); - if (!closeParen.isSuccess()) return closeParen.chainError(src.loc(i + n), "Expected a closing paren"); - n += closeParen.n; + var closeParen = Parsing.parseOperator(src, i + n, ")"); + if (!closeParen.isSuccess()) return closeParen.chainError(src.loc(i + n), "Expected a closing paren"); + n += closeParen.n; - return ParseRes.res(res.result, n); - } + return ParseRes.res(res.result, n); + } - public static ParseRes parseSimple(Source src, int i, boolean statement) { - return ParseRes.first(src, i, - (s, j) -> statement ? ParseRes.failed() : ObjectNode.parse(s, j), - (s, j) -> statement ? ParseRes.failed() : FunctionNode.parseFunction(s, j, false), - JavaScript::parseLiteral, - StringNode::parse, - RegexNode::parse, - NumberNode::parse, - ChangeNode::parsePrefixDecrease, - ChangeNode::parsePrefixIncrease, - OperationNode::parsePrefix, - ArrayNode::parse, - JavaScript::parseParens, - CallNode::parseNew, - TypeofNode::parse, - DiscardNode::parse, - DeleteNode::parse, - VariableNode::parse - ); - } + public static ParseRes parseSimple(Source src, int i, boolean statement) { + return ParseRes.first(src, i, + (s, j) -> statement ? ParseRes.failed() : ObjectNode.parse(s, j), + (s, j) -> statement ? ParseRes.failed() : FunctionNode.parseFunction(s, j, false), + JavaScript::parseLiteral, + StringNode::parse, + RegexNode::parse, + NumberNode::parse, + ChangeNode::parsePrefixDecrease, + ChangeNode::parsePrefixIncrease, + OperationNode::parsePrefix, + ArrayNode::parse, + JavaScript::parseParens, + CallNode::parseNew, + TypeofNode::parse, + DiscardNode::parse, + DeleteNode::parse, + VariableNode::parse + ); + } - public static ParseRes parseLiteral(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parseLiteral(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var id = Parsing.parseIdentifier(src, i); - if (!id.isSuccess()) return id.chainError(); - n += id.n; + var id = Parsing.parseIdentifier(src, i); + if (!id.isSuccess()) return id.chainError(); + n += id.n; - if (id.result.equals("true")) return ParseRes.res(new BoolNode(loc, true), n); - if (id.result.equals("false")) return ParseRes.res(new BoolNode(loc, false), n); - if (id.result.equals("null")) return ParseRes.res(new NullNode(loc), n); - if (id.result.equals("this")) return ParseRes.res(new ThisNode(loc), n); - if (id.result.equals("arguments")) return ParseRes.res(new ArgumentsNode(loc), n); - if (id.result.equals("globalThis")) return ParseRes.res(new GlobalThisNode(loc), n); + if (id.result.equals("true")) return ParseRes.res(new BoolNode(loc, true), n); + if (id.result.equals("false")) return ParseRes.res(new BoolNode(loc, false), n); + if (id.result.equals("null")) return ParseRes.res(new NullNode(loc), n); + if (id.result.equals("this")) return ParseRes.res(new ThisNode(loc), n); + if (id.result.equals("arguments")) return ParseRes.res(new ArgumentsNode(loc), n); + if (id.result.equals("globalThis")) return ParseRes.res(new GlobalThisNode(loc), n); - return ParseRes.failed(); - } + return ParseRes.failed(); + } - public static ParseRes parseExpression(Source src, int i, int precedence, boolean statement) { - var n = Parsing.skipEmpty(src, i); - Node prev = null; + public static ParseRes parseExpression(Source src, int i, int precedence, boolean statement) { + var n = Parsing.skipEmpty(src, i); + Node prev = null; - while (true) { - if (prev == null) { - var res = parseSimple(src, i + n, statement); - if (res.isSuccess()) { - n += res.n; - prev = res.result; - } - else if (res.isError()) return res.chainError(); - else break; - } - else { - var _prev = prev; - ParseRes res = ParseRes.first(src, i + n, - (s, j) -> OperationNode.parseInstanceof(s, j, _prev, precedence), - (s, j) -> OperationNode.parseIn(s, j, _prev, precedence), - (s, j) -> PostfixNode.parsePostfixIncrease(s, j, _prev, precedence), - (s, j) -> PostfixNode.parsePostfixDecrease(s, j, _prev, precedence), - (s, j) -> OperationNode.parseOperator(s, j, _prev, precedence), - (s, j) -> IfNode.parseTernary(s, j, _prev, precedence), - (s, j) -> IndexNode.parseMember(s, j, _prev, precedence), - (s, j) -> IndexNode.parseIndex(s, j, _prev, precedence), - (s, j) -> CallNode.parseCall(s, j, _prev, precedence), - (s, j) -> CompoundNode.parseComma(s, j, _prev, precedence) - ); + while (true) { + if (prev == null) { + var res = parseSimple(src, i + n, statement); + if (res.isSuccess()) { + n += res.n; + prev = res.result; + } + else if (res.isError()) return res.chainError(); + else break; + } + else { + var _prev = prev; + ParseRes res = ParseRes.first(src, i + n, + (s, j) -> OperationNode.parseInstanceof(s, j, _prev, precedence), + (s, j) -> OperationNode.parseIn(s, j, _prev, precedence), + (s, j) -> PostfixNode.parsePostfixIncrease(s, j, _prev, precedence), + (s, j) -> PostfixNode.parsePostfixDecrease(s, j, _prev, precedence), + (s, j) -> OperationNode.parseOperator(s, j, _prev, precedence), + (s, j) -> IfNode.parseTernary(s, j, _prev, precedence), + (s, j) -> IndexNode.parseMember(s, j, _prev, precedence), + (s, j) -> IndexNode.parseIndex(s, j, _prev, precedence), + (s, j) -> CallNode.parseCall(s, j, _prev, precedence), + (s, j) -> CompoundNode.parseComma(s, j, _prev, precedence) + ); - if (res.isSuccess()) { - n += res.n; - prev = res.result; - continue; - } - else if (res.isError()) return res.chainError(); + if (res.isSuccess()) { + n += res.n; + prev = res.result; + continue; + } + else if (res.isError()) return res.chainError(); - break; - } - } + break; + } + } - if (prev == null) return ParseRes.failed(); - else return ParseRes.res(prev, n); - } + if (prev == null) return ParseRes.failed(); + else return ParseRes.res(prev, n); + } - public static ParseRes parseExpression(Source src, int i, int precedence) { - return parseExpression(src, i, precedence, false); - } + public static ParseRes parseExpression(Source src, int i, int precedence) { + return parseExpression(src, i, precedence, false); + } - public static ParseRes parseExpressionStatement(Source src, int i) { - var res = parseExpression(src, i, 0, true); - if (!res.isSuccess()) return res.chainError(); + public static ParseRes parseExpressionStatement(Source src, int i) { + var res = parseExpression(src, i, 0, true); + if (!res.isSuccess()) return res.chainError(); - var end = JavaScript.parseStatementEnd(src, i + res.n); - if (!end.isSuccess()) return ParseRes.error(src.loc(i + res.n), "Expected an end of statement"); + var end = JavaScript.parseStatementEnd(src, i + res.n); + if (!end.isSuccess()) return ParseRes.error(src.loc(i + res.n), "Expected an end of statement"); - return res.addN(end.n); - } + return res.addN(end.n); + } - public static ParseRes parseStatement(Source src, int i) { - var n = Parsing.skipEmpty(src, i); + public static ParseRes parseStatement(Source src, int i) { + var n = Parsing.skipEmpty(src, i); - if (src.is(i + n, ";")) return ParseRes.res(new DiscardNode(src.loc(i+ n), null), n + 1); - if (Parsing.isIdentifier(src, i + n, "with")) return ParseRes.error(src.loc(i + n), "'with' statements are not allowed."); + if (src.is(i + n, ";")) return ParseRes.res(new DiscardNode(src.loc(i+ n), null), n + 1); + if (Parsing.isIdentifier(src, i + n, "with")) return ParseRes.error(src.loc(i + n), "'with' statements are not allowed."); - ParseRes res = ParseRes.first(src, i + n, - VariableDeclareNode::parse, - ReturnNode::parse, - ThrowNode::parse, - ContinueNode::parse, - BreakNode::parse, - DebugNode::parse, - IfNode::parse, - WhileNode::parse, - SwitchNode::parse, - ForNode::parse, - ForInNode::parse, - DoWhileNode::parse, - TryNode::parse, - CompoundNode::parse, - (s, j) -> FunctionNode.parseFunction(s, j, true), - JavaScript::parseExpressionStatement - ); - return res.addN(n); - } + ParseRes res = ParseRes.first(src, i + n, + VariableDeclareNode::parse, + ReturnNode::parse, + ThrowNode::parse, + ContinueNode::parse, + BreakNode::parse, + DebugNode::parse, + IfNode::parse, + WhileNode::parse, + SwitchNode::parse, + ForNode::parse, + ForInNode::parse, + DoWhileNode::parse, + TryNode::parse, + CompoundNode::parse, + (s, j) -> FunctionNode.parseFunction(s, j, true), + JavaScript::parseExpressionStatement + ); + return res.addN(n); + } - public static ParseRes parseStatementEnd(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - if (i + n >= src.size()) return ParseRes.res(true, n); + public static ParseRes parseStatementEnd(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + if (i + n >= src.size()) return ParseRes.res(true, n); - for (var j = i; j < i + n; j++) { - if (src.is(j, '\n')) return ParseRes.res(true, n); - } + for (var j = i; j < i + n; j++) { + if (src.is(j, '\n')) return ParseRes.res(true, n); + } - if (src.is(i + n, ';')) return ParseRes.res(true, n + 1); - if (src.is(i + n, '}')) return ParseRes.res(true, n); + if (src.is(i + n, ';')) return ParseRes.res(true, n + 1); + if (src.is(i + n, '}')) return ParseRes.res(true, n); - return ParseRes.failed(); - } + return ParseRes.failed(); + } - public static ParseRes parseDeclarationType(Source src, int i) { - var res = Parsing.parseIdentifier(src, i); - if (!res.isSuccess()) return res.chainError(); + public static ParseRes parseDeclarationType(Source src, int i) { + var res = Parsing.parseIdentifier(src, i); + if (!res.isSuccess()) return res.chainError(); - if (res.result.equals("var")) return ParseRes.res(true, res.n); + if (res.result.equals("var")) return ParseRes.res(true, res.n); - return ParseRes.failed(); - } + return ParseRes.failed(); + } - public static Node[] parse(Environment env, Filename filename, String raw) { - var src = new Source(env, filename, raw); - var list = new ArrayList(); - int i = 0; + public static Node[] parse(Environment env, Filename filename, String raw) { + var src = new Source(env, filename, raw); + var list = new ArrayList(); + int i = 0; - while (true) { - if (i >= src.size()) break; + while (true) { + if (i >= src.size()) break; - var res = parseStatement(src, i); + var res = parseStatement(src, i); - if (res.isError()) throw new SyntaxException(res.errorLocation, res.error); - else if (res.isFailed()) throw new SyntaxException(src.loc(i), "Unexpected syntax"); + if (res.isError()) throw new SyntaxException(res.errorLocation, res.error); + else if (res.isFailed()) throw new SyntaxException(src.loc(i), "Unexpected syntax"); - i += res.n; - i += Parsing.skipEmpty(src, i); + i += res.n; + i += Parsing.skipEmpty(src, i); - list.add(res.result); - } + list.add(res.result); + } - return list.toArray(new Node[0]); - } + return list.toArray(new Node[0]); + } - public static boolean checkVarName(String name) { - return !JavaScript.reserved.contains(name); - } + public static boolean checkVarName(String name) { + return !JavaScript.reserved.contains(name); + } - public static CompileResult compile(Environment env, Node ...statements) { - env = env.child(); - env.add(COMPILE_ROOT, env); + public static CompileResult compile(Environment env, Node ...statements) { + env = env.child(); + env.add(COMPILE_ROOT, env); - var func = new FunctionValueNode(null, null, Arrays.asList(), new CompoundNode(null, statements), null); - var res = func.compileBody(env, new FunctionScope(true), true, null); - return res; - } + var func = new FunctionValueNode(null, null, Arrays.asList(), new CompoundNode(null, statements), null); + var res = func.compileBody(env, new FunctionScope(true), true, null); + return res; + } - public static CompileResult compile(Environment env, Filename filename, String raw) { - return JavaScript.compile(env, JavaScript.parse(env, filename, raw)); - } - public static CompileResult compile(Filename filename, String raw) { - var env = new Environment(); - return JavaScript.compile(env, JavaScript.parse(env, filename, raw)); - } + public static CompileResult compile(Environment env, Filename filename, String raw) { + return JavaScript.compile(env, JavaScript.parse(env, filename, raw)); + } + public static CompileResult compile(Filename filename, String raw) { + var env = new Environment(); + return JavaScript.compile(env, JavaScript.parse(env, filename, raw)); + } - public static ParseRes parseLabel(Source src, int i) { - int n = Parsing.skipEmpty(src, i); - - var nameRes = Parsing.parseIdentifier(src, i + n); - if (!nameRes.isSuccess()) return nameRes.chainError(); - n += nameRes.n; - n += Parsing.skipEmpty(src, i + n); - - if (!src.is(i + n, ":")) return ParseRes.failed(); - n++; - - return ParseRes.res(nameRes.result, n); - } + public static ParseRes parseLabel(Source src, int i) { + int n = Parsing.skipEmpty(src, i); + + var nameRes = Parsing.parseIdentifier(src, i + n); + if (!nameRes.isSuccess()) return nameRes.chainError(); + n += nameRes.n; + n += Parsing.skipEmpty(src, i + n); + + if (!src.is(i + n, ":")) return ParseRes.failed(); + n++; + + return ParseRes.res(nameRes.result, n); + } public static ParseRes> parseParameters(Source src, int i) { var n = Parsing.skipEmpty(src, i); diff --git a/src/main/java/me/topchetoeu/jscript/compilation/LabelContext.java b/src/main/java/me/topchetoeu/jscript/compilation/LabelContext.java index a9cfe03..0c8eb2f 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/LabelContext.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/LabelContext.java @@ -13,20 +13,20 @@ import me.topchetoeu.jscript.common.environment.Key; import me.topchetoeu.jscript.common.parsing.Location; public class LabelContext { - public static final Key BREAK_CTX = Key.of(); - public static final Key CONTINUE_CTX = Key.of(); + public static final Key BREAK_CTX = new Key<>(); + public static final Key CONTINUE_CTX = new Key<>(); - private final LinkedList list = new LinkedList<>(); - private final HashMap map = new HashMap<>(); + private final LinkedList list = new LinkedList<>(); + private final HashMap map = new HashMap<>(); private final Stack> deferredAdders = new Stack<>(); - public IntSupplier get() { - return list.peekLast(); - } - public IntSupplier get(String name) { - return map.get(name); - } + public IntSupplier get() { + return list.peekLast(); + } + public IntSupplier get(String name) { + return map.get(name); + } public void flushAdders() { for (var adder : deferredAdders.peek()) { @@ -36,71 +36,71 @@ public class LabelContext { deferredAdders.pop(); } - public boolean jump(CompileResult target) { - var res = get(); - if (res != null) { + public boolean jump(CompileResult target) { + var res = get(); + if (res != null) { var tmp = target.temp(); this.deferredAdders.peek().add(() -> target.set(tmp, Instruction.jmp(res.getAsInt() - tmp))); return true; } else return false; - } - public boolean jump(CompileResult target, String name) { - var res = get(name); - if (res != null) { + } + public boolean jump(CompileResult target, String name) { + var res = get(name); + if (res != null) { var tmp = target.temp(); this.deferredAdders.peek().add(() -> target.set(tmp, Instruction.jmp(res.getAsInt() - tmp))); return true; } else return false; - } + } - public void push(IntSupplier jumpTarget) { - list.add(jumpTarget); - } - public void push(Location loc, String name, IntSupplier jumpTarget) { - if (name == null) return; - if (map.containsKey(name)) throw new SyntaxException(loc, String.format("Label '%s' has already been declared", name)); - map.put(name, jumpTarget); - } + public void push(IntSupplier jumpTarget) { + list.add(jumpTarget); + } + public void push(Location loc, String name, IntSupplier jumpTarget) { + if (name == null) return; + if (map.containsKey(name)) throw new SyntaxException(loc, String.format("Label '%s' has already been declared", name)); + map.put(name, jumpTarget); + } - public void pushLoop(Location loc, String name, IntSupplier jumpTarget) { - push(jumpTarget); - push(loc, name, jumpTarget); + public void pushLoop(Location loc, String name, IntSupplier jumpTarget) { + push(jumpTarget); + push(loc, name, jumpTarget); deferredAdders.push(new ArrayList<>()); - } + } - public void pop() { - list.removeLast(); - } - public void pop(String name) { - if (name == null) return; - map.remove(name); - } + public void pop() { + list.removeLast(); + } + public void pop(String name) { + if (name == null) return; + map.remove(name); + } - public void popLoop(String name) { - pop(); - pop(name); + public void popLoop(String name) { + pop(); + pop(name); flushAdders(); - } + } - public static LabelContext getBreak(Environment env) { - return env.initFrom(BREAK_CTX, () -> new LabelContext()); - } - public static LabelContext getCont(Environment env) { - return env.initFrom(CONTINUE_CTX, () -> new LabelContext()); - } + public static LabelContext getBreak(Environment env) { + return env.initFrom(BREAK_CTX, () -> new LabelContext()); + } + public static LabelContext getCont(Environment env) { + return env.initFrom(CONTINUE_CTX, () -> new LabelContext()); + } - public static void pushLoop(Environment env, Location loc, String name, IntSupplier breakTarget, int contTarget) { - LabelContext.getBreak(env).pushLoop(loc, name, breakTarget); - LabelContext.getCont(env).pushLoop(loc, name, () -> contTarget); - } - public static void pushLoop(Environment env, Location loc, String name, IntSupplier breakTarget, IntSupplier contTarget) { - LabelContext.getBreak(env).pushLoop(loc, name, breakTarget); - LabelContext.getCont(env).pushLoop(loc, name, contTarget); - } - public static void popLoop(Environment env, String name) { - LabelContext.getBreak(env).popLoop(name); - LabelContext.getCont(env).popLoop(name); - } + public static void pushLoop(Environment env, Location loc, String name, IntSupplier breakTarget, int contTarget) { + LabelContext.getBreak(env).pushLoop(loc, name, breakTarget); + LabelContext.getCont(env).pushLoop(loc, name, () -> contTarget); + } + public static void pushLoop(Environment env, Location loc, String name, IntSupplier breakTarget, IntSupplier contTarget) { + LabelContext.getBreak(env).pushLoop(loc, name, breakTarget); + LabelContext.getCont(env).pushLoop(loc, name, contTarget); + } + public static void popLoop(Environment env, String name) { + LabelContext.getBreak(env).popLoop(name); + LabelContext.getCont(env).popLoop(name); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/Node.java b/src/main/java/me/topchetoeu/jscript/compilation/Node.java index 033aa44..071c904 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/Node.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/Node.java @@ -4,25 +4,25 @@ import me.topchetoeu.jscript.common.Instruction.BreakpointType; import me.topchetoeu.jscript.common.parsing.Location; public abstract class Node { - private Location loc; + private Location loc; - public void resolve(CompileResult target) {} + public void resolve(CompileResult target) {} - public void compile(CompileResult target, boolean pollute, BreakpointType type) { - int start = target.size(); - compile(target, pollute); - if (target.size() != start) target.setLocationAndDebug(start, loc(), type); - } - public void compile(CompileResult target, boolean pollute) { - compile(target, pollute, BreakpointType.NONE); - } + public void compile(CompileResult target, boolean pollute, BreakpointType type) { + int start = target.size(); + compile(target, pollute); + if (target.size() != start) target.setLocationAndDebug(start, loc(), type); + } + public void compile(CompileResult target, boolean pollute) { + compile(target, pollute, BreakpointType.NONE); + } public abstract void compileFunctions(CompileResult target); - public Location loc() { return loc; } - public void setLoc(Location loc) { this.loc = loc; } + public Location loc() { return loc; } + public void setLoc(Location loc) { this.loc = loc; } - protected Node(Location loc) { - this.loc = loc; - } + protected Node(Location loc) { + this.loc = loc; + } } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/compilation/NodeChildren.java b/src/main/java/me/topchetoeu/jscript/compilation/NodeChildren.java index 6080fbc..b912517 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/NodeChildren.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/NodeChildren.java @@ -5,89 +5,89 @@ import java.util.Iterator; import java.util.function.Function; public final class NodeChildren implements Iterable { - public static final class Slot { - private Node node; - private final Function replacer; + public static final class Slot { + private Node node; + private final Function replacer; - public final void replace(Node node) { - this.node = this.replacer.apply(node); - } + public final void replace(Node node) { + this.node = this.replacer.apply(node); + } - public Slot(Node nodes, Function replacer) { - this.node = nodes; - this.replacer = replacer; - } - } + public Slot(Node nodes, Function replacer) { + this.node = nodes; + this.replacer = replacer; + } + } - private final Slot[] slots; + private final Slot[] slots; - private NodeChildren(Slot[] slots) { - this.slots = slots; - } + private NodeChildren(Slot[] slots) { + this.slots = slots; + } - @Override public Iterator iterator() { - return new Iterator() { - private int i = 0; - private Slot[] arr = slots; + @Override public Iterator iterator() { + return new Iterator() { + private int i = 0; + private Slot[] arr = slots; - @Override public boolean hasNext() { - if (arr == null) return false; - else if (i >= arr.length) { - arr = null; - return false; - } - else return true; - } - @Override public Node next() { - if (!hasNext()) return null; - return arr[i++].node; - } - }; - } - public Iterable slots() { - return () -> new Iterator() { - private int i = 0; - private Slot[] arr = slots; + @Override public boolean hasNext() { + if (arr == null) return false; + else if (i >= arr.length) { + arr = null; + return false; + } + else return true; + } + @Override public Node next() { + if (!hasNext()) return null; + return arr[i++].node; + } + }; + } + public Iterable slots() { + return () -> new Iterator() { + private int i = 0; + private Slot[] arr = slots; - @Override public boolean hasNext() { - if (arr == null) return false; - else if (i >= arr.length) { - arr = null; - return false; - } - else return true; - } - @Override public Slot next() { - if (!hasNext()) return null; - return arr[i++]; - } - }; - } + @Override public boolean hasNext() { + if (arr == null) return false; + else if (i >= arr.length) { + arr = null; + return false; + } + else return true; + } + @Override public Slot next() { + if (!hasNext()) return null; + return arr[i++]; + } + }; + } - public static final class Builder { - private final ArrayList slots = new ArrayList<>(); + public static final class Builder { + private final ArrayList slots = new ArrayList<>(); - public final Builder add(Slot ...children) { - for (var child : children) { - this.slots.add(child); - } + public final Builder add(Slot ...children) { + for (var child : children) { + this.slots.add(child); + } - return this; - } - public final Builder add(Iterable children) { - for (var child : children) { - this.slots.add(child); - } + return this; + } + public final Builder add(Iterable children) { + for (var child : children) { + this.slots.add(child); + } - return this; - } - public final Builder add(Node child, Function replacer) { - slots.add(new Slot(child, replacer)); - return this; - } + return this; + } + public final Builder add(Node child, Function replacer) { + slots.add(new Slot(child, replacer)); + return this; + } - public final NodeChildren build() { - return new NodeChildren(slots.toArray(new Slot[0])); - } - } + public final NodeChildren build() { + return new NodeChildren(slots.toArray(new Slot[0])); + } + } } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/compilation/Parameter.java b/src/main/java/me/topchetoeu/jscript/compilation/Parameter.java index 9404d5d..09f8ed6 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/Parameter.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/Parameter.java @@ -3,13 +3,13 @@ package me.topchetoeu.jscript.compilation; import me.topchetoeu.jscript.common.parsing.Location; public final class Parameter { - public final Location loc; - public final String name; - public final Node node; + public final Location loc; + public final String name; + public final Node node; - public Parameter(Location loc, String name, Node node) { - this.name = name; - this.node = node; - this.loc = loc; - } + public Parameter(Location loc, String name, Node node) { + this.name = name; + this.node = node; + this.loc = loc; + } } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/compilation/VariableDeclareNode.java b/src/main/java/me/topchetoeu/jscript/compilation/VariableDeclareNode.java index 083bf57..450cbc2 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/VariableDeclareNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/VariableDeclareNode.java @@ -14,89 +14,89 @@ import me.topchetoeu.jscript.compilation.values.VariableNode; public class VariableDeclareNode extends Node { @Desugar - public static record Pair(VariableNode var, Node value) { } + public static record Pair(VariableNode var, Node value) { } - public final List values; + public final List values; - @Override public void resolve(CompileResult target) { + @Override public void resolve(CompileResult target) { for (var entry : values) { target.scope.define(entry.var.name); } - } + } @Override public void compileFunctions(CompileResult target) { for (var pair : values) { if (pair.value != null) pair.value.compileFunctions(target); } } - @Override public void compile(CompileResult target, boolean pollute) { - for (var entry : values) { - if (entry.value != null) { - entry.value.compile(target, true); + @Override public void compile(CompileResult target, boolean pollute) { + for (var entry : values) { + if (entry.value != null) { + entry.value.compile(target, true); target.add(VariableNode.toSet(target, loc(), entry.var.name, false, true)).setLocation(loc()); - } - } + } + } - if (pollute) target.add(Instruction.pushUndefined()); - } + if (pollute) target.add(Instruction.pushUndefined()); + } - public VariableDeclareNode(Location loc, List values) { - super(loc); - this.values = values; - } + public VariableDeclareNode(Location loc, List values) { + super(loc); + this.values = values; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var declType = JavaScript.parseDeclarationType(src, i + n); - if (!declType.isSuccess()) return declType.chainError(); - n += declType.n; + var declType = JavaScript.parseDeclarationType(src, i + n); + if (!declType.isSuccess()) return declType.chainError(); + n += declType.n; - var res = new ArrayList(); + var res = new ArrayList(); - var end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new VariableDeclareNode(loc, res), n); - } + var end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new VariableDeclareNode(loc, res), n); + } - while (true) { - var nameLoc = src.loc(i + n); + while (true) { + var nameLoc = src.loc(i + n); - var name = Parsing.parseIdentifier(src, i + n); - if (!name.isSuccess()) return name.chainError(nameLoc, "Expected a variable name"); - n += name.n; + var name = Parsing.parseIdentifier(src, i + n); + if (!name.isSuccess()) return name.chainError(nameLoc, "Expected a variable name"); + n += name.n; - Node val = null; - var endN = n; - n += Parsing.skipEmpty(src, i + n); + Node val = null; + var endN = n; + n += Parsing.skipEmpty(src, i + n); - if (src.is(i + n, "=")) { - n++; + if (src.is(i + n, "=")) { + n++; - var valRes = JavaScript.parseExpression(src, i + n, 2); - if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after '='"); + var valRes = JavaScript.parseExpression(src, i + n, 2); + if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after '='"); - n += valRes.n; - endN = n; - n += Parsing.skipEmpty(src, i + n); - val = valRes.result; - } + n += valRes.n; + endN = n; + n += Parsing.skipEmpty(src, i + n); + val = valRes.result; + } - res.add(new Pair(new VariableNode(nameLoc, name.result), val)); + res.add(new Pair(new VariableNode(nameLoc, name.result), val)); - if (src.is(i + n, ",")) { - n++; - continue; - } + if (src.is(i + n, ",")) { + n++; + continue; + } - end = JavaScript.parseStatementEnd(src, i + endN); + end = JavaScript.parseStatementEnd(src, i + endN); - if (end.isSuccess()) { - n += end.n + endN - n; - return ParseRes.res(new VariableDeclareNode(loc, res), n); - } - else return end.chainError(src.loc(i + n), "Expected a comma or end of statement"); - } - } + if (end.isSuccess()) { + n += end.n + endN - n; + return ParseRes.res(new VariableDeclareNode(loc, res), n); + } + else return end.chainError(src.loc(i + n), "Expected a comma or end of statement"); + } + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/BreakNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/BreakNode.java index a52a47d..32203c6 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/BreakNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/BreakNode.java @@ -12,47 +12,47 @@ import me.topchetoeu.jscript.compilation.LabelContext; import me.topchetoeu.jscript.compilation.Node; public class BreakNode extends Node { - public final String label; + public final String label; @Override public void compileFunctions(CompileResult target) { } @Override public void compile(CompileResult target, boolean pollute) { - if (!LabelContext.getBreak(target.env).jump(target)) { - if (label != null) throw new SyntaxException(loc(), String.format("Undefined label '%s'", label)); - else throw new SyntaxException(loc(), "Illegal break statement"); - } + if (!LabelContext.getBreak(target.env).jump(target)) { + if (label != null) throw new SyntaxException(loc(), String.format("Undefined label '%s'", label)); + else throw new SyntaxException(loc(), "Illegal break statement"); + } - if (pollute) target.add(Instruction.pushUndefined()); - } + if (pollute) target.add(Instruction.pushUndefined()); + } - public BreakNode(Location loc, String label) { - super(loc); - this.label = label; - } + public BreakNode(Location loc, String label) { + super(loc); + this.label = label; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!Parsing.isIdentifier(src, i + n, "break")) return ParseRes.failed(); - n += 5; + if (!Parsing.isIdentifier(src, i + n, "break")) return ParseRes.failed(); + n += 5; - var end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new BreakNode(loc, null), n); - } + var end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new BreakNode(loc, null), n); + } - var label = Parsing.parseIdentifier(src, i + n); - if (label.isFailed()) return ParseRes.error(src.loc(i + n), "Expected a label name or an end of statement"); - n += label.n; + var label = Parsing.parseIdentifier(src, i + n); + if (label.isFailed()) return ParseRes.error(src.loc(i + n), "Expected a label name or an end of statement"); + n += label.n; - end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new BreakNode(loc, label.result), n); - } - else return end.chainError(src.loc(i + n), "Expected end of statement"); - } + end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new BreakNode(loc, label.result), n); + } + else return end.chainError(src.loc(i + n), "Expected end of statement"); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/ContinueNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/ContinueNode.java index 8531211..b40085c 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/ContinueNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/ContinueNode.java @@ -12,47 +12,47 @@ import me.topchetoeu.jscript.compilation.LabelContext; import me.topchetoeu.jscript.compilation.Node; public class ContinueNode extends Node { - public final String label; + public final String label; @Override public void compileFunctions(CompileResult target) { } - @Override public void compile(CompileResult target, boolean pollute) { + @Override public void compile(CompileResult target, boolean pollute) { if (!LabelContext.getCont(target.env).jump(target)) { - if (label != null) throw new SyntaxException(loc(), String.format("Undefined label '%s'", label)); - else throw new SyntaxException(loc(), "Illegal continue statement"); - } + if (label != null) throw new SyntaxException(loc(), String.format("Undefined label '%s'", label)); + else throw new SyntaxException(loc(), "Illegal continue statement"); + } - if (pollute) target.add(Instruction.pushUndefined()); - } + if (pollute) target.add(Instruction.pushUndefined()); + } - public ContinueNode(Location loc, String label) { - super(loc); - this.label = label; - } + public ContinueNode(Location loc, String label) { + super(loc); + this.label = label; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!Parsing.isIdentifier(src, i + n, "continue")) return ParseRes.failed(); - n += 8; + if (!Parsing.isIdentifier(src, i + n, "continue")) return ParseRes.failed(); + n += 8; - var end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new ContinueNode(loc, null), n); - } + var end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new ContinueNode(loc, null), n); + } - var label = Parsing.parseIdentifier(src, i + n); - if (label.isFailed()) return ParseRes.error(src.loc(i + n), "Expected a label name or an end of statement"); - n += label.n; + var label = Parsing.parseIdentifier(src, i + n); + if (label.isFailed()) return ParseRes.error(src.loc(i + n), "Expected a label name or an end of statement"); + n += label.n; - end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new ContinueNode(loc, label.result), n); - } - else return end.chainError(src.loc(i + n), "Expected end of statement"); - } + end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new ContinueNode(loc, label.result), n); + } + else return end.chainError(src.loc(i + n), "Expected end of statement"); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/DebugNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/DebugNode.java index bb0bd36..c5a97df 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/DebugNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/DebugNode.java @@ -13,28 +13,28 @@ public class DebugNode extends Node { @Override public void compileFunctions(CompileResult target) { } - @Override public void compile(CompileResult target, boolean pollute) { - target.add(Instruction.debug()); - if (pollute) target.add(Instruction.pushUndefined()); - } + @Override public void compile(CompileResult target, boolean pollute) { + target.add(Instruction.debug()); + if (pollute) target.add(Instruction.pushUndefined()); + } - public DebugNode(Location loc) { - super(loc); - } + public DebugNode(Location loc) { + super(loc); + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!Parsing.isIdentifier(src, i + n, "debugger")) return ParseRes.failed(); - n += 8; + if (!Parsing.isIdentifier(src, i + n, "debugger")) return ParseRes.failed(); + n += 8; - var end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new DebugNode(loc), n); - } - else return end.chainError(src.loc(i + n), "Expected end of statement"); - } + var end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new DebugNode(loc), n); + } + else return end.chainError(src.loc(i + n), "Expected end of statement"); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/DeleteNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/DeleteNode.java index 60886bc..d97eba4 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/DeleteNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/DeleteNode.java @@ -13,45 +13,45 @@ import me.topchetoeu.jscript.compilation.values.constants.BoolNode; import me.topchetoeu.jscript.compilation.values.operations.IndexNode; public class DeleteNode extends Node { - public final Node key; - public final Node value; + public final Node key; + public final Node value; @Override public void compileFunctions(CompileResult target) { key.compileFunctions(target); value.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - value.compile(target, true); - key.compile(target, true); + @Override public void compile(CompileResult target, boolean pollute) { + value.compile(target, true); + key.compile(target, true); - target.add(Instruction.delete()); - if (pollute) target.add(Instruction.pushValue(true)); - } + target.add(Instruction.delete()); + if (pollute) target.add(Instruction.pushValue(true)); + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!Parsing.isIdentifier(src, i + n, "delete")) return ParseRes.failed(); - n += 6; + if (!Parsing.isIdentifier(src, i + n, "delete")) return ParseRes.failed(); + n += 6; - var valRes = JavaScript.parseExpression(src, i + n, 15); - if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'delete'"); - n += valRes.n; + var valRes = JavaScript.parseExpression(src, i + n, 15); + if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'delete'"); + n += valRes.n; - if (valRes.result instanceof IndexNode) { - var index = (IndexNode)valRes.result; - return ParseRes.res(new DeleteNode(loc, index.index, index.object), n); - } - else if (valRes.result instanceof VariableNode) { - return ParseRes.error(src.loc(i + n), "A variable may not be deleted"); - } - else return ParseRes.res(new BoolNode(loc, true), n); - } + if (valRes.result instanceof IndexNode) { + var index = (IndexNode)valRes.result; + return ParseRes.res(new DeleteNode(loc, index.index, index.object), n); + } + else if (valRes.result instanceof VariableNode) { + return ParseRes.error(src.loc(i + n), "A variable may not be deleted"); + } + else return ParseRes.res(new BoolNode(loc, true), n); + } - public DeleteNode(Location loc, Node key, Node value) { - super(loc); - this.key = key; - this.value = value; - } + public DeleteNode(Location loc, Node key, Node value) { + super(loc); + this.key = key; + this.value = value; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/DoWhileNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/DoWhileNode.java index 704218b..d50d19f 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/DoWhileNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/DoWhileNode.java @@ -13,78 +13,78 @@ import me.topchetoeu.jscript.compilation.LabelContext; import me.topchetoeu.jscript.compilation.Node; public class DoWhileNode extends Node { - public final Node condition, body; - public final String label; + public final Node condition, body; + public final String label; @Override public void compileFunctions(CompileResult target) { condition.compileFunctions(target); body.compileFunctions(target); } - @Override public void resolve(CompileResult target) { - body.resolve(target); - } + @Override public void resolve(CompileResult target) { + body.resolve(target); + } - @Override public void compile(CompileResult target, boolean pollute) { - int start = target.size(); - var end = new DeferredIntSupplier(); - var mid = new DeferredIntSupplier(); + @Override public void compile(CompileResult target, boolean pollute) { + int start = target.size(); + var end = new DeferredIntSupplier(); + var mid = new DeferredIntSupplier(); - LabelContext.pushLoop(target.env, loc(), label, end, start); - body.compile(target, false, BreakpointType.STEP_OVER); + LabelContext.pushLoop(target.env, loc(), label, end, start); + body.compile(target, false, BreakpointType.STEP_OVER); - mid.set(target.size()); - condition.compile(target, true, BreakpointType.STEP_OVER); - int endI = target.size(); - end.set(endI + 1); + mid.set(target.size()); + condition.compile(target, true, BreakpointType.STEP_OVER); + int endI = target.size(); + end.set(endI + 1); - LabelContext.popLoop(target.env, label); + LabelContext.popLoop(target.env, label); - target.add(Instruction.jmpIf(start - endI)); - } + target.add(Instruction.jmpIf(start - endI)); + } - public DoWhileNode(Location loc, String label, Node condition, Node body) { - super(loc); - this.label = label; - this.condition = condition; - this.body = body; - } + public DoWhileNode(Location loc, String label, Node condition, Node body) { + super(loc); + this.label = label; + this.condition = condition; + this.body = body; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var labelRes = JavaScript.parseLabel(src, i + n); - n += labelRes.n; + var labelRes = JavaScript.parseLabel(src, i + n); + n += labelRes.n; - if (!Parsing.isIdentifier(src, i + n, "do")) return ParseRes.failed(); - n += 2; + if (!Parsing.isIdentifier(src, i + n, "do")) return ParseRes.failed(); + n += 2; - var bodyRes = JavaScript.parseStatement(src, i + n); - if (!bodyRes.isSuccess()) return bodyRes.chainError(src.loc(i + n), "Expected a do-while body."); - n += bodyRes.n; - n += Parsing.skipEmpty(src, i + n); + var bodyRes = JavaScript.parseStatement(src, i + n); + if (!bodyRes.isSuccess()) return bodyRes.chainError(src.loc(i + n), "Expected a do-while body."); + n += bodyRes.n; + n += Parsing.skipEmpty(src, i + n); - if (!Parsing.isIdentifier(src, i + n, "while")) return ParseRes.failed(); - n += 5; - n += Parsing.skipEmpty(src, i + n); + if (!Parsing.isIdentifier(src, i + n, "while")) return ParseRes.failed(); + n += 5; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected a open paren after 'while'."); - n++; + if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected a open paren after 'while'."); + n++; - var condRes = JavaScript.parseExpression(src, i + n, 0); - if (!condRes.isSuccess()) return condRes.chainError(src.loc(i + n), "Expected a do-while condition."); - n += condRes.n; - n += Parsing.skipEmpty(src, i + n); + var condRes = JavaScript.parseExpression(src, i + n, 0); + if (!condRes.isSuccess()) return condRes.chainError(src.loc(i + n), "Expected a do-while condition."); + n += condRes.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren after do-while condition."); - n++; + if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren after do-while condition."); + n++; - var end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new DoWhileNode(loc, labelRes.result, condRes.result, bodyRes.result), n); - } - else return end.chainError(src.loc(i + n), "Expected end of statement"); - } + var end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new DoWhileNode(loc, labelRes.result, condRes.result, bodyRes.result), n); + } + else return end.chainError(src.loc(i + n), "Expected end of statement"); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/ForInNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/ForInNode.java index b176632..77a210d 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/ForInNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/ForInNode.java @@ -15,100 +15,100 @@ import me.topchetoeu.jscript.compilation.values.VariableNode; public class ForInNode extends Node { public final boolean isDecl; - public final VariableNode binding; - public final Node object, body; - public final String label; + public final VariableNode binding; + public final Node object, body; + public final String label; - @Override public void resolve(CompileResult target) { - body.resolve(target); - binding.resolve(target); - } + @Override public void resolve(CompileResult target) { + body.resolve(target); + binding.resolve(target); + } @Override public void compileFunctions(CompileResult target) { object.compileFunctions(target); body.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - object.compile(target, true, BreakpointType.STEP_OVER); - target.add(Instruction.keys(false, true)); + @Override public void compile(CompileResult target, boolean pollute) { + object.compile(target, true, BreakpointType.STEP_OVER); + target.add(Instruction.keys(false, true)); - int start = target.size(); - target.add(Instruction.dup()); - int mid = target.temp(); + int start = target.size(); + target.add(Instruction.dup()); + int mid = target.temp(); - target.add(Instruction.loadMember("value")).setLocation(binding.loc()); - target.add(VariableNode.toSet(target, loc(), binding.name, false, true)).setLocation(binding.loc()); + target.add(Instruction.loadMember("value")).setLocation(binding.loc()); + target.add(VariableNode.toSet(target, loc(), binding.name, false, true)).setLocation(binding.loc()); - target.setLocationAndDebug(object.loc(), BreakpointType.STEP_OVER); + target.setLocationAndDebug(object.loc(), BreakpointType.STEP_OVER); - var end = new DeferredIntSupplier(); + var end = new DeferredIntSupplier(); - LabelContext.pushLoop(target.env, loc(), label, end, start); - body.compile(target, false, BreakpointType.STEP_OVER); + LabelContext.pushLoop(target.env, loc(), label, end, start); + body.compile(target, false, BreakpointType.STEP_OVER); - int endI = target.size(); + int endI = target.size(); - target.add(Instruction.jmp(start - endI)); - target.add(Instruction.discard()); - target.set(mid, Instruction.jmpIfNot(endI - mid + 1)); + target.add(Instruction.jmp(start - endI)); + target.add(Instruction.discard()); + target.set(mid, Instruction.jmpIfNot(endI - mid + 1)); end.set(endI); - LabelContext.popLoop(target.env, label); + LabelContext.popLoop(target.env, label); - if (pollute) target.add(Instruction.pushUndefined()); - } + if (pollute) target.add(Instruction.pushUndefined()); + } - public ForInNode(Location loc, String label, VariableNode binding, boolean isDecl, Node object, Node body) { - super(loc); - this.label = label; - this.binding = binding; + public ForInNode(Location loc, String label, VariableNode binding, boolean isDecl, Node object, Node body) { + super(loc); + this.label = label; + this.binding = binding; this.isDecl = isDecl; - this.object = object; - this.body = body; - } + this.object = object; + this.body = body; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var label = JavaScript.parseLabel(src, i + n); - n += label.n; - n += Parsing.skipEmpty(src, i + n); + var label = JavaScript.parseLabel(src, i + n); + n += label.n; + n += Parsing.skipEmpty(src, i + n); - if (!Parsing.isIdentifier(src, i + n, "for")) return ParseRes.failed(); - n += 3; - n += Parsing.skipEmpty(src, i + n); + if (!Parsing.isIdentifier(src, i + n, "for")) return ParseRes.failed(); + n += 3; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected an opening paren"); - n++; - n += Parsing.skipEmpty(src, i + n); + if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected an opening paren"); + n++; + n += Parsing.skipEmpty(src, i + n); - var varKw = JavaScript.parseDeclarationType(src, i + n); - n += varKw.n; - n += Parsing.skipEmpty(src, i + n); + var varKw = JavaScript.parseDeclarationType(src, i + n); + n += varKw.n; + n += Parsing.skipEmpty(src, i + n); var bindingLoc = src.loc(i + n); var name = Parsing.parseIdentifier(src, i + n); if (!name.isSuccess()) return name.chainError(src.loc(i + n), "Expected a variable name"); n += name.n; - n += Parsing.skipEmpty(src, i + n); + n += Parsing.skipEmpty(src, i + n); - if (!Parsing.isIdentifier(src, i + n, "in")) return ParseRes.error(src.loc(i + n), "Expected 'in' keyword after variable declaration"); - n += 2; + if (!Parsing.isIdentifier(src, i + n, "in")) return ParseRes.error(src.loc(i + n), "Expected 'in' keyword after variable declaration"); + n += 2; - var obj = JavaScript.parseExpression(src, i + n, 0); - if (!obj.isSuccess()) return obj.chainError(src.loc(i + n), "Expected a value"); - n += obj.n; - n += Parsing.skipEmpty(src, i + n); + var obj = JavaScript.parseExpression(src, i + n, 0); + if (!obj.isSuccess()) return obj.chainError(src.loc(i + n), "Expected a value"); + n += obj.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren"); - n++; + if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren"); + n++; - var bodyRes = JavaScript.parseStatement(src, i + n); - if (!bodyRes.isSuccess()) return bodyRes.chainError(src.loc(i + n), "Expected a for-in body"); - n += bodyRes.n; + var bodyRes = JavaScript.parseStatement(src, i + n); + if (!bodyRes.isSuccess()) return bodyRes.chainError(src.loc(i + n), "Expected a for-in body"); + n += bodyRes.n; - return ParseRes.res(new ForInNode(loc, label.result, new VariableNode(bindingLoc, name.result), varKw.isSuccess(), obj.result, bodyRes.result), n); - } + return ParseRes.res(new ForInNode(loc, label.result, new VariableNode(bindingLoc, name.result), varKw.isSuccess(), obj.result, bodyRes.result), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/ForNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/ForNode.java index 7eb2852..32d0c59 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/ForNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/ForNode.java @@ -15,117 +15,117 @@ import me.topchetoeu.jscript.compilation.VariableDeclareNode; import me.topchetoeu.jscript.compilation.values.operations.DiscardNode; public class ForNode extends Node { - public final Node declaration, assignment, condition, body; - public final String label; + public final Node declaration, assignment, condition, body; + public final String label; - @Override public void resolve(CompileResult target) { - declaration.resolve(target); - body.resolve(target); - } + @Override public void resolve(CompileResult target) { + declaration.resolve(target); + body.resolve(target); + } @Override public void compileFunctions(CompileResult target) { if (declaration != null) declaration.compileFunctions(target); if (assignment != null) assignment.compileFunctions(target); if (condition != null) condition.compileFunctions(target); body.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - if (declaration != null) declaration.compile(target, false, BreakpointType.STEP_OVER); + @Override public void compile(CompileResult target, boolean pollute) { + if (declaration != null) declaration.compile(target, false, BreakpointType.STEP_OVER); - int start = target.size(); + int start = target.size(); int mid = -1; - if (condition != null) { + if (condition != null) { condition.compile(target, true, BreakpointType.STEP_OVER); mid = target.temp(); } - var end = new DeferredIntSupplier(); + var end = new DeferredIntSupplier(); - LabelContext.pushLoop(target.env, loc(), label, end, start); - body.compile(target, false, BreakpointType.STEP_OVER); + LabelContext.pushLoop(target.env, loc(), label, end, start); + body.compile(target, false, BreakpointType.STEP_OVER); - if (assignment != null) assignment.compile(target, false, BreakpointType.STEP_OVER); - int endI = target.size(); + if (assignment != null) assignment.compile(target, false, BreakpointType.STEP_OVER); + int endI = target.size(); - end.set(endI); - LabelContext.popLoop(target.env, label); + end.set(endI); + LabelContext.popLoop(target.env, label); - target.add(Instruction.jmp(start - endI)); - if (mid >= 0) target.set(mid, Instruction.jmpIfNot(endI - mid + 1)); - if (pollute) target.add(Instruction.pushUndefined()); - } + target.add(Instruction.jmp(start - endI)); + if (mid >= 0) target.set(mid, Instruction.jmpIfNot(endI - mid + 1)); + if (pollute) target.add(Instruction.pushUndefined()); + } - public ForNode(Location loc, String label, Node declaration, Node condition, Node assignment, Node body) { - super(loc); - this.label = label; - this.declaration = declaration; - this.condition = condition; - this.assignment = assignment; - this.body = body; - } + public ForNode(Location loc, String label, Node declaration, Node condition, Node assignment, Node body) { + super(loc); + this.label = label; + this.declaration = declaration; + this.condition = condition; + this.assignment = assignment; + this.body = body; + } - private static ParseRes parseSemicolon(Source src, int i) { - var n = Parsing.skipEmpty(src, i); + private static ParseRes parseSemicolon(Source src, int i) { + var n = Parsing.skipEmpty(src, i); - if (!src.is(i + n, ";")) return ParseRes.failed(); - else return ParseRes.res(new DiscardNode(src.loc(i), null), n + 1); - } - private static ParseRes parseCondition(Source src, int i) { - var n = Parsing.skipEmpty(src, i); + if (!src.is(i + n, ";")) return ParseRes.failed(); + else return ParseRes.res(new DiscardNode(src.loc(i), null), n + 1); + } + private static ParseRes parseCondition(Source src, int i) { + var n = Parsing.skipEmpty(src, i); - var res = JavaScript.parseExpression(src, i + n, 0); - if (!res.isSuccess()) return res.chainError(); - n += res.n; - n += Parsing.skipEmpty(src, i + n); + var res = JavaScript.parseExpression(src, i + n, 0); + if (!res.isSuccess()) return res.chainError(); + n += res.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ";")) return ParseRes.error(src.loc(i + n), "Expected a semicolon"); - else return ParseRes.res(res.result, n + 1); - } - private static ParseRes parseUpdater(Source src, int i) { - return JavaScript.parseExpression(src, i, 0); - } + if (!src.is(i + n, ";")) return ParseRes.error(src.loc(i + n), "Expected a semicolon"); + else return ParseRes.res(res.result, n + 1); + } + private static ParseRes parseUpdater(Source src, int i) { + return JavaScript.parseExpression(src, i, 0); + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var labelRes = JavaScript.parseLabel(src, i + n); - n += labelRes.n; - n += Parsing.skipEmpty(src, i + n); + var labelRes = JavaScript.parseLabel(src, i + n); + n += labelRes.n; + n += Parsing.skipEmpty(src, i + n); - if (!Parsing.isIdentifier(src, i + n, "for")) return ParseRes.failed(); - n += 3; - n += Parsing.skipEmpty(src, i + n); + if (!Parsing.isIdentifier(src, i + n, "for")) return ParseRes.failed(); + n += 3; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected a open paren after 'for'"); - n++; + if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected a open paren after 'for'"); + n++; - ParseRes decl = ParseRes.first(src, i + n, - ForNode::parseSemicolon, - VariableDeclareNode::parse, - ForNode::parseCondition - ); - if (!decl.isSuccess()) return decl.chainError(src.loc(i + n), "Expected a declaration or an expression"); - n += decl.n; + ParseRes decl = ParseRes.first(src, i + n, + ForNode::parseSemicolon, + VariableDeclareNode::parse, + ForNode::parseCondition + ); + if (!decl.isSuccess()) return decl.chainError(src.loc(i + n), "Expected a declaration or an expression"); + n += decl.n; - ParseRes cond = ParseRes.first(src, i + n, - ForNode::parseSemicolon, - ForNode::parseCondition - ); - if (!cond.isSuccess()) return cond.chainError(src.loc(i + n), "Expected a condition"); - n += cond.n; + ParseRes cond = ParseRes.first(src, i + n, + ForNode::parseSemicolon, + ForNode::parseCondition + ); + if (!cond.isSuccess()) return cond.chainError(src.loc(i + n), "Expected a condition"); + n += cond.n; - var update = parseUpdater(src, i + n); - if (update.isError()) return update.chainError(); - n += update.n; - n += Parsing.skipEmpty(src, i + n); + var update = parseUpdater(src, i + n); + if (update.isError()) return update.chainError(); + n += update.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a close paren after for updater"); - n++; + if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a close paren after for updater"); + n++; - var body = JavaScript.parseStatement(src, i + n); - if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a for body."); - n += body.n; + var body = JavaScript.parseStatement(src, i + n); + if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a for body."); + n += body.n; - return ParseRes.res(new ForNode(loc, labelRes.result, decl.result, cond.result, update.result, body.result), n); - } + return ParseRes.res(new ForNode(loc, labelRes.result, decl.result, cond.result, update.result, body.result), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/IfNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/IfNode.java index d6013b9..a588a52 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/IfNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/IfNode.java @@ -13,123 +13,123 @@ import me.topchetoeu.jscript.compilation.LabelContext; import me.topchetoeu.jscript.compilation.Node; public class IfNode extends Node { - public final Node condition, body, elseBody; - public final String label; + public final Node condition, body, elseBody; + public final String label; - @Override public void resolve(CompileResult target) { - body.resolve(target); - if (elseBody != null) elseBody.resolve(target); - } + @Override public void resolve(CompileResult target) { + body.resolve(target); + if (elseBody != null) elseBody.resolve(target); + } @Override public void compileFunctions(CompileResult target) { condition.compileFunctions(target); body.compileFunctions(target); if (elseBody != null) elseBody.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute, BreakpointType breakpoint) { - condition.compile(target, true, breakpoint); + @Override public void compile(CompileResult target, boolean pollute, BreakpointType breakpoint) { + condition.compile(target, true, breakpoint); - if (elseBody == null) { - int start = target.temp(); - var end = new DeferredIntSupplier(); + if (elseBody == null) { + int start = target.temp(); + var end = new DeferredIntSupplier(); - LabelContext.getBreak(target.env).push(loc(), label, end); - body.compile(target, pollute, BreakpointType.STEP_OVER); - LabelContext.getBreak(target.env).pop(label); + LabelContext.getBreak(target.env).push(loc(), label, end); + body.compile(target, pollute, BreakpointType.STEP_OVER); + LabelContext.getBreak(target.env).pop(label); - int endI = target.size(); - end.set(endI); + int endI = target.size(); + end.set(endI); - target.set(start, Instruction.jmpIfNot(endI - start)); - } - else { - int start = target.temp(); - var end = new DeferredIntSupplier(); + target.set(start, Instruction.jmpIfNot(endI - start)); + } + else { + int start = target.temp(); + var end = new DeferredIntSupplier(); - LabelContext.getBreak(target.env).push(loc(), label, end); - body.compile(target, pollute, BreakpointType.STEP_OVER); + LabelContext.getBreak(target.env).push(loc(), label, end); + body.compile(target, pollute, BreakpointType.STEP_OVER); - int mid = target.temp(); + int mid = target.temp(); - elseBody.compile(target, pollute, BreakpointType.STEP_OVER); - LabelContext.getBreak(target.env).pop(label); + elseBody.compile(target, pollute, BreakpointType.STEP_OVER); + LabelContext.getBreak(target.env).pop(label); - int endI = target.size(); - end.set(endI); + int endI = target.size(); + end.set(endI); - target.set(start, Instruction.jmpIfNot(mid - start + 1)); - target.set(mid, Instruction.jmp(endI - mid)); - } - } - @Override public void compile(CompileResult target, boolean pollute) { - compile(target, pollute, BreakpointType.STEP_IN); - } + target.set(start, Instruction.jmpIfNot(mid - start + 1)); + target.set(mid, Instruction.jmp(endI - mid)); + } + } + @Override public void compile(CompileResult target, boolean pollute) { + compile(target, pollute, BreakpointType.STEP_IN); + } - public IfNode(Location loc, Node condition, Node body, Node elseBody, String label) { - super(loc); - this.condition = condition; - this.body = body; - this.elseBody = elseBody; - this.label = label; - } + public IfNode(Location loc, Node condition, Node body, Node elseBody, String label) { + super(loc); + this.condition = condition; + this.body = body; + this.elseBody = elseBody; + this.label = label; + } - public static ParseRes parseTernary(Source src, int i, Node prev, int precedence) { - if (precedence > 2) return ParseRes.failed(); + public static ParseRes parseTernary(Source src, int i, Node prev, int precedence) { + if (precedence > 2) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); + var n = Parsing.skipEmpty(src, i); - if (!src.is(i + n, "?")) return ParseRes.failed(); - var loc = src.loc(i + n); - n++; + if (!src.is(i + n, "?")) return ParseRes.failed(); + var loc = src.loc(i + n); + n++; - var a = JavaScript.parseExpression(src, i + n, 2); - if (!a.isSuccess()) return a.chainError(src.loc(i + n), "Expected a value after the ternary operator."); - n += a.n; - n += Parsing.skipEmpty(src, i + n); + var a = JavaScript.parseExpression(src, i + n, 2); + if (!a.isSuccess()) return a.chainError(src.loc(i + n), "Expected a value after the ternary operator."); + n += a.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ":")) return ParseRes.failed(); - n++; + if (!src.is(i + n, ":")) return ParseRes.failed(); + n++; - var b = JavaScript.parseExpression(src, i + n, 2); - if (!b.isSuccess()) return b.chainError(src.loc(i + n), "Expected a second value after the ternary operator."); - n += b.n; + var b = JavaScript.parseExpression(src, i + n, 2); + if (!b.isSuccess()) return b.chainError(src.loc(i + n), "Expected a second value after the ternary operator."); + n += b.n; - return ParseRes.res(new IfNode(loc, prev, a.result, b.result, null), n); - } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + return ParseRes.res(new IfNode(loc, prev, a.result, b.result, null), n); + } + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var label = JavaScript.parseLabel(src, i + n); - n += label.n; - n += Parsing.skipEmpty(src, i + n); + var label = JavaScript.parseLabel(src, i + n); + n += label.n; + n += Parsing.skipEmpty(src, i + n); - if (!Parsing.isIdentifier(src, i + n, "if")) return ParseRes.failed(); - n += 2; - n += Parsing.skipEmpty(src, i + n); + if (!Parsing.isIdentifier(src, i + n, "if")) return ParseRes.failed(); + n += 2; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected a open paren after 'if'."); - n++; + if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected a open paren after 'if'."); + n++; - var condRes = JavaScript.parseExpression(src, i + n, 0); - if (!condRes.isSuccess()) return condRes.chainError(src.loc(i + n), "Expected an if condition."); - n += condRes.n; - n += Parsing.skipEmpty(src, i + n); + var condRes = JavaScript.parseExpression(src, i + n, 0); + if (!condRes.isSuccess()) return condRes.chainError(src.loc(i + n), "Expected an if condition."); + n += condRes.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren after if condition."); - n++; + if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren after if condition."); + n++; - var res = JavaScript.parseStatement(src, i + n); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected an if body."); - n += res.n; + var res = JavaScript.parseStatement(src, i + n); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected an if body."); + n += res.n; - var elseKw = Parsing.parseIdentifier(src, i + n, "else"); - if (!elseKw.isSuccess()) return ParseRes.res(new IfNode(loc, condRes.result, res.result, null, label.result), n); - n += elseKw.n; + var elseKw = Parsing.parseIdentifier(src, i + n, "else"); + if (!elseKw.isSuccess()) return ParseRes.res(new IfNode(loc, condRes.result, res.result, null, label.result), n); + n += elseKw.n; - var elseRes = JavaScript.parseStatement(src, i + n); - if (!elseRes.isSuccess()) return elseRes.chainError(src.loc(i + n), "Expected an else body."); - n += elseRes.n; + var elseRes = JavaScript.parseStatement(src, i + n); + if (!elseRes.isSuccess()) return elseRes.chainError(src.loc(i + n), "Expected an else body."); + n += elseRes.n; - return ParseRes.res(new IfNode(loc, condRes.result, res.result, elseRes.result, label.result), n); - } + return ParseRes.res(new IfNode(loc, condRes.result, res.result, elseRes.result, label.result), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/ReturnNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/ReturnNode.java index 7e7d708..2674552 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/ReturnNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/ReturnNode.java @@ -10,44 +10,44 @@ import me.topchetoeu.jscript.compilation.JavaScript; import me.topchetoeu.jscript.compilation.Node; public class ReturnNode extends Node { - public final Node value; + public final Node value; @Override public void compileFunctions(CompileResult target) { if (value != null) value.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - if (value == null) target.add(Instruction.pushUndefined()); - else value.compile(target, true); - target.add(Instruction.ret()).setLocation(loc()); - } + @Override public void compile(CompileResult target, boolean pollute) { + if (value == null) target.add(Instruction.pushUndefined()); + else value.compile(target, true); + target.add(Instruction.ret()).setLocation(loc()); + } - public ReturnNode(Location loc, Node value) { - super(loc); - this.value = value; - } + public ReturnNode(Location loc, Node value) { + super(loc); + this.value = value; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!Parsing.isIdentifier(src, i + n, "return")) return ParseRes.failed(); - n += 6; + if (!Parsing.isIdentifier(src, i + n, "return")) return ParseRes.failed(); + n += 6; - var end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new ReturnNode(loc, null), n); - } + var end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new ReturnNode(loc, null), n); + } - var val = JavaScript.parseExpression(src, i + n, 0); - if (val.isError()) return val.chainError(); - n += val.n; + var val = JavaScript.parseExpression(src, i + n, 0); + if (val.isError()) return val.chainError(); + n += val.n; - end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new ReturnNode(loc, val.result), n); - } - else return end.chainError(src.loc(i + n), "Expected end of statement or a return value"); - } + end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new ReturnNode(loc, val.result), n); + } + else return end.chainError(src.loc(i + n), "Expected end of statement or a return value"); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/SwitchNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/SwitchNode.java index f32baa2..cb896f9 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/SwitchNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/SwitchNode.java @@ -17,25 +17,25 @@ import me.topchetoeu.jscript.compilation.LabelContext; import me.topchetoeu.jscript.compilation.Node; public class SwitchNode extends Node { - public static class SwitchCase { - public final Node value; - public final int statementI; + public static class SwitchCase { + public final Node value; + public final int statementI; - public SwitchCase(Node value, int statementI) { - this.value = value; - this.statementI = statementI; - } - } + public SwitchCase(Node value, int statementI) { + this.value = value; + this.statementI = statementI; + } + } - public final Node value; - public final SwitchCase[] cases; - public final Node[] body; - public final int defaultI; - public final String label; + public final Node value; + public final SwitchCase[] cases; + public final Node[] body; + public final int defaultI; + public final String label; - @Override public void resolve(CompileResult target) { - for (var stm : body) stm.resolve(target); - } + @Override public void resolve(CompileResult target) { + for (var stm : body) stm.resolve(target); + } @Override public void compileFunctions(CompileResult target) { value.compileFunctions(target); for (var _case : cases) { @@ -45,154 +45,154 @@ public class SwitchNode extends Node { stm.compileFunctions(target); } } - @Override public void compile(CompileResult target, boolean pollute) { - var caseToStatement = new HashMap(); - var statementToIndex = new HashMap(); + @Override public void compile(CompileResult target, boolean pollute) { + var caseToStatement = new HashMap(); + var statementToIndex = new HashMap(); - value.compile(target, true, BreakpointType.STEP_OVER); + value.compile(target, true, BreakpointType.STEP_OVER); - // TODO: create a jump map - for (var ccase : cases) { - target.add(Instruction.dup()); - ccase.value.compile(target, true); - target.add(Instruction.operation(Operation.EQUALS)); - caseToStatement.put(target.temp(), ccase.statementI); - } + // TODO: create a jump map + for (var ccase : cases) { + target.add(Instruction.dup()); + ccase.value.compile(target, true); + target.add(Instruction.operation(Operation.EQUALS)); + caseToStatement.put(target.temp(), ccase.statementI); + } - int start = target.temp(); - var end = new DeferredIntSupplier(); + int start = target.temp(); + var end = new DeferredIntSupplier(); - LabelContext.getBreak(target.env).pushLoop(loc(), label, end); - for (var stm : body) { - statementToIndex.put(statementToIndex.size(), target.size()); - stm.compile(target, false, BreakpointType.STEP_OVER); - } + LabelContext.getBreak(target.env).pushLoop(loc(), label, end); + for (var stm : body) { + statementToIndex.put(statementToIndex.size(), target.size()); + stm.compile(target, false, BreakpointType.STEP_OVER); + } - int endI = target.size(); - end.set(endI); - LabelContext.getBreak(target.env).popLoop(label); + int endI = target.size(); + end.set(endI); + LabelContext.getBreak(target.env).popLoop(label); - target.add(Instruction.discard()); - if (pollute) target.add(Instruction.pushUndefined()); + target.add(Instruction.discard()); + if (pollute) target.add(Instruction.pushUndefined()); - if (defaultI < 0 || defaultI >= body.length) target.set(start, Instruction.jmp(endI - start)); - else target.set(start, Instruction.jmp(statementToIndex.get(defaultI) - start)); + if (defaultI < 0 || defaultI >= body.length) target.set(start, Instruction.jmp(endI - start)); + else target.set(start, Instruction.jmp(statementToIndex.get(defaultI) - start)); - for (var el : caseToStatement.entrySet()) { - var i = statementToIndex.get(el.getValue()); - if (i == null) i = endI; - target.set(el.getKey(), Instruction.jmpIf(i - el.getKey())); - } + for (var el : caseToStatement.entrySet()) { + var i = statementToIndex.get(el.getValue()); + if (i == null) i = endI; + target.set(el.getKey(), Instruction.jmpIf(i - el.getKey())); + } - } + } - public SwitchNode(Location loc, String label, Node value, int defaultI, SwitchCase[] cases, Node[] body) { - super(loc); - this.label = label; - this.value = value; - this.defaultI = defaultI; - this.cases = cases; - this.body = body; - } + public SwitchNode(Location loc, String label, Node value, int defaultI, SwitchCase[] cases, Node[] body) { + super(loc); + this.label = label; + this.value = value; + this.defaultI = defaultI; + this.cases = cases; + this.body = body; + } - private static ParseRes parseSwitchCase(Source src, int i) { - var n = Parsing.skipEmpty(src, i); + private static ParseRes parseSwitchCase(Source src, int i) { + var n = Parsing.skipEmpty(src, i); - if (!Parsing.isIdentifier(src, i + n, "case")) return ParseRes.failed(); - n += 4; + if (!Parsing.isIdentifier(src, i + n, "case")) return ParseRes.failed(); + n += 4; - var val = JavaScript.parseExpression(src, i + n, 0); - if (!val.isSuccess()) return val.chainError(src.loc(i + n), "Expected a value after 'case'"); - n += val.n; - n += Parsing.skipEmpty(src, i + n); + var val = JavaScript.parseExpression(src, i + n, 0); + if (!val.isSuccess()) return val.chainError(src.loc(i + n), "Expected a value after 'case'"); + n += val.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ":")) return ParseRes.error(src.loc(i + n), "Expected colons after 'case' value"); - n++; + if (!src.is(i + n, ":")) return ParseRes.error(src.loc(i + n), "Expected colons after 'case' value"); + n++; - return ParseRes.res(val.result, n); - } - private static ParseRes parseDefaultCase(Source src, int i) { - var n = Parsing.skipEmpty(src, i); + return ParseRes.res(val.result, n); + } + private static ParseRes parseDefaultCase(Source src, int i) { + var n = Parsing.skipEmpty(src, i); - if (!Parsing.isIdentifier(src, i + n, "default")) return ParseRes.failed(); - n += 7; - n += Parsing.skipEmpty(src, i + n); + if (!Parsing.isIdentifier(src, i + n, "default")) return ParseRes.failed(); + n += 7; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ":")) return ParseRes.error(src.loc(i + n), "Expected colons after 'default'"); - n++; + if (!src.is(i + n, ":")) return ParseRes.error(src.loc(i + n), "Expected colons after 'default'"); + n++; - return ParseRes.res(null, n); - } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + return ParseRes.res(null, n); + } + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var label = JavaScript.parseLabel(src, i + n); - n += label.n; - n += Parsing.skipEmpty(src, i + n); + var label = JavaScript.parseLabel(src, i + n); + n += label.n; + n += Parsing.skipEmpty(src, i + n); - if (!Parsing.isIdentifier(src, i + n, "switch")) return ParseRes.failed(); - n += 6; - n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected a open paren after 'switch'"); - n++; + if (!Parsing.isIdentifier(src, i + n, "switch")) return ParseRes.failed(); + n += 6; + n += Parsing.skipEmpty(src, i + n); + if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected a open paren after 'switch'"); + n++; - var val = JavaScript.parseExpression(src, i + n, 0); - if (!val.isSuccess()) return val.chainError(src.loc(i + n), "Expected a switch value"); - n += val.n; - n += Parsing.skipEmpty(src, i + n); + var val = JavaScript.parseExpression(src, i + n, 0); + if (!val.isSuccess()) return val.chainError(src.loc(i + n), "Expected a switch value"); + n += val.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren after switch value"); - n++; - n += Parsing.skipEmpty(src, i + n); + if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren after switch value"); + n++; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, "{")) return ParseRes.error(src.loc(i + n), "Expected an opening brace after switch value"); - n++; - n += Parsing.skipEmpty(src, i + n); + if (!src.is(i + n, "{")) return ParseRes.error(src.loc(i + n), "Expected an opening brace after switch value"); + n++; + n += Parsing.skipEmpty(src, i + n); - var statements = new ArrayList(); - var cases = new ArrayList(); - var defaultI = -1; + var statements = new ArrayList(); + var cases = new ArrayList(); + var defaultI = -1; - while (true) { - n += Parsing.skipEmpty(src, i + n); + while (true) { + n += Parsing.skipEmpty(src, i + n); - if (src.is(i + n, "}")) { - n++; - break; - } - if (src.is(i + n, ";")) { - n++; - continue; - } + if (src.is(i + n, "}")) { + n++; + break; + } + if (src.is(i + n, ";")) { + n++; + continue; + } - ParseRes caseRes = ParseRes.first(src, i + n, - SwitchNode::parseDefaultCase, - SwitchNode::parseSwitchCase - ); + ParseRes caseRes = ParseRes.first(src, i + n, + SwitchNode::parseDefaultCase, + SwitchNode::parseSwitchCase + ); - if (caseRes.isSuccess()) { - n += caseRes.n; + if (caseRes.isSuccess()) { + n += caseRes.n; - if (caseRes.result == null) defaultI = statements.size(); - else cases.add(new SwitchCase(caseRes.result, statements.size())); - continue; - } - if (caseRes.isError()) return caseRes.chainError(); + if (caseRes.result == null) defaultI = statements.size(); + else cases.add(new SwitchCase(caseRes.result, statements.size())); + continue; + } + if (caseRes.isError()) return caseRes.chainError(); - var stm = JavaScript.parseStatement(src, i + n); - if (stm.isSuccess()) { - n += stm.n; - statements.add(stm.result); - continue; - } - else stm.chainError(src.loc(i + n), "Expected a statement, 'case' or 'default'"); - } + var stm = JavaScript.parseStatement(src, i + n); + if (stm.isSuccess()) { + n += stm.n; + statements.add(stm.result); + continue; + } + else stm.chainError(src.loc(i + n), "Expected a statement, 'case' or 'default'"); + } - return ParseRes.res(new SwitchNode( - loc, label.result, val.result, defaultI, - cases.toArray(new SwitchCase[0]), - statements.toArray(new Node[0]) - ), n); - } + return ParseRes.res(new SwitchNode( + loc, label.result, val.result, defaultI, + cases.toArray(new SwitchCase[0]), + statements.toArray(new Node[0]) + ), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/ThrowNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/ThrowNode.java index 9f05e2f..87dcce2 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/ThrowNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/ThrowNode.java @@ -10,43 +10,43 @@ import me.topchetoeu.jscript.compilation.JavaScript; import me.topchetoeu.jscript.compilation.Node; public class ThrowNode extends Node { - public final Node value; + public final Node value; @Override public void compileFunctions(CompileResult target) { value.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - value.compile(target, true); - target.add(Instruction.throwInstr()).setLocation(loc()); - } + @Override public void compile(CompileResult target, boolean pollute) { + value.compile(target, true); + target.add(Instruction.throwInstr()).setLocation(loc()); + } - public ThrowNode(Location loc, Node value) { - super(loc); - this.value = value; - } + public ThrowNode(Location loc, Node value) { + super(loc); + this.value = value; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!Parsing.isIdentifier(src, i + n, "throw")) return ParseRes.failed(); - n += 5; + if (!Parsing.isIdentifier(src, i + n, "throw")) return ParseRes.failed(); + n += 5; - var end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new ThrowNode(loc, null), n); - } + var end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new ThrowNode(loc, null), n); + } - var val = JavaScript.parseExpression(src, i + n, 0); - if (val.isFailed()) return ParseRes.error(src.loc(i + n), "Expected a value"); - n += val.n; + var val = JavaScript.parseExpression(src, i + n, 0); + if (val.isFailed()) return ParseRes.error(src.loc(i + n), "Expected a value"); + n += val.n; - end = JavaScript.parseStatementEnd(src, i + n); - if (end.isSuccess()) { - n += end.n; - return ParseRes.res(new ThrowNode(loc, val.result), n); - } - else return end.chainError(src.loc(i + n), "Expected end of statement"); - } + end = JavaScript.parseStatementEnd(src, i + n); + if (end.isSuccess()) { + n += end.n; + return ParseRes.res(new ThrowNode(loc, val.result), n); + } + else return end.chainError(src.loc(i + n), "Expected end of statement"); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/TryNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/TryNode.java index f2dcda1..2cc2419 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/TryNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/TryNode.java @@ -14,126 +14,126 @@ import me.topchetoeu.jscript.compilation.LabelContext; import me.topchetoeu.jscript.compilation.Node; public class TryNode extends Node { - public final CompoundNode tryBody; - public final CompoundNode catchBody; - public final CompoundNode finallyBody; - public final String captureName; - public final String label; + public final CompoundNode tryBody; + public final CompoundNode catchBody; + public final CompoundNode finallyBody; + public final String captureName; + public final String label; - @Override public void resolve(CompileResult target) { - tryBody.resolve(target); - if (catchBody != null) catchBody.resolve(target); - if (finallyBody != null) finallyBody.resolve(target); - } + @Override public void resolve(CompileResult target) { + tryBody.resolve(target); + if (catchBody != null) catchBody.resolve(target); + if (finallyBody != null) finallyBody.resolve(target); + } @Override public void compileFunctions(CompileResult target) { tryBody.compileFunctions(target); if (catchBody != null) catchBody.compileFunctions(target); if (finallyBody != null) finallyBody.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute, BreakpointType bpt) { - int replace = target.temp(); - var endSuppl = new DeferredIntSupplier(); + @Override public void compile(CompileResult target, boolean pollute, BreakpointType bpt) { + int replace = target.temp(); + var endSuppl = new DeferredIntSupplier(); - int start = replace + 1, catchStart = -1, finallyStart = -1; + int start = replace + 1, catchStart = -1, finallyStart = -1; - LabelContext.getBreak(target.env).push(loc(), label, endSuppl); + LabelContext.getBreak(target.env).push(loc(), label, endSuppl); - tryBody.compile(target, false); - target.add(Instruction.tryEnd()); + tryBody.compile(target, false); + target.add(Instruction.tryEnd()); - if (catchBody != null) { - catchStart = target.size() - start; + if (catchBody != null) { + catchStart = target.size() - start; - if (captureName != null) { - var catchVar = target.scope.defineCatch(captureName); - target.add(Instruction.loadError()).setLocation(catchBody.loc()); - target.add(catchVar.index().toSet(false)).setLocation(catchBody.loc()); - catchBody.compile(target, false); + if (captureName != null) { + var catchVar = target.scope.defineCatch(captureName); + target.add(Instruction.loadError()).setLocation(catchBody.loc()); + target.add(catchVar.index().toSet(false)).setLocation(catchBody.loc()); + catchBody.compile(target, false); target.scope.undefineCatch(); - } - else catchBody.compile(target, false); + } + else catchBody.compile(target, false); - target.add(Instruction.tryEnd()); - } + target.add(Instruction.tryEnd()); + } - if (finallyBody != null) { - finallyStart = target.size() - start; - finallyBody.compile(target, false); - } + if (finallyBody != null) { + finallyStart = target.size() - start; + finallyBody.compile(target, false); + } - LabelContext.getBreak(target.env).pop(label); + LabelContext.getBreak(target.env).pop(label); - endSuppl.set(target.size()); + endSuppl.set(target.size()); - target.set(replace, Instruction.tryStart(catchStart, finallyStart, target.size() - start)); - target.setLocationAndDebug(replace, loc(), BreakpointType.STEP_OVER); + target.set(replace, Instruction.tryStart(catchStart, finallyStart, target.size() - start)); + target.setLocationAndDebug(replace, loc(), BreakpointType.STEP_OVER); - if (pollute) target.add(Instruction.pushUndefined()); - } + if (pollute) target.add(Instruction.pushUndefined()); + } - public TryNode(Location loc, String label, CompoundNode tryBody, CompoundNode catchBody, CompoundNode finallyBody, String captureName) { - super(loc); - this.tryBody = tryBody; - this.catchBody = catchBody; - this.finallyBody = finallyBody; - this.captureName = captureName; - this.label = label; - } + public TryNode(Location loc, String label, CompoundNode tryBody, CompoundNode catchBody, CompoundNode finallyBody, String captureName) { + super(loc); + this.tryBody = tryBody; + this.catchBody = catchBody; + this.finallyBody = finallyBody; + this.captureName = captureName; + this.label = label; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var labelRes = JavaScript.parseLabel(src, i + n); - n += labelRes.n; - n += Parsing.skipEmpty(src, i + n); + var labelRes = JavaScript.parseLabel(src, i + n); + n += labelRes.n; + n += Parsing.skipEmpty(src, i + n); - if (!Parsing.isIdentifier(src, i + n, "try")) return ParseRes.failed(); - n += 3; + if (!Parsing.isIdentifier(src, i + n, "try")) return ParseRes.failed(); + n += 3; - var tryBody = CompoundNode.parse(src, i + n); - if (!tryBody.isSuccess()) return tryBody.chainError(src.loc(i + n), "Expected a try body"); - n += tryBody.n; - n += Parsing.skipEmpty(src, i + n); + var tryBody = CompoundNode.parse(src, i + n); + if (!tryBody.isSuccess()) return tryBody.chainError(src.loc(i + n), "Expected a try body"); + n += tryBody.n; + n += Parsing.skipEmpty(src, i + n); - String capture = null; - CompoundNode catchBody = null, finallyBody = null; + String capture = null; + CompoundNode catchBody = null, finallyBody = null; - if (Parsing.isIdentifier(src, i + n, "catch")) { - n += 5; - n += Parsing.skipEmpty(src, i + n); - if (src.is(i + n, "(")) { - n++; - var nameRes = Parsing.parseIdentifier(src, i + n); - if (!nameRes.isSuccess()) return nameRes.chainError(src.loc(i + n), "xpected a catch variable name"); - capture = nameRes.result; - n += nameRes.n; - n += Parsing.skipEmpty(src, i + n); + if (Parsing.isIdentifier(src, i + n, "catch")) { + n += 5; + n += Parsing.skipEmpty(src, i + n); + if (src.is(i + n, "(")) { + n++; + var nameRes = Parsing.parseIdentifier(src, i + n); + if (!nameRes.isSuccess()) return nameRes.chainError(src.loc(i + n), "xpected a catch variable name"); + capture = nameRes.result; + n += nameRes.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren after catch variable name"); - n++; - } + if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren after catch variable name"); + n++; + } - var bodyRes = CompoundNode.parse(src, i + n); - if (!bodyRes.isSuccess()) return tryBody.chainError(src.loc(i + n), "Expected a catch body"); - n += bodyRes.n; - n += Parsing.skipEmpty(src, i + n); + var bodyRes = CompoundNode.parse(src, i + n); + if (!bodyRes.isSuccess()) return tryBody.chainError(src.loc(i + n), "Expected a catch body"); + n += bodyRes.n; + n += Parsing.skipEmpty(src, i + n); - catchBody = bodyRes.result; - } + catchBody = bodyRes.result; + } - if (Parsing.isIdentifier(src, i + n, "finally")) { - n += 7; + if (Parsing.isIdentifier(src, i + n, "finally")) { + n += 7; - var bodyRes = CompoundNode.parse(src, i + n); - if (!bodyRes.isSuccess()) return tryBody.chainError(src.loc(i + n), "Expected a finally body"); - n += bodyRes.n; - n += Parsing.skipEmpty(src, i + n); - finallyBody = bodyRes.result; - } + var bodyRes = CompoundNode.parse(src, i + n); + if (!bodyRes.isSuccess()) return tryBody.chainError(src.loc(i + n), "Expected a finally body"); + n += bodyRes.n; + n += Parsing.skipEmpty(src, i + n); + finallyBody = bodyRes.result; + } - if (finallyBody == null && catchBody == null) ParseRes.error(src.loc(i + n), "Expected catch or finally"); + if (finallyBody == null && catchBody == null) ParseRes.error(src.loc(i + n), "Expected catch or finally"); - return ParseRes.res(new TryNode(loc, labelRes.result, tryBody.result, catchBody, finallyBody, capture), n); - } + return ParseRes.res(new TryNode(loc, labelRes.result, tryBody.result, catchBody, finallyBody, capture), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/control/WhileNode.java b/src/main/java/me/topchetoeu/jscript/compilation/control/WhileNode.java index 13bbc2f..a341cce 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/control/WhileNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/control/WhileNode.java @@ -13,70 +13,70 @@ import me.topchetoeu.jscript.compilation.LabelContext; import me.topchetoeu.jscript.compilation.Node; public class WhileNode extends Node { - public final Node condition, body; - public final String label; + public final Node condition, body; + public final String label; - @Override public void resolve(CompileResult target) { - body.resolve(target); - } + @Override public void resolve(CompileResult target) { + body.resolve(target); + } @Override public void compileFunctions(CompileResult target) { condition.compileFunctions(target); body.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - int start = target.size(); - condition.compile(target, true); - int mid = target.temp(); + @Override public void compile(CompileResult target, boolean pollute) { + int start = target.size(); + condition.compile(target, true); + int mid = target.temp(); - var end = new DeferredIntSupplier(); + var end = new DeferredIntSupplier(); - LabelContext.pushLoop(target.env, loc(), label, end, start); - body.compile(target, false, BreakpointType.STEP_OVER); + LabelContext.pushLoop(target.env, loc(), label, end, start); + body.compile(target, false, BreakpointType.STEP_OVER); - var endI = target.size(); - end.set(endI + 1); - LabelContext.popLoop(target.env, label); + var endI = target.size(); + end.set(endI + 1); + LabelContext.popLoop(target.env, label); - target.add(Instruction.jmp(start - end.getAsInt())); - target.set(mid, Instruction.jmpIfNot(end.getAsInt() - mid + 1)); - if (pollute) target.add(Instruction.pushUndefined()); - } + target.add(Instruction.jmp(start - end.getAsInt())); + target.set(mid, Instruction.jmpIfNot(end.getAsInt() - mid + 1)); + if (pollute) target.add(Instruction.pushUndefined()); + } - public WhileNode(Location loc, String label, Node condition, Node body) { - super(loc); - this.label = label; - this.condition = condition; - this.body = body; - } + public WhileNode(Location loc, String label, Node condition, Node body) { + super(loc); + this.label = label; + this.condition = condition; + this.body = body; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var label = JavaScript.parseLabel(src, i + n); - n += label.n; - n += Parsing.skipEmpty(src, i + n); + var label = JavaScript.parseLabel(src, i + n); + n += label.n; + n += Parsing.skipEmpty(src, i + n); - if (!Parsing.isIdentifier(src, i + n, "while")) return ParseRes.failed(); - n += 5; - n += Parsing.skipEmpty(src, i + n); + if (!Parsing.isIdentifier(src, i + n, "while")) return ParseRes.failed(); + n += 5; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected a open paren after 'while'."); - n++; + if (!src.is(i + n, "(")) return ParseRes.error(src.loc(i + n), "Expected a open paren after 'while'."); + n++; - var cond = JavaScript.parseExpression(src, i + n, 0); - if (!cond.isSuccess()) return cond.chainError(src.loc(i + n), "Expected a while condition."); - n += cond.n; - n += Parsing.skipEmpty(src, i + n); + var cond = JavaScript.parseExpression(src, i + n, 0); + if (!cond.isSuccess()) return cond.chainError(src.loc(i + n), "Expected a while condition."); + n += cond.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren after while condition."); - n++; + if (!src.is(i + n, ")")) return ParseRes.error(src.loc(i + n), "Expected a closing paren after while condition."); + n++; - var body = JavaScript.parseStatement(src, i + n); - if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a while body."); - n += body.n; + var body = JavaScript.parseStatement(src, i + n); + if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a while body."); + n += body.n; - return ParseRes.res(new WhileNode(loc, label.result, cond.result, body.result), n); - } + return ParseRes.res(new WhileNode(loc, label.result, cond.result, body.result), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/members/FieldMemberNode.java b/src/main/java/me/topchetoeu/jscript/compilation/members/FieldMemberNode.java index f369f65..65c6c8b 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/members/FieldMemberNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/members/FieldMemberNode.java @@ -11,49 +11,49 @@ import me.topchetoeu.jscript.compilation.Node; import me.topchetoeu.jscript.compilation.values.ObjectNode; public class FieldMemberNode implements Member { - public final Location loc; - public final Node key; - public final Node value; + public final Location loc; + public final Node key; + public final Node value; - @Override public Location loc() { return loc; } + @Override public Location loc() { return loc; } @Override public void compileFunctions(CompileResult target) { key.compileFunctions(target); value.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - if (pollute) target.add(Instruction.dup()); - key.compile(target, true); + @Override public void compile(CompileResult target, boolean pollute) { + if (pollute) target.add(Instruction.dup()); + key.compile(target, true); - if (value == null) target.add(Instruction.pushUndefined()); - else value.compile(target, true); + if (value == null) target.add(Instruction.pushUndefined()); + else value.compile(target, true); - target.add(Instruction.defField()); - } + target.add(Instruction.defField()); + } - public FieldMemberNode(Location loc, Node key, Node value) { - this.loc = loc; - this.key = key; - this.value = value; - } + public FieldMemberNode(Location loc, Node key, Node value) { + this.loc = loc; + this.key = key; + this.value = value; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var name = ObjectNode.parsePropName(src, i + n); - if (!name.isSuccess()) return name.chainError(); - n += name.n; - n += Parsing.skipEmpty(src, i + n); + var name = ObjectNode.parsePropName(src, i + n); + if (!name.isSuccess()) return name.chainError(); + n += name.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, ":")) return ParseRes.failed(); - n++; + if (!src.is(i + n, ":")) return ParseRes.failed(); + n++; - var value = JavaScript.parseExpression(src, i + n, 2); - if (!value.isSuccess()) return value.chainError(src.loc(i + n), "Expected a value"); - n += value.n; + var value = JavaScript.parseExpression(src, i + n, 2); + if (!value.isSuccess()) return value.chainError(src.loc(i + n), "Expected a value"); + n += value.n; - return ParseRes.res(new FieldMemberNode(loc, name.result, value.result), n); - } + return ParseRes.res(new FieldMemberNode(loc, name.result, value.result), n); + } } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/compilation/members/Member.java b/src/main/java/me/topchetoeu/jscript/compilation/members/Member.java index 84ebf68..36ce7df 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/members/Member.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/members/Member.java @@ -4,8 +4,8 @@ import me.topchetoeu.jscript.common.parsing.Location; import me.topchetoeu.jscript.compilation.CompileResult; public interface Member { - Location loc(); + Location loc(); void compileFunctions(CompileResult target); - void compile(CompileResult target, boolean pollute); + void compile(CompileResult target, boolean pollute); } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/members/PropertyMemberNode.java b/src/main/java/me/topchetoeu/jscript/compilation/members/PropertyMemberNode.java index 279e560..6be7ee0 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/members/PropertyMemberNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/members/PropertyMemberNode.java @@ -18,66 +18,66 @@ import me.topchetoeu.jscript.compilation.values.VariableNode; import me.topchetoeu.jscript.compilation.values.constants.StringNode; public final class PropertyMemberNode extends FunctionNode implements Member { - public final Node key; - public final VariableNode argument; + public final Node key; + public final VariableNode argument; - @Override public String name() { - if (key instanceof StringNode str) { - if (isGetter()) return "get " + str.value; - else return "set " + str.value; - } - else return null; - } + @Override public String name() { + if (key instanceof StringNode str) { + if (isGetter()) return "get " + str.value; + else return "set " + str.value; + } + else return null; + } - public boolean isGetter() { return argument == null; } - public boolean isSetter() { return argument != null; } + public boolean isGetter() { return argument == null; } + public boolean isSetter() { return argument != null; } @Override public void compileFunctions(CompileResult target) { key.compileFunctions(target); target.addChild(this, compileBody(target, null)); } - @Override public void compile(CompileResult target, boolean pollute, String name, BreakpointType bp) { - if (pollute) target.add(Instruction.dup()); - key.compile(target, true); + @Override public void compile(CompileResult target, boolean pollute, String name, BreakpointType bp) { + if (pollute) target.add(Instruction.dup()); + key.compile(target, true); - target.add(Instruction.loadFunc(target.childrenIndices.get(this), name(name), captures(target))).setLocation(loc()); - target.add(Instruction.defProp(isSetter())); - } + target.add(Instruction.loadFunc(target.childrenIndices.get(this), name(name), captures(target))).setLocation(loc()); + target.add(Instruction.defProp(isSetter())); + } - public PropertyMemberNode(Location loc, Location end, Node key, VariableNode argument, CompoundNode body) { - super(loc, end, argument == null ? Arrays.asList() : Arrays.asList(argument), body); - this.key = key; - this.argument = argument; - } + public PropertyMemberNode(Location loc, Location end, Node key, VariableNode argument, CompoundNode body) { + super(loc, end, argument == null ? Arrays.asList() : Arrays.asList(argument), body); + this.key = key; + this.argument = argument; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var access = Parsing.parseIdentifier(src, i + n); - if (!access.isSuccess()) return ParseRes.failed(); - if (!access.result.equals("get") && !access.result.equals("set")) return ParseRes.failed(); - n += access.n; + var access = Parsing.parseIdentifier(src, i + n); + if (!access.isSuccess()) return ParseRes.failed(); + if (!access.result.equals("get") && !access.result.equals("set")) return ParseRes.failed(); + n += access.n; - var name = ObjectNode.parsePropName(src, i + n); - if (!name.isSuccess()) return name.chainError(src.loc(i + n), "Expected a property name after '" + access + "'"); - n += name.n; + var name = ObjectNode.parsePropName(src, i + n); + if (!name.isSuccess()) return name.chainError(src.loc(i + n), "Expected a property name after '" + access + "'"); + n += name.n; - var params = JavaScript.parseParameters(src, i + n); - if (!params.isSuccess()) return params.chainError(src.loc(i + n), "Expected an argument list"); - if (access.result.equals("get") && params.result.size() != 0) return ParseRes.error(src.loc(i + n), "Getter must not have any parameters"); - if (access.result.equals("set") && params.result.size() != 1) return ParseRes.error(src.loc(i + n), "Setter must have exactly one parameter"); - n += params.n; + var params = JavaScript.parseParameters(src, i + n); + if (!params.isSuccess()) return params.chainError(src.loc(i + n), "Expected an argument list"); + if (access.result.equals("get") && params.result.size() != 0) return ParseRes.error(src.loc(i + n), "Getter must not have any parameters"); + if (access.result.equals("set") && params.result.size() != 1) return ParseRes.error(src.loc(i + n), "Setter must have exactly one parameter"); + n += params.n; - var body = CompoundNode.parse(src, i + n); - if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a compound statement for property accessor."); - n += body.n; + var body = CompoundNode.parse(src, i + n); + if (!body.isSuccess()) return body.chainError(src.loc(i + n), "Expected a compound statement for property accessor."); + n += body.n; - var end = src.loc(i + n - 1); + var end = src.loc(i + n - 1); - return ParseRes.res(new PropertyMemberNode( - loc, end, name.result, access.result.equals("get") ? null : params.result.get(0), body.result - ), n); - } + return ParseRes.res(new PropertyMemberNode( + loc, end, name.result, access.result.equals("get") ? null : params.result.get(0), body.result + ), n); + } } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/compilation/patterns/AssignTarget.java b/src/main/java/me/topchetoeu/jscript/compilation/patterns/AssignTarget.java index f8b4739..0d78a4d 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/patterns/AssignTarget.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/patterns/AssignTarget.java @@ -7,21 +7,21 @@ import me.topchetoeu.jscript.compilation.CompileResult; * Represents all nodes that can be assign targets */ public interface AssignTarget extends AssignTargetLike { - Location loc(); + Location loc(); - /** - * Called to perform calculations before the assigned value is calculated - */ - default void beforeAssign(CompileResult target) {} - /** - * Called to perform the actual assignemnt. Between the `beforeAssign` and this call a single value will have been pushed to the stack - * @param pollute Whether or not to leave the original value on the stack - */ - void afterAssign(CompileResult target, boolean pollute); + /** + * Called to perform calculations before the assigned value is calculated + */ + default void beforeAssign(CompileResult target) {} + /** + * Called to perform the actual assignemnt. Between the `beforeAssign` and this call a single value will have been pushed to the stack + * @param pollute Whether or not to leave the original value on the stack + */ + void afterAssign(CompileResult target, boolean pollute); - default void assign(CompileResult target, boolean pollute) { - afterAssign(target, pollute); - } + default void assign(CompileResult target, boolean pollute) { + afterAssign(target, pollute); + } - @Override default AssignTarget toAssignTarget() { return this; } + @Override default AssignTarget toAssignTarget() { return this; } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/patterns/AssignTargetLike.java b/src/main/java/me/topchetoeu/jscript/compilation/patterns/AssignTargetLike.java index 8d8f908..4c329c2 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/patterns/AssignTargetLike.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/patterns/AssignTargetLike.java @@ -4,5 +4,5 @@ package me.topchetoeu.jscript.compilation.patterns; * Represents all nodes that can be converted to assign targets */ public interface AssignTargetLike { - AssignTarget toAssignTarget(); + AssignTarget toAssignTarget(); } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/patterns/ChangeTarget.java b/src/main/java/me/topchetoeu/jscript/compilation/patterns/ChangeTarget.java index 68993af..941e270 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/patterns/ChangeTarget.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/patterns/ChangeTarget.java @@ -3,5 +3,5 @@ package me.topchetoeu.jscript.compilation.patterns; import me.topchetoeu.jscript.compilation.CompileResult; public interface ChangeTarget extends AssignTarget { - void beforeChange(CompileResult target); + void beforeChange(CompileResult target); } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/scope/FunctionScope.java b/src/main/java/me/topchetoeu/jscript/compilation/scope/FunctionScope.java index 213f020..8fdb3a5 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/scope/FunctionScope.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/scope/FunctionScope.java @@ -4,24 +4,24 @@ import java.util.ArrayList; import java.util.HashMap; public final class FunctionScope { - protected final VariableList locals = new VariableList(VariableIndex.IndexType.LOCALS); - protected final VariableList capturables = new VariableList(VariableIndex.IndexType.CAPTURABLES, this.locals); - private final VariableList captures = new VariableList(VariableIndex.IndexType.CAPTURES); + protected final VariableList locals = new VariableList(VariableIndex.IndexType.LOCALS); + protected final VariableList capturables = new VariableList(VariableIndex.IndexType.CAPTURABLES, this.locals); + private final VariableList captures = new VariableList(VariableIndex.IndexType.CAPTURES); - private final HashMap localsMap = new HashMap<>(); - private final HashMap capturesMap = new HashMap<>(); - private final ArrayList catchesMap = new ArrayList<>(); + private final HashMap localsMap = new HashMap<>(); + private final HashMap capturesMap = new HashMap<>(); + private final ArrayList catchesMap = new ArrayList<>(); - private final HashMap childToParent = new HashMap<>(); - private final HashMap parentToChild = new HashMap<>(); + private final HashMap childToParent = new HashMap<>(); + private final HashMap parentToChild = new HashMap<>(); - public final FunctionScope parent; - public final boolean passthrough; + public final FunctionScope parent; + public final boolean passthrough; - private Variable addCaptured(Variable var, boolean captured) { - if (captured && !this.capturables.has(var)) this.capturables.add(var); - return var; - } + private Variable addCaptured(Variable var, boolean captured) { + if (captured && !this.capturables.has(var)) this.capturables.add(var); + return var; + } private Variable getCatchVar(String name) { for (var el : catchesMap) { @@ -31,28 +31,28 @@ public final class FunctionScope { return null; } - /** - * @returns If a variable with the same name exists, the old variable. Otherwise, the given variable - */ - public Variable define(Variable var) { - if (passthrough) return null; - else { + /** + * @returns If a variable with the same name exists, the old variable. Otherwise, the given variable + */ + public Variable define(Variable var) { + if (passthrough) return null; + else { var catchVar = getCatchVar(var.name); if (catchVar != null) return catchVar; if (localsMap.containsKey(var.name)) return localsMap.get(var.name); if (capturesMap.containsKey(var.name)) throw new RuntimeException("HEY!"); - localsMap.put(var.name, var); - return locals.add(var); - } - } + localsMap.put(var.name, var); + return locals.add(var); + } + } - /** - * @returns A variable with the given name, or null if a global variable - */ - public Variable define(String name) { - return define(new Variable(name, false)); - } + /** + * @returns A variable with the given name, or null if a global variable + */ + public Variable define(String name) { + return define(new Variable(name, false)); + } /** * Creates a catch variable and returns it @@ -71,41 +71,41 @@ public final class FunctionScope { this.catchesMap.remove(this.catchesMap.size() - 1); } - /** - * Gets the index supplier of the given variable name, or null if it is a global - * - * @param capture If true, the variable is being captured by a function - */ - public Variable get(String name, boolean capture) { + /** + * Gets the index supplier of the given variable name, or null if it is a global + * + * @param capture If true, the variable is being captured by a function + */ + public Variable get(String name, boolean capture) { var catchVar = getCatchVar(name); - if (catchVar != null) return addCaptured(catchVar, capture); - if (localsMap.containsKey(name)) return addCaptured(localsMap.get(name), capture); - if (capturesMap.containsKey(name)) return addCaptured(capturesMap.get(name), capture); + if (catchVar != null) return addCaptured(catchVar, capture); + if (localsMap.containsKey(name)) return addCaptured(localsMap.get(name), capture); + if (capturesMap.containsKey(name)) return addCaptured(capturesMap.get(name), capture); - if (parent == null) return null; + if (parent == null) return null; - var parentVar = parent.get(name, true); - if (parentVar == null) return null; + var parentVar = parent.get(name, true); + if (parentVar == null) return null; var childVar = captures.add(parentVar.clone().setIndexSupplier(null)); - capturesMap.put(childVar.name, childVar); - childToParent.put(childVar, parentVar); - parentToChild.put(parentVar, childVar); + capturesMap.put(childVar.name, childVar); + childToParent.put(childVar, parentVar); + parentToChild.put(parentVar, childVar); - return childVar; - } + return childVar; + } - /** - * If the variable given is contained in this function, just returns the variable itself. + /** + * If the variable given is contained in this function, just returns the variable itself. * However, this function is important to handle cases in which you might want to access * a captured variable. In such cases, this function will return a capture to the given variable. - * - * @param capture Whether or not to execute this capturing logic - */ - public Variable get(Variable var, boolean capture) { - if (captures.has(var)) return addCaptured(var, capture); - if (locals.has(var)) return addCaptured(var, capture); + * + * @param capture Whether or not to execute this capturing logic + */ + public Variable get(Variable var, boolean capture) { + if (captures.has(var)) return addCaptured(var, capture); + if (locals.has(var)) return addCaptured(var, capture); if (capture) { if (parentToChild.containsKey(var)) return addCaptured(parentToChild.get(var), capture); @@ -122,54 +122,53 @@ public final class FunctionScope { return childVar; } else return null; - } + } - /** - * Checks if the given variable name is accessible - * - * @param capture If true, will check beyond this function's scope - */ - public boolean has(String name, boolean capture) { - if (localsMap.containsKey(name)) return true; - // if (specialVarMap.containsKey(name)) return true; + /** + * Checks if the given variable name is accessible + * + * @param capture If true, will check beyond this function's scope + */ + public boolean has(String name, boolean capture) { + if (localsMap.containsKey(name)) return true; - if (capture) { - if (capturesMap.containsKey(name)) return true; - if (parent != null) return parent.has(name, true); - } + if (capture) { + if (capturesMap.containsKey(name)) return true; + if (parent != null) return parent.has(name, true); + } - return false; - } + return false; + } - public int localsCount() { - return locals.size(); - } - public int capturesCount() { - return captures.size(); - } - public int capturablesCount() { - return capturables.size(); - } + public int localsCount() { + return locals.size(); + } + public int capturesCount() { + return captures.size(); + } + public int capturablesCount() { + return capturables.size(); + } - public int[] getCaptureIndices() { - var res = new int[captures.size()]; - var i = 0; + public int[] getCaptureIndices() { + var res = new int[captures.size()]; + var i = 0; - for (var el : captures) { - assert childToParent.containsKey(el); - res[i] = childToParent.get(el).index().toCaptureIndex(); - i++; - } + for (var el : captures) { + assert childToParent.containsKey(el); + res[i] = childToParent.get(el).index().toCaptureIndex(); + i++; + } - return res; - } + return res; + } - public Iterable capturables() { - return capturables; - } - public Iterable locals() { - return locals; - } + public Iterable capturables() { + return capturables; + } + public Iterable locals() { + return locals; + } public String[] captureNames() { var res = new String[this.captures.size()]; @@ -195,12 +194,12 @@ public final class FunctionScope { return res; } - public FunctionScope(FunctionScope parent) { - this.parent = parent; - this.passthrough = false; - } - public FunctionScope(boolean passthrough) { - this.parent = null; - this.passthrough = passthrough; - } + public FunctionScope(FunctionScope parent) { + this.parent = parent; + this.passthrough = false; + } + public FunctionScope(boolean passthrough) { + this.parent = null; + this.passthrough = passthrough; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/scope/Variable.java b/src/main/java/me/topchetoeu/jscript/compilation/scope/Variable.java index 571f796..8faf42f 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/scope/Variable.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/scope/Variable.java @@ -3,33 +3,33 @@ package me.topchetoeu.jscript.compilation.scope; import java.util.function.Supplier; public final class Variable { - private Supplier indexSupplier; + private Supplier indexSupplier; - public final boolean readonly; - public final String name; + public final boolean readonly; + public final String name; - public final VariableIndex index() { - return indexSupplier.get(); - } + public final VariableIndex index() { + return indexSupplier.get(); + } - public final Variable setIndexSupplier(Supplier index) { - this.indexSupplier = index; - return this; - } - public final Supplier indexSupplier() { - return indexSupplier; - } + public final Variable setIndexSupplier(Supplier index) { + this.indexSupplier = index; + return this; + } + public final Supplier indexSupplier() { + return indexSupplier; + } - public final Variable clone() { - return new Variable(name, readonly).setIndexSupplier(indexSupplier); - } + public final Variable clone() { + return new Variable(name, readonly).setIndexSupplier(indexSupplier); + } - public Variable(String name, boolean readonly) { - this.name = name; - this.readonly = readonly; - } + public Variable(String name, boolean readonly) { + this.name = name; + this.readonly = readonly; + } - public static Variable of(String name, boolean readonly, VariableIndex index) { - return new Variable(name, readonly).setIndexSupplier(() -> index); - } + public static Variable of(String name, boolean readonly, VariableIndex index) { + return new Variable(name, readonly).setIndexSupplier(() -> index); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/scope/VariableIndex.java b/src/main/java/me/topchetoeu/jscript/compilation/scope/VariableIndex.java index ea01ac9..1eee91b 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/scope/VariableIndex.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/scope/VariableIndex.java @@ -3,51 +3,51 @@ package me.topchetoeu.jscript.compilation.scope; import me.topchetoeu.jscript.common.Instruction; public final class VariableIndex { - public static enum IndexType { + public static enum IndexType { /** * A simple variable that is only ever used within the function */ - LOCALS, + LOCALS, /** * A variable that has the ability to be captured by children functions */ - CAPTURABLES, + CAPTURABLES, /** * A variable that has been captured from the parent function */ - CAPTURES, - } + CAPTURES, + } - public final IndexType type; - public final int index; + public final IndexType type; + public final int index; - public final int toCaptureIndex() { - switch (type) { - case CAPTURES: return ~index; - case CAPTURABLES: return index; - default: throw new UnsupportedOperationException("Index type " + type + " may not be captured"); - } - } + public final int toCaptureIndex() { + switch (type) { + case CAPTURES: return ~index; + case CAPTURABLES: return index; + default: throw new UnsupportedOperationException("Index type " + type + " may not be captured"); + } + } - public final Instruction toGet() { - switch (type) { - case CAPTURES: return Instruction.loadVar(~index); - case CAPTURABLES: return Instruction.loadVar(index); - case LOCALS: return Instruction.loadVar(index); - default: throw new UnsupportedOperationException("Unknown index type " + type); - } - } - public final Instruction toSet(boolean keep) { - switch (type) { - case CAPTURES: return Instruction.storeVar(index, keep, false); - case CAPTURABLES: return Instruction.storeVar(index, keep, false); - case LOCALS: return Instruction.storeVar(index, keep, false); - default: throw new UnsupportedOperationException("Unknown index type " + type); - } - } + public final Instruction toGet() { + switch (type) { + case CAPTURES: return Instruction.loadVar(~index); + case CAPTURABLES: return Instruction.loadVar(index); + case LOCALS: return Instruction.loadVar(index); + default: throw new UnsupportedOperationException("Unknown index type " + type); + } + } + public final Instruction toSet(boolean keep) { + switch (type) { + case CAPTURES: return Instruction.storeVar(index, keep, false); + case CAPTURABLES: return Instruction.storeVar(index, keep, false); + case LOCALS: return Instruction.storeVar(index, keep, false); + default: throw new UnsupportedOperationException("Unknown index type " + type); + } + } - public VariableIndex(VariableIndex.IndexType type, int index) { - this.type = type; - this.index = index; - } + public VariableIndex(VariableIndex.IndexType type, int index) { + this.type = type; + this.index = index; + } } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/compilation/scope/VariableList.java b/src/main/java/me/topchetoeu/jscript/compilation/scope/VariableList.java index 414b4d2..a2fafbf 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/scope/VariableList.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/scope/VariableList.java @@ -8,14 +8,14 @@ import java.util.function.Supplier; import me.topchetoeu.jscript.compilation.scope.VariableIndex.IndexType; public final class VariableList implements Iterable { - private final class VariableNode implements Supplier { - public Variable var; - public VariableNode next; - public VariableNode prev; - public int index; + private final class VariableNode implements Supplier { + public Variable var; + public VariableNode next; + public VariableNode prev; + public int index; public int indexIteration = -1; - public VariableList list() { return VariableList.this; } + public VariableList list() { return VariableList.this; } private int getIndex() { if (this.indexIteration != VariableList.this.indexIteration) { @@ -28,23 +28,23 @@ public final class VariableList implements Iterable { return this.index; } - @Override public VariableIndex get() { + @Override public VariableIndex get() { if (offset == null) return new VariableIndex(indexType, this.getIndex()); else return new VariableIndex(indexType, offset.getAsInt() + this.getIndex()); - } + } - public VariableNode(Variable var, VariableNode next, VariableNode prev) { - this.var = var; - this.next = next; - this.prev = prev; - } - } + public VariableNode(Variable var, VariableNode next, VariableNode prev) { + this.var = var; + this.next = next; + this.prev = prev; + } + } - private VariableNode first, last; + private VariableNode first, last; - private HashMap varMap = new HashMap<>(); + private HashMap varMap = new HashMap<>(); - private final IntSupplier offset; + private final IntSupplier offset; /** * Increased when indices need recalculation. VariableNode will check if * its internal indexIteration is up to date with this, and if not, will @@ -52,140 +52,140 @@ public final class VariableList implements Iterable { */ private int indexIteration = 0; - public final VariableIndex.IndexType indexType; + public final VariableIndex.IndexType indexType; /** * Adds the given variable to this list. If it already exists, does nothing * @return val */ - public Variable add(Variable val) { + public Variable add(Variable val) { if (this.varMap.containsKey(val)) return val; this.indexIteration++; - if (val.indexSupplier() instanceof VariableNode prevNode) { - prevNode.list().remove(val); - } + if (val.indexSupplier() instanceof VariableNode prevNode) { + prevNode.list().remove(val); + } - var node = new VariableNode(val, null, last); + var node = new VariableNode(val, null, last); - if (last != null) { - assert first != null; + if (last != null) { + assert first != null; - last.next = node; - node.prev = last; + last.next = node; + node.prev = last; - last = node; - } - else { - first = last = node; - } + last = node; + } + else { + first = last = node; + } - varMap.put(val, node); - val.setIndexSupplier(node); + varMap.put(val, node); + val.setIndexSupplier(node); - return val; - } + return val; + } /** * If the variable is not in the list, does nothing. Otherwise, removes the variable from the list * @return null if nothing was done, else the deleted variable (should be var) */ - public Variable remove(Variable var) { - if (var == null) return null; + public Variable remove(Variable var) { + if (var == null) return null; - var node = varMap.get(var); - if (node == null) return null; + var node = varMap.get(var); + if (node == null) return null; this.indexIteration++; - if (node.prev != null) { - assert node != first; - node.prev.next = node.next; - } - else { - assert node == first; - first = first.next; - } + if (node.prev != null) { + assert node != first; + node.prev.next = node.next; + } + else { + assert node == first; + first = first.next; + } - if (node.next != null) { - assert node != last; - node.next.prev = node.prev; - } - else { - assert node == last; - last = last.prev; - } + if (node.next != null) { + assert node != last; + node.next.prev = node.prev; + } + else { + assert node == last; + last = last.prev; + } - node.next = null; - node.prev = null; + node.next = null; + node.prev = null; - varMap.remove(node.var); + varMap.remove(node.var); node.var.setIndexSupplier(null); - return node.var; - } + return node.var; + } /** * Checks if the list has the given variable */ - public boolean has(Variable var) { - return varMap.containsKey(var); - } + public boolean has(Variable var) { + return varMap.containsKey(var); + } /** * Returns an indexer for the given variable */ - public Supplier indexer(Variable var) { - return varMap.get(var); - } + public Supplier indexer(Variable var) { + return varMap.get(var); + } - public int size() { + public int size() { return varMap.size(); - } + } public Iterator iterator() { - return new Iterator() { - private VariableNode curr = first; + return new Iterator() { + private VariableNode curr = first; - @Override public boolean hasNext() { - return curr != null; - } - @Override public Variable next() { - if (curr == null) return null; + @Override public boolean hasNext() { + return curr != null; + } + @Override public Variable next() { + if (curr == null) return null; - var res = curr; - curr = curr.next; - return res.var; - } - }; - } + var res = curr; + curr = curr.next; + return res.var; + } + }; + } /** * @param offset Will offset the indices by the given amount from the supplier */ - public VariableList(IndexType type, IntSupplier offset) { - this.indexType = type; - this.offset = offset; - } + public VariableList(IndexType type, IntSupplier offset) { + this.indexType = type; + this.offset = offset; + } /** * @param offset Will offset the indices by the given amount */ - public VariableList(IndexType type, int offset) { - this.indexType = type; - this.offset = () -> offset; - } + public VariableList(IndexType type, int offset) { + this.indexType = type; + this.offset = () -> offset; + } /** * @param offset Will offset the indices by the size of the given list */ - public VariableList(IndexType type, VariableList prev) { - this.indexType = type; - this.offset = () -> { + public VariableList(IndexType type, VariableList prev) { + this.indexType = type; + this.offset = () -> { if (prev.offset != null) return prev.offset.getAsInt() + prev.size(); else return prev.size(); }; - } - public VariableList(IndexType type) { - this.indexType = type; - this.offset = null; - } + } + public VariableList(IndexType type) { + this.indexType = type; + this.offset = null; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/ArgumentsNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/ArgumentsNode.java index 2ed09d0..3508d35 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/ArgumentsNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/ArgumentsNode.java @@ -10,11 +10,11 @@ public class ArgumentsNode extends Node { @Override public void compileFunctions(CompileResult target) { } - @Override public void compile(CompileResult target, boolean pollute) { - if (pollute) target.add(Instruction.loadArgs()); - } + @Override public void compile(CompileResult target, boolean pollute) { + if (pollute) target.add(Instruction.loadArgs()); + } - public ArgumentsNode(Location loc) { - super(loc); - } + public ArgumentsNode(Location loc) { + super(loc); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/ArrayNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/ArrayNode.java index 8e4ba22..35962d5 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/ArrayNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/ArrayNode.java @@ -13,75 +13,75 @@ import me.topchetoeu.jscript.compilation.Node; public class ArrayNode extends Node { - public final Node[] statements; + public final Node[] statements; @Override public void compileFunctions(CompileResult target) { - for (var stm : statements) { + for (var stm : statements) { if (stm != null) stm.compileFunctions(target); } } - @Override public void compile(CompileResult target, boolean pollute) { - target.add(Instruction.loadArr(statements.length)); + @Override public void compile(CompileResult target, boolean pollute) { + target.add(Instruction.loadArr(statements.length)); - for (var i = 0; i < statements.length; i++) { - var el = statements[i]; - if (el != null) { - target.add(Instruction.dup()); - el.compile(target, true); - target.add(Instruction.storeMember(i)); - } - } + for (var i = 0; i < statements.length; i++) { + var el = statements[i]; + if (el != null) { + target.add(Instruction.dup()); + el.compile(target, true); + target.add(Instruction.storeMember(i)); + } + } - if (!pollute) target.add(Instruction.discard()); - } + if (!pollute) target.add(Instruction.discard()); + } - public ArrayNode(Location loc, Node[] statements) { - super(loc); - this.statements = statements; - } + public ArrayNode(Location loc, Node[] statements) { + super(loc); + this.statements = statements; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, "[")) return ParseRes.failed(); - n++; + if (!src.is(i + n, "[")) return ParseRes.failed(); + n++; - var values = new ArrayList(); + var values = new ArrayList(); - loop: while (true) { - n += Parsing.skipEmpty(src, i + n); - if (src.is(i + n, "]")) { - n++; - break; - } + loop: while (true) { + n += Parsing.skipEmpty(src, i + n); + if (src.is(i + n, "]")) { + n++; + break; + } - while (src.is(i + n, ",")) { - n++; - n += Parsing.skipEmpty(src, i + n); - values.add(null); + while (src.is(i + n, ",")) { + n++; + n += Parsing.skipEmpty(src, i + n); + values.add(null); - if (src.is(i + n, "]")) { - n++; - break loop; - } - } + if (src.is(i + n, "]")) { + n++; + break loop; + } + } - var res = JavaScript.parseExpression(src, i + n, 2); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected an array element."); - n += res.n; - n += Parsing.skipEmpty(src, i + n); + var res = JavaScript.parseExpression(src, i + n, 2); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected an array element."); + n += res.n; + n += Parsing.skipEmpty(src, i + n); - values.add(res.result); + values.add(res.result); - if (src.is(i + n, ",")) n++; - else if (src.is(i + n, "]")) { - n++; - break; - } - } + if (src.is(i + n, ",")) n++; + else if (src.is(i + n, "]")) { + n++; + break; + } + } - return ParseRes.res(new ArrayNode(loc, values.toArray(new Node[0])), n); - } + return ParseRes.res(new ArrayNode(loc, values.toArray(new Node[0])), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/GlobalThisNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/GlobalThisNode.java index ac83d7d..fde1966 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/GlobalThisNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/GlobalThisNode.java @@ -10,11 +10,11 @@ public class GlobalThisNode extends Node { @Override public void compileFunctions(CompileResult target) { } - @Override public void compile(CompileResult target, boolean pollute) { - if (pollute) target.add(Instruction.loadGlob()); - } + @Override public void compile(CompileResult target, boolean pollute) { + if (pollute) target.add(Instruction.loadGlob()); + } - public GlobalThisNode(Location loc) { - super(loc); - } + public GlobalThisNode(Location loc) { + super(loc); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/ObjectNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/ObjectNode.java index 7b41a28..de71814 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/ObjectNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/ObjectNode.java @@ -18,97 +18,97 @@ import me.topchetoeu.jscript.compilation.values.constants.NumberNode; import me.topchetoeu.jscript.compilation.values.constants.StringNode; public class ObjectNode extends Node { - public final List members; + public final List members; @Override public void compileFunctions(CompileResult target) { for (var member : members) member.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - target.add(Instruction.loadObj()); - for (var el : members) el.compile(target, true); - } + @Override public void compile(CompileResult target, boolean pollute) { + target.add(Instruction.loadObj()); + for (var el : members) el.compile(target, true); + } - public ObjectNode(Location loc, List map) { - super(loc); - this.members = map; - } + public ObjectNode(Location loc, List map) { + super(loc); + this.members = map; + } - private static ParseRes parseComputePropName(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - if (!src.is(i + n, "[")) return ParseRes.failed(); - n++; + private static ParseRes parseComputePropName(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + if (!src.is(i + n, "[")) return ParseRes.failed(); + n++; - var val = JavaScript.parseExpression(src, i, 0); - if (!val.isSuccess()) return val.chainError(src.loc(i + n), "Expected an expression in compute property"); - n += val.n; - n += Parsing.skipEmpty(src, i + n); + var val = JavaScript.parseExpression(src, i, 0); + if (!val.isSuccess()) return val.chainError(src.loc(i + n), "Expected an expression in compute property"); + n += val.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, "]")) return ParseRes.error(src.loc(i + n), "Expected a closing bracket after compute property"); - n++; + if (!src.is(i + n, "]")) return ParseRes.error(src.loc(i + n), "Expected a closing bracket after compute property"); + n++; - return ParseRes.res(val.result, n); - } - public static ParseRes parsePropName(Source src, int i) { - return ParseRes.first(src, i, - (s, j) -> { - var m = Parsing.skipEmpty(s, j); - var l = s.loc(j + m); + return ParseRes.res(val.result, n); + } + public static ParseRes parsePropName(Source src, int i) { + return ParseRes.first(src, i, + (s, j) -> { + var m = Parsing.skipEmpty(s, j); + var l = s.loc(j + m); - var r = Parsing.parseIdentifier(s, j + m); - if (r.isSuccess()) return ParseRes.res(new StringNode(l, r.result), r.n); - else return r.chainError(); - }, - StringNode::parse, - NumberNode::parse, - ObjectNode::parseComputePropName - ); - } + var r = Parsing.parseIdentifier(s, j + m); + if (r.isSuccess()) return ParseRes.res(new StringNode(l, r.result), r.n); + else return r.chainError(); + }, + StringNode::parse, + NumberNode::parse, + ObjectNode::parseComputePropName + ); + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, "{")) return ParseRes.failed(); - n++; - n += Parsing.skipEmpty(src, i + n); + if (!src.is(i + n, "{")) return ParseRes.failed(); + n++; + n += Parsing.skipEmpty(src, i + n); - var members = new LinkedList(); + var members = new LinkedList(); - if (src.is(i + n, "}")) { - n++; - return ParseRes.res(new ObjectNode(loc, members), n); - } + if (src.is(i + n, "}")) { + n++; + return ParseRes.res(new ObjectNode(loc, members), n); + } - while (true) { - ParseRes prop = ParseRes.first(src, i + n, - PropertyMemberNode::parse, - FieldMemberNode::parse - ); - if (!prop.isSuccess()) return prop.chainError(src.loc(i + n), "Expected a member in object literal"); - n += prop.n; + while (true) { + ParseRes prop = ParseRes.first(src, i + n, + PropertyMemberNode::parse, + FieldMemberNode::parse + ); + if (!prop.isSuccess()) return prop.chainError(src.loc(i + n), "Expected a member in object literal"); + n += prop.n; - members.add(prop.result); + members.add(prop.result); - n += Parsing.skipEmpty(src, i + n); - if (src.is(i + n, ",")) { - n++; - n += Parsing.skipEmpty(src, i + n); + n += Parsing.skipEmpty(src, i + n); + if (src.is(i + n, ",")) { + n++; + n += Parsing.skipEmpty(src, i + n); - if (src.is(i + n, "}")) { - n++; - break; - } + if (src.is(i + n, "}")) { + n++; + break; + } - continue; - } - else if (src.is(i + n, "}")) { - n++; - break; - } - else ParseRes.error(src.loc(i + n), "Expected a comma or a closing brace."); - } - - return ParseRes.res(new ObjectNode(loc, members), n); - } + continue; + } + else if (src.is(i + n, "}")) { + n++; + break; + } + else ParseRes.error(src.loc(i + n), "Expected a comma or a closing brace."); + } + + return ParseRes.res(new ObjectNode(loc, members), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/RegexNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/RegexNode.java index 11cab99..8c8ccc4 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/RegexNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/RegexNode.java @@ -9,29 +9,29 @@ import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.Node; public class RegexNode extends Node { - public final String pattern, flags; + public final String pattern, flags; @Override public void compileFunctions(CompileResult target) { } - @Override public void compile(CompileResult target, boolean pollute) { - target.add(Instruction.loadRegex(pattern, flags)); - if (!pollute) target.add(Instruction.discard()); - } + @Override public void compile(CompileResult target, boolean pollute) { + target.add(Instruction.loadRegex(pattern, flags)); + if (!pollute) target.add(Instruction.discard()); + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); - if (!src.is(i + n, '/')) return ParseRes.failed(); - var loc = src.loc(i + n); - n++; + if (!src.is(i + n, '/')) return ParseRes.failed(); + var loc = src.loc(i + n); + n++; - var source = new StringBuilder(); - var flags = new StringBuilder(); + var source = new StringBuilder(); + var flags = new StringBuilder(); - var inBrackets = false; + var inBrackets = false; - loop: while (true) { + loop: while (true) { switch (src.at(i + n)) { case '[': inBrackets = true; @@ -60,26 +60,26 @@ public class RegexNode extends Node { n++; break; } - } + } - while (true) { - char c = src.at(i + n, '\0'); + while (true) { + char c = src.at(i + n, '\0'); - if (src.is(i + n, v -> Parsing.isAny(c, "dgimsuy"))) { - if (flags.indexOf(c + "") >= 0) return ParseRes.error(src.loc(i + n), "The flags of a regular expression may not be repeated"); - flags.append(c); - } - else break; + if (src.is(i + n, v -> Parsing.isAny(c, "dgimsuy"))) { + if (flags.indexOf(c + "") >= 0) return ParseRes.error(src.loc(i + n), "The flags of a regular expression may not be repeated"); + flags.append(c); + } + else break; - n++; - } + n++; + } - return ParseRes.res(new RegexNode(loc, source.toString(), flags.toString()), n); - } + return ParseRes.res(new RegexNode(loc, source.toString(), flags.toString()), n); + } - public RegexNode(Location loc, String pattern, String flags) { - super(loc); - this.pattern = pattern; - this.flags = flags; - } + public RegexNode(Location loc, String pattern, String flags) { + super(loc); + this.pattern = pattern; + this.flags = flags; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/ThisNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/ThisNode.java index 27a05b3..af466b8 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/ThisNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/ThisNode.java @@ -10,11 +10,11 @@ public class ThisNode extends Node { @Override public void compileFunctions(CompileResult target) { } - @Override public void compile(CompileResult target, boolean pollute) { - if (pollute) target.add(Instruction.loadThis()); - } + @Override public void compile(CompileResult target, boolean pollute) { + if (pollute) target.add(Instruction.loadThis()); + } - public ThisNode(Location loc) { - super(loc); - } + public ThisNode(Location loc) { + super(loc); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/VariableNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/VariableNode.java index 9e76617..823baca 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/VariableNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/VariableNode.java @@ -11,63 +11,63 @@ import me.topchetoeu.jscript.compilation.Node; import me.topchetoeu.jscript.compilation.patterns.ChangeTarget; public class VariableNode extends Node implements ChangeTarget { - public final String name; + public final String name; @Override public void compileFunctions(CompileResult target) { } - public String assignName() { return name; } + public String assignName() { return name; } - @Override public void beforeChange(CompileResult target) { - target.add(VariableNode.toGet(target, loc(), name)); - } + @Override public void beforeChange(CompileResult target) { + target.add(VariableNode.toGet(target, loc(), name)); + } - @Override public void afterAssign(CompileResult target, boolean pollute) { - target.add(VariableNode.toSet(target, loc(), name, pollute, false)).setLocation(loc()); - } + @Override public void afterAssign(CompileResult target, boolean pollute) { + target.add(VariableNode.toSet(target, loc(), name, pollute, false)).setLocation(loc()); + } - @Override public void compile(CompileResult target, boolean pollute) { - target.add(toGet(target, loc(), name, true, false)).setLocation(loc()); - } + @Override public void compile(CompileResult target, boolean pollute) { + target.add(toGet(target, loc(), name, true, false)).setLocation(loc()); + } - public static Instruction toGet(CompileResult target, Location loc, String name, boolean keep, boolean forceGet) { - var i = target.scope.get(name, false); + public static Instruction toGet(CompileResult target, Location loc, String name, boolean keep, boolean forceGet) { + var i = target.scope.get(name, false); - if (i != null) { - if (keep) return i.index().toGet(); - else return Instruction.nop(); - } - else return Instruction.globGet(name, forceGet); - } - public static Instruction toGet(CompileResult target, Location loc, String name) { - return toGet(target, loc, name, true, false); - } + if (i != null) { + if (keep) return i.index().toGet(); + else return Instruction.nop(); + } + else return Instruction.globGet(name, forceGet); + } + public static Instruction toGet(CompileResult target, Location loc, String name) { + return toGet(target, loc, name, true, false); + } - public static Instruction toSet(CompileResult target, Location loc, String name, boolean keep, boolean init) { - var i = target.scope.get(name, false); + public static Instruction toSet(CompileResult target, Location loc, String name, boolean keep, boolean init) { + var i = target.scope.get(name, false); - if (i != null) return i.index().toSet(keep); - else return Instruction.globSet(name, keep, init); - } + if (i != null) return i.index().toSet(keep); + else return Instruction.globSet(name, keep, init); + } - public VariableNode(Location loc, String name) { - super(loc); - this.name = name; - } + public VariableNode(Location loc, String name) { + super(loc); + this.name = name; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var literal = Parsing.parseIdentifier(src, i); - if (!literal.isSuccess()) return literal.chainError(); - n += literal.n; + var literal = Parsing.parseIdentifier(src, i); + if (!literal.isSuccess()) return literal.chainError(); + n += literal.n; - if (!JavaScript.checkVarName(literal.result)) { - if (literal.result.equals("await")) return ParseRes.error(src.loc(i + n), "'await' expressions are not supported"); - return ParseRes.error(src.loc(i + n), String.format("Unexpected keyword '%s'", literal.result)); - } + if (!JavaScript.checkVarName(literal.result)) { + if (literal.result.equals("await")) return ParseRes.error(src.loc(i + n), "'await' expressions are not supported"); + return ParseRes.error(src.loc(i + n), String.format("Unexpected keyword '%s'", literal.result)); + } - return ParseRes.res(new VariableNode(loc, literal.result), n); - } + return ParseRes.res(new VariableNode(loc, literal.result), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/constants/BoolNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/constants/BoolNode.java index 4eab801..262f8ec 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/constants/BoolNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/constants/BoolNode.java @@ -6,17 +6,17 @@ import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.Node; public class BoolNode extends Node { - public final boolean value; + public final boolean value; @Override public void compileFunctions(CompileResult target) { } - @Override public void compile(CompileResult target, boolean pollute) { - if (pollute) target.add(Instruction.pushValue(value)); - } + @Override public void compile(CompileResult target, boolean pollute) { + if (pollute) target.add(Instruction.pushValue(value)); + } - public BoolNode(Location loc, boolean value) { - super(loc); - this.value = value; - } + public BoolNode(Location loc, boolean value) { + super(loc); + this.value = value; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/constants/NullNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/constants/NullNode.java index 3b1ff02..90d8a60 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/constants/NullNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/constants/NullNode.java @@ -9,9 +9,9 @@ public class NullNode extends Node { @Override public void compileFunctions(CompileResult target) { } - @Override public void compile(CompileResult target, boolean pollute) { - if (pollute) target.add(Instruction.pushNull()); - } + @Override public void compile(CompileResult target, boolean pollute) { + if (pollute) target.add(Instruction.pushNull()); + } - public NullNode(Location loc) { super(loc); } + public NullNode(Location loc) { super(loc); } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/constants/NumberNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/constants/NumberNode.java index d76a949..a0a4fa6 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/constants/NumberNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/constants/NumberNode.java @@ -9,35 +9,35 @@ import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.Node; public class NumberNode extends Node { - public final double value; + public final double value; @Override public void compileFunctions(CompileResult target) { } - @Override public void compile(CompileResult target, boolean pollute) { - if (pollute) target.add(Instruction.pushValue(value)); - } + @Override public void compile(CompileResult target, boolean pollute) { + if (pollute) target.add(Instruction.pushValue(value)); + } - public NumberNode(Location loc, double value) { - super(loc); - this.value = value; - } + public NumberNode(Location loc, double value) { + super(loc); + this.value = value; + } - public static double power(double a, long b) { - if (b == 0) return 1; - if (b == 1) return a; - if (b < 0) return 1 / power(a, -b); + public static double power(double a, long b) { + if (b == 0) return 1; + if (b == 1) return a; + if (b < 0) return 1 / power(a, -b); - if ((b & 1) == 0) return power(a * a, b / 2); - else return a * power(a * a, b / 2); - } + if ((b & 1) == 0) return power(a * a, b / 2); + else return a * power(a * a, b / 2); + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var res = Parsing.parseNumber(src, i + n, false); - if (res.isSuccess()) return ParseRes.res(new NumberNode(loc, res.result), n + res.n); - else return res.chainError(); - } + var res = Parsing.parseNumber(src, i + n, false); + if (res.isSuccess()) return ParseRes.res(new NumberNode(loc, res.result), n + res.n); + else return res.chainError(); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/constants/StringNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/constants/StringNode.java index ede91c3..23187a0 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/constants/StringNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/constants/StringNode.java @@ -9,26 +9,26 @@ import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.Node; public class StringNode extends Node { - public final String value; + public final String value; @Override public void compileFunctions(CompileResult target) { } - @Override public void compile(CompileResult target, boolean pollute) { - if (pollute) target.add(Instruction.pushValue(value)); - } + @Override public void compile(CompileResult target, boolean pollute) { + if (pollute) target.add(Instruction.pushValue(value)); + } - public StringNode(Location loc, String value) { - super(loc); - this.value = value; - } + public StringNode(Location loc, String value) { + super(loc); + this.value = value; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var res = Parsing.parseString(src, i + n); - if (res.isSuccess()) return ParseRes.res(new StringNode(loc, res.result), n + res.n); - else return res.chainError(); - } + var res = Parsing.parseString(src, i + n); + if (res.isSuccess()) return ParseRes.res(new StringNode(loc, res.result), n + res.n); + else return res.chainError(); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/AssignNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/AssignNode.java index 6860f09..292ce2e 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/AssignNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/AssignNode.java @@ -9,43 +9,43 @@ import me.topchetoeu.jscript.compilation.Node; import me.topchetoeu.jscript.compilation.patterns.AssignTarget; public class AssignNode extends Node implements AssignTarget { - public final AssignTarget assignable; - public final Node value; + public final AssignTarget assignable; + public final Node value; @Override public void compileFunctions(CompileResult target) { ((Node)assignable).compileFunctions(target); value.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - if (assignable instanceof AssignNode other) throw new SyntaxException(other.loc(), "Assign deconstructor not allowed here"); + @Override public void compile(CompileResult target, boolean pollute) { + if (assignable instanceof AssignNode other) throw new SyntaxException(other.loc(), "Assign deconstructor not allowed here"); - assignable.beforeAssign(target); - value.compile(target, true); - assignable.afterAssign(target, pollute); - } + assignable.beforeAssign(target); + value.compile(target, true); + assignable.afterAssign(target, pollute); + } - @Override public void afterAssign(CompileResult target, boolean pollute) { - if (assignable instanceof AssignNode other) throw new SyntaxException(other.loc(), "Double assign deconstructor not allowed"); + @Override public void afterAssign(CompileResult target, boolean pollute) { + if (assignable instanceof AssignNode other) throw new SyntaxException(other.loc(), "Double assign deconstructor not allowed"); - if (pollute) target.add(Instruction.dup(2, 0)); - else target.add(Instruction.dup()); - target.add(Instruction.pushUndefined()); - target.add(Instruction.operation(Operation.EQUALS)); - var start = target.temp(); - target.add(Instruction.discard()); + if (pollute) target.add(Instruction.dup(2, 0)); + else target.add(Instruction.dup()); + target.add(Instruction.pushUndefined()); + target.add(Instruction.operation(Operation.EQUALS)); + var start = target.temp(); + target.add(Instruction.discard()); - value.compile(target, true); + value.compile(target, true); - target.set(start, Instruction.jmpIfNot(target.size() - start)); + target.set(start, Instruction.jmpIfNot(target.size() - start)); - assignable.assign(target, false); - if (!pollute) target.add(Instruction.discard()); - } + assignable.assign(target, false); + if (!pollute) target.add(Instruction.discard()); + } - public AssignNode(Location loc, AssignTarget assignable, Node value) { - super(loc); - this.assignable = assignable; - this.value = value; - } + public AssignNode(Location loc, AssignTarget assignable, Node value) { + super(loc); + this.assignable = assignable; + this.value = value; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/CallNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/CallNode.java index 150ea36..3b91b61 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/CallNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/CallNode.java @@ -13,103 +13,103 @@ import me.topchetoeu.jscript.compilation.JavaScript; import me.topchetoeu.jscript.compilation.Node; public class CallNode extends Node { - public final Node func; - public final Node[] args; - public final boolean isNew; + public final Node func; + public final Node[] args; + public final boolean isNew; @Override public void compileFunctions(CompileResult target) { func.compileFunctions(target); for (var arg : args) arg.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute, BreakpointType type) { + @Override public void compile(CompileResult target, boolean pollute, BreakpointType type) { if (!isNew && func instanceof IndexNode indexNode) { - var obj = indexNode.object; - var index = indexNode.index; + var obj = indexNode.object; + var index = indexNode.index; obj.compile(target, true); target.add(Instruction.dup()); IndexNode.indexLoad(target, index, true); - for (var arg : args) arg.compile(target, true); + for (var arg : args) arg.compile(target, true); - target.add(Instruction.call(args.length, true)); + target.add(Instruction.call(args.length, true)); - target.setLocationAndDebug(loc(), type); - } - else { - func.compile(target, true); - for (var arg : args) arg.compile(target, true); + target.setLocationAndDebug(loc(), type); + } + else { + func.compile(target, true); + for (var arg : args) arg.compile(target, true); - if (isNew) target.add(Instruction.callNew(args.length)).setLocationAndDebug(loc(), type); - else target.add(Instruction.call(args.length, false)).setLocationAndDebug(loc(), type); - } - if (!pollute) target.add(Instruction.discard()); - } - @Override public void compile(CompileResult target, boolean pollute) { - compile(target, pollute, BreakpointType.STEP_IN); - } + if (isNew) target.add(Instruction.callNew(args.length)).setLocationAndDebug(loc(), type); + else target.add(Instruction.call(args.length, false)).setLocationAndDebug(loc(), type); + } + if (!pollute) target.add(Instruction.discard()); + } + @Override public void compile(CompileResult target, boolean pollute) { + compile(target, pollute, BreakpointType.STEP_IN); + } - public CallNode(Location loc, boolean isNew, Node func, Node ...args) { - super(loc); - this.isNew = isNew; - this.func = func; - this.args = args; - } + public CallNode(Location loc, boolean isNew, Node func, Node ...args) { + super(loc); + this.isNew = isNew; + this.func = func; + this.args = args; + } - public static ParseRes parseCall(Source src, int i, Node prev, int precedence) { - if (precedence > 17) return ParseRes.failed(); + public static ParseRes parseCall(Source src, int i, Node prev, int precedence) { + if (precedence > 17) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, "(")) return ParseRes.failed(); - n++; + if (!src.is(i + n, "(")) return ParseRes.failed(); + n++; - var args = new ArrayList(); - boolean prevArg = false; + var args = new ArrayList(); + boolean prevArg = false; - while (true) { - var argRes = JavaScript.parseExpression(src, i + n, 2); - n += argRes.n; - n += Parsing.skipEmpty(src, i + n); + while (true) { + var argRes = JavaScript.parseExpression(src, i + n, 2); + n += argRes.n; + n += Parsing.skipEmpty(src, i + n); - if (argRes.isSuccess()) { - args.add(argRes.result); - prevArg = true; - } - else if (argRes.isError()) return argRes.chainError(); + if (argRes.isSuccess()) { + args.add(argRes.result); + prevArg = true; + } + else if (argRes.isError()) return argRes.chainError(); if (prevArg && src.is(i + n, ",")) { - prevArg = false; - n++; - } - else if (src.is(i + n, ")")) { - n++; - break; - } - else if (prevArg) return ParseRes.error(src.loc(i + n), "Expected a comma or a closing paren"); - else return ParseRes.error(src.loc(i + n), "Expected an expression or a closing paren"); - } + prevArg = false; + n++; + } + else if (src.is(i + n, ")")) { + n++; + break; + } + else if (prevArg) return ParseRes.error(src.loc(i + n), "Expected a comma or a closing paren"); + else return ParseRes.error(src.loc(i + n), "Expected an expression or a closing paren"); + } - return ParseRes.res(new CallNode(loc, false, prev, args.toArray(new Node[0])), n); - } - public static ParseRes parseNew(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + return ParseRes.res(new CallNode(loc, false, prev, args.toArray(new Node[0])), n); + } + public static ParseRes parseNew(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!Parsing.isIdentifier(src, i + n, "new")) return ParseRes.failed(); - n += 3; + if (!Parsing.isIdentifier(src, i + n, "new")) return ParseRes.failed(); + n += 3; - var valRes = JavaScript.parseExpression(src, i + n, 18); - if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'new' keyword."); - n += valRes.n; + var valRes = JavaScript.parseExpression(src, i + n, 18); + if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'new' keyword."); + n += valRes.n; - var callRes = CallNode.parseCall(src, i + n, valRes.result, 0); - if (callRes.isFailed()) return ParseRes.res(new CallNode(loc, true, valRes.result), n); - if (callRes.isError()) return callRes.chainError(); - n += callRes.n; + var callRes = CallNode.parseCall(src, i + n, valRes.result, 0); + if (callRes.isFailed()) return ParseRes.res(new CallNode(loc, true, valRes.result), n); + if (callRes.isError()) return callRes.chainError(); + n += callRes.n; - return ParseRes.res(new CallNode(loc, true, callRes.result.func, callRes.result.args), n); - } + return ParseRes.res(new CallNode(loc, true, callRes.result.func, callRes.result.args), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/ChangeNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/ChangeNode.java index 160d875..caf60fd 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/ChangeNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/ChangeNode.java @@ -13,53 +13,53 @@ import me.topchetoeu.jscript.compilation.patterns.ChangeTarget; import me.topchetoeu.jscript.compilation.values.constants.NumberNode; public class ChangeNode extends Node { - public final ChangeTarget changable; - public final Node value; - public final Operation op; + public final ChangeTarget changable; + public final Node value; + public final Operation op; @Override public void compileFunctions(CompileResult target) { ((Node)changable).compileFunctions(target); value.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - changable.beforeChange(target); - value.compile(target, true); - target.add(Instruction.operation(op)); - changable.afterAssign(target, pollute); - } + @Override public void compile(CompileResult target, boolean pollute) { + changable.beforeChange(target); + value.compile(target, true); + target.add(Instruction.operation(op)); + changable.afterAssign(target, pollute); + } - public ChangeNode(Location loc, ChangeTarget changable, Node value, Operation op) { - super(loc); - this.changable = changable; - this.value = value; - this.op = op; - } + public ChangeNode(Location loc, ChangeTarget changable, Node value, Operation op) { + super(loc); + this.changable = changable; + this.value = value; + this.op = op; + } - public static ParseRes parsePrefixIncrease(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parsePrefixIncrease(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, "++")) return ParseRes.failed(); - n += 2; + if (!src.is(i + n, "++")) return ParseRes.failed(); + n += 2; - var res = JavaScript.parseExpression(src, i + n, 15); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected assignable value after prefix operator."); - else if (!(res.result instanceof ChangeTarget)) return ParseRes.error(src.loc(i + n), "Expected assignable value after prefix operator."); + var res = JavaScript.parseExpression(src, i + n, 15); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected assignable value after prefix operator."); + else if (!(res.result instanceof ChangeTarget)) return ParseRes.error(src.loc(i + n), "Expected assignable value after prefix operator."); - return ParseRes.res(new ChangeNode(loc, (ChangeTarget)res.result, new NumberNode(loc, -1), Operation.SUBTRACT), n + res.n); - } - public static ParseRes parsePrefixDecrease(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + return ParseRes.res(new ChangeNode(loc, (ChangeTarget)res.result, new NumberNode(loc, -1), Operation.SUBTRACT), n + res.n); + } + public static ParseRes parsePrefixDecrease(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, "--")) return ParseRes.failed(); - n += 2; + if (!src.is(i + n, "--")) return ParseRes.failed(); + n += 2; - var res = JavaScript.parseExpression(src, i + n, 15); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected assignable value after prefix operator."); - else if (!(res.result instanceof ChangeTarget)) return ParseRes.error(src.loc(i + n), "Expected assignable value after prefix operator."); + var res = JavaScript.parseExpression(src, i + n, 15); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected assignable value after prefix operator."); + else if (!(res.result instanceof ChangeTarget)) return ParseRes.error(src.loc(i + n), "Expected assignable value after prefix operator."); - return ParseRes.res(new ChangeNode(loc, (ChangeTarget)res.result, new NumberNode(loc, 1), Operation.SUBTRACT), n + res.n); - } + return ParseRes.res(new ChangeNode(loc, (ChangeTarget)res.result, new NumberNode(loc, 1), Operation.SUBTRACT), n + res.n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/DiscardNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/DiscardNode.java index 3e2315c..ac1ab0d 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/DiscardNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/DiscardNode.java @@ -11,33 +11,33 @@ import me.topchetoeu.jscript.compilation.Node; public class DiscardNode extends Node { - public final Node value; + public final Node value; @Override public void compileFunctions(CompileResult target) { if (value != null) value.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - if (value != null) value.compile(target, false); - if (pollute) target.add(Instruction.pushUndefined()); - } + @Override public void compile(CompileResult target, boolean pollute) { + if (value != null) value.compile(target, false); + if (pollute) target.add(Instruction.pushUndefined()); + } - public DiscardNode(Location loc, Node val) { - super(loc); - this.value = val; - } + public DiscardNode(Location loc, Node val) { + super(loc); + this.value = val; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!Parsing.isIdentifier(src, i + n, "void")) return ParseRes.failed(); - n += 4; + if (!Parsing.isIdentifier(src, i + n, "void")) return ParseRes.failed(); + n += 4; - var valRes = JavaScript.parseExpression(src, i + n, 14); - if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'void' keyword."); - n += valRes.n; + var valRes = JavaScript.parseExpression(src, i + n, 14); + if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'void' keyword."); + n += valRes.n; - return ParseRes.res(new DiscardNode(loc, valRes.result), n); - } + return ParseRes.res(new DiscardNode(loc, valRes.result), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexNode.java index d108eea..fe27f1a 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexNode.java @@ -14,141 +14,141 @@ import me.topchetoeu.jscript.compilation.values.constants.NumberNode; import me.topchetoeu.jscript.compilation.values.constants.StringNode; public class IndexNode extends Node implements ChangeTarget { - public final Node object; - public final Node index; + public final Node object; + public final Node index; @Override public void compileFunctions(CompileResult target) { object.compileFunctions(target); index.compileFunctions(target); } - @Override public void beforeAssign(CompileResult target) { - object.compile(target, true); - indexStorePushKey(target, index); - } - @Override public void beforeChange(CompileResult target) { - object.compile(target, true); + @Override public void beforeAssign(CompileResult target) { + object.compile(target, true); + indexStorePushKey(target, index); + } + @Override public void beforeChange(CompileResult target) { + object.compile(target, true); - if (index instanceof NumberNode num && (int)num.value == num.value) { - target.add(Instruction.dup()); - target.add(Instruction.loadMember((int)num.value)); - } - else if (index instanceof StringNode str) { - target.add(Instruction.dup()); - target.add(Instruction.loadMember(str.value)); - } - else { - index.compile(target, true); + if (index instanceof NumberNode num && (int)num.value == num.value) { + target.add(Instruction.dup()); + target.add(Instruction.loadMember((int)num.value)); + } + else if (index instanceof StringNode str) { + target.add(Instruction.dup()); + target.add(Instruction.loadMember(str.value)); + } + else { + index.compile(target, true); - target.add(Instruction.dup(1, 1)); - target.add(Instruction.dup(1, 1)); - target.add(Instruction.loadMember()); - } - } + target.add(Instruction.dup(1, 1)); + target.add(Instruction.dup(1, 1)); + target.add(Instruction.loadMember()); + } + } - @Override public void assign(CompileResult target, boolean pollute) { - object.compile(target, true); - target.add(Instruction.dup(1, 1)); - indexStorePushKey(target, index); - indexStore(target, index, pollute); - } + @Override public void assign(CompileResult target, boolean pollute) { + object.compile(target, true); + target.add(Instruction.dup(1, 1)); + indexStorePushKey(target, index); + indexStore(target, index, pollute); + } - @Override public void afterAssign(CompileResult target, boolean pollute) { - indexStore(target, index, pollute); - } + @Override public void afterAssign(CompileResult target, boolean pollute) { + indexStore(target, index, pollute); + } - public void compile(CompileResult target, boolean dupObj, boolean pollute) { - object.compile(target, true); - if (dupObj) target.add(Instruction.dup()); + public void compile(CompileResult target, boolean dupObj, boolean pollute) { + object.compile(target, true); + if (dupObj) target.add(Instruction.dup()); - if (index instanceof NumberNode num && (int)num.value == num.value) { - target.add(Instruction.loadMember((int)num.value)); - } - else if (index instanceof StringNode str) { - target.add(Instruction.loadMember(str.value)); - } - else { - index.compile(target, true); - target.add(Instruction.loadMember()); - } + if (index instanceof NumberNode num && (int)num.value == num.value) { + target.add(Instruction.loadMember((int)num.value)); + } + else if (index instanceof StringNode str) { + target.add(Instruction.loadMember(str.value)); + } + else { + index.compile(target, true); + target.add(Instruction.loadMember()); + } - target.setLocationAndDebug(loc(), BreakpointType.STEP_IN); + target.setLocationAndDebug(loc(), BreakpointType.STEP_IN); - if (!pollute) target.add(Instruction.discard()); - } - @Override public void compile(CompileResult target, boolean pollute) { - compile(target, false, pollute); - } + if (!pollute) target.add(Instruction.discard()); + } + @Override public void compile(CompileResult target, boolean pollute) { + compile(target, false, pollute); + } - public IndexNode(Location loc, Node object, Node index) { - super(loc); - this.object = object; - this.index = index; - } + public IndexNode(Location loc, Node object, Node index) { + super(loc); + this.object = object; + this.index = index; + } - public static ParseRes parseIndex(Source src, int i, Node prev, int precedence) { - if (precedence > 18) return ParseRes.failed(); + public static ParseRes parseIndex(Source src, int i, Node prev, int precedence) { + if (precedence > 18) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, "[")) return ParseRes.failed(); - n++; + if (!src.is(i + n, "[")) return ParseRes.failed(); + n++; - var valRes = JavaScript.parseExpression(src, i + n, 0); - if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value in index expression"); - n += valRes.n; - n += Parsing.skipEmpty(src, i + n); + var valRes = JavaScript.parseExpression(src, i + n, 0); + if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value in index expression"); + n += valRes.n; + n += Parsing.skipEmpty(src, i + n); - if (!src.is(i + n, "]")) return ParseRes.error(src.loc(i + n), "Expected a closing bracket"); - n++; + if (!src.is(i + n, "]")) return ParseRes.error(src.loc(i + n), "Expected a closing bracket"); + n++; - return ParseRes.res(new IndexNode(loc, prev, valRes.result), n); - } - public static ParseRes parseMember(Source src, int i, Node prev, int precedence) { - if (precedence > 18) return ParseRes.failed(); + return ParseRes.res(new IndexNode(loc, prev, valRes.result), n); + } + public static ParseRes parseMember(Source src, int i, Node prev, int precedence) { + if (precedence > 18) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, ".")) return ParseRes.failed(); - n++; + if (!src.is(i + n, ".")) return ParseRes.failed(); + n++; - var literal = Parsing.parseIdentifier(src, i + n); - if (!literal.isSuccess()) return literal.chainError(src.loc(i + n), "Expected an identifier after member access."); - n += literal.n; + var literal = Parsing.parseIdentifier(src, i + n); + if (!literal.isSuccess()) return literal.chainError(src.loc(i + n), "Expected an identifier after member access."); + n += literal.n; - return ParseRes.res(new IndexNode(loc, prev, new StringNode(loc, literal.result)), n); - } + return ParseRes.res(new IndexNode(loc, prev, new StringNode(loc, literal.result)), n); + } - public static void indexStorePushKey(CompileResult target, Node index) { - if (index instanceof NumberNode num && (int)num.value == num.value) return; - if (index instanceof StringNode) return; - index.compile(target, true); - } - public static void indexStore(CompileResult target, Node index, boolean pollute) { - if (index instanceof NumberNode num && (int)num.value == num.value) { - target.add(Instruction.storeMember((int)num.value, pollute)); - } - else if (index instanceof StringNode str) { - target.add(Instruction.storeMember(str.value, pollute)); - } - else { - target.add(Instruction.storeMember(pollute)); - } - } - public static void indexLoad(CompileResult target, Node index, boolean pollute) { - if (index instanceof NumberNode num && (int)num.value == num.value) { - target.add(Instruction.loadMember((int)num.value)); - } - else if (index instanceof StringNode str) { - target.add(Instruction.loadMember(str.value)); - } - else { - index.compile(target, true); - target.add(Instruction.loadMember()); - } + public static void indexStorePushKey(CompileResult target, Node index) { + if (index instanceof NumberNode num && (int)num.value == num.value) return; + if (index instanceof StringNode) return; + index.compile(target, true); + } + public static void indexStore(CompileResult target, Node index, boolean pollute) { + if (index instanceof NumberNode num && (int)num.value == num.value) { + target.add(Instruction.storeMember((int)num.value, pollute)); + } + else if (index instanceof StringNode str) { + target.add(Instruction.storeMember(str.value, pollute)); + } + else { + target.add(Instruction.storeMember(pollute)); + } + } + public static void indexLoad(CompileResult target, Node index, boolean pollute) { + if (index instanceof NumberNode num && (int)num.value == num.value) { + target.add(Instruction.loadMember((int)num.value)); + } + else if (index instanceof StringNode str) { + target.add(Instruction.loadMember(str.value)); + } + else { + index.compile(target, true); + target.add(Instruction.loadMember()); + } - if (!pollute) target.add(Instruction.discard()); - } + if (!pollute) target.add(Instruction.discard()); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/LazyAndNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/LazyAndNode.java index 152551a..58a222b 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/LazyAndNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/LazyAndNode.java @@ -10,41 +10,41 @@ import me.topchetoeu.jscript.compilation.JavaScript; import me.topchetoeu.jscript.compilation.Node; public class LazyAndNode extends Node { - public final Node first, second; + public final Node first, second; @Override public void compileFunctions(CompileResult target) { first.compileFunctions(target); second.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - first.compile(target, true); - if (pollute) target.add(Instruction.dup()); - int start = target.temp(); - if (pollute) target.add(Instruction.discard()); - second.compile(target, pollute); - target.set(start, Instruction.jmpIfNot(target.size() - start)); - } + @Override public void compile(CompileResult target, boolean pollute) { + first.compile(target, true); + if (pollute) target.add(Instruction.dup()); + int start = target.temp(); + if (pollute) target.add(Instruction.discard()); + second.compile(target, pollute); + target.set(start, Instruction.jmpIfNot(target.size() - start)); + } - public LazyAndNode(Location loc, Node first, Node second) { - super(loc); - this.first = first; - this.second = second; - } + public LazyAndNode(Location loc, Node first, Node second) { + super(loc); + this.first = first; + this.second = second; + } - public static ParseRes parse(Source src, int i, Node prev, int precedence) { - if (precedence < 4) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); + public static ParseRes parse(Source src, int i, Node prev, int precedence) { + if (precedence < 4) return ParseRes.failed(); + var n = Parsing.skipEmpty(src, i); - if (!src.is(i + n, "&&")) return ParseRes.failed(); - var loc = src.loc(i + n); - n += 2; + if (!src.is(i + n, "&&")) return ParseRes.failed(); + var loc = src.loc(i + n); + n += 2; - var res = JavaScript.parseExpression(src, i + n, 4); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected a value after the '&&' operator."); - n += res.n; + var res = JavaScript.parseExpression(src, i + n, 4); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected a value after the '&&' operator."); + n += res.n; - return ParseRes.res(new LazyAndNode(loc, prev, res.result), n); - } + return ParseRes.res(new LazyAndNode(loc, prev, res.result), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/LazyOrNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/LazyOrNode.java index f75864a..9bb0a27 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/LazyOrNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/LazyOrNode.java @@ -11,41 +11,41 @@ import me.topchetoeu.jscript.compilation.Node; public class LazyOrNode extends Node { - public final Node first, second; + public final Node first, second; @Override public void compileFunctions(CompileResult target) { first.compileFunctions(target); second.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - first.compile(target, true); - if (pollute) target.add(Instruction.dup()); - int start = target.temp(); - if (pollute) target.add(Instruction.discard()); - second.compile(target, pollute); - target.set(start, Instruction.jmpIf(target.size() - start)); - } + @Override public void compile(CompileResult target, boolean pollute) { + first.compile(target, true); + if (pollute) target.add(Instruction.dup()); + int start = target.temp(); + if (pollute) target.add(Instruction.discard()); + second.compile(target, pollute); + target.set(start, Instruction.jmpIf(target.size() - start)); + } - public LazyOrNode(Location loc, Node first, Node second) { - super(loc); - this.first = first; - this.second = second; - } + public LazyOrNode(Location loc, Node first, Node second) { + super(loc); + this.first = first; + this.second = second; + } - public static ParseRes parse(Source src, int i, Node prev, int precedence) { - if (precedence < 3) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); + public static ParseRes parse(Source src, int i, Node prev, int precedence) { + if (precedence < 3) return ParseRes.failed(); + var n = Parsing.skipEmpty(src, i); - if (!src.is(i + n, "||")) return ParseRes.failed(); - var loc = src.loc(i + n); - n += 2; + if (!src.is(i + n, "||")) return ParseRes.failed(); + var loc = src.loc(i + n); + n += 2; - var res = JavaScript.parseExpression(src, i + n, 4); - if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected a value after the '||' operator."); - n += res.n; + var res = JavaScript.parseExpression(src, i + n, 4); + if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected a value after the '||' operator."); + n += res.n; - return ParseRes.res(new LazyOrNode(loc, prev, res.result), n); - } + return ParseRes.res(new LazyOrNode(loc, prev, res.result), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/OperationNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/OperationNode.java index b9ac637..b299545 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/OperationNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/OperationNode.java @@ -18,220 +18,220 @@ import me.topchetoeu.jscript.compilation.patterns.AssignTargetLike; import me.topchetoeu.jscript.compilation.patterns.ChangeTarget; public class OperationNode extends Node { - private static interface OperatorFactory { - String token(); - int precedence(); - ParseRes construct(Source src, int i, Node prev); - } + private static interface OperatorFactory { + String token(); + int precedence(); + ParseRes construct(Source src, int i, Node prev); + } - private static class NormalOperatorFactory implements OperatorFactory { - public final String token; - public final int precedence; - public final Operation operation; + private static class NormalOperatorFactory implements OperatorFactory { + public final String token; + public final int precedence; + public final Operation operation; - @Override public int precedence() { return precedence; } - @Override public String token() { return token; } - @Override public ParseRes construct(Source src, int i, Node prev) { - var loc = src.loc(i); + @Override public int precedence() { return precedence; } + @Override public String token() { return token; } + @Override public ParseRes construct(Source src, int i, Node prev) { + var loc = src.loc(i); - var other = JavaScript.parseExpression(src, i, precedence + 1); - if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), String.format("Expected a value after '%s'", token)); - return ParseRes.res(new OperationNode(loc, operation, prev, (Node)other.result), other.n); - } + var other = JavaScript.parseExpression(src, i, precedence + 1); + if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), String.format("Expected a value after '%s'", token)); + return ParseRes.res(new OperationNode(loc, operation, prev, (Node)other.result), other.n); + } - public NormalOperatorFactory(String token, int precedence, Operation operation) { - this.token = token; - this.precedence = precedence; - this.operation = operation; - } - } - private static class AssignmentOperatorFactory implements OperatorFactory { - public final String token; - public final int precedence; - public final Operation operation; + public NormalOperatorFactory(String token, int precedence, Operation operation) { + this.token = token; + this.precedence = precedence; + this.operation = operation; + } + } + private static class AssignmentOperatorFactory implements OperatorFactory { + public final String token; + public final int precedence; + public final Operation operation; - @Override public int precedence() { return precedence; } - @Override public String token() { return token; } - @Override public ParseRes construct(Source src, int i, Node prev) { - var loc = src.loc(i); + @Override public int precedence() { return precedence; } + @Override public String token() { return token; } + @Override public ParseRes construct(Source src, int i, Node prev) { + var loc = src.loc(i); - if (operation == null) { - if (!(prev instanceof AssignTargetLike target)) return ParseRes.error(loc, String.format("Expected an assignable expression before '%s'", token)); + if (operation == null) { + if (!(prev instanceof AssignTargetLike target)) return ParseRes.error(loc, String.format("Expected an assignable expression before '%s'", token)); - var other = JavaScript.parseExpression(src, i, precedence); - if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), String.format("Expected a value after '%s'", token)); + var other = JavaScript.parseExpression(src, i, precedence); + if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), String.format("Expected a value after '%s'", token)); - return ParseRes.res(new AssignNode(loc, target.toAssignTarget(), other.result), other.n); - } - else { - if (!(prev instanceof ChangeTarget target)) return ParseRes.error(loc, String.format("Expected a changeable expression before '%s'", token)); + return ParseRes.res(new AssignNode(loc, target.toAssignTarget(), other.result), other.n); + } + else { + if (!(prev instanceof ChangeTarget target)) return ParseRes.error(loc, String.format("Expected a changeable expression before '%s'", token)); - var other = JavaScript.parseExpression(src, i, precedence); - if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), String.format("Expected a value after '%s'", token)); + var other = JavaScript.parseExpression(src, i, precedence); + if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), String.format("Expected a value after '%s'", token)); - return ParseRes.res(new ChangeNode(loc, target, other.result, operation), other.n); - } - } + return ParseRes.res(new ChangeNode(loc, target, other.result, operation), other.n); + } + } - public AssignmentOperatorFactory(String token, int precedence, Operation operation) { - this.token = token; - this.precedence = precedence; - this.operation = operation; - } - } - private static class LazyAndFactory implements OperatorFactory { - @Override public int precedence() { return 4; } - @Override public String token() { return "&&"; } - @Override public ParseRes construct(Source src, int i, Node prev) { - var loc = src.loc(i); + public AssignmentOperatorFactory(String token, int precedence, Operation operation) { + this.token = token; + this.precedence = precedence; + this.operation = operation; + } + } + private static class LazyAndFactory implements OperatorFactory { + @Override public int precedence() { return 4; } + @Override public String token() { return "&&"; } + @Override public ParseRes construct(Source src, int i, Node prev) { + var loc = src.loc(i); - var other = JavaScript.parseExpression(src, i, 5); - if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), "Expected a value after '&&'"); - return ParseRes.res(new LazyAndNode(loc, prev, (Node)other.result), other.n); - } - } - private static class LazyOrFactory implements OperatorFactory { - @Override public int precedence() { return 5; } - @Override public String token() { return "||"; } - @Override public ParseRes construct(Source src, int i, Node prev) { - var loc = src.loc(i); + var other = JavaScript.parseExpression(src, i, 5); + if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), "Expected a value after '&&'"); + return ParseRes.res(new LazyAndNode(loc, prev, (Node)other.result), other.n); + } + } + private static class LazyOrFactory implements OperatorFactory { + @Override public int precedence() { return 5; } + @Override public String token() { return "||"; } + @Override public ParseRes construct(Source src, int i, Node prev) { + var loc = src.loc(i); - var other = JavaScript.parseExpression(src, i, 6); - if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), "Expected a value after '||'"); - return ParseRes.res(new LazyOrNode(loc, prev, (Node)other.result), other.n); - } - } + var other = JavaScript.parseExpression(src, i, 6); + if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), "Expected a value after '||'"); + return ParseRes.res(new LazyOrNode(loc, prev, (Node)other.result), other.n); + } + } - public final Node[] args; - public final Operation operation; + public final Node[] args; + public final Operation operation; @Override public void compileFunctions(CompileResult target) { for (var arg : args) arg.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - for (var arg : args) { - arg.compile(target, true); - } + @Override public void compile(CompileResult target, boolean pollute) { + for (var arg : args) { + arg.compile(target, true); + } - target.add(Instruction.operation(operation)); - if (!pollute) target.add(Instruction.discard()); - } + target.add(Instruction.operation(operation)); + if (!pollute) target.add(Instruction.discard()); + } - public OperationNode(Location loc, Operation operation, Node ...args) { - super(loc); - this.operation = operation; - this.args = args; - } + public OperationNode(Location loc, Operation operation, Node ...args) { + super(loc); + this.operation = operation; + this.args = args; + } - private static final Map factories = Arrays.asList( - new NormalOperatorFactory("*", 13, Operation.MULTIPLY), - new NormalOperatorFactory("/", 12, Operation.DIVIDE), - new NormalOperatorFactory("%", 12, Operation.MODULO), - new NormalOperatorFactory("-", 11, Operation.SUBTRACT), - new NormalOperatorFactory("+", 11, Operation.ADD), - new NormalOperatorFactory(">>", 10, Operation.SHIFT_RIGHT), - new NormalOperatorFactory("<<", 10, Operation.SHIFT_LEFT), - new NormalOperatorFactory(">>>", 10, Operation.USHIFT_RIGHT), - new NormalOperatorFactory(">", 9, Operation.GREATER), - new NormalOperatorFactory("<", 9, Operation.LESS), - new NormalOperatorFactory(">=", 9, Operation.GREATER_EQUALS), - new NormalOperatorFactory("<=", 9, Operation.LESS_EQUALS), - new NormalOperatorFactory("!=", 8, Operation.LOOSE_NOT_EQUALS), - new NormalOperatorFactory("!==", 8, Operation.NOT_EQUALS), - new NormalOperatorFactory("==", 8, Operation.LOOSE_EQUALS), - new NormalOperatorFactory("===", 8, Operation.EQUALS), - new NormalOperatorFactory("&", 7, Operation.AND), - new NormalOperatorFactory("^", 6, Operation.XOR), - new NormalOperatorFactory("|", 5, Operation.OR), + private static final Map factories = Arrays.asList( + new NormalOperatorFactory("*", 13, Operation.MULTIPLY), + new NormalOperatorFactory("/", 12, Operation.DIVIDE), + new NormalOperatorFactory("%", 12, Operation.MODULO), + new NormalOperatorFactory("-", 11, Operation.SUBTRACT), + new NormalOperatorFactory("+", 11, Operation.ADD), + new NormalOperatorFactory(">>", 10, Operation.SHIFT_RIGHT), + new NormalOperatorFactory("<<", 10, Operation.SHIFT_LEFT), + new NormalOperatorFactory(">>>", 10, Operation.USHIFT_RIGHT), + new NormalOperatorFactory(">", 9, Operation.GREATER), + new NormalOperatorFactory("<", 9, Operation.LESS), + new NormalOperatorFactory(">=", 9, Operation.GREATER_EQUALS), + new NormalOperatorFactory("<=", 9, Operation.LESS_EQUALS), + new NormalOperatorFactory("!=", 8, Operation.LOOSE_NOT_EQUALS), + new NormalOperatorFactory("!==", 8, Operation.NOT_EQUALS), + new NormalOperatorFactory("==", 8, Operation.LOOSE_EQUALS), + new NormalOperatorFactory("===", 8, Operation.EQUALS), + new NormalOperatorFactory("&", 7, Operation.AND), + new NormalOperatorFactory("^", 6, Operation.XOR), + new NormalOperatorFactory("|", 5, Operation.OR), - new AssignmentOperatorFactory("=", 2, null), - new AssignmentOperatorFactory("*=", 2, Operation.MULTIPLY), - new AssignmentOperatorFactory("/=", 2, Operation.DIVIDE), - new AssignmentOperatorFactory("%=", 2, Operation.MODULO), - new AssignmentOperatorFactory("-=", 2, Operation.SUBTRACT), - new AssignmentOperatorFactory("+=", 2, Operation.ADD), - new AssignmentOperatorFactory(">>=", 2, Operation.SHIFT_RIGHT), - new AssignmentOperatorFactory("<<=", 2, Operation.SHIFT_LEFT), - new AssignmentOperatorFactory(">>>=", 2, Operation.USHIFT_RIGHT), - new AssignmentOperatorFactory("&=", 2, Operation.AND), - new AssignmentOperatorFactory("^=", 2, Operation.XOR), - new AssignmentOperatorFactory("|=", 2, Operation.OR), + new AssignmentOperatorFactory("=", 2, null), + new AssignmentOperatorFactory("*=", 2, Operation.MULTIPLY), + new AssignmentOperatorFactory("/=", 2, Operation.DIVIDE), + new AssignmentOperatorFactory("%=", 2, Operation.MODULO), + new AssignmentOperatorFactory("-=", 2, Operation.SUBTRACT), + new AssignmentOperatorFactory("+=", 2, Operation.ADD), + new AssignmentOperatorFactory(">>=", 2, Operation.SHIFT_RIGHT), + new AssignmentOperatorFactory("<<=", 2, Operation.SHIFT_LEFT), + new AssignmentOperatorFactory(">>>=", 2, Operation.USHIFT_RIGHT), + new AssignmentOperatorFactory("&=", 2, Operation.AND), + new AssignmentOperatorFactory("^=", 2, Operation.XOR), + new AssignmentOperatorFactory("|=", 2, Operation.OR), - new LazyAndFactory(), - new LazyOrFactory() - ).stream().collect(Collectors.toMap(v -> v.token(), v -> v)); + new LazyAndFactory(), + new LazyOrFactory() + ).stream().collect(Collectors.toMap(v -> v.token(), v -> v)); - private static final List operatorsByLength = factories.keySet().stream().sorted((a, b) -> -a.compareTo(b)).collect(Collectors.toList()); + private static final List operatorsByLength = factories.keySet().stream().sorted((a, b) -> -a.compareTo(b)).collect(Collectors.toList()); - public static ParseRes parsePrefix(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parsePrefix(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - Operation operation = null; - String op; + Operation operation = null; + String op; - if (src.is(i + n, op = "+")) operation = Operation.POS; - else if (src.is(i + n, op = "-")) operation = Operation.NEG; - else if (src.is(i + n, op = "~")) operation = Operation.INVERSE; - else if (src.is(i + n, op = "!")) operation = Operation.NOT; - else return ParseRes.failed(); + if (src.is(i + n, op = "+")) operation = Operation.POS; + else if (src.is(i + n, op = "-")) operation = Operation.NEG; + else if (src.is(i + n, op = "~")) operation = Operation.INVERSE; + else if (src.is(i + n, op = "!")) operation = Operation.NOT; + else return ParseRes.failed(); - n++; + n++; - var res = JavaScript.parseExpression(src, i + n, 14); + var res = JavaScript.parseExpression(src, i + n, 14); - if (res.isSuccess()) return ParseRes.res(new OperationNode(loc, operation, res.result), n + res.n); - else return res.chainError(src.loc(i + n), String.format("Expected a value after the unary operator '%s'.", op)); - } - public static ParseRes parseInstanceof(Source src, int i, Node prev, int precedence) { - if (precedence > 9) return ParseRes.failed(); + if (res.isSuccess()) return ParseRes.res(new OperationNode(loc, operation, res.result), n + res.n); + else return res.chainError(src.loc(i + n), String.format("Expected a value after the unary operator '%s'.", op)); + } + public static ParseRes parseInstanceof(Source src, int i, Node prev, int precedence) { + if (precedence > 9) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var kw = Parsing.parseIdentifier(src, i + n, "instanceof"); - if (!kw.isSuccess()) return kw.chainError(); - n += kw.n; + var kw = Parsing.parseIdentifier(src, i + n, "instanceof"); + if (!kw.isSuccess()) return kw.chainError(); + n += kw.n; - var valRes = JavaScript.parseExpression(src, i + n, 10); - if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'instanceof'."); - n += valRes.n; + var valRes = JavaScript.parseExpression(src, i + n, 10); + if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'instanceof'."); + n += valRes.n; - return ParseRes.res(new OperationNode(loc, Operation.INSTANCEOF, prev, valRes.result), n); - } - public static ParseRes parseIn(Source src, int i, Node prev, int precedence) { - if (precedence > 9) return ParseRes.failed(); + return ParseRes.res(new OperationNode(loc, Operation.INSTANCEOF, prev, valRes.result), n); + } + public static ParseRes parseIn(Source src, int i, Node prev, int precedence) { + if (precedence > 9) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - var kw = Parsing.parseIdentifier(src, i + n, "in"); - if (!kw.isSuccess()) return kw.chainError(); - n += kw.n; + var kw = Parsing.parseIdentifier(src, i + n, "in"); + if (!kw.isSuccess()) return kw.chainError(); + n += kw.n; - var valRes = JavaScript.parseExpression(src, i + n, 10); - if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'in'."); - n += valRes.n; + var valRes = JavaScript.parseExpression(src, i + n, 10); + if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'in'."); + n += valRes.n; - return ParseRes.res(new OperationNode(loc, Operation.IN, valRes.result, prev), n); - } - public static ParseRes parseOperator(Source src, int i, Node prev, int precedence) { - var n = Parsing.skipEmpty(src, i); + return ParseRes.res(new OperationNode(loc, Operation.IN, valRes.result, prev), n); + } + public static ParseRes parseOperator(Source src, int i, Node prev, int precedence) { + var n = Parsing.skipEmpty(src, i); - for (var token : operatorsByLength) { - var factory = factories.get(token); + for (var token : operatorsByLength) { + var factory = factories.get(token); - if (!src.is(i + n, token)) continue; - if (factory.precedence() < precedence) return ParseRes.failed(); + if (!src.is(i + n, token)) continue; + if (factory.precedence() < precedence) return ParseRes.failed(); - n += token.length(); - n += Parsing.skipEmpty(src, i + n); + n += token.length(); + n += Parsing.skipEmpty(src, i + n); - var res = factory.construct(src, i + n, prev); - return res.addN(n); - } + var res = factory.construct(src, i + n, prev); + return res.addN(n); + } - return ParseRes.failed(); - } + return ParseRes.failed(); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/PostfixNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/PostfixNode.java index 492b581..99e86a5 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/PostfixNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/PostfixNode.java @@ -16,41 +16,41 @@ public class PostfixNode extends ChangeNode { ((Node)changable).compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - super.compile(target, pollute); + @Override public void compile(CompileResult target, boolean pollute) { + super.compile(target, pollute); - if (pollute) { - value.compile(target, true); - target.add(Instruction.operation(Operation.ADD)); - } - } + if (pollute) { + value.compile(target, true); + target.add(Instruction.operation(Operation.ADD)); + } + } - public PostfixNode(Location loc, ChangeTarget value, double addAmount) { - super(loc, value, new NumberNode(loc, -addAmount), Operation.SUBTRACT); - } + public PostfixNode(Location loc, ChangeTarget value, double addAmount) { + super(loc, value, new NumberNode(loc, -addAmount), Operation.SUBTRACT); + } - public static ParseRes parsePostfixIncrease(Source src, int i, Node prev, int precedence) { - if (precedence > 15) return ParseRes.failed(); + public static ParseRes parsePostfixIncrease(Source src, int i, Node prev, int precedence) { + if (precedence > 15) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, "++")) return ParseRes.failed(); - if (!(prev instanceof ChangeTarget)) return ParseRes.error(src.loc(i + n), "Expected assignable value before suffix operator."); - n += 2; + if (!src.is(i + n, "++")) return ParseRes.failed(); + if (!(prev instanceof ChangeTarget)) return ParseRes.error(src.loc(i + n), "Expected assignable value before suffix operator."); + n += 2; - return ParseRes.res(new PostfixNode(loc, (ChangeTarget)prev, 1), n); - } - public static ParseRes parsePostfixDecrease(Source src, int i, Node prev, int precedence) { - if (precedence > 15) return ParseRes.failed(); + return ParseRes.res(new PostfixNode(loc, (ChangeTarget)prev, 1), n); + } + public static ParseRes parsePostfixDecrease(Source src, int i, Node prev, int precedence) { + if (precedence > 15) return ParseRes.failed(); - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!src.is(i + n, "--")) return ParseRes.failed(); - if (!(prev instanceof ChangeTarget)) return ParseRes.error(src.loc(i + n), "Expected assignable value before suffix operator."); - n += 2; + if (!src.is(i + n, "--")) return ParseRes.failed(); + if (!(prev instanceof ChangeTarget)) return ParseRes.error(src.loc(i + n), "Expected assignable value before suffix operator."); + n += 2; - return ParseRes.res(new PostfixNode(loc, (ChangeTarget)prev, -1), n); - } + return ParseRes.res(new PostfixNode(loc, (ChangeTarget)prev, -1), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/TypeofNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/TypeofNode.java index 68683dd..8fea97b 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/TypeofNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/TypeofNode.java @@ -12,41 +12,41 @@ import me.topchetoeu.jscript.compilation.Node; import me.topchetoeu.jscript.compilation.values.VariableNode; public class TypeofNode extends Node { - public final Node value; + public final Node value; @Override public void compileFunctions(CompileResult target) { value.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - if (value instanceof VariableNode varNode) { - target.add(VariableNode.toGet(target, varNode.loc(), varNode.name, true, true)); - if (pollute) target.add(Instruction.typeof()); - else target.add(Instruction.discard()); + @Override public void compile(CompileResult target, boolean pollute) { + if (value instanceof VariableNode varNode) { + target.add(VariableNode.toGet(target, varNode.loc(), varNode.name, true, true)); + if (pollute) target.add(Instruction.typeof()); + else target.add(Instruction.discard()); - return; - } + return; + } - value.compile(target, pollute); - if (pollute) target.add(Instruction.typeof()); - } + value.compile(target, pollute); + if (pollute) target.add(Instruction.typeof()); + } - public TypeofNode(Location loc, Node value) { - super(loc); - this.value = value; - } + public TypeofNode(Location loc, Node value) { + super(loc); + this.value = value; + } - public static ParseRes parse(Source src, int i) { - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); + public static ParseRes parse(Source src, int i) { + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); - if (!Parsing.isIdentifier(src, i + n, "typeof")) return ParseRes.failed(); - n += 6; + if (!Parsing.isIdentifier(src, i + n, "typeof")) return ParseRes.failed(); + n += 6; - var valRes = JavaScript.parseExpression(src, i + n, 15); - if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'typeof' keyword."); - n += valRes.n; - - return ParseRes.res(new TypeofNode(loc, valRes.result), n); - } + var valRes = JavaScript.parseExpression(src, i + n, 15); + if (!valRes.isSuccess()) return valRes.chainError(src.loc(i + n), "Expected a value after 'typeof' keyword."); + n += valRes.n; + + return ParseRes.res(new TypeofNode(loc, valRes.result), n); + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/VariableAssignNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/VariableAssignNode.java index 7474a0e..ff923d2 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/VariableAssignNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/VariableAssignNode.java @@ -9,31 +9,31 @@ import me.topchetoeu.jscript.compilation.Node; import me.topchetoeu.jscript.compilation.values.VariableNode; public class VariableAssignNode extends Node { - public final String name; - public final Node value; - public final Operation operation; + public final String name; + public final Node value; + public final Operation operation; @Override public void compileFunctions(CompileResult target) { value.compileFunctions(target); } - @Override public void compile(CompileResult target, boolean pollute) { - if (operation != null) { - target.add(VariableNode.toGet(target, loc(), name)); - FunctionNode.compileWithName(value, target, true, name); - target.add(Instruction.operation(operation)); - target.add(VariableNode.toSet(target, loc(), name, pollute, false)).setLocation(loc()); - } - else { - FunctionNode.compileWithName(value, target, true, name); - target.add(VariableNode.toSet(target, loc(), name, pollute, false)).setLocation(loc()); - } - } + @Override public void compile(CompileResult target, boolean pollute) { + if (operation != null) { + target.add(VariableNode.toGet(target, loc(), name)); + FunctionNode.compileWithName(value, target, true, name); + target.add(Instruction.operation(operation)); + target.add(VariableNode.toSet(target, loc(), name, pollute, false)).setLocation(loc()); + } + else { + FunctionNode.compileWithName(value, target, true, name); + target.add(VariableNode.toSet(target, loc(), name, pollute, false)).setLocation(loc()); + } + } - public VariableAssignNode(Location loc, String name, Node val, Operation operation) { - super(loc); - this.name = name; - this.value = val; - this.operation = operation; - } + public VariableAssignNode(Location loc, String name, Node val, Operation operation) { + super(loc); + this.name = name; + this.value = val; + this.operation = operation; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/ArgumentsValue.java b/src/main/java/me/topchetoeu/jscript/runtime/ArgumentsValue.java index df5a7e3..d475b00 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/ArgumentsValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/ArgumentsValue.java @@ -4,10 +4,10 @@ import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.objects.ArrayValue; public class ArgumentsValue extends ArrayValue { - public final Frame frame; + public final Frame frame; - public ArgumentsValue(Frame frame, Value... args) { - super(args); - this.frame = frame; - } + public ArgumentsValue(Frame frame, Value... args) { + super(args); + this.frame = frame; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/Compiler.java b/src/main/java/me/topchetoeu/jscript/runtime/Compiler.java index 42266dc..ccc130c 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/Compiler.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/Compiler.java @@ -13,42 +13,42 @@ import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.functions.CodeFunction; public interface Compiler { - public static final Compiler DEFAULT = (env, filename, raw) -> { - try { - var res = JavaScript.compile(env, filename, raw); - var body = res.body(); - DebugContext.get(env).onSource(filename, raw); - registerFunc(env, body, res); - return body; - } - catch (SyntaxException e) { - var res = EngineException.ofSyntax(e.msg); - res.add(env, e.loc.filename() + "", e.loc); - throw res; - } - }; + public static final Compiler DEFAULT = (env, filename, raw) -> { + try { + var res = JavaScript.compile(env, filename, raw); + var body = res.body(); + DebugContext.get(env).onSource(filename, raw); + registerFunc(env, body, res); + return body; + } + catch (SyntaxException e) { + var res = EngineException.ofSyntax(e.msg); + res.add(env, e.loc.filename() + "", e.loc); + throw res; + } + }; - public Key KEY = Key.of(); + public Key KEY = new Key<>(); - public FunctionBody compile(Environment env, Filename filename, String source); + public FunctionBody compile(Environment env, Filename filename, String source); - public static Compiler get(Environment ext) { - return ext.get(KEY, (env, filename, src) -> { - throw EngineException.ofError("No compiler attached to engine"); - }); - } + public static Compiler get(Environment ext) { + return ext.get(KEY, (env, filename, src) -> { + throw EngineException.ofError("No compiler attached to engine"); + }); + } - static void registerFunc(Environment env, FunctionBody body, CompileResult res) { - var map = res.map(); + static void registerFunc(Environment env, FunctionBody body, CompileResult res) { + var map = res.map(); - DebugContext.get(env).onFunctionLoad(body, map); + DebugContext.get(env).onFunctionLoad(body, map); - for (var i = 0; i < body.children.length; i++) { - registerFunc(env, body.children[i], res.children.get(i)); - } - } + for (var i = 0; i < body.children.length; i++) { + registerFunc(env, body.children[i], res.children.get(i)); + } + } - public static CodeFunction compileFunc(Environment env, Filename filename, String raw) { - return new CodeFunction(env, filename.toString(), get(env).compile(env, filename, raw), new Value[0][]); - } + public static CodeFunction compileFunc(Environment env, Filename filename, String raw) { + return new CodeFunction(env, filename.toString(), get(env).compile(env, filename, raw), new Value[0][]); + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/Engine.java b/src/main/java/me/topchetoeu/jscript/runtime/Engine.java index 244b4b9..736b7fc 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/Engine.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/Engine.java @@ -7,68 +7,68 @@ import java.util.concurrent.PriorityBlockingQueue; import java.util.function.Supplier; public final class Engine implements EventLoop { - private static class Task implements Comparable> { - public final Supplier runnable; - public final CompletableFuture notifier = new CompletableFuture(); - public final boolean micro; + private static class Task implements Comparable> { + public final Supplier runnable; + public final CompletableFuture notifier = new CompletableFuture(); + public final boolean micro; - public Task(Supplier runnable, boolean micro) { - this.runnable = runnable; - this.micro = micro; - } + public Task(Supplier runnable, boolean micro) { + this.runnable = runnable; + this.micro = micro; + } - @Override public int compareTo(Task other) { - return Integer.compare(this.micro ? 0 : 1, other.micro ? 0 : 1); - } - } + @Override public int compareTo(Task other) { + return Integer.compare(this.micro ? 0 : 1, other.micro ? 0 : 1); + } + } - private PriorityBlockingQueue> tasks = new PriorityBlockingQueue<>(); - private Thread thread; + private PriorityBlockingQueue> tasks = new PriorityBlockingQueue<>(); + private Thread thread; - @Override public Future pushMsg(Supplier runnable, boolean micro) { - var msg = new Task(runnable, micro); - tasks.add(msg); - return msg.notifier; - } + @Override public Future pushMsg(Supplier runnable, boolean micro) { + var msg = new Task(runnable, micro); + tasks.add(msg); + return msg.notifier; + } - @SuppressWarnings("unchecked") - public void run(boolean untilEmpty) { - while (!untilEmpty || !tasks.isEmpty()) { - try { - var task = tasks.take(); + @SuppressWarnings("unchecked") + public void run(boolean untilEmpty) { + while (!untilEmpty || !tasks.isEmpty()) { + try { + var task = tasks.take(); - try { - ((Task)task).notifier.complete(task.runnable.get()); - } - catch (CancellationException e) { throw e; } - catch (RuntimeException e) { task.notifier.completeExceptionally(e); } - } - catch (InterruptedException | CancellationException e) { - for (var msg : tasks) msg.notifier.cancel(false); - break; - } - } - } + try { + ((Task)task).notifier.complete(task.runnable.get()); + } + catch (CancellationException e) { throw e; } + catch (RuntimeException e) { task.notifier.completeExceptionally(e); } + } + catch (InterruptedException | CancellationException e) { + for (var msg : tasks) msg.notifier.cancel(false); + break; + } + } + } - public Thread thread() { - return thread; - } - public Thread start() { - if (thread == null) { - thread = new Thread(() -> run(false), "Event loop #" + hashCode()); - thread.start(); - } - return thread; - } - public void stop() { - if (thread != null) thread.interrupt(); - thread = null; - } + public Thread thread() { + return thread; + } + public Thread start() { + if (thread == null) { + thread = new Thread(() -> run(false), "Event loop #" + hashCode()); + thread.start(); + } + return thread; + } + public void stop() { + if (thread != null) thread.interrupt(); + thread = null; + } - public boolean inLoopThread() { - return Thread.currentThread() == thread; - } - public boolean isRunning() { - return this.thread != null; - } + public boolean inLoopThread() { + return Thread.currentThread() == thread; + } + public boolean isRunning() { + return this.thread != null; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/EventLoop.java b/src/main/java/me/topchetoeu/jscript/runtime/EventLoop.java index 6126684..b5abc9a 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/EventLoop.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/EventLoop.java @@ -11,26 +11,26 @@ import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.functions.FunctionValue; public interface EventLoop { - public static final Key KEY = Key.of(); + public static final Key KEY = new Key<>(); - public static EventLoop get(Environment ext) { - if (ext.hasNotNull(KEY)) return ext.get(KEY); - else return new EventLoop() { - @Override public Future pushMsg(Supplier runnable, boolean micro) { - throw EngineException.ofError("No event loop attached to environment."); - } - }; - } + public static EventLoop get(Environment ext) { + if (ext.hasNotNull(KEY)) return ext.get(KEY); + else return new EventLoop() { + @Override public Future pushMsg(Supplier runnable, boolean micro) { + throw EngineException.ofError("No event loop attached to environment."); + } + }; + } - public Future pushMsg(Supplier runnable, boolean micro); - public default Future pushMsg(Runnable runnable, boolean micro) { - return pushMsg(() -> { runnable.run(); return null; }, micro); - } + public Future pushMsg(Supplier runnable, boolean micro); + public default Future pushMsg(Runnable runnable, boolean micro) { + return pushMsg(() -> { runnable.run(); return null; }, micro); + } - public default Future pushMsg(boolean micro, Environment env, FunctionValue func, Value thisArg, Value ...args) { - return pushMsg(() -> func.apply(env, thisArg, args), micro); - } - public default Future pushMsg(boolean micro, Environment env, Filename filename, String raw, Value thisArg, Value ...args) { - return pushMsg(() -> Compiler.compileFunc(env, filename, raw).apply(env, thisArg, args), micro); - } + public default Future pushMsg(boolean micro, Environment env, FunctionValue func, Value thisArg, Value ...args) { + return pushMsg(() -> func.apply(env, thisArg, args), micro); + } + public default Future pushMsg(boolean micro, Environment env, Filename filename, String raw, Value thisArg, Value ...args) { + return pushMsg(() -> Compiler.compileFunc(env, filename, raw).apply(env, thisArg, args), micro); + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/Frame.java b/src/main/java/me/topchetoeu/jscript/runtime/Frame.java index 62ef129..cf22b35 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/Frame.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/Frame.java @@ -16,371 +16,371 @@ import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.IntValue; public final class Frame { - public static final Key KEY = Key.of(); - public static final EngineException STACK_OVERFLOW; - static { - STACK_OVERFLOW = EngineException.ofRange("Stack overflow!"); - STACK_OVERFLOW.value.freeze(); - } + public static final Key KEY = new Key<>(); + public static final EngineException STACK_OVERFLOW; + static { + STACK_OVERFLOW = EngineException.ofRange("Stack overflow!"); + STACK_OVERFLOW.value.freeze(); + } - public static enum TryState { - TRY, - CATCH, - FINALLY, - } + public static enum TryState { + TRY, + CATCH, + FINALLY, + } - public static class TryCtx { - public final int start, end, catchStart, finallyStart; - public final int restoreStackPtr; - public final TryState state; - public final EngineException error; - public final PendingResult result; + public static class TryCtx { + public final int start, end, catchStart, finallyStart; + public final int restoreStackPtr; + public final TryState state; + public final EngineException error; + public final PendingResult result; - public boolean hasCatch() { return catchStart >= 0; } - public boolean hasFinally() { return finallyStart >= 0; } + public boolean hasCatch() { return catchStart >= 0; } + public boolean hasFinally() { return finallyStart >= 0; } - public boolean inBounds(int ptr) { - return ptr >= start && ptr < end; - } + public boolean inBounds(int ptr) { + return ptr >= start && ptr < end; + } - public void setCause(EngineException target) { - if (error != null) target.setCause(error); - } - public TryCtx _catch(EngineException e) { - return new TryCtx(TryState.CATCH, e, result, restoreStackPtr, start, end, -1, finallyStart); - } - public TryCtx _finally(PendingResult res) { - return new TryCtx(TryState.FINALLY, error, res, restoreStackPtr, start, end, -1, -1); - } + public void setCause(EngineException target) { + if (error != null) target.setCause(error); + } + public TryCtx _catch(EngineException e) { + return new TryCtx(TryState.CATCH, e, result, restoreStackPtr, start, end, -1, finallyStart); + } + public TryCtx _finally(PendingResult res) { + return new TryCtx(TryState.FINALLY, error, res, restoreStackPtr, start, end, -1, -1); + } - public TryCtx(TryState state, EngineException err, PendingResult res, int stackPtr, int start, int end, int catchStart, int finallyStart) { - this.catchStart = catchStart; - this.finallyStart = finallyStart; - this.restoreStackPtr = stackPtr; - this.result = res == null ? PendingResult.ofNone() : res; - this.state = state; - this.start = start; - this.end = end; - this.error = err; - } - } + public TryCtx(TryState state, EngineException err, PendingResult res, int stackPtr, int start, int end, int catchStart, int finallyStart) { + this.catchStart = catchStart; + this.finallyStart = finallyStart; + this.restoreStackPtr = stackPtr; + this.result = res == null ? PendingResult.ofNone() : res; + this.state = state; + this.start = start; + this.end = end; + this.error = err; + } + } - private static class PendingResult { - public final boolean isReturn, isJump, isThrow; - public final Value value; - public final EngineException error; - public final int ptr; - public final Instruction instruction; + private static class PendingResult { + public final boolean isReturn, isJump, isThrow; + public final Value value; + public final EngineException error; + public final int ptr; + public final Instruction instruction; - private PendingResult(Instruction instr, boolean isReturn, boolean isJump, boolean isThrow, Value value, EngineException error, int ptr) { - this.instruction = instr; - this.isReturn = isReturn; - this.isJump = isJump; - this.isThrow = isThrow; - this.value = value; - this.error = error; - this.ptr = ptr; - } + private PendingResult(Instruction instr, boolean isReturn, boolean isJump, boolean isThrow, Value value, EngineException error, int ptr) { + this.instruction = instr; + this.isReturn = isReturn; + this.isJump = isJump; + this.isThrow = isThrow; + this.value = value; + this.error = error; + this.ptr = ptr; + } - public static PendingResult ofNone() { - return new PendingResult(null, false, false, false, null, null, 0); - } - public static PendingResult ofReturn(Value value, Instruction instr) { - return new PendingResult(instr, true, false, false, value, null, 0); - } - public static PendingResult ofThrow(EngineException error, Instruction instr) { - return new PendingResult(instr, false, false, true, null, error, 0); - } - public static PendingResult ofJump(int codePtr, Instruction instr) { - return new PendingResult(instr, false, true, false, null, null, codePtr); - } - } + public static PendingResult ofNone() { + return new PendingResult(null, false, false, false, null, null, 0); + } + public static PendingResult ofReturn(Value value, Instruction instr) { + return new PendingResult(instr, true, false, false, value, null, 0); + } + public static PendingResult ofThrow(EngineException error, Instruction instr) { + return new PendingResult(instr, false, false, true, null, error, 0); + } + public static PendingResult ofJump(int codePtr, Instruction instr) { + return new PendingResult(instr, false, true, false, null, null, codePtr); + } + } - /** - * An array of captures from the parent function - */ - public final Value[][] captures; + /** + * An array of captures from the parent function + */ + public final Value[][] captures; /** * An array of non-capture variables */ - public final Value[] locals; + public final Value[] locals; /** * An array of children-captured variables */ - public final Value[][] capturables; + public final Value[][] capturables; public final Value self; - public final Value[] args; - public final Value argsVal; + public final Value[] args; + public final Value argsVal; public final Value argsLen; public final boolean isNew; public final Stack tryStack = new Stack<>(); - public final CodeFunction function; - public final Environment env; - private final DebugContext dbg; + public final CodeFunction function; + public final Environment env; + private final DebugContext dbg; - public Value getVar(int i) { - if (i < 0) return captures[~i][0]; - else if (i < locals.length) return locals[i]; - else return capturables[i - locals.length][0]; - } - public Value setVar(int i, Value val) { - if (i < 0) return captures[~i][0] = val; - else if (i < locals.length) return locals[i] = val; - else return capturables[i - locals.length][0] = val; - } - public Value[] captureVar(int i) { - if (i < 0) return captures[~i]; - if (i >= locals.length) return capturables[i - locals.length]; - else throw new RuntimeException("Illegal capture"); - } + public Value getVar(int i) { + if (i < 0) return captures[~i][0]; + else if (i < locals.length) return locals[i]; + else return capturables[i - locals.length][0]; + } + public Value setVar(int i, Value val) { + if (i < 0) return captures[~i][0] = val; + else if (i < locals.length) return locals[i] = val; + else return capturables[i - locals.length][0] = val; + } + public Value[] captureVar(int i) { + if (i < 0) return captures[~i]; + if (i >= locals.length) return capturables[i - locals.length]; + else throw new RuntimeException("Illegal capture"); + } - public Value[] stack = new Value[32]; - public int stackPtr = 0; - public int codePtr = 0; - public boolean jumpFlag = false; - public boolean popTryFlag = false; + public Value[] stack = new Value[32]; + public int stackPtr = 0; + public int codePtr = 0; + public boolean jumpFlag = false; + public boolean popTryFlag = false; - public void addTry(int start, int end, int catchStart, int finallyStart) { - var err = tryStack.empty() ? null : tryStack.peek().error; - var res = new TryCtx(TryState.TRY, err, null, stackPtr, start, end, catchStart, finallyStart); + public void addTry(int start, int end, int catchStart, int finallyStart) { + var err = tryStack.empty() ? null : tryStack.peek().error; + var res = new TryCtx(TryState.TRY, err, null, stackPtr, start, end, catchStart, finallyStart); - tryStack.add(res); - } + tryStack.add(res); + } - public Value peek() { - return peek(0); - } - public Value peek(int offset) { - return stack[stackPtr - 1 - offset]; - } - public Value pop() { - return stack[--stackPtr]; - } - public Value[] take(int n) { - Value[] res = new Value[n]; - System.arraycopy(stack, stackPtr - n, res, 0, n); - stackPtr -= n; + public Value peek() { + return peek(0); + } + public Value peek(int offset) { + return stack[stackPtr - 1 - offset]; + } + public Value pop() { + return stack[--stackPtr]; + } + public Value[] take(int n) { + Value[] res = new Value[n]; + System.arraycopy(stack, stackPtr - n, res, 0, n); + stackPtr -= n; - return res; - } - public void push(Value val) { - if (stack.length <= stackPtr) { - var newStack = new Value[stack.length * 2]; - System.arraycopy(stack, 0, newStack, 0, stack.length); - stack = newStack; - } + return res; + } + public void push(Value val) { + if (stack.length <= stackPtr) { + var newStack = new Value[stack.length * 2]; + System.arraycopy(stack, 0, newStack, 0, stack.length); + stack = newStack; + } - stack[stackPtr++] = val; - } - public void replace(Value val) { - stack[stackPtr - 1] = val; - } + stack[stackPtr++] = val; + } + public void replace(Value val) { + stack[stackPtr - 1] = val; + } - // for the love of christ don't touch this - /** - * This is provided only for optimization-sike. All parameters must be null except at most one, otherwise undefined behavior - */ - public final Value next(Value value, Value returnValue, EngineException error) { - if (value != null) push(value); + // for the love of christ don't touch this + /** + * This is provided only for optimization-sike. All parameters must be null except at most one, otherwise undefined behavior + */ + public final Value next(Value value, Value returnValue, EngineException error) { + if (value != null) push(value); - Instruction instr = null; - if (codePtr != function.body.instructions.length) instr = function.body.instructions[codePtr]; + Instruction instr = null; + if (codePtr != function.body.instructions.length) instr = function.body.instructions[codePtr]; - if (returnValue == null && error == null) { - try { - if (Thread.interrupted()) throw new CancellationException(); + if (returnValue == null && error == null) { + try { + if (Thread.interrupted()) throw new CancellationException(); - if (instr == null) { - if (stackPtr > 0) returnValue = stack[stackPtr - 1]; - else returnValue = Value.UNDEFINED; - } - else { - dbg.onInstruction(env, this, instr); + if (instr == null) { + if (stackPtr > 0) returnValue = stack[stackPtr - 1]; + else returnValue = Value.UNDEFINED; + } + else { + dbg.onInstruction(env, this, instr); - try { - this.jumpFlag = this.popTryFlag = false; - returnValue = InstructionRunner.exec(env, instr, this); - } - catch (EngineException e) { - error = e.add(env, function.name, dbg.getMapOrEmpty(function).toLocation(codePtr, true)); - } - } - } - catch (StackOverflowError e) { throw STACK_OVERFLOW; } - catch (EngineException e) { error = e; } - catch (RuntimeException e) { - System.out.println(dbg.getMapOrEmpty(function).toLocation(codePtr, true)); - throw e; - } - } + try { + this.jumpFlag = this.popTryFlag = false; + returnValue = InstructionRunner.exec(env, instr, this); + } + catch (EngineException e) { + error = e.add(env, function.name, dbg.getMapOrEmpty(function).toLocation(codePtr, true)); + } + } + } + catch (StackOverflowError e) { throw STACK_OVERFLOW; } + catch (EngineException e) { error = e; } + catch (RuntimeException e) { + System.out.println(dbg.getMapOrEmpty(function).toLocation(codePtr, true)); + throw e; + } + } - while (!tryStack.empty()) { - var tryCtx = tryStack.peek(); - TryCtx newCtx = null; + while (!tryStack.empty()) { + var tryCtx = tryStack.peek(); + TryCtx newCtx = null; - if (error != null) { - tryCtx.setCause(error); - if (tryCtx.hasCatch()) newCtx = tryCtx._catch(error); - else if (tryCtx.hasFinally()) newCtx = tryCtx._finally(PendingResult.ofThrow(error, instr)); - } - else if (returnValue != null) { - if (tryCtx.hasFinally()) newCtx = tryCtx._finally(PendingResult.ofReturn(returnValue, instr)); - } - else if (jumpFlag && !tryCtx.inBounds(codePtr)) { - if (tryCtx.hasFinally()) newCtx = tryCtx._finally(PendingResult.ofJump(codePtr, instr)); - } - else if (!this.popTryFlag) newCtx = tryCtx; + if (error != null) { + tryCtx.setCause(error); + if (tryCtx.hasCatch()) newCtx = tryCtx._catch(error); + else if (tryCtx.hasFinally()) newCtx = tryCtx._finally(PendingResult.ofThrow(error, instr)); + } + else if (returnValue != null) { + if (tryCtx.hasFinally()) newCtx = tryCtx._finally(PendingResult.ofReturn(returnValue, instr)); + } + else if (jumpFlag && !tryCtx.inBounds(codePtr)) { + if (tryCtx.hasFinally()) newCtx = tryCtx._finally(PendingResult.ofJump(codePtr, instr)); + } + else if (!this.popTryFlag) newCtx = tryCtx; - if (newCtx != null) { - if (newCtx != tryCtx) { - switch (newCtx.state) { - case CATCH: - codePtr = tryCtx.catchStart; - stackPtr = tryCtx.restoreStackPtr; - break; - case FINALLY: - codePtr = tryCtx.finallyStart; - stackPtr = tryCtx.restoreStackPtr; - default: - } + if (newCtx != null) { + if (newCtx != tryCtx) { + switch (newCtx.state) { + case CATCH: + codePtr = tryCtx.catchStart; + stackPtr = tryCtx.restoreStackPtr; + break; + case FINALLY: + codePtr = tryCtx.finallyStart; + stackPtr = tryCtx.restoreStackPtr; + default: + } - tryStack.pop(); - tryStack.push(newCtx); - } + tryStack.pop(); + tryStack.push(newCtx); + } - error = null; - returnValue = null; - break; - } - else { - popTryFlag = false; + error = null; + returnValue = null; + break; + } + else { + popTryFlag = false; - if (tryCtx.state != TryState.FINALLY && tryCtx.hasFinally()) { - codePtr = tryCtx.finallyStart; - stackPtr = tryCtx.restoreStackPtr; - tryStack.pop(); - tryStack.push(tryCtx._finally(null)); - break; - } - else { - tryStack.pop(); - codePtr = tryCtx.end; - if (tryCtx.result.instruction != null) instr = tryCtx.result.instruction; - if (!jumpFlag && returnValue == null && error == null) { - if (tryCtx.result.isJump) { - codePtr = tryCtx.result.ptr; - jumpFlag = true; - } - if (tryCtx.result.isReturn) returnValue = tryCtx.result.value; - if (error == null && tryCtx.result.isThrow) { - error = tryCtx.result.error; - } - } - if (error != null) tryCtx.setCause(error); - continue; - } - } - } + if (tryCtx.state != TryState.FINALLY && tryCtx.hasFinally()) { + codePtr = tryCtx.finallyStart; + stackPtr = tryCtx.restoreStackPtr; + tryStack.pop(); + tryStack.push(tryCtx._finally(null)); + break; + } + else { + tryStack.pop(); + codePtr = tryCtx.end; + if (tryCtx.result.instruction != null) instr = tryCtx.result.instruction; + if (!jumpFlag && returnValue == null && error == null) { + if (tryCtx.result.isJump) { + codePtr = tryCtx.result.ptr; + jumpFlag = true; + } + if (tryCtx.result.isReturn) returnValue = tryCtx.result.value; + if (error == null && tryCtx.result.isThrow) { + error = tryCtx.result.error; + } + } + if (error != null) tryCtx.setCause(error); + continue; + } + } + } - if (returnValue != null) { - dbg.onInstruction(env, this, instr, returnValue, null, false); - return returnValue; - } - if (error != null) { - var caught = false; + if (returnValue != null) { + dbg.onInstruction(env, this, instr, returnValue, null, false); + return returnValue; + } + if (error != null) { + var caught = false; - for (var frame : dbg.getStackFrames()) { - for (var tryCtx : frame.tryStack) { - if (tryCtx.state == TryState.TRY) caught = true; - } - } + for (var frame : dbg.getStackFrames()) { + for (var tryCtx : frame.tryStack) { + if (tryCtx.state == TryState.TRY) caught = true; + } + } - dbg.onInstruction(env, this, instr, null, error, caught); - throw error; - } + dbg.onInstruction(env, this, instr, null, error, caught); + throw error; + } - return null; - } + return null; + } - /** - * Executes the next instruction in the frame - */ - public final Value next() { - return next(null, null, null); - } - /** - * Induces a value on the stack (as if it were returned by the last function call) - * and executes the next instruction in the frame. - * - * @param value The value to induce - */ - public final Value next(Value value) { - return next(value, null, null); - } - /** - * Induces a thrown error and executes the next instruction. - * Note that this is different than just throwing the error outside the - * function, as the function executed could have a try-catch which - * would otherwise handle the error - * - * @param error The error to induce - */ - public final Value induceError(EngineException error) { - return next(null, null, error); - } - /** - * Induces a return, as if there was a return statement before - * the currently executed instruction and executes the next instruction. - * Note that this is different than just returning the value outside the - * function, as the function executed could have a try-catch which - * would otherwise handle the error - * - * @param value The retunr value to induce - */ - public final Value induceReturn(Value value) { - return next(null, value, null); - } + /** + * Executes the next instruction in the frame + */ + public final Value next() { + return next(null, null, null); + } + /** + * Induces a value on the stack (as if it were returned by the last function call) + * and executes the next instruction in the frame. + * + * @param value The value to induce + */ + public final Value next(Value value) { + return next(value, null, null); + } + /** + * Induces a thrown error and executes the next instruction. + * Note that this is different than just throwing the error outside the + * function, as the function executed could have a try-catch which + * would otherwise handle the error + * + * @param error The error to induce + */ + public final Value induceError(EngineException error) { + return next(null, null, error); + } + /** + * Induces a return, as if there was a return statement before + * the currently executed instruction and executes the next instruction. + * Note that this is different than just returning the value outside the + * function, as the function executed could have a try-catch which + * would otherwise handle the error + * + * @param value The retunr value to induce + */ + public final Value induceReturn(Value value) { + return next(null, value, null); + } - public void onPush() { - DebugContext.get(env).onFramePush(env, this); - } - public void onPop() { - DebugContext.get(env).onFramePop(env, this); - } + public void onPush() { + DebugContext.get(env).onFramePush(env, this); + } + public void onPop() { + DebugContext.get(env).onFramePop(env, this); + } - /** - * Gets an array proxy of the local locals - */ - public ObjectValue getValStackScope() { - return new ArrayLikeValue() { - @Override public Value get(int i) { return stack[i]; } - @Override public boolean set(Environment env, int i, Value val) { return false; } - @Override public boolean has(int i) { return i >= 0 && i < size(); } - @Override public boolean remove(int i) { return false; } + /** + * Gets an array proxy of the local locals + */ + public ObjectValue getValStackScope() { + return new ArrayLikeValue() { + @Override public Value get(int i) { return stack[i]; } + @Override public boolean set(Environment env, int i, Value val) { return false; } + @Override public boolean has(int i) { return i >= 0 && i < size(); } + @Override public boolean remove(int i) { return false; } - @Override public int size() { return stackPtr; } - @Override public boolean setSize(int val) { return false; } - }; - } + @Override public int size() { return stackPtr; } + @Override public boolean setSize(int val) { return false; } + }; + } - public Frame(Environment env, boolean isNew, Value self, Value[] args, CodeFunction func) { - this.env = env; - this.dbg = DebugContext.get(env); - this.function = func; - this.isNew = isNew; + public Frame(Environment env, boolean isNew, Value self, Value[] args, CodeFunction func) { + this.env = env; + this.dbg = DebugContext.get(env); + this.function = func; + this.isNew = isNew; - this.self = self; - this.args = args; - this.argsVal = new ArgumentsValue(this, args); - this.argsLen = new IntValue(args.length); - this.captures = func.captures; + this.self = self; + this.args = args; + this.argsVal = new ArgumentsValue(this, args); + this.argsLen = new IntValue(args.length); + this.captures = func.captures; - this.locals = new Value[func.body.localsN]; + this.locals = new Value[func.body.localsN]; Arrays.fill(this.locals, Value.UNDEFINED); - this.capturables = new Value[func.body.capturablesN][1]; + this.capturables = new Value[func.body.capturablesN][1]; for (var i = 0; i < this.capturables.length; i++) this.capturables[i][0] = Value.UNDEFINED; - } + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/InstructionRunner.java b/src/main/java/me/topchetoeu/jscript/runtime/InstructionRunner.java index ec6efa7..bb6c23a 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/InstructionRunner.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/InstructionRunner.java @@ -19,548 +19,548 @@ import me.topchetoeu.jscript.runtime.values.primitives.StringValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public class InstructionRunner { - private static Value execReturn(Environment env, Instruction instr, Frame frame) { - return frame.pop(); - } - private static Value execThrow(Environment env, Instruction instr, Frame frame) { - throw new EngineException(frame.pop()); - } - private static Value execThrowSyntax(Environment env, Instruction instr, Frame frame) { - throw EngineException.ofSyntax((String)instr.get(0)); - } - - private static Value execCall(Environment env, Instruction instr, Frame frame) { - var callArgs = frame.take(instr.get(0)); - var func = frame.pop(); - var self = (boolean)instr.get(1) ? frame.pop() : Value.UNDEFINED; - - frame.push(func.apply(env, self, callArgs)); - - frame.codePtr++; - return null; - } - private static Value execCallNew(Environment env, Instruction instr, Frame frame) { - var callArgs = frame.take(instr.get(0)); - var funcObj = frame.pop(); - - frame.push(funcObj.construct(env, callArgs)); - - frame.codePtr++; - return null; - } - - private static Value execDefProp(Environment env, Instruction instr, Frame frame) { - var val = frame.pop(); - var key = frame.pop(); - var obj = frame.pop(); - - FunctionValue accessor; - - if (val == Value.UNDEFINED) accessor = null; - else if (val instanceof FunctionValue func) accessor = func; - else throw EngineException.ofType("Getter must be a function or undefined"); - - if ((boolean)instr.get(0)) obj.defineOwnMember(env, key, new PropertyMember(obj, null, accessor, true, true)); - else obj.defineOwnMember(env, key, new PropertyMember(obj, accessor, null, true, true)); - - frame.codePtr++; - return null; - } - private static Value execDefField(Environment env, Instruction instr, Frame frame) { - var val = frame.pop(); - var key = frame.pop(); - var obj = frame.pop(); - - obj.defineOwnMember(env, key, FieldMember.of(obj, val, true, true, true)); - - frame.codePtr++; - return null; - } - private static Value execKeys(Environment env, Instruction instr, Frame frame) { - var val = frame.pop(); - - var members = new ArrayList<>(val.getMembers(env, instr.get(0), instr.get(1))); - Collections.reverse(members); - - frame.push(Value.UNDEFINED); - - for (var el : members) { - var obj = new ObjectValue(); - obj.defineOwnMember(env, "value", StringValue.of(el)); - frame.push(obj); - } - - frame.codePtr++; - return null; - } - - private static Value execTryStart(Environment env, Instruction instr, Frame frame) { - int start = frame.codePtr + 1; - int catchStart = (int)instr.get(0); - int finallyStart = (int)instr.get(1); - if (finallyStart >= 0) finallyStart += start; - if (catchStart >= 0) catchStart += start; - int end = (int)instr.get(2) + start; - frame.addTry(start, end, catchStart, finallyStart); - frame.codePtr++; - return null; - } - private static Value execTryEnd(Environment env, Instruction instr, Frame frame) { - frame.popTryFlag = true; - return null; - } - - private static Value execDup(Environment env, Instruction instr, Frame frame) { - int count = instr.get(0); - int offset = instr.get(1); - - var el = frame.stack[frame.stackPtr - offset - 1]; - - for (var i = 0; i < count; i++) { - frame.push(el); - } - - frame.codePtr++; - return null; - } - private static Value execLoadValue(Environment env, Instruction instr, Frame frame) { - switch (instr.type) { - case PUSH_UNDEFINED: frame.push(Value.UNDEFINED); break; - case PUSH_NULL: frame.push(Value.NULL); break; - case PUSH_BOOL: frame.push(BoolValue.of(instr.get(0))); break; - case PUSH_NUMBER: frame.push(NumberValue.of((double)instr.get(0))); break; - case PUSH_STRING: frame.push(StringValue.of(instr.get(0))); break; - default: - } - - frame.codePtr++; - return null; - } - private static Value execLoadVar(Environment env, Instruction instr, Frame frame) { - int i = instr.get(0); - - frame.push(frame.getVar(i)); - frame.codePtr++; - - return null; - } - private static Value execLoadObj(Environment env, Instruction instr, Frame frame) { - var obj = new ObjectValue(); - obj.setPrototype(Value.OBJECT_PROTO); - frame.push(obj); - frame.codePtr++; - return null; - } - private static Value execLoadGlob(Environment env, Instruction instr, Frame frame) { - frame.push(Value.global(env)); - frame.codePtr++; - return null; - } - private static Value execLoadIntrinsics(Environment env, Instruction instr, Frame frame) { - frame.push(Value.intrinsics(env).get((String)instr.get(0))); - frame.codePtr++; - return null; - } - private static Value execLoadArr(Environment env, Instruction instr, Frame frame) { - var res = new ArrayValue(); - res.setSize(instr.get(0)); - frame.push(res); - frame.codePtr++; - return null; - } - private static Value execLoadFunc(Environment env, Instruction instr, Frame frame) { - int id = instr.get(0); - String name = instr.get(1); - - var captures = new Value[instr.params.length - 2][]; - - for (var i = 2; i < instr.params.length; i++) { - captures[i - 2] = frame.captureVar(instr.get(i)); - } - - var func = new CodeFunction(env, name, frame.function.body.children[id], captures); - - frame.push(func); - - frame.codePtr++; - return null; - } - private static Value execLoadMember(Environment env, Instruction instr, Frame frame) { - var key = frame.pop(); - - try { - var top = frame.stackPtr - 1; - frame.stack[top] = frame.stack[top].getMember(env, key); - } - catch (IllegalArgumentException e) { - throw EngineException.ofType(e.getMessage()); - } - frame.codePtr++; - return null; - } - private static Value execLoadMemberInt(Environment env, Instruction instr, Frame frame) { - try { - var top = frame.stackPtr - 1; - frame.stack[top] = frame.stack[top].getMember(env, (int)instr.get(0)); - } - catch (IllegalArgumentException e) { - throw EngineException.ofType(e.getMessage()); - } - frame.codePtr++; - return null; - } - private static Value execLoadMemberStr(Environment env, Instruction instr, Frame frame) { - try { - var top = frame.stackPtr - 1; - frame.stack[top] = frame.stack[top].getMember(env, (String)instr.get(0)); - } - catch (IllegalArgumentException e) { - throw EngineException.ofType(e.getMessage()); - } - frame.codePtr++; - return null; - } - private static Value execLoadRegEx(Environment env, Instruction instr, Frame frame) { - if (env.hasNotNull(Value.REGEX_CONSTR)) { - frame.push(env.get(Value.REGEX_CONSTR).construct(env, instr.get(0), instr.get(1))); - } - else { - throw EngineException.ofSyntax("Regex is not supported"); - } - - frame.codePtr++; - return null; - } - - private static Value execDiscard(Environment env, Instruction instr, Frame frame) { - frame.pop(); - frame.codePtr++; - return null; - } - private static Value execStoreMember(Environment env, Instruction instr, Frame frame) { - var val = frame.pop(); - var key = frame.pop(); - var obj = frame.pop(); - - if (!obj.setMember(env, key, val)) throw EngineException.ofSyntax("Can't set member '" + key.toReadable(env) + "'"); - if ((boolean)instr.get(0)) frame.push(val); - frame.codePtr++; - return null; - } - private static Value execStoreMemberStr(Environment env, Instruction instr, Frame frame) { - var val = frame.pop(); - var obj = frame.pop(); - - if (!obj.setMember(env, (String)instr.get(0), val)) throw EngineException.ofSyntax("Can't set member '" + instr.get(0) + "'"); - if ((boolean)instr.get(1)) frame.push(val); - frame.codePtr++; - return null; - } - private static Value execStoreMemberInt(Environment env, Instruction instr, Frame frame) { - var val = frame.pop(); - var obj = frame.pop(); - - if (!obj.setMember(env, (int)instr.get(0), val)) throw EngineException.ofSyntax("Can't set member '" + instr.get(0) + "'"); - if ((boolean)instr.get(1)) frame.push(val); - frame.codePtr++; - return null; - } - private static Value execStoreVar(Environment env, Instruction instr, Frame frame) { - var val = (boolean)instr.get(1) ? frame.peek() : frame.pop(); - int i = instr.get(0); - - frame.setVar(i, val); - frame.codePtr++; - - return null; - } - - private static Value execJmp(Environment env, Instruction instr, Frame frame) { - frame.codePtr += (int)instr.get(0); - frame.jumpFlag = true; - return null; - } - private static Value execJmpIf(Environment env, Instruction instr, Frame frame) { - if (frame.pop().toBoolean()) { - frame.codePtr += (int)instr.get(0); - frame.jumpFlag = true; - } - else frame.codePtr ++; - return null; - } - private static Value execJmpIfNot(Environment env, Instruction instr, Frame frame) { - if (!frame.pop().toBoolean()) { - frame.codePtr += (int)instr.get(0); - frame.jumpFlag = true; - } - else frame.codePtr ++; - return null; - } - - private static Value execTypeof(Environment env, Instruction instr, Frame frame) { - String name = instr.get(0); - Value obj; - - if (name != null) obj = Value.global(env).getMember(env, name); - else obj = frame.pop(); - - frame.push(obj.type()); - - frame.codePtr++; - return null; - } - private static Value execNop(Environment env, Instruction instr, Frame frame) { - frame.codePtr++; - return null; - } - - private static Value execDelete(Environment env, Instruction instr, Frame frame) { - var key = frame.pop(); - var val = frame.pop(); - - if (!val.deleteMember(env, key)) throw EngineException.ofSyntax("Can't delete member '" + key.toReadable(env) + "'"); - frame.codePtr++; - return null; - } - - private static Value execOperation(Environment env, Instruction instr, Frame frame) { - Operation op = instr.get(0); - Value res; - var stack = frame.stack; - - frame.stackPtr -= 1; - var ptr = frame.stackPtr; - - switch (op) { - case ADD: - res = Value.add(env, stack[ptr - 1], stack[ptr]); - break; - case SUBTRACT: - res = Value.subtract(env, stack[ptr - 1], stack[ptr]); - break; - case DIVIDE: - res = Value.divide(env, stack[ptr - 1], stack[ptr]); - break; - case MULTIPLY: - res = Value.multiply(env, stack[ptr - 1], stack[ptr]); - break; - case MODULO: - res = Value.modulo(env, stack[ptr - 1], stack[ptr]); - break; - - case AND: - res = Value.and(env, stack[ptr - 1], stack[ptr]); - break; - case OR: - res = Value.or(env, stack[ptr - 1], stack[ptr]); - break; - case XOR: - res = Value.xor(env, stack[ptr - 1], stack[ptr]); - break; - - case EQUALS: - res = BoolValue.of(stack[ptr - 1].equals(stack[ptr])); - break; - case NOT_EQUALS: - res = BoolValue.of(!stack[ptr - 1].equals(stack[ptr])); - break; - case LOOSE_EQUALS: - res = BoolValue.of(Value.looseEqual(env, stack[ptr - 1], stack[ptr])); - break; - case LOOSE_NOT_EQUALS: - res = BoolValue.of(!Value.looseEqual(env, stack[ptr - 1], stack[ptr])); - break; - - case GREATER: - res = BoolValue.of(Value.greater(env, stack[ptr - 1], stack[ptr])); - break; - case GREATER_EQUALS: - res = BoolValue.of(Value.greaterOrEqual(env, stack[ptr - 1], stack[ptr])); - break; - case LESS: - res = BoolValue.of(Value.less(env, stack[ptr - 1], stack[ptr])); - break; - case LESS_EQUALS: - res = BoolValue.of(Value.lessOrEqual(env, stack[ptr - 1], stack[ptr])); - break; - - case INVERSE: - res = Value.bitwiseNot(env, stack[ptr++]); - frame.stackPtr++; - break; - case NOT: - res = BoolValue.of(!stack[ptr++].toBoolean()); - frame.stackPtr++; - break; - case POS: - res = stack[ptr++].toNumber(env); - frame.stackPtr++; - break; - case NEG: - res = Value.negative(env, stack[ptr++]); - frame.stackPtr++; - break; - - case SHIFT_LEFT: - res = Value.shiftLeft(env, stack[ptr], stack[ptr]); - break; - case SHIFT_RIGHT: - res = Value.shiftRight(env, stack[ptr], stack[ptr]); - break; - case USHIFT_RIGHT: - res = Value.unsignedShiftRight(env, stack[ptr], stack[ptr]); - break; - - case IN: - res = BoolValue.of(stack[ptr - 1].hasMember(env, stack[ptr], false)); - break; - case INSTANCEOF: - res = BoolValue.of(stack[ptr - 1].isInstanceOf(env, stack[ptr].getMember(env, StringValue.of("prototype")))); - break; - - default: return null; - } - - stack[ptr - 1] = res; - frame.codePtr++; - return null; - } - - private static Value execGlobDef(Environment env, Instruction instr, Frame frame) { - var name = (String)instr.get(0); - - if (!Value.global(env).hasMember(env, name, false)) { - if (!Value.global(env).defineOwnMember(env, name, Value.UNDEFINED)) throw EngineException.ofError("Couldn't define variable " + name); - } - - frame.codePtr++; - return null; - } - private static Value execGlobGet(Environment env, Instruction instr, Frame frame) { - var name = (String)instr.get(0); - if ((boolean)instr.get(1)) { - frame.push(Value.global(env).getMember(env, name)); - } - else { - var res = Value.global(env).getMemberOrNull(env, name); - - if (res == null) throw EngineException.ofSyntax(name + " is not defined"); - else frame.push(res); - } - - frame.codePtr++; - return null; - } - private static Value execGlobSet(Environment env, Instruction instr, Frame frame) { - var name = (String)instr.get(0); - var keep = (boolean)instr.get(1); - var define = (boolean)instr.get(2); - - var val = keep ? frame.peek() : frame.pop(); - var res = false; - - if (define) res = Value.global(env).setMember(env, name, val); - else res = Value.global(env).setMemberIfExists(env, name, val); - - if (!res) throw EngineException.ofError("Couldn't set variable " + name); - - frame.codePtr++; - return null; - } - - private static Value execLoadArg(Environment env, Instruction instr, Frame frame) { + private static Value execReturn(Environment env, Instruction instr, Frame frame) { + return frame.pop(); + } + private static Value execThrow(Environment env, Instruction instr, Frame frame) { + throw new EngineException(frame.pop()); + } + private static Value execThrowSyntax(Environment env, Instruction instr, Frame frame) { + throw EngineException.ofSyntax((String)instr.get(0)); + } + + private static Value execCall(Environment env, Instruction instr, Frame frame) { + var callArgs = frame.take(instr.get(0)); + var func = frame.pop(); + var self = (boolean)instr.get(1) ? frame.pop() : Value.UNDEFINED; + + frame.push(func.apply(env, self, callArgs)); + + frame.codePtr++; + return null; + } + private static Value execCallNew(Environment env, Instruction instr, Frame frame) { + var callArgs = frame.take(instr.get(0)); + var funcObj = frame.pop(); + + frame.push(funcObj.construct(env, callArgs)); + + frame.codePtr++; + return null; + } + + private static Value execDefProp(Environment env, Instruction instr, Frame frame) { + var val = frame.pop(); + var key = frame.pop(); + var obj = frame.pop(); + + FunctionValue accessor; + + if (val == Value.UNDEFINED) accessor = null; + else if (val instanceof FunctionValue func) accessor = func; + else throw EngineException.ofType("Getter must be a function or undefined"); + + if ((boolean)instr.get(0)) obj.defineOwnMember(env, key, new PropertyMember(obj, null, accessor, true, true)); + else obj.defineOwnMember(env, key, new PropertyMember(obj, accessor, null, true, true)); + + frame.codePtr++; + return null; + } + private static Value execDefField(Environment env, Instruction instr, Frame frame) { + var val = frame.pop(); + var key = frame.pop(); + var obj = frame.pop(); + + obj.defineOwnMember(env, key, FieldMember.of(obj, val, true, true, true)); + + frame.codePtr++; + return null; + } + private static Value execKeys(Environment env, Instruction instr, Frame frame) { + var val = frame.pop(); + + var members = new ArrayList<>(val.getMembers(env, instr.get(0), instr.get(1))); + Collections.reverse(members); + + frame.push(Value.UNDEFINED); + + for (var el : members) { + var obj = new ObjectValue(); + obj.defineOwnMember(env, "value", StringValue.of(el)); + frame.push(obj); + } + + frame.codePtr++; + return null; + } + + private static Value execTryStart(Environment env, Instruction instr, Frame frame) { + int start = frame.codePtr + 1; + int catchStart = (int)instr.get(0); + int finallyStart = (int)instr.get(1); + if (finallyStart >= 0) finallyStart += start; + if (catchStart >= 0) catchStart += start; + int end = (int)instr.get(2) + start; + frame.addTry(start, end, catchStart, finallyStart); + frame.codePtr++; + return null; + } + private static Value execTryEnd(Environment env, Instruction instr, Frame frame) { + frame.popTryFlag = true; + return null; + } + + private static Value execDup(Environment env, Instruction instr, Frame frame) { + int count = instr.get(0); + int offset = instr.get(1); + + var el = frame.stack[frame.stackPtr - offset - 1]; + + for (var i = 0; i < count; i++) { + frame.push(el); + } + + frame.codePtr++; + return null; + } + private static Value execLoadValue(Environment env, Instruction instr, Frame frame) { + switch (instr.type) { + case PUSH_UNDEFINED: frame.push(Value.UNDEFINED); break; + case PUSH_NULL: frame.push(Value.NULL); break; + case PUSH_BOOL: frame.push(BoolValue.of(instr.get(0))); break; + case PUSH_NUMBER: frame.push(NumberValue.of((double)instr.get(0))); break; + case PUSH_STRING: frame.push(StringValue.of(instr.get(0))); break; + default: + } + + frame.codePtr++; + return null; + } + private static Value execLoadVar(Environment env, Instruction instr, Frame frame) { + int i = instr.get(0); + + frame.push(frame.getVar(i)); + frame.codePtr++; + + return null; + } + private static Value execLoadObj(Environment env, Instruction instr, Frame frame) { + var obj = new ObjectValue(); + obj.setPrototype(Value.OBJECT_PROTO); + frame.push(obj); + frame.codePtr++; + return null; + } + private static Value execLoadGlob(Environment env, Instruction instr, Frame frame) { + frame.push(Value.global(env)); + frame.codePtr++; + return null; + } + private static Value execLoadIntrinsics(Environment env, Instruction instr, Frame frame) { + frame.push(Value.intrinsics(env).get((String)instr.get(0))); + frame.codePtr++; + return null; + } + private static Value execLoadArr(Environment env, Instruction instr, Frame frame) { + var res = new ArrayValue(); + res.setSize(instr.get(0)); + frame.push(res); + frame.codePtr++; + return null; + } + private static Value execLoadFunc(Environment env, Instruction instr, Frame frame) { + int id = instr.get(0); + String name = instr.get(1); + + var captures = new Value[instr.params.length - 2][]; + + for (var i = 2; i < instr.params.length; i++) { + captures[i - 2] = frame.captureVar(instr.get(i)); + } + + var func = new CodeFunction(env, name, frame.function.body.children[id], captures); + + frame.push(func); + + frame.codePtr++; + return null; + } + private static Value execLoadMember(Environment env, Instruction instr, Frame frame) { + var key = frame.pop(); + + try { + var top = frame.stackPtr - 1; + frame.stack[top] = frame.stack[top].getMember(env, key); + } + catch (IllegalArgumentException e) { + throw EngineException.ofType(e.getMessage()); + } + frame.codePtr++; + return null; + } + private static Value execLoadMemberInt(Environment env, Instruction instr, Frame frame) { + try { + var top = frame.stackPtr - 1; + frame.stack[top] = frame.stack[top].getMember(env, (int)instr.get(0)); + } + catch (IllegalArgumentException e) { + throw EngineException.ofType(e.getMessage()); + } + frame.codePtr++; + return null; + } + private static Value execLoadMemberStr(Environment env, Instruction instr, Frame frame) { + try { + var top = frame.stackPtr - 1; + frame.stack[top] = frame.stack[top].getMember(env, (String)instr.get(0)); + } + catch (IllegalArgumentException e) { + throw EngineException.ofType(e.getMessage()); + } + frame.codePtr++; + return null; + } + private static Value execLoadRegEx(Environment env, Instruction instr, Frame frame) { + if (env.hasNotNull(Value.REGEX_CONSTR)) { + frame.push(env.get(Value.REGEX_CONSTR).construct(env, instr.get(0), instr.get(1))); + } + else { + throw EngineException.ofSyntax("Regex is not supported"); + } + + frame.codePtr++; + return null; + } + + private static Value execDiscard(Environment env, Instruction instr, Frame frame) { + frame.pop(); + frame.codePtr++; + return null; + } + private static Value execStoreMember(Environment env, Instruction instr, Frame frame) { + var val = frame.pop(); + var key = frame.pop(); + var obj = frame.pop(); + + if (!obj.setMember(env, key, val)) throw EngineException.ofSyntax("Can't set member '" + key.toReadable(env) + "'"); + if ((boolean)instr.get(0)) frame.push(val); + frame.codePtr++; + return null; + } + private static Value execStoreMemberStr(Environment env, Instruction instr, Frame frame) { + var val = frame.pop(); + var obj = frame.pop(); + + if (!obj.setMember(env, (String)instr.get(0), val)) throw EngineException.ofSyntax("Can't set member '" + instr.get(0) + "'"); + if ((boolean)instr.get(1)) frame.push(val); + frame.codePtr++; + return null; + } + private static Value execStoreMemberInt(Environment env, Instruction instr, Frame frame) { + var val = frame.pop(); + var obj = frame.pop(); + + if (!obj.setMember(env, (int)instr.get(0), val)) throw EngineException.ofSyntax("Can't set member '" + instr.get(0) + "'"); + if ((boolean)instr.get(1)) frame.push(val); + frame.codePtr++; + return null; + } + private static Value execStoreVar(Environment env, Instruction instr, Frame frame) { + var val = (boolean)instr.get(1) ? frame.peek() : frame.pop(); + int i = instr.get(0); + + frame.setVar(i, val); + frame.codePtr++; + + return null; + } + + private static Value execJmp(Environment env, Instruction instr, Frame frame) { + frame.codePtr += (int)instr.get(0); + frame.jumpFlag = true; + return null; + } + private static Value execJmpIf(Environment env, Instruction instr, Frame frame) { + if (frame.pop().toBoolean()) { + frame.codePtr += (int)instr.get(0); + frame.jumpFlag = true; + } + else frame.codePtr ++; + return null; + } + private static Value execJmpIfNot(Environment env, Instruction instr, Frame frame) { + if (!frame.pop().toBoolean()) { + frame.codePtr += (int)instr.get(0); + frame.jumpFlag = true; + } + else frame.codePtr ++; + return null; + } + + private static Value execTypeof(Environment env, Instruction instr, Frame frame) { + String name = instr.get(0); + Value obj; + + if (name != null) obj = Value.global(env).getMember(env, name); + else obj = frame.pop(); + + frame.push(obj.type()); + + frame.codePtr++; + return null; + } + private static Value execNop(Environment env, Instruction instr, Frame frame) { + frame.codePtr++; + return null; + } + + private static Value execDelete(Environment env, Instruction instr, Frame frame) { + var key = frame.pop(); + var val = frame.pop(); + + if (!val.deleteMember(env, key)) throw EngineException.ofSyntax("Can't delete member '" + key.toReadable(env) + "'"); + frame.codePtr++; + return null; + } + + private static Value execOperation(Environment env, Instruction instr, Frame frame) { + Operation op = instr.get(0); + Value res; + var stack = frame.stack; + + frame.stackPtr -= 1; + var ptr = frame.stackPtr; + + switch (op) { + case ADD: + res = Value.add(env, stack[ptr - 1], stack[ptr]); + break; + case SUBTRACT: + res = Value.subtract(env, stack[ptr - 1], stack[ptr]); + break; + case DIVIDE: + res = Value.divide(env, stack[ptr - 1], stack[ptr]); + break; + case MULTIPLY: + res = Value.multiply(env, stack[ptr - 1], stack[ptr]); + break; + case MODULO: + res = Value.modulo(env, stack[ptr - 1], stack[ptr]); + break; + + case AND: + res = Value.and(env, stack[ptr - 1], stack[ptr]); + break; + case OR: + res = Value.or(env, stack[ptr - 1], stack[ptr]); + break; + case XOR: + res = Value.xor(env, stack[ptr - 1], stack[ptr]); + break; + + case EQUALS: + res = BoolValue.of(stack[ptr - 1].equals(stack[ptr])); + break; + case NOT_EQUALS: + res = BoolValue.of(!stack[ptr - 1].equals(stack[ptr])); + break; + case LOOSE_EQUALS: + res = BoolValue.of(Value.looseEqual(env, stack[ptr - 1], stack[ptr])); + break; + case LOOSE_NOT_EQUALS: + res = BoolValue.of(!Value.looseEqual(env, stack[ptr - 1], stack[ptr])); + break; + + case GREATER: + res = BoolValue.of(Value.greater(env, stack[ptr - 1], stack[ptr])); + break; + case GREATER_EQUALS: + res = BoolValue.of(Value.greaterOrEqual(env, stack[ptr - 1], stack[ptr])); + break; + case LESS: + res = BoolValue.of(Value.less(env, stack[ptr - 1], stack[ptr])); + break; + case LESS_EQUALS: + res = BoolValue.of(Value.lessOrEqual(env, stack[ptr - 1], stack[ptr])); + break; + + case INVERSE: + res = Value.bitwiseNot(env, stack[ptr++]); + frame.stackPtr++; + break; + case NOT: + res = BoolValue.of(!stack[ptr++].toBoolean()); + frame.stackPtr++; + break; + case POS: + res = stack[ptr++].toNumber(env); + frame.stackPtr++; + break; + case NEG: + res = Value.negative(env, stack[ptr++]); + frame.stackPtr++; + break; + + case SHIFT_LEFT: + res = Value.shiftLeft(env, stack[ptr], stack[ptr]); + break; + case SHIFT_RIGHT: + res = Value.shiftRight(env, stack[ptr], stack[ptr]); + break; + case USHIFT_RIGHT: + res = Value.unsignedShiftRight(env, stack[ptr], stack[ptr]); + break; + + case IN: + res = BoolValue.of(stack[ptr - 1].hasMember(env, stack[ptr], false)); + break; + case INSTANCEOF: + res = BoolValue.of(stack[ptr - 1].isInstanceOf(env, stack[ptr].getMember(env, StringValue.of("prototype")))); + break; + + default: return null; + } + + stack[ptr - 1] = res; + frame.codePtr++; + return null; + } + + private static Value execGlobDef(Environment env, Instruction instr, Frame frame) { + var name = (String)instr.get(0); + + if (!Value.global(env).hasMember(env, name, false)) { + if (!Value.global(env).defineOwnMember(env, name, Value.UNDEFINED)) throw EngineException.ofError("Couldn't define variable " + name); + } + + frame.codePtr++; + return null; + } + private static Value execGlobGet(Environment env, Instruction instr, Frame frame) { + var name = (String)instr.get(0); + if ((boolean)instr.get(1)) { + frame.push(Value.global(env).getMember(env, name)); + } + else { + var res = Value.global(env).getMemberOrNull(env, name); + + if (res == null) throw EngineException.ofSyntax(name + " is not defined"); + else frame.push(res); + } + + frame.codePtr++; + return null; + } + private static Value execGlobSet(Environment env, Instruction instr, Frame frame) { + var name = (String)instr.get(0); + var keep = (boolean)instr.get(1); + var define = (boolean)instr.get(2); + + var val = keep ? frame.peek() : frame.pop(); + var res = false; + + if (define) res = Value.global(env).setMember(env, name, val); + else res = Value.global(env).setMemberIfExists(env, name, val); + + if (!res) throw EngineException.ofError("Couldn't set variable " + name); + + frame.codePtr++; + return null; + } + + private static Value execLoadArg(Environment env, Instruction instr, Frame frame) { int i = instr.get(0); if (i >= frame.args.length) frame.push(Value.UNDEFINED); else frame.push(frame.args[i]); - frame.codePtr++; - return null; - } - private static Value execLoadArgsN(Environment env, Instruction instr, Frame frame) { + frame.codePtr++; + return null; + } + private static Value execLoadArgsN(Environment env, Instruction instr, Frame frame) { frame.push(frame.argsLen); - frame.codePtr++; - return null; - } - private static Value execLoadArgs(Environment env, Instruction instr, Frame frame) { - frame.push(frame.argsVal); - frame.codePtr++; - return null; - } - private static Value execLoadCallee(Environment env, Instruction instr, Frame frame) { - frame.push(frame.function); - frame.codePtr++; - return null; - } - private static Value execLoadThis(Environment env, Instruction instr, Frame frame) { - if (frame.self == null) throw EngineException.ofError("Super constructor must be called before 'this' is accessed"); - frame.push(frame.self); - frame.codePtr++; - return null; - } - private static Value execLoadError(Environment env, Instruction instr, Frame frame) { - frame.push(frame.tryStack.peek().error.value); - frame.codePtr++; - return null; - } + frame.codePtr++; + return null; + } + private static Value execLoadArgs(Environment env, Instruction instr, Frame frame) { + frame.push(frame.argsVal); + frame.codePtr++; + return null; + } + private static Value execLoadCallee(Environment env, Instruction instr, Frame frame) { + frame.push(frame.function); + frame.codePtr++; + return null; + } + private static Value execLoadThis(Environment env, Instruction instr, Frame frame) { + if (frame.self == null) throw EngineException.ofError("Super constructor must be called before 'this' is accessed"); + frame.push(frame.self); + frame.codePtr++; + return null; + } + private static Value execLoadError(Environment env, Instruction instr, Frame frame) { + frame.push(frame.tryStack.peek().error.value); + frame.codePtr++; + return null; + } public static Value exec(Environment env, Instruction instr, Frame frame) { - switch (instr.type) { - case NOP: return execNop(env, instr, frame); - case RETURN: return execReturn(env, instr, frame); - case THROW: return execThrow(env, instr, frame); - case THROW_SYNTAX: return execThrowSyntax(env, instr, frame); - case CALL: return execCall(env, instr, frame); - case CALL_NEW: return execCallNew(env, instr, frame); - case TRY_START: return execTryStart(env, instr, frame); - case TRY_END: return execTryEnd(env, instr, frame); + switch (instr.type) { + case NOP: return execNop(env, instr, frame); + case RETURN: return execReturn(env, instr, frame); + case THROW: return execThrow(env, instr, frame); + case THROW_SYNTAX: return execThrowSyntax(env, instr, frame); + case CALL: return execCall(env, instr, frame); + case CALL_NEW: return execCallNew(env, instr, frame); + case TRY_START: return execTryStart(env, instr, frame); + case TRY_END: return execTryEnd(env, instr, frame); - case DUP: return execDup(env, instr, frame); - case PUSH_UNDEFINED: - case PUSH_NULL: - case PUSH_STRING: - case PUSH_NUMBER: - case PUSH_BOOL: - return execLoadValue(env, instr, frame); - case LOAD_VAR: return execLoadVar(env, instr, frame); - case LOAD_OBJ: return execLoadObj(env, instr, frame); - case LOAD_ARR: return execLoadArr(env, instr, frame); - case LOAD_FUNC: return execLoadFunc(env, instr, frame); - case LOAD_MEMBER: return execLoadMember(env, instr, frame); - case LOAD_MEMBER_INT: return execLoadMemberInt(env, instr, frame); - case LOAD_MEMBER_STR: return execLoadMemberStr(env, instr, frame); - case LOAD_REGEX: return execLoadRegEx(env, instr, frame); - case LOAD_GLOB: return execLoadGlob(env, instr, frame); - case LOAD_INTRINSICS: return execLoadIntrinsics(env, instr, frame); - case LOAD_ERROR: return execLoadError(env, instr, frame); + case DUP: return execDup(env, instr, frame); + case PUSH_UNDEFINED: + case PUSH_NULL: + case PUSH_STRING: + case PUSH_NUMBER: + case PUSH_BOOL: + return execLoadValue(env, instr, frame); + case LOAD_VAR: return execLoadVar(env, instr, frame); + case LOAD_OBJ: return execLoadObj(env, instr, frame); + case LOAD_ARR: return execLoadArr(env, instr, frame); + case LOAD_FUNC: return execLoadFunc(env, instr, frame); + case LOAD_MEMBER: return execLoadMember(env, instr, frame); + case LOAD_MEMBER_INT: return execLoadMemberInt(env, instr, frame); + case LOAD_MEMBER_STR: return execLoadMemberStr(env, instr, frame); + case LOAD_REGEX: return execLoadRegEx(env, instr, frame); + case LOAD_GLOB: return execLoadGlob(env, instr, frame); + case LOAD_INTRINSICS: return execLoadIntrinsics(env, instr, frame); + case LOAD_ERROR: return execLoadError(env, instr, frame); - case LOAD_THIS: return execLoadThis(env, instr, frame); + case LOAD_THIS: return execLoadThis(env, instr, frame); case LOAD_ARG: return execLoadArg(env, instr, frame); - case LOAD_ARGS: return execLoadArgs(env, instr, frame); - case LOAD_ARGS_N: return execLoadArgsN(env, instr, frame); + case LOAD_ARGS: return execLoadArgs(env, instr, frame); + case LOAD_ARGS_N: return execLoadArgsN(env, instr, frame); case LOAD_CALLED: return execLoadCallee(env, instr, frame); - case DISCARD: return execDiscard(env, instr, frame); - case STORE_MEMBER: return execStoreMember(env, instr, frame); - case STORE_MEMBER_STR: return execStoreMemberStr(env, instr, frame); - case STORE_MEMBER_INT: return execStoreMemberInt(env, instr, frame); - case STORE_VAR: return execStoreVar(env, instr, frame); + case DISCARD: return execDiscard(env, instr, frame); + case STORE_MEMBER: return execStoreMember(env, instr, frame); + case STORE_MEMBER_STR: return execStoreMemberStr(env, instr, frame); + case STORE_MEMBER_INT: return execStoreMemberInt(env, instr, frame); + case STORE_VAR: return execStoreVar(env, instr, frame); - case KEYS: return execKeys(env, instr, frame); - case DEF_PROP: return execDefProp(env, instr, frame); - case DEF_FIELD: return execDefField(env, instr, frame); - case TYPEOF: return execTypeof(env, instr, frame); - case DELETE: return execDelete(env, instr, frame); + case KEYS: return execKeys(env, instr, frame); + case DEF_PROP: return execDefProp(env, instr, frame); + case DEF_FIELD: return execDefField(env, instr, frame); + case TYPEOF: return execTypeof(env, instr, frame); + case DELETE: return execDelete(env, instr, frame); - case JMP: return execJmp(env, instr, frame); - case JMP_IF: return execJmpIf(env, instr, frame); - case JMP_IFN: return execJmpIfNot(env, instr, frame); + case JMP: return execJmp(env, instr, frame); + case JMP_IF: return execJmpIf(env, instr, frame); + case JMP_IFN: return execJmpIfNot(env, instr, frame); - case OPERATION: return execOperation(env, instr, frame); + case OPERATION: return execOperation(env, instr, frame); - case GLOB_DEF: return execGlobDef(env, instr, frame); - case GLOB_GET: return execGlobGet(env, instr, frame); - case GLOB_SET: return execGlobSet(env, instr, frame); + case GLOB_DEF: return execGlobDef(env, instr, frame); + case GLOB_GET: return execGlobGet(env, instr, frame); + case GLOB_SET: return execGlobSet(env, instr, frame); - default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + ""); - } - } + default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + ""); + } + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/JSONConverter.java b/src/main/java/me/topchetoeu/jscript/runtime/JSONConverter.java index a451588..5a0e3b5 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/JSONConverter.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/JSONConverter.java @@ -17,70 +17,70 @@ import me.topchetoeu.jscript.runtime.values.primitives.VoidValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public class JSONConverter { - public static Value toJs(JSONElement val) { - if (val.isBoolean()) return BoolValue.of(val.bool()); - if (val.isString()) return StringValue.of(val.string()); - if (val.isNumber()) return NumberValue.of(val.number()); - if (val.isList()) return ArrayValue.of(val.list().stream().map(JSONConverter::toJs).collect(Collectors.toList())); - if (val.isMap()) { - var res = new ObjectValue(); - - for (var el : val.map().entrySet()) { - res.defineOwnMember(null, el.getKey(), toJs(el.getValue())); - } - - return res; - } - if (val.isNull()) return Value.NULL; - return Value.UNDEFINED; - } + public static Value toJs(JSONElement val) { + if (val.isBoolean()) return BoolValue.of(val.bool()); + if (val.isString()) return StringValue.of(val.string()); + if (val.isNumber()) return NumberValue.of(val.number()); + if (val.isList()) return ArrayValue.of(val.list().stream().map(JSONConverter::toJs).collect(Collectors.toList())); + if (val.isMap()) { + var res = new ObjectValue(); + + for (var el : val.map().entrySet()) { + res.defineOwnMember(null, el.getKey(), toJs(el.getValue())); + } + + return res; + } + if (val.isNull()) return Value.NULL; + return Value.UNDEFINED; + } - public static JSONElement fromJs(Environment ext, Value val) { - var res = JSONConverter.fromJs(ext, val, new HashSet<>()); - if (res == null) return JSONElement.NULL; - else return res; - } + public static JSONElement fromJs(Environment ext, Value val) { + var res = JSONConverter.fromJs(ext, val, new HashSet<>()); + if (res == null) return JSONElement.NULL; + else return res; + } - public static JSONElement fromJs(Environment env, Value val, HashSet prev) { - if (val instanceof BoolValue) return JSONElement.bool(((BoolValue)val).value); - if (val instanceof NumberValue) return JSONElement.number(((NumberValue)val).getDouble()); - if (val instanceof StringValue) return JSONElement.string(((StringValue)val).value); - if (val == Value.NULL) return JSONElement.NULL; - if (val instanceof VoidValue) return null; - - if (val instanceof ArrayValue) { - if (prev.contains(val)) throw EngineException.ofError("Circular dependency in JSON."); - prev.add(val); - - var res = new JSONList(); - - for (var el : ((ArrayValue)val).toArray()) { - var jsonEl = fromJs(env, el, prev); - if (jsonEl == null) continue; - res.add(jsonEl); - } - - prev.remove(val); - return JSONElement.of(res); - } - if (val instanceof ObjectValue) { - if (prev.contains(val)) throw EngineException.ofError("Circular dependency in JSON."); - prev.add(val); - - var res = new JSONMap(); - - for (var key : val.getOwnMembers(env, true)) { - var el = fromJs(env, val.getMember(env, key), prev); - if (el == null) continue; + public static JSONElement fromJs(Environment env, Value val, HashSet prev) { + if (val instanceof BoolValue) return JSONElement.bool(((BoolValue)val).value); + if (val instanceof NumberValue) return JSONElement.number(((NumberValue)val).getDouble()); + if (val instanceof StringValue) return JSONElement.string(((StringValue)val).value); + if (val == Value.NULL) return JSONElement.NULL; + if (val instanceof VoidValue) return null; + + if (val instanceof ArrayValue) { + if (prev.contains(val)) throw EngineException.ofError("Circular dependency in JSON."); + prev.add(val); + + var res = new JSONList(); + + for (var el : ((ArrayValue)val).toArray()) { + var jsonEl = fromJs(env, el, prev); + if (jsonEl == null) continue; + res.add(jsonEl); + } + + prev.remove(val); + return JSONElement.of(res); + } + if (val instanceof ObjectValue) { + if (prev.contains(val)) throw EngineException.ofError("Circular dependency in JSON."); + prev.add(val); + + var res = new JSONMap(); + + for (var key : val.getOwnMembers(env, true)) { + var el = fromJs(env, val.getMember(env, key), prev); + if (el == null) continue; - res.put(key, el); - } - - prev.remove(val); - return JSONElement.of(res); - } - if (val == null) return null; - return null; - } - + res.put(key, el); + } + + prev.remove(val); + return JSONElement.of(res); + } + if (val == null) return null; + return null; + } + } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java b/src/main/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java index e87905c..e9255a8 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java @@ -17,102 +17,102 @@ import me.topchetoeu.jscript.runtime.values.functions.CodeFunction; import me.topchetoeu.jscript.runtime.values.functions.FunctionValue; public class DebugContext { - public static final Key KEY = Key.of(); - public static final Key IGNORE = Key.of(); + public static final Key KEY = new Key<>(); + public static final Key IGNORE = new Key<>(); - private HashMap sources; - private WeakHashMap maps; - private DebugHandler debugger; + private HashMap sources; + private WeakHashMap maps; + private DebugHandler debugger; - public boolean attachDebugger(DebugHandler debugger) { - if (this.debugger != null) return false; + public boolean attachDebugger(DebugHandler debugger) { + if (this.debugger != null) return false; - if (sources != null) { - for (var source : sources.entrySet()) debugger.onSourceLoad(source.getKey(), source.getValue()); - } - if (maps != null) { - for (var map : maps.entrySet()) debugger.onFunctionLoad(map.getKey(), map.getValue()); - } + if (sources != null) { + for (var source : sources.entrySet()) debugger.onSourceLoad(source.getKey(), source.getValue()); + } + if (maps != null) { + for (var map : maps.entrySet()) debugger.onFunctionLoad(map.getKey(), map.getValue()); + } - this.debugger = debugger; - return true; - } - public boolean detachDebugger(DebugHandler debugger) { - if (this.debugger != debugger) return false; - return detachDebugger(); - } - public boolean detachDebugger() { - this.debugger = null; - return true; - } + this.debugger = debugger; + return true; + } + public boolean detachDebugger(DebugHandler debugger) { + if (this.debugger != debugger) return false; + return detachDebugger(); + } + public boolean detachDebugger() { + this.debugger = null; + return true; + } - public DebugHandler debugger() { - return debugger; - } + public DebugHandler debugger() { + return debugger; + } - public FunctionMap getMap(FunctionBody func) { - if (maps == null) return null; - return maps.get(func); - } - public FunctionMap getMap(FunctionValue func) { - if (maps == null || !(func instanceof CodeFunction)) return null; - return getMap(((CodeFunction)func).body); - } - public FunctionMap getMapOrEmpty(FunctionBody func) { - if (maps == null) return FunctionMap.EMPTY; - var res = maps.get(func); - if (res == null) return FunctionMap.EMPTY; - else return res; - } - public FunctionMap getMapOrEmpty(FunctionValue func) { - if (maps == null || !(func instanceof CodeFunction)) return FunctionMap.EMPTY; - return getMapOrEmpty(((CodeFunction)func).body); - } - public List getStackFrames() { - if (debugger == null) return Arrays.asList(); - return this.debugger.getStackFrame(); - } + public FunctionMap getMap(FunctionBody func) { + if (maps == null) return null; + return maps.get(func); + } + public FunctionMap getMap(FunctionValue func) { + if (maps == null || !(func instanceof CodeFunction)) return null; + return getMap(((CodeFunction)func).body); + } + public FunctionMap getMapOrEmpty(FunctionBody func) { + if (maps == null) return FunctionMap.EMPTY; + var res = maps.get(func); + if (res == null) return FunctionMap.EMPTY; + else return res; + } + public FunctionMap getMapOrEmpty(FunctionValue func) { + if (maps == null || !(func instanceof CodeFunction)) return FunctionMap.EMPTY; + return getMapOrEmpty(((CodeFunction)func).body); + } + public List getStackFrames() { + if (debugger == null) return Arrays.asList(); + return this.debugger.getStackFrame(); + } - public void onFramePop(Environment env, Frame frame) { - if (debugger != null) debugger.onFramePop(env, frame); - } - public void onFramePush(Environment env, Frame frame) { - if (debugger != null) debugger.onFramePush(env, frame); - } + public void onFramePop(Environment env, Frame frame) { + if (debugger != null) debugger.onFramePop(env, frame); + } + public void onFramePush(Environment env, Frame frame) { + if (debugger != null) debugger.onFramePush(env, frame); + } - public boolean onInstruction(Environment env, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) { - if (debugger != null) return debugger.onInstruction(env, frame, instruction, returnVal, error, caught); - else return false; - } - public boolean onInstruction(Environment env, Frame frame, Instruction instruction) { - if (debugger != null) return debugger.onInstruction(env, frame, instruction, null, null, false); - else return false; - } - public void onSource(Filename filename, String source) { - if (debugger != null) debugger.onSourceLoad(filename, source); - if (sources != null) sources.put(filename, source); - } - public void onFunctionLoad(FunctionBody func, FunctionMap map) { - if (maps != null) maps.put(func, map); - if (debugger != null) debugger.onFunctionLoad(func, map); - } + public boolean onInstruction(Environment env, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) { + if (debugger != null) return debugger.onInstruction(env, frame, instruction, returnVal, error, caught); + else return false; + } + public boolean onInstruction(Environment env, Frame frame, Instruction instruction) { + if (debugger != null) return debugger.onInstruction(env, frame, instruction, null, null, false); + else return false; + } + public void onSource(Filename filename, String source) { + if (debugger != null) debugger.onSourceLoad(filename, source); + if (sources != null) sources.put(filename, source); + } + public void onFunctionLoad(FunctionBody func, FunctionMap map) { + if (maps != null) maps.put(func, map); + if (debugger != null) debugger.onFunctionLoad(func, map); + } - private DebugContext(boolean enabled) { - if (enabled) { - sources = new HashMap<>(); - maps = new WeakHashMap<>(); - } - } + private DebugContext(boolean enabled) { + if (enabled) { + sources = new HashMap<>(); + maps = new WeakHashMap<>(); + } + } - public DebugContext() { - this(true); - } + public DebugContext() { + this(true); + } - public static boolean enabled(Environment exts) { - return exts != null && exts.hasNotNull(KEY) && !exts.has(IGNORE); - } - public static DebugContext get(Environment exts) { - if (enabled(exts)) return exts.get(KEY); - else return new DebugContext(false); - } + public static boolean enabled(Environment exts) { + return exts != null && exts.hasNotNull(KEY) && !exts.has(IGNORE); + } + public static DebugContext get(Environment exts) { + if (enabled(exts)) return exts.get(KEY); + else return new DebugContext(false); + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/debug/DebugHandler.java b/src/main/java/me/topchetoeu/jscript/runtime/debug/DebugHandler.java index cd7478a..28afcc7 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/debug/DebugHandler.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/debug/DebugHandler.java @@ -11,49 +11,49 @@ import me.topchetoeu.jscript.runtime.Frame; import me.topchetoeu.jscript.runtime.exceptions.EngineException; public interface DebugHandler { - /** - * Called when a script has been loaded - * @param filename The name of the source - * @param source The name of the source - * @param breakpoints A set of all the breakpointable locations in this source - * @param map The source map associated with this file. null if this source map isn't mapped - */ - void onSourceLoad(Filename filename, String source); + /** + * Called when a script has been loaded + * @param filename The name of the source + * @param source The name of the source + * @param breakpoints A set of all the breakpointable locations in this source + * @param map The source map associated with this file. null if this source map isn't mapped + */ + void onSourceLoad(Filename filename, String source); - /** - * Called when a function body has been loaded - * @param body The body loaded - * @param map The map of the function - */ - void onFunctionLoad(FunctionBody body, FunctionMap map); + /** + * Called when a function body has been loaded + * @param body The body loaded + * @param map The map of the function + */ + void onFunctionLoad(FunctionBody body, FunctionMap map); - /** - * Called immediatly before an instruction is executed, as well as after an instruction, if it has threw or returned. - * This function might pause in order to await debugging commands. - * @param env The context of execution - * @param frame The frame in which execution is occuring - * @param instruction The instruction which was or will be executed - * @param returnVal The return value of the instruction, Values.NO_RETURN if none - * @param error The error that the instruction threw, null if none - * @param caught Whether or not the error has been caught - * @return Whether or not the frame should restart (currently does nothing) - */ - boolean onInstruction(Environment env, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught); + /** + * Called immediatly before an instruction is executed, as well as after an instruction, if it has threw or returned. + * This function might pause in order to await debugging commands. + * @param env The context of execution + * @param frame The frame in which execution is occuring + * @param instruction The instruction which was or will be executed + * @param returnVal The return value of the instruction, Values.NO_RETURN if none + * @param error The error that the instruction threw, null if none + * @param caught Whether or not the error has been caught + * @return Whether or not the frame should restart (currently does nothing) + */ + boolean onInstruction(Environment env, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught); - /** - * Called immediatly before a frame has been pushed on the frame stack. - * This function might pause in order to await debugging commands. - * @param env The context of execution - * @param frame The code frame which was pushed - */ - void onFramePush(Environment env, Frame frame); - /** - * Called immediatly after a frame has been popped out of the frame stack. - * This function might pause in order to await debugging commands. - * @param env The context of execution - * @param frame The code frame which was popped out - */ - void onFramePop(Environment env, Frame frame); + /** + * Called immediatly before a frame has been pushed on the frame stack. + * This function might pause in order to await debugging commands. + * @param env The context of execution + * @param frame The code frame which was pushed + */ + void onFramePush(Environment env, Frame frame); + /** + * Called immediatly after a frame has been popped out of the frame stack. + * This function might pause in order to await debugging commands. + * @param env The context of execution + * @param frame The code frame which was popped out + */ + void onFramePop(Environment env, Frame frame); - List getStackFrame(); + List getStackFrame(); } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/exceptions/EngineException.java b/src/main/java/me/topchetoeu/jscript/runtime/exceptions/EngineException.java index c89314b..eace8cb 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/exceptions/EngineException.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/exceptions/EngineException.java @@ -12,116 +12,116 @@ import me.topchetoeu.jscript.runtime.values.primitives.StringValue; import me.topchetoeu.jscript.runtime.values.primitives.VoidValue; public class EngineException extends RuntimeException { - public static class StackElement { - public final Location location; - public final String name; - public final Environment ext; + public static class StackElement { + public final Location location; + public final String name; + public final Environment ext; - public boolean visible() { - return ext == null || !ext.get(Value.HIDE_STACK, false); - } - public String toString() { - var res = ""; - var loc = location; + public boolean visible() { + return ext == null || !ext.get(Value.HIDE_STACK, false); + } + public String toString() { + var res = ""; + var loc = location; - if (loc != null) res += "at " + loc.toString() + " "; - if (name != null && !name.equals("")) res += "in " + name + " "; + if (loc != null) res += "at " + loc.toString() + " "; + if (name != null && !name.equals("")) res += "in " + name + " "; - return res.trim(); - } + return res.trim(); + } - public StackElement(Environment ext, Location location, String name) { - if (name != null) name = name.trim(); - if (name.equals("")) name = null; + public StackElement(Environment ext, Location location, String name) { + if (name != null) name = name.trim(); + if (name.equals("")) name = null; - if (ext == null) this.ext = null; - else this.ext = ext; + if (ext == null) this.ext = null; + else this.ext = ext; - this.location = location; - this.name = name; - } - } + this.location = location; + this.name = name; + } + } - public final Value value; - public EngineException cause; - public Environment env = null; - public final List stackTrace = new ArrayList<>(); + public final Value value; + public EngineException cause; + public Environment env = null; + public final List stackTrace = new ArrayList<>(); - public EngineException add(Environment env, String name, Location location) { - var el = new StackElement(env, location, name); - if (el.name == null && el.location == null) return this; - setEnvironment(env); - stackTrace.add(el); - return this; - } - public EngineException setCause(EngineException cause) { - this.cause = cause; - return this; - } - public EngineException setEnvironment(Environment env) { - if (this.env == null) this.env = env; - return this; - } + public EngineException add(Environment env, String name, Location location) { + var el = new StackElement(env, location, name); + if (el.name == null && el.location == null) return this; + setEnvironment(env); + stackTrace.add(el); + return this; + } + public EngineException setCause(EngineException cause) { + this.cause = cause; + return this; + } + public EngineException setEnvironment(Environment env) { + if (this.env == null) this.env = env; + return this; + } - public String toString(Environment env) { - var ss = new StringBuilder(); - try { - ss.append(value.toString(env)).append('\n'); - } - catch (EngineException e) { - var name = value.getMember(env, "name"); - var desc = value.getMember(env, "message"); + public String toString(Environment env) { + var ss = new StringBuilder(); + try { + ss.append(value.toString(env)).append('\n'); + } + catch (EngineException e) { + var name = value.getMember(env, "name"); + var desc = value.getMember(env, "message"); - if (name.isPrimitive() && desc.isPrimitive()) { - if (name instanceof VoidValue) ss.append("Error: "); - else ss.append(name.toString(env) + ": "); + if (name.isPrimitive() && desc.isPrimitive()) { + if (name instanceof VoidValue) ss.append("Error: "); + else ss.append(name.toString(env) + ": "); - if (desc instanceof VoidValue) ss.append("An error occurred"); - else ss.append(desc.toString(env)); + if (desc instanceof VoidValue) ss.append("An error occurred"); + else ss.append(desc.toString(env)); - ss.append("\n"); - } - else ss.append("[Error while stringifying]\n"); - } - for (var line : stackTrace) { - if (line.visible()) ss.append(" ").append(line.toString()).append("\n"); - } - if (cause != null) ss.append("Caused by ").append(cause.toString(env)).append('\n'); - ss.deleteCharAt(ss.length() - 1); - return ss.toString(); - } + ss.append("\n"); + } + else ss.append("[Error while stringifying]\n"); + } + for (var line : stackTrace) { + if (line.visible()) ss.append(" ").append(line.toString()).append("\n"); + } + if (cause != null) ss.append("Caused by ").append(cause.toString(env)).append('\n'); + ss.deleteCharAt(ss.length() - 1); + return ss.toString(); + } - private static ObjectValue err(String name, String msg, PrototypeProvider proto) { - var res = new ObjectValue(); - res.setPrototype(proto); + private static ObjectValue err(String name, String msg, PrototypeProvider proto) { + var res = new ObjectValue(); + res.setPrototype(proto); - if (msg == null) msg = ""; + if (msg == null) msg = ""; - if (name != null) res.defineOwnMember(Environment.empty(), "name", StringValue.of(name)); - res.defineOwnMember(Environment.empty(), "message", StringValue.of(msg)); - return res; - } + if (name != null) res.defineOwnMember(Environment.empty(), "name", StringValue.of(name)); + res.defineOwnMember(Environment.empty(), "message", StringValue.of(msg)); + return res; + } - public EngineException(Value error) { - super(error.toReadable(Environment.empty())); + public EngineException(Value error) { + super(error.toReadable(Environment.empty())); - this.value = error; - this.cause = null; - } + this.value = error; + this.cause = null; + } - public static EngineException ofError(String name, String msg) { - return new EngineException(err(name, msg, env -> env.get(Value.ERROR_PROTO))); - } - public static EngineException ofError(String msg) { - return new EngineException(err(null, msg, env -> env.get(Value.ERROR_PROTO))); - } - public static EngineException ofSyntax(String msg) { - return new EngineException(err(null, msg, env -> env.get(Value.SYNTAX_ERR_PROTO))); - } - public static EngineException ofType(String msg) { - return new EngineException(err(null, msg, env -> env.get(Value.TYPE_ERR_PROTO))); - } - public static EngineException ofRange(String msg) { - return new EngineException(err(null, msg, env -> env.get(Value.RANGE_ERR_PROTO))); - } + public static EngineException ofError(String name, String msg) { + return new EngineException(err(name, msg, env -> env.get(Value.ERROR_PROTO))); + } + public static EngineException ofError(String msg) { + return new EngineException(err(null, msg, env -> env.get(Value.ERROR_PROTO))); + } + public static EngineException ofSyntax(String msg) { + return new EngineException(err(null, msg, env -> env.get(Value.SYNTAX_ERR_PROTO))); + } + public static EngineException ofType(String msg) { + return new EngineException(err(null, msg, env -> env.get(Value.TYPE_ERR_PROTO))); + } + public static EngineException ofRange(String msg) { + return new EngineException(err(null, msg, env -> env.get(Value.RANGE_ERR_PROTO))); + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/KeyCache.java b/src/main/java/me/topchetoeu/jscript/runtime/values/KeyCache.java index 4d70dd5..c564511 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/KeyCache.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/KeyCache.java @@ -6,67 +6,67 @@ import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public final class KeyCache { - public final Value value; - private boolean isInt; - private int intCache; - private Double doubleCache; - private Boolean booleanCache; - private String stringCache; + public final Value value; + private boolean isInt; + private int intCache; + private Double doubleCache; + private Boolean booleanCache; + private String stringCache; - public String toString(Environment env) { - if (stringCache != null) return stringCache; - else return stringCache = value.toString(env); - } - public double toNumber(Environment env) { - if (doubleCache == null) { - var res = value.toNumber(env); - isInt = res.isInt(); - intCache = res.getInt(); - doubleCache = res.getDouble(); - } + public String toString(Environment env) { + if (stringCache != null) return stringCache; + else return stringCache = value.toString(env); + } + public double toNumber(Environment env) { + if (doubleCache == null) { + var res = value.toNumber(env); + isInt = res.isInt(); + intCache = res.getInt(); + doubleCache = res.getDouble(); + } - return doubleCache; - } - public boolean isInt(Environment env) { - if (doubleCache == null) toNumber(env); - return isInt; - } - public int toInt(Environment env) { - if (doubleCache == null) toNumber(env); - return intCache; - } - public boolean toBoolean() { - if (booleanCache != null) return booleanCache; - else return booleanCache = value.toBoolean(); - } - public SymbolValue toSymbol() { - if (value instanceof SymbolValue) return (SymbolValue)value; - else return null; - } - public boolean isSymbol() { - return value instanceof SymbolValue; - } + return doubleCache; + } + public boolean isInt(Environment env) { + if (doubleCache == null) toNumber(env); + return isInt; + } + public int toInt(Environment env) { + if (doubleCache == null) toNumber(env); + return intCache; + } + public boolean toBoolean() { + if (booleanCache != null) return booleanCache; + else return booleanCache = value.toBoolean(); + } + public SymbolValue toSymbol() { + if (value instanceof SymbolValue) return (SymbolValue)value; + else return null; + } + public boolean isSymbol() { + return value instanceof SymbolValue; + } - public KeyCache(Value value) { - this.value = value; - } - public KeyCache(String value) { - this.value = StringValue.of(value); - this.stringCache = value; - this.booleanCache = !value.equals(""); - } - public KeyCache(int value) { - this.value = NumberValue.of(value); - this.isInt = true; - this.intCache = value; - this.doubleCache = (double)value; - this.booleanCache = value != 0; - } - public KeyCache(double value) { - this.value = NumberValue.of(value); - this.isInt = (int)value == value; - this.intCache = (int)value; - this.doubleCache = value; - this.booleanCache = value != 0; - } + public KeyCache(Value value) { + this.value = value; + } + public KeyCache(String value) { + this.value = StringValue.of(value); + this.stringCache = value; + this.booleanCache = !value.equals(""); + } + public KeyCache(int value) { + this.value = NumberValue.of(value); + this.isInt = true; + this.intCache = value; + this.doubleCache = (double)value; + this.booleanCache = value != 0; + } + public KeyCache(double value) { + this.value = NumberValue.of(value); + this.isInt = (int)value == value; + this.intCache = (int)value; + this.doubleCache = value; + this.booleanCache = value != 0; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/Member.java b/src/main/java/me/topchetoeu/jscript/runtime/values/Member.java index 9e3d964..91efadf 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/Member.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/Member.java @@ -6,168 +6,168 @@ import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; import me.topchetoeu.jscript.runtime.values.primitives.BoolValue; public interface Member { - public static final class PropertyMember implements Member { - public final Value self; - public FunctionValue getter; - public FunctionValue setter; - public boolean configurable; - public boolean enumerable; + public static final class PropertyMember implements Member { + public final Value self; + public FunctionValue getter; + public FunctionValue setter; + public boolean configurable; + public boolean enumerable; - @Override public Value get(Environment env, Value self) { - if (getter != null) return getter.apply(env, self); - else return Value.UNDEFINED; - } - @Override public boolean set(Environment env, Value val, Value self) { - if (setter == null) return false; - setter.apply(env, self, val); - return true; - } + @Override public Value get(Environment env, Value self) { + if (getter != null) return getter.apply(env, self); + else return Value.UNDEFINED; + } + @Override public boolean set(Environment env, Value val, Value self) { + if (setter == null) return false; + setter.apply(env, self, val); + return true; + } - @Override public boolean configurable() { return configurable && self.getState().configurable; } - @Override public boolean enumerable() { return enumerable; } + @Override public boolean configurable() { return configurable && self.getState().configurable; } + @Override public boolean enumerable() { return enumerable; } - @Override public boolean redefine(Environment env, Member newMember, Value self) { - // If the given member isn't a property, we can't redefine - if (!(newMember instanceof PropertyMember prop)) return false; + @Override public boolean redefine(Environment env, Member newMember, Value self) { + // If the given member isn't a property, we can't redefine + if (!(newMember instanceof PropertyMember prop)) return false; - if (configurable()) { - // We will overlay the getters and setters of the new member - enumerable = prop.enumerable; - configurable = prop.configurable; + if (configurable()) { + // We will overlay the getters and setters of the new member + enumerable = prop.enumerable; + configurable = prop.configurable; - if (prop.getter != null) getter = prop.getter; - if (prop.setter != null) setter = prop.setter; + if (prop.getter != null) getter = prop.getter; + if (prop.setter != null) setter = prop.setter; - return true; - } - else { - // We will pretend that a redefinition has occurred if the two members match exactly - if (prop.configurable() != configurable()) return false; - if (prop.enumerable != enumerable) return false; - if (prop.getter != getter || prop.setter != setter) return false; + return true; + } + else { + // We will pretend that a redefinition has occurred if the two members match exactly + if (prop.configurable() != configurable()) return false; + if (prop.enumerable != enumerable) return false; + if (prop.getter != getter || prop.setter != setter) return false; - return true; - } - } + return true; + } + } - @Override public ObjectValue descriptor(Environment env, Value self) { - var res = new ObjectValue(); + @Override public ObjectValue descriptor(Environment env, Value self) { + var res = new ObjectValue(); - // Don't touch the ordering, as it's emulating V8 + // Don't touch the ordering, as it's emulating V8 - if (getter == null) res.defineOwnMember(env, "getter", Value.UNDEFINED); - else res.defineOwnMember(env, "getter", getter); + if (getter == null) res.defineOwnMember(env, "getter", Value.UNDEFINED); + else res.defineOwnMember(env, "getter", getter); - if (setter == null) res.defineOwnMember(env, "setter", Value.UNDEFINED); - else res.defineOwnMember(env, "setter", setter); + if (setter == null) res.defineOwnMember(env, "setter", Value.UNDEFINED); + else res.defineOwnMember(env, "setter", setter); - res.defineOwnMember(env, "enumerable", BoolValue.of(enumerable)); - res.defineOwnMember(env, "configurable", BoolValue.of(configurable)); - return res; - } + res.defineOwnMember(env, "enumerable", BoolValue.of(enumerable)); + res.defineOwnMember(env, "configurable", BoolValue.of(configurable)); + return res; + } - public PropertyMember(Value self, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) { - this.self = self; - this.getter = getter; - this.setter = setter; - this.configurable = configurable; - this.enumerable = enumerable; - } - } + public PropertyMember(Value self, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) { + this.self = self; + this.getter = getter; + this.setter = setter; + this.configurable = configurable; + this.enumerable = enumerable; + } + } - public static abstract class FieldMember implements Member { - private static class SimpleFieldMember extends FieldMember { - public Value value; + public static abstract class FieldMember implements Member { + private static class SimpleFieldMember extends FieldMember { + public Value value; - @Override public Value get(Environment env, Value self) { return value; } - @Override public boolean set(Environment env, Value val, Value self) { - if (!writable) return false; - value = val; - return true; - } - public SimpleFieldMember(Value self, Value value, boolean configurable, boolean enumerable, boolean writable) { - super(self, configurable, enumerable, writable); - this.value = value; - } - } + @Override public Value get(Environment env, Value self) { return value; } + @Override public boolean set(Environment env, Value val, Value self) { + if (!writable) return false; + value = val; + return true; + } + public SimpleFieldMember(Value self, Value value, boolean configurable, boolean enumerable, boolean writable) { + super(self, configurable, enumerable, writable); + this.value = value; + } + } - public final Value self; - public boolean configurable; - public boolean enumerable; - public boolean writable; + public final Value self; + public boolean configurable; + public boolean enumerable; + public boolean writable; - @Override public final boolean configurable() { return configurable && self.getState().configurable; } - @Override public final boolean enumerable() { return enumerable; } - public final boolean writable() { return writable && self.getState().writable; } + @Override public final boolean configurable() { return configurable && self.getState().configurable; } + @Override public final boolean enumerable() { return enumerable; } + public final boolean writable() { return writable && self.getState().writable; } - @Override public final boolean redefine(Environment env, Member newMember, Value self) { - // If the given member isn't a field, we can't redefine - if (!(newMember instanceof FieldMember field)) return false; + @Override public final boolean redefine(Environment env, Member newMember, Value self) { + // If the given member isn't a field, we can't redefine + if (!(newMember instanceof FieldMember field)) return false; - if (configurable()) { - configurable = field.configurable; - enumerable = field.enumerable; - writable = field.enumerable; + if (configurable()) { + configurable = field.configurable; + enumerable = field.enumerable; + writable = field.enumerable; - // We will try to set a new value. However, the underlying field might be immutably readonly - // In such case, we will silently fail, since this is not covered by the specification - if (!set(env, field.get(env, self), self)) writable = false; - return true; - } - else { - // New field settings must be an exact match - if (configurable() != field.configurable()) return false; - if (enumerable() != field.enumerable()) return false; + // We will try to set a new value. However, the underlying field might be immutably readonly + // In such case, we will silently fail, since this is not covered by the specification + if (!set(env, field.get(env, self), self)) writable = false; + return true; + } + else { + // New field settings must be an exact match + if (configurable() != field.configurable()) return false; + if (enumerable() != field.enumerable()) return false; - if (!writable()) { - // If the field isn't writable, the redefinition should be an exact match - if (field.writable()) return false; - if (field.get(env, self).equals(this.get(env, self))) return false; + if (!writable()) { + // If the field isn't writable, the redefinition should be an exact match + if (field.writable()) return false; + if (field.get(env, self).equals(this.get(env, self))) return false; - return true; - } - else { - // Writable non-configurable fields may be made readonly or their values may be changed - writable = field.writable; + return true; + } + else { + // Writable non-configurable fields may be made readonly or their values may be changed + writable = field.writable; - if (!set(env, field.get(env, self), self)) writable = false; - return true; - } - } - } + if (!set(env, field.get(env, self), self)) writable = false; + return true; + } + } + } - @Override public ObjectValue descriptor(Environment env, Value self) { - var res = new ObjectValue(); - res.defineOwnMember(env, "value", get(env, self)); - res.defineOwnMember(env, "writable", BoolValue.of(writable)); - res.defineOwnMember(env, "enumerable", BoolValue.of(enumerable)); - res.defineOwnMember(env, "configurable", BoolValue.of(configurable)); - return res; - } + @Override public ObjectValue descriptor(Environment env, Value self) { + var res = new ObjectValue(); + res.defineOwnMember(env, "value", get(env, self)); + res.defineOwnMember(env, "writable", BoolValue.of(writable)); + res.defineOwnMember(env, "enumerable", BoolValue.of(enumerable)); + res.defineOwnMember(env, "configurable", BoolValue.of(configurable)); + return res; + } - public FieldMember(Value self, boolean configurable, boolean enumerable, boolean writable) { - this.self = self; - this.configurable = configurable; - this.enumerable = enumerable; - this.writable = writable; - } + public FieldMember(Value self, boolean configurable, boolean enumerable, boolean writable) { + this.self = self; + this.configurable = configurable; + this.enumerable = enumerable; + this.writable = writable; + } - public static FieldMember of(Value self, Value value) { - return new SimpleFieldMember(self, value, true, true, true); - } - public static FieldMember of(Value self, Value value, boolean writable) { - return new SimpleFieldMember(self, value, true, true, writable); - } - public static FieldMember of(Value self, Value value, boolean configurable, boolean enumerable, boolean writable) { - return new SimpleFieldMember(self, value, configurable, enumerable, writable); - } - } + public static FieldMember of(Value self, Value value) { + return new SimpleFieldMember(self, value, true, true, true); + } + public static FieldMember of(Value self, Value value, boolean writable) { + return new SimpleFieldMember(self, value, true, true, writable); + } + public static FieldMember of(Value self, Value value, boolean configurable, boolean enumerable, boolean writable) { + return new SimpleFieldMember(self, value, configurable, enumerable, writable); + } + } - public boolean configurable(); - public boolean enumerable(); - public boolean redefine(Environment env, Member newMember, Value self); - public ObjectValue descriptor(Environment env, Value self); + public boolean configurable(); + public boolean enumerable(); + public boolean redefine(Environment env, Member newMember, Value self); + public ObjectValue descriptor(Environment env, Value self); - public Value get(Environment env, Value self); - public boolean set(Environment env, Value val, Value self); + public Value get(Environment env, Value self); + public boolean set(Environment env, Value val, Value self); } \ No newline at end of file diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/Value.java b/src/main/java/me/topchetoeu/jscript/runtime/values/Value.java index dc7f293..81758e4 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/Value.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/Value.java @@ -30,625 +30,625 @@ import me.topchetoeu.jscript.runtime.values.primitives.VoidValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public abstract class Value { - public static enum State { - NORMAL(true, true, true), - NON_EXTENDABLE(false, true, true), - SEALED(false, false, true), - FROZEN(false, false, false); + public static enum State { + NORMAL(true, true, true), + NON_EXTENDABLE(false, true, true), + SEALED(false, false, true), + FROZEN(false, false, false); - public final boolean extendable; - public final boolean configurable; - public final boolean writable; + public final boolean extendable; + public final boolean configurable; + public final boolean writable; - private State(boolean extendable, boolean configurable, boolean writable) { - this.extendable = extendable; - this.writable = writable; - this.configurable = configurable; - } - } - - public static final Key REGEX_CONSTR = Key.of(); - - public static final Key MAX_STACK_COUNT = Key.of(); - public static final Key HIDE_STACK = Key.of(); - - public static final Key BOOL_PROTO = Key.of(); - public static final Key NUMBER_PROTO = Key.of(); - public static final Key STRING_PROTO = Key.of(); - public static final Key SYMBOL_PROTO = Key.of(); - - public static final Key OBJECT_PROTO = Key.of(); - public static final Key FUNCTION_PROTO = Key.of(); - - public static final Key ARRAY_PROTO = Key.of(); - public static final Key BYTE_BUFF_PROTO = Key.of(); - - public static final Key ERROR_PROTO = Key.of(); - public static final Key SYNTAX_ERR_PROTO = Key.of(); - public static final Key TYPE_ERR_PROTO = Key.of(); - public static final Key RANGE_ERR_PROTO = Key.of(); - - public static final Key GLOBAL = Key.of(); - public static final Key> INTRINSICS = Key.of(); - - public static final VoidValue UNDEFINED = new VoidValue("undefined", "undefined"); - public static final VoidValue NULL = new VoidValue("null", "object"); - - public abstract StringValue type(); - public abstract boolean isPrimitive(); - - public final boolean isNaN() { - return this == NumberValue.NAN || this instanceof NumberValue num && Double.isNaN(num.getDouble()); - } - - public Value apply(Environment env, Value self, Value ...args) { - throw EngineException.ofType("Value is not a function"); - } - public Value construct(Environment env, Value self, Value ...args) { - throw EngineException.ofType("Value is not a constructor"); + private State(boolean extendable, boolean configurable, boolean writable) { + this.extendable = extendable; + this.writable = writable; + this.configurable = configurable; + } } - public final Value construct(Environment env, Value ...args) { - var res = new ObjectValue(); - var proto = getMember(env, StringValue.of("prototype")); - - if (proto instanceof ObjectValue) res.setPrototype(env, (ObjectValue)proto); - - var ret = this.construct(env, res, args); - - if (ret == Value.UNDEFINED || ret.isPrimitive()) return res; - return ret; - } - - - public abstract Value toPrimitive(Environment env); - public abstract NumberValue toNumber(Environment env); - public abstract String toString(Environment env); - public abstract boolean toBoolean(); - - public final boolean isInstanceOf(Environment env, Value proto) { - for (var val = getPrototype(env); val != null; val = val.getPrototype(env)) { - if (val.equals(proto)) return true; - } - - return false; - } - - public abstract Member getOwnMember(Environment env, KeyCache key); - public abstract Set getOwnMembers(Environment env, boolean onlyEnumerable); - public abstract Set getOwnSymbolMembers(Environment env, boolean onlyEnumerable); - public abstract boolean defineOwnMember(Environment env, KeyCache key, Member member); - public abstract boolean deleteOwnMember(Environment env, KeyCache key); - - public abstract ObjectValue getPrototype(Environment env); - public abstract boolean setPrototype(Environment env, ObjectValue val); - - public abstract State getState(); - - public abstract void preventExtensions(); - public abstract void seal(); - public abstract void freeze(); - - public final Member getOwnMember(Environment env, Value key) { - return getOwnMember(env, new KeyCache(key)); - } - public final Member getOwnMember(Environment env, String key) { - return getOwnMember(env, new KeyCache(key)); - } - public final Member getOwnMember(Environment env, int key) { - return getOwnMember(env, new KeyCache(key)); - } - public final Member getOwnMember(Environment env, double key) { - return getOwnMember(env, new KeyCache(key)); - } - - public final boolean defineOwnMember(Environment env, Value key, Member member) { - return defineOwnMember(env, new KeyCache(key), member); - } - public final boolean defineOwnMember(Environment env, String key, Member member) { - return defineOwnMember(env, new KeyCache(key), member); - } - public final boolean defineOwnMember(Environment env, int key, Member member) { - return defineOwnMember(env, new KeyCache(key), member); - } - public final boolean defineOwnMember(Environment env, double key, Member member) { - return defineOwnMember(env, new KeyCache(key), member); - } - - public final boolean defineOwnMember(Environment env, KeyCache key, Value val) { - return defineOwnMember(env, key, FieldMember.of(this, val)); - } - public final boolean defineOwnMember(Environment env, Value key, Value val) { - return defineOwnMember(env, new KeyCache(key), val); - } - public final boolean defineOwnMember(Environment env, String key, Value val) { - return defineOwnMember(env, new KeyCache(key), val); - } - public final boolean defineOwnMember(Environment env, int key, Value val) { - return defineOwnMember(env, new KeyCache(key), val); - } - public final boolean defineOwnMember(Environment env, double key, Value val) { - return defineOwnMember(env, new KeyCache(key), val); - } - - public final boolean deleteOwnMember(Environment env, Value key) { - return deleteOwnMember(env, new KeyCache(key)); - } - public final boolean deleteOwnMember(Environment env, String key) { - return deleteOwnMember(env, new KeyCache(key)); - } - public final boolean deleteOwnMember(Environment env, int key) { - return deleteOwnMember(env, new KeyCache(key)); - } - public final boolean deleteOwnMember(Environment env, double key) { - return deleteOwnMember(env, new KeyCache(key)); - } - - public final Value getMemberOrNull(Environment env, KeyCache key) { - for (Value obj = this; obj != null; obj = obj.getPrototype(env)) { - var member = obj.getOwnMember(env, key); - if (member != null) return member.get(env, this); - } - - return null; - } - public final Value getMemberOrNull(Environment env, Value key) { - return getMemberOrNull(env, new KeyCache(key)); - } - public final Value getMemberOrNull(Environment env, String key) { - return getMemberOrNull(env, new KeyCache(key)); - } - public final Value getMemberOrNull(Environment env, int key) { - return getMemberOrNull(env, new KeyCache(key)); - } - public final Value getMemberOrNull(Environment env, double key) { - return getMemberOrNull(env, new KeyCache(key)); - } - - public final Value getMember(Environment env, KeyCache key) { - var res = getMemberOrNull(env, key); - if (res != null) return res; - else return Value.UNDEFINED; - } - public final Value getMember(Environment env, Value key) { - return getMember(env, new KeyCache(key)); - } - public final Value getMember(Environment env, String key) { - return getMember(env, new KeyCache(key)); - } - public final Value getMember(Environment env, int key) { - return getMember(env, new KeyCache(key)); - } - public final Value getMember(Environment env, double key) { - return getMember(env, new KeyCache(key)); - } - - public final boolean setMember(Environment env, KeyCache key, Value val) { - for (Value obj = this; obj != null; obj = obj.getPrototype(env)) { - var member = obj.getOwnMember(env, key); - if (member != null && (member instanceof PropertyMember || obj == this)) { - if (member.set(env, val, this)) { - if (val instanceof FunctionValue) ((FunctionValue)val).setName(key.toString(env)); - return true; - } - else return false; - } - } - - if (defineOwnMember(env, key, val)) { - if (val instanceof FunctionValue) ((FunctionValue)val).setName(key.toString(env)); - return true; - } - else return false; - } - public final boolean setMember(Environment env, Value key, Value val) { - return setMember(env, new KeyCache(key), val); - } - public final boolean setMember(Environment env, String key, Value val) { - return setMember(env, new KeyCache(key), val); - } - public final boolean setMember(Environment env, int key, Value val) { - return setMember(env, new KeyCache(key), val); - } - public final boolean setMember(Environment env, double key, Value val) { - return setMember(env, new KeyCache(key), val); - } - - public final boolean setMemberIfExists(Environment env, KeyCache key, Value val) { - for (Value obj = this; obj != null; obj = obj.getPrototype(env)) { - var member = obj.getOwnMember(env, key); - if (member != null) { - if (member.set(env, val, obj)) { - if (val instanceof FunctionValue) ((FunctionValue)val).setName(key.toString(env)); - return true; - } - else return false; - } - } - - return false; - } - public final boolean setMemberIfExists(Environment env, Value key, Value val) { - return setMemberIfExists(env, new KeyCache(key), val); - } - public final boolean setMemberIfExists(Environment env, String key, Value val) { - return setMemberIfExists(env, new KeyCache(key), val); - } - public final boolean setMemberIfExists(Environment env, int key, Value val) { - return setMemberIfExists(env, new KeyCache(key), val); - } - public final boolean setMemberIfExists(Environment env, double key, Value val) { - return setMemberIfExists(env, new KeyCache(key), val); - } - - public final boolean hasMember(Environment env, KeyCache key, boolean own) { - for (Value obj = this; obj != null; obj = obj.getPrototype(env)) { - if (obj.getOwnMember(env, key) != null) return true; - if (own) return false; - } - - return false; - } - public final boolean hasMember(Environment env, Value key, boolean own) { - return hasMember(env, new KeyCache(key), own); - } - public final boolean hasMember(Environment env, String key, boolean own) { - return hasMember(env, new KeyCache(key), own); - } - public final boolean hasMember(Environment env, int key, boolean own) { - return hasMember(env, new KeyCache(key), own); - } - public final boolean hasMember(Environment env, double key, boolean own) { - return hasMember(env, new KeyCache(key), own); - } - - public final boolean deleteMember(Environment env, KeyCache key) { - if (!hasMember(env, key, true)) return true; - return deleteOwnMember(env, key); - } - public final boolean deleteMember(Environment env, Value key) { - return deleteMember(env, new KeyCache(key)); - } - public final boolean deleteMember(Environment env, String key) { - return deleteMember(env, new KeyCache(key)); - } - public final boolean deleteMember(Environment env, int key) { - return deleteMember(env, new KeyCache(key)); - } - public final boolean deleteMember(Environment env, double key) { - return deleteMember(env, new KeyCache(key)); - } - - public final Set getMembers(Environment env, boolean own, boolean onlyEnumerable) { - var res = new LinkedHashSet(); - var protos = new ArrayList(); - - for (var proto = this; proto != null; proto = proto.getPrototype(env)) { - protos.add(proto); - if (own) break; - } - - Collections.reverse(protos); - - for (var proto : protos) { - res.addAll(proto.getOwnMembers(env, onlyEnumerable)); - } - - return res; - } - public final Set getSymbolMembers(Environment env, boolean own, boolean onlyEnumerable) { - var res = new LinkedHashSet(); - var protos = new ArrayList(); - - for (var proto = this; proto != null; proto = proto.getPrototype(env)) { - protos.add(proto); - if (own) break; - } - - Collections.reverse(protos); - - for (var proto : protos) { - res.addAll(proto.getOwnSymbolMembers(env, onlyEnumerable)); - } - - return res; - } - - public final Value getMemberPath(Environment env, Value ...path) { - var res = this; - for (var key : path) res = res.getMember(env, key); - return res; - } - public final ObjectValue getMemberDescriptor(Environment env, Value key) { - var member = getOwnMember(env, new KeyCache(key)); - - if (member != null) return member.descriptor(env, this); - else return null; - } - - public Iterable toIterable(Environment env) { - return () -> { - if (!(this instanceof FunctionValue)) return Collections.emptyIterator(); - var func = (FunctionValue)this; - - return new Iterator() { - private Object value = null; - public boolean consumed = true; - private FunctionValue supplier = func; - - private void loadNext() { - if (supplier == null) value = null; - else if (consumed) { - var curr = supplier.apply(env, Value.UNDEFINED); - - if (curr == null) { supplier = null; value = null; } - if (curr.getMember(env, StringValue.of("done")).toBoolean()) { supplier = null; value = null; } - else { - this.value = curr.getMember(env, StringValue.of("value")); - consumed = false; - } - } - } - - @Override public boolean hasNext() { - loadNext(); - return supplier != null; - } - @Override public Object next() { - loadNext(); - var res = value; - value = null; - consumed = true; - return res; - } - }; - }; - } - - public void callWith(Environment env, Iterable it) { - for (var el : it) { - this.apply(env, Value.UNDEFINED, el); - } - } - public void callWithAsync(Environment env, Iterable it, boolean async) { - for (var el : it) { - env.get(EventLoop.KEY).pushMsg(() -> this.apply(env, Value.UNDEFINED, el), true); - } - } - - /** @internal */ - public List toReadableLines(Environment env, HashSet passed) { - return Arrays.asList(toString(env)); - } - - public final String toReadable(Environment ext) { - return String.join("\n", toReadableLines(ext, new HashSet<>())); - } - - public static final ObjectValue global(Environment env) { - return env.initFrom(GLOBAL, () -> new ObjectValue()); - } - public static final Map intrinsics(Environment env) { - return env.initFrom(INTRINSICS, () -> new HashMap<>()); - } - - public static FunctionValue fromIterator(Environment ext, Iterable iterable) { - var it = iterable.iterator(); - - return new NativeFunction("", args -> { - var obj = new ObjectValue(); - - if (!it.hasNext()) obj.defineOwnMember(args.env, "done", BoolValue.TRUE); - else obj.defineOwnMember(args.env, "value", it.next()); - - return obj; - }); - } - - public static final boolean lessOrEqual(Environment env, Value a, Value b) { - a = a.toPrimitive(env); - b = b.toPrimitive(env); - - if (a instanceof StringValue aStr && b instanceof StringValue bStr) { - return aStr.value.compareTo(bStr.value) <= 0; - } - else { - var na = a.toNumber(env); - var nb = b.toNumber(env); - - if (na.isLong() && nb.isLong()) return na.getLong() <= nb.getLong(); - else return na.getDouble() <= nb.getDouble(); - } - } - public static final boolean greaterOrEqual(Environment env, Value a, Value b) { - a = a.toPrimitive(env); - b = b.toPrimitive(env); - - if (a instanceof StringValue aStr && b instanceof StringValue bStr) { - return aStr.value.compareTo(bStr.value) >= 0; - } - else { - var na = a.toNumber(env); - var nb = b.toNumber(env); - - if (na.isLong() && nb.isLong()) return na.getLong() >= nb.getLong(); - else return na.getDouble() >= nb.getDouble(); - } - } - public static final boolean less(Environment env, Value a, Value b) { - a = a.toPrimitive(env); - b = b.toPrimitive(env); - - if (a instanceof StringValue aStr && b instanceof StringValue bStr) { - return aStr.value.compareTo(bStr.value) < 0; - } - else { - var na = a.toNumber(env); - var nb = b.toNumber(env); - - if (na.isLong() && nb.isLong()) return na.getLong() < nb.getLong(); - else return na.getDouble() < nb.getDouble(); - } - } - public static final boolean greater(Environment env, Value a, Value b) { - a = a.toPrimitive(env); - b = b.toPrimitive(env); - - if (a instanceof StringValue aStr && b instanceof StringValue bStr) { - return aStr.value.compareTo(bStr.value) > 0; - } - else { - var na = a.toNumber(env); - var nb = b.toNumber(env); - - if (na.isLong() && nb.isLong()) return na.getLong() > nb.getLong(); - else return na.getDouble() > nb.getDouble(); - } - } - - public static final Value add(Environment env, Value a, Value b) { - a = a.toPrimitive(env); - b = b.toPrimitive(env); - - if (a instanceof StringValue || b instanceof StringValue) { - return StringValue.of(a.toString(env) + b.toString(env)); - } - else { - var na = a.toNumber(env); - var nb = b.toNumber(env); - - if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() + nb.getInt()); - else return NumberValue.of(na.getDouble() + nb.getDouble()); - } - } - - public static final NumberValue subtract(Environment env, Value a, Value b) { - var na = a.toNumber(env); - var nb = b.toNumber(env); - - if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() - nb.getInt()); - else return NumberValue.of(na.getDouble() - nb.getDouble()); - } - public static final NumberValue multiply(Environment env, Value a, Value b) { - var na = a.toNumber(env); - var nb = b.toNumber(env); - - if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() * nb.getInt()); - else return NumberValue.of(na.getDouble() * nb.getDouble()); - } - public static final NumberValue divide(Environment env, Value a, Value b) { - var na = a.toNumber(env); - var nb = b.toNumber(env); - - if (na.isInt() && nb.isInt()) { - var ia = na.getInt(); - var ib = nb.getInt(); - - if (ib == 0) { - if (ia == 0) return NumberValue.NAN; - else if (ia > 0) return NumberValue.of(Double.POSITIVE_INFINITY); - else return NumberValue.of(Double.NEGATIVE_INFINITY); - } - else if (ia % ib != 0) return NumberValue.of((double)ia / ib); - else return NumberValue.of(ia / ib); - } - else return NumberValue.of(na.getDouble() / nb.getDouble()); - } - public static final NumberValue modulo(Environment env, Value a, Value b) { - var na = a.toNumber(env); - var nb = b.toNumber(env); - - if (na.isInt() && nb.isInt()) { - var ia = na.getInt(); - var ib = nb.getInt(); - - if (ib == 0) return NumberValue.NAN; - else return NumberValue.of(ia % ib); - } - else return NumberValue.of(na.getDouble() % nb.getDouble()); - } - public static final NumberValue negative(Environment env, Value a) { - var na = a.toNumber(env); - - if (na.isInt()) return NumberValue.of(-na.getInt()); - else return NumberValue.of(-na.getDouble()); - } - - public static final NumberValue and(Environment env, Value a, Value b) { - return NumberValue.of(a.toNumber(env).getInt() & b.toNumber(env).getInt()); - } - public static final NumberValue or(Environment env, Value a, Value b) { - return NumberValue.of(a.toNumber(env).getInt() | b.toNumber(env).getInt()); - } - public static final NumberValue xor(Environment env, Value a, Value b) { - return NumberValue.of(a.toNumber(env).getInt() ^ b.toNumber(env).getInt()); - } - public static final NumberValue bitwiseNot(Environment env, Value a) { - return NumberValue.of(~a.toNumber(env).getInt()); - } - - public static final NumberValue shiftLeft(Environment env, Value a, Value b) { - return NumberValue.of(a.toNumber(env).getInt() << b.toNumber(env).getInt()); - } - public static final NumberValue shiftRight(Environment env, Value a, Value b) { - return NumberValue.of(a.toNumber(env).getInt() >> b.toNumber(env).getInt()); - } - public static final NumberValue unsignedShiftRight(Environment env, Value a, Value b) { - long _a = a.toNumber(env).getLong() & 0xFFFFFFFF; - long _b = b.toNumber(env).getLong() & 0xFFFFFFFF; - - if (_a < 0) _a += 0x100000000l; - if (_b < 0) _b += 0x100000000l; - - return NumberValue.of(_a >>> _b); - } - - public static final boolean looseEqual(Environment env, Value a, Value b) { - // In loose equality, null is equivalent to undefined - if (a instanceof VoidValue || b instanceof VoidValue) return a instanceof VoidValue && b instanceof VoidValue; - - // If both are objects, just compare their references - if (!a.isPrimitive() && !b.isPrimitive()) return a.equals(b); - - // Convert values to primitives - a = a.toPrimitive(env); - b = b.toPrimitive(env); - - // Compare symbols by reference - if (a instanceof SymbolValue || b instanceof SymbolValue) return a.equals(b); - // Compare booleans as numbers - if (a instanceof BoolValue || b instanceof BoolValue) return a.toNumber(env).equals(b.toNumber(env)); - // Comparse numbers as numbers - if (a instanceof NumberValue || b instanceof NumberValue) return a.toNumber(env).equals(b.toNumber(env)); - - // Default to strings - return a.toString(env).equals(b.toString(env)); - } - - public static final String errorToReadable(Environment env, RuntimeException err, String prefix) { - prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix; - if (err instanceof EngineException ee) { - if (env == null) env = ee.env; - - try { - return prefix + " " + ee.toString(env); - } - catch (EngineException ex) { - return prefix + " " + ee.value.toReadable(env); - } - } - else if (err instanceof SyntaxException syntax) { - var newErr = EngineException.ofSyntax(syntax.msg); - newErr.add(null, syntax.loc.filename() + "", syntax.loc); - return errorToReadable(env, newErr, prefix); - } - else if (err.getCause() instanceof InterruptedException) return ""; - else { - var str = new ByteArrayOutputStream(); - err.printStackTrace(new PrintStream(str)); - - return prefix + " internal error " + str.toString(); - } - } + public static final Key REGEX_CONSTR = new Key<>(); + + public static final Key MAX_STACK_COUNT = new Key<>(); + public static final Key HIDE_STACK = new Key<>(); + + public static final Key BOOL_PROTO = new Key<>(); + public static final Key NUMBER_PROTO = new Key<>(); + public static final Key STRING_PROTO = new Key<>(); + public static final Key SYMBOL_PROTO = new Key<>(); + + public static final Key OBJECT_PROTO = new Key<>(); + public static final Key FUNCTION_PROTO = new Key<>(); + + public static final Key ARRAY_PROTO = new Key<>(); + public static final Key BYTE_BUFF_PROTO = new Key<>(); + + public static final Key ERROR_PROTO = new Key<>(); + public static final Key SYNTAX_ERR_PROTO = new Key<>(); + public static final Key TYPE_ERR_PROTO = new Key<>(); + public static final Key RANGE_ERR_PROTO = new Key<>(); + + public static final Key GLOBAL = new Key<>(); + public static final Key> INTRINSICS = new Key<>(); + + public static final VoidValue UNDEFINED = new VoidValue("undefined", "undefined"); + public static final VoidValue NULL = new VoidValue("null", "object"); + + public abstract StringValue type(); + public abstract boolean isPrimitive(); + + public final boolean isNaN() { + return this == NumberValue.NAN || this instanceof NumberValue num && Double.isNaN(num.getDouble()); + } + + public Value apply(Environment env, Value self, Value ...args) { + throw EngineException.ofType("Value is not a function"); + } + public Value construct(Environment env, Value self, Value ...args) { + throw EngineException.ofType("Value is not a constructor"); + } + + public final Value construct(Environment env, Value ...args) { + var res = new ObjectValue(); + var proto = getMember(env, StringValue.of("prototype")); + + if (proto instanceof ObjectValue) res.setPrototype(env, (ObjectValue)proto); + + var ret = this.construct(env, res, args); + + if (ret == Value.UNDEFINED || ret.isPrimitive()) return res; + return ret; + } + + + public abstract Value toPrimitive(Environment env); + public abstract NumberValue toNumber(Environment env); + public abstract String toString(Environment env); + public abstract boolean toBoolean(); + + public final boolean isInstanceOf(Environment env, Value proto) { + for (var val = getPrototype(env); val != null; val = val.getPrototype(env)) { + if (val.equals(proto)) return true; + } + + return false; + } + + public abstract Member getOwnMember(Environment env, KeyCache key); + public abstract Set getOwnMembers(Environment env, boolean onlyEnumerable); + public abstract Set getOwnSymbolMembers(Environment env, boolean onlyEnumerable); + public abstract boolean defineOwnMember(Environment env, KeyCache key, Member member); + public abstract boolean deleteOwnMember(Environment env, KeyCache key); + + public abstract ObjectValue getPrototype(Environment env); + public abstract boolean setPrototype(Environment env, ObjectValue val); + + public abstract State getState(); + + public abstract void preventExtensions(); + public abstract void seal(); + public abstract void freeze(); + + public final Member getOwnMember(Environment env, Value key) { + return getOwnMember(env, new KeyCache(key)); + } + public final Member getOwnMember(Environment env, String key) { + return getOwnMember(env, new KeyCache(key)); + } + public final Member getOwnMember(Environment env, int key) { + return getOwnMember(env, new KeyCache(key)); + } + public final Member getOwnMember(Environment env, double key) { + return getOwnMember(env, new KeyCache(key)); + } + + public final boolean defineOwnMember(Environment env, Value key, Member member) { + return defineOwnMember(env, new KeyCache(key), member); + } + public final boolean defineOwnMember(Environment env, String key, Member member) { + return defineOwnMember(env, new KeyCache(key), member); + } + public final boolean defineOwnMember(Environment env, int key, Member member) { + return defineOwnMember(env, new KeyCache(key), member); + } + public final boolean defineOwnMember(Environment env, double key, Member member) { + return defineOwnMember(env, new KeyCache(key), member); + } + + public final boolean defineOwnMember(Environment env, KeyCache key, Value val) { + return defineOwnMember(env, key, FieldMember.of(this, val)); + } + public final boolean defineOwnMember(Environment env, Value key, Value val) { + return defineOwnMember(env, new KeyCache(key), val); + } + public final boolean defineOwnMember(Environment env, String key, Value val) { + return defineOwnMember(env, new KeyCache(key), val); + } + public final boolean defineOwnMember(Environment env, int key, Value val) { + return defineOwnMember(env, new KeyCache(key), val); + } + public final boolean defineOwnMember(Environment env, double key, Value val) { + return defineOwnMember(env, new KeyCache(key), val); + } + + public final boolean deleteOwnMember(Environment env, Value key) { + return deleteOwnMember(env, new KeyCache(key)); + } + public final boolean deleteOwnMember(Environment env, String key) { + return deleteOwnMember(env, new KeyCache(key)); + } + public final boolean deleteOwnMember(Environment env, int key) { + return deleteOwnMember(env, new KeyCache(key)); + } + public final boolean deleteOwnMember(Environment env, double key) { + return deleteOwnMember(env, new KeyCache(key)); + } + + public final Value getMemberOrNull(Environment env, KeyCache key) { + for (Value obj = this; obj != null; obj = obj.getPrototype(env)) { + var member = obj.getOwnMember(env, key); + if (member != null) return member.get(env, this); + } + + return null; + } + public final Value getMemberOrNull(Environment env, Value key) { + return getMemberOrNull(env, new KeyCache(key)); + } + public final Value getMemberOrNull(Environment env, String key) { + return getMemberOrNull(env, new KeyCache(key)); + } + public final Value getMemberOrNull(Environment env, int key) { + return getMemberOrNull(env, new KeyCache(key)); + } + public final Value getMemberOrNull(Environment env, double key) { + return getMemberOrNull(env, new KeyCache(key)); + } + + public final Value getMember(Environment env, KeyCache key) { + var res = getMemberOrNull(env, key); + if (res != null) return res; + else return Value.UNDEFINED; + } + public final Value getMember(Environment env, Value key) { + return getMember(env, new KeyCache(key)); + } + public final Value getMember(Environment env, String key) { + return getMember(env, new KeyCache(key)); + } + public final Value getMember(Environment env, int key) { + return getMember(env, new KeyCache(key)); + } + public final Value getMember(Environment env, double key) { + return getMember(env, new KeyCache(key)); + } + + public final boolean setMember(Environment env, KeyCache key, Value val) { + for (Value obj = this; obj != null; obj = obj.getPrototype(env)) { + var member = obj.getOwnMember(env, key); + if (member != null && (member instanceof PropertyMember || obj == this)) { + if (member.set(env, val, this)) { + if (val instanceof FunctionValue) ((FunctionValue)val).setName(key.toString(env)); + return true; + } + else return false; + } + } + + if (defineOwnMember(env, key, val)) { + if (val instanceof FunctionValue) ((FunctionValue)val).setName(key.toString(env)); + return true; + } + else return false; + } + public final boolean setMember(Environment env, Value key, Value val) { + return setMember(env, new KeyCache(key), val); + } + public final boolean setMember(Environment env, String key, Value val) { + return setMember(env, new KeyCache(key), val); + } + public final boolean setMember(Environment env, int key, Value val) { + return setMember(env, new KeyCache(key), val); + } + public final boolean setMember(Environment env, double key, Value val) { + return setMember(env, new KeyCache(key), val); + } + + public final boolean setMemberIfExists(Environment env, KeyCache key, Value val) { + for (Value obj = this; obj != null; obj = obj.getPrototype(env)) { + var member = obj.getOwnMember(env, key); + if (member != null) { + if (member.set(env, val, obj)) { + if (val instanceof FunctionValue) ((FunctionValue)val).setName(key.toString(env)); + return true; + } + else return false; + } + } + + return false; + } + public final boolean setMemberIfExists(Environment env, Value key, Value val) { + return setMemberIfExists(env, new KeyCache(key), val); + } + public final boolean setMemberIfExists(Environment env, String key, Value val) { + return setMemberIfExists(env, new KeyCache(key), val); + } + public final boolean setMemberIfExists(Environment env, int key, Value val) { + return setMemberIfExists(env, new KeyCache(key), val); + } + public final boolean setMemberIfExists(Environment env, double key, Value val) { + return setMemberIfExists(env, new KeyCache(key), val); + } + + public final boolean hasMember(Environment env, KeyCache key, boolean own) { + for (Value obj = this; obj != null; obj = obj.getPrototype(env)) { + if (obj.getOwnMember(env, key) != null) return true; + if (own) return false; + } + + return false; + } + public final boolean hasMember(Environment env, Value key, boolean own) { + return hasMember(env, new KeyCache(key), own); + } + public final boolean hasMember(Environment env, String key, boolean own) { + return hasMember(env, new KeyCache(key), own); + } + public final boolean hasMember(Environment env, int key, boolean own) { + return hasMember(env, new KeyCache(key), own); + } + public final boolean hasMember(Environment env, double key, boolean own) { + return hasMember(env, new KeyCache(key), own); + } + + public final boolean deleteMember(Environment env, KeyCache key) { + if (!hasMember(env, key, true)) return true; + return deleteOwnMember(env, key); + } + public final boolean deleteMember(Environment env, Value key) { + return deleteMember(env, new KeyCache(key)); + } + public final boolean deleteMember(Environment env, String key) { + return deleteMember(env, new KeyCache(key)); + } + public final boolean deleteMember(Environment env, int key) { + return deleteMember(env, new KeyCache(key)); + } + public final boolean deleteMember(Environment env, double key) { + return deleteMember(env, new KeyCache(key)); + } + + public final Set getMembers(Environment env, boolean own, boolean onlyEnumerable) { + var res = new LinkedHashSet(); + var protos = new ArrayList(); + + for (var proto = this; proto != null; proto = proto.getPrototype(env)) { + protos.add(proto); + if (own) break; + } + + Collections.reverse(protos); + + for (var proto : protos) { + res.addAll(proto.getOwnMembers(env, onlyEnumerable)); + } + + return res; + } + public final Set getSymbolMembers(Environment env, boolean own, boolean onlyEnumerable) { + var res = new LinkedHashSet(); + var protos = new ArrayList(); + + for (var proto = this; proto != null; proto = proto.getPrototype(env)) { + protos.add(proto); + if (own) break; + } + + Collections.reverse(protos); + + for (var proto : protos) { + res.addAll(proto.getOwnSymbolMembers(env, onlyEnumerable)); + } + + return res; + } + + public final Value getMemberPath(Environment env, Value ...path) { + var res = this; + for (var key : path) res = res.getMember(env, key); + return res; + } + public final ObjectValue getMemberDescriptor(Environment env, Value key) { + var member = getOwnMember(env, new KeyCache(key)); + + if (member != null) return member.descriptor(env, this); + else return null; + } + + public Iterable toIterable(Environment env) { + return () -> { + if (!(this instanceof FunctionValue)) return Collections.emptyIterator(); + var func = (FunctionValue)this; + + return new Iterator() { + private Object value = null; + public boolean consumed = true; + private FunctionValue supplier = func; + + private void loadNext() { + if (supplier == null) value = null; + else if (consumed) { + var curr = supplier.apply(env, Value.UNDEFINED); + + if (curr == null) { supplier = null; value = null; } + if (curr.getMember(env, StringValue.of("done")).toBoolean()) { supplier = null; value = null; } + else { + this.value = curr.getMember(env, StringValue.of("value")); + consumed = false; + } + } + } + + @Override public boolean hasNext() { + loadNext(); + return supplier != null; + } + @Override public Object next() { + loadNext(); + var res = value; + value = null; + consumed = true; + return res; + } + }; + }; + } + + public void callWith(Environment env, Iterable it) { + for (var el : it) { + this.apply(env, Value.UNDEFINED, el); + } + } + public void callWithAsync(Environment env, Iterable it, boolean async) { + for (var el : it) { + env.get(EventLoop.KEY).pushMsg(() -> this.apply(env, Value.UNDEFINED, el), true); + } + } + + /** @internal */ + public List toReadableLines(Environment env, HashSet passed) { + return Arrays.asList(toString(env)); + } + + public final String toReadable(Environment ext) { + return String.join("\n", toReadableLines(ext, new HashSet<>())); + } + + public static final ObjectValue global(Environment env) { + return env.initFrom(GLOBAL, () -> new ObjectValue()); + } + public static final Map intrinsics(Environment env) { + return env.initFrom(INTRINSICS, () -> new HashMap<>()); + } + + public static FunctionValue fromIterator(Environment ext, Iterable iterable) { + var it = iterable.iterator(); + + return new NativeFunction("", args -> { + var obj = new ObjectValue(); + + if (!it.hasNext()) obj.defineOwnMember(args.env, "done", BoolValue.TRUE); + else obj.defineOwnMember(args.env, "value", it.next()); + + return obj; + }); + } + + public static final boolean lessOrEqual(Environment env, Value a, Value b) { + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + if (a instanceof StringValue aStr && b instanceof StringValue bStr) { + return aStr.value.compareTo(bStr.value) <= 0; + } + else { + var na = a.toNumber(env); + var nb = b.toNumber(env); + + if (na.isLong() && nb.isLong()) return na.getLong() <= nb.getLong(); + else return na.getDouble() <= nb.getDouble(); + } + } + public static final boolean greaterOrEqual(Environment env, Value a, Value b) { + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + if (a instanceof StringValue aStr && b instanceof StringValue bStr) { + return aStr.value.compareTo(bStr.value) >= 0; + } + else { + var na = a.toNumber(env); + var nb = b.toNumber(env); + + if (na.isLong() && nb.isLong()) return na.getLong() >= nb.getLong(); + else return na.getDouble() >= nb.getDouble(); + } + } + public static final boolean less(Environment env, Value a, Value b) { + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + if (a instanceof StringValue aStr && b instanceof StringValue bStr) { + return aStr.value.compareTo(bStr.value) < 0; + } + else { + var na = a.toNumber(env); + var nb = b.toNumber(env); + + if (na.isLong() && nb.isLong()) return na.getLong() < nb.getLong(); + else return na.getDouble() < nb.getDouble(); + } + } + public static final boolean greater(Environment env, Value a, Value b) { + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + if (a instanceof StringValue aStr && b instanceof StringValue bStr) { + return aStr.value.compareTo(bStr.value) > 0; + } + else { + var na = a.toNumber(env); + var nb = b.toNumber(env); + + if (na.isLong() && nb.isLong()) return na.getLong() > nb.getLong(); + else return na.getDouble() > nb.getDouble(); + } + } + + public static final Value add(Environment env, Value a, Value b) { + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + if (a instanceof StringValue || b instanceof StringValue) { + return StringValue.of(a.toString(env) + b.toString(env)); + } + else { + var na = a.toNumber(env); + var nb = b.toNumber(env); + + if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() + nb.getInt()); + else return NumberValue.of(na.getDouble() + nb.getDouble()); + } + } + + public static final NumberValue subtract(Environment env, Value a, Value b) { + var na = a.toNumber(env); + var nb = b.toNumber(env); + + if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() - nb.getInt()); + else return NumberValue.of(na.getDouble() - nb.getDouble()); + } + public static final NumberValue multiply(Environment env, Value a, Value b) { + var na = a.toNumber(env); + var nb = b.toNumber(env); + + if (na.isInt() && nb.isInt()) return NumberValue.of(na.getInt() * nb.getInt()); + else return NumberValue.of(na.getDouble() * nb.getDouble()); + } + public static final NumberValue divide(Environment env, Value a, Value b) { + var na = a.toNumber(env); + var nb = b.toNumber(env); + + if (na.isInt() && nb.isInt()) { + var ia = na.getInt(); + var ib = nb.getInt(); + + if (ib == 0) { + if (ia == 0) return NumberValue.NAN; + else if (ia > 0) return NumberValue.of(Double.POSITIVE_INFINITY); + else return NumberValue.of(Double.NEGATIVE_INFINITY); + } + else if (ia % ib != 0) return NumberValue.of((double)ia / ib); + else return NumberValue.of(ia / ib); + } + else return NumberValue.of(na.getDouble() / nb.getDouble()); + } + public static final NumberValue modulo(Environment env, Value a, Value b) { + var na = a.toNumber(env); + var nb = b.toNumber(env); + + if (na.isInt() && nb.isInt()) { + var ia = na.getInt(); + var ib = nb.getInt(); + + if (ib == 0) return NumberValue.NAN; + else return NumberValue.of(ia % ib); + } + else return NumberValue.of(na.getDouble() % nb.getDouble()); + } + public static final NumberValue negative(Environment env, Value a) { + var na = a.toNumber(env); + + if (na.isInt()) return NumberValue.of(-na.getInt()); + else return NumberValue.of(-na.getDouble()); + } + + public static final NumberValue and(Environment env, Value a, Value b) { + return NumberValue.of(a.toNumber(env).getInt() & b.toNumber(env).getInt()); + } + public static final NumberValue or(Environment env, Value a, Value b) { + return NumberValue.of(a.toNumber(env).getInt() | b.toNumber(env).getInt()); + } + public static final NumberValue xor(Environment env, Value a, Value b) { + return NumberValue.of(a.toNumber(env).getInt() ^ b.toNumber(env).getInt()); + } + public static final NumberValue bitwiseNot(Environment env, Value a) { + return NumberValue.of(~a.toNumber(env).getInt()); + } + + public static final NumberValue shiftLeft(Environment env, Value a, Value b) { + return NumberValue.of(a.toNumber(env).getInt() << b.toNumber(env).getInt()); + } + public static final NumberValue shiftRight(Environment env, Value a, Value b) { + return NumberValue.of(a.toNumber(env).getInt() >> b.toNumber(env).getInt()); + } + public static final NumberValue unsignedShiftRight(Environment env, Value a, Value b) { + long _a = a.toNumber(env).getLong() & 0xFFFFFFFF; + long _b = b.toNumber(env).getLong() & 0xFFFFFFFF; + + if (_a < 0) _a += 0x100000000l; + if (_b < 0) _b += 0x100000000l; + + return NumberValue.of(_a >>> _b); + } + + public static final boolean looseEqual(Environment env, Value a, Value b) { + // In loose equality, null is equivalent to undefined + if (a instanceof VoidValue || b instanceof VoidValue) return a instanceof VoidValue && b instanceof VoidValue; + + // If both are objects, just compare their references + if (!a.isPrimitive() && !b.isPrimitive()) return a.equals(b); + + // Convert values to primitives + a = a.toPrimitive(env); + b = b.toPrimitive(env); + + // Compare symbols by reference + if (a instanceof SymbolValue || b instanceof SymbolValue) return a.equals(b); + // Compare booleans as numbers + if (a instanceof BoolValue || b instanceof BoolValue) return a.toNumber(env).equals(b.toNumber(env)); + // Comparse numbers as numbers + if (a instanceof NumberValue || b instanceof NumberValue) return a.toNumber(env).equals(b.toNumber(env)); + + // Default to strings + return a.toString(env).equals(b.toString(env)); + } + + public static final String errorToReadable(Environment env, RuntimeException err, String prefix) { + prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix; + if (err instanceof EngineException ee) { + if (env == null) env = ee.env; + + try { + return prefix + " " + ee.toString(env); + } + catch (EngineException ex) { + return prefix + " " + ee.value.toReadable(env); + } + } + else if (err instanceof SyntaxException syntax) { + var newErr = EngineException.ofSyntax(syntax.msg); + newErr.add(null, syntax.loc.filename() + "", syntax.loc); + return errorToReadable(env, newErr, prefix); + } + else if (err.getCause() instanceof InterruptedException) return ""; + else { + var str = new ByteArrayOutputStream(); + err.printStackTrace(new PrintStream(str)); + + return prefix + " internal error " + str.toString(); + } + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/Arguments.java b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/Arguments.java index 7b280c4..984cb2b 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/Arguments.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/Arguments.java @@ -6,41 +6,41 @@ import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.primitives.UserValue; public class Arguments { - public final Value self; - public final Value[] args; - public final Environment env; - public final boolean isNew; + public final Value self; + public final Value[] args; + public final Environment env; + public final boolean isNew; - public int n() { - return args.length; - } + public int n() { + return args.length; + } - public boolean has(int i) { - return i == -1 || i >= 0 && i < args.length; - } + public boolean has(int i) { + return i == -1 || i >= 0 && i < args.length; + } - public Value self() { - return get(-1); - } - @SuppressWarnings("unchecked") + public Value self() { + return get(-1); + } + @SuppressWarnings("unchecked") public T self(Class clazz) { if (self instanceof UserValue user && clazz.isInstance(user.value)) return (T)user.value; else return null; - } - public Value get(int i) { - if (i >= args.length || i < -1) return Value.UNDEFINED; - else if (i == -1) return self; - else return args[i]; - } - public Value getOrDefault(int i, Value def) { - if (i < -1 || i >= args.length) return def; - else return get(i); - } + } + public Value get(int i) { + if (i >= args.length || i < -1) return Value.UNDEFINED; + else if (i == -1) return self; + else return args[i]; + } + public Value getOrDefault(int i, Value def) { + if (i < -1 || i >= args.length) return def; + else return get(i); + } - public Arguments(Environment env, boolean isNew, Value thisArg, Value... args) { - this.env = env; - this.args = args; - this.self = thisArg; - this.isNew = isNew; - } + public Arguments(Environment env, boolean isNew, Value thisArg, Value... args) { + this.env = env; + this.args = args; + this.self = thisArg; + this.isNew = isNew; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java index 5183b62..0b9568a 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java @@ -6,37 +6,37 @@ import me.topchetoeu.jscript.runtime.Frame; import me.topchetoeu.jscript.runtime.values.Value; public final class CodeFunction extends FunctionValue { - public final FunctionBody body; - public final Value[][] captures; - public Environment env; + public final FunctionBody body; + public final Value[][] captures; + public Environment env; - private Value onCall(Frame frame) { - frame.onPush(); + private Value onCall(Frame frame) { + frame.onPush(); - try { - while (true) { - var res = frame.next(null, null, null); - if (res != null) return res; - } - } - finally { - frame.onPop(); - } - } + try { + while (true) { + var res = frame.next(null, null, null); + if (res != null) return res; + } + } + finally { + frame.onPop(); + } + } - @Override public Value onCall(Environment env, boolean isNew, Value self, Value ...args) { - var frame = new Frame(env, isNew, self, args, this); + @Override public Value onCall(Environment env, boolean isNew, Value self, Value ...args) { + var frame = new Frame(env, isNew, self, args, this); - var res = onCall(frame); + var res = onCall(frame); - if (isNew) return frame.self; - else return res; - } + if (isNew) return frame.self; + else return res; + } - public CodeFunction(Environment env, String name, FunctionBody body, Value[][] captures) { - super(name, body.length); - this.captures = captures; - this.env = env; - this.body = body; - } + public CodeFunction(Environment env, String name, FunctionBody body, Value[][] captures) { + super(name, body.length); + this.captures = captures; + this.env = env; + this.body = body; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/FunctionValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/FunctionValue.java index 5b3fcc7..cef538e 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/FunctionValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/FunctionValue.java @@ -17,103 +17,103 @@ import me.topchetoeu.jscript.runtime.values.primitives.StringValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public abstract class FunctionValue extends ObjectValue { - public String name = ""; - public int length; - public Value prototype = new ObjectValue(); + public String name = ""; + public int length; + public Value prototype = new ObjectValue(); - public boolean enableApply = true; - public boolean enableConstruct = true; + public boolean enableApply = true; + public boolean enableConstruct = true; - private final FieldMember nameField = new FieldMember(this, true, false, false) { - @Override public Value get(Environment env, Value self) { - if (name == null) return StringValue.of(""); - return StringValue.of(name); - } - @Override public boolean set(Environment env, Value val, Value self) { - name = val.toString(env); - return true; - } - }; - private final FieldMember lengthField = new FieldMember(this, true, false, false) { - @Override public Value get(Environment env, Value self) { - return NumberValue.of(length); - } - @Override public boolean set(Environment env, Value val, Value self) { - return false; - } - }; - private final FieldMember prototypeField = new FieldMember(this, false, false, true) { - @Override public Value get(Environment env, Value self) { - return prototype; - } - @Override public boolean set(Environment env, Value val, Value self) { - prototype = val; - return true; - } - }; + private final FieldMember nameField = new FieldMember(this, true, false, false) { + @Override public Value get(Environment env, Value self) { + if (name == null) return StringValue.of(""); + return StringValue.of(name); + } + @Override public boolean set(Environment env, Value val, Value self) { + name = val.toString(env); + return true; + } + }; + private final FieldMember lengthField = new FieldMember(this, true, false, false) { + @Override public Value get(Environment env, Value self) { + return NumberValue.of(length); + } + @Override public boolean set(Environment env, Value val, Value self) { + return false; + } + }; + private final FieldMember prototypeField = new FieldMember(this, false, false, true) { + @Override public Value get(Environment env, Value self) { + return prototype; + } + @Override public boolean set(Environment env, Value val, Value self) { + prototype = val; + return true; + } + }; - protected abstract Value onCall(Environment ext, boolean isNew, Value thisArg, Value ...args); + protected abstract Value onCall(Environment ext, boolean isNew, Value thisArg, Value ...args); - @Override public String toString() { return String.format("function %s(...)", name); } + @Override public String toString() { return String.format("function %s(...)", name); } @Override public Value apply(Environment env, Value self, Value... args) { - if (!enableApply) throw EngineException.ofType("Function cannot be applied"); - return onCall(env, false, self, args); + if (!enableApply) throw EngineException.ofType("Function cannot be applied"); + return onCall(env, false, self, args); } @Override public Value construct(Environment env, Value self, Value... args) { - if (!enableConstruct) throw EngineException.ofType("Function cannot be constructed"); - return onCall(env, true, self, args); + if (!enableConstruct) throw EngineException.ofType("Function cannot be constructed"); + return onCall(env, true, self, args); } - @Override public Member getOwnMember(Environment env, KeyCache key) { - switch (key.toString(env)) { - case "length": return lengthField; - case "name": return nameField; - case "prototype": return prototypeField; - default: return super.getOwnMember(env, key); - } - } - @Override public boolean deleteOwnMember(Environment env, KeyCache key) { - switch (key.toString(env)) { - case "length": - length = 0; - return true; - case "name": - name = ""; - return true; - case "prototype": - return false; - default: return super.deleteOwnMember(env, key); - } - } + @Override public Member getOwnMember(Environment env, KeyCache key) { + switch (key.toString(env)) { + case "length": return lengthField; + case "name": return nameField; + case "prototype": return prototypeField; + default: return super.getOwnMember(env, key); + } + } + @Override public boolean deleteOwnMember(Environment env, KeyCache key) { + switch (key.toString(env)) { + case "length": + length = 0; + return true; + case "name": + name = ""; + return true; + case "prototype": + return false; + default: return super.deleteOwnMember(env, key); + } + } - @Override public StringValue type() { return StringValue.of("function"); } + @Override public StringValue type() { return StringValue.of("function"); } - @Override public List toReadableLines(Environment env, HashSet passed) { - var dbg = DebugContext.get(env); - var res = new StringBuilder(this.toString()); - var loc = dbg.getMapOrEmpty(this).start(); + @Override public List toReadableLines(Environment env, HashSet passed) { + var dbg = DebugContext.get(env); + var res = new StringBuilder(this.toString()); + var loc = dbg.getMapOrEmpty(this).start(); - if (loc != null) res.append(" @ " + loc); + if (loc != null) res.append(" @ " + loc); - var lines = new LinkedList(super.toReadableLines(env, passed)); - if (lines.size() == 1 && lines.getFirst().equals("{}")) return Arrays.asList(res.toString()); - lines.set(0, res.toString() + " " + lines.getFirst()); + var lines = new LinkedList(super.toReadableLines(env, passed)); + if (lines.size() == 1 && lines.getFirst().equals("{}")) return Arrays.asList(res.toString()); + lines.set(0, res.toString() + " " + lines.getFirst()); - return lines; - } + return lines; + } - public void setName(String val) { - if (this.name == null || this.name.equals("")) this.name = val; - } + public void setName(String val) { + if (this.name == null || this.name.equals("")) this.name = val; + } - public FunctionValue(String name, int length) { - setPrototype(FUNCTION_PROTO); + public FunctionValue(String name, int length) { + setPrototype(FUNCTION_PROTO); - if (name == null) name = ""; - this.length = length; - this.name = name; + if (name == null) name = ""; + this.length = length; + this.name = name; - prototype.defineOwnMember(null, "constructor", this); - } + prototype.defineOwnMember(null, "constructor", this); + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/NativeFunction.java b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/NativeFunction.java index f2bdc47..a4a81e3 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/NativeFunction.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/NativeFunction.java @@ -4,22 +4,22 @@ import me.topchetoeu.jscript.common.environment.Environment; import me.topchetoeu.jscript.runtime.values.Value; public final class NativeFunction extends FunctionValue { - public static interface NativeFunctionRunner { - Value run(Arguments args); - } + public static interface NativeFunctionRunner { + Value run(Arguments args); + } - public final NativeFunctionRunner action; + public final NativeFunctionRunner action; - @Override public Value onCall(Environment env, boolean isNew, Value self, Value ...args) { - return action.run(new Arguments(env, isNew, self, args)); - } + @Override public Value onCall(Environment env, boolean isNew, Value self, Value ...args) { + return action.run(new Arguments(env, isNew, self, args)); + } - public NativeFunction(String name, NativeFunctionRunner action) { - super(name, 0); - this.action = action; - } - public NativeFunction(NativeFunctionRunner action) { - super("", 0); - this.action = action; - } + public NativeFunction(String name, NativeFunctionRunner action) { + super(name, 0); + this.action = action; + } + public NativeFunction(NativeFunctionRunner action) { + super("", 0); + this.action = action; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ArrayLikeValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ArrayLikeValue.java index 6de8e2f..d8a79ef 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ArrayLikeValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ArrayLikeValue.java @@ -16,182 +16,182 @@ import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; import me.topchetoeu.jscript.runtime.values.Value; public abstract class ArrayLikeValue extends ObjectValue { - private static class IndexField extends FieldMember { - private int i; - private ArrayLikeValue arr; + private static class IndexField extends FieldMember { + private int i; + private ArrayLikeValue arr; - @Override public Value get(Environment env, Value self) { - return arr.get(i); - } - @Override public boolean set(Environment env, Value val, Value self) { - return arr.set(env, i, val); - } - public IndexField(int i, ArrayLikeValue arr) { - super(arr, true, true, true); - this.arr = arr; - this.i = i; - } - } + @Override public Value get(Environment env, Value self) { + return arr.get(i); + } + @Override public boolean set(Environment env, Value val, Value self) { + return arr.set(env, i, val); + } + public IndexField(int i, ArrayLikeValue arr) { + super(arr, true, true, true); + this.arr = arr; + this.i = i; + } + } - private final FieldMember lengthField = new FieldMember(this, false, false, true) { - @Override public Value get(Environment env, Value self) { - return NumberValue.of(size()); - } - @Override public boolean set(Environment env, Value val, Value self) { - var num = val.toNumber(env); - if (!num.isInt()) throw EngineException.ofRange("Invalid array length"); + private final FieldMember lengthField = new FieldMember(this, false, false, true) { + @Override public Value get(Environment env, Value self) { + return NumberValue.of(size()); + } + @Override public boolean set(Environment env, Value val, Value self) { + var num = val.toNumber(env); + if (!num.isInt()) throw EngineException.ofRange("Invalid array length"); - var i = num.getInt(); - if (i < 0) throw EngineException.ofRange("Invalid array length"); + var i = num.getInt(); + if (i < 0) throw EngineException.ofRange("Invalid array length"); - return setSize(i); - } - }; + return setSize(i); + } + }; - public abstract int size(); - public abstract boolean setSize(int val); + public abstract int size(); + public abstract boolean setSize(int val); - public abstract Value get(int i); - public abstract boolean set(Environment env, int i, Value val); - public abstract boolean has(int i); - public abstract boolean remove(int i); + public abstract Value get(int i); + public abstract boolean set(Environment env, int i, Value val); + public abstract boolean has(int i); + public abstract boolean remove(int i); - @Override public Member getOwnMember(Environment env, KeyCache key) { - var res = super.getOwnMember(env, key); - if (res != null) return res; - if (key.isSymbol()) return null; + @Override public Member getOwnMember(Environment env, KeyCache key) { + var res = super.getOwnMember(env, key); + if (res != null) return res; + if (key.isSymbol()) return null; - var num = key.toNumber(env); - var i = key.toInt(env); + var num = key.toNumber(env); + var i = key.toInt(env); - if (i == num && i >= 0 && i < size() && has(i)) return new IndexField(i, this); - else if (key.toString(env).equals("length")) return lengthField; - else return null; - } - @Override public boolean defineOwnMember(Environment env, KeyCache key, Member member) { - if (!(member instanceof FieldMember) || super.getOwnMember(env, key) != null) return super.defineOwnMember(env, key, member); - if (!getState().writable) return false; + if (i == num && i >= 0 && i < size() && has(i)) return new IndexField(i, this); + else if (key.toString(env).equals("length")) return lengthField; + else return null; + } + @Override public boolean defineOwnMember(Environment env, KeyCache key, Member member) { + if (!(member instanceof FieldMember) || super.getOwnMember(env, key) != null) return super.defineOwnMember(env, key, member); + if (!getState().writable) return false; - if (!key.isSymbol()) { - var num = key.toNumber(env); - var i = key.toInt(env); + if (!key.isSymbol()) { + var num = key.toNumber(env); + var i = key.toInt(env); - if (i == num) { - if (!getState().extendable && !has(i)) return false; - if (set(env, i, ((FieldMember)member).get(env, this))) return true; - } - } + if (i == num) { + if (!getState().extendable && !has(i)) return false; + if (set(env, i, ((FieldMember)member).get(env, this))) return true; + } + } - return super.defineOwnMember(env, key, member); - } - @Override public boolean deleteOwnMember(Environment env, KeyCache key) { - if (!super.deleteOwnMember(env, key)) return false; - if (key.isSymbol()) return true; + return super.defineOwnMember(env, key, member); + } + @Override public boolean deleteOwnMember(Environment env, KeyCache key) { + if (!super.deleteOwnMember(env, key)) return false; + if (key.isSymbol()) return true; - var num = key.toNumber(env); - var i = key.toInt(env); + var num = key.toNumber(env); + var i = key.toInt(env); - if (i == num && i >= 0 && i < size()) return remove(i); - else return true; - } + if (i == num && i >= 0 && i < size()) return remove(i); + else return true; + } - @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { - var res = new LinkedHashSet(); + @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { + var res = new LinkedHashSet(); - res.addAll(super.getOwnMembers(env, onlyEnumerable)); + res.addAll(super.getOwnMembers(env, onlyEnumerable)); - for (var i = 0; i < size(); i++) { - if (has(i)) res.add(i + ""); - } + for (var i = 0; i < size(); i++) { + if (has(i)) res.add(i + ""); + } - if (!onlyEnumerable) res.add("length"); + if (!onlyEnumerable) res.add("length"); - return res; - } + return res; + } - private LinkedList toReadableBase(Environment env, HashSet passed, HashSet ignoredKeys) { - var stringified = new LinkedList>(); + private LinkedList toReadableBase(Environment env, HashSet passed, HashSet ignoredKeys) { + var stringified = new LinkedList>(); - passed.add(this); + passed.add(this); - var emptyN = 0; + var emptyN = 0; - for (int i = 0; i < size(); i++) { - if (has(i)) { - String emptyStr = null; + for (int i = 0; i < size(); i++) { + if (has(i)) { + String emptyStr = null; - if (emptyN == 1) emptyStr = ""; - else if (emptyN > 1) emptyStr = ""; + if (emptyN == 1) emptyStr = ""; + else if (emptyN > 1) emptyStr = ""; - if (emptyStr != null) stringified.add(new LinkedList<>(Arrays.asList(emptyStr + ","))); - emptyN = 0; + if (emptyStr != null) stringified.add(new LinkedList<>(Arrays.asList(emptyStr + ","))); + emptyN = 0; - stringified.add(new LinkedList<>(get(i).toReadableLines(env, passed))); - ignoredKeys.add(i + ""); + stringified.add(new LinkedList<>(get(i).toReadableLines(env, passed))); + ignoredKeys.add(i + ""); - var entry = stringified.getLast(); - entry.set(entry.size() - 1, entry.getLast() + ","); - } - else { - emptyN++; - } - } + var entry = stringified.getLast(); + entry.set(entry.size() - 1, entry.getLast() + ","); + } + else { + emptyN++; + } + } - String emptyStr = null; + String emptyStr = null; - if (emptyN == 1) emptyStr = ""; - else if (emptyN > 1) emptyStr = ""; + if (emptyN == 1) emptyStr = ""; + else if (emptyN > 1) emptyStr = ""; - if (emptyStr != null) stringified.add(new LinkedList<>(Arrays.asList(emptyStr))); - else if (stringified.size() > 0) { - var lastEntry = stringified.getLast(); - lastEntry.set(lastEntry.size() - 1, lastEntry.getLast().substring(0, lastEntry.getLast().length() - 1)); - } + if (emptyStr != null) stringified.add(new LinkedList<>(Arrays.asList(emptyStr))); + else if (stringified.size() > 0) { + var lastEntry = stringified.getLast(); + lastEntry.set(lastEntry.size() - 1, lastEntry.getLast().substring(0, lastEntry.getLast().length() - 1)); + } - passed.remove(this); + passed.remove(this); - if (stringified.size() == 0) return new LinkedList<>(Arrays.asList("[]")); - var concat = new StringBuilder(); - for (var entry : stringified) { - // We make a one-liner only when all members are one-liners - if (entry.size() != 1) { - concat = null; - break; - } + if (stringified.size() == 0) return new LinkedList<>(Arrays.asList("[]")); + var concat = new StringBuilder(); + for (var entry : stringified) { + // We make a one-liner only when all members are one-liners + if (entry.size() != 1) { + concat = null; + break; + } - if (concat.length() != 0) concat.append(" "); - concat.append(entry.get(0)); - } + if (concat.length() != 0) concat.append(" "); + concat.append(entry.get(0)); + } - // We don't want too long one-liners - if (concat != null && concat.length() < 160) return new LinkedList<>(Arrays.asList("[" + concat.toString() + "]")); + // We don't want too long one-liners + if (concat != null && concat.length() < 160) return new LinkedList<>(Arrays.asList("[" + concat.toString() + "]")); - var res = new LinkedList(); + var res = new LinkedList(); - res.add("["); + res.add("["); - for (var entry : stringified) { - for (var line : entry) { - res.add(" " + line); - } - } - res.set(res.size() - 1, res.getLast().substring(0, res.getLast().length() - 1)); - res.add("]"); + for (var entry : stringified) { + for (var line : entry) { + res.add(" " + line); + } + } + res.set(res.size() - 1, res.getLast().substring(0, res.getLast().length() - 1)); + res.add("]"); - return res; - } + return res; + } - @Override public List toReadableLines(Environment env, HashSet passed) { - var ignored = new HashSet(); - var lines = toReadableBase(env, passed, ignored); + @Override public List toReadableLines(Environment env, HashSet passed) { + var ignored = new HashSet(); + var lines = toReadableBase(env, passed, ignored); - var superLines = new LinkedList(super.toReadableLines(env, passed, ignored)); - if (superLines.size() == 1 && superLines.getFirst().equals("{}")) return lines; + var superLines = new LinkedList(super.toReadableLines(env, passed, ignored)); + if (superLines.size() == 1 && superLines.getFirst().equals("{}")) return lines; - lines.set(lines.size() - 1, lines.getLast() + " " + superLines.getFirst()); - lines.addAll(superLines.subList(1, superLines.size())); + lines.set(lines.size() - 1, lines.getLast() + " " + superLines.getFirst()); + lines.addAll(superLines.subList(1, superLines.size())); - return lines; - } + return lines; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ArrayValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ArrayValue.java index 39f7db7..6b3f457 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ArrayValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ArrayValue.java @@ -10,141 +10,141 @@ import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.primitives.VoidValue; public class ArrayValue extends ArrayLikeValue implements Iterable { - private Value[] values; - private int size; + private Value[] values; + private int size; - private Value[] alloc(int index) { - index++; - if (index < values.length) return values; - if (index < values.length * 2) index = values.length * 2; + private Value[] alloc(int index) { + index++; + if (index < values.length) return values; + if (index < values.length * 2) index = values.length * 2; - var arr = new Value[index]; - System.arraycopy(values, 0, arr, 0, values.length); - return values = arr; - } + var arr = new Value[index]; + System.arraycopy(values, 0, arr, 0, values.length); + return values = arr; + } - public int size() { return size; } - public boolean setSize(int val) { - if (val < 0) return false; - if (size > val) shrink(size - val); - else { - values = alloc(val); - size = val; - } - return true; - } + public int size() { return size; } + public boolean setSize(int val) { + if (val < 0) return false; + if (size > val) shrink(size - val); + else { + values = alloc(val); + size = val; + } + return true; + } - @Override public Value get(int i) { - if (i < 0 || i >= size) return null; - var res = values[i]; + @Override public Value get(int i) { + if (i < 0 || i >= size) return null; + var res = values[i]; - if (res == null) return Value.UNDEFINED; - else return res; - } - @Override public boolean set(Environment env, int i, Value val) { - if (i < 0) return false; + if (res == null) return Value.UNDEFINED; + else return res; + } + @Override public boolean set(Environment env, int i, Value val) { + if (i < 0) return false; - alloc(i)[i] = val; - if (i >= size) size = i + 1; - return true; - } - @Override public boolean has(int i) { - return i >= 0 && i < size && values[i] != null; - } - @Override public boolean remove(int i) { - if (i < 0 || i >= values.length) return true; - values[i] = null; - return true; - } + alloc(i)[i] = val; + if (i >= size) size = i + 1; + return true; + } + @Override public boolean has(int i) { + return i >= 0 && i < size && values[i] != null; + } + @Override public boolean remove(int i) { + if (i < 0 || i >= values.length) return true; + values[i] = null; + return true; + } - public void shrink(int n) { - if (n >= values.length) { - values = new Value[16]; - size = 0; - } - else { - for (int i = 0; i < n; i++) values[--size] = null; - } - } + public void shrink(int n) { + if (n >= values.length) { + values = new Value[16]; + size = 0; + } + else { + for (int i = 0; i < n; i++) values[--size] = null; + } + } - public Value[] toArray() { - var res = new Value[size]; - copyTo(res, 0, 0, size); - return res; - } + public Value[] toArray() { + var res = new Value[size]; + copyTo(res, 0, 0, size); + return res; + } - public void copyTo(Value[] arr, int sourceStart, int destStart, int count) { - var nullFill = Math.max(0, arr.length - size - destStart); - count -= nullFill; + public void copyTo(Value[] arr, int sourceStart, int destStart, int count) { + var nullFill = Math.max(0, arr.length - size - destStart); + count -= nullFill; - System.arraycopy(values, sourceStart, arr, destStart, count); - Arrays.fill(arr, count, nullFill + count, null); - } - public void copyTo(ArrayValue arr, int sourceStart, int destStart, int count) { - if (arr == this) { - move(sourceStart, destStart, count); - return; - } + System.arraycopy(values, sourceStart, arr, destStart, count); + Arrays.fill(arr, count, nullFill + count, null); + } + public void copyTo(ArrayValue arr, int sourceStart, int destStart, int count) { + if (arr == this) { + move(sourceStart, destStart, count); + return; + } - arr.copyFrom(values, sourceStart, destStart, count); - } - public void copyFrom(Value[] arr, int sourceStart, int destStart, int count) { - alloc(destStart + count); - System.arraycopy(arr, sourceStart, values, destStart, count); - if (size < destStart + count) size = destStart + count; - } + arr.copyFrom(values, sourceStart, destStart, count); + } + public void copyFrom(Value[] arr, int sourceStart, int destStart, int count) { + alloc(destStart + count); + System.arraycopy(arr, sourceStart, values, destStart, count); + if (size < destStart + count) size = destStart + count; + } - public void move(int srcI, int dstI, int n) { - values = alloc(dstI + n); - System.arraycopy(values, srcI, values, dstI, n); - if (dstI + n >= size) size = dstI + n; - } + public void move(int srcI, int dstI, int n) { + values = alloc(dstI + n); + System.arraycopy(values, srcI, values, dstI, n); + if (dstI + n >= size) size = dstI + n; + } - public void sort(Comparator comparator) { - Arrays.sort(values, 0, size, (a, b) -> { - var _a = 0; - var _b = 0; + public void sort(Comparator comparator) { + Arrays.sort(values, 0, size, (a, b) -> { + var _a = 0; + var _b = 0; - if (a == null) _a = 2; - if (a instanceof VoidValue) _a = 1; + if (a == null) _a = 2; + if (a instanceof VoidValue) _a = 1; - if (b == null) _b = 2; - if (b instanceof VoidValue) _b = 1; + if (b == null) _b = 2; + if (b instanceof VoidValue) _b = 1; - if (_a != 0 || _b != 0) return Integer.compare(_a, _b); + if (_a != 0 || _b != 0) return Integer.compare(_a, _b); - return comparator.compare(a, b); - }); - } + return comparator.compare(a, b); + }); + } - @Override public Iterator iterator() { - return new Iterator<>() { - private int i = 0; + @Override public Iterator iterator() { + return new Iterator<>() { + private int i = 0; - @Override public boolean hasNext() { - return i < size(); - } - @Override public Value next() { - if (!hasNext()) return null; - return get(i++); - } - }; - } + @Override public boolean hasNext() { + return i < size(); + } + @Override public Value next() { + if (!hasNext()) return null; + return get(i++); + } + }; + } - public ArrayValue() { - this(16); - } - public ArrayValue(int cap) { - setPrototype(ARRAY_PROTO); - values = new Value[Math.min(cap, 16)]; - size = 0; - } - public ArrayValue(Value ...values) { - this(); - copyFrom(values, 0, 0, values.length); - } + public ArrayValue() { + this(16); + } + public ArrayValue(int cap) { + setPrototype(ARRAY_PROTO); + values = new Value[Math.min(cap, 16)]; + size = 0; + } + public ArrayValue(Value ...values) { + this(); + copyFrom(values, 0, 0, values.length); + } - public static ArrayValue of(Collection values) { - return new ArrayValue(values.toArray(new Value[0])); - } + public static ArrayValue of(Collection values) { + return new ArrayValue(values.toArray(new Value[0])); + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ByteBufferValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ByteBufferValue.java index aac4d1e..1be772a 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ByteBufferValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ByteBufferValue.java @@ -8,74 +8,74 @@ import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public class ByteBufferValue extends ArrayLikeValue implements Iterable { - public final byte[] values; + public final byte[] values; - public int size() { return values.length; } - public boolean setSize(int val) { return false; } + public int size() { return values.length; } + public boolean setSize(int val) { return false; } - @Override public Value get(int i) { - if (i < 0 || i >= values.length) return null; - return NumberValue.of(values[i]); - } - @Override public boolean set(Environment env, int i, Value val) { - if (i < 0 || i >= values.length) return false; - values[i] = (byte)val.toNumber(env).getInt(); - return true; - } - @Override public boolean has(int i) { - return i >= 0 && i < values.length; - } - @Override public boolean remove(int i) { - return false; - } + @Override public Value get(int i) { + if (i < 0 || i >= values.length) return null; + return NumberValue.of(values[i]); + } + @Override public boolean set(Environment env, int i, Value val) { + if (i < 0 || i >= values.length) return false; + values[i] = (byte)val.toNumber(env).getInt(); + return true; + } + @Override public boolean has(int i) { + return i >= 0 && i < values.length; + } + @Override public boolean remove(int i) { + return false; + } - public void copyTo(byte[] arr, int sourceStart, int destStart, int count) { - System.arraycopy(values, sourceStart, arr, destStart, count); - } - public void copyTo(ByteBufferValue arr, int sourceStart, int destStart, int count) { - arr.copyFrom(values, sourceStart, destStart, count); - } - public void copyFrom(byte[] arr, int sourceStart, int destStart, int count) { - System.arraycopy(arr, sourceStart, arr, destStart, count); - } + public void copyTo(byte[] arr, int sourceStart, int destStart, int count) { + System.arraycopy(values, sourceStart, arr, destStart, count); + } + public void copyTo(ByteBufferValue arr, int sourceStart, int destStart, int count) { + arr.copyFrom(values, sourceStart, destStart, count); + } + public void copyFrom(byte[] arr, int sourceStart, int destStart, int count) { + System.arraycopy(arr, sourceStart, arr, destStart, count); + } - public void move(int srcI, int dstI, int n) { - System.arraycopy(values, srcI, values, dstI, n); - } + public void move(int srcI, int dstI, int n) { + System.arraycopy(values, srcI, values, dstI, n); + } - public void sort() { - var buckets = new int[256]; + public void sort() { + var buckets = new int[256]; - for (var i = 0; i < values.length; i++) { - buckets[values[i] + 128]++; - } + for (var i = 0; i < values.length; i++) { + buckets[values[i] + 128]++; + } - var offset = 0; + var offset = 0; - for (var i = 0; i < values.length; i++) { - Arrays.fill(values, offset, offset += buckets[i], (byte)(i - 128)); - } - } + for (var i = 0; i < values.length; i++) { + Arrays.fill(values, offset, offset += buckets[i], (byte)(i - 128)); + } + } - @Override public Iterator iterator() { - return new Iterator<>() { - private int i = 0; + @Override public Iterator iterator() { + return new Iterator<>() { + private int i = 0; - @Override public boolean hasNext() { - return i < size(); - } - @Override public Value next() { - if (!hasNext()) return null; - return get(i++); - } - }; - } + @Override public boolean hasNext() { + return i < size(); + } + @Override public Value next() { + if (!hasNext()) return null; + return get(i++); + } + }; + } - public ByteBufferValue(int size) { - this(new byte[size]); - } - public ByteBufferValue(byte[] buffer) { - setPrototype(BYTE_BUFF_PROTO); - this.values = buffer; - } + public ByteBufferValue(int size) { + this(new byte[size]); + } + public ByteBufferValue(byte[] buffer) { + setPrototype(BYTE_BUFF_PROTO); + this.values = buffer; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ObjectValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ObjectValue.java index 12e67b0..2e2f7e9 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ObjectValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ObjectValue.java @@ -21,207 +21,207 @@ import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public class ObjectValue extends Value { - public static interface PrototypeProvider { - public ObjectValue get(Environment env); - } + public static interface PrototypeProvider { + public ObjectValue get(Environment env); + } - public static class Property { - public final FunctionValue getter; - public final FunctionValue setter; + public static class Property { + public final FunctionValue getter; + public final FunctionValue setter; - public Property(FunctionValue getter, FunctionValue setter) { - this.getter = getter; - this.setter = setter; - } - } + public Property(FunctionValue getter, FunctionValue setter) { + this.getter = getter; + this.setter = setter; + } + } - protected PrototypeProvider prototype; + protected PrototypeProvider prototype; - public LinkedHashMap members = new LinkedHashMap<>(); - public LinkedHashMap symbolMembers = new LinkedHashMap<>(); + public LinkedHashMap members = new LinkedHashMap<>(); + public LinkedHashMap symbolMembers = new LinkedHashMap<>(); - @Override public boolean isPrimitive() { return false; } - @Override public Value toPrimitive(Environment env) { - if (env != null) { - var valueOf = getMember(env, "valueOf"); + @Override public boolean isPrimitive() { return false; } + @Override public Value toPrimitive(Environment env) { + if (env != null) { + var valueOf = getMember(env, "valueOf"); - if (valueOf instanceof FunctionValue) { - var res = valueOf.apply(env, this); - if (res.isPrimitive()) return res; - } + if (valueOf instanceof FunctionValue) { + var res = valueOf.apply(env, this); + if (res.isPrimitive()) return res; + } - var toString = getMember(env, "toString"); - if (toString instanceof FunctionValue) { - var res = toString.apply(env, this); - if (res.isPrimitive()) return res; - } - } + var toString = getMember(env, "toString"); + if (toString instanceof FunctionValue) { + var res = toString.apply(env, this); + if (res.isPrimitive()) return res; + } + } - throw EngineException.ofType("Value couldn't be converted to a primitive."); - } - @Override public String toString(Environment env) { return toPrimitive(env).toString(env); } - @Override public boolean toBoolean() { return true; } - @Override public NumberValue toNumber(Environment env) { return toPrimitive(env).toNumber(env); } - @Override public StringValue type() { return StringValue.of("object"); } + throw EngineException.ofType("Value couldn't be converted to a primitive."); + } + @Override public String toString(Environment env) { return toPrimitive(env).toString(env); } + @Override public boolean toBoolean() { return true; } + @Override public NumberValue toNumber(Environment env) { return toPrimitive(env).toNumber(env); } + @Override public StringValue type() { return StringValue.of("object"); } - private State state = State.NORMAL; + private State state = State.NORMAL; - @Override public State getState() { return state; } + @Override public State getState() { return state; } - public final void preventExtensions() { - if (state == State.NORMAL) state = State.NON_EXTENDABLE; - } - public final void seal() { - if (state == State.NORMAL || state == State.NON_EXTENDABLE) state = State.SEALED; - } - @Override public final void freeze() { state = State.FROZEN; } + public final void preventExtensions() { + if (state == State.NORMAL) state = State.NON_EXTENDABLE; + } + public final void seal() { + if (state == State.NORMAL || state == State.NON_EXTENDABLE) state = State.SEALED; + } + @Override public final void freeze() { state = State.FROZEN; } - @Override public Member getOwnMember(Environment env, KeyCache key) { - if (key.isSymbol()) { - if (symbolMembers.size() > 0) return symbolMembers.get(key.toSymbol()); - else return null; - } - else if (members.size() > 0) return members.get(key.toString(env)); - else return null; - } - @Override public boolean defineOwnMember(Environment env, KeyCache key, Member member) { - var old = getOwnMember(env, key); - if (old != null && old.redefine(env, member, this)) return true; - if (old != null && !old.configurable()) return false; + @Override public Member getOwnMember(Environment env, KeyCache key) { + if (key.isSymbol()) { + if (symbolMembers.size() > 0) return symbolMembers.get(key.toSymbol()); + else return null; + } + else if (members.size() > 0) return members.get(key.toString(env)); + else return null; + } + @Override public boolean defineOwnMember(Environment env, KeyCache key, Member member) { + var old = getOwnMember(env, key); + if (old != null && old.redefine(env, member, this)) return true; + if (old != null && !old.configurable()) return false; - if (key.isSymbol()) symbolMembers.put(key.toSymbol(), member); - else members.put(key.toString(env), member); + if (key.isSymbol()) symbolMembers.put(key.toSymbol(), member); + else members.put(key.toString(env), member); - return true; - } - @Override public boolean deleteOwnMember(Environment env, KeyCache key) { - if (!getState().extendable) return false; + return true; + } + @Override public boolean deleteOwnMember(Environment env, KeyCache key) { + if (!getState().extendable) return false; - var member = getOwnMember(env, key); - if (member == null) return true; - if (!member.configurable()) return false; + var member = getOwnMember(env, key); + if (member == null) return true; + if (!member.configurable()) return false; - if (key.isSymbol()) symbolMembers.remove(key.toSymbol()); - else members.remove(key.toString(env)); - return true; - } + if (key.isSymbol()) symbolMembers.remove(key.toSymbol()); + else members.remove(key.toString(env)); + return true; + } - @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { - if (onlyEnumerable) { - var res = new LinkedHashSet(); + @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { + if (onlyEnumerable) { + var res = new LinkedHashSet(); - for (var el : members.entrySet()) { - if (el.getValue().enumerable()) res.add(el.getKey()); - } + for (var el : members.entrySet()) { + if (el.getValue().enumerable()) res.add(el.getKey()); + } - return res; - } - else return members.keySet(); - } - @Override public Set getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { - if (onlyEnumerable) { - var res = new LinkedHashSet(); + return res; + } + else return members.keySet(); + } + @Override public Set getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { + if (onlyEnumerable) { + var res = new LinkedHashSet(); - for (var el : symbolMembers.entrySet()) { - if (el.getValue().enumerable()) res.add(el.getKey()); - } + for (var el : symbolMembers.entrySet()) { + if (el.getValue().enumerable()) res.add(el.getKey()); + } - return res; - } - else return symbolMembers.keySet(); - } + return res; + } + else return symbolMembers.keySet(); + } - @Override public ObjectValue getPrototype(Environment env) { - if (prototype == null || env == null) return null; - else return prototype.get(env); - } - @Override public final boolean setPrototype(Environment env, ObjectValue val) { - return setPrototype(_env -> val); - } + @Override public ObjectValue getPrototype(Environment env) { + if (prototype == null || env == null) return null; + else return prototype.get(env); + } + @Override public final boolean setPrototype(Environment env, ObjectValue val) { + return setPrototype(_env -> val); + } - private final LinkedList memberToReadable(Environment env, String key, Member member, HashSet passed) { - if (member instanceof PropertyMember prop) { - if (prop.getter == null && prop.setter == null) return new LinkedList<>(Arrays.asList(key + ": [No accessors]")); - else if (prop.getter == null) return new LinkedList<>(Arrays.asList(key + ": [Setter]")); - else if (prop.setter == null) return new LinkedList<>(Arrays.asList(key + ": [Getter]")); - else return new LinkedList<>(Arrays.asList(key + ": [Getter/Setter]")); - } - else { - var res = new LinkedList(); - var first = true; + private final LinkedList memberToReadable(Environment env, String key, Member member, HashSet passed) { + if (member instanceof PropertyMember prop) { + if (prop.getter == null && prop.setter == null) return new LinkedList<>(Arrays.asList(key + ": [No accessors]")); + else if (prop.getter == null) return new LinkedList<>(Arrays.asList(key + ": [Setter]")); + else if (prop.setter == null) return new LinkedList<>(Arrays.asList(key + ": [Getter]")); + else return new LinkedList<>(Arrays.asList(key + ": [Getter/Setter]")); + } + else { + var res = new LinkedList(); + var first = true; - for (var line : member.get(env, this).toReadableLines(env, passed)) { - if (first) res.add(key + ": " + line); - else res.add(line); - first = false; - } + for (var line : member.get(env, this).toReadableLines(env, passed)) { + if (first) res.add(key + ": " + line); + else res.add(line); + first = false; + } - return res; - } - } + return res; + } + } - public List toReadableLines(Environment env, HashSet passed, HashSet ignoredKeys) { - passed.add(this); + public List toReadableLines(Environment env, HashSet passed, HashSet ignoredKeys) { + passed.add(this); - var stringified = new LinkedList>(); + var stringified = new LinkedList>(); - for (var entry : getOwnSymbolMembers(env, true)) { - var member = getOwnMember(env, entry); - stringified.add(memberToReadable(env, "[" + entry.value + "]", member, passed)); - } - for (var entry : getOwnMembers(env, true)) { - if (ignoredKeys.contains(entry)) continue; + for (var entry : getOwnSymbolMembers(env, true)) { + var member = getOwnMember(env, entry); + stringified.add(memberToReadable(env, "[" + entry.value + "]", member, passed)); + } + for (var entry : getOwnMembers(env, true)) { + if (ignoredKeys.contains(entry)) continue; - var member = getOwnMember(env, entry); - stringified.add(memberToReadable(env, entry, member, passed)); - } + var member = getOwnMember(env, entry); + stringified.add(memberToReadable(env, entry, member, passed)); + } - passed.remove(this); + passed.remove(this); - if (stringified.size() == 0) return Arrays.asList("{}"); - var concat = new StringBuilder(); - for (var entry : stringified) { - // We make a one-liner only when all members are one-liners - if (entry.size() != 1) { - concat = null; - break; - } + if (stringified.size() == 0) return Arrays.asList("{}"); + var concat = new StringBuilder(); + for (var entry : stringified) { + // We make a one-liner only when all members are one-liners + if (entry.size() != 1) { + concat = null; + break; + } - if (concat.length() != 0) concat.append(", "); - concat.append(entry.get(0)); - } + if (concat.length() != 0) concat.append(", "); + concat.append(entry.get(0)); + } - // We don't want too long one-liners - if (concat != null && concat.length() < 80) return Arrays.asList("{ " + concat.toString() + " }"); + // We don't want too long one-liners + if (concat != null && concat.length() < 80) return Arrays.asList("{ " + concat.toString() + " }"); - var res = new LinkedList(); + var res = new LinkedList(); - res.add("{"); + res.add("{"); - for (var entry : stringified) { - for (var line : entry) { - res.add(" " + line); - } + for (var entry : stringified) { + for (var line : entry) { + res.add(" " + line); + } - res.set(res.size() - 1, res.getLast() + ","); - } - res.set(res.size() - 1, res.getLast().substring(0, res.getLast().length() - 1)); - res.add("}"); + res.set(res.size() - 1, res.getLast() + ","); + } + res.set(res.size() - 1, res.getLast().substring(0, res.getLast().length() - 1)); + res.add("}"); - return res; - } - @Override public List toReadableLines(Environment env, HashSet passed) { - return toReadableLines(env, passed, new HashSet<>()); - } + return res; + } + @Override public List toReadableLines(Environment env, HashSet passed) { + return toReadableLines(env, passed, new HashSet<>()); + } - public final boolean setPrototype(PrototypeProvider val) { - if (!getState().extendable) return false; - prototype = val; - return true; - } - public final boolean setPrototype(Key key) { - if (!getState().extendable) return false; - prototype = env -> env.get(key); - return true; - } + public final boolean setPrototype(PrototypeProvider val) { + if (!getState().extendable) return false; + prototype = val; + return true; + } + public final boolean setPrototype(Key key) { + if (!getState().extendable) return false; + prototype = env -> env.get(key); + return true; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ScopeValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ScopeValue.java index dc60a83..2c12c8f 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ScopeValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/objects/ScopeValue.java @@ -5,30 +5,30 @@ import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.Member.FieldMember; public final class ScopeValue extends ObjectValue { - private static class VariableField extends FieldMember { - private int i; + private static class VariableField extends FieldMember { + private int i; - public VariableField(int i, ScopeValue self) { - super(self, false, true, true); - this.i = i; - } + public VariableField(int i, ScopeValue self) { + super(self, false, true, true); + this.i = i; + } - @Override public Value get(Environment env, Value self) { - return ((ScopeValue)self).variables[i][0]; - } + @Override public Value get(Environment env, Value self) { + return ((ScopeValue)self).variables[i][0]; + } - @Override public boolean set(Environment env, Value val, Value self) { - ((ScopeValue)self).variables[i][0] = val; - return true; - } - } + @Override public boolean set(Environment env, Value val, Value self) { + ((ScopeValue)self).variables[i][0] = val; + return true; + } + } - public final Value[][] variables; + public final Value[][] variables; - public ScopeValue(Value[][] variables, String[] names) { - this.variables = variables; - for (var i = 0; i < names.length && i < variables.length; i++) { - defineOwnMember(Environment.empty(), i, new VariableField(i, this)); - } - } + public ScopeValue(Value[][] variables, String[] names) { + this.variables = variables; + for (var i = 0; i < names.length && i < variables.length; i++) { + defineOwnMember(Environment.empty(), i, new VariableField(i, this)); + } + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/BoolValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/BoolValue.java index 7fb5398..e70eaff 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/BoolValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/BoolValue.java @@ -5,35 +5,35 @@ import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public final class BoolValue extends PrimitiveValue { - public static final BoolValue TRUE = new BoolValue(true); - public static final BoolValue FALSE = new BoolValue(false); + public static final BoolValue TRUE = new BoolValue(true); + public static final BoolValue FALSE = new BoolValue(false); - public final boolean value; + public final boolean value; - @Override public StringValue type() { return StringValue.of("boolean"); } + @Override public StringValue type() { return StringValue.of("boolean"); } - @Override public boolean toBoolean() { return value; } - @Override public NumberValue toNumber(Environment ext) { return NumberValue.of(value ? 1 : 0); } - @Override public String toString(Environment ext) { return value ? "true" : "false"; } + @Override public boolean toBoolean() { return value; } + @Override public NumberValue toNumber(Environment ext) { return NumberValue.of(value ? 1 : 0); } + @Override public String toString(Environment ext) { return value ? "true" : "false"; } - @Override public ObjectValue getPrototype(Environment env) { - return env.get(BOOL_PROTO); - } + @Override public ObjectValue getPrototype(Environment env) { + return env.get(BOOL_PROTO); + } @Override public int hashCode() { return Boolean.hashCode(value); } - @Override public boolean equals(Object other) { - if (other == this) return true; - else if (other instanceof BoolValue bool) return value == bool.value; - else return false; - } + @Override public boolean equals(Object other) { + if (other == this) return true; + else if (other instanceof BoolValue bool) return value == bool.value; + else return false; + } - private BoolValue(boolean val) { - this.value = val; - } + private BoolValue(boolean val) { + this.value = val; + } - public static BoolValue of(boolean val) { - return val ? TRUE : FALSE; - } + public static BoolValue of(boolean val) { + return val ? TRUE : FALSE; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/PrimitiveValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/PrimitiveValue.java index 919d99d..f1be82b 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/PrimitiveValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/PrimitiveValue.java @@ -10,20 +10,20 @@ import me.topchetoeu.jscript.runtime.values.Value; import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; public abstract class PrimitiveValue extends Value { - @Override public final boolean defineOwnMember(Environment env, KeyCache key, Member member) { return false; } - @Override public final boolean deleteOwnMember(Environment env, KeyCache key) { return false; } - @Override public final boolean isPrimitive() { return true; } - @Override public final Value toPrimitive(Environment env) { return this; } + @Override public final boolean defineOwnMember(Environment env, KeyCache key, Member member) { return false; } + @Override public final boolean deleteOwnMember(Environment env, KeyCache key) { return false; } + @Override public final boolean isPrimitive() { return true; } + @Override public final Value toPrimitive(Environment env) { return this; } - @Override public final boolean setPrototype(Environment env, ObjectValue val) { return false; } + @Override public final boolean setPrototype(Environment env, ObjectValue val) { return false; } - @Override public Member getOwnMember(Environment env, KeyCache key) { return null; } - @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); } - @Override public Set getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); } + @Override public Member getOwnMember(Environment env, KeyCache key) { return null; } + @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); } + @Override public Set getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); } - @Override public State getState() { return State.FROZEN; } + @Override public State getState() { return State.FROZEN; } - @Override public void preventExtensions() {} - @Override public void seal() {} - @Override public void freeze() {} + @Override public void preventExtensions() {} + @Override public void seal() {} + @Override public void freeze() {} } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/StringValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/StringValue.java index 378dab8..d2386ae 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/StringValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/StringValue.java @@ -19,76 +19,76 @@ import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public final class StringValue extends PrimitiveValue { - private static final WeakHashMap cache = new WeakHashMap<>(); + private static final WeakHashMap cache = new WeakHashMap<>(); - public final String value; + public final String value; - @Override public StringValue type() { return of("string"); } + @Override public StringValue type() { return of("string"); } - @Override public boolean toBoolean() { return !value.equals(""); } - @Override public NumberValue toNumber(Environment ext) { - var val = value.trim(); - if (val.equals("")) return NumberValue.of(0); - var res = Parsing.parseNumber(new Source(val), 0, true); + @Override public boolean toBoolean() { return !value.equals(""); } + @Override public NumberValue toNumber(Environment ext) { + var val = value.trim(); + if (val.equals("")) return NumberValue.of(0); + var res = Parsing.parseNumber(new Source(val), 0, true); - if (res.isSuccess() && res.n == val.length()) return NumberValue.of(res.result); - else return NumberValue.NAN; - } - @Override public String toString(Environment ext) { return value; } + if (res.isSuccess() && res.n == val.length()) return NumberValue.of(res.result); + else return NumberValue.NAN; + } + @Override public String toString(Environment ext) { return value; } @Override public int hashCode() { return value.hashCode(); } - @Override public boolean equals(Object other) { - if (this == other) return true; - else if (other instanceof StringValue val) return value.length() == val.value.length() && value.equals(val.value); - else return false; - } + @Override public boolean equals(Object other) { + if (this == other) return true; + else if (other instanceof StringValue val) return value.length() == val.value.length() && value.equals(val.value); + else return false; + } - @Override public ObjectValue getPrototype(Environment env) { return env.get(STRING_PROTO); } + @Override public ObjectValue getPrototype(Environment env) { return env.get(STRING_PROTO); } - @Override public Member getOwnMember(Environment env, KeyCache key) { - if (!key.isSymbol()) { - var num = key.toNumber(env); - var i = key.toInt(env); + @Override public Member getOwnMember(Environment env, KeyCache key) { + if (!key.isSymbol()) { + var num = key.toNumber(env); + var i = key.toInt(env); - if (i == num && i >= 0 && i < value.length()) { - return FieldMember.of(this, new StringValue(value.charAt(i) + ""), false, true, false); - } - else if (key.toString(env).equals("length")) { - return FieldMember.of(this, NumberValue.of(value.length()), false, false, false); - } - } + if (i == num && i >= 0 && i < value.length()) { + return FieldMember.of(this, new StringValue(value.charAt(i) + ""), false, true, false); + } + else if (key.toString(env).equals("length")) { + return FieldMember.of(this, NumberValue.of(value.length()), false, false, false); + } + } - return super.getOwnMember(env, key); - } + return super.getOwnMember(env, key); + } - @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { - var res = new LinkedHashSet(); + @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { + var res = new LinkedHashSet(); - res.addAll(super.getOwnMembers(env, onlyEnumerable)); + res.addAll(super.getOwnMembers(env, onlyEnumerable)); - for (var i = 0; i < value.length(); i++) res.add(i + ""); + for (var i = 0; i < value.length(); i++) res.add(i + ""); - if (!onlyEnumerable) res.add("length"); + if (!onlyEnumerable) res.add("length"); - return res; - } + return res; + } - @Override public List toReadableLines(Environment env, HashSet passed) { - return Arrays.asList(JSON.stringify(JSONElement.string(value))); - } + @Override public List toReadableLines(Environment env, HashSet passed) { + return Arrays.asList(JSON.stringify(JSONElement.string(value))); + } - private StringValue(String value) { - this.value = value; - } + private StringValue(String value) { + this.value = value; + } - public static StringValue of(String value) { - if (cache.containsKey(value)) return cache.get(value); - else { - StringValue res; - cache.put(value, res = new StringValue(value)); - return res; - } - } + public static StringValue of(String value) { + if (cache.containsKey(value)) return cache.get(value); + else { + StringValue res; + cache.put(value, res = new StringValue(value)); + return res; + } + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/SymbolValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/SymbolValue.java index 08d37d0..bf7aedf 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/SymbolValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/SymbolValue.java @@ -12,46 +12,46 @@ import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public final class SymbolValue extends PrimitiveValue { - private static final HashMap registry = new HashMap<>(); + private static final HashMap registry = new HashMap<>(); - public final String value; + public final String value; - public Value key() { - return registry.containsKey(value) && registry.get(value) == this ? StringValue.of(value) : Value.UNDEFINED; - } + public Value key() { + return registry.containsKey(value) && registry.get(value) == this ? StringValue.of(value) : Value.UNDEFINED; + } - @Override public StringValue type() { return StringValue.of("symbol"); } + @Override public StringValue type() { return StringValue.of("symbol"); } - @Override public boolean toBoolean() { return false; } - @Override public String toString(Environment env) { - throw EngineException.ofType("Cannot convert a Symbol value to a string"); - } - @Override public NumberValue toNumber(Environment env) { - throw EngineException.ofType("Cannot convert a Symbol value to a number"); - } + @Override public boolean toBoolean() { return false; } + @Override public String toString(Environment env) { + throw EngineException.ofType("Cannot convert a Symbol value to a string"); + } + @Override public NumberValue toNumber(Environment env) { + throw EngineException.ofType("Cannot convert a Symbol value to a number"); + } - @Override public ObjectValue getPrototype(Environment env) { return env.get(SYMBOL_PROTO); } + @Override public ObjectValue getPrototype(Environment env) { return env.get(SYMBOL_PROTO); } - @Override public String toString() { - if (value == null) return "Symbol()"; - else return "Symbol(" + value + ")"; - } + @Override public String toString() { + if (value == null) return "Symbol()"; + else return "Symbol(" + value + ")"; + } @Override public List toReadableLines(Environment env, HashSet passed) { return Arrays.asList(toString()); } - public SymbolValue(String value) { - this.value = value; - } + public SymbolValue(String value) { + this.value = value; + } - public static SymbolValue get(String name) { - if (registry.containsKey(name)) return registry.get(name); - else { - var res = new SymbolValue(name); - registry.put(name, res); - return res; - } - } + public static SymbolValue get(String name) { + if (registry.containsKey(name)) return registry.get(name); + else { + var res = new SymbolValue(name); + registry.put(name, res); + return res; + } + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/UserValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/UserValue.java index 33985d8..5c426d3 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/UserValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/UserValue.java @@ -14,56 +14,56 @@ import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public final class UserValue extends Value { - public final T value; + public final T value; public final ObjectValue prototype; - @Override public StringValue type() { return StringValue.of("object"); } + @Override public StringValue type() { return StringValue.of("object"); } - @Override public boolean toBoolean() { return true; } - @Override public NumberValue toNumber(Environment ext) { return NumberValue.NAN; } - @Override public String toString(Environment ext) { return "[user value]"; } + @Override public boolean toBoolean() { return true; } + @Override public NumberValue toNumber(Environment ext) { return NumberValue.NAN; } + @Override public String toString(Environment ext) { return "[user value]"; } - @Override public final boolean defineOwnMember(Environment env, KeyCache key, Member member) { return false; } - @Override public final boolean deleteOwnMember(Environment env, KeyCache key) { return false; } - @Override public final boolean isPrimitive() { return false; } - @Override public final Value toPrimitive(Environment env) { return NumberValue.NAN; } + @Override public final boolean defineOwnMember(Environment env, KeyCache key, Member member) { return false; } + @Override public final boolean deleteOwnMember(Environment env, KeyCache key) { return false; } + @Override public final boolean isPrimitive() { return false; } + @Override public final Value toPrimitive(Environment env) { return NumberValue.NAN; } - @Override public final boolean setPrototype(Environment env, ObjectValue val) { return false; } + @Override public final boolean setPrototype(Environment env, ObjectValue val) { return false; } - @Override public Member getOwnMember(Environment env, KeyCache key) { return null; } - @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); } - @Override public Set getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); } + @Override public Member getOwnMember(Environment env, KeyCache key) { return null; } + @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); } + @Override public Set getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { return new HashSet<>(); } - @Override public State getState() { return State.FROZEN; } + @Override public State getState() { return State.FROZEN; } - @Override public void preventExtensions() {} - @Override public void seal() {} - @Override public void freeze() {} + @Override public void preventExtensions() {} + @Override public void seal() {} + @Override public void freeze() {} @Override public int hashCode() { return value.hashCode(); } - @Override public boolean equals(Object other) { - if (this == other) return true; - else if (other instanceof UserValue val) return Objects.equals(value, val.value); - else return false; - } + @Override public boolean equals(Object other) { + if (this == other) return true; + else if (other instanceof UserValue val) return Objects.equals(value, val.value); + else return false; + } - @Override public ObjectValue getPrototype(Environment env) { return prototype; } + @Override public ObjectValue getPrototype(Environment env) { return prototype; } - @Override public List toReadableLines(Environment env, HashSet passed) { - return Arrays.asList(value.toString()); - } + @Override public List toReadableLines(Environment env, HashSet passed) { + return Arrays.asList(value.toString()); + } - private UserValue(T value, ObjectValue prototype) { - this.value = value; + private UserValue(T value, ObjectValue prototype) { + this.value = value; this.prototype = prototype; - } + } - public static UserValue of(T value) { + public static UserValue of(T value) { return new UserValue(value, null); - } - public static UserValue of(T value, ObjectValue prototype) { + } + public static UserValue of(T value, ObjectValue prototype) { return new UserValue(value, prototype); - } + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java index 938db35..6354625 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java @@ -12,27 +12,27 @@ import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue; public final class VoidValue extends PrimitiveValue { - public final String name; - public final String type; + public final String name; + public final String type; - @Override public StringValue type() { return StringValue.of(type); } - @Override public boolean toBoolean() { return false; } - @Override public NumberValue toNumber(Environment ext) { return NumberValue.NAN; } - @Override public String toString(Environment ext) { return name; } + @Override public StringValue type() { return StringValue.of(type); } + @Override public boolean toBoolean() { return false; } + @Override public NumberValue toNumber(Environment ext) { return NumberValue.NAN; } + @Override public String toString(Environment ext) { return name; } - @Override public ObjectValue getPrototype(Environment env) { return null; } + @Override public ObjectValue getPrototype(Environment env) { return null; } - @Override public Member getOwnMember(Environment env, KeyCache key) { + @Override public Member getOwnMember(Environment env, KeyCache key) { if (key.isSymbol()) throw EngineException.ofError(String.format("Cannot read properties of %s (reading '%s')", name, key.toSymbol().toString())); else throw EngineException.ofError(String.format("Cannot read properties of %s (reading '%s')", name, key.toString(env))); - } + } - @Override public List toReadableLines(Environment env, HashSet passed) { - return Arrays.asList(name); - } + @Override public List toReadableLines(Environment env, HashSet passed) { + return Arrays.asList(name); + } - public VoidValue(String name, String type) { - this.name = name; - this.type = type; - } + public VoidValue(String name, String type) { + this.name = name; + this.type = type; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/DoubleValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/DoubleValue.java index 0c75f61..e1ad51a 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/DoubleValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/DoubleValue.java @@ -4,39 +4,39 @@ import me.topchetoeu.jscript.common.json.JSON; import me.topchetoeu.jscript.common.json.JSONElement; public final class DoubleValue extends NumberValue { - public final double value; + public final double value; - @Override public boolean isInt() { - return (int)value == value; - } - @Override public boolean isLong() { - return (long)value == value; - } - @Override public int getInt() { - return (int)value; - } - @Override public long getLong() { - return (long)value; - } - @Override public double getDouble() { - return value; - } + @Override public boolean isInt() { + return (int)value == value; + } + @Override public boolean isLong() { + return (long)value == value; + } + @Override public int getInt() { + return (int)value; + } + @Override public long getLong() { + return (long)value; + } + @Override public double getDouble() { + return value; + } - @Override public String toString() { return JSON.stringify(JSONElement.number(value)); } + @Override public String toString() { return JSON.stringify(JSONElement.number(value)); } @Override public int hashCode() { return Double.hashCode(value); } - @Override public boolean equals(Object other) { - if (this == other) return true; - else if (other instanceof NumberValue val) return value == val.getDouble(); - else return false; - } + @Override public boolean equals(Object other) { + if (this == other) return true; + else if (other instanceof NumberValue val) return value == val.getDouble(); + else return false; + } - /** - * This constructs a double value directly. In almost all cases, you want to use NumberValue.of instead - */ - public DoubleValue(double value) { - this.value = value; - } + /** + * This constructs a double value directly. In almost all cases, you want to use NumberValue.of instead + */ + public DoubleValue(double value) { + this.value = value; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/IntValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/IntValue.java index b624bdb..a4e4d79 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/IntValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/IntValue.java @@ -8,42 +8,42 @@ import me.topchetoeu.jscript.common.environment.Environment; import me.topchetoeu.jscript.runtime.values.objects.ObjectValue; public final class IntValue extends NumberValue { - public final long value; + public final long value; - @Override public boolean isInt() { - return (int)value == value; - } - @Override public boolean isLong() { - return true; - } - @Override public int getInt() { - return (int)value; - } - @Override public long getLong() { - return value; - } - @Override public double getDouble() { - return value; - } + @Override public boolean isInt() { + return (int)value == value; + } + @Override public boolean isLong() { + return true; + } + @Override public int getInt() { + return (int)value; + } + @Override public long getLong() { + return value; + } + @Override public double getDouble() { + return value; + } @Override public int hashCode() { return Long.hashCode(value); } - @Override public String toString() { return value + ""; } - @Override public boolean equals(Object other) { - if (this == other) return true; - else if (other instanceof NumberValue val) return val.isLong() && value == val.getLong(); - else return false; - } + @Override public String toString() { return value + ""; } + @Override public boolean equals(Object other) { + if (this == other) return true; + else if (other instanceof NumberValue val) return val.isLong() && value == val.getLong(); + else return false; + } - @Override public List toReadableLines(Environment env, HashSet passed) { - return Arrays.asList(value + "i"); - } + @Override public List toReadableLines(Environment env, HashSet passed) { + return Arrays.asList(value + "i"); + } - public IntValue(long value) { - this.value = value; - } - public IntValue(int value) { - this.value = value; - } + public IntValue(long value) { + this.value = value; + } + public IntValue(int value) { + this.value = value; + } } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/NumberValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/NumberValue.java index 5060d2f..c09a02a 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/NumberValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/numbers/NumberValue.java @@ -8,57 +8,57 @@ import me.topchetoeu.jscript.runtime.values.primitives.PrimitiveValue; import me.topchetoeu.jscript.runtime.values.primitives.StringValue; public abstract class NumberValue extends PrimitiveValue { - public static final NumberValue NAN = new DoubleValue(Double.NaN); + public static final NumberValue NAN = new DoubleValue(Double.NaN); - @Override public final StringValue type() { return StringValue.of("number"); } + @Override public final StringValue type() { return StringValue.of("number"); } - public abstract double getDouble(); - public abstract int getInt(); - public abstract long getLong(); + public abstract double getDouble(); + public abstract int getInt(); + public abstract long getLong(); - public abstract boolean isLong(); - public abstract boolean isInt(); + public abstract boolean isLong(); + public abstract boolean isInt(); - public abstract boolean equals(Object other); - public abstract String toString(); + public abstract boolean equals(Object other); + public abstract String toString(); - @Override public final boolean toBoolean() { return getDouble() != 0; } - @Override public final NumberValue toNumber(Environment ext) { return this; } - @Override public final String toString(Environment ext) { return toString(); } + @Override public final boolean toBoolean() { return getDouble() != 0; } + @Override public final NumberValue toNumber(Environment ext) { return this; } + @Override public final String toString(Environment ext) { return toString(); } - @Override public final ObjectValue getPrototype(Environment env) { - return env.get(NUMBER_PROTO); - } + @Override public final ObjectValue getPrototype(Environment env) { + return env.get(NUMBER_PROTO); + } - public static NumberValue parseInt(String str, int radix, boolean relaxed) { - if (radix < 2 || radix > 36) return NumberValue.NAN; + public static NumberValue parseInt(String str, int radix, boolean relaxed) { + if (radix < 2 || radix > 36) return NumberValue.NAN; - str = str.trim(); - var res = Parsing.parseInt(new Source(str), 0, "0123456789abcdefghijklmnopqrstuvwxyz".substring(0, radix), true); - if (res.isSuccess()) { - if (relaxed || res.n == str.length()) return of(res.result); - } - return NumberValue.NAN; - } - public static NumberValue parseFloat(String str, boolean relaxed) { - str = str.trim(); - var res = Parsing.parseFloat(new Source(str), 0, true); - if (res.isSuccess()) { - if (relaxed || res.n == str.length()) return of(res.result); - } - return NumberValue.NAN; - } + str = str.trim(); + var res = Parsing.parseInt(new Source(str), 0, "0123456789abcdefghijklmnopqrstuvwxyz".substring(0, radix), true); + if (res.isSuccess()) { + if (relaxed || res.n == str.length()) return of(res.result); + } + return NumberValue.NAN; + } + public static NumberValue parseFloat(String str, boolean relaxed) { + str = str.trim(); + var res = Parsing.parseFloat(new Source(str), 0, true); + if (res.isSuccess()) { + if (relaxed || res.n == str.length()) return of(res.result); + } + return NumberValue.NAN; + } - public static NumberValue of(double value) { - if (Double.isNaN(value)) return NAN; - else if ((int)value == value) return new IntValue((int)value); - else return new DoubleValue(value); - } - public static NumberValue of(long value) { - return new IntValue(value); - } - public static NumberValue of(int value) { - return new IntValue(value); - } + public static NumberValue of(double value) { + if (Double.isNaN(value)) return NAN; + else if ((int)value == value) return new IntValue((int)value); + else return new DoubleValue(value); + } + public static NumberValue of(long value) { + return new IntValue(value); + } + public static NumberValue of(int value) { + return new IntValue(value); + } } diff --git a/src/main/test/java/me/topchetoeu/jscript/TestHelloWorld.java b/src/main/test/java/me/topchetoeu/jscript/TestHelloWorld.java index efb2e25..60866ce 100644 --- a/src/main/test/java/me/topchetoeu/jscript/TestHelloWorld.java +++ b/src/main/test/java/me/topchetoeu/jscript/TestHelloWorld.java @@ -6,9 +6,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; public class TestHelloWorld { - @Test - public void testHelloWorld() { - final String message = "Hello World!"; - assertEquals("Hello World!", message); - } + @Test + public void testHelloWorld() { + final String message = "Hello World!"; + assertEquals("Hello World!", message); + } }