Compare commits

...

206 Commits

Author SHA1 Message Date
b97e4bf163 improve: UserValue API 2024-12-28 13:20:04 +02:00
9ce0504948 fix: debugger concurrency issues 2024-12-28 13:19:53 +02:00
4c53689d9c feat: some behavioral fixes 2024-12-28 13:19:35 +02:00
6c8c329992 feat: improve transpiler infrastructure 2024-12-28 13:19:02 +02:00
74f08b7483 small stdlib improvements
Some checks failed
tagged-release / Tagged Release (push) Failing after 7m8s
2024-12-28 13:17:45 +02:00
2bf920c681 remove old soruce map primordials and add next tick scheduler 2024-12-27 19:18:41 +02:00
1ac68425af feat: implement basic promises 2024-12-27 19:18:18 +02:00
7423e3f283 feat: more sophisticated stdlib definitions 2024-12-27 19:16:55 +02:00
afe4542682 fix: concurrency issues with debug server 2024-12-27 19:16:26 +02:00
c971fde0e2 feat: implement binary number literals 2024-12-27 19:15:20 +02:00
8a34db833c refactor: implement source mapping in javascript, instead of java 2024-12-27 19:15:09 +02:00
398d88c0a5 add more functions in stdlib, fix some issues 2024-12-27 19:10:56 +02:00
f80266618c fix: throw copied return syntax too closely 2024-12-27 19:09:01 +02:00
f1997e4584 fix: incorrect continue jump location in for loops 2024-12-25 03:01:49 +02:00
e93498fed5 fix typescript compiler script 2024-12-25 02:56:16 +02:00
29bea68525 feat: add back debugger from old version 2024-12-25 02:55:54 +02:00
3a6401094f fix: don't omit stack trace elements without locations 2024-12-25 02:54:22 +02:00
a705bf296e fix: empty file yields an error 2024-12-25 02:53:53 +02:00
c3432306f7 fix: global object can be an arbitrary value 2024-12-25 02:53:44 +02:00
d8c18ccf17 more utility 2024-12-25 02:53:24 +02:00
277f59e54a prepare codebase for source maps 2024-12-25 02:53:11 +02:00
a1bb5bdba6 separate the call stack from the debug context 2024-12-25 02:52:10 +02:00
c699102e56 try-catch AGAIN 2024-12-25 02:51:02 +02:00
b2f5068e12 some utility methods 2024-12-25 02:50:37 +02:00
05bafc7317 improve json parsing 2024-12-25 02:48:37 +02:00
c7c31c3859 feat: implement a lot of built-ins 2024-12-25 02:48:04 +02:00
c18015b9a0 fix: wrong precedences of && and ||
(how the fuck did i get this wrong)
2024-12-13 02:33:25 +02:00
5346b8917d refactor: add semicolons and spaces -> tabs in gradle scripts 2024-12-13 02:33:01 +02:00
2ed7959088 refacor: remove pesky console.log 2024-12-13 02:29:55 +02:00
239d0ae8d7 feat: implement a lot of stdlibs 2024-12-13 02:29:41 +02:00
6fac295b99 fix: try-catch broken (again) 2024-12-13 02:29:09 +02:00
66440a9649 fix: a plethora of loop off by one and null issues 2024-12-13 02:28:36 +02:00
274a925ff8 fix: broken labeled jumps 2024-12-13 02:27:57 +02:00
130fe17441 missed you lil fucker 2024-12-13 02:27:32 +02:00
493c54ed39 fix: symbol was falsy 2024-12-13 02:27:21 +02:00
75786f39ad fix: access of symbols in string 2024-12-13 02:27:12 +02:00
bce8b7293c fix: parseInt was broken 2024-12-13 02:26:34 +02:00
00aeef5321 fix: make member algorithms correct 2024-12-13 02:26:12 +02:00
ff4aa3dcfd fix: return null when loading an inexistent resource 2024-12-11 11:53:29 +02:00
45f52ff123 fix: catch variable causing issues 2024-12-11 11:53:19 +02:00
bed4014bef feat: implement simple env + ts loader 2024-12-11 11:53:02 +02:00
17406c6b81 feat: create build process for environment 2024-12-11 11:51:03 +02:00
3abdd8d3c9 feat: add constructor target support 2024-12-10 15:37:39 +02:00
a329f615cf fix: "e1" literal read as a number exponent 2024-12-10 01:21:44 +02:00
058d20b27f feat: dead simple Map and RegExp implementations 2024-12-10 01:11:07 +02:00
ea158c1e60 fix: converts symbol key to string when assigning function to member 2024-12-10 01:10:43 +02:00
4e18c76bb1 some toStrings 2024-12-10 01:10:14 +02:00
8d7939d85a fix: wrong index calculation 2024-12-10 01:09:50 +02:00
814e0d7b7e feat: allow to invoke compiler with variable encapsulation enabled 2024-12-10 00:44:18 +02:00
138baebacb fix: call regex constructor correctly 2024-12-10 00:43:56 +02:00
db241919f2 fix: when capturing, must check if already in captures 2024-12-10 00:43:15 +02:00
db45eb529d change indentation to tabs 2024-12-09 23:58:43 +02:00
caf44a50e5 Merge pull request #31 from TopchetoEU:TopchetoEU/revert-ES5
TopchetoEU/revert-ES5
2024-12-09 23:39:57 +02:00
65f9debecc fix: use default construct method 2024-12-09 23:39:05 +02:00
3f5e1a5fd8 feat: implement user values 2024-12-09 23:38:53 +02:00
b0d8a072aa add hashCode to primitives 2024-12-09 23:38:39 +02:00
2e8e123ec4 small parser fixes 2024-12-09 23:37:08 +02:00
54d55814af fix: errors with out of range arguments 2024-12-09 22:16:24 +02:00
28679f44d5 fix: symbols not stringified properly 2024-12-09 22:15:51 +02:00
611be55bbb fix: should throw engine exceptions, not java exceptions 2024-12-09 22:15:38 +02:00
4992d0211b fix: nasty issues with compilation 2024-12-09 22:15:15 +02:00
ba7505e148 fix: globalThis and for-in not parsed 2024-11-24 12:49:31 +02:00
3c13799c2f feat: make function logging configurable 2024-11-24 12:49:04 +02:00
5c2fd00bfb fix: add location data for LOAD_FUNCs 2024-11-24 12:48:49 +02:00
39eb6ffac5 fix: do variable inits properly 2024-11-24 12:48:30 +02:00
7f6df49fc5 fix: scope issues 2024-11-24 12:47:51 +02:00
61c5df5003 fix: gd damn it 2024-11-24 12:47:15 +02:00
41bb27e4dd implement all changes in runtime 2024-11-23 20:15:42 +02:00
b4e7a42975 regress: remove ES6 stuff (except apply and construct constraints) from funcs 2024-11-23 20:11:57 +02:00
92fb0dbbfd regress: simplify invoke model 2024-11-23 20:11:12 +02:00
fe8f65faf5 some final stuff in parsing 2024-11-23 20:10:47 +02:00
54fe16393a regress: remove infrastructure for super references 2024-11-23 20:10:11 +02:00
14e4aade35 regress: remove infrastructure needed for ES6 stuff, simplify loops 2024-11-23 20:09:29 +02:00
754648fbf6 regress: remove ES6 instructions 2024-11-23 20:08:01 +02:00
20f2c3c5e9 regress: remove ES6 stuff from members 2024-11-23 20:07:10 +02:00
c5067cbfdd regress: remove ES6 variables and simplify scope 2024-11-23 20:06:24 +02:00
5644966dd7 regress: remove ES6 nodes 2024-11-23 20:06:09 +02:00
50eb204da7 fix: remove unnecessary reference from core to compiler 2024-11-23 20:04:19 +02:00
45308e6d65 refactor: remove periods from ends of error msgs 2024-11-23 20:04:03 +02:00
0ebf189c95 fix: remove multi-key bullcrap 2024-11-23 20:01:00 +02:00
2fe5ce607a fix: multiply acting as subtract 2024-09-21 19:01:05 +03:00
d821a3a89b refactor: utilize inheritence in index.js 2024-09-21 18:46:22 +03:00
0064c74ac8 fix: don't allow execution of CALL_SUPER twice or in non-construct call 2024-09-21 18:46:02 +03:00
bd548c813a fix: null out thisArg only when constructing 2024-09-21 18:45:38 +03:00
78af69ec80 fix: parseStatementEnd behaving incorrectly when EOF 2024-09-21 18:44:08 +03:00
98e5299f9c fix: derived classes use the scope API incorrectly 2024-09-21 18:43:32 +03:00
797452c28f fix: tmp variables captured incorrectly 2024-09-21 18:43:15 +03:00
fee74dcba4 fix: infinite loop in class parser 2024-09-21 18:42:51 +03:00
9845a39e84 fix: operations polluting stack 2024-09-21 18:42:34 +03:00
ee78bdc1cb feat: implement derived classes 2024-09-21 18:06:03 +03:00
7fcb9ed19f fix: member field initializers should be iterable 2024-09-20 11:39:48 +03:00
8dee4353d4 feat: implement non-enumerable members in classes 2024-09-20 11:39:46 +03:00
59e6f34a01 refactor: clean up REPL stringification code 2024-09-20 11:39:40 +03:00
fdac93bf4d fix: scope offsets calculated incorrectly 2024-09-20 11:39:34 +03:00
06eae2eaf2 Merge pull request #29 from TopchetoEU/TopchetoEU/classes
Classes
2024-09-19 15:21:01 +00:00
d7b50fa45b refactor: use classes in index.js 2024-09-19 18:11:42 +03:00
077e8afff7 fix: some behavioral issues 2024-09-19 18:11:35 +03:00
631ef9db4a fix: differenciate between non-functions and non-invokables in messages 2024-09-19 18:10:50 +03:00
0258cc0a90 feat: implement classes (without inheritence) 2024-09-19 18:09:28 +03:00
0b3dca8b13 refactor: extract members into own classes 2024-09-19 18:08:11 +03:00
6d56660136 fix: stupid mistake with variable capturing 2024-09-19 14:22:21 +03:00
8a21873631 fix: retrofit patterns for bindings and check if var is init in runtime 2024-09-19 11:02:02 +03:00
fbbd26bf7d fix: remove unneeded comments 2024-09-14 22:08:33 +03:00
e2a8a382cc refactoring 2024-09-14 21:33:33 +03:00
0670ffcdd1 fix: int value not correctly recognized 2024-09-14 19:54:42 +03:00
9b957335bf optimization: keep StringValue instances tied to one String instance 2024-09-14 19:45:05 +03:00
e9f889576c feat: implement hidden integers 2024-09-14 19:38:30 +03:00
e11d182631 refactor: remove dead code 2024-09-14 18:52:07 +03:00
30674ee463 refactor: get rid of InterruptException 2024-09-14 18:46:47 +03:00
fab3e59910 feat: implement a byte array 2024-09-14 18:46:28 +03:00
d7e4e7a024 refactor: oops 2024-09-14 18:45:55 +03:00
e4166fe450 refactor: rewrite some code for java 8 compatibility 2024-09-14 18:45:20 +03:00
b5b7781136 Merge pull request #28 from TopchetoEU:TopchetoEU/destructing
TopchetoEU/destructing
2024-09-14 15:38:02 +03:00
f13bf584a5 feat: add some missing features in the polyfills 2024-09-14 15:25:34 +03:00
4e8b110fc4 feat: add assign shorthands 2024-09-14 14:33:09 +03:00
cb82f4cf32 feat: implement patterns 2024-09-14 14:23:46 +03:00
23ae2b2e46 todo 2024-09-14 14:23:35 +03:00
55613ef2c9 feat: extend the instruction set 2024-09-14 14:23:28 +03:00
0b34c68139 fix: unnecessary new line in toReadable 2024-09-14 14:22:51 +03:00
d87e53264d refactor: split array logic 2024-09-14 14:22:31 +03:00
1f42263051 clean up member logic 2024-09-14 13:53:58 +03:00
3e6816cb2c fix: properly hande variable collisions 2024-09-12 20:25:11 +03:00
2a01b3d86e some work losl 2024-09-07 21:06:08 +03:00
8e64d13c87 refactor: clean up assigning 2024-09-06 15:48:22 +03:00
5f88061ee7 refactor: rename callNew -> construct and call -> invoke 2024-09-06 15:48:07 +03:00
b9268518f6 fix: array statements broken when empty elements 2024-09-06 15:46:10 +03:00
63ccd5757e feat: implement spread_obj intrinsic 2024-09-06 10:03:55 +03:00
515011b3ef refactor: improve meber listing system 2024-09-06 10:03:37 +03:00
b6f04aa177 Merge pull request #27 from TopchetoEU/TopchetoEU/optimize-var-flatten
Optimize var flattening
2024-09-05 22:32:48 +03:00
6f548ce5ff feat: reflect scope optimizations in runtime 2024-09-05 22:30:28 +03:00
7c74df4d36 refactor: use new system to reorder variables that overlaps neighboring scopes 2024-09-05 21:25:39 +03:00
641d4d1863 Merge pull request #26 from TopchetoEU/ES6
ES6 Support Groundwork + Fixes
2024-09-05 17:26:07 +03:00
0004839f6f fix: realloc for declarations after each iteration 2024-09-05 17:15:26 +03:00
07411f62c8 feat: implement capturable locals realloc 2024-09-05 17:14:59 +03:00
4bfc062aaf fix: correctly flatten locals in control flow statements 2024-09-05 17:13:34 +03:00
9ec99def3f fix: variable declarations shouldn't collide with defined name of named function exp 2024-09-05 13:29:42 +03:00
8f13ff3e0b fix: scope gets polluted by arguments with named function expressions 2024-09-05 13:29:20 +03:00
d7353e19ed fix: treat "arguments" as a keyword (as per strict soecifications) 2024-09-05 13:18:53 +03:00
e509edc459 fix: wrong arguments when compilling function bodies 2024-09-05 13:03:49 +03:00
b6a90b108b fix: wrong check for var decl collisions 2024-09-05 13:03:36 +03:00
55caf1e206 refactor: remove unneeded old comments 2024-09-05 13:03:04 +03:00
eac4a3af23 fix: throw access before decl for const and let in runtime 2024-09-05 00:31:03 +03:00
5b4adf5286 a clusterfuck of fixes with let and const 2024-09-05 00:28:13 +03:00
807b3918fa motherfucker 2024-09-04 15:55:59 +03:00
9265a7d813 Merge branch 'master' into ES6 2024-09-04 15:52:03 +03:00
1589ef51b0 refactor: move src and resources to standard places 2024-09-04 15:32:54 +03:00
marregui
313b20a3b3 Add first test (#23)
* Add the first test and upgrade build.gradle to modern standards

1. gradle wrapper
2. ./gradlew run
3. manifest will look like
    Manifest-Version: 1.0
    Main-Class: me.topchetoeu.jscript.runtime.SimpleRepl
    Build-Timestamp: 2024-09-04T10:44:35.990+0200
    Build-Branch: ma/add-first-tests
    Build-Revision: 412edc0ebc
    Build-Jdk: 21.0.3 (Oracle Corporation 21.0.3+7-LTS-152)
    Build-Author: TopchetoEU
4. build/distributions contains a zip and a jar which contain jscript-0.9.41-beta.jar
5. unnecessary libs have been removed
6. gradle has been updated to 8.10
7. first test has been added

* fix: revert removal of Jabel (for support of Java 11)

---------

Co-authored-by: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com>
2024-09-04 15:29:17 +03:00
ce9b419757 reafactor: make globals initializer use ES6 features 2024-09-04 10:45:34 +03:00
6f8efe74c4 fix: print was returning java null, not JS undefined 2024-09-04 10:45:14 +03:00
bd503ed943 feat: impl new instructions 2024-09-04 10:44:58 +03:00
5359c54694 fix: rethrow SyntaxException from compilation as EngineException 2024-09-04 10:44:44 +03:00
93c246ad97 refactor: remove arg loading from frame 2024-09-04 10:44:24 +03:00
7c8efaf066 fix: incorrect printing of object-like values 2024-09-04 10:43:40 +03:00
546d663466 feat: add this arg capture 2024-09-04 10:42:21 +03:00
f929015f55 ammend to prev commit 2024-09-04 10:41:52 +03:00
2a5f6aa9aa fix: use _STR and _INT variants of member instructions 2024-09-04 10:41:17 +03:00
78d233a6bd refactor: remove ArgumentsNode 2024-09-04 10:39:11 +03:00
3f25868f19 fix: some scope bug fixes 2024-09-04 10:38:16 +03:00
e3f1bc0949 fix: incorrect compilation of if-else 2024-09-04 10:36:48 +03:00
506726fd76 feat: implement ES6 variables and rest args 2024-09-04 10:36:25 +03:00
4cbc108686 feat: implement optional arguments 2024-09-04 10:00:48 +03:00
c39c06b792 refactor: move away intrinsic logic to final methods for performance 2024-09-04 10:00:45 +03:00
7ab78b9cea fix: control flow nodes were making scopes instead of compound nodes 2024-09-04 10:00:43 +03:00
87e077d70d oops 2024-09-04 10:00:40 +03:00
52f7c15ac8 refactor: change how function scope keeps track of arguments 2024-09-04 10:00:38 +03:00
6932bea677 refactor: remove unused class 2024-09-04 10:00:36 +03:00
82d6f52a26 refactor: make some classes final for performance 2024-09-04 10:00:33 +03:00
1b87c2f5a6 fix: add for-of to statement list 2024-09-04 10:00:30 +03:00
163dfe7b6e feat: implement access to intrinsics 2024-09-04 10:00:25 +03:00
2b6d4a87ca fix: for in and for of not reading open paren 2024-09-04 10:00:22 +03:00
349d392269 major rewrite: clean up a lot of code and lay ground for ES6 support 2024-09-04 10:00:15 +03:00
6481e992fa feat: implement "has" function for scopes 2024-09-04 10:00:11 +03:00
4a5e5a71af feat: Create new scope system for ES6+ support 2024-09-04 10:00:02 +03:00
89ba921b4a refactor: rename statements to nodes 2024-09-04 10:00:00 +03:00
a45f4109d8 feat: add environment in Source 2024-09-04 09:59:57 +03:00
62aba62a41 refactor: make Environment more reusable 2024-09-04 09:59:54 +03:00
4048d6ef1c refactor: rename ES5 to JavaScript 2024-09-04 09:59:42 +03:00
d0ccf00f14 everything all at once 2024-09-04 09:59:35 +03:00
f09feae08f refactor: clean up parsing 2024-09-04 09:59:32 +03:00
ef0fc5a61d refactor: distribute parse functions in node classes 2024-09-04 09:59:28 +03:00
bab59d454f refactor: Transition to a Value class 2024-09-04 09:59:26 +03:00
3475e3a130 refactor: Remove environment-related bloat 2024-09-04 09:59:15 +03:00
49b52d90a7 fix: wrappers cache compare objects with .equals and not == 2024-04-21 11:03:00 +03:00
8a8de518a6 feat: make Function constructor 2024-04-20 23:44:02 +03:00
099201e4ad refactor: remove testing junk in REPL 2024-04-20 22:23:45 +03:00
f8553b79f9 fix: run module in an isolated context 2024-04-20 22:22:55 +03:00
ba6462458c fix: some fixes in the filesystem 2024-04-20 22:18:47 +03:00
e33cdbb172 fix: properties not applied to wrappers without constructor method 2024-04-13 01:03:34 +03:00
fc6ddf7d3c feat: allow interface proxy wrappers 2024-04-12 16:37:06 +03:00
7f275095a2 fix: continue statement compiled incorrectly 2024-04-07 12:50:58 +03:00
90d019f92a bump 2024-04-07 12:33:48 +03:00
6fb31be12c fix(debugger): handle all errors when generating description 2024-04-07 12:33:26 +03:00
d6ede0b404 fix: incorrect toFixed behavior 2024-04-03 15:52:01 +03:00
71b40240c0 feat: add Number.toFixed 2024-04-03 15:09:01 +03:00
a8775d212f fix: clean up extensions at some points 2024-04-03 14:52:29 +03:00
71872a8d64 fix 2024-04-03 14:25:14 +03:00
c707f880f7 fix: use Extensions instead of Environment 2024-04-03 14:21:23 +03:00
0d629a6e82 fix: use correct class instead of proxy 2024-04-03 12:27:15 +03:00
6eea342d04 fix: fuck 2024-04-02 18:24:43 +03:00
ece9cf68dc fix: correctly update proto chain 2024-04-02 18:19:05 +03:00
11ecd8c68f fix: exec debugger close logic on application exit 2024-04-02 18:05:49 +03:00
48bd304c6e fix: environment forks fixes 2024-04-02 18:05:20 +03:00
d8e46c3149 fix: clone environment correctly 2024-03-31 16:11:32 +03:00
5fc5eb08f8 fix: update breakpoints when removing bp 2024-03-30 12:52:44 +02:00
8acbc003c4 fix: properly resolve breakpoints 2024-03-30 12:13:04 +02:00
fda33112a7 fix: load maps when attaching debugger 2024-03-30 11:13:45 +02:00
349 changed files with 16468 additions and 16064 deletions

16
.gitignore vendored
View File

@@ -1,24 +1,18 @@
*
/*
!/src
!/src/**/*
!/doc
!/doc/**/*
!/tests
!/tests/**/*
!/.github
!/.github/**/*
!/.gitignore
!/.gitattributes
!/LICENSE
!/README.md
!/settings.gradle
!/build.gradle
!/gradle.properties
!/gradle
!/gradle/wrapper
!/gradle/wrapper/gradle-wrapper.properties
!/package.json
!/rollup.config.js

View File

@@ -1,32 +1,124 @@
import java.text.SimpleDateFormat
plugins {
id "application"
id 'application';
id 'com.github.node-gradle.node' version '5.0.0';
id 'net.nemerosa.versioning' version '2.15.0';
id 'org.ajoberstar.grgit' version '5.0.0-rc.3'; // required by gradle
// TODO: figure out how to integrate proguard
// id "com.github.xaverkapeller.proguard-annotations"
}
base.archivesName = project.project_name;
version = project.project_version;
group = project.project_group;
description = 'ES5-compliant JavaScript interpreter';
node {
version = '20.0.0';
npmVersion = '8.0.0';
download = true;
}
task compileEnv(type: NpmTask) {
inputs.files('rollup.config.js');
inputs.dir('src/lib/libs');
outputs.files("build/js/env.js");
// group = 'build'
args = ['run', 'build-env'];
}
task compileTypescript(type: NpmTask) {
inputs.files('rollup.config.js');
inputs.dir('src/lib/transpiler');
outputs.files("build/js/ts.js");
// nom nom tasty ram
environment.put("NODE_OPTIONS", "--max-old-space-size=4096");
// group = 'build'
args = ['run', 'build-ts'];
}
repositories {
mavenCentral();
}
dependencies {
annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:0.4.2';
compileOnly 'com.github.bsideup.jabel:jabel-javac-plugin:0.4.2';
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2';
testRuntimeOnly 'org.junit.platform:junit-platform-launcher';
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
toolchain.languageVersion = JavaLanguageVersion.of(11)
withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_17;
targetCompatibility = JavaVersion.VERSION_17;
toolchain {
languageVersion = JavaLanguageVersion.of(17);
}
}
configure([tasks.compileJava]) {
options.release = 8;
}
jar {
manifest.attributes["Main-class"] = project.main_class
manifest {
attributes(
'Main-Class': project.main_class,
'Build-Timestamp': new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()),
'Build-Branch': versioning.info.branch,
'Build-Revision': versioning.info.commit,
'Build-Jdk': "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']})",
'Build-Author': 'TopchetoEU',
);
}
}
sourceSets {
main.java.srcDirs = [ "src/java" ]
main.resources.srcDirs = [ "src/assets" ]
application {
mainClass = project.main_class;
applicationDefaultJvmArgs = ['-Xmx2G', '-Xms2G', '-server', '-Dfile.encoding=UTF-8'];
}
distZip {
eachFile { file ->
if (file.path.contains('bin')) {
file.exclude();
}
}
}
distTar {
eachFile { file ->
if (file.path.contains('bin')) {
file.exclude();
}
}
}
processResources {
filesMatching "metadata.json", {
expand(
version: project.project_version,
name: project.project_name
)
}
dependsOn compileEnv;
dependsOn compileTypescript;
from("build/js") {
into "lib";
}
filesMatching "metadata.json", {
expand(
version: project.project_version,
name: project.project_name,
);
}
}
base.archivesName = project.project_name
version = project.project_version
group = project.project_group
test {
useJUnitPlatform();
}
wrapper {
gradleVersion = '8.10';
}

View File

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

View File

@@ -1,7 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

31
package.json Normal file
View File

@@ -0,0 +1,31 @@
{
"scripts": {
"build-env": "rollup -c --environment INPUT:src/lib/libs/_entry.ts,OUTPUT:build/js/index.js,POLYFILLS:src/lib/libs/polyfills",
"build-ts": "rollup -c --environment INPUT:src/lib/transpiler/_entry.ts,OUTPUT:build/js/ts.js"
},
"dependencies": {
"@babel/core": "^7.26.0",
"@babel/runtime": "^7.26.0",
"@babel/standalone": "^7.26.4",
"@rollup/plugin-json": "^6.1.0",
"@types/babel__preset-env": "^7.9.7",
"@types/babel__standalone": "^7.1.9",
"@types/coffeescript": "^2.5.7",
"coffeescript": "^2.7.0",
"typescript": "^5.7.2"
},
"devDependencies": {
"@babel/plugin-transform-class-properties": "^7.25.9",
"@babel/plugin-transform-runtime": "^7.25.9",
"@babel/plugin-transform-typescript": "^7.25.9",
"@babel/preset-env": "^7.26.0",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.1",
"@types/node": "^22.10.1",
"rollup": "^4.24.0",
"tslib": "^2.8.0"
}
}

130
rollup.config.js Normal file
View File

@@ -0,0 +1,130 @@
const { defineConfig } = require("rollup");
const terser = require("@rollup/plugin-terser");
const typescript = require("@rollup/plugin-typescript");
const babel = require("@rollup/plugin-babel");
const commonjs = require("@rollup/plugin-commonjs");
const nodeResolve = require("@rollup/plugin-node-resolve");
const json = require("@rollup/plugin-json");
const { resolve } = require("path");
const shouldMinify = () => false;
const shouldEmitSourcemaps = () => true;
const shouldPolyfill = () => !!process.env.POLYFILLS;
const construct = (input, output) => defineConfig({
input,
plugins: [
shouldPolyfill() && {
name: "babel-fake-runtime",
resolveId(source) {
if (source.startsWith("!polyfills:/helpers")) return resolve(process.env.POLYFILLS) + source.slice(19) + ".js";
}
},
commonjs(),
nodeResolve(),
json(),
babel({
extensions: [],
exclude: ["node_modules/**"],
babelHelpers: "runtime",
plugins: [
["@babel/plugin-transform-typescript", {
onlyRemoveTypeImports: true,
optimizeConstEnums: true,
allowDeclareFields: true,
}],
["@babel/plugin-transform-class-properties"],
["@babel/plugin-transform-runtime", {
moduleName: shouldPolyfill() ? "!polyfills:" : undefined,
version: "^7.24.0",
}],
]
}),
babel({
extensions: [],
exclude: shouldPolyfill() ? [process.env.POLYFILLS + "/**"] : [],
assumptions: {
ignoreToPrimitiveHint: true,
noClassCalls: true,
},
env: {
development: { compact: false },
},
babelHelpers: "runtime",
plugins: [
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-block-scoping",
"@babel/plugin-transform-classes",
"@babel/plugin-transform-computed-properties",
"@babel/plugin-transform-destructuring",
"@babel/plugin-transform-for-of",
"@babel/plugin-transform-object-super",
"@babel/plugin-transform-parameters",
"@babel/plugin-transform-shorthand-properties",
"@babel/plugin-transform-spread",
"@babel/plugin-transform-object-rest-spread",
"@babel/plugin-transform-template-literals",
"@babel/plugin-transform-unicode-escapes",
"@babel/plugin-transform-unicode-regex",
"@babel/plugin-transform-exponentiation-operator",
"@babel/plugin-transform-async-to-generator",
"@babel/plugin-transform-async-generator-functions",
"@babel/plugin-transform-nullish-coalescing-operator",
"@babel/plugin-transform-optional-chaining",
"@babel/plugin-transform-logical-assignment-operators",
"@babel/plugin-transform-numeric-separator",
"@babel/plugin-transform-class-properties",
"@babel/plugin-transform-class-static-block",
"@babel/plugin-transform-regenerator",
["@babel/plugin-transform-runtime", {
moduleName: shouldPolyfill() ? "!polyfills:" : undefined,
version: "^7.24.0",
}],
],
}),
typescript({
exclude: ["node_modules/**", "*.js"],
compilerOptions: {
allowImportingTsExtensions: true,
noEmit: true,
},
noForceEmit: true,
noEmitOnError: true,
}),
shouldMinify() && terser({
sourceMap: shouldEmitSourcemaps(),
keep_classnames: true,
}),
],
output: {
file: output,
format: "iife",
globals: {
fs: "null",
path: "null",
os: "null",
inspector: "null",
tty: "null",
util: "null",
assert: "null",
url: "null",
"@babel/preset-typescript/package.json": "null",
module: "null",
process: "null",
v8: "null",
},
// plugins: [babel.getBabelOutputPlugin({
// allowAllFormats: true,
// })],
sourcemap: shouldEmitSourcemaps(),
inlineDynamicImports: true,
},
});
module.exports = construct(process.env.INPUT, process.env.OUTPUT);

View File

@@ -1,5 +1,12 @@
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0'
pluginManagement {
repositories {
mavenCentral();
gradlePluginPortal();
}
}
rootProject.name = properties.project_name
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0';
}
rootProject.name = properties.project_name;

View File

@@ -1,58 +0,0 @@
package me.topchetoeu.jscript.common;
public class Buffer {
private byte[] data;
private int length;
public void write(int i, byte[] val) {
if (i + val.length > data.length) {
var newCap = i + val.length + 1;
if (newCap < data.length * 2) newCap = data.length * 2;
var tmp = new byte[newCap];
System.arraycopy(this.data, 0, tmp, 0, length);
this.data = tmp;
}
System.arraycopy(val, 0, data, i, val.length);
if (i + val.length > length) length = i + val.length;
}
public int read(int i, byte[] buff) {
int n = buff.length;
if (i + n > length) n = length - i;
System.arraycopy(data, i, buff, 0, n);
return n;
}
public void clear() {
data = new byte[128];
length = 0;
}
public void append(byte b) {
write(length, new byte[] { b });
}
public byte[] data() {
var res = new byte[length];
System.arraycopy(this.data, 0, res, 0, length);
return res;
}
public int length() {
return length;
}
public Buffer(byte[] data) {
this.data = new byte[data.length];
this.length = data.length;
System.arraycopy(data, 0, this.data, 0, data.length);
}
public Buffer(int capacity) {
this.data = new byte[capacity];
this.length = 0;
}
public Buffer() {
this.data = new byte[128];
this.length = 0;
}
}

View File

@@ -1,57 +0,0 @@
package me.topchetoeu.jscript.common;
import java.io.File;
import java.nio.file.Path;
public class Filename {
public final String protocol;
public final String path;
@Override public String toString() {
return protocol + "://" + path;
}
@Override public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + protocol.hashCode();
result = prime * result + path.hashCode();
return result;
}
@Override public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
var other = (Filename) obj;
if (protocol == null) {
if (other.protocol != null) return false;
}
else if (!protocol.equals(other.protocol)) return false;
if (path == null) {
if (other.path != null) return false;
}
else if (!path.equals(other.path)) return false;
return true;
}
public Filename(String protocol, String path) {
path = path.trim();
protocol = protocol.trim();
this.protocol = protocol;
this.path = path;
}
public static Filename parse(String val) {
var i = val.indexOf("://");
if (i >= 0) return new Filename(val.substring(0, i).trim(), val.substring(i + 3).trim());
else return new Filename("file", val.trim());
}
public static Path normalize(String path) {
return Path.of(Path.of("/" + path.trim().replace("\\", "/")).normalize().toString().substring(1));
}
public static Filename fromFile(File file) {
return new Filename("file", file.getAbsolutePath());
}
}

View File

@@ -1,14 +0,0 @@
package me.topchetoeu.jscript.common;
public class FunctionBody {
public final FunctionBody[] children;
public final Instruction[] instructions;
public final int localsN, argsN;
public FunctionBody(int localsN, int argsN, Instruction[] instructions, FunctionBody[] children) {
this.children = children;
this.argsN = argsN;
this.localsN = localsN;
this.instructions = instructions;
}
}

View File

@@ -1,369 +0,0 @@
package me.topchetoeu.jscript.common;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
public class Instruction {
public static enum Type {
NOP(0),
RETURN(1),
THROW(2),
THROW_SYNTAX(3),
DELETE(4),
TRY_START(5),
TRY_END(6),
CALL(7),
CALL_NEW(8),
JMP_IF(9),
JMP_IFN(10),
JMP(11),
PUSH_UNDEFINED(12),
PUSH_NULL(13),
PUSH_BOOL(14),
PUSH_NUMBER(15),
PUSH_STRING(16),
LOAD_VAR(17),
LOAD_MEMBER(18),
LOAD_GLOB(20),
LOAD_FUNC(21),
LOAD_ARR(22),
LOAD_OBJ(23),
STORE_SELF_FUNC(24),
LOAD_REGEX(25),
DUP(26),
STORE_VAR(27),
STORE_MEMBER(28),
DISCARD(29),
MAKE_VAR(30),
DEF_PROP(31),
KEYS(32),
TYPEOF(33),
OPERATION(34);
private static final HashMap<Integer, Type> types = new HashMap<>();
public final int numeric;
static {
for (var val : Type.values()) types.put(val.numeric, val);
}
private Type(int numeric) {
this.numeric = numeric;
}
public static Type fromNumeric(int i) {
return types.get(i);
}
}
public static enum BreakpointType {
NONE,
STEP_OVER,
STEP_IN;
public boolean shouldStepIn() {
return this != NONE;
}
public boolean shouldStepOver() {
return this == STEP_OVER;
}
}
public final Type type;
public final Object[] params;
@SuppressWarnings("unchecked")
public <T> T get(int i) {
if (i >= params.length || i < 0) return null;
return (T)params[i];
}
@SuppressWarnings("unchecked")
public <T> T get(int i, T defaultVal) {
if (i >= params.length || i < 0) return defaultVal;
return (T)params[i];
}
public boolean match(Object ...args) {
if (args.length != params.length) return false;
for (int i = 0; i < args.length; i++) {
var a = params[i];
var b = args[i];
if (a == null || b == null) {
if (!(a == null && b == null)) return false;
}
if (!a.equals(b)) return false;
}
return true;
}
public boolean is(int i, Object arg) {
if (params.length <= i) return false;
return params[i].equals(arg);
}
public void write(DataOutputStream writer) throws IOException {
var rawType = type.numeric;
switch (type) {
case KEYS:
case PUSH_BOOL:
case STORE_MEMBER: rawType |= (boolean)get(0) ? 128 : 0; break;
case STORE_VAR: rawType |= (boolean)get(1) ? 128 : 0; break;
case TYPEOF: rawType |= params.length > 0 ? 128 : 0; break;
default:
}
writer.writeByte(rawType);
switch (type) {
case CALL: writer.writeInt(get(0)); break;
case CALL_NEW: writer.writeInt(get(0)); break;
case DUP: writer.writeInt(get(0)); break;
case JMP: writer.writeInt(get(0)); break;
case JMP_IF: writer.writeInt(get(0)); break;
case JMP_IFN: writer.writeInt(get(0)); break;
case LOAD_ARR: writer.writeInt(get(0)); break;
case LOAD_FUNC: {
writer.writeInt(params.length - 1);
for (var i = 0; i < params.length; i++) {
writer.writeInt(get(i + 1));
}
writer.writeInt(get(0));
break;
}
case LOAD_REGEX: writer.writeUTF(get(0)); break;
case LOAD_VAR: writer.writeInt(get(0)); break;
case MAKE_VAR: writer.writeUTF(get(0)); break;
case OPERATION: writer.writeByte(((Operation)get(0)).numeric); break;
case PUSH_NUMBER: writer.writeDouble(get(0)); break;
case PUSH_STRING: writer.writeUTF(get(0)); break;
case STORE_SELF_FUNC: writer.writeInt(get(0)); break;
case STORE_VAR: writer.writeInt(get(0)); break;
case THROW_SYNTAX: writer.writeUTF(get(0));
case TRY_START:
writer.writeInt(get(0));
writer.writeInt(get(1));
writer.writeInt(get(2));
break;
case TYPEOF:
if (params.length > 0) writer.writeUTF(get(0));
break;
default:
}
}
private Instruction(Type type, Object ...params) {
this.type = type;
this.params = params;
}
public static Instruction read(DataInputStream stream) throws IOException {
var rawType = stream.readUnsignedByte();
var type = Type.fromNumeric(rawType & 127);
var flag = (rawType & 128) != 0;
switch (type) {
case CALL: return call(stream.readInt());
case CALL_NEW: return callNew(stream.readInt());
case DEF_PROP: return defProp();
case DELETE: return delete();
case DISCARD: return discard();
case DUP: return dup(stream.readInt());
case JMP: return jmp(stream.readInt());
case JMP_IF: return jmpIf(stream.readInt());
case JMP_IFN: return jmpIfNot(stream.readInt());
case KEYS: return keys(flag);
case LOAD_ARR: return loadArr(stream.readInt());
case LOAD_FUNC: {
var captures = new int[stream.readInt()];
for (var i = 0; i < captures.length; i++) {
captures[i] = stream.readInt();
}
return loadFunc(stream.readInt(), captures);
}
case LOAD_GLOB: return loadGlob();
case LOAD_MEMBER: return loadMember();
case LOAD_OBJ: return loadObj();
case LOAD_REGEX: return loadRegex(stream.readUTF(), null);
case LOAD_VAR: return loadVar(stream.readInt());
case MAKE_VAR: return makeVar(stream.readUTF());
case OPERATION: return operation(Operation.fromNumeric(stream.readUnsignedByte()));
case PUSH_NULL: return pushNull();
case PUSH_UNDEFINED: return pushUndefined();
case PUSH_BOOL: return pushValue(flag);
case PUSH_NUMBER: return pushValue(stream.readDouble());
case PUSH_STRING: return pushValue(stream.readUTF());
case RETURN: return ret();
case STORE_MEMBER: return storeMember(flag);
case STORE_SELF_FUNC: return storeSelfFunc(stream.readInt());
case STORE_VAR: return storeVar(stream.readInt(), flag);
case THROW: return throwInstr();
case THROW_SYNTAX: return throwSyntax(stream.readUTF());
case TRY_END: return tryEnd();
case TRY_START: return tryStart(stream.readInt(), stream.readInt(), stream.readInt());
case TYPEOF: return flag ? typeof(stream.readUTF()) : typeof();
case NOP:
if (flag) return null;
else return nop();
default: return null;
}
}
public static Instruction tryStart(int catchStart, int finallyStart, int end) {
return new Instruction(Type.TRY_START, catchStart, finallyStart, end);
}
public static Instruction tryEnd() {
return new Instruction(Type.TRY_END);
}
public static Instruction throwInstr() {
return new Instruction(Type.THROW);
}
public static Instruction throwSyntax(SyntaxException err) {
return new Instruction(Type.THROW_SYNTAX, err.getMessage());
}
public static Instruction throwSyntax(String err) {
return new Instruction(Type.THROW_SYNTAX, err);
}
public static Instruction delete() {
return new Instruction(Type.DELETE);
}
public static Instruction ret() {
return new Instruction(Type.RETURN);
}
public static Instruction debug() {
return new Instruction(Type.NOP, "debug");
}
public static Instruction nop(Object ...params) {
return new Instruction(Type.NOP, params);
}
public static Instruction call(int argn) {
return new Instruction(Type.CALL, argn);
}
public static Instruction callNew(int argn) {
return new Instruction(Type.CALL_NEW, argn);
}
public static Instruction jmp(int offset) {
return new Instruction(Type.JMP, offset);
}
public static Instruction jmpIf(int offset) {
return new Instruction(Type.JMP_IF, offset);
}
public static Instruction jmpIfNot(int offset) {
return new Instruction(Type.JMP_IFN, offset);
}
public static Instruction pushUndefined() {
return new Instruction(Type.PUSH_UNDEFINED);
}
public static Instruction pushNull() {
return new Instruction(Type.PUSH_NULL);
}
public static Instruction pushValue(boolean val) {
return new Instruction(Type.PUSH_BOOL, val);
}
public static Instruction pushValue(double val) {
return new Instruction(Type.PUSH_NUMBER, val);
}
public static Instruction pushValue(String val) {
return new Instruction(Type.PUSH_STRING, val);
}
public static Instruction makeVar(String name) {
return new Instruction(Type.MAKE_VAR, name);
}
public static Instruction loadVar(Object i) {
return new Instruction(Type.LOAD_VAR, i);
}
public static Instruction loadGlob() {
return new Instruction(Type.LOAD_GLOB);
}
public static Instruction loadMember() {
return new Instruction(Type.LOAD_MEMBER);
}
public static Instruction loadRegex(String pattern, String flags) {
return new Instruction(Type.LOAD_REGEX, pattern, flags);
}
public static Instruction loadFunc(int id, int[] captures) {
var args = new Object[1 + captures.length];
args[0] = id;
for (var i = 0; i < captures.length; i++) args[i + 1] = captures[i];
return new Instruction(Type.LOAD_FUNC, args);
}
public static Instruction loadObj() {
return new Instruction(Type.LOAD_OBJ);
}
public static Instruction loadArr(int count) {
return new Instruction(Type.LOAD_ARR, count);
}
public static Instruction dup() {
return new Instruction(Type.DUP, 1);
}
public static Instruction dup(int count) {
return new Instruction(Type.DUP, count);
}
public static Instruction storeSelfFunc(int i) {
return new Instruction(Type.STORE_SELF_FUNC, i);
}
public static Instruction storeVar(Object i) {
return new Instruction(Type.STORE_VAR, i, false);
}
public static Instruction storeVar(Object i, boolean keep) {
return new Instruction(Type.STORE_VAR, i, keep);
}
public static Instruction storeMember() {
return new Instruction(Type.STORE_MEMBER, false);
}
public static Instruction storeMember(boolean keep) {
return new Instruction(Type.STORE_MEMBER, keep);
}
public static Instruction 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 keys(boolean forInFormat) {
return new Instruction(Type.KEYS, forInFormat);
}
public static Instruction defProp() {
return new Instruction(Type.DEF_PROP);
}
public static Instruction operation(Operation op) {
return new Instruction(Type.OPERATION, op);
}
@Override
public String toString() {
var res = type.toString();
for (int i = 0; i < params.length; i++) {
res += " " + params[i];
}
return res;
}
}

View File

@@ -1,101 +0,0 @@
package me.topchetoeu.jscript.common;
import java.util.ArrayList;
public class Location implements Comparable<Location> {
public static final Location INTERNAL = new Location(-1, -1, new Filename("jscript", "native"));
private int line;
private int start;
private Filename filename;
public int line() { return line; }
public int start() { return start; }
public Filename filename() { return filename; }
@Override
public String toString() {
var res = new ArrayList<String>();
if (filename != null) res.add(filename.toString());
if (line >= 0) res.add(line + "");
if (start >= 0) res.add(start + "");
return String.join(":", res);
}
public Location add(int n, boolean clone) {
if (clone) return new Location(line, start + n, filename);
this.start += n;
return this;
}
public Location add(int n) {
return add(n, false);
}
public Location nextLine() {
line++;
start = 0;
return this;
}
public Location clone() {
return new Location(line, start, filename);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + line;
result = prime * result + start;
result = prime * result + ((filename == null) ? 0 : filename.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Location other = (Location) obj;
if (line != other.line) return false;
if (start != other.start) return false;
if (filename == null && other.filename != null) return false;
else if (!filename.equals(other.filename)) return false;
return true;
}
@Override
public int compareTo(Location other) {
int a = filename.toString().compareTo(other.filename.toString());
int b = Integer.compare(line, other.line);
int c = Integer.compare(start, other.start);
if (a != 0) return a;
if (b != 0) return b;
return c;
}
public Location(int line, int start, Filename filename) {
this.line = line;
this.start = start;
this.filename = filename;
}
public static Location parse(String raw) {
int i0 = -1, i1 = -1;
for (var i = raw.length() - 1; i >= 0; i--) {
if (raw.charAt(i) == ':') {
if (i1 == -1) i1 = i;
else if (i0 == -1) {
i0 = i;
break;
}
}
}
return new Location(
Integer.parseInt(raw.substring(i0 + 1, i1)),
Integer.parseInt(raw.substring(i1 + 1)),
Filename.parse(raw.substring(0, i0))
);
}
}

View File

@@ -1,29 +0,0 @@
package me.topchetoeu.jscript.common;
import me.topchetoeu.jscript.common.json.JSON;
public class Metadata {
private static final String VERSION;
private static final String AUTHOR;
private static final String NAME;
static {
var data = JSON.parse(null, Reading.resourceToString("metadata.json")).map();
VERSION = data.string("version");
AUTHOR = data.string("author");
NAME = data.string("name");
}
public static String version() {
if (VERSION.equals("$" + "{VERSION}")) return "1337-devel";
else return VERSION;
}
public static String author() {
if (AUTHOR.equals("$" + "{AUTHOR}")) return "anonymous";
else return AUTHOR;
}
public static String name() {
if (NAME.equals("$" + "{NAME}")) return "some-product";
else return NAME;
}
}

View File

@@ -1,54 +0,0 @@
package me.topchetoeu.jscript.common;
import java.util.HashMap;
public enum Operation {
INSTANCEOF(1, 2),
IN(2, 2),
MULTIPLY(3, 2),
DIVIDE(4, 2),
MODULO(5, 2),
ADD(6, 2),
SUBTRACT(7, 2),
USHIFT_RIGHT(8, 2),
SHIFT_RIGHT(9, 2),
SHIFT_LEFT(10, 2),
GREATER(11, 2),
LESS(12, 2),
GREATER_EQUALS(13, 2),
LESS_EQUALS(14, 2),
LOOSE_EQUALS(15, 2),
LOOSE_NOT_EQUALS(16, 2),
EQUALS(17, 2),
NOT_EQUALS(18, 2),
AND(19, 2),
OR(20, 2),
XOR(21, 2),
NEG(23, 1),
POS(24, 1),
NOT(25, 1),
INVERSE(26, 1);
private static final HashMap<Integer, Operation> operations = new HashMap<>();
static {
for (var val : Operation.values()) operations.put(val.numeric, val);
}
public final int numeric;
public final int operands;
private Operation(int numeric, int n) {
this.numeric = numeric;
this.operands = n;
}
public static Operation fromNumeric(int i) {
return operations.get(i);
}
}

View File

@@ -1,28 +0,0 @@
package me.topchetoeu.jscript.common;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
public class Reading {
private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
public static synchronized String readline() throws IOException {
return reader.readLine();
}
public static String streamToString(InputStream in) {
try {
return new String(in.readAllBytes());
}
catch (IOException e) { throw new UncheckedIOException(e); }
}
public static InputStream resourceToStream(String name) {
return Reading.class.getResourceAsStream("/" + name);
}
public static String resourceToString(String name) {
return streamToString(resourceToStream(name));
}
}

View File

@@ -1,23 +0,0 @@
package me.topchetoeu.jscript.common;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
public class RefTracker {
public static void onDestroy(Object obj, Runnable runnable) {
var queue = new ReferenceQueue<>();
var ref = new WeakReference<>(obj, queue);
obj = null;
var th = new Thread(() -> {
try {
queue.remove();
ref.get();
runnable.run();
}
catch (InterruptedException e) { return; }
});
th.setDaemon(true);
th.start();
}
}

View File

@@ -1,5 +0,0 @@
package me.topchetoeu.jscript.common;
public interface ResultRunnable<T> {
T run();
}

View File

@@ -1,31 +0,0 @@
package me.topchetoeu.jscript.common.events;
public class DataNotifier<T> {
private Notifier notifier = new Notifier();
private boolean isErr;
private T val;
private RuntimeException err;
public void error(RuntimeException t) {
err = t;
isErr = true;
notifier.next();
}
public void next(T val) {
this.val = val;
isErr = false;
notifier.next();
}
public T await() {
notifier.await();
try {
if (isErr) throw err;
else return val;
}
finally {
this.err = null;
this.val = null;
}
}
}

View File

@@ -1,19 +0,0 @@
package me.topchetoeu.jscript.common.events;
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
public class Notifier {
private boolean ok = false;
public synchronized void next() {
ok = true;
notifyAll();
}
public synchronized void await() {
try {
while (!ok) wait();
ok = false;
}
catch (InterruptedException e) { throw new InterruptException(e); }
}
}

View File

@@ -1,243 +0,0 @@
package me.topchetoeu.jscript.common.json;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.compilation.parsing.Operator;
import me.topchetoeu.jscript.compilation.parsing.ParseRes;
import me.topchetoeu.jscript.compilation.parsing.Parsing;
import me.topchetoeu.jscript.compilation.parsing.Token;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
public class JSON {
public static Object toJs(JSONElement val) {
if (val.isBoolean()) return val.bool();
if (val.isString()) return val.string();
if (val.isNumber()) return val.number();
if (val.isList()) return ArrayValue.of(null, val.list().stream().map(JSON::toJs).collect(Collectors.toList()));
if (val.isMap()) {
var res = new ObjectValue();
for (var el : val.map().entrySet()) {
res.defineProperty(null, el.getKey(), toJs(el.getValue()));
}
return res;
}
if (val.isNull()) return Values.NULL;
return null;
}
private static JSONElement fromJs(Context ctx, Object val, HashSet<Object> prev) {
if (val instanceof Boolean) return JSONElement.bool((boolean)val);
if (val instanceof Number) return JSONElement.number(((Number)val).doubleValue());
if (val instanceof String) return JSONElement.string((String)val);
if (val == Values.NULL) return JSONElement.NULL;
if (val instanceof ArrayValue) {
if (prev.contains(val)) throw new EngineException("Circular dependency in JSON.");
prev.add(val);
var res = new JSONList();
for (var el : ((ArrayValue)val).toArray()) {
var jsonEl = fromJs(ctx, el, prev);
if (jsonEl == null) jsonEl = JSONElement.NULL;
res.add(jsonEl);
}
prev.remove(val);
return JSONElement.of(res);
}
if (val instanceof ObjectValue) {
if (prev.contains(val)) throw new EngineException("Circular dependency in JSON.");
prev.add(val);
var res = new JSONMap();
for (var el : Values.getMembers(ctx, val, false, false)) {
var jsonEl = fromJs(ctx, Values.getMember(ctx, val, el), prev);
if (jsonEl == null) continue;
if (el instanceof String || el instanceof Number) res.put(el.toString(), jsonEl);
}
prev.remove(val);
return JSONElement.of(res);
}
if (val == null) return null;
return null;
}
public static JSONElement fromJs(Context ctx, Object val) {
return fromJs(ctx, val, new HashSet<>());
}
public static ParseRes<String> parseIdentifier(List<Token> tokens, int i) {
return Parsing.parseIdentifier(tokens, i);
}
public static ParseRes<String> parseString(Filename filename, List<Token> tokens, int i) {
var res = Parsing.parseString(filename, tokens, i);
if (res.isSuccess()) return ParseRes.res((String)res.result.value, res.n);
else return res.transform();
}
public static ParseRes<Double> parseNumber(Filename filename, List<Token> tokens, int i) {
var minus = Parsing.isOperator(tokens, i, Operator.SUBTRACT);
if (minus) i++;
var res = Parsing.parseNumber(filename, tokens, i);
if (res.isSuccess()) return ParseRes.res((minus ? -1 : 1) * (Double)res.result.value, res.n + (minus ? 1 : 0));
else return res.transform();
}
public static ParseRes<Boolean> parseBool(Filename filename, List<Token> tokens, int i) {
var id = parseIdentifier(tokens, i);
if (!id.isSuccess()) return ParseRes.failed();
else if (id.result.equals("true")) return ParseRes.res(true, 1);
else if (id.result.equals("false")) return ParseRes.res(false, 1);
else return ParseRes.failed();
}
public static ParseRes<?> parseValue(Filename filename, List<Token> tokens, int i) {
return ParseRes.any(
parseString(filename, tokens, i),
parseNumber(filename, tokens, i),
parseBool(filename, tokens, i),
parseMap(filename, tokens, i),
parseList(filename, tokens, i)
);
}
public static ParseRes<JSONMap> parseMap(Filename filename, List<Token> tokens, int i) {
int n = 0;
if (!Parsing.isOperator(tokens, i + n++, Operator.BRACE_OPEN)) return ParseRes.failed();
var values = new JSONMap();
while (true) {
if (Parsing.isOperator(tokens, i + n, Operator.BRACE_CLOSE)) {
n++;
break;
}
var name = ParseRes.any(
parseIdentifier(tokens, i + n),
parseString(filename, tokens, i + n),
parseNumber(filename, tokens, i + n)
);
if (!name.isSuccess()) return ParseRes.error(Parsing.getLoc(filename, tokens, i + n), "Expected an index.", name);
else n += name.n;
if (!Parsing.isOperator(tokens, i + n, Operator.COLON)) {
return ParseRes.error(Parsing.getLoc(filename, tokens, i + n), "Expected a colon.", name);
}
n++;
var res = parseValue(filename, tokens, i + n);
if (!res.isSuccess()) return ParseRes.error(Parsing.getLoc(filename, tokens, i + n), "Expected a list element.", res);
else n += res.n;
values.put(name.result.toString(), JSONElement.of(res.result));
if (Parsing.isOperator(tokens, i + n, Operator.COMMA)) n++;
else if (Parsing.isOperator(tokens, i + n, Operator.BRACE_CLOSE)) {
n++;
break;
}
}
return ParseRes.res(values, n);
}
public static ParseRes<JSONList> parseList(Filename filename, List<Token> tokens, int i) {
int n = 0;
if (!Parsing.isOperator(tokens, i + n++, Operator.BRACKET_OPEN)) return ParseRes.failed();
var values = new JSONList();
while (true) {
if (Parsing.isOperator(tokens, i + n, Operator.BRACKET_CLOSE)) {
n++;
break;
}
var res = parseValue(filename, tokens, i + n);
if (!res.isSuccess()) return ParseRes.error(Parsing.getLoc(filename, tokens, i + n), "Expected a list element.", res);
else n += res.n;
values.add(JSONElement.of(res.result));
if (Parsing.isOperator(tokens, i + n, Operator.COMMA)) n++;
else if (Parsing.isOperator(tokens, i + n, Operator.BRACKET_CLOSE)) {
n++;
break;
}
}
return ParseRes.res(values, n);
}
public static JSONElement parse(Filename filename, String raw) {
if (filename == null) filename = new Filename("jscript", "json");
var res = parseValue(filename, Parsing.tokenize(filename, raw), 0);
if (res.isFailed()) throw new SyntaxException(null, "Invalid JSON given.");
else if (res.isError()) throw new SyntaxException(null, res.error);
else return JSONElement.of(res.result);
}
public static String stringify(JSONElement el) {
if (el.isNumber()) return Double.toString(el.number());
if (el.isBoolean()) return el.bool() ? "true" : "false";
if (el.isNull()) return "null";
if (el.isString()) {
var res = new StringBuilder("\"");
var alphabet = "0123456789ABCDEF".toCharArray();
for (var c : el.string().toCharArray()) {
if (c < 32 || c >= 127) {
res
.append("\\u")
.append(alphabet[(c >> 12) & 0xF])
.append(alphabet[(c >> 8) & 0xF])
.append(alphabet[(c >> 4) & 0xF])
.append(alphabet[(c >> 0) & 0xF]);
}
else if (c == '\\')
res.append("\\\\");
else if (c == '"')
res.append("\\\"");
else res.append(c);
}
return res.append('"').toString();
}
if (el.isList()) {
var res = new StringBuilder().append("[");
for (int i = 0; i < el.list().size(); i++) {
if (i != 0) res.append(",");
res.append(stringify(el.list().get(i)));
}
res.append("]");
return res.toString();
}
if (el.isMap()) {
var res = new StringBuilder().append("{");
var entries = el.map().entrySet().stream().collect(Collectors.toList());
for (int i = 0; i < entries.size(); i++) {
if (i != 0) res.append(",");
res.append(stringify(JSONElement.string(entries.get(i).getKey())));
res.append(":");
res.append(stringify(entries.get(i).getValue()));
}
res.append("}");
return res.toString();
}
return null;
}
public static String stringify(JSONMap map) {
return stringify(JSONElement.of(map));
}
public static String stringify(JSONList list) {
return stringify(JSONElement.of(list));
}
}

View File

@@ -1,88 +0,0 @@
package me.topchetoeu.jscript.common.json;
public class JSONElement {
public static enum Type {
STRING,
NUMBER,
BOOLEAN,
NULL,
LIST,
MAP,
}
public static final JSONElement NULL = new JSONElement(Type.NULL, null);
public static JSONElement map(JSONMap val) {
return new JSONElement(Type.MAP, val);
}
public static JSONElement list(JSONList val) {
return new JSONElement(Type.LIST, val);
}
public static JSONElement string(String val) {
return new JSONElement(Type.STRING, val);
}
public static JSONElement number(double val) {
return new JSONElement(Type.NUMBER, val);
}
public static JSONElement bool(boolean val) {
return new JSONElement(Type.BOOLEAN, val);
}
public static JSONElement of(Object val) {
if (val instanceof JSONMap) return map((JSONMap)val);
else if (val instanceof JSONList) return list((JSONList)val);
else if (val instanceof String) return string((String)val);
else if (val instanceof Boolean) return bool((Boolean)val);
else if (val instanceof Number) return number(((Number)val).doubleValue());
else if (val == null) return NULL;
else throw new IllegalArgumentException("val must be: String, Boolean, Number, JSONList or JSONMap.");
}
public final Type type;
private final Object value;
public boolean isMap() { return type == Type.MAP; }
public boolean isList() { return type == Type.LIST; }
public boolean isString() { return type == Type.STRING; }
public boolean isNumber() { return type == Type.NUMBER; }
public boolean isBoolean() { return type == Type.BOOLEAN; }
public boolean isNull() { return type == Type.NULL; }
public JSONMap map() {
if (!isMap()) throw new IllegalStateException("Element is not a map.");
return (JSONMap)value;
}
public JSONList list() {
if (!isList()) throw new IllegalStateException("Element is not a map.");
return (JSONList)value;
}
public String string() {
if (!isString()) throw new IllegalStateException("Element is not a string.");
return (String)value;
}
public double number() {
if (!isNumber()) throw new IllegalStateException("Element is not a number.");
return (double)value;
}
public boolean bool() {
if (!isBoolean()) throw new IllegalStateException("Element is not a boolean.");
return (boolean)value;
}
@Override
public String toString() {
if (isMap()) return "{...}";
if (isList()) return "[...]";
if (isString()) return (String)value;
if (isString()) return (String)value;
if (isNumber()) return (double)value + "";
if (isBoolean()) return (boolean)value + "";
if (isNull()) return "null";
return "";
}
private JSONElement(Type type, Object val) {
this.type = type;
this.value = val;
}
}

View File

@@ -1,26 +0,0 @@
package me.topchetoeu.jscript.common.json;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class JSONList extends ArrayList<JSONElement> {
public JSONList() {}
public JSONList(JSONElement ...els) {
super(List.of(els));
}
public JSONList(Collection<JSONElement> els) {
super(els);
}
public JSONList addNull() { this.add(JSONElement.NULL); return this; }
public JSONList add(String val) { this.add(JSONElement.of(val)); return this; }
public JSONList add(double val) { this.add(JSONElement.of(val)); return this; }
public JSONList add(boolean val) { this.add(JSONElement.of(val)); return this; }
public JSONList add(Map<String, JSONElement> val) { this.add(JSONElement.of(val)); return this; }
public JSONList add(Collection<JSONElement> val) { this.add(JSONElement.of(val)); return this; }
public JSONList add(JSONMap val) { this.add(JSONElement.of(val)); return this; }
public JSONList add(JSONList val) { this.add(JSONElement.of(val)); return this; }
}

View File

@@ -1,150 +0,0 @@
package me.topchetoeu.jscript.common.json;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class JSONMap implements Map<String, JSONElement> {
private Map<String, JSONElement> elements = new HashMap<>();
public JSONElement get(String path) {
var curr = this;
var segs = path.split("\\.");
var i = 0;
while (true) {
var tmp = curr.elements.get(segs[i++]);
if (i == segs.length) return tmp;
if (!tmp.isMap()) return null;
curr = tmp.map();
}
}
public boolean isMap(String path) {
var el = get(path);
return el != null && el.isMap();
}
public boolean isList(String path) {
var el = get(path);
return el != null && el.isList();
}
public boolean isString(String path) {
var el = get(path);
return el != null && el.isString();
}
public boolean isNumber(String path) {
var el = get(path);
return el != null && el.isNumber();
}
public boolean isBoolean(String path) {
var el = get(path);
return el != null && el.isBoolean();
}
public boolean isNull(String path) {
var el = get(path);
return el != null && el.isNull();
}
public boolean contains(String path) {
return get(path) != null;
}
public JSONMap map(String path) {
var el = get(path);
if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist.", path));
return el.map();
}
public JSONMap map(String path, JSONMap defaultVal) {
var el = get(path);
if (el == null) return defaultVal;
if (el.isMap()) return el.map();
return defaultVal;
}
public JSONList list(String path) {
var el = get(path);
if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist.", path));
return el.list();
}
public JSONList list(String path, JSONList defaultVal) {
var el = get(path);
if (el == null) return defaultVal;
if (el.isList()) return el.list();
return defaultVal;
}
public String string(String path) {
var el = get(path);
if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist.", path));
return el.string();
}
public String string(String path, String defaultVal) {
var el = get(path);
if (el == null) return defaultVal;
if (el.isString()) return el.string();
return defaultVal;
}
public double number(String path) {
var el = get(path);
if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist.", path));
return el.number();
}
public double number(String path, double defaultVal) {
var el = get(path);
if (el == null) return defaultVal;
if (el.isNumber()) return el.number();
return defaultVal;
}
public boolean bool(String path) {
var el = get(path);
if (el == null) throw new RuntimeException(String.format("'%s' doesn't exist.", path));
return el.bool();
}
public boolean bool(String path, boolean defaultVal) {
var el = get(path);
if (el == null) return defaultVal;
if (el.isBoolean()) return el.bool();
return defaultVal;
}
public JSONMap setNull(String key) { elements.put(key, JSONElement.NULL); return this; }
public JSONMap set(String key, String val) { elements.put(key, JSONElement.of(val)); return this; }
public JSONMap set(String key, double val) { elements.put(key, JSONElement.of(val)); return this; }
public JSONMap set(String key, boolean val) { elements.put(key, JSONElement.of(val)); return this; }
public JSONMap set(String key, Map<String, JSONElement> val) { elements.put(key, JSONElement.of(val)); return this; }
public JSONMap set(String key, Collection<JSONElement> val) { elements.put(key, JSONElement.of(val)); return this; }
@Override
public int size() { return elements.size(); }
@Override
public boolean isEmpty() { return elements.isEmpty(); }
@Override
public boolean containsKey(Object key) { return elements.containsKey(key); }
@Override
public boolean containsValue(Object value) { return elements.containsValue(value); }
@Override
public JSONElement get(Object key) { return elements.get(key); }
@Override
public JSONElement put(String key, JSONElement value) { return elements.put(key, value); }
@Override
public JSONElement remove(Object key) { return elements.remove(key); }
@Override
public void putAll(Map<? extends String, ? extends JSONElement> m) { elements.putAll(m); }
@Override
public void clear() { elements.clear(); }
@Override
public Set<String> keySet() { return elements.keySet(); }
@Override
public Collection<JSONElement> values() { return elements.values(); }
@Override
public Set<Entry<String, JSONElement>> entrySet() { return elements.entrySet(); }
public JSONMap() { }
public JSONMap(Map<String, JSONElement> els) {
this.elements = new HashMap<>(els);
}
}

View File

@@ -1,8 +0,0 @@
package me.topchetoeu.jscript.common.mapping;
public enum ConvertType {
Exact,
Lower,
Upper,
Both,
}

View File

@@ -1,190 +0,0 @@
package me.topchetoeu.jscript.common.mapping;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Objects;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.scope.LocalScopeRecord;
import me.topchetoeu.jscript.utils.mapping.SourceMap;
public class FunctionMap {
public static class FunctionMapBuilder {
private final TreeMap<Integer, Location> sourceMap = new TreeMap<>();
private final HashMap<Location, BreakpointType> breakpoints = new HashMap<>();
public Location toLocation(int pc) {
return sourceMap.headMap(pc, true).firstEntry().getValue();
}
public FunctionMapBuilder setDebug(Location loc, BreakpointType type) {
if (loc == null || type == null || type == BreakpointType.NONE) return this;
breakpoints.put(loc, type);
return this;
}
public FunctionMapBuilder setLocation(int i, Location loc) {
if (loc == null || i < 0) return this;
sourceMap.put(i, loc);
return this;
}
public FunctionMapBuilder setLocationAndDebug(int i, Location loc, BreakpointType type) {
setDebug(loc, type);
setLocation(i, loc);
return this;
}
public Location first() {
if (sourceMap.size() == 0) return null;
return sourceMap.firstEntry().getValue();
}
public Location last() {
if (sourceMap.size() == 0) return null;
return sourceMap.lastEntry().getValue();
}
public FunctionMap build(String[] localNames, String[] captureNames) {
return new FunctionMap(sourceMap, breakpoints, localNames, captureNames);
}
public FunctionMap build(LocalScopeRecord scope) {
return new FunctionMap(sourceMap, breakpoints, scope.locals(), scope.captures());
}
public FunctionMap build() {
return new FunctionMap(sourceMap, breakpoints, new String[0], new String[0]);
}
private FunctionMapBuilder() { }
}
public static final FunctionMap EMPTY = new FunctionMap();
private final HashMap<Integer, BreakpointType> bps = new HashMap<>();
private final HashMap<Filename, TreeSet<Location>> bpLocs = new HashMap<>();
private final TreeMap<Integer, Location> pcToLoc = new TreeMap<>();
public final String[] localNames, captureNames;
public Location toLocation(int pc, boolean approxiamte) {
if (pcToLoc.size() == 0 || pc < 0 || pc > pcToLoc.lastKey()) return null;
var res = pcToLoc.get(pc);
if (!approxiamte || res != null) return res;
var entry = pcToLoc.headMap(pc, true).lastEntry();
if (entry == null) return null;
else return entry.getValue();
}
public Location toLocation(int pc) {
return toLocation(pc, false);
}
public BreakpointType getBreakpoint(int pc) {
return bps.getOrDefault(pc, BreakpointType.NONE);
}
public Location correctBreakpoint(Location loc) {
var set = bpLocs.get(loc.filename());
if (set == null) return null;
else return set.ceiling(loc);
}
public List<Location> correctBreakpoint(Pattern filename, int line, int column) {
var candidates = new HashMap<Filename, TreeSet<Location>>();
for (var name : bpLocs.keySet()) {
if (filename.matcher(name.toString()).matches()) {
candidates.put(name, bpLocs.get(name));
}
}
var res = new ArrayList<Location>(candidates.size());
for (var candidate : candidates.entrySet()) {
res.add(candidate.getValue().ceiling(new Location(line, column, candidate.getKey())));
}
return res;
}
public List<Location> breakpoints(Location start, Location end) {
if (!Objects.equals(start.filename(), end.filename())) return List.of();
NavigableSet<Location> set = bpLocs.get(start.filename());
if (set == null) return List.of();
if (start != null) set = set.tailSet(start, true);
if (end != null) set = set.headSet(end, true);
return set.stream().collect(Collectors.toList());
}
public Location start() {
if (pcToLoc.size() == 0) return null;
return pcToLoc.firstEntry().getValue();
}
public Location end() {
if (pcToLoc.size() == 0) return null;
return pcToLoc.lastEntry().getValue();
}
public FunctionMap apply(SourceMap map) {
var res = new FunctionMap(Map.of(), Map.of(), localNames, captureNames);
for (var el : pcToLoc.entrySet()) {
res.pcToLoc.put(el.getKey(), map.toCompiled(el.getValue()));
}
res.bps.putAll(bps);
for (var el : bpLocs.entrySet()) {
for (var loc : el.getValue()) {
loc = map.toCompiled(loc);
if (loc == null) continue;
if (!res.bpLocs.containsKey(loc.filename())) res.bpLocs.put(loc.filename(), new TreeSet<>());
res.bpLocs.get(loc.filename()).add(loc);
}
}
return res;
}
public FunctionMap clone() {
var res = new FunctionMap(Map.of(), Map.of(), localNames, captureNames);
res.pcToLoc.putAll(this.pcToLoc);
res.bps.putAll(bps);
res.bpLocs.putAll(bpLocs);
res.pcToLoc.putAll(pcToLoc);
return res;
}
public FunctionMap(Map<Integer, Location> map, Map<Location, BreakpointType> breakpoints, String[] localNames, String[] captureNames) {
var locToPc = new HashMap<Location, Integer>();
for (var el : map.entrySet()) {
pcToLoc.put(el.getKey(), el.getValue());
locToPc.putIfAbsent(el.getValue(), el.getKey());
}
for (var el : breakpoints.entrySet()) {
if (el.getValue() == null || el.getValue() == BreakpointType.NONE) continue;
bps.put(locToPc.get(el.getKey()), el.getValue());
if (!bpLocs.containsKey(el.getKey().filename())) bpLocs.put(el.getKey().filename(), new TreeSet<>());
bpLocs.get(el.getKey().filename()).add(el.getKey());
}
this.localNames = localNames;
this.captureNames = captureNames;
}
private FunctionMap() {
localNames = new String[0];
captureNames = new String[0];
}
public static FunctionMapBuilder builder() {
return new FunctionMapBuilder();
}
}

View File

@@ -1,12 +0,0 @@
package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
public abstract class AssignableStatement extends Statement {
public abstract Statement toAssign(Statement val, Operation operation);
protected AssignableStatement(Location loc) {
super(loc);
}
}

View File

@@ -1,78 +0,0 @@
package me.topchetoeu.jscript.compilation;
import java.util.List;
import java.util.LinkedList;
import java.util.Vector;
import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.mapping.FunctionMap;
import me.topchetoeu.jscript.common.mapping.FunctionMap.FunctionMapBuilder;
import me.topchetoeu.jscript.compilation.scope.LocalScopeRecord;
public class CompileResult {
public final Vector<Instruction> instructions = new Vector<>();
public final List<CompileResult> children = new LinkedList<>();
public final FunctionMapBuilder map = FunctionMap.builder();
public final LocalScopeRecord scope;
public int length = 0;
public int temp() {
instructions.add(null);
return instructions.size() - 1;
}
public CompileResult add(Instruction instr) {
instructions.add(instr);
return this;
}
public CompileResult set(int i, Instruction instr) {
instructions.set(i, instr);
return this;
}
public Instruction get(int i) {
return instructions.get(i);
}
public int size() { return instructions.size(); }
public void setDebug(Location loc, BreakpointType type) {
map.setDebug(loc, type);
}
public void setLocation(int i, Location loc) {
map.setLocation(i, loc);
}
public void setLocationAndDebug(int i, Location loc, BreakpointType type) {
map.setLocationAndDebug(i, loc, type);
}
public void setDebug(BreakpointType type) {
setDebug(map.last(), type);
}
public void setLocation(Location type) {
setLocation(instructions.size() - 1, type);
}
public void setLocationAndDebug(Location loc, BreakpointType type) {
setLocationAndDebug(instructions.size() - 1, loc, type);
}
public CompileResult addChild(CompileResult child) {
this.children.add(child);
return child;
}
public FunctionMap map() {
return map.build(scope);
}
public FunctionBody body() {
var builtChildren = new FunctionBody[children.size()];
for (var i = 0; i < children.size(); i++) builtChildren[i] = children.get(i).body();
return new FunctionBody(scope.localsCount(), length, instructions.toArray(Instruction[]::new), builtChildren);
}
public CompileResult(LocalScopeRecord scope) {
this.scope = scope;
}
}

View File

@@ -1,64 +0,0 @@
package me.topchetoeu.jscript.compilation;
import java.util.List;
import java.util.Vector;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.values.FunctionStatement;
public class CompoundStatement extends Statement {
public final Statement[] statements;
public final boolean separateFuncs;
public Location end;
@Override public boolean pure() {
for (var stm : statements) {
if (!stm.pure()) return false;
}
return true;
}
@Override
public void declare(CompileResult target) {
for (var stm : statements) stm.declare(target);
}
@Override
public void compile(CompileResult target, boolean pollute, BreakpointType type) {
List<Statement> statements = new Vector<Statement>();
if (separateFuncs) for (var stm : this.statements) {
if (stm instanceof FunctionStatement && ((FunctionStatement)stm).statement) {
stm.compile(target, false);
}
else statements.add(stm);
}
else statements = List.of(this.statements);
var polluted = false;
for (var i = 0; i < statements.size(); i++) {
var stm = statements.get(i);
if (i != statements.size() - 1) stm.compile(target, false, BreakpointType.STEP_OVER);
else stm.compile(target, polluted = pollute, BreakpointType.STEP_OVER);
}
if (!polluted && pollute) {
target.add(Instruction.pushUndefined());
}
}
public CompoundStatement setEnd(Location loc) {
this.end = loc;
return this;
}
public CompoundStatement(Location loc, boolean separateFuncs, Statement ...statements) {
super(loc);
this.separateFuncs = separateFuncs;
this.statements = statements;
}
}

View File

@@ -1,27 +0,0 @@
package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
public abstract class Statement {
private Location _loc;
public boolean pure() { return false; }
public void declare(CompileResult target) { }
public void compile(CompileResult target, boolean pollute, BreakpointType type) {
int start = target.size();
compile(target, pollute);
if (target.size() != start) target.setLocationAndDebug(start, loc(), type);
}
public void compile(CompileResult target, boolean pollute) {
compile(target, pollute, BreakpointType.NONE);
}
public Location loc() { return _loc; }
public void setLoc(Location loc) { _loc = loc; }
protected Statement(Location loc) {
this._loc = loc;
}
}

View File

@@ -1,18 +0,0 @@
package me.topchetoeu.jscript.compilation;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
public class ThrowSyntaxStatement extends Statement {
public final String name;
@Override
public void compile(CompileResult target, boolean pollute) {
target.add(Instruction.throwSyntax(name));
}
public ThrowSyntaxStatement(SyntaxException e) {
super(e.loc);
this.name = e.msg;
}
}

View File

@@ -1,52 +0,0 @@
package me.topchetoeu.jscript.compilation;
import java.util.List;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.values.FunctionStatement;
public class VariableDeclareStatement extends Statement {
public static class Pair {
public final String name;
public final Statement value;
public final Location location;
public Pair(String name, Statement value, Location location) {
this.name = name;
this.value = value;
this.location = location;
}
}
public final List<Pair> values;
@Override
public void declare(CompileResult target) {
for (var key : values) {
target.scope.define(key.name);
}
}
@Override
public void compile(CompileResult target, boolean pollute) {
for (var entry : values) {
if (entry.name == null) continue;
var key = target.scope.getKey(entry.name);
if (key instanceof String) target.add(Instruction.makeVar((String)key));
if (entry.value != null) {
FunctionStatement.compileWithName(entry.value, target, true, entry.name, BreakpointType.STEP_OVER);
target.add(Instruction.storeVar(key));
}
}
if (pollute) target.add(Instruction.pushUndefined());
}
public VariableDeclareStatement(Location loc, List<Pair> values) {
super(loc);
this.values = values;
}
}

View File

@@ -1,21 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class BreakStatement extends Statement {
public final String label;
@Override
public void compile(CompileResult target, boolean pollute) {
target.add(Instruction.nop("break", label));
if (pollute) target.add(Instruction.pushUndefined());
}
public BreakStatement(Location loc, String label) {
super(loc);
this.label = label;
}
}

View File

@@ -1,21 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ContinueStatement extends Statement {
public final String label;
@Override
public void compile(CompileResult target, boolean pollute) {
target.add(Instruction.nop(loc(), "cont", label));
if (pollute) target.add(Instruction.pushUndefined());
}
public ContinueStatement(Location loc, String label) {
super(loc);
this.label = label;
}
}

View File

@@ -1,18 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class DebugStatement extends Statement {
@Override
public void compile(CompileResult target, boolean pollute) {
target.add(Instruction.debug());
if (pollute) target.add(Instruction.pushUndefined());
}
public DebugStatement(Location loc) {
super(loc);
}
}

View File

@@ -1,26 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class DeleteStatement extends Statement {
public final Statement key;
public final Statement value;
@Override
public void compile(CompileResult target, boolean pollute) {
value.compile(target, true);
key.compile(target, true);
target.add(Instruction.delete());
if (pollute) target.add(Instruction.pushValue(true));
}
public DeleteStatement(Location loc, Statement key, Statement value) {
super(loc);
this.key = key;
this.value = value;
}
}

View File

@@ -1,36 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class DoWhileStatement extends Statement {
public final Statement condition, body;
public final String label;
@Override
public void declare(CompileResult target) {
body.declare(target);
}
@Override
public void compile(CompileResult target, boolean pollute) {
int start = target.size();
body.compile(target, false, BreakpointType.STEP_OVER);
int mid = target.size();
condition.compile(target, true, BreakpointType.STEP_OVER);
int end = target.size();
WhileStatement.replaceBreaks(target, label, start, mid - 1, mid, end + 1);
target.add(Instruction.jmpIf(start - end));
}
public DoWhileStatement(Location loc, String label, Statement condition, Statement body) {
super(loc);
this.label = label;
this.condition = condition;
this.body = body;
}
}

View File

@@ -1,69 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ForInStatement extends Statement {
public final String varName;
public final boolean isDeclaration;
public final Statement varValue, object, body;
public final String label;
public final Location varLocation;
@Override
public void declare(CompileResult target) {
body.declare(target);
if (isDeclaration) target.scope.define(varName);
}
@Override
public void compile(CompileResult target, boolean pollute) {
var key = target.scope.getKey(varName);
if (key instanceof String) target.add(Instruction.makeVar((String)key));
if (varValue != null) {
varValue.compile(target, true);
target.add(Instruction.storeVar(target.scope.getKey(varName)));
}
object.compile(target, true, BreakpointType.STEP_OVER);
target.add(Instruction.keys(true));
int start = target.size();
target.add(Instruction.dup());
target.add(Instruction.pushUndefined());
target.add(Instruction.operation(Operation.EQUALS));
int mid = target.temp();
target.add(Instruction.pushValue("value")).setLocation(varLocation);
target.add(Instruction.loadMember()).setLocation(varLocation);
target.add(Instruction.storeVar(key)).setLocationAndDebug(object.loc(), BreakpointType.STEP_OVER);
body.compile(target, false, BreakpointType.STEP_OVER);
int end = target.size();
WhileStatement.replaceBreaks(target, label, mid + 1, end, start, end + 1);
target.add(Instruction.jmp(start - end));
target.add(Instruction.discard());
target.set(mid, Instruction.jmpIf(end - mid + 1));
if (pollute) target.add(Instruction.pushUndefined());
}
public ForInStatement(Location loc, Location varLocation, String label, boolean isDecl, String varName, Statement varValue, Statement object, Statement body) {
super(loc);
this.varLocation = varLocation;
this.label = label;
this.isDeclaration = isDecl;
this.varName = varName;
this.varValue = varValue;
this.object = object;
this.body = body;
}
}

View File

@@ -1,73 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ForOfStatement extends Statement {
public final String varName;
public final boolean isDeclaration;
public final Statement iterable, body;
public final String label;
public final Location varLocation;
@Override
public void declare(CompileResult target) {
body.declare(target);
if (isDeclaration) target.scope.define(varName);
}
@Override
public void compile(CompileResult target, boolean pollute) {
var key = target.scope.getKey(varName);
if (key instanceof String) target.add(Instruction.makeVar((String)key));
iterable.compile(target, true, BreakpointType.STEP_OVER);
target.add(Instruction.dup());
target.add(Instruction.loadVar("Symbol"));
target.add(Instruction.pushValue("iterator"));
target.add(Instruction.loadMember()).setLocation(iterable.loc());
target.add(Instruction.loadMember()).setLocation(iterable.loc());
target.add(Instruction.call(0)).setLocation(iterable.loc());
int start = target.size();
target.add(Instruction.dup());
target.add(Instruction.dup());
target.add(Instruction.pushValue("next"));
target.add(Instruction.loadMember()).setLocation(iterable.loc());
target.add(Instruction.call(0)).setLocation(iterable.loc());
target.add(Instruction.dup());
target.add(Instruction.pushValue("done"));
target.add(Instruction.loadMember()).setLocation(iterable.loc());
int mid = target.temp();
target.add(Instruction.pushValue("value"));
target.add(Instruction.loadMember()).setLocation(varLocation);
target.add(Instruction.storeVar(key)).setLocationAndDebug(iterable.loc(), BreakpointType.STEP_OVER);
body.compile(target, false, BreakpointType.STEP_OVER);
int end = target.size();
WhileStatement.replaceBreaks(target, label, mid + 1, end, start, end + 1);
target.add(Instruction.jmp(start - end));
target.add(Instruction.discard());
target.add(Instruction.discard());
target.set(mid, Instruction.jmpIf(end - mid + 1));
if (pollute) target.add(Instruction.pushUndefined());
}
public ForOfStatement(Location loc, Location varLocation, String label, boolean isDecl, String varName, Statement object, Statement body) {
super(loc);
this.varLocation = varLocation;
this.label = label;
this.isDeclaration = isDecl;
this.varName = varName;
this.iterable = object;
this.body = body;
}
}

View File

@@ -1,45 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ForStatement extends Statement {
public final Statement declaration, assignment, condition, body;
public final String label;
@Override
public void declare(CompileResult target) {
declaration.declare(target);
body.declare(target);
}
@Override
public void compile(CompileResult target, boolean pollute) {
declaration.compile(target, false, BreakpointType.STEP_OVER);
int start = target.size();
condition.compile(target, true, BreakpointType.STEP_OVER);
int mid = target.temp();
body.compile(target, false, BreakpointType.STEP_OVER);
int beforeAssign = target.size();
assignment.compile(target, false, BreakpointType.STEP_OVER);
int end = target.size();
WhileStatement.replaceBreaks(target, label, mid + 1, end, beforeAssign, end + 1);
target.add(Instruction.jmp(start - end));
target.set(mid, Instruction.jmpIfNot(end - mid + 1));
if (pollute) target.add(Instruction.pushUndefined());
}
public ForStatement(Location loc, String label, Statement declaration, Statement condition, Statement assignment, Statement body) {
super(loc);
this.label = label;
this.declaration = declaration;
this.condition = condition;
this.assignment = assignment;
this.body = body;
}
}

View File

@@ -1,48 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class IfStatement extends Statement {
public final Statement condition, body, elseBody;
@Override
public void declare(CompileResult target) {
body.declare(target);
if (elseBody != null) elseBody.declare(target);
}
@Override public void compile(CompileResult target, boolean pollute, BreakpointType breakpoint) {
condition.compile(target, true, breakpoint);
if (elseBody == null) {
int i = target.temp();
body.compile(target, pollute, breakpoint);
int endI = target.size();
target.set(i, Instruction.jmpIfNot(endI - i));
}
else {
int start = target.temp();
body.compile(target, pollute, breakpoint);
int mid = target.temp();
elseBody.compile(target, pollute, breakpoint);
int end = target.size();
target.set(start, Instruction.jmpIfNot(mid - start + 1));
target.set(mid, Instruction.jmp(end - mid));
}
}
@Override public void compile(CompileResult target, boolean pollute) {
compile(target, pollute, BreakpointType.STEP_IN);
}
public IfStatement(Location loc, Statement condition, Statement body, Statement elseBody) {
super(loc);
this.condition = condition;
this.body = body;
this.elseBody = elseBody;
}
}

View File

@@ -1,22 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ReturnStatement extends Statement {
public final Statement value;
@Override
public void compile(CompileResult target, boolean pollute) {
if (value == null) target.add(Instruction.pushUndefined());
else value.compile(target, true);
target.add(Instruction.ret()).setLocation(loc());
}
public ReturnStatement(Location loc, Statement value) {
super(loc);
this.value = value;
}
}

View File

@@ -1,83 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import java.util.HashMap;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.Instruction.Type;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class SwitchStatement extends Statement {
public static class SwitchCase {
public final Statement value;
public final int statementI;
public SwitchCase(Statement value, int statementI) {
this.value = value;
this.statementI = statementI;
}
}
public final Statement value;
public final SwitchCase[] cases;
public final Statement[] body;
public final int defaultI;
@Override
public void declare(CompileResult target) {
for (var stm : body) stm.declare(target);
}
@Override
public void compile(CompileResult target, boolean pollute) {
var caseToStatement = new HashMap<Integer, Integer>();
var statementToIndex = new HashMap<Integer, Integer>();
value.compile(target, true, BreakpointType.STEP_OVER);
for (var ccase : cases) {
target.add(Instruction.dup());
ccase.value.compile(target, true);
target.add(Instruction.operation(Operation.EQUALS));
caseToStatement.put(target.temp(), ccase.statementI);
}
int start = target.temp();
for (var stm : body) {
statementToIndex.put(statementToIndex.size(), target.size());
stm.compile(target, false, BreakpointType.STEP_OVER);
}
int end = target.size();
target.add(Instruction.discard());
if (pollute) target.add(Instruction.pushUndefined());
if (defaultI < 0 || defaultI >= body.length) target.set(start, Instruction.jmp(end - start));
else target.set(start, Instruction.jmp(statementToIndex.get(defaultI) - start));
for (int i = start; i < end; i++) {
var instr = target.get(i);
if (instr.type == Type.NOP && instr.is(0, "break") && instr.get(1) == null) {
target.set(i, Instruction.jmp(end - i));
}
}
for (var el : caseToStatement.entrySet()) {
var i = statementToIndex.get(el.getValue());
if (i == null) i = end;
target.set(el.getKey(), Instruction.jmpIf(i - el.getKey()));
}
}
public SwitchStatement(Location loc, Statement value, int defaultI, SwitchCase[] cases, Statement[] body) {
super(loc);
this.value = value;
this.defaultI = defaultI;
this.cases = cases;
this.body = body;
}
}

View File

@@ -1,21 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ThrowStatement extends Statement {
public final Statement value;
@Override
public void compile(CompileResult target, boolean pollute) {
value.compile(target, true);
target.add(Instruction.throwInstr()).setLocation(loc());
}
public ThrowStatement(Location loc, Statement value) {
super(loc);
this.value = value;
}
}

View File

@@ -1,58 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class TryStatement extends Statement {
public final Statement tryBody;
public final Statement catchBody;
public final Statement finallyBody;
public final String name;
@Override
public void declare(CompileResult target) {
tryBody.declare(target);
if (catchBody != null) catchBody.declare(target);
if (finallyBody != null) finallyBody.declare(target);
}
@Override
public void compile(CompileResult target, boolean pollute, BreakpointType bpt) {
int replace = target.temp();
int start = replace + 1, catchStart = -1, finallyStart = -1;
tryBody.compile(target, false);
target.add(Instruction.tryEnd());
if (catchBody != null) {
catchStart = target.size() - start;
target.scope.define(name, true);
catchBody.compile(target, false);
target.scope.undefine();
target.add(Instruction.tryEnd());
}
if (finallyBody != null) {
finallyStart = target.size() - start;
finallyBody.compile(target, false);
target.add(Instruction.tryEnd());
}
target.set(replace, Instruction.tryStart(catchStart, finallyStart, target.size() - start));
target.setLocationAndDebug(replace, loc(), BreakpointType.STEP_OVER);
if (pollute) target.add(Instruction.pushUndefined());
}
public TryStatement(Location loc, Statement tryBody, Statement catchBody, Statement finallyBody, String name) {
super(loc);
this.tryBody = tryBody;
this.catchBody = catchBody;
this.finallyBody = finallyBody;
this.name = name;
}
}

View File

@@ -1,52 +0,0 @@
package me.topchetoeu.jscript.compilation.control;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.Instruction.Type;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class WhileStatement extends Statement {
public final Statement condition, body;
public final String label;
@Override
public void declare(CompileResult target) {
body.declare(target);
}
@Override
public void compile(CompileResult target, boolean pollute) {
int start = target.size();
condition.compile(target, true);
int mid = target.temp();
body.compile(target, false, BreakpointType.STEP_OVER);
int end = target.size();
replaceBreaks(target, label, mid + 1, end, start, end + 1);
target.add(Instruction.jmp(start - end));
target.set(mid, Instruction.jmpIfNot(end - mid + 1));
if (pollute) target.add(Instruction.pushUndefined());
}
public WhileStatement(Location loc, String label, Statement condition, Statement body) {
super(loc);
this.label = label;
this.condition = condition;
this.body = body;
}
public static void replaceBreaks(CompileResult target, String label, int start, int end, int continuePoint, int breakPoint) {
for (int i = start; i < end; i++) {
var instr = target.get(i);
if (instr.type == Type.NOP && instr.is(0, "cont") && (instr.get(1) == null || instr.is(1, label))) {
target.set(i, Instruction.jmp(continuePoint - i));
}
if (instr.type == Type.NOP && instr.is(0, "break") && (instr.get(1) == null || instr.is(1, label))) {
target.set(i, Instruction.jmp(breakPoint - i));
}
}
}
}

View File

@@ -1,113 +0,0 @@
package me.topchetoeu.jscript.compilation.parsing;
import java.util.HashMap;
import java.util.Map;
import me.topchetoeu.jscript.common.Operation;
public enum Operator {
MULTIPLY("*", Operation.MULTIPLY, 13),
DIVIDE("/", Operation.DIVIDE, 12),
MODULO("%", Operation.MODULO, 12),
SUBTRACT("-", Operation.SUBTRACT, 11),
ADD("+", Operation.ADD, 11),
SHIFT_RIGHT(">>", Operation.SHIFT_RIGHT, 10),
SHIFT_LEFT("<<", Operation.SHIFT_LEFT, 10),
USHIFT_RIGHT(">>>", Operation.USHIFT_RIGHT, 10),
GREATER(">", Operation.GREATER, 9),
LESS("<", Operation.LESS, 9),
GREATER_EQUALS(">=", Operation.GREATER_EQUALS, 9),
LESS_EQUALS("<=", Operation.LESS_EQUALS, 9),
NOT_EQUALS("!=", Operation.LOOSE_NOT_EQUALS, 8),
LOOSE_NOT_EQUALS("!==", Operation.NOT_EQUALS, 8),
EQUALS("==", Operation.LOOSE_EQUALS, 8),
LOOSE_EQUALS("===", Operation.EQUALS, 8),
AND("&", Operation.AND, 7),
XOR("^", Operation.XOR, 6),
OR("|", Operation.OR, 5),
LAZY_AND("&&", 4),
LAZY_OR("||", 3),
ASSIGN_SHIFT_LEFT("<<=", 2, true),
ASSIGN_SHIFT_RIGHT(">>=", 2, true),
ASSIGN_USHIFT_RIGHT(">>>=", 2, true),
ASSIGN_AND("&=", 2, true),
ASSIGN_OR("|=", 2, true),
ASSIGN_XOR("^=", 2, true),
ASSIGN_MODULO("%=", 2, true),
ASSIGN_DIVIDE("/=", 2, true),
ASSIGN_MULTIPLY("*=", 2, true),
ASSIGN_SUBTRACT("-=", 2, true),
ASSIGN_ADD("+=", 2, true),
ASSIGN("=", 2, true),
SEMICOLON(";"),
COLON(":"),
PAREN_OPEN("("),
PAREN_CLOSE(")"),
BRACKET_OPEN("["),
BRACKET_CLOSE("]"),
BRACE_OPEN("{"),
BRACE_CLOSE("}"),
DOT("."),
COMMA(","),
NOT("!"),
QUESTION("?"),
INVERSE("~"),
INCREASE("++"),
DECREASE("--");
public final String readable;
public final Operation operation;
public final int precedence;
public final boolean reverse;
private static final Map<String, Operator> ops = new HashMap<>();
static {
for (var el : Operator.values()) {
ops.put(el.readable, el);
}
}
public boolean isAssign() { return precedence == 2; }
public static Operator parse(String val) {
return ops.get(val);
}
private Operator() {
this.readable = null;
this.operation = null;
this.precedence = -1;
this.reverse = false;
}
private Operator(String value) {
this.readable = value;
this.operation = null;
this.precedence = -1;
this.reverse = false;
}
private Operator(String value, int precedence) {
this.readable = value;
this.operation = null;
this.precedence = precedence;
this.reverse = false;
}
private Operator(String value, int precedence, boolean reverse) {
this.readable = value;
this.operation = null;
this.precedence = precedence;
this.reverse = reverse;
}
private Operator(String value, Operation funcName, int precedence) {
this.readable = value;
this.operation = funcName;
this.precedence = precedence;
this.reverse = false;
}
private Operator(String value, Operation funcName, int precedence, boolean reverse) {
this.readable = value;
this.operation = funcName;
this.precedence = precedence;
this.reverse = reverse;
}
}

View File

@@ -1,100 +0,0 @@
package me.topchetoeu.jscript.compilation.parsing;
import java.util.List;
import java.util.Map;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.parsing.Parsing.Parser;
public class ParseRes<T> {
public static enum State {
SUCCESS,
FAILED,
ERROR;
public boolean isSuccess() { return this == SUCCESS; }
public boolean isFailed() { return this == FAILED; }
public boolean isError() { return this == ERROR; }
}
public final ParseRes.State state;
public final String error;
public final T result;
public final int n;
private ParseRes(ParseRes.State state, String error, T result, int readN) {
this.result = result;
this.n = readN;
this.state = state;
this.error = error;
}
public ParseRes<T> setN(int i) {
if (!state.isSuccess()) return this;
return new ParseRes<>(state, null, result, i);
}
public ParseRes<T> addN(int i) {
if (!state.isSuccess()) return this;
return new ParseRes<>(state, null, result, this.n + i);
}
public <T2> ParseRes<T2> transform() {
if (isSuccess()) throw new RuntimeException("Can't transform a ParseRes that hasn't failed.");
return new ParseRes<>(state, error, null, 0);
}
public TestRes toTest() {
if (isSuccess()) return TestRes.res(n);
else if (isError()) return TestRes.error(null, error);
else return TestRes.failed();
}
public boolean isSuccess() { return state.isSuccess(); }
public boolean isFailed() { return state.isFailed(); }
public boolean isError() { return state.isError(); }
public static <T> ParseRes<T> failed() {
return new ParseRes<T>(State.FAILED, null, null, 0);
}
public static <T> ParseRes<T> error(Location loc, String error) {
if (loc != null) error = loc + ": " + error;
return new ParseRes<>(State.ERROR, error, null, 0);
}
public static <T> ParseRes<T> error(Location loc, String error, ParseRes<?> other) {
if (loc != null) error = loc + ": " + error;
if (!other.isError()) return new ParseRes<>(State.ERROR, error, null, 0);
return new ParseRes<>(State.ERROR, other.error, null, 0);
}
public static <T> ParseRes<T> res(T val, int i) {
return new ParseRes<>(State.SUCCESS, null, val, i);
}
@SafeVarargs
public static <T> ParseRes<? extends T> any(ParseRes<? extends T> ...parsers) {
return any(List.of(parsers));
}
public static <T> ParseRes<? extends T> any(List<ParseRes<? extends T>> parsers) {
ParseRes<? extends T> best = null;
ParseRes<? extends T> error = ParseRes.failed();
for (var parser : parsers) {
if (parser.isSuccess()) {
if (best == null || best.n < parser.n) best = parser;
}
else if (parser.isError() && error.isFailed()) error = parser.transform();
}
if (best != null) return best;
else return error;
}
@SafeVarargs
public static <T> ParseRes<? extends T> first(String filename, List<Token> tokens, Map<String, Parser<T>> named, Parser<? extends T> ...parsers) {
ParseRes<? extends T> error = ParseRes.failed();
for (var parser : parsers) {
var res = parser.parse(null, tokens, 0);
if (res.isSuccess()) return res;
else if (res.isError() && error.isFailed()) error = res.transform();
}
return error;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +0,0 @@
package me.topchetoeu.jscript.compilation.parsing;
public class RawToken {
public final String value;
public final TokenType type;
public final int line;
public final int start;
public RawToken(String value, TokenType type, int line, int start) {
this.value = value;
this.type = type;
this.line = line;
this.start = start;
}
}

View File

@@ -1,45 +0,0 @@
package me.topchetoeu.jscript.compilation.parsing;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.parsing.ParseRes.State;
public class TestRes {
public final State state;
public final String error;
public final int i;
private TestRes(ParseRes.State state, String error, int i) {
this.i = i;
this.state = state;
this.error = error;
}
public TestRes add(int n) {
return new TestRes(state, null, this.i + n);
}
public <T> ParseRes<T> transform() {
if (isSuccess()) throw new RuntimeException("Can't transform a TestRes that hasn't failed.");
else if (isError()) return ParseRes.error(null, error);
else return ParseRes.failed();
}
public boolean isSuccess() { return state.isSuccess(); }
public boolean isFailed() { return state.isFailed(); }
public boolean isError() { return state.isError(); }
public static TestRes failed() {
return new TestRes(State.FAILED, null, 0);
}
public static TestRes error(Location loc, String error) {
if (loc != null) error = loc + ": " + error;
return new TestRes(State.ERROR, error, 0);
}
public static TestRes error(Location loc, String error, TestRes other) {
if (loc != null) error = loc + ": " + error;
if (!other.isError()) return new TestRes(State.ERROR, error, 0);
return new TestRes(State.ERROR, other.error, 0);
}
public static TestRes res(int i) {
return new TestRes(State.SUCCESS, null, i);
}
}

View File

@@ -1,58 +0,0 @@
package me.topchetoeu.jscript.compilation.parsing;
public class Token {
public final Object value;
public final String rawValue;
public final boolean isString;
public final boolean isRegex;
public final int line;
public final int start;
private Token(int line, int start, Object value, String rawValue, boolean isString, boolean isRegex) {
this.value = value;
this.rawValue = rawValue;
this.line = line;
this.start = start;
this.isString = isString;
this.isRegex = isRegex;
}
private Token(int line, int start, Object value, String rawValue) {
this.value = value;
this.rawValue = rawValue;
this.line = line;
this.start = start;
this.isString = false;
this.isRegex = false;
}
public boolean isString() { return isString; }
public boolean isRegex() { return isRegex; }
public boolean isNumber() { return value instanceof Number; }
public boolean isIdentifier() { return !isString && !isRegex && value instanceof String; }
public boolean isOperator() { return value instanceof Operator; }
public boolean isIdentifier(String lit) { return !isString && !isRegex && value.equals(lit); }
public boolean isOperator(Operator op) { return value.equals(op); }
public String string() { return (String)value; }
public String regex() { return (String)value; }
public double number() { return (double)value; }
public String identifier() { return (String)value; }
public Operator operator() { return (Operator)value; }
public static Token regex(int line, int start, String val, String rawValue) {
return new Token(line, start, val, rawValue, false, true);
}
public static Token string(int line, int start, String val, String rawValue) {
return new Token(line, start, val, rawValue, true, false);
}
public static Token number(int line, int start, double val, String rawValue) {
return new Token(line, start, val, rawValue);
}
public static Token identifier(int line, int start, String val) {
return new Token(line, start, val, val);
}
public static Token operator(int line, int start, Operator val) {
return new Token(line, start, val, val.readable);
}
}

View File

@@ -1,9 +0,0 @@
package me.topchetoeu.jscript.compilation.parsing;
enum TokenType {
REGEX,
STRING,
NUMBER,
LITERAL,
OPERATOR,
}

View File

@@ -1,77 +0,0 @@
package me.topchetoeu.jscript.compilation.scope;
import java.util.ArrayList;
public class LocalScopeRecord implements ScopeRecord {
public final LocalScopeRecord parent;
private final ArrayList<String> captures = new ArrayList<>();
private final ArrayList<String> locals = new ArrayList<>();
public String[] captures() {
return captures.toArray(String[]::new);
}
public String[] locals() {
return locals.toArray(String[]::new);
}
public LocalScopeRecord child() {
return new LocalScopeRecord(this);
}
public int localsCount() {
return locals.size();
}
public int capturesCount() {
return captures.size();
}
public int[] getCaptures() {
var buff = new int[captures.size()];
var i = 0;
for (var name : captures) {
var index = parent.getKey(name);
if (index instanceof Integer) buff[i++] = (int)index;
}
var res = new int[i];
System.arraycopy(buff, 0, res, 0, i);
return res;
}
public Object getKey(String name) {
var capI = captures.indexOf(name);
var locI = locals.lastIndexOf(name);
if (locI >= 0) return locI;
if (capI >= 0) return ~capI;
if (parent != null) {
var res = parent.getKey(name);
if (res != null && res instanceof Integer) {
captures.add(name);
return -captures.size();
}
}
return name;
}
public Object define(String name, boolean force) {
if (!force && locals.contains(name)) return locals.indexOf(name);
locals.add(name);
return locals.size() - 1;
}
public Object define(String name) {
return define(name, false);
}
public void undefine() {
locals.remove(locals.size() - 1);
}
public LocalScopeRecord() {
this.parent = null;
}
public LocalScopeRecord(LocalScopeRecord parent) {
this.parent = parent;
}
}

View File

@@ -1,7 +0,0 @@
package me.topchetoeu.jscript.compilation.scope;
public interface ScopeRecord {
public Object getKey(String name);
public Object define(String name);
public LocalScopeRecord child();
}

View File

@@ -1,40 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ArrayStatement extends Statement {
public final Statement[] statements;
@Override public boolean pure() {
for (var stm : statements) {
if (!stm.pure()) return false;
}
return true;
}
@Override
public void compile(CompileResult target, boolean pollute) {
target.add(Instruction.loadArr(statements.length));
for (var i = 0; i < statements.length; i++) {
var el = statements[i];
if (el != null) {
target.add(Instruction.dup());
target.add(Instruction.pushValue(i));
el.compile(target, true);
target.add(Instruction.storeMember());
}
}
if (!pollute) target.add(Instruction.discard());
}
public ArrayStatement(Location loc, Statement[] statements) {
super(loc);
this.statements = statements;
}
}

View File

@@ -1,43 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class CallStatement extends Statement {
public final Statement func;
public final Statement[] args;
public final boolean isNew;
@Override
public void compile(CompileResult target, boolean pollute, BreakpointType type) {
if (isNew) func.compile(target, true);
else if (func instanceof IndexStatement) {
((IndexStatement)func).compile(target, true, true);
}
else {
target.add(Instruction.pushUndefined());
func.compile(target, true);
}
for (var arg : args) arg.compile(target, true);
if (isNew) target.add(Instruction.callNew(args.length)).setLocationAndDebug(loc(), type);
else target.add(Instruction.call(args.length)).setLocationAndDebug(loc(), type);
if (!pollute) target.add(Instruction.discard());
}
@Override
public void compile(CompileResult target, boolean pollute) {
compile(target, pollute, BreakpointType.STEP_IN);
}
public CallStatement(Location loc, boolean isNew, Statement func, Statement ...args) {
super(loc);
this.isNew = isNew;
this.func = func;
this.args = args;
}
}

View File

@@ -1,31 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.compilation.AssignableStatement;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ChangeStatement extends Statement {
public final AssignableStatement value;
public final double addAmount;
public final boolean postfix;
@Override
public void compile(CompileResult target, boolean pollute) {
value.toAssign(new ConstantStatement(loc(), -addAmount), Operation.SUBTRACT).compile(target, true);
if (!pollute) target.add(Instruction.discard());
else if (postfix) {
target.add(Instruction.pushValue(addAmount));
target.add(Instruction.operation(Operation.SUBTRACT));
}
}
public ChangeStatement(Location loc, AssignableStatement value, double addAmount, boolean postfix) {
super(loc);
this.value = value;
this.addAmount = addAmount;
this.postfix = postfix;
}
}

View File

@@ -1,47 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ConstantStatement extends Statement {
public final Object value;
public final boolean isNull;
@Override public boolean pure() { return true; }
@Override
public void compile(CompileResult target, boolean pollute) {
if (pollute) {
if (isNull) target.add(Instruction.pushNull());
else if (value instanceof Double) target.add(Instruction.pushValue((Double)value));
else if (value instanceof String) target.add(Instruction.pushValue((String)value));
else if (value instanceof Boolean) target.add(Instruction.pushValue((Boolean)value));
else target.add(Instruction.pushUndefined());
}
}
private ConstantStatement(Location loc, Object val, boolean isNull) {
super(loc);
this.value = val;
this.isNull = isNull;
}
public ConstantStatement(Location loc, boolean val) {
this(loc, val, false);
}
public ConstantStatement(Location loc, String val) {
this(loc, val, false);
}
public ConstantStatement(Location loc, double val) {
this(loc, val, false);
}
public static ConstantStatement ofUndefined(Location loc) {
return new ConstantStatement(loc, null, false);
}
public static ConstantStatement ofNull(Location loc) {
return new ConstantStatement(loc, null, true);
}
}

View File

@@ -1,23 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class DiscardStatement extends Statement {
public final Statement value;
@Override public boolean pure() { return value.pure(); }
@Override
public void compile(CompileResult target, boolean pollute) {
value.compile(target, false);
if (pollute) target.add(Instruction.pushUndefined());
}
public DiscardStatement(Location loc, Statement val) {
super(loc);
this.value = val;
}
}

View File

@@ -1,127 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.common.Instruction.Type;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.CompoundStatement;
import me.topchetoeu.jscript.compilation.Statement;
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
public class FunctionStatement extends Statement {
public final CompoundStatement body;
public final String varName;
public final String[] args;
public final boolean statement;
public final Location end;
@Override public boolean pure() { return varName == null && statement; }
@Override
public void declare(CompileResult target) {
if (varName != null && statement) target.scope.define(varName);
}
public static void checkBreakAndCont(CompileResult target, int start) {
for (int i = start; i < target.size(); i++) {
if (target.get(i).type == Type.NOP) {
if (target.get(i).is(0, "break") ) {
throw new SyntaxException(target.map.toLocation(i), "Break was placed outside a loop.");
}
if (target.get(i).is(0, "cont")) {
throw new SyntaxException(target.map.toLocation(i), "Continue was placed outside a loop.");
}
}
}
}
private CompileResult compileBody(CompileResult target, boolean pollute, BreakpointType bp) {
for (var i = 0; i < args.length; i++) {
for (var j = 0; j < i; j++) {
if (args[i].equals(args[j])) {
throw new SyntaxException(loc(), "Duplicate parameter '" + args[i] + "'.");
}
}
}
var subtarget = new CompileResult(target.scope.child());
subtarget.scope.define("this");
var argsVar = subtarget.scope.define("arguments");
if (args.length > 0) {
for (var i = 0; i < args.length; i++) {
subtarget.add(Instruction.loadVar(argsVar));
subtarget.add(Instruction.pushValue(i));
subtarget.add(Instruction.loadMember());
subtarget.add(Instruction.storeVar(subtarget.scope.define(args[i])));
}
}
if (!statement && this.varName != null) {
subtarget.add(Instruction.storeSelfFunc((int)subtarget.scope.define(this.varName))).setLocationAndDebug(loc(), bp);
}
body.declare(subtarget);
body.compile(subtarget, false);
subtarget.length = args.length;
subtarget.add(Instruction.ret()).setLocation(end);
checkBreakAndCont(subtarget, 0);
if (pollute) target.add(Instruction.loadFunc(target.children.size(), subtarget.scope.getCaptures()));
return target.addChild(subtarget);
}
public void compile(CompileResult target, boolean pollute, String name, BreakpointType bp) {
if (this.varName != null) name = this.varName;
var hasVar = this.varName != null && statement;
var hasName = name != null;
compileBody(target, pollute || hasVar || hasName, bp);
if (hasName) {
if (pollute || hasVar) target.add(Instruction.dup());
target.add(Instruction.pushValue("name"));
target.add(Instruction.pushValue(name));
target.add(Instruction.storeMember());
}
if (hasVar) {
var key = target.scope.getKey(this.varName);
if (key instanceof String) target.add(Instruction.makeVar((String)key));
target.add(Instruction.storeVar(target.scope.getKey(this.varName), false));
}
}
public void compile(CompileResult target, boolean pollute, String name) {
compile(target, pollute, name, BreakpointType.NONE);
}
@Override public void compile(CompileResult target, boolean pollute, BreakpointType bp) {
compile(target, pollute, (String)null, bp);
}
@Override public void compile(CompileResult target, boolean pollute) {
compile(target, pollute, (String)null, BreakpointType.NONE);
}
public FunctionStatement(Location loc, Location end, String varName, String[] args, boolean statement, CompoundStatement body) {
super(loc);
this.end = end;
this.varName = varName;
this.statement = statement;
this.args = args;
this.body = body;
}
public static void compileWithName(Statement stm, CompileResult target, boolean pollute, String name) {
if (stm instanceof FunctionStatement) ((FunctionStatement)stm).compile(target, pollute, name);
else stm.compile(target, pollute);
}
public static void compileWithName(Statement stm, CompileResult target, boolean pollute, String name, BreakpointType bp) {
if (stm instanceof FunctionStatement) ((FunctionStatement)stm).compile(target, pollute, name, bp);
else stm.compile(target, pollute, bp);
}
}

View File

@@ -1,19 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class GlobalThisStatement extends Statement {
@Override public boolean pure() { return true; }
@Override
public void compile(CompileResult target, boolean pollute) {
if (pollute) target.add(Instruction.loadGlob());
}
public GlobalThisStatement(Location loc) {
super(loc);
}
}

View File

@@ -1,45 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class IndexAssignStatement extends Statement {
public final Statement object;
public final Statement index;
public final Statement value;
public final Operation operation;
@Override
public void compile(CompileResult target, boolean pollute) {
if (operation != null) {
object.compile(target, true);
index.compile(target, true);
target.add(Instruction.dup(2));
target.add(Instruction.loadMember());
value.compile(target, true);
target.add(Instruction.operation(operation));
target.add(Instruction.storeMember(pollute)).setLocationAndDebug(loc(), BreakpointType.STEP_IN);
}
else {
object.compile(target, true);
index.compile(target, true);
value.compile(target, true);
target.add(Instruction.storeMember(pollute)).setLocationAndDebug(loc(), BreakpointType.STEP_IN);;
}
}
public IndexAssignStatement(Location loc, Statement object, Statement index, Statement value, Operation operation) {
super(loc);
this.object = object;
this.index = index;
this.value = value;
this.operation = operation;
}
}

View File

@@ -1,37 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
import me.topchetoeu.jscript.compilation.AssignableStatement;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class IndexStatement extends AssignableStatement {
public final Statement object;
public final Statement index;
@Override
public Statement toAssign(Statement val, Operation operation) {
return new IndexAssignStatement(loc(), object, index, val, operation);
}
public void compile(CompileResult target, boolean dupObj, boolean pollute) {
object.compile(target, true);
if (dupObj) target.add(Instruction.dup());
index.compile(target, true);
target.add(Instruction.loadMember()).setLocationAndDebug(loc(), BreakpointType.STEP_IN);
if (!pollute) target.add(Instruction.discard());
}
@Override
public void compile(CompileResult target, boolean pollute) {
compile(target, false, pollute);
}
public IndexStatement(Location loc, Statement object, Statement index) {
super(loc);
this.object = object;
this.index = index;
}
}

View File

@@ -1,28 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class LazyAndStatement extends Statement {
public final Statement first, second;
@Override public boolean pure() { return first.pure() && second.pure(); }
@Override
public void compile(CompileResult target, boolean pollute) {
first.compile(target, true);
if (pollute) target.add(Instruction.dup());
int start = target.temp();
if (pollute) target.add(Instruction.discard());
second.compile(target, pollute);
target.set(start, Instruction.jmpIfNot(target.size() - start));
}
public LazyAndStatement(Location loc, Statement first, Statement second) {
super(loc);
this.first = first;
this.second = second;
}
}

View File

@@ -1,28 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class LazyOrStatement extends Statement {
public final Statement first, second;
@Override public boolean pure() { return first.pure() && second.pure(); }
@Override
public void compile(CompileResult target, boolean pollute) {
first.compile(target, true);
if (pollute) target.add(Instruction.dup());
int start = target.temp();
if (pollute) target.add(Instruction.discard());
second.compile(target, pollute);
target.set(start, Instruction.jmpIf(target.size() - start));
}
public LazyOrStatement(Location loc, Statement first, Statement second) {
super(loc);
this.first = first;
this.second = second;
}
}

View File

@@ -1,61 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import java.util.ArrayList;
import java.util.Map;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class ObjectStatement extends Statement {
public final Map<String, Statement> map;
public final Map<String, FunctionStatement> getters;
public final Map<String, FunctionStatement> setters;
@Override public boolean pure() {
for (var el : map.values()) {
if (!el.pure()) return false;
}
return true;
}
@Override
public void compile(CompileResult target, boolean pollute) {
target.add(Instruction.loadObj());
for (var el : map.entrySet()) {
target.add(Instruction.dup());
target.add(Instruction.pushValue(el.getKey()));
var val = el.getValue();
FunctionStatement.compileWithName(val, target, true, el.getKey().toString());
target.add(Instruction.storeMember());
}
var keys = new ArrayList<Object>();
keys.addAll(getters.keySet());
keys.addAll(setters.keySet());
for (var key : keys) {
target.add(Instruction.pushValue((String)key));
if (getters.containsKey(key)) getters.get(key).compile(target, true);
else target.add(Instruction.pushUndefined());
if (setters.containsKey(key)) setters.get(key).compile(target, true);
else target.add(Instruction.pushUndefined());
target.add(Instruction.defProp());
}
if (!pollute) target.add(Instruction.discard());
}
public ObjectStatement(Location loc, Map<String, Statement> map, Map<String, FunctionStatement> getters, Map<String, FunctionStatement> setters) {
super(loc);
this.map = map;
this.getters = getters;
this.setters = setters;
}
}

View File

@@ -1,36 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class OperationStatement extends Statement {
public final Statement[] args;
public final Operation operation;
@Override public boolean pure() {
for (var el : args) {
if (!el.pure()) return false;
}
return true;
}
@Override
public void compile(CompileResult target, boolean pollute) {
for (var arg : args) {
arg.compile(target, true);
}
if (pollute) target.add(Instruction.operation(operation));
else target.add(Instruction.discard());
}
public OperationStatement(Location loc, Operation operation, Statement ...args) {
super(loc);
this.operation = operation;
this.args = args;
}
}

View File

@@ -1,25 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class RegexStatement extends Statement {
public final String pattern, flags;
// Not really pure, since a function is called, but can be ignored.
@Override public boolean pure() { return true; }
@Override
public void compile(CompileResult target, boolean pollute) {
target.add(Instruction.loadRegex(pattern, flags));
if (!pollute) target.add(Instruction.discard());
}
public RegexStatement(Location loc, String pattern, String flags) {
super(loc);
this.pattern = pattern;
this.flags = flags;
}
}

View File

@@ -1,32 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class TypeofStatement extends Statement {
public final Statement value;
// Not really pure, since a variable from the global scope could be accessed,
// which could lead to code execution, that would get omitted
@Override public boolean pure() { return true; }
@Override
public void compile(CompileResult target, boolean pollute) {
if (value instanceof VariableStatement) {
var i = target.scope.getKey(((VariableStatement)value).name);
if (i instanceof String) {
target.add(Instruction.typeof((String)i));
return;
}
}
value.compile(target, pollute);
target.add(Instruction.typeof());
}
public TypeofStatement(Location loc, Statement value) {
super(loc);
this.value = value;
}
}

View File

@@ -1,37 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class VariableAssignStatement extends Statement {
public final String name;
public final Statement value;
public final Operation operation;
@Override public boolean pure() { return false; }
@Override
public void compile(CompileResult target, boolean pollute) {
var i = target.scope.getKey(name);
if (operation != null) {
target.add(Instruction.loadVar(i));
FunctionStatement.compileWithName(value, target, true, name);
target.add(Instruction.operation(operation));
target.add(Instruction.storeVar(i, pollute));
}
else {
FunctionStatement.compileWithName(value, target, true, name);
target.add(Instruction.storeVar(i, pollute));
}
}
public VariableAssignStatement(Location loc, String name, Statement val, Operation operation) {
super(loc);
this.name = name;
this.value = val;
this.operation = operation;
}
}

View File

@@ -1,22 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class VariableIndexStatement extends Statement {
public final int index;
@Override public boolean pure() { return true; }
@Override
public void compile(CompileResult target, boolean pollute) {
if (pollute) target.add(Instruction.loadVar(index));
}
public VariableIndexStatement(Location loc, int i) {
super(loc);
this.index = i;
}
}

View File

@@ -1,31 +0,0 @@
package me.topchetoeu.jscript.compilation.values;
import me.topchetoeu.jscript.common.Instruction;
import me.topchetoeu.jscript.common.Location;
import me.topchetoeu.jscript.common.Operation;
import me.topchetoeu.jscript.compilation.AssignableStatement;
import me.topchetoeu.jscript.compilation.CompileResult;
import me.topchetoeu.jscript.compilation.Statement;
public class VariableStatement extends AssignableStatement {
public final String name;
@Override public boolean pure() { return false; }
@Override
public Statement toAssign(Statement val, Operation operation) {
return new VariableAssignStatement(loc(), name, val, operation);
}
@Override
public void compile(CompileResult target, boolean pollute) {
var i = target.scope.getKey(name);
target.add(Instruction.loadVar(i));
if (!pollute) target.add(Instruction.discard());
}
public VariableStatement(Location loc, String name) {
super(loc);
this.name = name;
}
}

View File

@@ -1,456 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.Iterator;
import java.util.Stack;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.ExposeType;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Array")
public class ArrayLib {
private static int normalizeI(int len, int i, boolean clamp) {
if (i < 0) i += len;
if (clamp) {
if (i < 0) i = 0;
if (i > len) i = len;
}
return i;
}
@Expose(value = "length", type = ExposeType.GETTER)
public static int __getLength(Arguments args) {
return args.self(ArrayValue.class).size();
}
@Expose(value = "length", type = ExposeType.SETTER)
public static void __setLength(Arguments args) {
args.self(ArrayValue.class).setSize(args.getInt(0));
}
@Expose public static ObjectValue __values(Arguments args) {
return __iterator(args);
}
@Expose public static ObjectValue __keys(Arguments args) {
return Values.toJSIterator(args.ctx, () -> new Iterator<Object>() {
private int i = 0;
@Override
public boolean hasNext() {
return i < args.self(ArrayValue.class).size();
}
@Override
public Object next() {
if (!hasNext()) return null;
return i++;
}
});
}
@Expose public static ObjectValue __entries(Arguments args) {
return Values.toJSIterator(args.ctx, () -> new Iterator<Object>() {
private int i = 0;
@Override
public boolean hasNext() {
return i < args.self(ArrayValue.class).size();
}
@Override
public Object next() {
if (!hasNext()) return null;
return new ArrayValue(args.ctx, i, args.self(ArrayValue.class).get(i++));
}
});
}
@Expose(value = "@@Symbol.iterator")
public static ObjectValue __iterator(Arguments args) {
return Values.toJSIterator(args.ctx, args.self(ArrayValue.class));
}
@Expose(value = "@@Symbol.asyncIterator")
public static ObjectValue __asyncIterator(Arguments args) {
return Values.toJSAsyncIterator(args.ctx, args.self(ArrayValue.class).iterator());
}
@Expose public static ArrayValue __concat(Arguments args) {
// TODO: Fully implement with non-array spreadable objects
var arrs = args.slice(-1);
var size = 0;
for (int i = 0; i < arrs.n(); i++) {
if (arrs.get(i) instanceof ArrayValue) size += arrs.convert(i, ArrayValue.class).size();
else i++;
}
var res = new ArrayValue(size);
for (int i = 0, j = 0; i < arrs.n(); i++) {
if (arrs.get(i) instanceof ArrayValue) {
var arrEl = arrs.convert(i, ArrayValue.class);
int n = arrEl.size();
arrEl.copyTo(res, 0, j, n);
j += n;
}
else {
res.set(args.ctx, j++, arrs.get(i));
}
}
return res;
}
@Expose public static ArrayValue __sort(Arguments args) {
var arr = args.self(ArrayValue.class);
var cmp = args.convert(0, FunctionValue.class);
var defaultCmp = new NativeFunction("", _args -> {
return _args.getString(0).compareTo(_args.getString(1));
});
arr.sort((a, b) -> {
var res = Values.toNumber(args.ctx, (cmp == null ? defaultCmp : cmp).call(args.ctx, null, a, b));
if (res < 0) return -1;
if (res > 0) return 1;
return 0;
});
return arr;
}
@Expose public static ArrayValue __fill(Arguments args) {
var arr = args.self(ArrayValue.class);
var val = args.get(0);
var start = normalizeI(arr.size(), args.getInt(1, 0), true);
var end = normalizeI(arr.size(), args.getInt(2, arr.size()), true);
for (; start < end; start++) arr.set(args.ctx, start, val);
return arr;
}
@Expose public static boolean __every(Arguments args) {
var arr = args.self(ArrayValue.class);
for (var i = 0; i < arr.size(); i++) {
if (arr.has(i) && !Values.toBoolean(Values.call(
args.ctx, args.get(0), args.get(1),
arr.get(i), i, arr
))) return false;
}
return true;
}
@Expose public static boolean __some(Arguments args) {
var arr = args.self(ArrayValue.class);
for (var i = 0; i < arr.size(); i++) {
if (arr.has(i) && Values.toBoolean(Values.call(
args.ctx, args.get(0), args.get(1),
arr.get(i), i, arr
))) return true;
}
return false;
}
@Expose public static ArrayValue __filter(Arguments args) {
var arr = args.self(ArrayValue.class);
var res = new ArrayValue(arr.size());
for (int i = 0, j = 0; i < arr.size(); i++) {
if (arr.has(i) && Values.toBoolean(Values.call(
args.ctx, args.get(0), args.get(1),
arr.get(i), i, arr
))) res.set(args.ctx, j++, arr.get(i));
}
return res;
}
@Expose public static ArrayValue __map(Arguments args) {
var arr = args.self(ArrayValue.class);
var res = new ArrayValue(arr.size());
res.setSize(arr.size());
for (int i = 0; i < arr.size(); i++) {
if (arr.has(i)) res.set(args.ctx, i, Values.call(args.ctx, args.get(0), args.get(1), arr.get(i), i, arr));
}
return res;
}
@Expose public static void __forEach(Arguments args) {
var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
for (int i = 0; i < arr.size(); i++) {
if (arr.has(i)) func.call(args.ctx, thisArg, arr.get(i), i, arr);
}
}
@Expose public static Object __reduce(Arguments args) {
var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var res = args.get(1);
var i = 0;
if (args.n() < 2) {
for (; i < arr.size(); i++) {
if (arr.has(i)){
res = arr.get(i++);
break;
}
}
}
for (; i < arr.size(); i++) {
if (arr.has(i)) {
res = func.call(args.ctx, null, res, arr.get(i), i, arr);
}
}
return res;
}
@Expose public static Object __reduceRight(Arguments args) {
var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var res = args.get(1);
var i = arr.size();
if (args.n() < 2) {
while (!arr.has(i--) && i >= 0) {
res = arr.get(i);
}
}
else i--;
for (; i >= 0; i--) {
if (arr.has(i)) {
res = func.call(args.ctx, null, res, arr.get(i), i, arr);
}
}
return res;
}
@Expose public static ArrayValue __flat(Arguments args) {
var arr = args.self(ArrayValue.class);
var depth = args.getInt(0, 1);
var res = new ArrayValue(arr.size());
var stack = new Stack<Object>();
var depths = new Stack<Integer>();
stack.push(arr);
depths.push(-1);
while (!stack.empty()) {
var el = stack.pop();
int d = depths.pop();
if ((d == -1 || d < depth) && el instanceof ArrayValue) {
var arrEl = (ArrayValue)el;
for (int i = arrEl.size() - 1; i >= 0; i--) {
if (!arrEl.has(i)) continue;
stack.push(arrEl.get(i));
depths.push(d + 1);
}
}
else res.set(args.ctx, res.size(), el);
}
return res;
}
@Expose public static ArrayValue __flatMap(Arguments args) {
return __flat(new Arguments(args.ctx, __map(args), 1));
}
@Expose public static Object __find(Arguments args) {
var arr = args.self(ArrayValue.class);
for (int i = 0; i < arr.size(); i++) {
if (arr.has(i) && Values.toBoolean(Values.call(
args.ctx, args.get(0), args.get(1),
arr.get(i), i, args.self
))) return arr.get(i);
}
return null;
}
@Expose public static Object __findLast(Arguments args) {
var arr = args.self(ArrayValue.class);
for (var i = arr.size() - 1; i >= 0; i--) {
if (arr.has(i) && Values.toBoolean(Values.call(
args.ctx, args.get(0), args.get(1),
arr.get(i), i, args.self
))) return arr.get(i);
}
return null;
}
@Expose public static int __findIndex(Arguments args) {
var arr = args.self(ArrayValue.class);
for (int i = 0; i < arr.size(); i++) {
if (arr.has(i) && Values.toBoolean(Values.call(
args.ctx, args.get(0), args.get(1),
arr.get(i), i, args.self
))) return i;
}
return -1;
}
@Expose public static int __findLastIndex(Arguments args) {
var arr = args.self(ArrayValue.class);
for (var i = arr.size() - 1; i >= 0; i--) {
if (arr.has(i) && Values.toBoolean(Values.call(
args.ctx, args.get(0), args.get(1),
arr.get(i), i, args.self
))) return i;
}
return -1;
}
@Expose public static int __indexOf(Arguments args) {
var arr = args.self(ArrayValue.class);
var val = args.get(0);
var start = normalizeI(arr.size(), args.getInt(1), true);
for (int i = start; i < arr.size(); i++) {
if (Values.strictEquals(args.ctx, arr.get(i), val)) return i;
}
return -1;
}
@Expose public static int __lastIndexOf(Arguments args) {
var arr = args.self(ArrayValue.class);
var val = args.get(0);
var start = normalizeI(arr.size(), args.getInt(1), true);
for (int i = arr.size(); i >= start; i--) {
if (Values.strictEquals(args.ctx, arr.get(i), val)) return i;
}
return -1;
}
@Expose public static boolean __includes(Arguments args) {
return __indexOf(args) >= 0;
}
@Expose public static Object __pop(Arguments args) {
var arr = args.self(ArrayValue.class);
if (arr.size() == 0) return null;
var val = arr.get(arr.size() - 1);
arr.shrink(1);
return val;
}
@Expose public static int __push(Arguments args) {
var arr = args.self(ArrayValue.class);
var values = args.args;
arr.copyFrom(args.ctx, values, 0, arr.size(), values.length);
return arr.size();
}
@Expose public static Object __shift(Arguments args) {
var arr = args.self(ArrayValue.class);
if (arr.size() == 0) return null;
var val = arr.get(0);
arr.move(1, 0, arr.size());
arr.shrink(1);
return val;
}
@Expose public static int __unshift(Arguments args) {
var arr = args.self(ArrayValue.class);
var values = args.slice(0).args;
arr.move(0, values.length, arr.size());
arr.copyFrom(args.ctx, values, 0, 0, values.length);
return arr.size();
}
@Expose public static ArrayValue __slice(Arguments args) {
var arr = args.self(ArrayValue.class);
var start = normalizeI(arr.size(), args.getInt(0), true);
var end = normalizeI(arr.size(), args.getInt(1, arr.size()), true);
var res = new ArrayValue(end - start);
arr.copyTo(res, start, 0, end - start);
return res;
}
@Expose public static ArrayValue __splice(Arguments args) {
var arr = args.self(ArrayValue.class);
var start = normalizeI(arr.size(), args.getInt(0), true);
var deleteCount = normalizeI(arr.size(), args.getInt(1, arr.size()), true);
var items = args.slice(2).args;
if (start + deleteCount >= arr.size()) deleteCount = arr.size() - start;
var size = arr.size() - deleteCount + items.length;
var res = new ArrayValue(deleteCount);
arr.copyTo(res, start, 0, deleteCount);
arr.move(start + deleteCount, start + items.length, arr.size() - start - deleteCount);
arr.copyFrom(args.ctx, items, 0, start, items.length);
arr.setSize(size);
return res;
}
@Expose public static String __toString(Arguments args) {
return __join(new Arguments(args.ctx, args.self, ","));
}
@Expose public static String __join(Arguments args) {
var arr = args.self(ArrayValue.class);
var sep = args.getString(0, ", ");
var res = new StringBuilder();
var comma = false;
for (int i = 0; i < arr.size(); i++) {
if (!arr.has(i)) continue;
if (comma) res.append(sep);
comma = true;
var el = arr.get(i);
if (el == null || el == Values.NULL) continue;
res.append(Values.toString(args.ctx, el));
}
return res.toString();
}
@Expose(target = ExposeTarget.STATIC)
public static boolean __isArray(Arguments args) {
return args.get(0) instanceof ArrayValue;
}
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __of(Arguments args) {
return new ArrayValue(args.ctx, args.slice(0).args);
}
@ExposeConstructor public static ArrayValue __constructor(Arguments args) {
ArrayValue res;
if (args.n() == 1 && args.get(0) instanceof Number) {
var len = args.getInt(0);
res = new ArrayValue(len);
res.setSize(len);
}
else {
var val = args.args;
res = new ArrayValue(val.length);
res.copyFrom(args.ctx, val, 0, 0, val.length);
}
return res;
}
}

View File

@@ -1,85 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.lib.PromiseLib.Handle;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("AsyncFunction")
public class AsyncFunctionLib extends FunctionValue {
public final CodeFunction func;
private static class AsyncHelper {
public PromiseLib promise = new PromiseLib();
public Frame frame;
private boolean awaiting = false;
private void next(Context ctx, Object inducedValue, EngineException inducedError) {
Object res = null;
frame.onPush();
awaiting = false;
while (!awaiting) {
try {
res = frame.next(inducedValue, Values.NO_RETURN, inducedError);
inducedValue = Values.NO_RETURN;
inducedError = null;
if (res != Values.NO_RETURN) {
promise.fulfill(ctx, res);
break;
}
}
catch (EngineException e) {
promise.reject(ctx, e);
break;
}
}
frame.onPop();
if (awaiting) {
PromiseLib.handle(ctx, frame.pop(), new Handle() {
@Override
public void onFulfil(Object val) {
next(ctx, val, null);
}
@Override
public void onReject(EngineException err) {
next(ctx, Values.NO_RETURN, err);
}
}.defer(ctx));
}
}
public Object await(Arguments args) {
this.awaiting = true;
return args.get(0);
}
}
@Override
public Object call(Context ctx, Object thisArg, Object ...args) {
var handler = new AsyncHelper();
var newArgs = new Object[args.length + 1];
newArgs[0] = new NativeFunction("await", handler::await);
System.arraycopy(args, 0, newArgs, 1, args.length);
handler.frame = new Frame(ctx, thisArg, newArgs, (CodeFunction)func);
handler.next(ctx, Values.NO_RETURN, null);
return handler.promise;
}
public AsyncFunctionLib(FunctionValue func) {
super(func.name, func.length);
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function.");
this.func = (CodeFunction)func;
}
}

View File

@@ -1,33 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("AsyncGeneratorFunction")
public class AsyncGeneratorFunctionLib extends FunctionValue {
public final CodeFunction func;
@Override
public Object call(Context ctx, Object thisArg, Object ...args) {
var handler = new AsyncGeneratorLib();
var newArgs = new Object[args.length + 2];
newArgs[0] = new NativeFunction("await", handler::await);
newArgs[1] = new NativeFunction("yield", handler::yield);
System.arraycopy(args, 0, newArgs, 2, args.length);
handler.frame = new Frame(ctx, thisArg, newArgs, func);
return handler;
}
public AsyncGeneratorFunctionLib(CodeFunction func) {
super(func.name, func.length);
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function.");
this.func = func;
}
}

View File

@@ -1,107 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.Map;
import me.topchetoeu.jscript.lib.PromiseLib.Handle;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("AsyncGenerator")
public class AsyncGeneratorLib {
private int state = 0;
private boolean done = false;
private PromiseLib currPromise;
public Frame frame;
private void next(Context ctx, Object inducedValue, Object inducedReturn, EngineException inducedError) {
if (done) {
if (inducedError != null) throw inducedError;
currPromise.fulfill(ctx, new ObjectValue(ctx, Map.of(
"done", true,
"value", inducedReturn == Values.NO_RETURN ? null : inducedReturn
)));
return;
}
Object res = null;
state = 0;
frame.onPush();
while (state == 0) {
try {
res = frame.next(inducedValue, inducedReturn, inducedError);
inducedValue = inducedReturn = Values.NO_RETURN;
inducedError = null;
if (res != Values.NO_RETURN) {
var obj = new ObjectValue();
obj.defineProperty(ctx, "done", true);
obj.defineProperty(ctx, "value", res);
currPromise.fulfill(ctx, obj);
break;
}
}
catch (EngineException e) {
currPromise.reject(ctx, e);
break;
}
}
frame.onPop();
if (state == 1) {
PromiseLib.handle(ctx, frame.pop(), new Handle() {
@Override public void onFulfil(Object val) {
next(ctx, val, Values.NO_RETURN, null);
}
@Override public void onReject(EngineException err) {
next(ctx, Values.NO_RETURN, Values.NO_RETURN, err);
}
}.defer(ctx));
}
else if (state == 2) {
var obj = new ObjectValue();
obj.defineProperty(ctx, "done", false);
obj.defineProperty(ctx, "value", frame.pop());
currPromise.fulfill(ctx, obj);
}
}
@Override
public String toString() {
if (done) return "Generator [closed]";
if (state != 0) return "Generator [suspended]";
return "Generator [running]";
}
public Object await(Arguments args) {
this.state = 1;
return args.get(0);
}
public Object yield(Arguments args) {
this.state = 2;
return args.get(0);
}
@Expose public PromiseLib __next(Arguments args) {
this.currPromise = new PromiseLib();
if (args.has(0)) next(args.ctx, args.get(0), Values.NO_RETURN, null);
else next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, null);
return this.currPromise;
}
@Expose public PromiseLib __return(Arguments args) {
this.currPromise = new PromiseLib();
next(args.ctx, Values.NO_RETURN, args.get(0), null);
return this.currPromise;
}
@Expose public PromiseLib __throw(Arguments args) {
this.currPromise = new PromiseLib();
next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setCtx(args.ctx));
return this.currPromise;
}
}

View File

@@ -1,37 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Boolean")
public class BooleanLib {
public static final BooleanLib TRUE = new BooleanLib(true);
public static final BooleanLib FALSE = new BooleanLib(false);
public final boolean value;
@Override public String toString() {
return value + "";
}
public BooleanLib(boolean val) {
this.value = val;
}
@ExposeConstructor public static Object __constructor(Arguments args) {
var val = args.getBoolean(0);
if (args.self instanceof ObjectValue) return val ? TRUE : FALSE;
else return val;
}
@Expose public static String __toString(Arguments args) {
return args.self(Boolean.class) ? "true" : "false";
}
@Expose public static boolean __valueOf(Arguments args) {
if (Values.isWrapper(args.self, BooleanLib.class)) return Values.wrapper(args.self, BooleanLib.class).value;
return args.self(Boolean.class);
}
}

View File

@@ -1,38 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.io.IOException;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.filesystem.File;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Console")
public class ConsoleLib {
public static interface Writer {
void writeLine(String val) throws IOException;
}
private File file;
@Expose
public void __log(Arguments args) {
var res = new StringBuilder();
var first = true;
for (var el : args.args) {
if (!first) res.append(" ");
first = false;
res.append(Values.toReadable(args.ctx, el).getBytes());
}
for (var line : res.toString().split("\n", -1)) {
file.write(line.getBytes());
}
}
public ConsoleLib(File file) {
this.file = file;
}
}

View File

@@ -1,266 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Date")
public class DateLib {
private Calendar normal;
private Calendar utc;
private void updateUTC() {
if (utc == null || normal == null) return;
utc.setTimeInMillis(normal.getTimeInMillis());
}
private void updateNormal() {
if (utc == null || normal == null) return;
normal.setTimeInMillis(utc.getTimeInMillis());
}
private void invalidate() {
normal = utc = null;
}
@Expose public double __getYear() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.YEAR) - 1900;
}
@Expose public double __setYeard(Arguments args) {
var real = args.getDouble(0);
if (real >= 0 && real <= 99) real = real + 1900;
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.YEAR, (int)real);
updateUTC();
return __getTime();
}
@Expose public double __getFullYear() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.YEAR);
}
@Expose public double __getMonth() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.MONTH);
}
@Expose public double __getDate() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.DAY_OF_MONTH);
}
@Expose public double __getDay() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.DAY_OF_WEEK);
}
@Expose public double __getHours() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.HOUR_OF_DAY);
}
@Expose public double __getMinutes() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.MINUTE);
}
@Expose public double __getSeconds() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.SECOND);
}
@Expose public double __getMilliseconds() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.MILLISECOND);
}
@Expose public double __getUTCFullYear() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.YEAR);
}
@Expose public double __getUTCMonth() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.MONTH);
}
@Expose public double __getUTCDate() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.DAY_OF_MONTH);
}
@Expose public double __getUTCDay() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.DAY_OF_WEEK);
}
@Expose public double __getUTCHours() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.HOUR_OF_DAY);
}
@Expose public double __getUTCMinutes() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.MINUTE);
}
@Expose public double __getUTCSeconds() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.SECOND);
}
@Expose public double __getUTCMilliseconds() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.MILLISECOND);
}
@Expose public double __setFullYear(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.YEAR, (int)real);
updateUTC();
return __getTime();
}
@Expose public double __setMonthd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.MONTH, (int)real);
updateUTC();
return __getTime();
}
@Expose public double __setDated(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.DAY_OF_MONTH, (int)real);
updateUTC();
return __getTime();
}
@Expose public double __setDayd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.DAY_OF_WEEK, (int)real);
updateUTC();
return __getTime();
}
@Expose public double __setHoursd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.HOUR_OF_DAY, (int)real);
updateUTC();
return __getTime();
}
@Expose public double __setMinutesd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.MINUTE, (int)real);
updateUTC();
return __getTime();
}
@Expose public double __setSecondsd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.SECOND, (int)real);
updateUTC();
return __getTime();
}
@Expose public double __setMillisecondsd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.MILLISECOND, (int)real);
updateUTC();
return __getTime();
}
@Expose public double __setUTCFullYeard(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.YEAR, (int)real);
updateNormal();
return __getTime();
}
@Expose public double __setUTCMonthd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.MONTH, (int)real);
updateNormal();
return __getTime();
}
@Expose public double __setUTCDated(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.DAY_OF_MONTH, (int)real);
updateNormal();
return __getTime();
}
@Expose public double __setUTCDayd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.DAY_OF_WEEK, (int)real);
updateNormal();
return __getTime();
}
@Expose public double __setUTCHoursd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.HOUR_OF_DAY, (int)real);
updateNormal();
return __getTime();
}
@Expose public double __setUTCMinutesd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.MINUTE, (int)real);
updateNormal();
return __getTime();
}
@Expose public double __setUTCSecondsd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.SECOND, (int)real);
updateNormal();
return __getTime();
}
@Expose public double __setUTCMillisecondsd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.MILLISECOND, (int)real);
updateNormal();
return __getTime();
}
@Expose public double __getTime() {
if (utc == null) return Double.NaN;
return utc.getTimeInMillis();
}
@Expose public double __getTimezoneOffset() {
if (normal == null) return Double.NaN;
return normal.getTimeZone().getRawOffset() / 60000;
}
@Expose public double __valueOf() {
if (normal == null) return Double.NaN;
else return normal.getTimeInMillis();
}
@Expose public String __toString() {
return normal.getTime().toString();
}
@Override public String toString() {
return __toString();
}
public DateLib(long timestamp) {
normal = Calendar.getInstance();
utc = Calendar.getInstance();
normal.setTimeInMillis(timestamp);
utc.setTimeZone(TimeZone.getTimeZone("UTC"));
utc.setTimeInMillis(timestamp);
}
public DateLib() {
this(new Date().getTime());
}
@ExposeConstructor public static DateLib init(Arguments args) {
if (args.has(0)) return new DateLib(args.getLong(0));
else return new DateLib();
}
@Expose(target = ExposeTarget.STATIC)
public static double __now() {
return new DateLib().__getTime();
}
}

View File

@@ -1,89 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.ArrayList;
import me.topchetoeu.jscript.common.Buffer;
import me.topchetoeu.jscript.compilation.parsing.Parsing;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Encoding")
public class EncodingLib {
private static final String HEX = "0123456789ABCDEF";
public static String encodeUriAny(String str, String keepAlphabet) {
if (str == null) str = "undefined";
var bytes = str.getBytes();
var sb = new StringBuilder(bytes.length);
for (byte c : bytes) {
if (Parsing.isAlphanumeric((char)c) || Parsing.isAny((char)c, keepAlphabet)) sb.append((char)c);
else {
sb.append('%');
sb.append(HEX.charAt(c / 16));
sb.append(HEX.charAt(c % 16));
}
}
return sb.toString();
}
public static String decodeUriAny(String str, String keepAlphabet) {
if (str == null) str = "undefined";
var res = new Buffer();
var bytes = str.getBytes();
for (var i = 0; i < bytes.length; i++) {
var c = bytes[i];
if (c == '%') {
if (i >= bytes.length - 2) throw EngineException.ofError("URIError", "URI malformed.");
var b = Parsing.fromHex((char)bytes[i + 1]) * 16 | Parsing.fromHex((char)bytes[i + 2]);
if (!Parsing.isAny((char)b, keepAlphabet)) {
i += 2;
res.append((byte)b);
continue;
}
}
res.append(c);
}
return new String(res.data());
}
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __encode(Arguments args) {
var res = new ArrayValue();
for (var el : args.getString(0).getBytes()) res.set(null, res.size(), (int)el);
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static String __decode(Arguments args) {
var raw = args.convert(0, ArrayList.class);
var res = new byte[raw.size()];
for (var i = 0; i < raw.size(); i++) res[i] = (byte)Values.toNumber(args.ctx, raw.get(i));
return new String(res);
}
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURIComponent(Arguments args) {
return EncodingLib.encodeUriAny(args.getString(0), ".-_!~*'()");
}
@Expose(target = ExposeTarget.STATIC)
public static String __decodeURIComponent(Arguments args) {
return decodeUriAny(args.getString(0), "");
}
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURI(Arguments args) {
return encodeUriAny(args.getString(0), ";,/?:@&=+$#.-_!~*'()");
}
@Expose(target = ExposeTarget.STATIC)
public static String __decodeURI(Arguments args) {
return decodeUriAny(args.getString(0), ",/?:@&=+$#.");
}
}

View File

@@ -1,54 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.exceptions.ConvertException;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeField;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Error")
public class ErrorLib {
private static String toString(Context ctx, Object name, Object message) {
if (name == null) name = "";
else name = Values.toString(ctx, name).trim();
if (message == null) message = "";
else message = Values.toString(ctx, message).trim();
StringBuilder res = new StringBuilder();
if (!name.equals("")) res.append(name);
if (!message.equals("") && !name.equals("")) res.append(": ");
if (!message.equals("")) res.append(message);
return res.toString();
}
@ExposeField public static final String __name = "Error";
@Expose public static String __toString(Arguments args) {
if (args.self instanceof ObjectValue) return toString(args.ctx,
Values.getMember(args.ctx, args.self, "name"),
Values.getMember(args.ctx, args.self, "message")
);
else return "[Invalid error]";
}
@ExposeConstructor public static ObjectValue __constructor(Arguments args) {
var target = new ObjectValue();
var message = args.getString(0, "");
try {
target = args.self(ObjectValue.class);
}
catch (ConvertException e) {}
target.setPrototype(PlaceholderProto.ERROR);
target.defineProperty(args.ctx, "message", Values.toString(args.ctx, message));
return target;
}
}

View File

@@ -1,84 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.filesystem.File;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("File")
public class FileLib {
public final File fd;
@Expose public PromiseLib __pointer(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
try {
return fd.seek(0, 1);
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Expose public PromiseLib __length(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
try {
long curr = fd.seek(0, 1);
long res = fd.seek(0, 2);
fd.seek(curr, 0);
return res;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Expose public PromiseLib __read(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
var n = args.getInt(0);
try {
var buff = new byte[n];
var res = new ArrayValue();
int resI = fd.read(buff);
for (var i = resI - 1; i >= 0; i--) res.set(args.ctx, i, (int)buff[i]);
return res;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Expose public PromiseLib __write(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
var val = args.convert(0, ArrayValue.class);
try {
var res = new byte[val.size()];
for (var i = 0; i < val.size(); i++) res[i] = (byte)Values.toNumber(args.ctx, val.get(i));
fd.write(res);
return null;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Expose public PromiseLib __close(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
fd.close();
return null;
});
}
@Expose public PromiseLib __seek(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
var ptr = args.getLong(0);
var whence = args.getInt(1);
try {
return fd.seek(ptr, whence);
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
public FileLib(File fd) {
this.fd = fd;
}
}

View File

@@ -1,193 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.io.IOException;
import java.util.Iterator;
import java.util.Stack;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.filesystem.ActionType;
import me.topchetoeu.jscript.utils.filesystem.EntryType;
import me.topchetoeu.jscript.utils.filesystem.ErrorReason;
import me.topchetoeu.jscript.utils.filesystem.File;
import me.topchetoeu.jscript.utils.filesystem.FileStat;
import me.topchetoeu.jscript.utils.filesystem.Filesystem;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException;
import me.topchetoeu.jscript.utils.filesystem.Mode;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeField;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Filesystem")
public class FilesystemLib {
@ExposeField(target = ExposeTarget.STATIC)
public static final int __SEEK_SET = 0;
@ExposeField(target = ExposeTarget.STATIC)
public static final int __SEEK_CUR = 1;
@ExposeField(target = ExposeTarget.STATIC)
public static final int __SEEK_END = 2;
private static Filesystem fs(Context ctx) {
var fs = Filesystem.get(ctx);
if (fs != null) return fs;
throw EngineException.ofError("Current environment doesn't have a file system.");
}
@Expose(target = ExposeTarget.STATIC)
public static String __normalize(Arguments args) {
return fs(args.ctx).normalize(args.convert(String.class));
}
@Expose(target = ExposeTarget.STATIC)
public static PromiseLib __open(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
var fs = fs(args.ctx);
var path = fs.normalize(args.getString(0));
var _mode = Mode.parse(args.getString(1));
try {
if (fs.stat(path).type != EntryType.FILE) {
throw new FilesystemException(ErrorReason.DOESNT_EXIST, "Not a file").setAction(ActionType.OPEN);
}
return new FileLib(fs.open(path, _mode));
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __ls(Arguments args) {
return Values.toJSAsyncIterator(args.ctx, new Iterator<>() {
private boolean failed, done;
private File file;
private String nextLine;
private void update() {
if (done) return;
if (!failed) {
if (file == null) {
var fs = fs(args.ctx);
var path = fs.normalize(args.getString(0));
if (fs.stat(path).type != EntryType.FOLDER) {
throw new FilesystemException(ErrorReason.DOESNT_EXIST, "Not a directory").setAction(ActionType.OPEN);
}
file = fs.open(path, Mode.READ);
}
if (nextLine == null) {
while (true) {
nextLine = file.readLine();
if (nextLine == null) {
done = true;
return;
}
nextLine = nextLine.trim();
if (!nextLine.equals("")) break;
}
}
}
}
@Override
public boolean hasNext() {
try {
update();
return !done && !failed;
}
catch (FilesystemException e) { throw e.toEngineException(); }
}
@Override
public String next() {
try {
update();
var res = nextLine;
nextLine = null;
return res;
}
catch (FilesystemException e) { throw e.toEngineException(); }
}
});
}
@Expose(target = ExposeTarget.STATIC)
public static PromiseLib __mkdir(Arguments args) throws IOException {
return PromiseLib.await(args.ctx, () -> {
try {
fs(args.ctx).create(args.getString(0), EntryType.FOLDER);
return null;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Expose(target = ExposeTarget.STATIC)
public static PromiseLib __mkfile(Arguments args) throws IOException {
return PromiseLib.await(args.ctx, () -> {
try {
fs(args.ctx).create(args.getString(0), EntryType.FILE);
return null;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Expose(target = ExposeTarget.STATIC)
public static PromiseLib __rm(Arguments args) throws IOException {
return PromiseLib.await(args.ctx, () -> {
try {
var fs = fs(args.ctx);
var path = fs.normalize(args.getString(0));
var recursive = args.getBoolean(1);
if (!recursive) fs.create(path, EntryType.NONE);
else {
var stack = new Stack<String>();
stack.push(path);
while (!stack.empty()) {
var currPath = stack.pop();
FileStat stat;
try { stat = fs.stat(currPath); }
catch (FilesystemException e) { continue; }
if (stat.type == EntryType.FOLDER) {
for (var el : fs.open(currPath, Mode.READ).readToString().split("\n")) stack.push(el);
}
else fs.create(currPath, EntryType.NONE);
}
}
return null;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Expose(target = ExposeTarget.STATIC)
public static PromiseLib __stat(Arguments args) throws IOException {
return PromiseLib.await(args.ctx, () -> {
try {
var fs = fs(args.ctx);
var path = fs.normalize(args.getString(0));
var stat = fs.stat(path);
var res = new ObjectValue();
res.defineProperty(args.ctx, "type", stat.type.name);
res.defineProperty(args.ctx, "mode", stat.mode.name);
return res;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Expose(target = ExposeTarget.STATIC)
public static PromiseLib __exists(Arguments args) throws IOException {
return PromiseLib.await(args.ctx, () -> {
try { fs(args.ctx).stat(args.getString(0)); return true; }
catch (FilesystemException e) { return false; }
});
}
}

View File

@@ -1,54 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Function")
public class FunctionLib {
@Expose public static Object __apply(Arguments args) {
return args.self(FunctionValue.class).call(args.ctx, args.get(0), args.convert(1, ArrayValue.class).toArray());
}
@Expose public static Object __call(Arguments args) {
return args.self(FunctionValue.class).call(args.ctx, args.get(0), args.slice(1).args);
}
@Expose public static FunctionValue __bind(Arguments args) {
var self = args.self(FunctionValue.class);
var thisArg = args.get(0);
var bindArgs = args.slice(1).args;
return new NativeFunction(self.name + " (bound)", callArgs -> {
Object[] resArgs;
if (args.n() == 0) resArgs = bindArgs;
else {
resArgs = new Object[bindArgs.length + callArgs.n()];
System.arraycopy(bindArgs, 0, resArgs, 0, bindArgs.length);
System.arraycopy(callArgs.args, 0, resArgs, bindArgs.length, callArgs.n());
}
return self.call(callArgs.ctx, thisArg, resArgs);
});
}
@Expose public static String __toString(Arguments args) {
return args.self.toString();
}
@Expose(target = ExposeTarget.STATIC)
public static FunctionValue __async(Arguments args) {
return new AsyncFunctionLib(args.convert(0, FunctionValue.class));
}
@Expose(target = ExposeTarget.STATIC)
public static FunctionValue __asyncGenerator(Arguments args) {
return new AsyncGeneratorFunctionLib(args.convert(0, CodeFunction.class));
}
@Expose(target = ExposeTarget.STATIC)
public static FunctionValue __generator(Arguments args) {
return new GeneratorFunctionLib(args.convert(0, CodeFunction.class));
}
}

View File

@@ -1,31 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.CodeFunction;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("GeneratorFunction")
public class GeneratorFunctionLib extends FunctionValue {
public final CodeFunction func;
@Override public Object call(Context ctx, Object thisArg, Object ...args) {
var handler = new GeneratorLib();
var newArgs = new Object[args.length + 1];
newArgs[0] = new NativeFunction("yield", handler::yield);
System.arraycopy(args, 0, newArgs, 1, args.length);
handler.frame = new Frame(ctx, thisArg, newArgs, func);
return handler;
}
public GeneratorFunctionLib(CodeFunction func) {
super(func.name, func.length);
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function.");
this.func = func;
}
}

View File

@@ -1,78 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Generator")
public class GeneratorLib {
private boolean yielding = true;
private boolean done = false;
public Frame frame;
private ObjectValue next(Context ctx, Object inducedValue, Object inducedReturn, EngineException inducedError) {
if (done) {
if (inducedError != Values.NO_RETURN) throw inducedError;
var res = new ObjectValue();
res.defineProperty(ctx, "done", true);
res.defineProperty(ctx, "value", inducedReturn == Values.NO_RETURN ? null : inducedReturn);
return res;
}
Object res = null;
yielding = false;
frame.onPush();
while (!yielding) {
try {
res = frame.next(inducedValue, inducedReturn, inducedError);
inducedReturn = Values.NO_RETURN;
inducedError = null;
if (res != Values.NO_RETURN) {
done = true;
break;
}
}
catch (EngineException e) {
done = true;
throw e;
}
}
frame.onPop();
if (done) frame = null;
else res = frame.pop();
var obj = new ObjectValue();
obj.defineProperty(ctx, "done", done);
obj.defineProperty(ctx, "value", res);
return obj;
}
@Expose public ObjectValue __next(Arguments args) {
if (args.n() == 0) return next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, null);
else return next(args.ctx, args.get(0), Values.NO_RETURN, null);
}
@Expose public ObjectValue __throw(Arguments args) {
return next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setCtx(args.ctx));
}
@Expose public ObjectValue __return(Arguments args) {
return next(args.ctx, Values.NO_RETURN, args.get(0), null);
}
@Override public String toString() {
if (done) return "Generator [closed]";
if (yielding) return "Generator [suspended]";
return "Generator [running]";
}
public Object yield(Arguments args) {
this.yielding = true;
return args.get(0);
}
}

View File

@@ -1,217 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.HashMap;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Environment;
import me.topchetoeu.jscript.runtime.EventLoop;
import me.topchetoeu.jscript.runtime.Key;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.filesystem.Filesystem;
import me.topchetoeu.jscript.utils.filesystem.Mode;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeField;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.ExposeType;
import me.topchetoeu.jscript.utils.modules.ModuleRepo;
public class Internals {
private static final Key<HashMap<Integer, Thread>> THREADS = new Key<>();
private static final Key<Integer> I = new Key<>();
@Expose(target = ExposeTarget.STATIC)
public static Object __require(Arguments args) {
var repo = ModuleRepo.get(args.ctx);
if (repo != null) {
var res = repo.getModule(args.ctx, ModuleRepo.cwd(args.ctx), args.getString(0));
res.load(args.ctx);
return res.value();
}
else throw EngineException.ofError("Modules are not supported.");
}
@Expose(target = ExposeTarget.STATIC)
public static Thread __setTimeout(Arguments args) {
var func = args.convert(0, FunctionValue.class);
var delay = args.getDouble(1);
var arguments = args.slice(2).args;
if (!args.ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
var thread = new Thread(() -> {
var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000);
try { Thread.sleep(ms, ns); }
catch (InterruptedException e) { return; }
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.environment), null, arguments), false);
});
thread.start();
var i = args.ctx.init(I, 1);
args.ctx.add(I, i + 1);
args.ctx.init(THREADS, new HashMap<Integer, Thread>()).put(i, thread);
return thread;
}
@Expose(target = ExposeTarget.STATIC)
public static Thread __setInterval(Arguments args) {
var func = args.convert(0, FunctionValue.class);
var delay = args.getDouble(1);
var arguments = args.slice(2).args;
if (!args.ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
var thread = new Thread(() -> {
var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000);
while (true) {
try {
Thread.sleep(ms, ns);
}
catch (InterruptedException e) { return; }
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.environment), null, arguments), false);
}
});
thread.start();
var i = args.ctx.init(I, 1);
args.ctx.add(I, i + 1);
args.ctx.init(THREADS, new HashMap<Integer, Thread>()).put(i, thread);
return thread;
}
@Expose(target = ExposeTarget.STATIC)
public static void __clearTimeout(Arguments args) {
var i = args.getInt(0);
HashMap<Integer, Thread> map = args.ctx.get(THREADS);
if (map == null) return;
var thread = map.get(i);
if (thread == null) return;
thread.interrupt();
map.remove(i);
}
@Expose(target = ExposeTarget.STATIC)
public static void __clearInterval(Arguments args) {
__clearTimeout(args);
}
@Expose(target = ExposeTarget.STATIC)
public static double __parseInt(Arguments args) {
return NumberLib.__parseInt(args);
}
@Expose(target = ExposeTarget.STATIC)
public static double __parseFloat(Arguments args) {
return NumberLib.__parseFloat(args);
}
@Expose(target = ExposeTarget.STATIC)
public static boolean __isNaN(Arguments args) {
return NumberLib.__isNaN(args);
}
@Expose(target = ExposeTarget.STATIC)
public static boolean __isFinite(Arguments args) {
return NumberLib.__isFinite(args);
}
@Expose(target = ExposeTarget.STATIC)
public static boolean __isInfinite(Arguments args) {
return NumberLib.__isInfinite(args);
}
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
public static FileLib __stdin(Arguments args) {
return new FileLib(Filesystem.get(args.ctx).open("std://in", Mode.READ));
}
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
public static FileLib __stdout(Arguments args) {
return new FileLib(Filesystem.get(args.ctx).open("std://out", Mode.READ));
}
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
public static FileLib __stderr(Arguments args) {
return new FileLib(Filesystem.get(args.ctx).open("std://err", Mode.READ));
}
@ExposeField(target = ExposeTarget.STATIC)
public static double __NaN = Double.NaN;
@ExposeField(target = ExposeTarget.STATIC)
public static double __Infinity = Double.POSITIVE_INFINITY;
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURIComponent(Arguments args) {
return EncodingLib.__encodeURIComponent(args);
}
@Expose(target = ExposeTarget.STATIC)
public static String __decodeURIComponent(Arguments args) {
return EncodingLib.__decodeURIComponent(args);
}
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURI(Arguments args) {
return EncodingLib.__encodeURI(args);
}
@Expose(target = ExposeTarget.STATIC)
public static String __decodeURI(Arguments args) {
return EncodingLib.__decodeURI(args);
}
public static Environment apply(Environment env) {
var wp = env.wrappers;
var glob = env.global = new GlobalScope(wp.getNamespace(Internals.class));
glob.define(null, "Math", false, wp.getNamespace(MathLib.class));
glob.define(null, "JSON", false, wp.getNamespace(JSONLib.class));
glob.define(null, "Encoding", false, wp.getNamespace(EncodingLib.class));
glob.define(null, "Filesystem", false, wp.getNamespace(FilesystemLib.class));
glob.define(null, false, wp.getConstr(FileLib.class));
glob.define(null, false, wp.getConstr(DateLib.class));
glob.define(null, false, wp.getConstr(ObjectLib.class));
glob.define(null, false, wp.getConstr(FunctionLib.class));
glob.define(null, false, wp.getConstr(ArrayLib.class));
glob.define(null, false, wp.getConstr(BooleanLib.class));
glob.define(null, false, wp.getConstr(NumberLib.class));
glob.define(null, false, wp.getConstr(StringLib.class));
glob.define(null, false, wp.getConstr(SymbolLib.class));
glob.define(null, false, wp.getConstr(PromiseLib.class));
glob.define(null, false, wp.getConstr(RegExpLib.class));
glob.define(null, false, wp.getConstr(MapLib.class));
glob.define(null, false, wp.getConstr(SetLib.class));
glob.define(null, false, wp.getConstr(ErrorLib.class));
glob.define(null, false, wp.getConstr(SyntaxErrorLib.class));
glob.define(null, false, wp.getConstr(TypeErrorLib.class));
glob.define(null, false, wp.getConstr(RangeErrorLib.class));
env.add(Environment.OBJECT_PROTO, wp.getProto(ObjectLib.class));
env.add(Environment.FUNCTION_PROTO, wp.getProto(FunctionLib.class));
env.add(Environment.ARRAY_PROTO, wp.getProto(ArrayLib.class));
env.add(Environment.BOOL_PROTO, wp.getProto(BooleanLib.class));
env.add(Environment.NUMBER_PROTO, wp.getProto(NumberLib.class));
env.add(Environment.STRING_PROTO, wp.getProto(StringLib.class));
env.add(Environment.SYMBOL_PROTO, wp.getProto(SymbolLib.class));
env.add(Environment.ERROR_PROTO, wp.getProto(ErrorLib.class));
env.add(Environment.SYNTAX_ERR_PROTO, wp.getProto(SyntaxErrorLib.class));
env.add(Environment.TYPE_ERR_PROTO, wp.getProto(TypeErrorLib.class));
env.add(Environment.RANGE_ERR_PROTO, wp.getProto(RangeErrorLib.class));
Values.setPrototype(Context.NULL, wp.getProto(ObjectLib.class), null);
env.add(Environment.REGEX_CONSTR, wp.getConstr(RegExpLib.class));
return env;
}
}

View File

@@ -1,24 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.common.json.JSON;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("JSON")
public class JSONLib {
@Expose(target = ExposeTarget.STATIC)
public static Object __parse(Arguments args) {
try {
return JSON.toJs(JSON.parse(null, args.getString(0)));
}
catch (SyntaxException e) { throw EngineException.ofSyntax(e.msg); }
}
@Expose(target = ExposeTarget.STATIC)
public static String __stringify(Arguments args) {
return JSON.stringify(JSON.fromJs(args.ctx, args.get(0)));
}
}

View File

@@ -1,87 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.stream.Collectors;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeType;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Map")
public class MapLib {
private LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
@Expose("@@Symbol.iterator")
public ObjectValue __iterator(Arguments args) {
return this.__entries(args);
}
@Expose public void __clear() {
map.clear();
}
@Expose public boolean __delete(Arguments args) {
var key = args.get(0);
if (map.containsKey(key)) {
map.remove(key);
return true;
}
return false;
}
@Expose public ObjectValue __entries(Arguments args) {
return Values.toJSIterator(args.ctx, map
.entrySet()
.stream()
.map(v -> new ArrayValue(args.ctx, v.getKey(), v.getValue()))
.collect(Collectors.toList())
);
}
@Expose public ObjectValue __keys(Arguments args) {
return Values.toJSIterator(args.ctx, map.keySet());
}
@Expose public ObjectValue __values(Arguments args) {
return Values.toJSIterator(args.ctx, map.values());
}
@Expose public Object __get(Arguments args) {
return map.get(args.get(0));
}
@Expose public MapLib __set(Arguments args) {
map.put(args.get(0), args.get(1));
return this;
}
@Expose public boolean __has(Arguments args) {
return map.containsKey(args.get(0));
}
@Expose(type = ExposeType.GETTER)
public int __size() {
return map.size();
}
@Expose public void __forEach(Arguments args) {
var keys = new ArrayList<>(map.keySet());
for (var el : keys) Values.call(args.ctx, args.get(0), args.get(1), map.get(el), el, args.self);
}
public MapLib(Context ctx, Object iterable) {
for (var el : Values.fromJSIterator(ctx, iterable)) {
try {
map.put(Values.getMember(ctx, el, 0), Values.getMember(ctx, el, 1));
}
catch (IllegalArgumentException e) { }
}
}
@ExposeConstructor public static MapLib __constructor(Arguments args) {
return new MapLib(args.ctx, args.get(0));
}
}

View File

@@ -1,211 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeField;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Math")
public class MathLib {
@ExposeField(target = ExposeTarget.STATIC)
public static final double __E = Math.E;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __PI = Math.PI;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __SQRT2 = Math.sqrt(2);
@ExposeField(target = ExposeTarget.STATIC)
public static final double __SQRT1_2 = Math.sqrt(.5);
@ExposeField(target = ExposeTarget.STATIC)
public static final double __LN2 = Math.log(2);
@ExposeField(target = ExposeTarget.STATIC)
public static final double __LN10 = Math.log(10);
@ExposeField(target = ExposeTarget.STATIC)
public static final double __LOG2E = Math.log(Math.E) / __LN2;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __LOG10E = Math.log10(Math.E);
@Expose(target = ExposeTarget.STATIC)
public static double __asin(Arguments args) {
return Math.asin(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __acos(Arguments args) {
return Math.acos(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __atan(Arguments args) {
return Math.atan(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __atan2(Arguments args) {
var x = args.getDouble(1);
var y = args.getDouble(0);
if (x == 0) {
if (y == 0) return Double.NaN;
return Math.signum(y) * Math.PI / 2;
}
else {
var val = Math.atan(y / x);
if (x > 0) return val;
else if (y < 0) return val - Math.PI;
else return val + Math.PI;
}
}
@Expose(target = ExposeTarget.STATIC)
public static double __asinh(Arguments args) {
var x = args.getDouble(0);
return Math.log(x + Math.sqrt(x * x + 1));
}
@Expose(target = ExposeTarget.STATIC)
public static double __acosh(Arguments args) {
var x = args.getDouble(0);
return Math.log(x + Math.sqrt(x * x - 1));
}
@Expose(target = ExposeTarget.STATIC)
public static double __atanh(Arguments args) {
var x = args.getDouble(0);
if (x <= -1 || x >= 1) return Double.NaN;
return .5 * Math.log((1 + x) / (1 - x));
}
@Expose(target = ExposeTarget.STATIC)
public static double __sin(Arguments args) {
return Math.sin(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __cos(Arguments args) {
return Math.cos(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __tan(Arguments args) {
return Math.tan(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __sinh(Arguments args) {
return Math.sinh(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __cosh(Arguments args) {
return Math.cosh(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __tanh(Arguments args) {
return Math.tanh(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __sqrt(Arguments args) {
return Math.sqrt(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __cbrt(Arguments args) {
return Math.cbrt(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __hypot(Arguments args) {
var res = 0.;
for (var i = 0; i < args.n(); i++) {
var val = args.getDouble(i);
res += val * val;
}
return Math.sqrt(res);
}
@Expose(target = ExposeTarget.STATIC)
public static int __imul(Arguments args) { return args.getInt(0) * args.getInt(1); }
@Expose(target = ExposeTarget.STATIC)
public static double __exp(Arguments args) {
return Math.exp(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __expm1(Arguments args) {
return Math.expm1(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __pow(Arguments args) { return Math.pow(args.getDouble(0), args.getDouble(1)); }
@Expose(target = ExposeTarget.STATIC)
public static double __log(Arguments args) {
return Math.log(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __log10(Arguments args) {
return Math.log10(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __log1p(Arguments args) {
return Math.log1p(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __log2(Arguments args) {
return Math.log(args.getDouble(0)) / __LN2;
}
@Expose(target = ExposeTarget.STATIC)
public static double __ceil(Arguments args) {
return Math.ceil(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __floor(Arguments args) {
return Math.floor(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __round(Arguments args) {
return Math.round(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static float __fround(Arguments args) {
return (float)args.getDouble(0);
}
@Expose(target = ExposeTarget.STATIC)
public static double __trunc(Arguments args) {
var x = args.getDouble(0);
return Math.floor(Math.abs(x)) * Math.signum(x);
}
@Expose(target = ExposeTarget.STATIC)
public static double __abs(Arguments args) {
return Math.abs(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __max(Arguments args) {
var res = Double.NEGATIVE_INFINITY;
for (var i = 0; i < args.n(); i++) {
var el = args.getDouble(i);
if (el > res) res = el;
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static double __min(Arguments args) {
var res = Double.POSITIVE_INFINITY;
for (var i = 0; i < args.n(); i++) {
var el = args.getDouble(i);
if (el < res) res = el;
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static double __sign(Arguments args) {
return Math.signum(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __random() { return Math.random(); }
@Expose(target = ExposeTarget.STATIC)
public static int __clz32(Arguments args) {
return Integer.numberOfLeadingZeros(args.getInt(0));
}
}

View File

@@ -1,92 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeField;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Number")
public class NumberLib {
@ExposeField(target = ExposeTarget.STATIC)
public static final double __EPSILON = Math.ulp(1.0);
@ExposeField(target = ExposeTarget.STATIC)
public static final double __MAX_SAFE_INTEGER = 9007199254740991.;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __MIN_SAFE_INTEGER = -__MAX_SAFE_INTEGER;
// lmao big number go brrr
@ExposeField(target = ExposeTarget.STATIC)
public static final double __MAX_VALUE = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __MIN_VALUE = -__MAX_VALUE;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __NaN = 0. / 0;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __NEGATIVE_INFINITY = -1. / 0;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __POSITIVE_INFINITY = 1. / 0;
public final double value;
@Override public String toString() { return value + ""; }
public NumberLib(double val) {
this.value = val;
}
@Expose(target = ExposeTarget.STATIC)
public static boolean __isFinite(Arguments args) { return Double.isFinite(args.getDouble(0)); }
@Expose(target = ExposeTarget.STATIC)
public static boolean __isInfinite(Arguments args) { return Double.isInfinite(args.getDouble(0)); }
@Expose(target = ExposeTarget.STATIC)
public static boolean __isNaN(Arguments args) { return Double.isNaN(args.getDouble(0)); }
@Expose(target = ExposeTarget.STATIC)
public static boolean __isSafeInteger(Arguments args) {
return args.getDouble(0) > __MIN_SAFE_INTEGER && args.getDouble(0) < __MAX_SAFE_INTEGER;
}
@Expose(target = ExposeTarget.STATIC)
public static double __parseFloat(Arguments args) {
return args.getDouble(0);
}
@Expose(target = ExposeTarget.STATIC)
public static double __parseInt(Arguments args) {
var radix = args.getInt(1, 10);
if (radix < 2 || radix > 36) return Double.NaN;
else {
long res = 0;
for (var c : args.getString(0).toCharArray()) {
var digit = 0;
if (c >= '0' && c <= '9') digit = c - '0';
else if (c >= 'a' && c <= 'z') digit = c - 'a' + 10;
else if (c >= 'A' && c <= 'Z') digit = c - 'A' + 10;
else break;
if (digit > radix) break;
res *= radix;
res += digit;
}
return res;
}
}
@ExposeConstructor public static Object __constructor(Arguments args) {
if (args.self instanceof ObjectValue) return new NumberLib(args.getDouble(0));
else return args.getDouble(0);
}
@Expose public static String __toString(Arguments args) {
return Values.toString(args.ctx, args.self);
}
@Expose public static double __valueOf(Arguments args) {
if (Values.isWrapper(args.self, NumberLib.class)) return Values.wrapper(args.self, NumberLib.class).value;
else return Values.toNumber(args.ctx, args.self);
}
}

View File

@@ -1,273 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Symbol;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Object")
public class ObjectLib {
@Expose(target = ExposeTarget.STATIC)
public static Object __assign(Arguments args) {
for (var obj : args.slice(1).args) {
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
Values.setMember(args.ctx, args.get(0), key, Values.getMember(args.ctx, obj, key));
}
}
return args.get(0);
}
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __create(Arguments args) {
var obj = new ObjectValue();
Values.setPrototype(args.ctx, obj, args.get(0));
if (args.n() >= 1) {
var newArgs = new Object[args.n()];
System.arraycopy(args.args, 1, args, 1, args.n() - 1);
newArgs[0] = obj;
__defineProperties(new Arguments(args.ctx, null, newArgs));
}
return obj;
}
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __defineProperty(Arguments args) {
var obj = args.convert(0, ObjectValue.class);
var key = args.get(1);
var attrib = args.convert(2, ObjectValue.class);
var hasVal = Values.hasMember(args.ctx, attrib, "value", false);
var hasGet = Values.hasMember(args.ctx, attrib, "get", false);
var hasSet = Values.hasMember(args.ctx, attrib, "set", false);
if (hasVal) {
if (hasGet || hasSet) throw EngineException.ofType("Cannot specify a value and accessors for a property.");
if (!obj.defineProperty(
args.ctx, key,
Values.getMember(args.ctx, attrib, "value"),
Values.toBoolean(Values.getMember(args.ctx, attrib, "writable")),
Values.toBoolean(Values.getMember(args.ctx, attrib, "configurable")),
Values.toBoolean(Values.getMember(args.ctx, attrib, "enumerable"))
)) throw EngineException.ofType("Can't define property '" + key + "'.");
}
else {
var get = Values.getMember(args.ctx, attrib, "get");
var set = Values.getMember(args.ctx, attrib, "set");
if (get != null && !(get instanceof FunctionValue)) throw EngineException.ofType("Get accessor must be a function.");
if (set != null && !(set instanceof FunctionValue)) throw EngineException.ofType("Set accessor must be a function.");
if (!obj.defineProperty(
args.ctx, key,
(FunctionValue)get, (FunctionValue)set,
Values.toBoolean(Values.getMember(args.ctx, attrib, "configurable")),
Values.toBoolean(Values.getMember(args.ctx, attrib, "enumerable"))
)) throw EngineException.ofType("Can't define property '" + key + "'.");
}
return obj;
}
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __defineProperties(Arguments args) {
var obj = args.convert(0, ObjectValue.class);
var attrib = args.get(1);
for (var key : Values.getMembers(null, attrib, false, false)) {
__defineProperty(new Arguments(args.ctx, null, obj, key, Values.getMember(args.ctx, attrib, key)));
}
return obj;
}
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __keys(Arguments args) {
var obj = args.get(0);
var all = args.getBoolean(1);
var res = new ArrayValue();
for (var key : Values.getMembers(args.ctx, obj, true, false)) {
if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), key);
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __entries(Arguments args) {
var res = new ArrayValue();
var obj = args.get(0);
var all = args.getBoolean(1);
for (var key : Values.getMembers(args.ctx, obj, true, false)) {
if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), new ArrayValue(args.ctx, key, Values.getMember(args.ctx, obj, key)));
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __values(Arguments args) {
var res = new ArrayValue();
var obj = args.get(0);
var all = args.getBoolean(1);
for (var key : Values.getMembers(args.ctx, obj, true, false)) {
if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), Values.getMember(args.ctx, obj, key));
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __getOwnPropertyDescriptor(Arguments args) {
return Values.getMemberDescriptor(args.ctx, args.get(0), args.get(1));
}
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __getOwnPropertyDescriptors(Arguments args) {
var res = new ObjectValue();
var obj = args.get(0);
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
res.defineProperty(args.ctx, key, Values.getMemberDescriptor(args.ctx, obj, key));
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __getOwnPropertyNames(Arguments args) {
var res = new ArrayValue();
var obj = args.get(0);
var all = args.getBoolean(1);
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), key);
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __getOwnPropertySymbols(Arguments args) {
var obj = args.get(0);
var res = new ArrayValue();
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
if (key instanceof Symbol) res.set(args.ctx, res.size(), key);
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static boolean __hasOwn(Arguments args) {
return Values.hasMember(args.ctx, args.get(0), args.get(1), true);
}
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __getPrototypeOf(Arguments args) {
return Values.getPrototype(args.ctx, args.get(0));
}
@Expose(target = ExposeTarget.STATIC)
public static Object __setPrototypeOf(Arguments args) {
Values.setPrototype(args.ctx, args.get(0), args.get(1));
return args.get(0);
}
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __fromEntries(Arguments args) {
var res = new ObjectValue();
for (var el : Values.fromJSIterator(args.ctx, args.get(0))) {
if (el instanceof ArrayValue) {
res.defineProperty(args.ctx, ((ArrayValue)el).get(0), ((ArrayValue)el).get(1));
}
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static Object __preventExtensions(Arguments args) {
if (args.get(0) instanceof ObjectValue) args.convert(0, ObjectValue.class).preventExtensions();
return args.get(0);
}
@Expose(target = ExposeTarget.STATIC)
public static Object __seal(Arguments args) {
if (args.get(0) instanceof ObjectValue) args.convert(0, ObjectValue.class).seal();
return args.get(0);
}
@Expose(target = ExposeTarget.STATIC)
public static Object __freeze(Arguments args) {
if (args.get(0) instanceof ObjectValue) args.convert(0, ObjectValue.class).freeze();
return args.get(0);
}
@Expose(target = ExposeTarget.STATIC)
public static boolean __isExtensible(Arguments args) {
var obj = args.get(0);
if (!(obj instanceof ObjectValue)) return false;
return ((ObjectValue)obj).extensible();
}
@Expose(target = ExposeTarget.STATIC)
public static boolean __isSealed(Arguments args) {
var obj = args.get(0);
if (!(obj instanceof ObjectValue)) return true;
var _obj = (ObjectValue)obj;
if (_obj.extensible()) return false;
for (var key : _obj.keys(true)) {
if (_obj.memberConfigurable(key)) return false;
}
return true;
}
@Expose(target = ExposeTarget.STATIC)
public static boolean __isFrozen(Arguments args) {
var obj = args.get(0);
if (!(obj instanceof ObjectValue)) return true;
var _obj = (ObjectValue)obj;
if (_obj.extensible()) return false;
for (var key : _obj.keys(true)) {
if (_obj.memberConfigurable(key)) return false;
if (_obj.memberWritable(key)) return false;
}
return true;
}
@Expose
public static Object __valueOf(Arguments args) {
return args.self;
}
@Expose
public static String __toString(Arguments args) {
var name = Values.getMember(args.ctx, args.self, Symbol.get("Symbol.typeName"));
if (name == null) name = "Unknown";
else name = Values.toString(args.ctx, name);
return "[object " + name + "]";
}
@Expose
public static boolean __hasOwnProperty(Arguments args) {
return Values.hasMember(args.ctx, args.self, args.get(0), true);
}
@ExposeConstructor
public static Object __constructor(Arguments args) {
var arg = args.get(0);
if (arg == null || arg == Values.NULL) return new ObjectValue();
else if (arg instanceof Boolean) return new BooleanLib((boolean)arg);
else if (arg instanceof Number) return new NumberLib(((Number)arg).doubleValue());
else if (arg instanceof String) return new StringLib((String)arg);
else if (arg instanceof Symbol) return new SymbolLib((Symbol)arg);
else return arg;
}
}

View File

@@ -1,404 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.ArrayList;
import java.util.List;
import me.topchetoeu.jscript.common.ResultRunnable;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.EventLoop;
import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeFunction;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Promise")
public class PromiseLib {
public static interface Handle {
void onFulfil(Object val);
void onReject(EngineException err);
default Handle defer(Extensions loop) {
var self = this;
return new Handle() {
@Override public void onFulfil(Object val) {
if (!loop.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
loop.get(EventLoop.KEY).pushMsg(() -> self.onFulfil(val), true);
}
@Override public void onReject(EngineException val) {
if (!loop.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
loop.get(EventLoop.KEY).pushMsg(() -> self.onReject(val), true);
}
};
}
}
private static final int STATE_PENDING = 0;
private static final int STATE_FULFILLED = 1;
private static final int STATE_REJECTED = 2;
private List<Handle> handles = new ArrayList<>();
private int state = STATE_PENDING;
private boolean handled = false;
private Object val;
private void resolveSynchronized(Context ctx, Object val, int newState) {
this.val = val;
this.state = newState;
for (var handle : handles) {
if (newState == STATE_FULFILLED) handle.onFulfil(val);
if (newState == STATE_REJECTED) {
handle.onReject((EngineException)val);
handled = true;
}
}
if (state == STATE_REJECTED && !handled) {
Values.printError(((EngineException)val).setCtx(ctx), "(in promise)");
}
handles = null;
// ctx.get(EventLoop.KEY).pushMsg(() -> {
// if (!ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
// handles = null;
// }, true);
}
private synchronized void resolve(Context ctx, Object val, int newState) {
if (this.state != STATE_PENDING || newState == STATE_PENDING) return;
handle(ctx, val, new Handle() {
@Override public void onFulfil(Object val) {
resolveSynchronized(ctx, val, newState);
}
@Override public void onReject(EngineException err) {
resolveSynchronized(ctx, val, STATE_REJECTED);
}
});
}
public synchronized void fulfill(Context ctx, Object val) {
resolve(ctx, val, STATE_FULFILLED);
}
public synchronized void reject(Context ctx, EngineException val) {
resolve(ctx, val, STATE_REJECTED);
}
private void handle(Handle handle) {
if (state == STATE_FULFILLED) handle.onFulfil(val);
else if (state == STATE_REJECTED) {
handle.onReject((EngineException)val);
handled = true;
}
else handles.add(handle);
}
@Override public String toString() {
if (state == STATE_PENDING) return "Promise (pending)";
else if (state == STATE_FULFILLED) return "Promise (fulfilled)";
else return "Promise (rejected)";
}
public PromiseLib() {
this.state = STATE_PENDING;
this.val = null;
}
public static PromiseLib await(Context ctx, ResultRunnable<Object> runner) {
var res = new PromiseLib();
new Thread(() -> {
try {
res.fulfill(ctx, runner.run());
}
catch (EngineException e) {
res.reject(ctx, e);
}
catch (Exception e) {
if (e instanceof InterruptException) throw e;
else {
res.reject(ctx, EngineException.ofError("Native code failed with " + e.getMessage()));
}
}
}, "Promisifier").start();
return res;
}
public static PromiseLib await(Context ctx, Runnable runner) {
return await(ctx, () -> {
runner.run();
return null;
});
}
public static void handle(Context ctx, Object obj, Handle handle) {
if (Values.isWrapper(obj, PromiseLib.class)) {
var promise = Values.wrapper(obj, PromiseLib.class);
handle(ctx, promise, handle);
return;
}
if (obj instanceof PromiseLib) {
((PromiseLib)obj).handle(handle);
return;
}
var rethrow = new boolean[1];
try {
var then = Values.getMember(ctx, obj, "then");
if (then instanceof FunctionValue) Values.call(ctx, then, obj,
new NativeFunction(args -> {
try { handle.onFulfil(args.get(0)); }
catch (Exception e) {
rethrow[0] = true;
throw e;
}
return null;
}),
new NativeFunction(args -> {
try { handle.onReject(new EngineException(args.get(0))); }
catch (Exception e) {
rethrow[0] = true;
throw e;
}
return null;
})
);
else handle.onFulfil(obj);
return;
}
catch (Exception e) {
if (rethrow[0]) throw e;
}
handle.onFulfil(obj);
}
public static PromiseLib ofResolved(Context ctx, Object value) {
var res = new PromiseLib();
res.fulfill(ctx, value);
return res;
}
public static PromiseLib ofRejected(Context ctx, EngineException value) {
var res = new PromiseLib();
res.reject(ctx, value);
return res;
}
@Expose(value = "resolve", target = ExposeTarget.STATIC)
public static PromiseLib __ofResolved(Arguments args) {
return ofResolved(args.ctx, args.get(0));
}
@Expose(value = "reject", target = ExposeTarget.STATIC)
public static PromiseLib __ofRejected(Arguments args) {
return ofRejected(args.ctx, new EngineException(args.get(0)).setCtx(args.ctx));
}
@Expose(target = ExposeTarget.STATIC)
public static PromiseLib __any(Arguments args) {
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = args.convert(0, ArrayValue.class);
if (promises.size() == 0) return ofRejected(args.ctx, EngineException.ofError("No promises passed to 'Promise.any'.").setCtx(args.ctx));
var n = new int[] { promises.size() };
var res = new PromiseLib();
var errors = new ArrayValue();
for (var i = 0; i < promises.size(); i++) {
var index = i;
var val = promises.get(i);
if (res.state != STATE_PENDING) break;
handle(args.ctx, val, new Handle() {
public void onFulfil(Object val) { res.fulfill(args.ctx, val); }
public void onReject(EngineException err) {
errors.set(args.ctx, index, err.value);
n[0]--;
if (n[0] <= 0) res.reject(args.ctx, new EngineException(errors).setCtx(args.ctx));
}
});
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static PromiseLib __race(Arguments args) {
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = args.convert(0, ArrayValue.class);
var res = new PromiseLib();
for (var i = 0; i < promises.size(); i++) {
var val = promises.get(i);
if (res.state != STATE_PENDING) break;
handle(args.ctx, val, new Handle() {
@Override public void onFulfil(Object val) { res.fulfill(args.ctx, val); }
@Override public void onReject(EngineException err) { res.reject(args.ctx, err); }
});
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static PromiseLib __all(Arguments args) {
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = args.convert(0, ArrayValue.class);
var n = new int[] { promises.size() };
var res = new PromiseLib();
var result = new ArrayValue();
for (var i = 0; i < promises.size(); i++) {
if (res.state != STATE_PENDING) break;
var index = i;
var val = promises.get(i);
handle(args.ctx, val, new Handle() {
@Override public void onFulfil(Object val) {
result.set(args.ctx, index, val);
n[0]--;
if (n[0] <= 0) res.fulfill(args.ctx, result);
}
@Override public void onReject(EngineException err) {
res.reject(args.ctx, err);
}
});
}
if (n[0] <= 0) res.fulfill(args.ctx, result);
return res;
}
@Expose(target = ExposeTarget.STATIC)
public static PromiseLib __allSettled(Arguments args) {
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = args.convert(0, ArrayValue.class);
var n = new int[] { promises.size() };
var res = new PromiseLib();
var result = new ArrayValue();
for (var i = 0; i < promises.size(); i++) {
if (res.state != STATE_PENDING) break;
var index = i;
handle(args.ctx, promises.get(i), new Handle() {
@Override public void onFulfil(Object val) {
var desc = new ObjectValue();
desc.defineProperty(args.ctx, "status", "fulfilled");
desc.defineProperty(args.ctx, "value", val);
result.set(args.ctx, index, desc);
n[0]--;
if (n[0] <= 0) res.fulfill(args.ctx, res);
}
@Override public void onReject(EngineException err) {
var desc = new ObjectValue();
desc.defineProperty(args.ctx, "status", "reject");
desc.defineProperty(args.ctx, "value", err.value);
result.set(args.ctx, index, desc);
n[0]--;
if (n[0] <= 0) res.fulfill(args.ctx, res);
}
});
}
if (n[0] <= 0) res.fulfill(args.ctx, result);
return res;
}
@Expose
public static Object __then(Arguments args) {
var onFulfill = args.get(0) instanceof FunctionValue ? args.convert(0, FunctionValue.class) : null;
var onReject = args.get(1) instanceof FunctionValue ? args.convert(1, FunctionValue.class) : null;
var res = new PromiseLib();
handle(args.ctx, args.self, new Handle() {
@Override public void onFulfil(Object val) {
try { res.fulfill(args.ctx, onFulfill.call(args.ctx, null, val)); }
catch (EngineException e) { res.reject(args.ctx, e); }
}
@Override public void onReject(EngineException err) {
try { res.fulfill(args.ctx, onReject.call(args.ctx, null, err.value)); }
catch (EngineException e) { res.reject(args.ctx, e); }
}
}.defer(args.ctx));
return res;
}
@Expose
public static Object __catch(Arguments args) {
return __then(new Arguments(args.ctx, args.self, null, args.get(0)));
}
@Expose
public static Object __finally(Arguments args) {
var func = args.get(0) instanceof FunctionValue ? args.convert(0, FunctionValue.class) : null;
var res = new PromiseLib();
handle(args.ctx, args.self, new Handle() {
@Override public void onFulfil(Object val) {
try {
func.call(args.ctx);
res.fulfill(args.ctx, val);
}
catch (EngineException e) { res.reject(args.ctx, e); }
}
@Override public void onReject(EngineException err) {
try {
func.call(args.ctx);
res.reject(args.ctx, err);
}
catch (EngineException e) { res.reject(args.ctx, e); }
}
}.defer(args.ctx));
return res;
}
@ExposeConstructor
public static PromiseLib __constructor(Arguments args) {
var func = args.convert(0, FunctionValue.class);
var res = new PromiseLib();
try {
func.call(
args.ctx, null,
new NativeFunction(null, _args -> {
res.fulfill(_args.ctx, _args.get(0));
return null;
}),
new NativeFunction(null, _args -> {
res.reject(_args.ctx, new EngineException(_args.get(0)).setCtx(_args.ctx));
return null;
})
);
}
catch (EngineException e) {
res.reject(args.ctx, e);
}
return res;
}
}

View File

@@ -1,19 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeField;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("RangeError")
public class RangeErrorLib extends ErrorLib {
@ExposeField public static final String __name = "RangeError";
@ExposeConstructor public static ObjectValue constructor(Arguments args) {
var target = ErrorLib.__constructor(args);
target.setPrototype(PlaceholderProto.RANGE_ERROR);
return target;
}
}

View File

@@ -1,354 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Pattern;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.NativeWrapper;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.ExposeType;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("RegExp")
public class RegExpLib {
// I used Regex to analyze Regex
private static final Pattern NAMED_PATTERN = Pattern.compile("\\(\\?<([^=!].*?)>", Pattern.DOTALL);
private static final Pattern ESCAPE_PATTERN = Pattern.compile("[/\\-\\\\^$*+?.()|\\[\\]{}]");
private Pattern pattern;
private String[] namedGroups;
private int flags;
public int lastI = 0;
public final String source;
public final boolean hasIndices;
public final boolean global;
public final boolean sticky;
@Expose(type = ExposeType.GETTER)
public int __lastIndex() { return lastI; }
@Expose(type = ExposeType.SETTER)
public void __setLastIndex(Arguments args) { lastI = args.getInt(0); }
@Expose(type = ExposeType.GETTER)
public String __source() { return source; }
@Expose(type = ExposeType.GETTER)
public boolean __ignoreCase() { return (flags & Pattern.CASE_INSENSITIVE) != 0; }
@Expose(type = ExposeType.GETTER)
public boolean __multiline() { return (flags & Pattern.MULTILINE) != 0; }
@Expose(type = ExposeType.GETTER)
public boolean __unicode() { return (flags & Pattern.UNICODE_CHARACTER_CLASS) != 0; }
@Expose(type = ExposeType.GETTER)
public boolean __dotAll() { return (flags & Pattern.DOTALL) != 0; }
@Expose(type = ExposeType.GETTER)
public boolean __global() { return global; }
@Expose(type = ExposeType.GETTER)
public boolean __sticky() { return sticky; }
@Expose(type = ExposeType.GETTER)
public final String __flags() {
String res = "";
if (hasIndices) res += 'd';
if (global) res += 'g';
if (__ignoreCase()) res += 'i';
if (__multiline()) res += 'm';
if (__dotAll()) res += 's';
if (__unicode()) res += 'u';
if (sticky) res += 'y';
return res;
}
@Expose public Object __exec(Arguments args) {
var str = args.getString(0);
var matcher = pattern.matcher(str);
if (lastI > str.length() || !matcher.find(lastI) || sticky && matcher.start() != lastI) {
lastI = 0;
return Values.NULL;
}
if (sticky || global) {
lastI = matcher.end();
if (matcher.end() == matcher.start()) lastI++;
}
var obj = new ArrayValue();
ObjectValue groups = null;
for (var el : namedGroups) {
if (groups == null) groups = new ObjectValue();
try { groups.defineProperty(null, el, matcher.group(el)); }
catch (IllegalArgumentException e) { }
}
for (int i = 0; i < matcher.groupCount() + 1; i++) {
obj.set(null, i, matcher.group(i));
}
obj.defineProperty(null, "groups", groups);
obj.defineProperty(null, "index", matcher.start());
obj.defineProperty(null, "input", str);
if (hasIndices) {
var indices = new ArrayValue();
for (int i = 0; i < matcher.groupCount() + 1; i++) {
indices.set(null, i, new ArrayValue(null, matcher.start(i), matcher.end(i)));
}
var groupIndices = new ObjectValue();
for (var el : namedGroups) {
groupIndices.defineProperty(null, el, new ArrayValue(null, matcher.start(el), matcher.end(el)));
}
indices.defineProperty(null, "groups", groupIndices);
obj.defineProperty(null, "indices", indices);
}
return obj;
}
@Expose public boolean __test(Arguments args) {
return this.__exec(args) != Values.NULL;
}
@Expose("@@Symbol.match") public Object __match(Arguments args) {
if (this.global) {
var res = new ArrayValue();
Object val;
while ((val = this.__exec(args)) != Values.NULL) {
res.set(args.ctx, res.size(), Values.getMember(args.ctx, val, 0));
}
lastI = 0;
return res;
}
else {
var res = this.__exec(args);
if (!this.sticky) this.lastI = 0;
return res;
}
}
@Expose("@@Symbol.matchAll") public Object __matchAll(Arguments args) {
var pattern = this.toGlobal();
return Values.toJSIterator(args.ctx, new Iterator<Object>() {
private Object val = null;
private boolean updated = false;
private void update() {
if (!updated) val = pattern.__exec(args);
}
@Override public boolean hasNext() {
update();
return val != Values.NULL;
}
@Override public Object next() {
update();
updated = false;
return val;
}
});
}
@Expose("@@Symbol.split") public ArrayValue __split(Arguments args) {
var pattern = this.toGlobal();
var target = args.getString(0);
var hasLimit = args.get(1) != null;
var lim = args.getInt(1);
var sensible = args.getBoolean(2);
Object match;
int lastEnd = 0;
var res = new ArrayValue();
while ((match = pattern.__exec(args)) != Values.NULL) {
var added = new ArrayList<String>();
var arrMatch = (ArrayValue)match;
int index = (int)Values.toNumber(args.ctx, Values.getMember(args.ctx, match, "index"));
var matchVal = (String)arrMatch.get(0);
if (index >= target.length()) break;
if (matchVal.length() == 0 || index - lastEnd > 0) {
added.add(target.substring(lastEnd, pattern.lastI));
if (pattern.lastI < target.length()) {
for (var i = 1; i < arrMatch.size(); i++) added.add((String)arrMatch.get(i));
}
}
else {
for (var i = 1; i < arrMatch.size(); i++) added.add((String)arrMatch.get(i));
}
if (sensible) {
if (hasLimit && res.size() + added.size() >= lim) break;
else for (var i = 0; i < added.size(); i++) res.set(args.ctx, res.size(), added.get(i));
}
else {
for (var i = 0; i < added.size(); i++) {
if (hasLimit && res.size() >= lim) return res;
else res.set(args.ctx, res.size(), added.get(i));
}
}
lastEnd = pattern.lastI;
}
if (lastEnd < target.length()) {
res.set(args.ctx, res.size(), target.substring(lastEnd));
}
return res;
}
@Expose("@@Symbol.replace") public String __replace(Arguments args) {
var pattern = this.toIndexed();
var target = args.getString(0);
var replacement = args.get(1);
Object match;
var lastEnd = 0;
var res = new StringBuilder();
while ((match = pattern.__exec(args)) != Values.NULL) {
var indices = (ArrayValue)((ArrayValue)Values.getMember(args.ctx, match, "indices")).get(0);
var arrMatch = (ArrayValue)match;
var start = ((Number)indices.get(0)).intValue();
var end = ((Number)indices.get(1)).intValue();
res.append(target.substring(lastEnd, start));
if (replacement instanceof FunctionValue) {
var callArgs = new Object[arrMatch.size() + 2];
callArgs[0] = target.substring(start, end);
arrMatch.copyTo(callArgs, 1, 1, arrMatch.size() - 1);
callArgs[callArgs.length - 2] = start;
callArgs[callArgs.length - 1] = target;
res.append(Values.toString(args.ctx, ((FunctionValue)replacement).call(args.ctx, null, callArgs)));
}
else {
res.append(Values.toString(args.ctx, replacement));
}
lastEnd = end;
if (!pattern.global) break;
}
if (lastEnd < target.length()) {
res.append(target.substring(lastEnd));
}
return res.toString();
}
// [Symbol.search](target, reverse, start) {
// const pattern: RegExp | undefined = new this.constructor(this, this.flags + "g") as RegExp;
// if (!reverse) {
// pattern.lastIndex = (start as any) | 0;
// const res = pattern.exec(target);
// if (res) return res.index;
// else return -1;
// }
// else {
// start ??= target.length;
// start |= 0;
// let res: RegExpResult | null = null;
// while (true) {
// const tmp = pattern.exec(target);
// if (tmp === null || tmp.index > start) break;
// res = tmp;
// }
// if (res && res.index <= start) return res.index;
// else return -1;
// }
// },
public RegExpLib toGlobal() {
return new RegExpLib(pattern, namedGroups, flags, source, hasIndices, true, sticky);
}
public RegExpLib toIndexed() {
return new RegExpLib(pattern, namedGroups, flags, source, true, global, sticky);
}
public String toString() {
return "/" + source + "/" + __flags();
}
public RegExpLib(String pattern, String flags) {
if (pattern == null || pattern.equals("")) pattern = "(?:)";
if (flags == null || flags.equals("")) flags = "";
this.flags = 0;
this.hasIndices = flags.contains("d");
this.global = flags.contains("g");
this.sticky = flags.contains("y");
this.source = pattern;
if (flags.contains("i")) this.flags |= Pattern.CASE_INSENSITIVE;
if (flags.contains("m")) this.flags |= Pattern.MULTILINE;
if (flags.contains("s")) this.flags |= Pattern.DOTALL;
if (flags.contains("u")) this.flags |= Pattern.UNICODE_CHARACTER_CLASS;
if (pattern.equals("{(\\d+)}")) pattern = "\\{([0-9]+)\\}";
this.pattern = Pattern.compile(pattern.replace("\\d", "[0-9]"), this.flags);
var matcher = NAMED_PATTERN.matcher(source);
var groups = new ArrayList<String>();
while (matcher.find()) {
if (!checkEscaped(source, matcher.start() - 1)) {
groups.add(matcher.group(1));
}
}
namedGroups = groups.toArray(String[]::new);
}
private RegExpLib(Pattern pattern, String[] namedGroups, int flags, String source, boolean hasIndices, boolean global, boolean sticky) {
this.pattern = pattern;
this.namedGroups = namedGroups;
this.flags = flags;
this.source = source;
this.hasIndices = hasIndices;
this.global = global;
this.sticky = sticky;
}
public RegExpLib(String pattern) { this(pattern, null); }
public RegExpLib() { this(null, null); }
@ExposeConstructor
public static RegExpLib __constructor(Arguments args) {
return new RegExpLib(cleanupPattern(args.ctx, args.get(0)), cleanupFlags(args.ctx, args.get(1)));
}
@Expose(target = ExposeTarget.STATIC)
public static RegExpLib __escape(Arguments args) {
return escape(Values.toString(args.ctx, args.get(0)), cleanupFlags(args.ctx, args.get(1)));
}
private static String cleanupPattern(Context ctx, Object val) {
if (val == null) return "(?:)";
if (val instanceof RegExpLib) return ((RegExpLib)val).source;
if (val instanceof NativeWrapper && ((NativeWrapper)val).wrapped instanceof RegExpLib) {
return ((RegExpLib)((NativeWrapper)val).wrapped).source;
}
var res = Values.toString(ctx, val);
if (res.equals("")) return "(?:)";
return res;
}
private static String cleanupFlags(Context ctx, Object val) {
if (val == null) return "";
return Values.toString(ctx, val);
}
private static boolean checkEscaped(String s, int pos) {
int n = 0;
while (true) {
if (pos <= 0) break;
if (s.charAt(pos) != '\\') break;
n++;
pos--;
}
return (n % 2) != 0;
}
public static RegExpLib escape(String raw, String flags) {
return new RegExpLib(ESCAPE_PATTERN.matcher(raw).replaceAll("\\\\$0"), flags);
}
}

View File

@@ -1,69 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.stream.Collectors;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeType;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Set")
public class SetLib {
private LinkedHashSet<Object> set = new LinkedHashSet<>();
@Expose("@@Symbol.iterator")
public ObjectValue __iterator(Arguments args) {
return this.__values(args);
}
@Expose public ObjectValue __entries(Arguments args) {
return Values.toJSIterator(args.ctx, set.stream().map(v -> new ArrayValue(args.ctx, v, v)).collect(Collectors.toList()));
}
@Expose public ObjectValue __keys(Arguments args) {
return Values.toJSIterator(args.ctx, set);
}
@Expose public ObjectValue __values(Arguments args) {
return Values.toJSIterator(args.ctx, set);
}
@Expose public Object __add(Arguments args) {
return set.add(args.get(0));
}
@Expose public boolean __delete(Arguments args) {
return set.remove(args.get(0));
}
@Expose public boolean __has(Arguments args) {
return set.contains(args.get(0));
}
@Expose public void __clear() {
set.clear();
}
@Expose(type = ExposeType.GETTER)
public int __size() {
return set.size();
}
@Expose public void __forEach(Arguments args) {
var keys = new ArrayList<>(set);
for (var el : keys) Values.call(args.ctx, args.get(0), args.get(1), el, el, args.self);
}
public SetLib(Context ctx, Object iterable) {
for (var el : Values.fromJSIterator(ctx, iterable)) set.add(el);
}
@ExposeConstructor
public static SetLib __constructor(Arguments args) {
return new SetLib(args.ctx, args.get(0));
}
}

View File

@@ -1,291 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.regex.Pattern;
import me.topchetoeu.jscript.runtime.Environment;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.ArrayValue;
import me.topchetoeu.jscript.runtime.values.FunctionValue;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Symbol;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.ExposeType;
import me.topchetoeu.jscript.utils.interop.WrapperName;
// TODO: implement index wrapping properly
@WrapperName("String")
public class StringLib {
public final String value;
@Override public String toString() { return value; }
public StringLib(String val) {
this.value = val;
}
private static String passThis(Arguments args, String funcName) {
var val = args.self;
if (Values.isWrapper(val, StringLib.class)) return Values.wrapper(val, StringLib.class).value;
else if (val instanceof String) return (String)val;
else throw EngineException.ofType(String.format("'%s' may only be called upon object and primitve strings.", funcName));
}
private static int normalizeI(int i, int len, boolean clamp) {
if (i < 0) i += len;
if (clamp) {
if (i < 0) i = 0;
if (i > len) i = len;
}
return i;
}
@Expose(type = ExposeType.GETTER)
public static int __length(Arguments args) {
return passThis(args, "length").length();
}
@Expose public static String __substring(Arguments args) {
var val = passThis(args, "substring");
var start = Math.max(0, Math.min(val.length(), args.getInt(0)));
var end = Math.max(0, Math.min(val.length(), args.getInt(1, val.length())));
if (end < start) {
var tmp = end;
end = start;
start = tmp;
}
return val.substring(start, end);
}
@Expose public static String __substr(Arguments args) {
var val = passThis(args, "substr");
var start = normalizeI(args.getInt(0), val.length(), true);
int end = normalizeI(args.getInt(1, val.length() - start) + start, val.length(), true);
return val.substring(start, end);
}
@Expose public static String __toLowerCase(Arguments args) {
return passThis(args, "toLowerCase").toLowerCase();
}
@Expose public static String __toUpperCase(Arguments args) {
return passThis(args, "toUpperCase").toUpperCase();
}
@Expose public static String __charAt(Arguments args) {
return passThis(args, "charAt").charAt(args.getInt(0)) + "";
}
@Expose public static double __charCodeAt(Arguments args) {
var str = passThis(args, "charCodeAt");
var i = args.getInt(0);
if (i < 0 || i >= str.length()) return Double.NaN;
else return str.charAt(i);
}
@Expose public static double __codePointAt(Arguments args) {
var str = passThis(args, "codePointAt");
var i = args.getInt(0);
if (i < 0 || i >= str.length()) return Double.NaN;
else return str.codePointAt(i);
}
@Expose public static boolean __startsWith(Arguments args) {
return passThis(args, "startsWith").startsWith(args.getString(0), args.getInt(1));
}
@Expose public static boolean __endsWith(Arguments args) {
return passThis(args, "endsWith").lastIndexOf(args.getString(0), args.getInt(1)) >= 0;
}
@Expose public static int __indexOf(Arguments args) {
var val = passThis(args, "indexOf");
var term = args.get(0);
var start = args.getInt(1);
var search = Values.getMember(args.ctx, term, Symbol.get("Symbol.search"));
if (search instanceof FunctionValue) {
return (int)Values.toNumber(args.ctx, Values.call(args.ctx, search, term, val, false, start));
}
else return val.indexOf(Values.toString(args.ctx, term), start);
}
@Expose public static int __lastIndexOf(Arguments args) {
var val = passThis(args, "lastIndexOf");
var term = args.get(0);
var start = args.getInt(1);
var search = Values.getMember(args.ctx, term, Symbol.get("Symbol.search"));
if (search instanceof FunctionValue) {
return (int)Values.toNumber(args.ctx, Values.call(args.ctx, search, term, val, true, start));
}
else return val.lastIndexOf(Values.toString(args.ctx, term), start);
}
@Expose public static boolean __includes(Arguments args) {
return __indexOf(args) >= 0;
}
@Expose public static String __replace(Arguments args) {
var val = passThis(args, "replace");
var term = args.get(0);
var replacement = args.get(1);
var replace = Values.getMember(args.ctx, term, Symbol.get("Symbol.replace"));
if (replace instanceof FunctionValue) {
return Values.toString(args.ctx, Values.call(args.ctx, replace, term, val, replacement));
}
else return val.replaceFirst(Pattern.quote(Values.toString(args.ctx, term)), Values.toString(args.ctx, replacement));
}
@Expose public static String __replaceAll(Arguments args) {
var val = passThis(args, "replaceAll");
var term = args.get(0);
var replacement = args.get(1);
var replace = Values.getMember(args.ctx, term, Symbol.get("Symbol.replace"));
if (replace instanceof FunctionValue) {
return Values.toString(args.ctx, Values.call(args.ctx, replace, term, val, replacement));
}
else return val.replace(Values.toString(args.ctx, term), Values.toString(args.ctx, replacement));
}
@Expose public static ArrayValue __match(Arguments args) {
var val = passThis(args, "match");
var term = args.get(0);
FunctionValue match;
try {
var _match = Values.getMember(args.ctx, term, Symbol.get("Symbol.match"));
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
else if (args.ctx.hasNotNull(Environment.REGEX_CONSTR)) {
var regex = Values.callNew(args.ctx, args.ctx.get(Environment.REGEX_CONSTR), Values.toString(args.ctx, term), "");
_match = Values.getMember(args.ctx, regex, Symbol.get("Symbol.match"));
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
else throw EngineException.ofError("Regular expressions don't support matching.");
}
else throw EngineException.ofError("Regular expressions not supported.");
}
catch (IllegalArgumentException e) { return new ArrayValue(args.ctx, ""); }
var res = match.call(args.ctx, term, val);
if (res instanceof ArrayValue) return (ArrayValue)res;
else return new ArrayValue(args.ctx, "");
}
@Expose public static Object __matchAll(Arguments args) {
var val = passThis(args, "matchAll");
var term = args.get(0);
FunctionValue match = null;
try {
var _match = Values.getMember(args.ctx, term, Symbol.get("Symbol.matchAll"));
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
}
catch (IllegalArgumentException e) { }
if (match == null && args.ctx.hasNotNull(Environment.REGEX_CONSTR)) {
var regex = Values.callNew(args.ctx, args.ctx.get(Environment.REGEX_CONSTR), Values.toString(args.ctx, term), "g");
var _match = Values.getMember(args.ctx, regex, Symbol.get("Symbol.matchAll"));
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
else throw EngineException.ofError("Regular expressions don't support matching.");
}
else throw EngineException.ofError("Regular expressions not supported.");
return match.call(args.ctx, term, val);
}
@Expose public static ArrayValue __split(Arguments args) {
var val = passThis(args, "split");
var term = args.get(0);
var lim = args.get(1);
var sensible = args.getBoolean(2);
if (lim != null) lim = Values.toNumber(args.ctx, lim);
if (term != null && term != Values.NULL && !(term instanceof String)) {
var replace = Values.getMember(args.ctx, term, Symbol.get("Symbol.replace"));
if (replace instanceof FunctionValue) {
var tmp = ((FunctionValue)replace).call(args.ctx, term, val, lim, sensible);
if (tmp instanceof ArrayValue) {
var parts = new ArrayValue(((ArrayValue)tmp).size());
for (int i = 0; i < parts.size(); i++) parts.set(args.ctx, i, Values.toString(args.ctx, ((ArrayValue)tmp).get(i)));
return parts;
}
}
}
String[] parts;
var pattern = Pattern.quote(Values.toString(args.ctx, term));
if (lim == null) parts = val.split(pattern);
else if ((double)lim < 1) return new ArrayValue();
else if (sensible) parts = val.split(pattern, (int)(double)lim);
else {
var limit = (int)(double)lim;
parts = val.split(pattern, limit + 1);
ArrayValue res;
if (parts.length > limit) res = new ArrayValue(limit);
else res = new ArrayValue(parts.length);
for (var i = 0; i < parts.length && i < limit; i++) res.set(args.ctx, i, parts[i]);
return res;
}
var res = new ArrayValue(parts.length);
var i = 0;
for (; i < parts.length; i++) {
if (lim != null && (double)lim <= i) break;
res.set(args.ctx, i, parts[i]);
}
return res;
}
@Expose public static String __slice(Arguments args) {
var self = passThis(args, "slice");
var start = normalizeI(args.getInt(0), self.length(), false);
var end = normalizeI(args.getInt(1, self.length()), self.length(), false);
return __substring(new Arguments(args.ctx, self, start, end));
}
@Expose public static String __concat(Arguments args) {
var res = new StringBuilder(passThis(args, "concat"));
for (var el : args.convert(String.class)) res.append(el);
return res.toString();
}
@Expose public static String __trim(Arguments args) {
return passThis(args, "trim").trim();
}
@Expose public static String __trimStart(Arguments args) {
return passThis(args, "trimStart").replaceAll("^\\s+", "");
}
@Expose public static String __trimEnd(Arguments args) {
return passThis(args, "trimEnd").replaceAll("\\s+$", "");
}
@ExposeConstructor public static Object __constructor(Arguments args) {
var val = args.getString(0, "");
if (args.self instanceof ObjectValue) return new StringLib(val);
else return val;
}
@Expose public static String __toString(Arguments args) {
return passThis(args, "toString");
}
@Expose public static String __valueOf(Arguments args) {
return passThis(args, "valueOf");
}
@Expose(target = ExposeTarget.STATIC)
public static String __fromCharCode(Arguments args) {
var val = args.convertInt();
char[] arr = new char[val.length];
for (var i = 0; i < val.length; i++) arr[i] = (char)val[i];
return new String(arr);
}
}

View File

@@ -1,81 +0,0 @@
package me.topchetoeu.jscript.lib;
import java.util.HashMap;
import java.util.Map;
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.Symbol;
import me.topchetoeu.jscript.runtime.values.Values;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeField;
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("Symbol")
public class SymbolLib {
private static final Map<String, Symbol> symbols = new HashMap<>();
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __typeName = Symbol.get("Symbol.typeName");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __replace = Symbol.get("Symbol.replace");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __match = Symbol.get("Symbol.match");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __matchAll = Symbol.get("Symbol.matchAll");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __split = Symbol.get("Symbol.split");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __search = Symbol.get("Symbol.search");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __iterator = Symbol.get("Symbol.iterator");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __asyncIterator = Symbol.get("Symbol.asyncIterator");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __cause = Symbol.get("Symbol.cause");
public final Symbol value;
private static Symbol passThis(Arguments args, String funcName) {
var val = args.self;
if (Values.isWrapper(val, SymbolLib.class)) return Values.wrapper(val, SymbolLib.class).value;
else if (val instanceof Symbol) return (Symbol)val;
else throw EngineException.ofType(String.format("'%s' may only be called upon object and primitve symbols.", funcName));
}
public SymbolLib(Symbol val) {
this.value = val;
}
@Expose public static String __toString(Arguments args) {
return passThis(args, "toString").value;
}
@Expose public static Symbol __valueOf(Arguments args) {
return passThis(args, "valueOf");
}
@ExposeConstructor
public static Object __constructor(Arguments args) {
if (args.self instanceof ObjectValue) throw EngineException.ofType("Symbol constructor may not be called with new.");
if (args.get(0) == null) return new Symbol("");
else return new Symbol(args.getString(0));
}
@Expose(target = ExposeTarget.STATIC)
public static Symbol __for(Arguments args) {
var key = args.getString(0);
if (symbols.containsKey(key)) return symbols.get(key);
else {
var sym = new Symbol(key);
symbols.put(key, sym);
return sym;
}
}
@Expose(target = ExposeTarget.STATIC)
public static String __keyFor(Arguments args) {
return passThis(new Arguments(args.ctx, args.get(0)), "keyFor").value;
}
}

View File

@@ -1,19 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeField;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("SyntaxError")
public class SyntaxErrorLib extends ErrorLib {
@ExposeField public static final String __name = "SyntaxError";
@ExposeConstructor public static ObjectValue __constructor(Arguments args) {
var target = ErrorLib.__constructor(args);
target.setPrototype(PlaceholderProto.SYNTAX_ERROR);
return target;
}
}

View File

@@ -1,19 +0,0 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.runtime.values.ObjectValue;
import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.ExposeConstructor;
import me.topchetoeu.jscript.utils.interop.ExposeField;
import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("TypeError")
public class TypeErrorLib extends ErrorLib {
@ExposeField public static final String __name = "TypeError";
@ExposeConstructor public static ObjectValue __constructor(Arguments args) {
var target = ErrorLib.__constructor(args);
target.setPrototype(PlaceholderProto.TYPE_ERROR);
return target;
}
}

Some files were not shown because too many files have changed in this diff Show More