Compare commits

...

29 Commits

Author SHA1 Message Date
31e2e95bc8 fix: prevent rollup from optimizing "void 0" to "undefined"
All checks were successful
tagged-release / Tagged Release (push) Successful in 2m29s
2025-01-09 00:13:14 +02:00
98dde69751 revert to coffeescript transpiler 2025-01-09 00:12:13 +02:00
ec1edb981e fix: register sources before the next compiler gets invoked 2025-01-09 00:11:57 +02:00
36f9839485 fix: get rid of readonly for the Location type
(only caused headaches)
2025-01-09 00:10:15 +02:00
22f36267c0 feat: add prettier printing for arrays in debugger 2025-01-09 00:09:43 +02:00
f8b9776f28 fix: for-in loop doesn't declare its binding when it has to 2025-01-09 00:09:18 +02:00
12cff84666 fix: String.lastIndexOf's offset argument must default to the string's length 2025-01-09 00:08:14 +02:00
7058a689a2 fix: Object.defineProperty passes flags wrongly 2025-01-09 00:07:51 +02:00
fde8b42e36 fix: wrong return value from array.push and array.unshift 2025-01-09 00:07:17 +02:00
4ea14ca1f5 build: enable minification 2025-01-06 17:06:10 +02:00
f6ce261485 fix: add custom global functions to ts decls 2025-01-06 17:05:59 +02:00
51b347e0d7 fix: more stable engine exit 2025-01-06 17:05:37 +02:00
0b6484e0b4 fuck
All checks were successful
tagged-release / Tagged Release (push) Successful in 2m41s
2025-01-06 14:53:27 +02:00
07e0d0ba3b fix script; bump version
Some checks failed
tagged-release / Tagged Release (push) Failing after 3m29s
2025-01-06 14:26:56 +02:00
93cae33bb0 fix: fix up script
Some checks failed
tagged-release / Tagged Release (push) Failing after 4m50s
2025-01-06 14:13:58 +02:00
b1e0db627c fix typings so they are usable for building the project itself
Some checks failed
tagged-release / Tagged Release (push) Failing after 3m24s
2025-01-06 14:02:07 +02:00
4fd05e9e6f fix up build scripts
Some checks failed
tagged-release / Tagged Release (push) Failing after 3m48s
2025-01-06 13:31:17 +02:00
de93adde8f fix: some source mapping fixes 2025-01-06 13:24:58 +02:00
5c68c1717c feat: implement some typed arrays 2025-01-06 13:24:44 +02:00
7883af7fff fix: some array function fixes 2025-01-06 13:24:09 +02:00
3d5be60fc7 feat: honor passed set in toReadableLines 2025-01-06 13:22:58 +02:00
ba0b4e06ad fix: some debugger issues 2025-01-06 13:22:26 +02:00
58e3546459 implement __proto__ field for all objects 2025-01-06 13:22:06 +02:00
57097e46ca reorganize libs 2025-01-06 13:20:51 +02:00
28e72503a6 Update .github/workflows/tagged-release.yml
Some checks failed
tagged-release / Tagged Release (push) Failing after 2m14s
2025-01-01 22:33:57 +00:00
d0a0796e14 Merge pull request 'topchetoeu-bump-0-10' (#32) from topchetoeu-bump-0-10 into master
Some checks failed
tagged-release / Tagged Release (push) Failing after 11m3s
Reviewed-on: #32
2025-01-01 22:20:16 +00:00
0de54e5505 Update gradle.properties 2025-01-01 22:19:56 +00:00
96c9d29a6a Update .github/workflows/tagged-release.yml 2025-01-01 22:19:36 +00:00
37dc844cc4 fix: use typescript instead 2025-01-01 22:16:01 +00:00
59 changed files with 931 additions and 246 deletions

View File

@@ -11,27 +11,24 @@ jobs:
runs-on: "ubuntu-latest"
steps:
- name: Clone repository
uses: actions/checkout@v3
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: '11'
java-version: '17'
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Clone repository
uses: GuillaumeFalourd/clone-github-repo-action@main
with:
branch: 'master'
owner: 'TopchetoEU'
repository: 'java-jscript'
cache-disabled: true
gradle-version: "8.10"
- name: Build
run: |
cd java-jscript; gradle build
- uses: "marvinpinto/action-automatic-releases@latest"
run: gradle build
- name: Create release
uses: "https://gitea.com/actions/gitea-release-action@main"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
# api_key: "${{secrets.TOKEN}}"
files: |
java-jscript/LICENSE
java-jscript/build/libs/*.jar
LICENSE
build/libs/*.jar

1
.gitignore vendored
View File

@@ -16,3 +16,4 @@
!/package.json
!/rollup.config.js
!/tsconfig.json

View File

@@ -22,6 +22,8 @@ node {
}
task compileEnv(type: NpmTask) {
dependsOn npmInstall;
inputs.files('rollup.config.js');
inputs.dir('src/lib/libs');
outputs.files("build/js/env.js");
@@ -30,6 +32,8 @@ task compileEnv(type: NpmTask) {
args = ['run', 'build-env'];
}
task compileTypescript(type: NpmTask) {
dependsOn npmInstall;
inputs.files('rollup.config.js');
inputs.dir('src/lib/transpiler');
outputs.files("build/js/ts.js");

View File

@@ -1,4 +1,4 @@
project_group = me.topchetoeu
project_name = jscript
project_version = 0.9.41-beta
project_version = 0.10.0-beta
main_class = me.topchetoeu.jscript.repl.SimpleRepl

View File

@@ -7,7 +7,7 @@ const nodeResolve = require("@rollup/plugin-node-resolve");
const json = require("@rollup/plugin-json");
const { resolve } = require("path");
const shouldMinify = () => false;
const shouldMinify = () => true;
const shouldEmitSourcemaps = () => true;
const shouldPolyfill = () => !!process.env.POLYFILLS;
@@ -99,6 +99,7 @@ const construct = (input, output) => defineConfig({
shouldMinify() && terser({
sourceMap: shouldEmitSourcemaps(),
keep_classnames: true,
keep_fnames: true,
}),
],
output: {

View File

@@ -1,21 +1,25 @@
import { object, setGlobalPrototypes, target } from "./primordials.ts";
import { Error, RangeError, SyntaxError, TypeError } from "./errors.ts";
import { Boolean } from "./boolean.ts";
import { Function } from "./function.ts";
import { Number } from "./number.ts";
import { Object } from "./object.ts";
import { String } from "./string.ts";
import { Symbol } from "./symbol.ts";
import { Array } from "./array.ts";
import { Map, WeakMap } from "./map.ts";
import { RegExp } from "./regex.ts";
import { Date } from "./date.ts";
import { Math as _Math } from "./math.ts";
import { Set, WeakSet } from "./set.ts";
import { JSON } from "./json.ts";
import { console } from "./console.ts";
import { Error, RangeError, SyntaxError, TypeError } from "./values/errors.ts";
import { Boolean } from "./values/boolean.ts";
import { Function } from "./values/function.ts";
import { Number } from "./values/number.ts";
import { Object } from "./values/object.ts";
import { String } from "./values/string.ts";
import { Symbol } from "./values/symbol.ts";
import { Array } from "./values/array.ts";
import { Map, WeakMap } from "./classes/map.ts";
import { RegExp } from "./values/regex.ts";
import { Date } from "./classes/date.ts";
import { Math as _Math } from "./namespaces/math.ts";
import { Set, WeakSet } from "./classes/set.ts";
import { JSON } from "./namespaces/json.ts";
import { console } from "./namespaces/console.ts";
import { encodeURI, encodeURIComponent } from "./url.ts";
import { Promise } from "./promise.ts";
import { Promise } from "./classes/promise.ts";
import { ArrayBuffer } from "./arrays/ArrayBuffer.ts";
import { Uint8Array } from "./arrays/Uint8Array.ts";
import { Int32Array } from "./arrays/Int32Array.ts";
import { TypedArray } from "./arrays/TypedArray.ts";
declare global {
function print(...args: any[]): void;
@@ -46,6 +50,11 @@ target.RangeError = RangeError;
target.SyntaxError = SyntaxError;
target.TypeError = TypeError;
fixup(TypedArray);
target.ArrayBuffer = fixup(ArrayBuffer);
target.Uint8Array = Uint8Array;
target.Int32Array = Int32Array;
target.Map = fixup(Map);
target.WeakMap = fixup(WeakMap);
target.Set = fixup(Set);
@@ -56,7 +65,6 @@ target.Promise = fixup(Promise);
target.Math = object.setPrototype(_Math, Object.prototype);
target.JSON = object.setPrototype(JSON, Object.prototype);
target.console = object.setPrototype(console, Object.prototype);
target.TYPED_ARRAY_SUPPORT = false;
target.parseInt = Number.parseInt;
target.parseFloat = Number.parseFloat;
@@ -77,5 +85,7 @@ setGlobalPrototypes({
syntax: SyntaxError.prototype,
range: RangeError.prototype,
type: TypeError.prototype,
uint8: Uint8Array.prototype,
int32: Int32Array.prototype,
regex: RegExp,
});

View File

@@ -0,0 +1,30 @@
import { buffer, type InternalBuffer, map, symbol } from "../primordials.ts";
export const abs = new map(true);
export const abKey: unique symbol = symbol.getSymbol("ArrayBuffer.impl") as any;
export class ArrayBuffer {
public [abKey]!: InternalBuffer;
public get byteLength() {
return this[abKey].length;
}
public get byteOffset() {
return 0;
}
public constructor(val: unknown) {
if (buffer.isBuff(val)) this[abKey] = val;
else this[abKey] = buffer.buff(Number(val));
}
}
export function getAB(buff: InternalBuffer): ArrayBuffer {
let res = abs.get(buff);
if (res == null) {
res = new ArrayBuffer(buff);
abs.set(buff, res);
}
return res;
}

View File

@@ -0,0 +1,25 @@
import { buffer } from "../primordials.ts";
import { abstractIgnore, TypedArray, typedArrayFuncs } from "./TypedArray.ts";
const factory = buffer.int32;
const funcs = typedArrayFuncs(4, factory);
export class Int32Array extends TypedArray {
public subarray(this: number[], start?: number, end?: number) {
return funcs.subarray(this, start, end);
}
public slice(this: any[], start?: number, end?: number) {
return funcs.slice(this, start, end);
}
public map(this: any[], cb: (val: number, i: number, self: any) => number, self?: any) {
return funcs.map(this, cb, self);
}
public filter(this: any[], cb: (val: number, i: number, self: any) => boolean, self?: any) {
return funcs.filter(this, cb, self);
}
public constructor(obj: any, start?: number, end?: number) {
super(abstractIgnore);
return funcs.construct(obj, start, end) as any;
}
}

View File

@@ -0,0 +1,220 @@
import { buffer, func, type InternalBuffer, object, string, symbol } from "../primordials.ts";
import { symbols, wrapI } from "../utils.ts";
import { Error, TypeError } from "../values/errors.ts";
import { abKey, ArrayBuffer, getAB } from "./ArrayBuffer.ts";
export const abstractIgnore = symbol.getSymbol("TypedArray.abstractIgnore");
export function typedArrayFuncs(perEl: number, constructor: (buff: InternalBuffer, start: number, end: number) => number[]) {
return {
map(self: number[], cb: (val: number, i: number, self: number[]) => number, fnSelf: any) {
const res = constructor(buffer.buff(self.length * perEl), 0, self.length);
for (let i = 0; i < self.length; i++) {
res[i] = func.invoke(cb, fnSelf, [self[i], i, self]);
}
return res;
},
filter(self: number[], cb: (val: number, i: number, self: number[]) => boolean, fnSelf: any) {
const bigger = constructor(buffer.buff(self.length * perEl), 0, self.length);
let j = 0;
for (let i = 0; i < self.length; i++) {
if (func.invoke(cb, self, [self[i], i, fnSelf])) bigger[j++] = self[i];
}
const res = constructor(buffer.buff(j * perEl), 0, j);
for (let i = 0; i < j; i++) res[i] = bigger[i];
return res;
},
slice(self: number[], start = 0, end = self.length) {
start = wrapI(start, self.length);
end = wrapI(end, self.length);
if (end <= start) return constructor(buffer.buff(0), 0, 0);
const res = constructor(buffer.buff((end - start) * perEl), 0, end - start);
for (let i = 0; i < end - start; i++) {
res[i] = self[start + i];
}
return res;
},
subarray(self: number[], start = 0, end = self.length) {
start = wrapI(start, self.length);
end = wrapI(end, self.length);
if (end <= start) return constructor(buffer.buff(0), 0, 0);
const offset = buffer.start(self);
return constructor(buffer.backer(self), offset + start, offset + end);
},
construct(self: ArrayBuffer | number[] | number | Iterable<number>, start?: number, end?: number) {
if (typeof self === "number") {
return constructor(buffer.buff(self * perEl), 0, self);
}
if (self instanceof ArrayBuffer) {
const internal = self[abKey];
if (start === undefined) start = 0;
if (end === undefined) end = (internal.length / perEl) | 0;
return constructor(internal, start, end);
}
if (symbols.iterator in self && typeof self[symbols.iterator] === "function") {
const arr: number[] = [];
let i = 0;
const gen: Iterator<number> = self[symbols.iterator]();
for (let it = gen.next(); !it.done; it = gen.next()) {
arr[i++] = Number(it.value);
}
const res = constructor(buffer.buff(i * perEl), 0, i);
for (let j = 0; j < i; j++) res[j] = arr[j];
return res;
}
const res = constructor(buffer.buff((self as number[]).length * perEl), 0, (self as number[]).length);
for (let i = 0; i < (self as number[]).length; i++) res[i] = (self as number[])[i];
return res;
},
byteOffset(self: number[]) {
return buffer.start(self) * perEl;
},
byteLength(self: number[]) {
return (buffer.end(self) - buffer.start(self)) * perEl;
},
};
}
export class TypedArray {
public get buffer() {
return getAB(buffer.backer(this as any));
}
public get byteOffset(): number {
throw new Error("abstract");
}
public get byteLength(): number {
throw new Error("abstract");
}
public forEach(this: number[], cb: (val: number, i: number, self: this) => void, self?: any) {
for (let i = 0; i < this.length; i++) {
if (i in this) func.invoke(cb, self, [this[i], i, this]);
}
}
public join(this: number[], delim = ",") {
delim = String(delim);
const parts = [];
if (delim) {
for (let i = 0; i < this.length; i++) {
if (i) parts[parts.length] = delim;
parts[parts.length] = (i in this) ? String(this[i]) : "";
}
}
else {
for (let i = 0; i < this.length; i++) {
parts[i] = (i in this) ? String(this[i]) : "";
}
}
return string.stringBuild(parts);
}
public subarray(this: number[], start = 0, end = this.length) {
throw new Error("'slice' is an abstract method");
}
public slice(this: number[], start = 0, end = this.length) {
throw new Error("'slice' is an abstract method");
}
public map(this: number[], cb: (val: number, i: number, self: this) => number, self?: any) {
throw new Error("'map' is an abstract method");
}
public filter(this: number[], cb: (val: number, i: number, self: this) => boolean, self?: any) {
throw new Error("'filter' is an abstract method");
}
public reduce(this: number[], cb: (a: number, b: number, i: number, self: number[]) => number, initial?: number) {
let i = 0;
if (arguments.length <= 1) initial = this[i++];
for (; i < this.length; i++) {
initial = cb(initial!, this[i], i, this);
}
return initial;
}
public some(this: number[], cb: (val: number, i: number, self: number[]) => boolean, self?: any) {
for (let i = 0; i < this.length; i++) {
if (func.invoke(cb, self, [this[i], i, this])) return true;
}
return false;
}
public every(this: number[], cb: (val: number, i: number, self: number[]) => boolean, self?: any) {
for (let i = 0; i < this.length; i++) {
if (!func.invoke(cb, self, [this[i], i, this])) return false;
}
return true;
}
public find(this: number[], cb: (val: number, i: number, self: number[]) => boolean, self?: any) {
for (let i = 0; i < this.length; i++) {
if (func.invoke(cb, self, [this[i], i, this])) return this[i];
}
return undefined;
}
public indexOf(this: number[], val: number, start = 0) {
start |= 0;
if (start < 0) start = 0;
for (let i = start; i < this.length; i++) {
if (this[i] === val) return i;
}
return -1;
}
public lastIndexOf(this: number[], val: number, start = 0) {
start |= 0;
if (start < 0) start = 0;
for (let i = this.length - 1; i >= start; i--) {
if (this[i] === val) return i;
}
return -1;
}
public includes(this: number[], val: number) {
for (let i = 0; i < this.length; i++) {
if (this[i] === val) return i;
}
return false;
}
public sort(this: number[], cb?: (a: number, b: number) => number) {
cb ||= (a, b) => a - b;
return object.sort(this, cb);
}
public reverse(this: number[]) {
const mid = this.length >> 1;
const end = this.length - 1;
for (let i = 0; i < mid; i++) {
const tmp = this[i];
this[i] = this[end - i];
this[end - i] = tmp;
}
return this;
}
public constructor(token?: typeof abstractIgnore) {
if (token !== abstractIgnore) {
throw new TypeError("TypedArray constructor can't be called");
}
}
}

View File

@@ -0,0 +1,32 @@
import { buffer } from "../primordials.ts";
import { abstractIgnore, TypedArray, typedArrayFuncs } from "./TypedArray.ts";
const factory = buffer.uint8;
const funcs = typedArrayFuncs(1, factory);
export class Uint8Array extends TypedArray {
public override get byteOffset() {
return funcs.byteOffset(this as any);
}
public override get byteLength() {
return funcs.byteLength(this as any);
}
public override subarray(this: number[], start?: number, end?: number) {
return funcs.subarray(this, start, end);
}
public override slice(this: any[], start?: number, end?: number) {
return funcs.slice(this, start, end);
}
public override map(this: any[], cb: (val: number, i: number, self: any) => number, self?: any) {
return funcs.map(this, cb, self);
}
public override filter(this: any[], cb: (val: number, i: number, self: any) => boolean, self?: any) {
return funcs.filter(this, cb, self);
}
public constructor(obj: any, start?: number, end?: number) {
super(abstractIgnore);
return funcs.construct(obj, start, end) as any;
}
}

View File

@@ -1,4 +1,4 @@
import { now, symbol } from "./primordials.ts";
import { now, symbol } from "../primordials.ts";
const timeKey: unique symbol = symbol.makeSymbol("") as any;

View File

@@ -1,6 +1,6 @@
import { Array } from "./array.ts";
import { func, map, symbol } from "./primordials.ts";
import { symbols } from "./utils.ts";
import { Array } from "../values/array.ts";
import { func, map, symbol } from "../primordials.ts";
import { symbols } from "../utils.ts";
const mapKey: unique symbol = symbol.makeSymbol("Map.impl") as any;

View File

@@ -1,4 +1,4 @@
import { func, next, object, symbol } from "./primordials.ts";
import { func, next, object, symbol } from "../primordials.ts";
enum PromiseState {
Pending = "pend",

View File

@@ -1,6 +1,6 @@
import { Array } from "./array.ts";
import { func, map, symbol } from "./primordials.ts";
import { symbols } from "./utils.ts";
import { Array } from "../values/array.ts";
import { func, map, symbol } from "../primordials.ts";
import { symbols } from "../utils.ts";
const mapKey: unique symbol = symbol.makeSymbol("Set.impl") as any;

View File

@@ -1,4 +1,4 @@
import { func, json, object } from "./primordials";
import { func, json, object } from "../primordials.ts";
export const console = {};

View File

@@ -1,4 +1,4 @@
import { json, object } from "./primordials";
import { json, object } from "../primordials.ts";
export const JSON = {};

View File

@@ -1,4 +1,4 @@
import { number, object } from "./primordials";
import { number, object } from "../primordials.ts";
export const Math = {};

View File

@@ -1,2 +1 @@
export default function _possibleConstructorReturn() {
}
export default function _possibleConstructorReturn(_, res) { return res; }

View File

@@ -1,3 +1,10 @@
const buffSymbol: unique symbol = undefined as any;
export interface InternalBuffer {
length: number;
[buffSymbol]: "buffer";
}
export interface SymbolPrimordials {
makeSymbol(name: string): symbol;
getSymbol(name: string): symbol;
@@ -46,6 +53,22 @@ export interface ObjectPrimordials {
memcpy(src: any[], dst: any[], srcI: number, dstI: number, n: number): void;
sort(arr: any[], cb: Function): any[];
}
export interface BufferPrimordials {
buff(n: number): InternalBuffer;
backer(arr: number[]): InternalBuffer;
start(arr: number[]): number;
end(arr: number[]): number;
uint8(buff: InternalBuffer, start: number, end: number): number[];
int8(buff: InternalBuffer, start: number, end: number): number[];
int32(buff: InternalBuffer, start: number, end: number): number[];
isUint8(val: any): val is number[];
isInt8(val: any): val is number[];
isInt32(val: any): val is number[];
is(val: any): val is number[];
isBuff(val: any): val is InternalBuffer;
}
export interface FunctionPrimordials {
invokeType(args: IArguments, self: any): "new" | "call";
invokeTypeInfer(): "new" | "call";
@@ -67,6 +90,7 @@ export interface Primordials {
object: ObjectPrimordials;
function: FunctionPrimordials;
json: JSONPrimordials;
buffer: BufferPrimordials;
map: new (weak?: boolean) => {
get(key: any): any;
has(key: any): boolean;
@@ -88,7 +112,8 @@ export interface Primordials {
schedule(func: () => void, delay: number): () => void;
}
globalThis.undefined = void 0;
// prevent optimization to "undefined", which doesn't exist yet
globalThis.undefined = ({} as any).bogus;
export const target = (globalThis as any).target;
export const primordials: Primordials = (globalThis as any).primordials;
@@ -97,6 +122,7 @@ export const {
number,
string,
object,
buffer,
function: func,
json,
map,

View File

@@ -25,7 +25,7 @@ export interface TypeMap {
export function unwrapThis<T extends keyof TypeMap>(self: any, type: T, constr: Function, name: string, arg = "this", defaultVal?: TypeMap[T]): TypeMap[T] {
if (typeof self === type) return self;
if (self instanceof constr && valueKey in self) self = (self as any)[valueKey];
if (self instanceof constr && valueKey in self) self = self[valueKey];
if (typeof self === type) return self;
if (defaultVal !== undefined) return defaultVal;
throw new TypeError(name + " requires that '" + arg + "' be a " + constr.name);

View File

@@ -1,7 +1,7 @@
import { Error } from "./errors.ts";
import { func, object, string } from "./primordials.ts";
import { String } from "./string.ts";
import { limitI, symbols, wrapI } from "./utils.ts";
import { Error } from "../values/errors.ts";
import { func, object, string } from "../primordials.ts";
import { String } from "../values/string.ts";
import { limitI, symbols, wrapI } from "../utils.ts";
export const Array = (() => {
class Array {
@@ -33,7 +33,7 @@ export const Array = (() => {
for (let i = arguments.length - 1; i >= 0; i--) {
this[start + i] = arguments[i];
}
return arguments.length;
return this.length;
}
public pop(this: any[]) {
if (this.length === 0) return undefined;
@@ -51,7 +51,7 @@ export const Array = (() => {
for (let i = 0; i < arguments.length; i++) {
this[i] = arguments[i];
}
return arguments.length;
return this.length;
}
public shift(this: any[]) {
if (this.length === 0) return undefined;
@@ -71,7 +71,7 @@ export const Array = (() => {
const res: any[] = [];
function add(arr: any) {
if (Array.isArray(arr) || symbols.isConcatSpreadable in arr) {
if (Array.isArray(arr) || arr != null && typeof arr === "object" && symbols.isConcatSpreadable in arr) {
const start = res.length;
res.length += arr.length;
@@ -209,7 +209,7 @@ export const Array = (() => {
}
public includes(this: any[], val: any) {
for (let i = 0; i < this.length; i++) {
if (i in this && this[i] === val) return i;
if (i in this && this[i] === val) return true;
}
return false;

View File

@@ -1,5 +1,5 @@
import { func } from "./primordials.ts";
import { unwrapThis, valueKey } from "./utils.ts";
import { func } from "../primordials.ts";
import { unwrapThis, valueKey } from "../utils.ts";
export const Boolean = (() => {
class Boolean {

View File

@@ -1,4 +1,4 @@
import { func, object } from "./primordials.ts";
import { func, object } from "../primordials.ts";
import { String } from "./string.ts";
export class Error {

View File

@@ -1,4 +1,4 @@
import { compile, func, string } from "./primordials.ts";
import { compile, func, string } from "../primordials.ts";
import { String } from "./string.ts";
export const Function = (() => {

View File

@@ -1,5 +1,5 @@
import { func, number, object } from "./primordials.ts";
import { unwrapThis, valueKey } from "./utils.ts";
import { func, number, object } from "../primordials.ts";
import { unwrapThis, valueKey } from "../utils.ts";
export const Number = (() => {
class Number {

View File

@@ -1,10 +1,10 @@
import { Boolean } from "./boolean.ts";
import { TypeError } from "./errors.ts";
import { Number } from "./number.ts";
import { func, object } from "./primordials.ts";
import { func, object } from "../primordials.ts";
import { String } from "./string.ts";
import { symbols, valueKey } from "./utils.ts";
import { Symbol } from "./symbol.ts";
import { symbols, valueKey } from "../utils.ts";
import { Symbol } from "../values/symbol.ts";
export const Object = (() => {
class Object {
@@ -29,6 +29,13 @@ export const Object = (() => {
return object.getOwnMember(this, key) != null;
}
public get __proto__() {
return object.getPrototype(this);
}
public set __proto__(val) {
object.setPrototype(this, val);
}
public constructor (value?: unknown) {
if (typeof value === 'object' && value !== null) return value as any;
if (typeof value === 'string') return new String(value) as any;
@@ -75,13 +82,13 @@ export const Object = (() => {
res.s = set;
}
if ("enumerable" in desc) res.e = !!desc.enumerable;
if ("configurable" in desc) res.e = !!desc.configurable;
if ("configurable" in desc) res.c = !!desc.configurable;
if (!object.defineProperty(obj, key, res)) throw new TypeError("Cannot redefine property: " + String(key));
}
else {
if ("enumerable" in desc) res.e = !!desc.enumerable;
if ("configurable" in desc) res.e = !!desc.configurable;
if ("configurable" in desc) res.c = !!desc.configurable;
if ("writable" in desc) res.w = !!desc.writable;
if ("value" in desc) res.v = desc.value;
@@ -190,6 +197,7 @@ export const Object = (() => {
}
}
object.defineProperty(Object.prototype, "__proto__", { e: false });
object.setPrototype(Object.prototype, undefined);
func.setCallable(Object, true);

View File

@@ -1,9 +1,9 @@
import { func, regex, symbol } from "./primordials.ts";
import { func, regex, symbol } from "../primordials.ts";
import { String } from "./string.ts";
import { type ReplaceRange } from "./utils.ts";
import { applyReplaces } from "./utils.ts";
import { applySplits } from "./utils.ts";
import { symbols } from "./utils.ts";
import { type ReplaceRange } from "../utils.ts";
import { applyReplaces } from "../utils.ts";
import { applySplits } from "../utils.ts";
import { symbols } from "../utils.ts";
const regexKey: unique symbol = symbol.makeSymbol("RegExp.impl") as any;

View File

@@ -1,7 +1,7 @@
import { TypeError } from "./errors.ts";
import { func, number, regex, string } from "./primordials.ts";
import { func, number, regex, string } from "../primordials.ts";
import { RegExp } from "./regex.ts";
import { applyReplaces, applySplits, limitI, type ReplaceRange, symbols, unwrapThis, valueKey, wrapI } from "./utils.ts";
import { applyReplaces, applySplits, limitI, type ReplaceRange, symbols, unwrapThis, valueKey, wrapI } from "../utils.ts";
const trimStartRegex = new regex("^\\s+", false, false, false, false, false);
const trimEndRegex = new regex("\\s+$", false, false, false, false, false);
@@ -41,8 +41,9 @@ export const String = (() => {
offset = +offset;
return string.indexOf(self, search, offset, false);
}
public lastIndexOf(search: string, offset = 0) {
public lastIndexOf(search: string, offset?: number) {
const self = unwrapThis(this, "string", String, "String.prototype.lastIndexOf");
if (offset == null) offset = self.length;
offset = +offset;
return string.indexOf(self, search, offset, true);
}

View File

@@ -1,5 +1,5 @@
import { func, object, symbol } from "./primordials.ts";
import { symbols, unwrapThis, valueKey } from "./utils.ts";
import { func, object, symbol } from "../primordials.ts";
import { symbols, unwrapThis, valueKey } from "../utils.ts";
export const Symbol = (() => {
class Symbol {

View File

@@ -1,14 +1,14 @@
import { SourceMap } from "./map.ts";
import { transform } from "@babel/standalone";
// import presetEnv from "@babel/preset-env";
import { transform, availablePresets } from "@babel/standalone";
export default function babel(next: Compiler): Compiler {
print("Loaded babel!");
return (filename, code, prevMap) => {
const res = transform(code, {
filename,
sourceMaps: true,
presets: [availablePresets.env],
});
const map = SourceMap.parse({
@@ -17,9 +17,8 @@ export default function babel(next: Compiler): Compiler {
sources: [filename],
});
const compiled = next("babel-internal://" + filename, res.code!, SourceMap.chain(map, prevMap));
registerSource(filename, code);
return compiled;
return next("babel-internal://" + filename, res.code!, SourceMap.chain(map, prevMap));
};
}

View File

@@ -20,9 +20,8 @@ export default function coffee(next: Compiler): Compiler {
sources: [filename],
});
const compiled = next("coffee-internal://" + filename, result, SourceMap.chain(map, prevMap));
registerSource(filename, code);
return compiled;
return next("coffee-internal://" + filename, result, SourceMap.chain(map, prevMap));
};
}

View File

@@ -6,15 +6,24 @@ for (let i = 97; i <= 122; i++) map[i] = j++;
map[43] = j++;
map[47] = j++;
export type Location = readonly [file: string, line: number, start: number];
export function decodeVLQ(val: string): number[][][] {
const lines: number[][][] = [];
for (const line of val.split(";", -1)) {
const elements: number[][] = [];
const fileParts = val.split(";", -1);
for (let i = 0; i < fileParts.length; i++) {
const line = fileParts[i];
if (line.length === 0) {
lines.push([]);
continue;
}
const elements: number[][] = [];
const lineParts = line.split(",", -1);
for (let i = 0; i < lineParts.length; i++) {
const el = lineParts[i];
for (const el of line.split(",", -1)) {
if (el.length === 0) elements.push([]);
else {
const list: number[] = [];
@@ -72,10 +81,6 @@ export namespace Location {
}
}
export interface SourceMap {
(loc: Location): Location | undefined;
}
export class VLQSourceMap {
public constructor(
public readonly array: Map<string, [start: number, dst: Location][][]>,
@@ -98,7 +103,7 @@ export class VLQSourceMap {
const mid = (a + b) >> 1;
const el = line[mid];
const cmp = el[0] - src[1];
const cmp = el[0] - src[2];
if (cmp < 0) {
if (done) {
@@ -132,10 +137,13 @@ export class VLQSourceMap {
const lastCols = new Set<number>();
for (let compiledRow = 0; compiledRow < mapping.length; compiledRow++) {
const line = file[compiledRow] ??= [];
const line: [start: number, dst: Location][] = file[compiledRow] = [];
let compiledCol = 0;
for (const rawSeg of mapping[compiledRow]) {
const rowData = mapping[compiledRow];
for (let i = 0; i < rowData.length; i++) {
const rawSeg = rowData[i];
compiledCol += rawSeg.length > 0 ? rawSeg[0] : 0;
originalFile += rawSeg.length > 1 ? rawSeg[1] : 0;
originalRow += rawSeg.length > 2 ? rawSeg[2] : 0;

10
src/lib/transpiler/transpiler.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
type Location = [file: string, line: number, start: number];
type SourceMap = (loc: Location) => Location | undefined;
type CompilerFactory = (next: Compiler) => Compiler;
type Compiler = (filename: string, src: string, mapper: SourceMap) => (this: any, ...args: any[]) => any;
declare function getResource(name: string): string | undefined;
declare function print(...args: any[]): void;
declare function register(factory: CompilerFactory): void;
declare function registerSource(filename: string, src: string): void;

View File

@@ -1,10 +0,0 @@
import { type SourceMap } from "./map.ts";
declare global {
type CompilerFactory = (next: Compiler) => Compiler;
type Compiler = (filename: string, src: string, mapper: SourceMap) => Function;
function print(...args: any[]): void;
function register(factory: CompilerFactory): void;
function registerSource(filename: string, src: string): void;
}

View File

@@ -1,17 +1,8 @@
import { createDocumentRegistry, createLanguageService, ModuleKind, ScriptSnapshot, ScriptTarget, type Diagnostic, type CompilerOptions, type IScriptSnapshot, flattenDiagnosticMessageText, CompilerHost, LanguageService } from "typescript";
import { SourceMap } from "./map.ts";
declare function getResource(name: string): string | undefined;
declare function print(...args: any[]): void;
declare function register(factory: CompilerFactory): void;
declare function registerSource(filename: string, src: string): void;
type CompilerFactory = (next: Compiler) => Compiler;
type Compiler = (filename: string, src: string, mapper: SourceMap) => Function;
const resources: Record<string, string | undefined> = {};
function resource(name: string) {
if (name in resources) return resources[name];
else return resources[name] = getResource(name);
@@ -115,8 +106,8 @@ export default function typescript(next: Compiler): Compiler {
const result = outputs["/src.js"];
const declaration = outputs["/src.d.ts"];
const compiled = next("ts-internal://" + filename, result, SourceMap.chain(map, prevMap));
registerSource(filename, code);
const compiled = next("ts-internal://" + filename, result, SourceMap.chain(map, prevMap));
return function (this: any) {
const res = compiled.apply(this, arguments);

View File

@@ -21,7 +21,9 @@ public class ForInNode extends Node {
@Override public void resolve(CompileResult target) {
body.resolve(target);
binding.resolve(target);
if (isDecl) {
target.scope.define(binding.name);
}
}
@Override public void compileFunctions(CompileResult target) {

View File

@@ -29,7 +29,7 @@ public class FieldMemberNode implements Member {
if (value == null) target.add(Instruction.pushUndefined());
else value.compile(target, true);
target.add(Instruction.defField());
target.add(Instruction.storeMember());
}
public FieldMemberNode(Location loc, Node key, Node value) {

View File

@@ -36,8 +36,13 @@ import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.Value;
import me.topchetoeu.jscript.runtime.values.functions.FunctionValue;
import me.topchetoeu.jscript.runtime.values.functions.NativeFunction;
import me.topchetoeu.jscript.runtime.values.objects.ArrayLikeValue;
import me.topchetoeu.jscript.runtime.values.objects.ArrayValue;
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
import me.topchetoeu.jscript.runtime.values.objects.buffers.Int32ArrayValue;
import me.topchetoeu.jscript.runtime.values.objects.buffers.Int8ArrayValue;
import me.topchetoeu.jscript.runtime.values.objects.buffers.TypedArrayValue;
import me.topchetoeu.jscript.runtime.values.objects.buffers.Uint8ArrayValue;
import me.topchetoeu.jscript.runtime.values.primitives.BoolValue;
import me.topchetoeu.jscript.runtime.values.primitives.StringValue;
import me.topchetoeu.jscript.runtime.values.primitives.SymbolValue;
@@ -61,9 +66,12 @@ public class SimpleRepl {
private static void reader() {
try {
environment = createESEnv();
tsEnvironment = createESEnv();
try {
environment = createESEnv();
tsEnvironment = createESEnv();
}
catch (ExecutionException e) { throw e.getCause(); }
server = new DebugServer();
debugTask = server.start(new InetSocketAddress("127.0.0.1", 9229), true);
server.targets.put("default", (socket, req) -> new SimpleDebugger(socket)
@@ -74,16 +82,19 @@ public class SimpleRepl {
try {
try { initGlobals(); } catch (ExecutionException e) { throw e.getCause(); }
}
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(environment, e, null)); }
catch (EngineException | SyntaxException e) {
System.err.println("Failed to load stdlib. Falling back to barebones environment...");
System.err.println(Value.errorToReadable(environment, e, null));
}
System.out.println(String.format("Running %s v%s by %s", Metadata.name(), Metadata.version(), Metadata.author()));
for (var arg : args) {
try {
var file = new File(arg);
var raw = Reading.streamToString(new FileInputStream(file));
var file = new File(arg);
var raw = Reading.streamToString(new FileInputStream(file));
try {
try {
var res = engine.pushMsg(
false, environment,
@@ -95,14 +106,15 @@ public class SimpleRepl {
catch (ExecutionException e) { throw e.getCause(); }
}
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(environment, e, null)); }
}
for (var i = 0; ; i++) {
var raw = Reading.readline();
if (raw == null) break;
try {
var raw = Reading.readline();
if (raw == null) break;
try {
var res = engine.pushMsg(
false, environment,
@@ -114,8 +126,10 @@ public class SimpleRepl {
catch (ExecutionException e) { throw e.getCause(); }
}
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(environment, e, null)); }
}
}
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(environment, e, null)); }
catch (IOException e) {
System.out.println(e.toString());
engine.thread().interrupt();
@@ -183,34 +197,78 @@ public class SimpleRepl {
var source = new StringBuilder();
var inBrackets = false;
StringBuilder bracesSource = null;
StringBuilder bracketsSource = null;
while (true) {
if (n >= src.length()) break;
var c = src.charAt(n++);
if (c == '\\') {
if (c == '\\' && n + 1 < src.length() && src.charAt(n) == 'b') {
c = '\b';
n++;
}
if (bracesSource != null) {
var failed = true;
if (Character.isDigit(c)) {
bracesSource.append(c);
failed = false;
}
else if (c == ',' && bracesSource.indexOf(",") < 0) {
bracesSource.append(c);
failed = false;
}
else if (c == '}' && bracesSource.length() > 0) {
bracesSource.append(c);
source.append(bracesSource);
bracesSource = null;
continue;
}
if (failed) {
source.append("\\");
source.append(bracesSource);
bracesSource = null;
n--;
}
}
else if (bracketsSource != null) {
if (c == '[') bracketsSource.append("\\[");
else if (c == ']') {
var res = bracketsSource.append(']').toString();
bracketsSource = null;
if (res.equals("[^]")) res = "[\\s\\S]";
else if (res.equals("[]")) res = "[^\\s\\S]";
source.append(res);
}
else if (c == '\\') {
if (n >= src.length()) break;
bracketsSource.append(c).append(src.charAt(n++));
}
else bracketsSource.append(c);
}
else if (c == '\\') {
if (n >= src.length()) throw new PatternSyntaxException("Unexpected end", src, n);
c = src.charAt(n++);
source.append('\\').append(c);
}
else if (c == '[') {
if (inBrackets) source.append("\\[");
else {
inBrackets = true;
source.append('[');
}
bracketsSource = new StringBuilder("[");
}
else if (c == ']') {
if (inBrackets) {
inBrackets = false;
source.append(']');
}
else throw new PatternSyntaxException("Unexpected ']'", src, n);
else if (c == '{' && bracketsSource == null) {
bracesSource = new StringBuilder("{");
}
else source.append(c);
}
if (bracesSource != null) {
source.append("\\");
source.append(bracesSource);
}
if (bracketsSource != null) throw new PatternSyntaxException("Unmatched '['", src, n - bracketsSource.length());
return source.toString();
}
@@ -314,12 +372,18 @@ public class SimpleRepl {
else return NumberValue.parseFloat(args.get(0).toString(), false);
}));
res.defineOwnField(env, "isNaN", new NativeFunction(args -> BoolValue.of(args.get(0).isNaN())));
res.defineOwnField(env, "NaN", NumberValue.NAN);
res.defineOwnField(env, "Infinity", NumberValue.of(Double.POSITIVE_INFINITY));
res.defineOwnField(env, "pow", new NativeFunction(args -> {
return NumberValue.of(Math.pow(args.get(0).toNumber(args.env).getDouble(), args.get(1).toNumber(args.env).getDouble()));
}));
res.defineOwnField(env, "log", new NativeFunction(args -> {
return NumberValue.of(Math.log(args.get(0).toNumber(args.env).getDouble()));
}));
res.defineOwnField(env, "NaN", NumberValue.NAN);
res.defineOwnField(env, "Infinity", NumberValue.of(Double.POSITIVE_INFINITY));
res.defineOwnField(env, "PI", NumberValue.of(Math.PI));
res.defineOwnField(env, "E", NumberValue.of(Math.E));
return res;
}
@@ -462,9 +526,6 @@ public class SimpleRepl {
if (member == null) return Value.UNDEFINED;
else return member.descriptor(args.env, obj);
}));
res.defineOwnField(env, "isArray", new NativeFunction(args -> {
return BoolValue.of(args.get(0) instanceof ArrayValue);
}));
res.defineOwnField(env, "preventExt", new NativeFunction(args -> {
args.get(0).preventExtensions();
return VoidValue.UNDEFINED;
@@ -499,6 +560,73 @@ public class SimpleRepl {
return arr;
}));
res.defineOwnField(env, "isArray", new NativeFunction(args -> {
return BoolValue.of(args.get(0) instanceof ArrayLikeValue);
}));
return res;
}
private static ObjectValue bufferPrimordials(Environment env) {
var buffProto = new ObjectValue();
buffProto.defineOwnProperty(env, "length", Optional.of(new NativeFunction(args -> {
return NumberValue.of(args.self(byte[].class).length);
})), Optional.empty(), false, true);
var res = new ObjectValue();
res.setPrototype(null, null);
res.defineOwnField(env, "buff", new NativeFunction(args -> {
var size = args.get(0).toNumber(env).getInt();
return TypedArrayValue.buffer(new byte[size], buffProto);
}));
res.defineOwnField(env, "uint8", new NativeFunction(args -> {
var buff = args.get(byte[].class, 0);
var start = args.get(1).toNumber(env).getInt();
var end = args.get(2).toNumber(env).getInt();
return new Uint8ArrayValue(buff, start, end);
}));
res.defineOwnField(env, "int8", new NativeFunction(args -> {
var buff = args.get(byte[].class, 0);
var start = args.get(1).toNumber(env).getInt();
var end = args.get(2).toNumber(env).getInt();
return new Int8ArrayValue(buff, start, end);
}));
res.defineOwnField(env, "int32", new NativeFunction(args -> {
var buff = args.get(byte[].class, 0);
var start = args.get(1).toNumber(env).getInt();
var end = args.get(2).toNumber(env).getInt();
return new Int32ArrayValue(buff, start, end);
}));
res.defineOwnField(env, "isUint8", new NativeFunction(args -> {
return BoolValue.of(args.get(0) instanceof Uint8ArrayValue);
}));
res.defineOwnField(env, "isInt8", new NativeFunction(args -> {
return BoolValue.of(args.get(0) instanceof Int8ArrayValue);
}));
res.defineOwnField(env, "isInt32", new NativeFunction(args -> {
return BoolValue.of(args.get(0) instanceof Int32ArrayValue);
}));
res.defineOwnField(env, "is", new NativeFunction(args -> {
return BoolValue.of(args.get(0) instanceof TypedArrayValue);
}));
res.defineOwnField(env, "isBuff", new NativeFunction(args -> {
return BoolValue.of(args.get(byte[].class, 0) != null);
}));
res.defineOwnField(env, "backer", new NativeFunction(args -> {
return TypedArrayValue.buffer(((TypedArrayValue)args.get(0)).buffer, buffProto);
}));
res.defineOwnField(env, "start", new NativeFunction(args -> {
return NumberValue.of(((TypedArrayValue)args.get(0)).start);
}));
res.defineOwnField(env, "end", new NativeFunction(args -> {
return NumberValue.of(((TypedArrayValue)args.get(0)).end);
}));
return res;
}
@@ -584,6 +712,7 @@ public class SimpleRepl {
res.defineOwnField(env, "number", numberPrimordials(env));
res.defineOwnField(env, "string", stringPrimordials(env));
res.defineOwnField(env, "object", objectPrimordials(env));
res.defineOwnField(env, "buffer", bufferPrimordials(env));
res.defineOwnField(env, "function", functionPrimordials(env));
res.defineOwnField(env, "json", jsonPrimordials(env));
res.defineOwnField(env, "map", mapPrimordials(env));
@@ -605,6 +734,8 @@ public class SimpleRepl {
setProto(args.env, env, Value.SYNTAX_ERR_PROTO, obj, "syntax");
setProto(args.env, env, Value.TYPE_ERR_PROTO, obj, "type");
setProto(args.env, env, Value.RANGE_ERR_PROTO, obj, "range");
setProto(args.env, env, Value.UINT8_ARR_PROTO, obj, "uint8");
setProto(args.env, env, Value.INT32_ARR_PROTO, obj, "int32");
var val = obj.getMember(args.env, "regex");
if (val instanceof FunctionValue func) {
env.add(Value.REGEX_CONSTR, func);
@@ -740,7 +871,7 @@ public class SimpleRepl {
reader.setName("STD Reader");
reader.start();
engine.thread().join();
reader.join();
engineTask.interrupt();
debugTask.interrupt();
}

View File

@@ -199,12 +199,15 @@ public class SimpleDebugger implements Debugger {
this.frame = frame;
this.id = id;
var map = DebugContext.get(frame.env).getMap(frame.function);
var map = DebugContext.get(frame.env).getMapOrEmpty(frame.function);
this.globals = Value.global(frame.env);
this.locals = ScopeObject.locals(frame, map.localNames);
this.capturables = ScopeObject.capturables(frame, map.capturableNames);
this.captures = ScopeObject.captures(frame, map.captureNames);
this.variables = ScopeObject.combine((ObjectValue)this.globals, locals, capturables, captures);
if (this.globals instanceof ObjectValue) {
this.variables = ScopeObject.combine((ObjectValue)this.globals, locals, capturables, captures);
}
else this.variables = ScopeObject.combine(null, locals, capturables, captures);
this.valstack = new StackObject(frame);
}
}
@@ -406,7 +409,43 @@ public class SimpleDebugger implements Debugger {
res.set("description", className);
}
if (val instanceof ArrayValue arr) res.set("description", "Array(" + arr.size() + ")");
if (val instanceof ArrayValue arr) {
var desc = new StringBuilder("Array(" + arr.size() + ")");
if (arr.size() > 0) {
desc.append("[");
for (var i = 0; i < arr.size(); i++) {
if (i != 0) desc.append(", ");
if (desc.length() > 120) {
desc.append("...");
break;
}
if (arr.has(i)) {
try {
var curr = arr.get(i);
if (curr instanceof StringValue str) {
desc.append(JSON.stringify(JSONElement.string(str.value)));
}
else {
desc.append(arr.get(i).toString(env));
}
}
catch (EngineException e) {
desc.append("<error>");
}
}
else {
desc.append("<empty>");
}
}
desc.append("]");
}
res.set("description", desc.toString());
}
else if (val instanceof FunctionValue) res.set("description", val.toString());
else {
var defaultToString = false;
@@ -984,7 +1023,7 @@ public class SimpleDebugger implements Debugger {
}
try {
Value res = null;
Value res = Value.UNDEFINED;
if (compare(src, VSCODE_EMPTY)) res = emptyObject;
else if (compare(src, VSCODE_SELF)) res = self;
else if (compare(src, CHROME_GET_PROP_FUNC)) {
@@ -997,6 +1036,7 @@ public class SimpleDebugger implements Debugger {
else if (compare(src, VSCODE_CALL)) {
var func = (FunctionValue)(args.size() < 1 ? null : args.get(0));
ws.send(msg.respond(new JSONMap().set("result", serializeObj(env, func.apply(env, self)))));
return;
}
else if (compare(src, VSCODE_AUTOCOMPLETE)) {
var target = args.get(0);

View File

@@ -40,7 +40,7 @@ public final class Engine implements EventLoop {
try {
((Task<Object>)task).notifier.complete(task.runnable.get());
}
catch (CancellationException e) { throw e; }
catch (CancellationException e) { task.notifier.cancel(false); throw e; }
catch (RuntimeException e) { task.notifier.completeExceptionally(e); }
}
catch (InterruptedException | CancellationException e) {

View File

@@ -213,7 +213,9 @@ public final class Frame {
catch (StackOverflowError e) { throw STACK_OVERFLOW; }
catch (EngineException e) { error = e; }
catch (RuntimeException e) {
System.out.println(dbg.getMapOrEmpty(function).toLocation(codePtr, true));
if (!(e instanceof CancellationException)) {
System.out.println(dbg.getMapOrEmpty(function).toLocation(codePtr, true));
}
throw e;
}
}

View File

@@ -62,7 +62,10 @@ public abstract class Value {
public static final Key<ObjectValue> FUNCTION_PROTO = new Key<>();
public static final Key<ObjectValue> ARRAY_PROTO = new Key<>();
public static final Key<ObjectValue> BYTE_BUFF_PROTO = new Key<>();
public static final Key<ObjectValue> INT8_ARR_PROTO = new Key<>();
public static final Key<ObjectValue> INT32_ARR_PROTO = new Key<>();
public static final Key<ObjectValue> UINT8_ARR_PROTO = new Key<>();
public static final Key<ObjectValue> ERROR_PROTO = new Key<>();
public static final Key<ObjectValue> SYNTAX_ERR_PROTO = new Key<>();

View File

@@ -1,81 +0,0 @@
package me.topchetoeu.jscript.runtime.values.objects;
import java.util.Arrays;
import java.util.Iterator;
import me.topchetoeu.jscript.common.environment.Environment;
import me.topchetoeu.jscript.runtime.values.Value;
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
public class ByteBufferValue extends ArrayLikeValue implements Iterable<Value> {
public final byte[] values;
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;
}
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 sort() {
var buckets = new int[256];
for (var i = 0; i < values.length; i++) {
buckets[values[i] + 128]++;
}
var offset = 0;
for (var i = 0; i < values.length; i++) {
Arrays.fill(values, offset, offset += buckets[i], (byte)(i - 128));
}
}
@Override public Iterator<Value> 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++);
}
};
}
public ByteBufferValue(int size) {
this(new byte[size]);
}
public ByteBufferValue(byte[] buffer) {
setPrototype(BYTE_BUFF_PROTO);
this.values = buffer;
}
}

View File

@@ -316,6 +316,7 @@ public class ObjectValue extends Value {
return res;
}
@Override public List<String> toReadableLines(Environment env, HashSet<ObjectValue> passed) {
if (passed.contains(this)) return Arrays.asList("[circular]");
return toReadableLines(env, passed, new HashSet<>());
}

View File

@@ -0,0 +1,25 @@
package me.topchetoeu.jscript.runtime.values.objects.buffers;
public final class Int32ArrayValue extends TypedArrayValue {
@Override protected int onGet(int i) {
i = (i + start) << 2;
return (
this.buffer[i] |
this.buffer[i + 1] << 8 |
this.buffer[i + 2] << 16 |
this.buffer[i + 3] << 24
);
}
@Override protected void onSet(int i, int val) {
i = (i + start) << 2;
this.buffer[i + start + 0] = (byte)(val & 0xFF);
this.buffer[i + start + 1] = (byte)(val >> 8 & 0xFF);
this.buffer[i + start + 2] = (byte)(val >> 16 & 0xFF);
this.buffer[i + start + 3] = (byte)(val >> 24 & 0xFF);
}
public Int32ArrayValue(byte[] buff, int start, int end) {
super(buff, 4, start, end);
setPrototype(INT32_ARR_PROTO);
}
}

View File

@@ -0,0 +1,15 @@
package me.topchetoeu.jscript.runtime.values.objects.buffers;
public final class Int8ArrayValue extends TypedArrayValue {
@Override protected int onGet(int i) {
return this.buffer[i + start];
}
@Override protected void onSet(int i, int val) {
this.buffer[i + start] = (byte)val;
}
public Int8ArrayValue(byte[] buff, int start, int end) {
super(buff, 1, start, end);
setPrototype(INT8_ARR_PROTO);
}
}

View File

@@ -0,0 +1,60 @@
package me.topchetoeu.jscript.runtime.values.objects.buffers;
import java.util.WeakHashMap;
import me.topchetoeu.jscript.common.environment.Environment;
import me.topchetoeu.jscript.runtime.values.Value;
import me.topchetoeu.jscript.runtime.values.objects.ArrayLikeValue;
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
import me.topchetoeu.jscript.runtime.values.primitives.UserValue;
import me.topchetoeu.jscript.runtime.values.primitives.numbers.NumberValue;
public abstract class TypedArrayValue extends ArrayLikeValue {
public static final WeakHashMap<byte[], UserValue<byte[]>> userValues = new WeakHashMap<>();
public final byte[] buffer;
public final int elementSize;
public final int start;
public final int end;
protected abstract int onGet(int i);
protected abstract void onSet(int i, int val);
@Override public int size() {
return end - start;
}
@Override public boolean setSize(int val) {
return false;
}
@Override public Value get(int i) {
if (i < 0 || i >= size()) return null;
return NumberValue.of(onGet(i));
}
@Override public boolean set(Environment env, int i, Value val) {
if (i < 0 || i >= size()) return false;
onSet(i, val.toNumber(env).getInt());
return true;
}
@Override public boolean has(int i) {
return i >= 0 && i < size();
}
@Override public boolean remove(int i) {
return false;
}
public TypedArrayValue(byte[] buffer, int elementSize, int start, int end) {
this.buffer = buffer;
this.elementSize = elementSize;
this.start = start;
this.end = end;
}
public static UserValue<byte[]> buffer(byte[] buff, ObjectValue proto) {
if (userValues.containsKey(buff)) return userValues.get(buff);
var res = UserValue.of(buff, proto);
userValues.put(buff, res);
return res;
}
}

View File

@@ -0,0 +1,19 @@
package me.topchetoeu.jscript.runtime.values.objects.buffers;
public final class Uint8ArrayValue extends TypedArrayValue {
@Override protected int onGet(int i) {
var res = this.buffer[i + start];
if (res < 0) res += 0x100;
return res;
}
@Override protected void onSet(int i, int val) {
if (val > 0x7F) val -= 0x100;
this.buffer[i + start] = (byte)val;
}
public Uint8ArrayValue(byte[] buff, int start, int end) {
super(buff, 1, start, end);
setPrototype(UINT8_ARR_PROTO);
}
}

27
src/main/resources/lib/errors.d.ts vendored Normal file
View File

@@ -0,0 +1,27 @@
interface Error {
message: string;
name: string;
}
interface ErrorConstructor {
(msg?: string): Error;
new (msg?: string): Error;
}
interface TypeError extends Error { }
interface TypeErrorConstructor {
(msg?: string): TypeError;
new (msg?: string): TypeError;
}
interface SyntaxError extends Error { }
interface SyntaxErrorConstructor {
(msg?: string): SyntaxError;
new (msg?: string): SyntaxError;
}
interface RangeError extends Error { }
interface RangeErrorConstructor {
(msg?: string): RangeError;
new (msg?: string): RangeError;
}

View File

@@ -0,0 +1,4 @@
interface JSON {
stringify(val: any): string;
parse(val: string): any;
}

19
src/main/resources/lib/globals/map.d.ts vendored Normal file
View File

@@ -0,0 +1,19 @@
interface Map<K, V> {
readonly size: number;
get(key: K): V;
has(key: K): boolean;
set(key: K, val: V): this;
delete(key: K): boolean;
clear(): void;
keys(): K[];
values(): V[];
entries(): [K, V][];
forEach(cb: (val: V, key: K, map: this) => void, self?: any): void;
[Symbol.iterator](): Iterator<[K, V]>;
}
interface MapConstructor {
new <K, V>(iterable?: Iterable<[K, V]>): Map<K, V>;
}

18
src/main/resources/lib/globals/set.d.ts vendored Normal file
View File

@@ -0,0 +1,18 @@
interface Set<V> {
readonly size: number;
add(val: V): this;
has(key: V): boolean;
delete(key: V): boolean;
clear(): void;
keys(): V[];
values(): V[];
entries(): [V, V][];
forEach(cb: (val: V, key: V, map: this) => void, self?: any): void;
[Symbol.iterator](): Iterator<V>;
}
interface SetConstructor {
new <V>(iterable?: Iterable<V>): Set<V>;
}

View File

@@ -0,0 +1,11 @@
interface WeakMap<K, V> {
readonly size: number;
get(key: K): V;
set(key: K, val: V): this;
has(key: K): boolean;
delete(key: K): boolean;
clear(): void;
}
interface WeakMapConstructor {
new <K, V>(iterable?: Iterable<[K, V]>): WeakMap<K, V>;
}

View File

@@ -1,6 +1,8 @@
/// <reference no-default-lib="true"/>
/// <reference path="./typing.d.ts"/>
/// <reference path="./iterator.d.ts"/>
/// <reference path="./async.d.ts"/>
/// <reference path="./errors.d.ts"/>
/// <reference path="./values/function.d.ts"/>
/// <reference path="./values/object.d.ts"/>
/// <reference path="./values/array.d.ts"/>
@@ -9,12 +11,22 @@
/// <reference path="./values/string.d.ts"/>
/// <reference path="./values/number.d.ts"/>
/// <reference path="./values/regexp.d.ts"/>
/// <reference path="./async.d.ts"/>
/// <reference path="./globals/json.d.ts"/>
/// <reference path="./globals/set.d.ts"/>
/// <reference path="./globals/map.d.ts"/>
/// <reference path="./globals/weak-map.d.ts"/>
declare function print(...args: any[]): void;
declare function exit(): never;
declare function measure(func: () => void): void;
declare type IArguments = Array<any>;
declare var Error: ErrorConstructor;
declare var TypeError: TypeErrorConstructor;
declare var SyntaxError: SyntaxErrorConstructor;
declare var RangeError: RangeErrorConstructor;
declare var Array: ArrayConstructor;
declare var Boolean: BooleanConstructor;
declare var Function: FunctionConstructor;
@@ -24,3 +36,9 @@ declare var Object: ObjectConstructor;
declare var RegExp: RegExpConstructor;
declare var String: StringConstructor;
declare var Promise: PromiseConstructor;
declare var JSON: JSON;
declare var Set: SetConstructor;
declare var Map: MapConstructor;
declare var WeakMap: WeakMapConstructor;

View File

@@ -1,6 +1,4 @@
declare interface Record<Key, Val> {
[key: Key]: Val;
}
declare type Record<Key, Val> = { [x in Key]: Val }
declare type InstanceType<T> = T extends new (...args: any[]) => infer T ? T : never;
declare type ReturnType<T> = T extends (...args: any[]) => infer T ? T : never;
declare type Arguments<T> =

View File

@@ -3,7 +3,7 @@ declare interface Array<T> {
[i: number]: T;
forEach(this: T[], cb: (val: T, i: number, self: this) => void, self?: any): void;
join(this: T[], delim?: string): void;
join(this: T[], delim?: string): string;
push(this: T[], ...elements: T[]): number;
pop(this: T[]): T | undefined;
@@ -11,8 +11,8 @@ declare interface Array<T> {
unshift(this: T[], ...elements: T[]): number;
shift(this: T[]): T | undefined;
concat(this: T[], ...elements: (T | T[])[]): T | undefined;
slice(this: T[], start?: number, end?: number): T | undefined;
concat(this: T[], ...elements: (T | T[])[]): T[];
slice(this: T[], start?: number, end?: number): T[];
splice(this: T[], start?: number, count?: number): T[];
splice(this: T[], start: number | undefined, count: number | undefined, ...elements: T[]): T[];

View File

@@ -1,11 +1,16 @@
declare interface Function {
prototype: unknown;
prototype: object;
name: string;
length: number;
valueOf(): this;
toString(): string;
apply<Args extends readonly any[], Ret, Self>(this: (this: Self, ...args: Args) => Ret, self: Self, args: Args): Ret;
apply(this: Function, self: any, args: any[]): any;
call<Args extends readonly any[], Ret, Self>(this: (this: Self, ...args: Args) => Ret, self: Self, ...args: Args): Ret;
call(this: Function, self: any, ...args: any): any;
bind<T extends (...args: any[]) => any>(this: T): T;
bind<
Bound extends readonly any[],

View File

@@ -7,8 +7,8 @@ declare interface String {
at(index: number): string | undefined;
charAt(i: number): string | undefined;
charCodeAt(i: number): string;
codePointAt(i: number): string;
charCodeAt(i: number): number;
codePointAt(i: number): number;
includes(search: string, offset?: number): number;
indexOf(search: string, offset?: number): number;

17
tsconfig.json Normal file
View File

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