Core library reprogramming #5
@ -37,6 +37,7 @@ interface Internals {
|
||||
|
||||
var env: Environment = arguments[0], internals: Internals = arguments[1];
|
||||
globalThis.log = internals.constructor.log;
|
||||
var i = 0.0;
|
||||
|
||||
try {
|
||||
run('values/object');
|
||||
|
@ -2,11 +2,12 @@ define("values/errors", () => {
|
||||
var Error = env.global.Error = function Error(msg: string) {
|
||||
if (msg === undefined) msg = '';
|
||||
else msg += '';
|
||||
|
||||
return Object.setPrototypeOf({
|
||||
|
||||
return {
|
||||
message: msg,
|
||||
stack: [] as string[],
|
||||
}, Error.prototype);
|
||||
__proto__: Error.prototype,
|
||||
} as any;
|
||||
} as ErrorConstructor;
|
||||
|
||||
setConstr(Error.prototype, Error);
|
||||
|
@ -44,8 +44,9 @@ public class EngineException extends RuntimeException {
|
||||
return ss.toString();
|
||||
}
|
||||
|
||||
private static Object err(String msg, PlaceholderProto proto) {
|
||||
private static Object err(String name, String msg, PlaceholderProto proto) {
|
||||
var res = new ObjectValue(proto);
|
||||
if (name != null) res.defineProperty(null, "name", name);
|
||||
res.defineProperty(null, "message", msg);
|
||||
return res;
|
||||
}
|
||||
@ -57,19 +58,22 @@ public class EngineException extends RuntimeException {
|
||||
this.cause = null;
|
||||
}
|
||||
|
||||
public static EngineException ofError(String name, String msg) {
|
||||
return new EngineException(err(name, msg, PlaceholderProto.ERROR));
|
||||
}
|
||||
public static EngineException ofError(String msg) {
|
||||
return new EngineException(err(msg, PlaceholderProto.ERROR));
|
||||
return new EngineException(err(null, msg, PlaceholderProto.ERROR));
|
||||
}
|
||||
public static EngineException ofSyntax(SyntaxException e) {
|
||||
return new EngineException(err(e.msg, PlaceholderProto.SYNTAX_ERROR)).add(null, e.loc);
|
||||
return new EngineException(err(null, e.msg, PlaceholderProto.SYNTAX_ERROR)).add(null, e.loc);
|
||||
}
|
||||
public static EngineException ofSyntax(String msg) {
|
||||
return new EngineException(err(msg, PlaceholderProto.SYNTAX_ERROR));
|
||||
return new EngineException(err(null, msg, PlaceholderProto.SYNTAX_ERROR));
|
||||
}
|
||||
public static EngineException ofType(String msg) {
|
||||
return new EngineException(err(msg, PlaceholderProto.TYPE_ERROR));
|
||||
return new EngineException(err(null, msg, PlaceholderProto.TYPE_ERROR));
|
||||
}
|
||||
public static EngineException ofRange(String msg) {
|
||||
return new EngineException(err(msg, PlaceholderProto.RANGE_ERROR));
|
||||
return new EngineException(err(null, msg, PlaceholderProto.RANGE_ERROR));
|
||||
}
|
||||
}
|
||||
|
7
src/me/topchetoeu/jscript/filesystem/EntryType.java
Normal file
7
src/me/topchetoeu/jscript/filesystem/EntryType.java
Normal file
@ -0,0 +1,7 @@
|
||||
package me.topchetoeu.jscript.filesystem;
|
||||
|
||||
public enum EntryType {
|
||||
NONE,
|
||||
FILE,
|
||||
FOLDER,
|
||||
}
|
27
src/me/topchetoeu/jscript/filesystem/File.java
Normal file
27
src/me/topchetoeu/jscript/filesystem/File.java
Normal file
@ -0,0 +1,27 @@
|
||||
package me.topchetoeu.jscript.filesystem;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface File {
|
||||
int read() throws IOException, InterruptedException;
|
||||
boolean write(byte val) throws IOException, InterruptedException;
|
||||
long tell() throws IOException, InterruptedException;
|
||||
void seek(long offset, int pos) throws IOException, InterruptedException;
|
||||
void close() throws IOException, InterruptedException;
|
||||
Permissions perms();
|
||||
|
||||
default String readToString() throws IOException, InterruptedException {
|
||||
seek(0, 2);
|
||||
long len = tell();
|
||||
if (len < 0) return null;
|
||||
|
||||
seek(0, 0);
|
||||
byte[] res = new byte[(int)len];
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
res[i] = (byte)read();
|
||||
}
|
||||
|
||||
return new String(res);
|
||||
}
|
||||
}
|
10
src/me/topchetoeu/jscript/filesystem/Filesystem.java
Normal file
10
src/me/topchetoeu/jscript/filesystem/Filesystem.java
Normal file
@ -0,0 +1,10 @@
|
||||
package me.topchetoeu.jscript.filesystem;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Filesystem {
|
||||
File open(String path) throws IOException, InterruptedException;
|
||||
boolean mkdir(String path) throws IOException, InterruptedException;
|
||||
EntryType type(String path) throws IOException, InterruptedException;
|
||||
boolean rm(String path) throws IOException, InterruptedException;
|
||||
}
|
35
src/me/topchetoeu/jscript/filesystem/InaccessibleFile.java
Normal file
35
src/me/topchetoeu/jscript/filesystem/InaccessibleFile.java
Normal file
@ -0,0 +1,35 @@
|
||||
package me.topchetoeu.jscript.filesystem;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class InaccessibleFile implements File {
|
||||
public static final InaccessibleFile INSTANCE = new InaccessibleFile();
|
||||
|
||||
@Override
|
||||
public int read() throws IOException, InterruptedException {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean write(byte val) throws IOException, InterruptedException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long tell() throws IOException, InterruptedException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(long offset, int pos) throws IOException, InterruptedException { }
|
||||
|
||||
@Override
|
||||
public void close() throws IOException, InterruptedException { }
|
||||
|
||||
@Override
|
||||
public Permissions perms() {
|
||||
return Permissions.NONE;
|
||||
}
|
||||
|
||||
private InaccessibleFile() { }
|
||||
}
|
53
src/me/topchetoeu/jscript/filesystem/MemoryFile.java
Normal file
53
src/me/topchetoeu/jscript/filesystem/MemoryFile.java
Normal file
@ -0,0 +1,53 @@
|
||||
package me.topchetoeu.jscript.filesystem;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class MemoryFile implements File {
|
||||
private int ptr;
|
||||
private Permissions mode;
|
||||
public final byte[] data;
|
||||
|
||||
@Override
|
||||
public int read() throws IOException, InterruptedException {
|
||||
if (data == null || !mode.readable || ptr >= data.length) return -1;
|
||||
return data[ptr++];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean write(byte val) throws IOException, InterruptedException {
|
||||
if (data == null || !mode.writable || ptr >= data.length) return false;
|
||||
data[ptr++] = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long tell() throws IOException, InterruptedException {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(long offset, int pos) throws IOException, InterruptedException {
|
||||
if (data == null) return;
|
||||
|
||||
if (pos == 0) ptr = (int)offset;
|
||||
else if (pos == 1) ptr += (int)offset;
|
||||
else if (pos == 2) ptr = data.length - (int)offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException, InterruptedException {
|
||||
mode = null;
|
||||
ptr = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permissions perms() {
|
||||
if (data == null) return Permissions.NONE;
|
||||
return mode;
|
||||
}
|
||||
|
||||
public MemoryFile(byte[] buff, Permissions mode) {
|
||||
this.data = buff;
|
||||
this.mode = mode;
|
||||
}
|
||||
}
|
17
src/me/topchetoeu/jscript/filesystem/Permissions.java
Normal file
17
src/me/topchetoeu/jscript/filesystem/Permissions.java
Normal file
@ -0,0 +1,17 @@
|
||||
package me.topchetoeu.jscript.filesystem;
|
||||
|
||||
public enum Permissions {
|
||||
NONE("", false, false),
|
||||
READ("r", true, false),
|
||||
READ_WRITE("rw", true, true);
|
||||
|
||||
public final String readMode;
|
||||
public final boolean readable;
|
||||
public final boolean writable;
|
||||
|
||||
private Permissions(String mode, boolean r, boolean w) {
|
||||
this.readMode = mode;
|
||||
this.readable = r;
|
||||
this.writable = w;
|
||||
}
|
||||
}
|
51
src/me/topchetoeu/jscript/filesystem/PhysicalFile.java
Normal file
51
src/me/topchetoeu/jscript/filesystem/PhysicalFile.java
Normal file
@ -0,0 +1,51 @@
|
||||
package me.topchetoeu.jscript.filesystem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public class PhysicalFile implements File {
|
||||
private RandomAccessFile file;
|
||||
private Permissions perms;
|
||||
|
||||
@Override
|
||||
public int read() throws IOException, InterruptedException {
|
||||
if (file == null || !perms.readable) return -1;
|
||||
else return file.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean write(byte val) throws IOException, InterruptedException {
|
||||
if (file == null || !perms.writable) return false;
|
||||
file.write(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long tell() throws IOException, InterruptedException {
|
||||
if (file == null) return 0;
|
||||
return file.getFilePointer();
|
||||
}
|
||||
@Override
|
||||
public void seek(long offset, int pos) throws IOException, InterruptedException {
|
||||
if (file == null) return;
|
||||
if (pos == 0) file.seek(pos);
|
||||
else if (pos == 1) file.seek(file.getFilePointer() + pos);
|
||||
else if (pos == 2) file.seek(file.length() + pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException, InterruptedException {
|
||||
if (file == null) return;
|
||||
file.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permissions perms() { return perms; }
|
||||
|
||||
public PhysicalFile(String path, Permissions mode) throws IOException {
|
||||
if (mode == Permissions.NONE) file = null;
|
||||
else file = new RandomAccessFile(path, mode.readMode);
|
||||
|
||||
perms = mode;
|
||||
}
|
||||
}
|
74
src/me/topchetoeu/jscript/filesystem/PhysicalFilesystem.java
Normal file
74
src/me/topchetoeu/jscript/filesystem/PhysicalFilesystem.java
Normal file
@ -0,0 +1,74 @@
|
||||
package me.topchetoeu.jscript.filesystem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class PhysicalFilesystem implements Filesystem {
|
||||
public final Path root;
|
||||
|
||||
private Permissions getPerms(Path path) {
|
||||
var file = path.toFile();
|
||||
if (!path.startsWith(root)) return Permissions.NONE;
|
||||
if (file.canRead() && file.canWrite()) return Permissions.READ_WRITE;
|
||||
if (file.canRead()) return Permissions.READ;
|
||||
|
||||
return Permissions.NONE;
|
||||
}
|
||||
private Path getPath(String name) {
|
||||
return root.resolve(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File open(String path) throws IOException, InterruptedException {
|
||||
var _path = root.resolve(path);
|
||||
|
||||
var perms = getPerms(_path);
|
||||
if (perms == Permissions.NONE) return InaccessibleFile.INSTANCE;
|
||||
|
||||
var f = _path.toFile();
|
||||
|
||||
if (f.isDirectory()) {
|
||||
var res = new StringBuilder();
|
||||
|
||||
for (var child : f.listFiles()) res.append(child.toString()).append('\n');
|
||||
|
||||
return new MemoryFile(res.toString().getBytes(), Permissions.READ);
|
||||
}
|
||||
else return new PhysicalFile(path, perms);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mkdir(String path) throws IOException, InterruptedException {
|
||||
var _path = getPath(path);
|
||||
var perms = getPerms(_path);
|
||||
var f = _path.toFile();
|
||||
|
||||
if (!perms.writable) return false;
|
||||
else return f.mkdir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntryType type(String path) throws IOException, InterruptedException {
|
||||
var _path = getPath(path);
|
||||
var perms = getPerms(_path);
|
||||
var f = _path.toFile();
|
||||
|
||||
if (perms == Permissions.NONE) return EntryType.NONE;
|
||||
else if (f.isFile()) return EntryType.FILE;
|
||||
else return EntryType.FOLDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean rm(String path) throws IOException, InterruptedException {
|
||||
var _path = getPath(path);
|
||||
var perms = getPerms(_path);
|
||||
var f = _path.toFile();
|
||||
|
||||
if (!perms.writable) return false;
|
||||
else return f.delete();
|
||||
}
|
||||
|
||||
public PhysicalFilesystem(Path root) {
|
||||
this.root = root;
|
||||
}
|
||||
}
|
@ -516,12 +516,59 @@ public class Parsing {
|
||||
|
||||
for (int i = 2; i < literal.length(); i++) {
|
||||
res *= 16;
|
||||
res += fromHex(literal.charAt(i));
|
||||
int dig = fromHex(literal.charAt(i));
|
||||
res += dig;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Double parseNumber(boolean octals, String value) {
|
||||
if (value.startsWith("0x") || value.startsWith("0X")) {
|
||||
if (value.length() == 2) return null;
|
||||
return parseHex(value);
|
||||
}
|
||||
if (value.endsWith("e") || value.endsWith("E") || value.endsWith("-")) return null;
|
||||
|
||||
int i = 0;
|
||||
double res = 0, dotDivisor = 1;
|
||||
boolean e = false, dot = false;
|
||||
int exponent = 0;
|
||||
|
||||
for (; i < value.length(); i++) {
|
||||
char c = value.charAt(i);
|
||||
if (c == '.') { dot = true; break; }
|
||||
if (c == 'e') { e = true; break; }
|
||||
if (!isDigit(c)) break;
|
||||
|
||||
res = res * 10 + c - '0';
|
||||
}
|
||||
|
||||
if (dot) for (i++; i < value.length(); i++) {
|
||||
char c = value.charAt(i);
|
||||
if (c == 'e') { e = true; break; }
|
||||
if (!isDigit(c)) break;
|
||||
|
||||
res += (c - '0') / (dotDivisor *= 10);
|
||||
}
|
||||
|
||||
if (e) for (i++; i < value.length(); i++) {
|
||||
char c = value.charAt(i);
|
||||
if (!isDigit(c)) break;
|
||||
exponent = 10 * exponent + c - '0';
|
||||
}
|
||||
|
||||
if (exponent < 0) for (int j = 0; j < -exponent; j++) res /= 10;
|
||||
else for (int j = 0; j < exponent; j++) res *= 10;
|
||||
|
||||
return res;
|
||||
}
|
||||
private static double parseNumber(Location loc, String value) {
|
||||
var res = parseNumber(false, value);
|
||||
if (res == null) throw new SyntaxException(loc, "Invalid number format.");
|
||||
else return res;
|
||||
}
|
||||
|
||||
private static List<Token> parseTokens(String filename, Collection<RawToken> tokens) {
|
||||
var res = new ArrayList<Token>();
|
||||
|
||||
@ -529,28 +576,14 @@ public class Parsing {
|
||||
var loc = new Location(el.line, el.start, filename);
|
||||
switch (el.type) {
|
||||
case LITERAL: res.add(Token.identifier(el.line, el.start, el.value)); break;
|
||||
case NUMBER:
|
||||
if (el.value.startsWith("0x") || el.value.startsWith("0X")) {
|
||||
if (el.value.endsWith("x") || el.value.endsWith("X")) {
|
||||
throw new SyntaxException(loc, "Invalid number format.");
|
||||
}
|
||||
res.add(Token.number(el.line, el.start, parseHex(el.value))); break;
|
||||
}
|
||||
if (
|
||||
el.value.endsWith("e") || el.value.endsWith("E") || el.value.endsWith("-")
|
||||
) throw new SyntaxException(loc, "Invalid number format.");
|
||||
else res.add(Token.number(el.line, el.start, Double.parseDouble(el.value))); break;
|
||||
case NUMBER: res.add(Token.number(el.line, el.start, parseNumber(loc, el.value))); break;
|
||||
case STRING: res.add(Token.string(el.line, el.start, parseString(loc, el.value))); break;
|
||||
case REGEX: res.add(Token.regex(el.line, el.start, parseRegex(loc, el.value))); break;
|
||||
case OPERATOR:
|
||||
Operator op = Operator.parse(el.value);
|
||||
if (op == null) throw new SyntaxException(loc, String.format("Unrecognized operator '%s'.", el.value));
|
||||
res.add(Token.operator(el.line, el.start, op));
|
||||
break;
|
||||
case STRING:
|
||||
res.add(Token.string(el.line, el.start, parseString(loc, el.value)));
|
||||
break;
|
||||
case REGEX:
|
||||
res.add(Token.regex(el.line, el.start, parseRegex(loc, el.value)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user