feat: implement non-enumerable members in classes
This commit is contained in:
parent
59e6f34a01
commit
8dee4353d4
@ -454,11 +454,11 @@ public class Instruction {
|
|||||||
return new Instruction(Type.KEYS, own, onlyEnumerable);
|
return new Instruction(Type.KEYS, own, onlyEnumerable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Instruction defProp(boolean setter) {
|
public static Instruction defProp(boolean setter, boolean enumerable) {
|
||||||
return new Instruction(Type.DEF_PROP, setter);
|
return new Instruction(Type.DEF_PROP, setter, enumerable);
|
||||||
}
|
}
|
||||||
public static Instruction defField() {
|
public static Instruction defField(boolean enumerable) {
|
||||||
return new Instruction(Type.DEF_FIELD);
|
return new Instruction(Type.DEF_FIELD, enumerable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Instruction operation(Operation op) {
|
public static Instruction operation(Operation op) {
|
||||||
|
@ -11,19 +11,20 @@ import me.topchetoeu.jscript.common.parsing.ParseRes;
|
|||||||
import me.topchetoeu.jscript.common.parsing.Parsing;
|
import me.topchetoeu.jscript.common.parsing.Parsing;
|
||||||
import me.topchetoeu.jscript.common.parsing.Source;
|
import me.topchetoeu.jscript.common.parsing.Source;
|
||||||
import me.topchetoeu.jscript.compilation.members.FieldMemberNode;
|
import me.topchetoeu.jscript.compilation.members.FieldMemberNode;
|
||||||
|
import me.topchetoeu.jscript.compilation.members.Member;
|
||||||
import me.topchetoeu.jscript.compilation.members.MethodMemberNode;
|
import me.topchetoeu.jscript.compilation.members.MethodMemberNode;
|
||||||
import me.topchetoeu.jscript.compilation.members.PropertyMemberNode;
|
import me.topchetoeu.jscript.compilation.members.PropertyMemberNode;
|
||||||
|
|
||||||
public abstract class ClassNode extends FunctionNode {
|
public abstract class ClassNode extends FunctionNode {
|
||||||
public static final class ClassBody {
|
public static final class ClassBody {
|
||||||
public final List<Node> staticMembers;
|
public final List<Member> staticMembers;
|
||||||
public final List<FieldMemberNode> protoFields;
|
public final List<FieldMemberNode> protoFields;
|
||||||
public final List<Node> protoMembers;
|
public final List<Member> protoMembers;
|
||||||
public final Parameters constructorParameters;
|
public final Parameters constructorParameters;
|
||||||
public final CompoundNode constructorBody;
|
public final CompoundNode constructorBody;
|
||||||
|
|
||||||
public ClassBody(
|
public ClassBody(
|
||||||
List<Node> staticMembers, List<FieldMemberNode> protoFields, List<Node> protoMembers,
|
List<Member> staticMembers, List<FieldMemberNode> protoFields, List<Member> protoMembers,
|
||||||
Parameters constructorParameters, CompoundNode constructorBody
|
Parameters constructorParameters, CompoundNode constructorBody
|
||||||
) {
|
) {
|
||||||
this.staticMembers = staticMembers;
|
this.staticMembers = staticMembers;
|
||||||
@ -34,13 +35,15 @@ public abstract class ClassNode extends FunctionNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public static final Key<Void>
|
||||||
|
|
||||||
public final ClassBody body;
|
public final ClassBody body;
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
@Override public String name() { return name; }
|
@Override public String name() { return name; }
|
||||||
|
|
||||||
public void compileStatic(CompileResult target) {
|
public void compileStatic(CompileResult target) {
|
||||||
for (var member : body.staticMembers) member.compile(target, true);
|
for (var member : body.staticMembers) member.compile(target, true, false);
|
||||||
}
|
}
|
||||||
public void compilePrototype(CompileResult target) {
|
public void compilePrototype(CompileResult target) {
|
||||||
if (body.protoMembers.size() > 0) {
|
if (body.protoMembers.size() > 0) {
|
||||||
@ -48,17 +51,17 @@ public abstract class ClassNode extends FunctionNode {
|
|||||||
target.add(Instruction.loadMember("prototype"));
|
target.add(Instruction.loadMember("prototype"));
|
||||||
|
|
||||||
for (var i = 0; i < body.protoMembers.size() - 1; i++) {
|
for (var i = 0; i < body.protoMembers.size() - 1; i++) {
|
||||||
body.protoMembers.get(i).compile(target, true);
|
body.protoMembers.get(i).compile(target, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.protoMembers.get(body.protoMembers.size() - 1).compile(target, false);
|
body.protoMembers.get(body.protoMembers.size() - 1).compile(target, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override protected void compilePreBody(CompileResult target) {
|
@Override protected void compilePreBody(CompileResult target) {
|
||||||
for (var member : body.protoFields) {
|
for (var member : body.protoFields) {
|
||||||
target.add(Instruction.loadThis());
|
target.add(Instruction.loadThis());
|
||||||
member.compile(target, false);
|
member.compile(target, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +79,7 @@ public abstract class ClassNode extends FunctionNode {
|
|||||||
this.body = body;
|
this.body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ParseRes<Node> parseMember(Source src, int i) {
|
public static ParseRes<Member> parseMember(Source src, int i) {
|
||||||
return ParseRes.first(src, i,
|
return ParseRes.first(src, i,
|
||||||
PropertyMemberNode::parse,
|
PropertyMemberNode::parse,
|
||||||
FieldMemberNode::parseClass,
|
FieldMemberNode::parseClass,
|
||||||
@ -93,8 +96,8 @@ public abstract class ClassNode extends FunctionNode {
|
|||||||
n += Parsing.skipEmpty(src, i + n);
|
n += Parsing.skipEmpty(src, i + n);
|
||||||
|
|
||||||
var fields = new LinkedList<FieldMemberNode>();
|
var fields = new LinkedList<FieldMemberNode>();
|
||||||
var members = new LinkedList<Node>();
|
var members = new LinkedList<Member>();
|
||||||
var statics = new LinkedList<Node>();
|
var statics = new LinkedList<Member>();
|
||||||
|
|
||||||
var params = new Parameters(new ArrayList<>());
|
var params = new Parameters(new ArrayList<>());
|
||||||
var body = new CompoundNode(loc, false);
|
var body = new CompoundNode(loc, false);
|
||||||
@ -106,7 +109,7 @@ public abstract class ClassNode extends FunctionNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ParseRes<Node> prop = parseMember(src, i + n);
|
ParseRes<Member> prop = parseMember(src, i + n);
|
||||||
|
|
||||||
if (prop.isSuccess()) {
|
if (prop.isSuccess()) {
|
||||||
n += prop.n;
|
n += prop.n;
|
||||||
|
@ -27,10 +27,6 @@ public abstract class FunctionNode extends Node {
|
|||||||
public final CompileResult compileBody(Environment env, FunctionScope scope, boolean lastReturn, String _name, String selfName) {
|
public final CompileResult compileBody(Environment env, FunctionScope scope, boolean lastReturn, String _name, String selfName) {
|
||||||
var name = this.name() != null ? this.name() : _name;
|
var name = this.name() != null ? this.name() : _name;
|
||||||
|
|
||||||
env = env.child()
|
|
||||||
.remove(LabelContext.BREAK_CTX)
|
|
||||||
.remove(LabelContext.CONTINUE_CTX);
|
|
||||||
|
|
||||||
return new CompileResult(env, scope, params.params.size(), target -> {
|
return new CompileResult(env, scope, params.params.size(), target -> {
|
||||||
compilePreBody(target);
|
compilePreBody(target);
|
||||||
|
|
||||||
@ -68,7 +64,7 @@ public abstract class FunctionNode extends Node {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
public final CompileResult compileBody(CompileResult parent, String name, String selfName) {
|
public final CompileResult compileBody(CompileResult parent, String name, String selfName) {
|
||||||
return compileBody(parent.env, new FunctionScope(parent.scope), false, name, selfName);
|
return compileBody(parent.env.get(JavaScript.COMPILE_ROOT).child(), new FunctionScope(parent.scope), false, name, selfName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void compile(CompileResult target, boolean pollute, String name, BreakpointType bp);
|
public abstract void compile(CompileResult target, boolean pollute, String name, BreakpointType bp);
|
||||||
|
@ -7,6 +7,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.common.SyntaxException;
|
import me.topchetoeu.jscript.common.SyntaxException;
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
import me.topchetoeu.jscript.common.environment.Environment;
|
||||||
|
import me.topchetoeu.jscript.common.environment.Key;
|
||||||
import me.topchetoeu.jscript.common.parsing.Filename;
|
import me.topchetoeu.jscript.common.parsing.Filename;
|
||||||
import me.topchetoeu.jscript.common.parsing.ParseRes;
|
import me.topchetoeu.jscript.common.parsing.ParseRes;
|
||||||
import me.topchetoeu.jscript.common.parsing.Parsing;
|
import me.topchetoeu.jscript.common.parsing.Parsing;
|
||||||
@ -31,6 +32,7 @@ import me.topchetoeu.jscript.compilation.values.ArrayNode;
|
|||||||
import me.topchetoeu.jscript.compilation.values.ClassValueNode;
|
import me.topchetoeu.jscript.compilation.values.ClassValueNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.ObjectNode;
|
import me.topchetoeu.jscript.compilation.values.ObjectNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.RegexNode;
|
import me.topchetoeu.jscript.compilation.values.RegexNode;
|
||||||
|
import me.topchetoeu.jscript.compilation.values.SuperNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.ThisNode;
|
import me.topchetoeu.jscript.compilation.values.ThisNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.VariableNode;
|
import me.topchetoeu.jscript.compilation.values.VariableNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.constants.BoolNode;
|
import me.topchetoeu.jscript.compilation.values.constants.BoolNode;
|
||||||
@ -59,6 +61,8 @@ public final class JavaScript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Key<Environment> COMPILE_ROOT = Key.of();
|
||||||
|
|
||||||
static final Set<String> reserved = new HashSet<>(Arrays.asList(
|
static final Set<String> reserved = new HashSet<>(Arrays.asList(
|
||||||
"true", "false", "void", "null", "this", "if", "else", "try", "catch",
|
"true", "false", "void", "null", "this", "if", "else", "try", "catch",
|
||||||
"finally", "for", "do", "while", "switch", "case", "default", "new",
|
"finally", "for", "do", "while", "switch", "case", "default", "new",
|
||||||
@ -120,6 +124,7 @@ public final class JavaScript {
|
|||||||
if (id.result.equals("false")) return ParseRes.res(new BoolNode(loc, false), 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("null")) return ParseRes.res(new NullNode(loc), n);
|
||||||
if (id.result.equals("this")) return ParseRes.res(new ThisNode(loc), n);
|
if (id.result.equals("this")) return ParseRes.res(new ThisNode(loc), n);
|
||||||
|
if (id.result.equals("super")) return ParseRes.res(new SuperNode(loc), n);
|
||||||
if (id.result.equals("arguments")) return ParseRes.res(new ArgumentsNode(loc), n);
|
if (id.result.equals("arguments")) return ParseRes.res(new ArgumentsNode(loc), n);
|
||||||
|
|
||||||
return ParseRes.failed();
|
return ParseRes.failed();
|
||||||
@ -264,6 +269,9 @@ public final class JavaScript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static CompileResult compile(Environment env, Node ...statements) {
|
public static CompileResult compile(Environment env, Node ...statements) {
|
||||||
|
env = env.child();
|
||||||
|
env.add(COMPILE_ROOT, env);
|
||||||
|
|
||||||
var func = new FunctionValueNode(null, null, new Parameters(Arrays.asList()), new CompoundNode(null, true, statements), null);
|
var func = new FunctionValueNode(null, null, new Parameters(Arrays.asList()), new CompoundNode(null, true, statements), null);
|
||||||
var res = func.compileBody(env, new FunctionScope(true), true, null, null);
|
var res = func.compileBody(env, new FunctionScope(true), true, null, null);
|
||||||
res.buildTask.run();
|
res.buildTask.run();
|
||||||
|
@ -13,17 +13,20 @@ import me.topchetoeu.jscript.compilation.values.VariableNode;
|
|||||||
import me.topchetoeu.jscript.compilation.values.constants.StringNode;
|
import me.topchetoeu.jscript.compilation.values.constants.StringNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.operations.AssignNode;
|
import me.topchetoeu.jscript.compilation.values.operations.AssignNode;
|
||||||
|
|
||||||
public class AssignShorthandNode extends Node {
|
public class AssignShorthandNode implements Member {
|
||||||
|
public final Location loc;
|
||||||
public final Node key;
|
public final Node key;
|
||||||
public final AssignTarget target;
|
public final AssignTarget target;
|
||||||
public final Node value;
|
public final Node value;
|
||||||
|
|
||||||
@Override public void compile(CompileResult target, boolean pollute) {
|
@Override public Location loc() { return loc; }
|
||||||
|
|
||||||
|
@Override public void compile(CompileResult target, boolean pollute, boolean enumerable) {
|
||||||
throw new SyntaxException(loc(), "Unexpected assign shorthand in non-destructor context");
|
throw new SyntaxException(loc(), "Unexpected assign shorthand in non-destructor context");
|
||||||
}
|
}
|
||||||
|
|
||||||
public AssignShorthandNode(Location loc, Node key, AssignTarget target, Node value) {
|
public AssignShorthandNode(Location loc, Node key, AssignTarget target, Node value) {
|
||||||
super(loc);
|
this.loc = loc;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
@ -12,22 +12,25 @@ import me.topchetoeu.jscript.compilation.values.ObjectNode;
|
|||||||
import me.topchetoeu.jscript.compilation.values.VariableNode;
|
import me.topchetoeu.jscript.compilation.values.VariableNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.constants.StringNode;
|
import me.topchetoeu.jscript.compilation.values.constants.StringNode;
|
||||||
|
|
||||||
public class FieldMemberNode extends Node {
|
public class FieldMemberNode implements Member {
|
||||||
|
public final Location loc;
|
||||||
public final Node key;
|
public final Node key;
|
||||||
public final Node value;
|
public final Node value;
|
||||||
|
|
||||||
@Override public void compile(CompileResult target, boolean pollute) {
|
@Override public Location loc() { return loc; }
|
||||||
|
|
||||||
|
@Override public void compile(CompileResult target, boolean pollute, boolean enumerable) {
|
||||||
if (pollute) target.add(Instruction.dup());
|
if (pollute) target.add(Instruction.dup());
|
||||||
key.compile(target, true);
|
key.compile(target, true);
|
||||||
|
|
||||||
if (value == null) target.add(Instruction.pushUndefined());
|
if (value == null) target.add(Instruction.pushUndefined());
|
||||||
else value.compile(target, true);
|
else value.compile(target, true);
|
||||||
|
|
||||||
target.add(Instruction.defField());
|
target.add(Instruction.defField(enumerable));
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldMemberNode(Location loc, Node key, Node value) {
|
public FieldMemberNode(Location loc, Node key, Node value) {
|
||||||
super(loc);
|
this.loc = loc;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package me.topchetoeu.jscript.compilation.members;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.common.parsing.Location;
|
||||||
|
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||||
|
|
||||||
|
public interface Member {
|
||||||
|
Location loc();
|
||||||
|
|
||||||
|
void compile(CompileResult target, boolean pollute, boolean enumerable);
|
||||||
|
}
|
@ -14,7 +14,7 @@ import me.topchetoeu.jscript.compilation.Parameters;
|
|||||||
import me.topchetoeu.jscript.compilation.values.ObjectNode;
|
import me.topchetoeu.jscript.compilation.values.ObjectNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.constants.StringNode;
|
import me.topchetoeu.jscript.compilation.values.constants.StringNode;
|
||||||
|
|
||||||
public class MethodMemberNode extends FunctionNode {
|
public class MethodMemberNode extends FunctionNode implements Member {
|
||||||
public final Node key;
|
public final Node key;
|
||||||
|
|
||||||
@Override public String name() {
|
@Override public String name() {
|
||||||
@ -28,8 +28,11 @@ public class MethodMemberNode extends FunctionNode {
|
|||||||
|
|
||||||
var id = target.addChild(compileBody(target, name, null));
|
var id = target.addChild(compileBody(target, name, null));
|
||||||
target.add(_i -> Instruction.loadFunc(id, true, false, false, name, captures(id, target)));
|
target.add(_i -> Instruction.loadFunc(id, true, false, false, name, captures(id, target)));
|
||||||
|
}
|
||||||
|
|
||||||
target.add(Instruction.defField());
|
@Override public void compile(CompileResult target, boolean pollute, boolean enumerable) {
|
||||||
|
compile(target, pollute);
|
||||||
|
target.add(Instruction.defField(enumerable));
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodMemberNode(Location loc, Location end, Node key, Parameters params, CompoundNode body) {
|
public MethodMemberNode(Location loc, Location end, Node key, Parameters params, CompoundNode body) {
|
||||||
|
@ -17,7 +17,7 @@ import me.topchetoeu.jscript.compilation.patterns.Pattern;
|
|||||||
import me.topchetoeu.jscript.compilation.values.ObjectNode;
|
import me.topchetoeu.jscript.compilation.values.ObjectNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.constants.StringNode;
|
import me.topchetoeu.jscript.compilation.values.constants.StringNode;
|
||||||
|
|
||||||
public class PropertyMemberNode extends FunctionNode {
|
public class PropertyMemberNode extends FunctionNode implements Member{
|
||||||
public final Node key;
|
public final Node key;
|
||||||
public final Pattern argument;
|
public final Pattern argument;
|
||||||
|
|
||||||
@ -38,8 +38,12 @@ public class PropertyMemberNode extends FunctionNode {
|
|||||||
|
|
||||||
var id = target.addChild(compileBody(target, name, null));
|
var id = target.addChild(compileBody(target, name, null));
|
||||||
target.add(_i -> Instruction.loadFunc(id, true, false, false, name, captures(id, target)));
|
target.add(_i -> Instruction.loadFunc(id, true, false, false, name, captures(id, target)));
|
||||||
|
}
|
||||||
|
|
||||||
target.add(Instruction.defProp(isSetter()));
|
|
||||||
|
@Override public void compile(CompileResult target, boolean pollute, boolean enumerable) {
|
||||||
|
compile(target, pollute);
|
||||||
|
target.add(Instruction.defProp(isSetter(), enumerable));
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyMemberNode(Location loc, Location end, Node key, Pattern argument, CompoundNode body) {
|
public PropertyMemberNode(Location loc, Location end, Node key, Pattern argument, CompoundNode body) {
|
||||||
|
@ -14,6 +14,7 @@ import me.topchetoeu.jscript.compilation.JavaScript;
|
|||||||
import me.topchetoeu.jscript.compilation.Node;
|
import me.topchetoeu.jscript.compilation.Node;
|
||||||
import me.topchetoeu.jscript.compilation.members.AssignShorthandNode;
|
import me.topchetoeu.jscript.compilation.members.AssignShorthandNode;
|
||||||
import me.topchetoeu.jscript.compilation.members.FieldMemberNode;
|
import me.topchetoeu.jscript.compilation.members.FieldMemberNode;
|
||||||
|
import me.topchetoeu.jscript.compilation.members.Member;
|
||||||
import me.topchetoeu.jscript.compilation.members.MethodMemberNode;
|
import me.topchetoeu.jscript.compilation.members.MethodMemberNode;
|
||||||
import me.topchetoeu.jscript.compilation.members.PropertyMemberNode;
|
import me.topchetoeu.jscript.compilation.members.PropertyMemberNode;
|
||||||
import me.topchetoeu.jscript.compilation.patterns.AssignTarget;
|
import me.topchetoeu.jscript.compilation.patterns.AssignTarget;
|
||||||
@ -23,7 +24,7 @@ import me.topchetoeu.jscript.compilation.values.constants.NumberNode;
|
|||||||
import me.topchetoeu.jscript.compilation.values.constants.StringNode;
|
import me.topchetoeu.jscript.compilation.values.constants.StringNode;
|
||||||
|
|
||||||
public class ObjectNode extends Node implements AssignTargetLike {
|
public class ObjectNode extends Node implements AssignTargetLike {
|
||||||
public final List<Node> members;
|
public final List<Member> members;
|
||||||
|
|
||||||
// TODO: Implement spreading into object
|
// TODO: Implement spreading into object
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ public class ObjectNode extends Node implements AssignTargetLike {
|
|||||||
|
|
||||||
@Override public void compile(CompileResult target, boolean pollute) {
|
@Override public void compile(CompileResult target, boolean pollute) {
|
||||||
target.add(Instruction.loadObj());
|
target.add(Instruction.loadObj());
|
||||||
for (var el : members) el.compile(target, true);
|
for (var el : members) el.compile(target, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public AssignTarget toAssignTarget() {
|
@Override public AssignTarget toAssignTarget() {
|
||||||
@ -82,7 +83,7 @@ public class ObjectNode extends Node implements AssignTargetLike {
|
|||||||
return new ObjectPattern(loc(), newMembers);
|
return new ObjectPattern(loc(), newMembers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectNode(Location loc, List<Node> map) {
|
public ObjectNode(Location loc, List<Member> map) {
|
||||||
super(loc);
|
super(loc);
|
||||||
this.members = map;
|
this.members = map;
|
||||||
}
|
}
|
||||||
@ -126,7 +127,7 @@ public class ObjectNode extends Node implements AssignTargetLike {
|
|||||||
n++;
|
n++;
|
||||||
n += Parsing.skipEmpty(src, i + n);
|
n += Parsing.skipEmpty(src, i + n);
|
||||||
|
|
||||||
var members = new LinkedList<Node>();
|
var members = new LinkedList<Member>();
|
||||||
|
|
||||||
if (src.is(i + n, "}")) {
|
if (src.is(i + n, "}")) {
|
||||||
n++;
|
n++;
|
||||||
@ -134,7 +135,7 @@ public class ObjectNode extends Node implements AssignTargetLike {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ParseRes<Node> prop = ParseRes.first(src, i + n,
|
ParseRes<Member> prop = ParseRes.first(src, i + n,
|
||||||
MethodMemberNode::parse,
|
MethodMemberNode::parse,
|
||||||
PropertyMemberNode::parse,
|
PropertyMemberNode::parse,
|
||||||
FieldMemberNode::parseObject,
|
FieldMemberNode::parseObject,
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package me.topchetoeu.jscript.compilation.values;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.common.SyntaxException;
|
||||||
|
import me.topchetoeu.jscript.common.parsing.Location;
|
||||||
|
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||||
|
import me.topchetoeu.jscript.compilation.Node;
|
||||||
|
|
||||||
|
|
||||||
|
public class SuperNode extends Node {
|
||||||
|
@Override public void compile(CompileResult target, boolean pollute) {
|
||||||
|
throw new SyntaxException(loc(), "Unexpected 'super' reference here");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SuperNode(Location loc) {
|
||||||
|
super(loc);
|
||||||
|
}
|
||||||
|
}
|
@ -45,6 +45,8 @@ public class VariableNode extends Node implements Pattern, ChangeTarget {
|
|||||||
if (i == null) return Instruction.globDef(name);
|
if (i == null) return Instruction.globDef(name);
|
||||||
else return Instruction.nop();
|
else return Instruction.nop();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
target.setLocation(loc());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void destruct(CompileResult target, DeclarationType decl, boolean shouldDeclare) {
|
@Override public void destruct(CompileResult target, DeclarationType decl, boolean shouldDeclare) {
|
||||||
@ -57,10 +59,12 @@ public class VariableNode extends Node implements Pattern, ChangeTarget {
|
|||||||
var v = target.scope.define(decl, name, loc());
|
var v = target.scope.define(decl, name, loc());
|
||||||
target.add(_i -> v.index().toInit());
|
target.add(_i -> v.index().toInit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
target.setLocation(loc());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void compile(CompileResult target, boolean pollute) {
|
@Override public void compile(CompileResult target, boolean pollute) {
|
||||||
target.add(toGet(target, loc(), name, true, false));
|
target.add(toGet(target, loc(), name, true, false)).setLocation(loc());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntFunction<Instruction> toGet(CompileResult target, Location loc, String name, boolean keep, boolean forceGet) {
|
public static IntFunction<Instruction> toGet(CompileResult target, Location loc, String name, boolean keep, boolean forceGet) {
|
||||||
|
@ -7,6 +7,7 @@ import me.topchetoeu.jscript.common.Instruction;
|
|||||||
import me.topchetoeu.jscript.common.Operation;
|
import me.topchetoeu.jscript.common.Operation;
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
import me.topchetoeu.jscript.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.Member.FieldMember;
|
||||||
import me.topchetoeu.jscript.runtime.values.Member.PropertyMember;
|
import me.topchetoeu.jscript.runtime.values.Member.PropertyMember;
|
||||||
import me.topchetoeu.jscript.runtime.values.Value;
|
import me.topchetoeu.jscript.runtime.values.Value;
|
||||||
import me.topchetoeu.jscript.runtime.values.functions.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.functions.CodeFunction;
|
||||||
@ -68,8 +69,8 @@ public class InstructionRunner {
|
|||||||
else if (val instanceof FunctionValue func) accessor = func;
|
else if (val instanceof FunctionValue func) accessor = func;
|
||||||
else throw EngineException.ofType("Getter must be a function or undefined.");
|
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));
|
if ((boolean)instr.get(0)) obj.defineOwnMember(env, key, new PropertyMember(obj, null, accessor, true, instr.get(1)));
|
||||||
else obj.defineOwnMember(env, key, new PropertyMember(obj, accessor, null, true, true));
|
else obj.defineOwnMember(env, key, new PropertyMember(obj, accessor, null, true, instr.get(1)));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return null;
|
return null;
|
||||||
@ -79,7 +80,7 @@ public class InstructionRunner {
|
|||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
|
|
||||||
obj.defineOwnMember(env, key, val);
|
obj.defineOwnMember(env, key, FieldMember.of(obj, val, true, instr.get(0), true));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// return;
|
|
||||||
|
|
||||||
const target = arguments[0];
|
const target = arguments[0];
|
||||||
const primordials = arguments[1];
|
const primordials = arguments[1];
|
||||||
|
|
||||||
@ -20,28 +18,26 @@ const symbol = primordials.symbol || (() => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const number = primordials.number || (() => {
|
const number = primordials.number || {
|
||||||
return {
|
parseInt() { throw new Error("parseInt not supported"); },
|
||||||
parseInt() { throw new Error("parseInt not supported"); },
|
parseFloat() { throw new Error("parseFloat not supported"); },
|
||||||
parseFloat() { throw new Error("parseFloat not supported"); },
|
isNaN: (val) => val !== val,
|
||||||
isNaN: (val) => val !== val,
|
NaN: 0 / 0,
|
||||||
NaN: 0 / 0,
|
Infinity: 1 / 0,
|
||||||
Infinity: 1 / 0,
|
};
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const fromCharCode = primordials.string.fromCharCode;
|
const string = primordials.string;
|
||||||
const fromCodePoint = primordials.string.fromCodePoint;
|
|
||||||
const stringBuild = primordials.string.stringBuild;
|
|
||||||
|
|
||||||
const defineProperty = primordials.object.defineProperty;
|
const object = primordials.object || {
|
||||||
const defineField = primordials.object.defineField;
|
defineProperty() { throw new Error("Define property not polyfillable"); },
|
||||||
const getOwnMember = primordials.object.getMember;
|
defineField(obj, key, a, b, c, value) { obj[key] = value; },
|
||||||
const getOwnSymbolMember = primordials.object.getOwnSymbolMember;
|
getOwnMember() { throw new Error("Get own member not polyfillable"); },
|
||||||
const getOwnMembers = primordials.object.getOwnMembers;
|
getOwnSymbolMember() { throw new Error("Get own symbol member not polyfillable"); },
|
||||||
const getOwnSymbolMembers = primordials.object.getOwnSymbolMembers;
|
getOwnMembers() { throw new Error("Get own members not polyfillable"); },
|
||||||
const getPrototype = primordials.object.getPrototype;
|
getOwnSymbolMembers() { throw new Error("Get own symbol members not polyfillable"); },
|
||||||
const setPrototype = primordials.object.setPrototype;
|
getPrototype() { throw new Error("Get prototype not polyfillable"); },
|
||||||
|
setPrototype() { throw new Error("Set prototype not polyfillable"); },
|
||||||
|
}
|
||||||
|
|
||||||
const invokeType = primordials.function.invokeType;
|
const invokeType = primordials.function.invokeType;
|
||||||
const setConstructable = primordials.function.setConstructable;
|
const setConstructable = primordials.function.setConstructable;
|
||||||
@ -97,14 +93,14 @@ class Symbol {
|
|||||||
setCallable(Symbol, true);
|
setCallable(Symbol, true);
|
||||||
setConstructable(Symbol, false);
|
setConstructable(Symbol, false);
|
||||||
|
|
||||||
defineField(Symbol, "asyncIterator", false, false, false, Symbol("Symbol.asyncIterator"));
|
object.defineField(Symbol, "asyncIterator", false, false, false, Symbol("Symbol.asyncIterator"));
|
||||||
defineField(Symbol, "iterator", false, false, false, Symbol("Symbol.iterator"));
|
object.defineField(Symbol, "iterator", false, false, false, Symbol("Symbol.iterator"));
|
||||||
defineField(Symbol, "match", false, false, false, Symbol("Symbol.match"));
|
object.defineField(Symbol, "match", false, false, false, Symbol("Symbol.match"));
|
||||||
defineField(Symbol, "matchAll", false, false, false, Symbol("Symbol.matchAll"));
|
object.defineField(Symbol, "matchAll", false, false, false, Symbol("Symbol.matchAll"));
|
||||||
defineField(Symbol, "replace", false, false, false, Symbol("Symbol.replace"));
|
object.defineField(Symbol, "replace", false, false, false, Symbol("Symbol.replace"));
|
||||||
defineField(Symbol, "search", false, false, false, Symbol("Symbol.search"));
|
object.defineField(Symbol, "search", false, false, false, Symbol("Symbol.search"));
|
||||||
defineField(Symbol, "split", false, false, false, Symbol("Symbol.split"));
|
object.defineField(Symbol, "split", false, false, false, Symbol("Symbol.split"));
|
||||||
defineField(Symbol, "toStringTag", false, false, false, Symbol("Symbol.toStringTag"));
|
object.defineField(Symbol, "toStringTag", false, false, false, Symbol("Symbol.toStringTag"));
|
||||||
|
|
||||||
Symbol();
|
Symbol();
|
||||||
target.Symbol = Symbol;
|
target.Symbol = Symbol;
|
||||||
@ -160,14 +156,14 @@ class Number {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defineField(Number, "EPSILON", false, false, false, 2.220446049250313e-16);
|
object.defineField(Number, "EPSILON", false, false, false, 2.220446049250313e-16);
|
||||||
defineField(Number, "MIN_SAFE_INTEGER", false, false, false, -9007199254740991);
|
object.defineField(Number, "MIN_SAFE_INTEGER", false, false, false, -9007199254740991);
|
||||||
defineField(Number, "MAX_SAFE_INTEGER", false, false, false, 9007199254740991);
|
object.defineField(Number, "MAX_SAFE_INTEGER", false, false, false, 9007199254740991);
|
||||||
defineField(Number, "POSITIVE_INFINITY", false, false, false, +number.Infinity);
|
object.defineField(Number, "POSITIVE_INFINITY", false, false, false, +number.Infinity);
|
||||||
defineField(Number, "NEGATIVE_INFINITY", false, false, false, -number.Infinity);
|
object.defineField(Number, "NEGATIVE_INFINITY", false, false, false, -number.Infinity);
|
||||||
defineField(Number, "NaN", false, false, false, number.NaN);
|
object.defineField(Number, "NaN", false, false, false, number.NaN);
|
||||||
defineField(Number, "MAX_VALUE", false, false, false, 1.7976931348623157e+308);
|
object.defineField(Number, "MAX_VALUE", false, false, false, 1.7976931348623157e+308);
|
||||||
defineField(Number, "MIN_VALUE", false, false, false, 5e-324);
|
object.defineField(Number, "MIN_VALUE", false, false, false, 5e-324);
|
||||||
|
|
||||||
setCallable(Number, true);
|
setCallable(Number, true);
|
||||||
target.Number = Number;
|
target.Number = Number;
|
||||||
@ -202,20 +198,20 @@ class String {
|
|||||||
res[arguments.length] = 0;
|
res[arguments.length] = 0;
|
||||||
|
|
||||||
for (let i = 0; i < arguments.length; i++) {
|
for (let i = 0; i < arguments.length; i++) {
|
||||||
res[i] = fromCharCode(+arguments[i]);
|
res[i] = string.fromCharCode(+arguments[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return stringBuild(res);
|
return string.stringBuild(res);
|
||||||
}
|
}
|
||||||
static fromCodePoint() {
|
static fromCodePoint() {
|
||||||
const res = [];
|
const res = [];
|
||||||
res[arguments.length] = 0;
|
res[arguments.length] = 0;
|
||||||
|
|
||||||
for (let i = 0; i < arguments.length; i++) {
|
for (let i = 0; i < arguments.length; i++) {
|
||||||
res[i] = fromCodePoint(+arguments[i]);
|
res[i] = string.fromCodePoint(+arguments[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return stringBuild(res);
|
return string.stringBuild(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,8 +286,6 @@ class Object {
|
|||||||
if ("get" in desc || "set" in desc) {
|
if ("get" in desc || "set" in desc) {
|
||||||
let get = desc.get, set = desc.set;
|
let get = desc.get, set = desc.set;
|
||||||
|
|
||||||
print(typeof get);
|
|
||||||
|
|
||||||
if (get !== undefined && typeof get !== "function") throw new TypeError("Getter must be a function: " + get);
|
if (get !== undefined && typeof get !== "function") throw new TypeError("Getter must be a function: " + get);
|
||||||
if (set !== undefined && typeof set !== "function") throw new TypeError("Setter must be a function: " + set);
|
if (set !== undefined && typeof set !== "function") throw new TypeError("Setter must be a function: " + set);
|
||||||
|
|
||||||
@ -299,11 +293,11 @@ class Object {
|
|||||||
throw new TypeError("Invalid property descriptor. Cannot both specify accessors and a value or writable attribute");
|
throw new TypeError("Invalid property descriptor. Cannot both specify accessors and a value or writable attribute");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defineProperty(obj, key, desc.enumerable, desc.configurable, get, set)) {
|
if (!object.defineProperty(obj, key, desc.enumerable, desc.configurable, get, set)) {
|
||||||
throw new TypeError("Cannot redefine property: " + key);
|
throw new TypeError("Cannot redefine property: " + key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!defineField(obj, key, desc.writable, desc.enumerable, desc.configurable, desc.value)) {
|
else if (!object.defineField(obj, key, desc.writable, desc.enumerable, desc.configurable, desc.value)) {
|
||||||
throw new TypeError("Cannot redefine property: " + key);
|
throw new TypeError("Cannot redefine property: " + key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,7 +306,7 @@ class Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setCallable(Object, true);
|
setCallable(Object, true);
|
||||||
setPrototype(Object.prototype, null);
|
object.setPrototype(Object.prototype, null);
|
||||||
target.Object = Object;
|
target.Object = Object;
|
||||||
|
|
||||||
class Function {
|
class Function {
|
||||||
@ -322,7 +316,7 @@ class Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const parts = ["return function annonymous("];
|
const parts = ["(function annonymous("];
|
||||||
|
|
||||||
for (let i = 0; i < arguments.length - 1; i++) {
|
for (let i = 0; i < arguments.length - 1; i++) {
|
||||||
if (i > 0) parts[parts.length] = ",";
|
if (i > 0) parts[parts.length] = ",";
|
||||||
@ -330,9 +324,9 @@ class Function {
|
|||||||
}
|
}
|
||||||
parts[parts.length] = "){\n";
|
parts[parts.length] = "){\n";
|
||||||
parts[parts.length] = String(arguments[arguments.length - 1]);
|
parts[parts.length] = String(arguments[arguments.length - 1]);
|
||||||
parts[parts.length] = "\n}";
|
parts[parts.length] = "\n})";
|
||||||
|
|
||||||
const res = compile(stringBuild(parts))();
|
const res = compile(string.stringBuild(parts))();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,27 +335,20 @@ class Function {
|
|||||||
|
|
||||||
if (wrap) parts[parts.length] = "return (function() {\n";
|
if (wrap) parts[parts.length] = "return (function() {\n";
|
||||||
if (globals.length > 0) {
|
if (globals.length > 0) {
|
||||||
parts[parts.length] = "var ";
|
parts[parts.length] = "let {";
|
||||||
|
|
||||||
for (let i = 0; i < globals.length; i++) {
|
for (let i = 0; i < globals.length; i++) {
|
||||||
if (i > 0) parts[parts.length] = ",";
|
if (i > 0) parts[parts.length] = ",";
|
||||||
parts[parts.length] = globals[i];
|
parts[parts.length] = globals[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
parts[parts.length] = ";((g=arguments[0])=>{";
|
parts[parts.length] = "} = arguments[0];";
|
||||||
|
|
||||||
for (let i = 0; i < globals.length; i++) {
|
|
||||||
const name = globals[i];
|
|
||||||
parts[parts.length] = name + "=g[" + json.stringify(name) + "];";
|
|
||||||
}
|
|
||||||
|
|
||||||
parts[parts.length] = "})()\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parts[parts.length] = src;
|
parts[parts.length] = src;
|
||||||
if (wrap) parts[parts.length] = "\n})(arguments[0])";
|
if (wrap) parts[parts.length] = "\n})(arguments[0])";
|
||||||
|
|
||||||
const res = compile(stringBuild(parts));
|
const res = compile(string.stringBuild(parts));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,8 +387,8 @@ class Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defineField(Error.prototype, "name", true, false, true, "Error");
|
object.defineField(Error.prototype, "name", true, false, true, "Error");
|
||||||
defineField(Error.prototype, "message", true, false, true, "");
|
object.defineField(Error.prototype, "message", true, false, true, "");
|
||||||
setCallable(Error, true);
|
setCallable(Error, true);
|
||||||
target.Error = Error;
|
target.Error = Error;
|
||||||
|
|
||||||
@ -412,9 +399,9 @@ class SyntaxError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defineField(SyntaxError.prototype, "name", true, false, true, "SyntaxError");
|
object.defineField(SyntaxError.prototype, "name", true, false, true, "SyntaxError");
|
||||||
setPrototype(SyntaxError, Error);
|
object.setPrototype(SyntaxError, Error);
|
||||||
setPrototype(SyntaxError.prototype, Error.prototype);
|
object.setPrototype(SyntaxError.prototype, Error.prototype);
|
||||||
setCallable(SyntaxError, true);
|
setCallable(SyntaxError, true);
|
||||||
target.SyntaxError = SyntaxError;
|
target.SyntaxError = SyntaxError;
|
||||||
|
|
||||||
@ -425,9 +412,9 @@ class TypeError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defineField(TypeError.prototype, "name", true, false, true, "TypeError");
|
object.defineField(TypeError.prototype, "name", true, false, true, "TypeError");
|
||||||
setPrototype(TypeError, Error);
|
object.setPrototype(TypeError, Error);
|
||||||
setPrototype(TypeError.prototype, Error.prototype);
|
object.setPrototype(TypeError.prototype, Error.prototype);
|
||||||
setCallable(TypeError, true);
|
setCallable(TypeError, true);
|
||||||
target.TypeError = TypeError;
|
target.TypeError = TypeError;
|
||||||
|
|
||||||
@ -438,9 +425,9 @@ class RangeError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defineField(RangeError.prototype, "name", true, false, true, "RangeError");
|
object.defineField(RangeError.prototype, "name", true, false, true, "RangeError");
|
||||||
setPrototype(RangeError, Error);
|
object.setPrototype(RangeError, Error);
|
||||||
setPrototype(RangeError.prototype, Error.prototype);
|
object.setPrototype(RangeError.prototype, Error.prototype);
|
||||||
setCallable(RangeError, true);
|
setCallable(RangeError, true);
|
||||||
target.RangeError = RangeError;
|
target.RangeError = RangeError;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user