diff --git a/src/me/topchetoeu/jscript/Main.java b/src/me/topchetoeu/jscript/Main.java index 6082226..818b328 100644 --- a/src/me/topchetoeu/jscript/Main.java +++ b/src/me/topchetoeu/jscript/Main.java @@ -16,6 +16,10 @@ import me.topchetoeu.jscript.events.Observer; import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.InterruptException; import me.topchetoeu.jscript.exceptions.SyntaxException; +import me.topchetoeu.jscript.filesystem.MemoryFilesystem; +import me.topchetoeu.jscript.filesystem.Mode; +import me.topchetoeu.jscript.filesystem.RootFilesystem; +import me.topchetoeu.jscript.lib.FilesystemLib; import me.topchetoeu.jscript.lib.Internals; public class Main { @@ -112,6 +116,11 @@ public class Main { throw new EngineException("Couldn't open do.js"); } }); + + var fs = new RootFilesystem(null); + fs.protocols.put("file", new MemoryFilesystem(Mode.READ_WRITE)); + + environment.global.define((Context)null, "fs", false, new FilesystemLib(fs)); } private static void initEngine() { debugServer.targets.put("target", (ws, req) -> new SimpleDebugger(ws, engine)); diff --git a/src/me/topchetoeu/jscript/engine/Environment.java b/src/me/topchetoeu/jscript/engine/Environment.java index 30a77a7..8bca1de 100644 --- a/src/me/topchetoeu/jscript/engine/Environment.java +++ b/src/me/topchetoeu/jscript/engine/Environment.java @@ -12,6 +12,7 @@ import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.NativeSetter; import me.topchetoeu.jscript.interop.NativeWrapperProvider; +import me.topchetoeu.jscript.permissions.PermissionsManager; public class Environment { private HashMap prototypes = new HashMap<>(); @@ -21,6 +22,7 @@ public class Environment { public GlobalScope global; public WrappersProvider wrappers; + public PermissionsManager permissions; private static int nextId = 0; diff --git a/src/me/topchetoeu/jscript/lib/FileLib.java b/src/me/topchetoeu/jscript/lib/FileLib.java new file mode 100644 index 0000000..11c042f --- /dev/null +++ b/src/me/topchetoeu/jscript/lib/FileLib.java @@ -0,0 +1,88 @@ +package me.topchetoeu.jscript.lib; + +import me.topchetoeu.jscript.engine.Context; +import me.topchetoeu.jscript.engine.values.ArrayValue; +import me.topchetoeu.jscript.engine.values.Values; +import me.topchetoeu.jscript.filesystem.File; +import me.topchetoeu.jscript.filesystem.FilesystemException; +import me.topchetoeu.jscript.interop.Native; +import me.topchetoeu.jscript.interop.NativeGetter; + +@Native("File") +public class FileLib { + public final File file; + + @Native public PromiseLib read(Context ctx, int n) { + return PromiseLib.await(ctx, () -> { + try { + var buff = new byte[n]; + var res = new ArrayValue(); + int resI = file.read(buff); + + for (var i = resI - 1; i >= 0; i--) res.set(ctx, i, (int)buff[i]); + return res; + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + } + @Native public PromiseLib write(Context ctx, ArrayValue val) { + return PromiseLib.await(ctx, () -> { + try { + var res = new byte[val.size()]; + + for (var i = 0; i < val.size(); i++) res[i] = (byte)Values.toNumber(ctx, val.get(i)); + file.write(res); + + return null; + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + } + @Native public PromiseLib close(Context ctx) { + return PromiseLib.await(ctx, () -> { + file.close(); + return null; + }); + } + @NativeGetter public PromiseLib pointer(Context ctx) { + return PromiseLib.await(ctx, () -> { + try { + return file.getPtr(); + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + } + @Native public PromiseLib setPointer(Context ctx, long ptr) { + return PromiseLib.await(ctx, () -> { + try { + file.setPtr(ptr, 0); + return null; + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + } + @NativeGetter("length") public PromiseLib getLength(Context ctx) { + return PromiseLib.await(ctx, () -> { + try { + long curr = file.getPtr(); + file.setPtr(0, 2); + long res = file.getPtr(); + file.setPtr(curr, 0); + return res; + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + } + @NativeGetter("mode") public PromiseLib getMode(Context ctx) { + return PromiseLib.await(ctx, () -> { + try { + return file.mode().name; + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + } + + public FileLib(File file) { + this.file = file; + } +} diff --git a/src/me/topchetoeu/jscript/lib/FilesystemLib.java b/src/me/topchetoeu/jscript/lib/FilesystemLib.java new file mode 100644 index 0000000..8a9aaab --- /dev/null +++ b/src/me/topchetoeu/jscript/lib/FilesystemLib.java @@ -0,0 +1,161 @@ +package me.topchetoeu.jscript.lib; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Stack; + +import me.topchetoeu.jscript.Filename; +import me.topchetoeu.jscript.engine.Context; +import me.topchetoeu.jscript.engine.values.ObjectValue; +import me.topchetoeu.jscript.engine.values.Values; +import me.topchetoeu.jscript.filesystem.EntryType; +import me.topchetoeu.jscript.filesystem.File; +import me.topchetoeu.jscript.filesystem.FileStat; +import me.topchetoeu.jscript.filesystem.FilesystemException; +import me.topchetoeu.jscript.filesystem.Mode; +import me.topchetoeu.jscript.filesystem.RootFilesystem; +import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode; +import me.topchetoeu.jscript.interop.Native; + +@Native("Filesystem") +public class FilesystemLib { + public final RootFilesystem fs; + + @Native public PromiseLib open(Context ctx, String _path, String mode) { + var filename = Filename.parse(_path); + var _mode = Mode.parse(mode); + + return PromiseLib.await(ctx, () -> { + try { + if (fs.stat(filename.path).type != EntryType.FILE) { + throw new FilesystemException(filename.toString(), FSCode.NOT_FILE); + } + + var file = fs.open(filename.path, _mode); + return new FileLib(file); + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + } + @Native public ObjectValue ls(Context ctx, String _path) throws IOException { + var filename = Filename.parse(_path); + + return Values.toJSAsyncIterator(ctx, new Iterator<>() { + private boolean failed, done; + private File file; + private String nextLine; + + private void update() { + if (done) return; + if (!failed) { + if (file == null) { + if (fs.stat(filename.path).type != EntryType.FOLDER) { + throw new FilesystemException(filename.toString(), FSCode.NOT_FOLDER); + } + + file = fs.open(filename.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(); } + } + }); + } + @Native public PromiseLib mkdir(Context ctx, String _path) throws IOException { + return PromiseLib.await(ctx, () -> { + try { + fs.create(Filename.parse(_path).toString(), EntryType.FOLDER); + return null; + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + + } + @Native public PromiseLib mkfile(Context ctx, String _path) throws IOException { + return PromiseLib.await(ctx, () -> { + try { + fs.create(Filename.parse(_path).toString(), EntryType.FILE); + return null; + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + } + @Native public PromiseLib rm(Context ctx, String _path, boolean recursive) throws IOException { + return PromiseLib.await(ctx, () -> { + try { + if (!recursive) fs.create(Filename.parse(_path).toString(), EntryType.NONE); + else { + var stack = new Stack(); + stack.push(_path); + + while (!stack.empty()) { + var path = Filename.parse(stack.pop()).toString(); + FileStat stat; + + try { stat = fs.stat(path); } + catch (FilesystemException e) { continue; } + + if (stat.type == EntryType.FOLDER) { + for (var el : fs.open(path, Mode.READ).readToString().split("\n")) stack.push(el); + } + else fs.create(path, EntryType.NONE); + } + } + return null; + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + } + @Native public PromiseLib stat(Context ctx, String _path) throws IOException { + return PromiseLib.await(ctx, () -> { + try { + var stat = fs.stat(_path); + var res = new ObjectValue(); + + res.defineProperty(ctx, "type", stat.type.name); + res.defineProperty(ctx, "mode", stat.mode.name); + return res; + } + catch (FilesystemException e) { throw e.toEngineException(); } + }); + } + @Native public PromiseLib exists(Context ctx, String _path) throws IOException { + return PromiseLib.await(ctx, () -> { + try { fs.stat(_path); return true; } + catch (FilesystemException e) { return false; } + }); + } + + public FilesystemLib(RootFilesystem fs) { + this.fs = fs; + } +} diff --git a/src/me/topchetoeu/jscript/lib/FunctionLib.java b/src/me/topchetoeu/jscript/lib/FunctionLib.java index ffa2ff7..77f5068 100644 --- a/src/me/topchetoeu/jscript/lib/FunctionLib.java +++ b/src/me/topchetoeu/jscript/lib/FunctionLib.java @@ -39,7 +39,7 @@ import me.topchetoeu.jscript.interop.Native; }); } @Native(thisArg = true) public static String toString(Context ctx, Object func) { - return "function (...) { ... }"; + return func.toString(); } @Native public static FunctionValue async(FunctionValue func) {