Compare commits

..

4 Commits

14 changed files with 127 additions and 94 deletions

View File

@ -51,8 +51,7 @@ public class Instruction {
STORE_MEMBER_INT(0x4A), STORE_MEMBER_INT(0x4A),
STORE_MEMBER_STR(0x4B), STORE_MEMBER_STR(0x4B),
TYPEOF(0x53), OPERATION(0x50),
OPERATION(0x54),
GLOB_GET(0x60), GLOB_GET(0x60),
GLOB_SET(0x61), GLOB_SET(0x61),
@ -333,13 +332,6 @@ public class Instruction {
return new Instruction(Type.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 operation(Operation op) { public static Instruction operation(Operation op) {
return new Instruction(Type.OPERATION, op); return new Instruction(Type.OPERATION, op);
} }

View File

@ -3,36 +3,37 @@ package me.topchetoeu.j2s.common;
import java.util.HashMap; import java.util.HashMap;
public enum Operation { public enum Operation {
INSTANCEOF(1, 2), TYPEOF(0x10, 1),
IN(2, 2), INSTANCEOF(0x11, 2),
IN(0x12, 2),
MULTIPLY(3, 2), MULTIPLY(0x20, 2),
DIVIDE(4, 2), DIVIDE(0x21, 2),
MODULO(5, 2), MODULO(0x22, 2),
ADD(6, 2), ADD(0x23, 2),
SUBTRACT(7, 2), SUBTRACT(0x24, 2),
USHIFT_RIGHT(8, 2), USHIFT_RIGHT(0x30, 2),
SHIFT_RIGHT(9, 2), SHIFT_RIGHT(0x31, 2),
SHIFT_LEFT(10, 2), SHIFT_LEFT(0x32, 2),
GREATER(11, 2), GREATER(0x40, 2),
LESS(12, 2), LESS(0x41, 2),
GREATER_EQUALS(13, 2), GREATER_EQUALS(0x42, 2),
LESS_EQUALS(14, 2), LESS_EQUALS(0x43, 2),
LOOSE_EQUALS(15, 2), LOOSE_EQUALS(0x44, 2),
LOOSE_NOT_EQUALS(16, 2), LOOSE_NOT_EQUALS(0x45, 2),
EQUALS(17, 2), EQUALS(0x46, 2),
NOT_EQUALS(18, 2), NOT_EQUALS(0x47, 2),
AND(19, 2), AND(0x50, 2),
OR(20, 2), OR(0x51, 2),
XOR(21, 2), XOR(0x52, 2),
NEG(23, 1), NEG(0x60, 1),
POS(24, 1), POS(0x61, 1),
NOT(25, 1), NOT(0x62, 1),
INVERSE(26, 1); INVERSE(0x63, 1);
private static final HashMap<Integer, Operation> operations = new HashMap<>(); private static final HashMap<Integer, Operation> operations = new HashMap<>();

View File

@ -2,6 +2,7 @@ package me.topchetoeu.j2s.compilation.values.operations;
import me.topchetoeu.j2s.common.Instruction; import me.topchetoeu.j2s.common.Instruction;
import me.topchetoeu.j2s.common.Location; import me.topchetoeu.j2s.common.Location;
import me.topchetoeu.j2s.common.Operation;
import me.topchetoeu.j2s.compilation.CompileResult; import me.topchetoeu.j2s.compilation.CompileResult;
import me.topchetoeu.j2s.compilation.JavaScript; import me.topchetoeu.j2s.compilation.JavaScript;
import me.topchetoeu.j2s.compilation.Node; import me.topchetoeu.j2s.compilation.Node;
@ -20,14 +21,14 @@ public class TypeofNode extends Node {
@Override public void compile(CompileResult target, boolean pollute) { @Override public void compile(CompileResult target, boolean pollute) {
if (value instanceof VariableNode varNode) { if (value instanceof VariableNode varNode) {
target.add(VariableNode.toGet(target, varNode.loc(), varNode.name, true, true)); target.add(VariableNode.toGet(target, varNode.loc(), varNode.name, true, true));
if (pollute) target.add(Instruction.typeof()); if (pollute) target.add(Instruction.operation(Operation.TYPEOF));
else target.add(Instruction.discard()); else target.add(Instruction.discard());
return; return;
} }
value.compile(target, pollute); value.compile(target, pollute);
if (pollute) target.add(Instruction.typeof()); if (pollute) target.add(Instruction.operation(Operation.TYPEOF));
} }
public TypeofNode(Location loc, Node value) { public TypeofNode(Location loc, Node value) {

View File

@ -4,9 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import me.topchetoeu.j2s.compilation.parsing.Parsing;
import me.topchetoeu.j2s.compilation.parsing.Source;
public class TestParseString { public class TestParseString {
@Test public void notAString() { @Test public void notAString() {
var res = Parsing.parseString(new Source("var a = 10"), 0); var res = Parsing.parseString(new Source("var a = 10"), 0);

View File

@ -4,9 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import me.topchetoeu.j2s.compilation.parsing.Parsing;
import me.topchetoeu.j2s.compilation.parsing.Source;
public class TestSkipWhite { public class TestSkipWhite {
@Test public void shBang() { @Test public void shBang() {
var res1 = Parsing.skipEmpty(new Source("#!my-shbang\n10"), 0); var res1 = Parsing.skipEmpty(new Source("#!my-shbang\n10"), 0);

View File

@ -10,6 +10,8 @@ declare interface String {
charCodeAt(i: number): number; charCodeAt(i: number): number;
codePointAt(i: number): number; codePointAt(i: number): number;
startsWith(search: string): boolean;
endsWith(search: string): boolean;
includes(search: string, offset?: number): number; includes(search: string, offset?: number): number;
indexOf(search: string, offset?: number): number; indexOf(search: string, offset?: number): number;
lastIndexOf(search: string, offset?: number): number; lastIndexOf(search: string, offset?: number): number;

View File

@ -105,7 +105,7 @@ export interface Primordials {
exec(target: string, offset: number, indices: boolean): { matches: RegExpMatchArray, end: number } | null; exec(target: string, offset: number, indices: boolean): { matches: RegExpMatchArray, end: number } | null;
groupCount(): number; groupCount(): number;
}; };
compile(src: string): Function; compile(src: string, filename?: string): Function;
setGlobalPrototypes(prototype: Record<string, any>): void; setGlobalPrototypes(prototype: Record<string, any>): void;
now(): number; now(): number;
next(func: () => void): void; next(func: () => void): void;

View File

@ -55,23 +55,8 @@ export const Function = (() => {
return res; return res;
} }
public static compile(src = "", { globals = [], wrap = false }: { globals?: string[], wrap?: boolean } = {}) { public static compile(src: string, filename?: string) {
const parts = []; return compile(String(src), filename);
if (wrap) parts[parts.length] = "return (function() {\n";
if (globals.length > 0) {
parts[parts.length] = "let {";
for (let i = 0; i < globals.length; i++) {
if (i > 0) parts[parts.length] = ",";
parts[parts.length] = globals[i];
}
parts[parts.length] = "} = arguments[0];";
}
parts[parts.length] = src;
if (wrap) parts[parts.length] = "\n})(arguments[0])";
const res = compile(string.stringBuild(parts));
return res;
} }
} }

View File

@ -1,5 +1,5 @@
import { SourceMap } from "./map.ts"; import { SourceMap } from "./map.ts";
import { transform, availablePresets } from "@babel/standalone"; import { transform, availablePlugins } from "@babel/standalone";
export default function babel(next: Compiler): Compiler { export default function babel(next: Compiler): Compiler {
print("Loaded babel!"); print("Loaded babel!");
@ -8,7 +8,63 @@ export default function babel(next: Compiler): Compiler {
const res = transform(code, { const res = transform(code, {
filename, filename,
sourceMaps: true, sourceMaps: true,
presets: [availablePresets.env], assumptions: {
arrayLikeIsIterable: true,
constantSuper: true,
ignoreFunctionLength: true,
ignoreToPrimitiveHint: true,
mutableTemplateObject: true,
noDocumentAll: true,
noNewArrows: true,
noUninitializedPrivateFieldAccess: true,
privateFieldsAsSymbols: true,
},
plugins: [
// ES2022
availablePlugins["transform-class-properties"],
availablePlugins["transform-class-static-block"],
availablePlugins["transform-private-methods"],
availablePlugins["transform-private-property-in-object"],
// "syntax-top-level-await",
// ES2021
availablePlugins["transform-logical-assignment-operators"],
availablePlugins["transform-numeric-separator"],
// ES2020
availablePlugins["transform-optional-chaining"],
availablePlugins["transform-nullish-coalescing-operator"],
// ES2018
availablePlugins["transform-async-generator-functions"],
availablePlugins["transform-object-rest-spread"],
availablePlugins["transform-unicode-property-regex"],
// ES2017
availablePlugins["transform-async-to-generator"],
// ES2016
availablePlugins["transform-exponentiation-operator"],
// ES2015
availablePlugins["transform-block-scoping"],
availablePlugins["transform-classes"],
availablePlugins["transform-computed-properties"],
availablePlugins["transform-destructuring"],
availablePlugins["transform-duplicate-keys"],
availablePlugins["transform-for-of"],
availablePlugins["transform-function-name"],
availablePlugins["transform-literals"],
availablePlugins["transform-new-target"],
availablePlugins["transform-object-super"],
availablePlugins["transform-parameters"],
availablePlugins["transform-shorthand-properties"],
availablePlugins["transform-spread"],
availablePlugins["transform-sticky-regex"],
availablePlugins["transform-template-literals"],
availablePlugins["transform-unicode-escapes"],
availablePlugins["transform-unicode-regex"],
],
}); });
const map = SourceMap.parse({ const map = SourceMap.parse({
@ -18,7 +74,9 @@ export default function babel(next: Compiler): Compiler {
}); });
registerSource(filename, code); registerSource(filename, code);
return next("babel-internal://" + filename, res.code!, SourceMap.chain(map, prevMap)); const func = next("babel-internal://" + filename, res.code!, SourceMap.chain(map, prevMap));
func.name = filename;
return func;
}; };
} }

View File

@ -21,7 +21,9 @@ export default function coffee(next: Compiler): Compiler {
}); });
registerSource(filename, code); registerSource(filename, code);
return next("coffee-internal://" + filename, result, SourceMap.chain(map, prevMap)); const func = next("coffee-internal://" + filename, result, SourceMap.chain(map, prevMap));
func.name = filename;
return func;
}; };
} }

View File

@ -109,10 +109,12 @@ export default function typescript(next: Compiler): Compiler {
registerSource(filename, code); registerSource(filename, code);
const compiled = next("ts-internal://" + filename, result, SourceMap.chain(map, prevMap)); const compiled = next("ts-internal://" + filename, result, SourceMap.chain(map, prevMap));
return function (this: any) { const func = function (this: any) {
const res = compiled.apply(this, arguments); const res = compiled.apply(this, arguments);
if (declaration !== '') files["/src." + declI++ + ".d.ts"] = ScriptSnapshot.fromString(declaration); if (declaration !== '') files["/src." + declI++ + ".d.ts"] = ScriptSnapshot.fromString(declaration);
return res; return res;
}; };
func.name = filename;
return func;
}; };
} }

View File

@ -1,17 +1,17 @@
{ {
"include": ["**/*.ts"], "include": ["**/*.ts"],
"compilerOptions": { "compilerOptions": {
"strict": true, "strict": true,
"esModuleInterop": true, "esModuleInterop": true,
"skipLibCheck": true, "skipLibCheck": true,
"moduleResolution": "Bundler", "moduleResolution": "Bundler",
"module": "ESNext", "module": "ESNext",
"target": "ESNext", "target": "ESNext",
"noLib": true, "noLib": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
"noEmit": true "noEmit": true
} }
} }

View File

@ -786,7 +786,12 @@ public class SimpleRepl {
return Value.UNDEFINED; return Value.UNDEFINED;
})); }));
res.defineOwnField(env, "compile", new NativeFunction(args -> { res.defineOwnField(env, "compile", new NativeFunction(args -> {
return Compiler.compileFunc(env, new Filename(Metadata.name(), "func" + i[0]++ + ".js"), args.get(0).toString(env)); var nameVal = args.get(1);
var name = nameVal instanceof VoidValue ?
new Filename(Metadata.name(), "func" + i[0]++ + ".js") :
Filename.parse(nameVal.toString(args.env));
return Compiler.compileFunc(env, name, args.get(0).toString(env));
})); }));
res.defineOwnField(env, "now", new NativeFunction(args -> { res.defineOwnField(env, "now", new NativeFunction(args -> {
return NumberValue.of(System.currentTimeMillis()); return NumberValue.of(System.currentTimeMillis());

View File

@ -235,18 +235,6 @@ public class InstructionRunner {
return null; 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) { private static Value execNop(Environment env, Instruction instr, Frame frame) {
frame.codePtr++; frame.codePtr++;
return null; return null;
@ -355,6 +343,10 @@ public class InstructionRunner {
case INSTANCEOF: case INSTANCEOF:
res = BoolValue.of(stack[ptr - 1].isInstanceOf(env, stack[ptr].getMember(env, StringValue.of("prototype")))); res = BoolValue.of(stack[ptr - 1].isInstanceOf(env, stack[ptr].getMember(env, StringValue.of("prototype"))));
break; break;
case TYPEOF:
res = stack[ptr++].type();
frame.stackPtr++;
break;
default: return null; default: return null;
} }
@ -481,7 +473,6 @@ public class InstructionRunner {
case STORE_MEMBER_INT: return execStoreMemberInt(env, instr, frame); case STORE_MEMBER_INT: return execStoreMemberInt(env, instr, frame);
case STORE_VAR: return execStoreVar(env, instr, frame); case STORE_VAR: return execStoreVar(env, instr, frame);
case TYPEOF: return execTypeof(env, instr, frame);
case DELETE: return execDelete(env, instr, frame); case DELETE: return execDelete(env, instr, frame);
case JMP: return execJmp(env, instr, frame); case JMP: return execJmp(env, instr, frame);