diff --git a/base/importlib.aya b/base/importlib.aya index c45e383b..9723ca0a 100644 --- a/base/importlib.aya +++ b/base/importlib.aya @@ -11,6 +11,8 @@ def importlib::aya_dir :(sys.ad) .# Dictionary of files which have been imported def importlib::imported :{} +def importlib::loaded_jars [] + def importlib::path [ importlib.aya_dir "std" :9s + + .# /base ] @@ -164,7 +166,9 @@ def importlib::import {__name : importlib^, __name importlib.from_path } (__name :T ::str =) { { .# Determine load command based on string type - (__name ".aya" H) { + (__name ".jar" H) { + __name importlib.load_library + } (__name ".aya" H) { __name importlib.from_file } (__name.[0] '/ =) { __name importlib.load_file @@ -181,6 +185,13 @@ def importlib::import {__name : importlib^, } +def importlib::load_library {jar_file : importlib^, + importlib.loaded_jars jar_file H ! { + jar_file :(library.load) ; + jar_file importlib.loaded_jars .B ; + } ? +} + def importlib::is_exportall { { .# try diff --git a/manual/libraries.md b/manual/libraries.md new file mode 100644 index 00000000..2638a6ff --- /dev/null +++ b/manual/libraries.md @@ -0,0 +1,36 @@ +## Adding more Instructions + +You can add more Instructions by loading a `.jar` file with `:(library.load)` + +A jar can provide one or more `NamedInstructionStore` implementations. +This is done by adding the fully qualified class name(s) to this file: +`META-INF/services/aya.instruction.named.NamedInstructionStore` + +For more information, you should look up 'Java SPI' (Service Provider Interface). + +### Example + +This adds an instruction `:{example.instruction}` which pushes the String `hello, world` onto the stack. + +```java +package my.instruction; + +import aya.eval.BlockEvaluator; +import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; +import aya.obj.list.List; + +public class MyInstructionStore implements NamedInstructionStore { + @Override + public Collection getNamedInstructions() { + return Arrays.asList( + new NamedOperator("example.instruction") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + blockEvaluator.push(List.fromString("hello, world")); + } + } + ); + } +} +``` diff --git a/src/aya/AyaPrefs.java b/src/aya/AyaPrefs.java index 0f4d81d8..def98ed3 100644 --- a/src/aya/AyaPrefs.java +++ b/src/aya/AyaPrefs.java @@ -24,25 +24,22 @@ public class AyaPrefs { + "https://github.com/nick-paul/aya-lang/issues with the stacktrace below.\n" + "=== [ Stacktrace ] ==="; - public static void initDefaultWorkingDir() { + public static File getAyaRootDirectory() { try { - workingDir = AyaThread.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath(); -// if(workingDir.length() > 0) { -// workingDir = workingDir.substring(1, workingDir.length()); //Remove the leading '/' -// } - if(workingDir.contains(".jar")) { - int ix = workingDir.lastIndexOf('/'); - workingDir = workingDir.substring(0, ix+1); + File codeSource = new File(AyaThread.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + if(codeSource.isFile()) { + codeSource = codeSource.getParentFile(); } - - workingDir = (new File(workingDir).getCanonicalPath()).toString() + File.separator; + return codeSource; } catch (URISyntaxException e) { - workingDir = ""; - StaticData.IO.printDebug("Cannot locate working dir"); - } catch (IOException e) { - workingDir = ""; - StaticData.IO.printDebug("Cannot locate working dir"); + StaticData.IO.printDebug("Cannot locate aya dir: " + e.getMessage()); + return null; } + } + + public static void initDefaultWorkingDir() { + File rootDir = getAyaRootDirectory(); + workingDir = rootDir == null ? "" : (rootDir.getAbsolutePath() + File.separator); defaultWorkingDir = workingDir; } diff --git a/src/aya/StaticData.java b/src/aya/StaticData.java index 5c1b09c5..506a5c25 100644 --- a/src/aya/StaticData.java +++ b/src/aya/StaticData.java @@ -1,7 +1,17 @@ package aya; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.stream.StreamSupport; +import aya.exceptions.runtime.IOError; import aya.ext.color.ColorInstructionStore; import aya.ext.date.DateInstructionStore; import aya.ext.debug.DebugInstructionStore; @@ -11,6 +21,7 @@ import aya.ext.image.ImageInstructionStore; import aya.ext.json.JSONInstructionStore; import aya.ext.la.LinearAlgebraInstructionStore; +import aya.ext.library.LibraryInstructionStore; import aya.ext.plot.PlotInstructionStore; import aya.ext.socket.SocketInstructionStore; import aya.ext.sys.SystemInstructionStore; @@ -48,60 +59,52 @@ public class StaticData { // All calls to modify this data will need to be thread safe // private static StaticData _instance; - + + // // Data loaded in the parser // private StringSearch _helpData; - + // // Data Loaded on Start-up // - private ArrayList _namedInstructionStores; - - + private final Map _namedInstructions = new HashMap<>(); + + private StaticData() { _helpData = null; // initHelpData will create - _namedInstructionStores = new ArrayList(); } - + public static StaticData getInstance() { if (_instance == null) { _instance = new StaticData(); } return _instance; } - + public void init() { initHelpData(); initNamedInstructions(); } - - public void addNamedInstructionStore(NamedInstructionStore is) { - _namedInstructionStores.add(is); - is.initHelpData(this); - } - - + + /////////////// // Help Data // /////////////// - + private void initHelpData() { - if(_helpData == null) { - + if (_helpData == null) { + //Make sure all classes are loaded - try - { - loadOps(Ops.OPS); - loadOps(Ops.EXTRA_OPS); - loadOps(MiscOps.MATH_OPS); - loadOps(ColonOps.COLON_OPS); - loadOps(DotOps.DOT_OPS); - } - catch(Exception e) - { + try { + loadOps(Ops.OPS); + loadOps(Ops.EXTRA_OPS); + loadOps(MiscOps.MATH_OPS); + loadOps(ColonOps.COLON_OPS); + loadOps(DotOps.DOT_OPS); + } catch (Exception e) { e.printStackTrace(); } ArrayList searchList = new ArrayList(); @@ -113,12 +116,12 @@ private void initHelpData() { _helpData = new StringSearch(searchList); } } - + public StringSearch getHelpData() { initHelpData(); return _helpData; } - + public void addHelpText(String in) { getHelpData().addUnique(in); } @@ -126,7 +129,7 @@ public void addHelpText(String in) { public String[] getQuickSearchData() { return getHelpData().getAllItems(); } - + /* This function does nothing but force java to load * the operators and call the static blocks */ @@ -141,36 +144,68 @@ private void loadOps(Operator[] ops) { //////////////////////// private void initNamedInstructions() { - _namedInstructionStores.add(new DebugInstructionStore()); - _namedInstructionStores.add(new JSONInstructionStore()); - _namedInstructionStores.add(new ImageInstructionStore()); - _namedInstructionStores.add(new GraphicsInstructionStore()); - _namedInstructionStores.add(new FStreamInstructionStore()); - _namedInstructionStores.add(new SystemInstructionStore()); - _namedInstructionStores.add(new DialogInstructionStore()); - _namedInstructionStores.add(new PlotInstructionStore()); - _namedInstructionStores.add(new DateInstructionStore()); - _namedInstructionStores.add(new SocketInstructionStore()); - _namedInstructionStores.add(new ColorInstructionStore()); - _namedInstructionStores.add(new LinearAlgebraInstructionStore()); - _namedInstructionStores.add(new ThreadInstructionStore()); + addNamedInstructionStore(new DebugInstructionStore()); + addNamedInstructionStore(new JSONInstructionStore()); + addNamedInstructionStore(new ImageInstructionStore()); + addNamedInstructionStore(new GraphicsInstructionStore()); + addNamedInstructionStore(new FStreamInstructionStore()); + addNamedInstructionStore(new SystemInstructionStore()); + addNamedInstructionStore(new DialogInstructionStore()); + addNamedInstructionStore(new PlotInstructionStore()); + addNamedInstructionStore(new DateInstructionStore()); + addNamedInstructionStore(new SocketInstructionStore()); + addNamedInstructionStore(new ColorInstructionStore()); + addNamedInstructionStore(new LinearAlgebraInstructionStore()); + addNamedInstructionStore(new ThreadInstructionStore()); + addNamedInstructionStore(new LibraryInstructionStore()); + } + + public ArrayList loadLibrary(File path) { + ArrayList loaded = new ArrayList(); - for (NamedInstructionStore x : _namedInstructionStores) { - x.initHelpData(this); + try { + URL[] urls = {path.toURI().toURL()}; + + try (URLClassLoader libClassLoader = new URLClassLoader(urls)) { + StreamSupport.stream( + ServiceLoader.load(NamedInstructionStore.class, libClassLoader).spliterator(), + false + ).forEach(store -> { + //IO.out().println("found store: " + store.getClass().getName()); + addNamedInstructionStore(store); + loaded.add(store); + }); + } catch (IOException e) { + throw new IOError("library.load", path.getPath(), e); + } + + } catch (MalformedURLException e) { + throw new IOError("library.load", path.getPath(), e); } + + return loaded; } - - - public NamedOperator getNamedInstruction(String name) { - for (NamedInstructionStore x : _namedInstructionStores) { - NamedOperator i = x.getInstruction(name); - if (i != null) { - return i; + + public void addNamedInstructionStore(NamedInstructionStore store) { + for (NamedOperator instruction : store.getNamedInstructions()) { + String iName = instruction.getName(); + NamedOperator previous = _namedInstructions.put(iName, instruction); + if (previous != null) { + IO.err().println("NamedInstruction '" + iName + "' has multiple implementations:\n" + + " " + previous.getClass().getName() + "\n" + + " " + instruction.getClass().getName() + ); + } + + String doc = instruction.getDoc(); + if (doc != null && !doc.isEmpty()) { + addHelpText(instruction.opName() + "\n " + doc); } } - return null; } - + public NamedOperator getNamedInstruction(String name) { + return _namedInstructions.get(name); + } } diff --git a/src/aya/ext/color/ColorInstructionStore.java b/src/aya/ext/color/ColorInstructionStore.java index c0fa5148..aa03bd0d 100644 --- a/src/aya/ext/color/ColorInstructionStore.java +++ b/src/aya/ext/color/ColorInstructionStore.java @@ -1,50 +1,52 @@ package aya.ext.color; import java.awt.Color; +import java.util.Arrays; +import java.util.Collection; import aya.eval.BlockEvaluator; import aya.exceptions.runtime.ValueError; -import aya.instruction.named.NamedOperator; import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; import aya.obj.dict.Dict; import aya.obj.list.List; import aya.obj.number.Num; import aya.obj.symbol.SymbolConstants; import aya.util.ColorFactory; -public class ColorInstructionStore extends NamedInstructionStore { - - @Override - protected void init() { +public class ColorInstructionStore implements NamedInstructionStore { - addInstruction(new NamedOperator("color.fromstr", "color::str: convert an html valid color to an rgba dict") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - String color_str = blockEvaluator.pop().str(); - try { - Color color = ColorFactory.web(color_str); - Dict d = new Dict(); - d.set(SymbolConstants.R, Num.fromInt(color.getRed())); - d.set(SymbolConstants.G, Num.fromInt(color.getGreen())); - d.set(SymbolConstants.B, Num.fromInt(color.getBlue())); - d.set(SymbolConstants.A, Num.fromInt(color.getAlpha())); - blockEvaluator.push(d); - } catch (IllegalArgumentException e) { - throw new ValueError(":(color.fromstr) Invalid color: '" + color_str + "'"); - } - } - }); + @Override + public Collection getNamedInstructions() { + return Arrays.asList( + new NamedOperator("color.fromstr", "color::str: convert an html valid color to an rgba dict") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + String color_str = blockEvaluator.pop().str(); + try { + Color color = ColorFactory.web(color_str); + Dict d = new Dict(); + d.set(SymbolConstants.R, Num.fromInt(color.getRed())); + d.set(SymbolConstants.G, Num.fromInt(color.getGreen())); + d.set(SymbolConstants.B, Num.fromInt(color.getBlue())); + d.set(SymbolConstants.A, Num.fromInt(color.getAlpha())); + blockEvaluator.push(d); + } catch (IllegalArgumentException e) { + throw new ValueError(":{color.fromstr} Invalid color: '" + color_str + "'"); + } + } + }, - addInstruction(new NamedOperator("color.name_list", "return a list of all named colors") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - List named_colors = new List(); - for (String s : ColorFactory.listNamedColors()) { - named_colors.mutAdd(List.fromString(s)); + new NamedOperator("color.name_list", "return a list of all named colors") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + List named_colors = new List(); + for (String s : ColorFactory.listNamedColors()) { + named_colors.mutAdd(List.fromString(s)); + } + blockEvaluator.push(named_colors); + } } - blockEvaluator.push(named_colors); - } - }); - + ); } } diff --git a/src/aya/ext/date/DateInstructionStore.java b/src/aya/ext/date/DateInstructionStore.java index fe8780e8..7888bad2 100644 --- a/src/aya/ext/date/DateInstructionStore.java +++ b/src/aya/ext/date/DateInstructionStore.java @@ -1,13 +1,19 @@ package aya.ext.date; import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; + +import java.util.Arrays; +import java.util.Collection; + +public class DateInstructionStore implements NamedInstructionStore { -public class DateInstructionStore extends NamedInstructionStore { - @Override - protected void init() { - addInstruction(new ParseDateInstruction()); - addInstruction(new FormatDateInstruction()); - addInstruction(new DescribeDateInstruction()); + public Collection getNamedInstructions() { + return Arrays.asList( + new ParseDateInstruction(), + new FormatDateInstruction(), + new DescribeDateInstruction() + ); } } diff --git a/src/aya/ext/debug/DebugInstructionStore.java b/src/aya/ext/debug/DebugInstructionStore.java index 6e23c5ee..c69239e5 100644 --- a/src/aya/ext/debug/DebugInstructionStore.java +++ b/src/aya/ext/debug/DebugInstructionStore.java @@ -1,12 +1,17 @@ package aya.ext.debug; import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; + +import java.util.Arrays; +import java.util.Collection; + +public class DebugInstructionStore implements NamedInstructionStore { -public class DebugInstructionStore extends NamedInstructionStore { - @Override - protected void init() { - // JSON - addInstruction(new PauseDebugInstruction()); + public Collection getNamedInstructions() { + return Arrays.asList( + new PauseDebugInstruction() + ); } } diff --git a/src/aya/ext/dialog/DialogInstructionStore.java b/src/aya/ext/dialog/DialogInstructionStore.java index 13f65dd4..0ef19ef4 100644 --- a/src/aya/ext/dialog/DialogInstructionStore.java +++ b/src/aya/ext/dialog/DialogInstructionStore.java @@ -7,144 +7,149 @@ import aya.eval.BlockEvaluator; import aya.exceptions.runtime.TypeError; import aya.exceptions.runtime.ValueError; -import aya.instruction.named.NamedOperator; import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; import aya.obj.Obj; import aya.obj.list.List; import aya.obj.number.Num; import aya.obj.symbol.Symbol; import aya.obj.symbol.SymbolConstants; -public class DialogInstructionStore extends NamedInstructionStore { - - @Override - protected void init() { - - addInstruction(new NamedOperator("dialog.getstr", "message::str: popup window with a a text input field") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj title = blockEvaluator.pop(); - blockEvaluator.push(List.fromString(QuickDialog.requestString(title.str()))); - } - }); - - addInstruction(new NamedOperator("dialog.getnum", "message::str: popup window with a number input field") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj title = blockEvaluator.pop(); - blockEvaluator.push(QuickDialog.numberInput(title.str())); - } - }); - - addInstruction(new NamedOperator("dialog.alert", "message::str title::str type::sym show an alert dialog") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj type_obj = blockEvaluator.pop(); - final Obj title_obj = blockEvaluator.pop(); - final Obj message_obj = blockEvaluator.pop(); - - if (!type_obj.isa(Obj.SYMBOL)) throw new TypeError(this, "SSJ", type_obj, title_obj, message_obj); - - int type = symToDialogType((Symbol)type_obj); - QuickDialog.alert(message_obj.str(), title_obj.str(), type); - } - }); - - addInstruction(new NamedOperator("dialog.confirm", "message::str options::list title::str type::sym show an alert dialog") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj type_obj = blockEvaluator.pop(); - final Obj title_obj = blockEvaluator.pop(); - final Obj options_obj = blockEvaluator.pop(); - final Obj message_obj = blockEvaluator.pop(); - - if (!(type_obj.isa(Obj.SYMBOL) && options_obj.isa(Obj.LIST))) throw new TypeError(this, "SSJ", type_obj, title_obj, message_obj); - - int type = symToDialogType((Symbol)type_obj); - List options = asList(options_obj); - - if (options.length() != 2) throw new ValueError(":(dialog.confirm) : Expected options list of length 2. Got " + options.repr()); - - boolean val = QuickDialog.confirm( - message_obj.str(), - options.getExact(0).str(), - options.getExact(1).str(), - title_obj.str(), - type); - - blockEvaluator.push(Num.fromBool(val)); - } - }); - - addInstruction(new NamedOperator("dialog.buttons", "message::str options::list title::str type::sym: show a dialog with several option buttons") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj type_obj = blockEvaluator.pop(); - final Obj title_obj = blockEvaluator.pop(); - final Obj options_obj = blockEvaluator.pop(); - final Obj message_obj = blockEvaluator.pop(); - - if (!(type_obj.isa(Obj.SYMBOL) && options_obj.isa(Obj.LIST))) throw new TypeError(this, "SSJ", type_obj, title_obj, message_obj); - - int type = symToDialogType((Symbol)type_obj); - - List options_list = asList(options_obj); - if (options_list.length() <= 0) throw new ValueError(":(dialog.buttons) : Expected non-empty options. Got " + options_list.repr()); - - String[] options = new String[options_list.length()]; - for (int i = 0; i < options_list.length(); i++) { - options[i] = options_list.getExact(i).str(); - } +import java.util.Arrays; +import java.util.Collection; - String selected = QuickDialog.selectOptionButtons( - message_obj.str(), - options, - title_obj.str(), - type); - - blockEvaluator.push(List.fromString(selected)); - } - }); - - addInstruction(new NamedOperator("dialog.dropdown", "message::str options::list title::str type::sym: show a dialog with several options as a dropdown") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj type_obj = blockEvaluator.pop(); - final Obj title_obj = blockEvaluator.pop(); - final Obj options_obj = blockEvaluator.pop(); - final Obj message_obj = blockEvaluator.pop(); - - if (!(type_obj.isa(Obj.SYMBOL) && options_obj.isa(Obj.LIST))) throw new TypeError(this, "SSJ", type_obj, title_obj, message_obj); - - int type = symToDialogType((Symbol)type_obj); - - List options_list = asList(options_obj); - if (options_list.length() <= 0) throw new ValueError(":(dialog.buttons) : Expected non-empty options. Got " + options_list.repr()); - - String[] options = new String[options_list.length()]; - for (int i = 0; i < options_list.length(); i++) { - options[i] = options_list.getExact(i).str(); - } +public class DialogInstructionStore implements NamedInstructionStore { - String selected = QuickDialog.selectOptionDropdown( - message_obj.str(), - options, - title_obj.str(), - type); - - blockEvaluator.push(List.fromString(selected)); - - } - }); - - addInstruction(new NamedOperator("dialog.choosefile") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - blockEvaluator.push(List.fromString(QuickDialog.chooseFile())); - } - }); + @Override + public Collection getNamedInstructions() { + return Arrays.asList( + + new NamedOperator("dialog.getstr", "message::str: popup window with a a text input field") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj title = blockEvaluator.pop(); + blockEvaluator.push(List.fromString(QuickDialog.requestString(title.str()))); + } + }, + + new NamedOperator("dialog.getnum", "message::str: popup window with a number input field") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj title = blockEvaluator.pop(); + blockEvaluator.push(QuickDialog.numberInput(title.str())); + } + }, + + new NamedOperator("dialog.alert", "message::str title::str type::sym show an alert dialog") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj type_obj = blockEvaluator.pop(); + final Obj title_obj = blockEvaluator.pop(); + final Obj message_obj = blockEvaluator.pop(); + + if (!type_obj.isa(Obj.SYMBOL)) throw new TypeError(this, "SSJ", type_obj, title_obj, message_obj); + + int type = symToDialogType((Symbol) type_obj); + QuickDialog.alert(message_obj.str(), title_obj.str(), type); + } + }, + + new NamedOperator("dialog.confirm", "message::str options::list title::str type::sym show an alert dialog") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj type_obj = blockEvaluator.pop(); + final Obj title_obj = blockEvaluator.pop(); + final Obj options_obj = blockEvaluator.pop(); + final Obj message_obj = blockEvaluator.pop(); + + if (!(type_obj.isa(Obj.SYMBOL) && options_obj.isa(Obj.LIST))) throw new TypeError(this, "SSJ", type_obj, title_obj, message_obj); + + int type = symToDialogType((Symbol) type_obj); + List options = asList(options_obj); + + if (options.length() != 2) throw new ValueError(":{dialog.confirm} : Expected options list of length 2. Got " + options.repr()); + + boolean val = QuickDialog.confirm( + message_obj.str(), + options.getExact(0).str(), + options.getExact(1).str(), + title_obj.str(), + type); + + blockEvaluator.push(Num.fromBool(val)); + } + }, + + new NamedOperator("dialog.buttons", "message::str options::list title::str type::sym: show a dialog with several option buttons") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj type_obj = blockEvaluator.pop(); + final Obj title_obj = blockEvaluator.pop(); + final Obj options_obj = blockEvaluator.pop(); + final Obj message_obj = blockEvaluator.pop(); + + if (!(type_obj.isa(Obj.SYMBOL) && options_obj.isa(Obj.LIST))) throw new TypeError(this, "SSJ", type_obj, title_obj, message_obj); + + int type = symToDialogType((Symbol) type_obj); + + List options_list = asList(options_obj); + if (options_list.length() <= 0) throw new ValueError(":{dialog.buttons} : Expected non-empty options. Got " + options_list.repr()); + + String[] options = new String[options_list.length()]; + for (int i = 0; i < options_list.length(); i++) { + options[i] = options_list.getExact(i).str(); + } + + String selected = QuickDialog.selectOptionButtons( + message_obj.str(), + options, + title_obj.str(), + type); + + blockEvaluator.push(List.fromString(selected)); + } + }, + + new NamedOperator("dialog.dropdown", "message::str options::list title::str type::sym: show a dialog with several options as a dropdown") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj type_obj = blockEvaluator.pop(); + final Obj title_obj = blockEvaluator.pop(); + final Obj options_obj = blockEvaluator.pop(); + final Obj message_obj = blockEvaluator.pop(); + + if (!(type_obj.isa(Obj.SYMBOL) && options_obj.isa(Obj.LIST))) throw new TypeError(this, "SSJ", type_obj, title_obj, message_obj); + + int type = symToDialogType((Symbol) type_obj); + + List options_list = asList(options_obj); + if (options_list.length() <= 0) throw new ValueError(":{dialog.buttons} : Expected non-empty options. Got " + options_list.repr()); + + String[] options = new String[options_list.length()]; + for (int i = 0; i < options_list.length(); i++) { + options[i] = options_list.getExact(i).str(); + } + + String selected = QuickDialog.selectOptionDropdown( + message_obj.str(), + options, + title_obj.str(), + type); + + blockEvaluator.push(List.fromString(selected)); + + } + }, + + new NamedOperator("dialog.choosefile") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + blockEvaluator.push(List.fromString(QuickDialog.chooseFile())); + } + } + ); } - + private int symToDialogType(Symbol sym) { final long id = sym.id(); if (id == SymbolConstants.PLAIN.id()) return JOptionPane.PLAIN_MESSAGE; diff --git a/src/aya/ext/fstream/FStreamInstructionStore.java b/src/aya/ext/fstream/FStreamInstructionStore.java index 3c3e9895..46d16980 100644 --- a/src/aya/ext/fstream/FStreamInstructionStore.java +++ b/src/aya/ext/fstream/FStreamInstructionStore.java @@ -1,6 +1,8 @@ package aya.ext.fstream; import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; import aya.eval.BlockEvaluator; import aya.exceptions.runtime.IOError; @@ -10,33 +12,36 @@ import aya.obj.list.numberlist.DoubleList; import aya.util.FileUtils; -public class FStreamInstructionStore extends NamedInstructionStore { - +public class FStreamInstructionStore implements NamedInstructionStore { + @Override - protected void init() { - // Legacy Stream Instructions - // TODO: Separate into individual instructions - addInstruction(new LegacyFStreamInstruction()); - - // - // Utility Instructions - // - - addInstruction(new NamedOperator("fileutils.readallbytes") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - String path = blockEvaluator.pop().str(); - try { - byte[] bytes = FileUtils.readAllBytes(FileUtils.resolveFile(path)); - double[] doubles = new double[bytes.length]; - for (int i = 0; i < bytes.length; i++) { - doubles[i] = bytes[i]; + public Collection getNamedInstructions() { + return Arrays.asList( + + // Legacy Stream Instructions + // TODO: Separate into individual instructions + new LegacyFStreamInstruction(), + + // + // Utility Instructions + // + + new NamedOperator("fileutils.readallbytes") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + String path = blockEvaluator.pop().str(); + try { + byte[] bytes = FileUtils.readAllBytes(FileUtils.resolveFile(path)); + double[] doubles = new double[bytes.length]; + for (int i = 0; i < bytes.length; i++) { + doubles[i] = bytes[i]; + } + blockEvaluator.push(new List(new DoubleList(doubles))); + } catch (IOException e) { + throw new IOError("{fstream.readallbytes}", path, e); + } } - blockEvaluator.push(new List(new DoubleList(doubles))); - } catch (IOException e) { - throw new IOError("{fstream.readallbytes}", path, e); } - } - }); + ); } } diff --git a/src/aya/ext/graphics/GraphicsInstructionStore.java b/src/aya/ext/graphics/GraphicsInstructionStore.java index 32cd8d06..bb8db96d 100644 --- a/src/aya/ext/graphics/GraphicsInstructionStore.java +++ b/src/aya/ext/graphics/GraphicsInstructionStore.java @@ -38,49 +38,55 @@ import aya.ext.graphics.instruction.keyboard.PressedKeysInstruction; import aya.ext.graphics.instruction.keyboard.TypedCharsInstruction; import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; -public class GraphicsInstructionStore extends NamedInstructionStore { +import java.util.Arrays; +import java.util.Collection; + +public class GraphicsInstructionStore implements NamedInstructionStore { public static final CanvasTable canvas_table = new CanvasTable(); @Override - protected void init() { - addInstruction(new ArcGraphicsInstruction(canvas_table)); - addInstruction(new ClearGraphicsInstruction(canvas_table)); - addInstruction(new ClearRectGraphicsInstruction(canvas_table)); - addInstruction(new ClickEventsInstruction(canvas_table)); - addInstruction(new CloseGraphicsInstruction(canvas_table)); - addInstruction(new CopyRectGraphicsInstruction(canvas_table)); - addInstruction(new PointsGraphicsInstruction(canvas_table)); - addInstruction(new EllipseGraphicsInstruction(canvas_table)); - addInstruction(new GetPixelsGraphicsInstruction(canvas_table)); - addInstruction(new IsOpenGraphicsInstruction(canvas_table)); - addInstruction(new LineGraphicsInstruction(canvas_table)); - addInstruction(new ListFontsGraphicsInstruction(canvas_table)); - addInstruction(new MoveEventsInstruction(canvas_table)); - addInstruction(new NewGraphicsInstruction(canvas_table)); - addInstruction(new OvalGraphicsInstruction(canvas_table)); - addInstruction(new PathGraphicsInstruction(canvas_table)); - addInstruction(new PressedKeysInstruction(canvas_table)); - addInstruction(new PressedButtonsInstruction(canvas_table)); - addInstruction(new RectGraphicsInstruction(canvas_table)); - addInstruction(new RotateGraphicsInstruction(canvas_table)); - addInstruction(new RoundRectGraphicsInstruction(canvas_table)); - addInstruction(new SaveGraphicsInstruction(canvas_table)); - addInstruction(new ScaleGraphicsInstruction(canvas_table)); - addInstruction(new SetAlphaGraphicsInstruction(canvas_table)); - addInstruction(new SetBGColorGraphicsInstruction(canvas_table)); - addInstruction(new SetColorGraphicsInstruction(canvas_table)); - addInstruction(new SetColorAlphaGraphicsInstruction(canvas_table)); - addInstruction(new SetFontGraphicsInstruction(canvas_table)); - addInstruction(new SetPaintGradGraphicsInstruction(canvas_table)); - addInstruction(new SetStrokeGraphicsInstruction(canvas_table)); - addInstruction(new SetStrokeWidthGraphicsInstruction(canvas_table)); - addInstruction(new ShearGraphicsInstruction(canvas_table)); - addInstruction(new ShowGraphicsInstruction(canvas_table)); - addInstruction(new TextGraphicsInstruction(canvas_table)); - addInstruction(new TranslateGraphicsInstruction(canvas_table)); - addInstruction(new TypedCharsInstruction(canvas_table)); - addInstruction(new ViewmatGraphicsInstruction(canvas_table)); + public Collection getNamedInstructions() { + return Arrays.asList( + new ArcGraphicsInstruction(canvas_table), + new ClearGraphicsInstruction(canvas_table), + new ClearRectGraphicsInstruction(canvas_table), + new ClickEventsInstruction(canvas_table), + new CloseGraphicsInstruction(canvas_table), + new CopyRectGraphicsInstruction(canvas_table), + new EllipseGraphicsInstruction(canvas_table), + new GetPixelsGraphicsInstruction(canvas_table), + new IsOpenGraphicsInstruction(canvas_table), + new LineGraphicsInstruction(canvas_table), + new ListFontsGraphicsInstruction(canvas_table), + new MoveEventsInstruction(canvas_table), + new NewGraphicsInstruction(canvas_table), + new OvalGraphicsInstruction(canvas_table), + new PathGraphicsInstruction(canvas_table), + new PointsGraphicsInstruction(canvas_table), + new PressedKeysInstruction(canvas_table), + new PressedButtonsInstruction(canvas_table), + new RectGraphicsInstruction(canvas_table), + new RotateGraphicsInstruction(canvas_table), + new RoundRectGraphicsInstruction(canvas_table), + new SaveGraphicsInstruction(canvas_table), + new ScaleGraphicsInstruction(canvas_table), + new SetAlphaGraphicsInstruction(canvas_table), + new SetBGColorGraphicsInstruction(canvas_table), + new SetColorGraphicsInstruction(canvas_table), + new SetColorAlphaGraphicsInstruction(canvas_table), + new SetFontGraphicsInstruction(canvas_table), + new SetPaintGradGraphicsInstruction(canvas_table), + new SetStrokeGraphicsInstruction(canvas_table), + new SetStrokeWidthGraphicsInstruction(canvas_table), + new ShearGraphicsInstruction(canvas_table), + new ShowGraphicsInstruction(canvas_table), + new TextGraphicsInstruction(canvas_table), + new TranslateGraphicsInstruction(canvas_table), + new TypedCharsInstruction(canvas_table), + new ViewmatGraphicsInstruction(canvas_table) + ); } } diff --git a/src/aya/ext/image/ImageInstructionStore.java b/src/aya/ext/image/ImageInstructionStore.java index 623ef42b..8b343fce 100644 --- a/src/aya/ext/image/ImageInstructionStore.java +++ b/src/aya/ext/image/ImageInstructionStore.java @@ -4,13 +4,19 @@ import aya.ext.image.instruction.ReadImageInstruction; import aya.ext.image.instruction.WriteImageInstruction; import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; -public class ImageInstructionStore extends NamedInstructionStore { +import java.util.Arrays; +import java.util.Collection; + +public class ImageInstructionStore implements NamedInstructionStore { @Override - protected void init() { - addInstruction(new GetImageFormatsInstruction()); - addInstruction(new ReadImageInstruction()); - addInstruction(new WriteImageInstruction()); + public Collection getNamedInstructions() { + return Arrays.asList( + new GetImageFormatsInstruction(), + new ReadImageInstruction(), + new WriteImageInstruction() + ); } } diff --git a/src/aya/ext/json/JSONInstructionStore.java b/src/aya/ext/json/JSONInstructionStore.java index cefd4eef..266b983e 100644 --- a/src/aya/ext/json/JSONInstructionStore.java +++ b/src/aya/ext/json/JSONInstructionStore.java @@ -1,13 +1,18 @@ package aya.ext.json; import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; + +import java.util.Arrays; +import java.util.Collection; + +public class JSONInstructionStore implements NamedInstructionStore { -public class JSONInstructionStore extends NamedInstructionStore { - @Override - protected void init() { - // JSON - addInstruction(new ToJSONInstruction()); - addInstruction(new LoadJSONInstruction()); + public Collection getNamedInstructions() { + return Arrays.asList( + new ToJSONInstruction(), + new LoadJSONInstruction() + ); } } diff --git a/src/aya/ext/la/LinearAlgebraInstructionStore.java b/src/aya/ext/la/LinearAlgebraInstructionStore.java index 30924f40..6d039679 100644 --- a/src/aya/ext/la/LinearAlgebraInstructionStore.java +++ b/src/aya/ext/la/LinearAlgebraInstructionStore.java @@ -1,11 +1,17 @@ package aya.ext.la; import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; + +import java.util.Arrays; +import java.util.Collection; + +public class LinearAlgebraInstructionStore implements NamedInstructionStore { -public class LinearAlgebraInstructionStore extends NamedInstructionStore { - @Override - protected void init() { - addInstruction(new MatMulInstruction()); + public Collection getNamedInstructions() { + return Arrays.asList( + new MatMulInstruction() + ); } } diff --git a/src/aya/ext/library/LibraryInstructionStore.java b/src/aya/ext/library/LibraryInstructionStore.java new file mode 100644 index 00000000..4eac165a --- /dev/null +++ b/src/aya/ext/library/LibraryInstructionStore.java @@ -0,0 +1,35 @@ +package aya.ext.library; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import aya.StaticData; +import aya.eval.BlockEvaluator; +import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; +import aya.obj.list.List; +import aya.util.FileUtils; + +public class LibraryInstructionStore implements NamedInstructionStore { + + @Override + public Collection getNamedInstructions() { + return Arrays.asList( + new NamedOperator("library.load", "path::str: load an external library, return list of loaded operators") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + String lib_path = blockEvaluator.pop().str(); + ArrayList loaded = StaticData.getInstance().loadLibrary(FileUtils.resolveFile(lib_path)); + List loaded_names = new List(); + for (NamedInstructionStore lib : loaded) { + for (NamedOperator op : lib.getNamedInstructions()) { + loaded_names.mutAdd(List.fromString(op.opName())); + } + } + blockEvaluator.push(loaded_names); + } + } + ); + } +} diff --git a/src/aya/ext/plot/PlotInstructionStore.java b/src/aya/ext/plot/PlotInstructionStore.java index 3c4e02f9..8804324c 100644 --- a/src/aya/ext/plot/PlotInstructionStore.java +++ b/src/aya/ext/plot/PlotInstructionStore.java @@ -5,14 +5,20 @@ import aya.ext.plot.instruction.PieChartInstruction; import aya.ext.plot.instruction.PlotInstruction; import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; -public class PlotInstructionStore extends NamedInstructionStore { +import java.util.Arrays; +import java.util.Collection; - @Override - protected void init() { - addInstruction(new PlotInstruction()); - addInstruction(new MultiPlotInstruction()); - addInstruction(new BoxPlotInstruction()); - addInstruction(new PieChartInstruction()); - } +public class PlotInstructionStore implements NamedInstructionStore { + + @Override + public Collection getNamedInstructions() { + return Arrays.asList( + new PlotInstruction(), + new MultiPlotInstruction(), + new BoxPlotInstruction(), + new PieChartInstruction() + ); + } } diff --git a/src/aya/ext/socket/SocketInstructionStore.java b/src/aya/ext/socket/SocketInstructionStore.java index 28012258..a309c7b0 100644 --- a/src/aya/ext/socket/SocketInstructionStore.java +++ b/src/aya/ext/socket/SocketInstructionStore.java @@ -1,138 +1,142 @@ package aya.ext.socket; import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; import aya.eval.BlockEvaluator; import aya.exceptions.runtime.IOError; import aya.exceptions.runtime.TypeError; -import aya.instruction.named.NamedOperator; import aya.instruction.named.NamedInstructionStore; +import aya.instruction.named.NamedOperator; import aya.obj.Obj; import aya.obj.list.List; import aya.obj.number.Num; import aya.util.Casting; -public class SocketInstructionStore extends NamedInstructionStore { - +public class SocketInstructionStore implements NamedInstructionStore { + @Override - protected void init() { + public Collection getNamedInstructions() { SocketManager socket_manager = new SocketManager(); - - addInstruction(new NamedOperator("socket.open_server", "ip::str port::int: Open a socket server") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj obj_port = blockEvaluator.pop(); - final Obj obj_ip = blockEvaluator.pop(); - if (obj_port.isa(Obj.NUM)) { - int port = Casting.asNumber(obj_port).toInt(); - String ip = obj_ip.str(); - int result = SocketManager.NULL_ID; - - try { - result = socket_manager.openServer(ip, port); - } catch (IOException e) { - result = SocketManager.NULL_ID; - throw new IOError(opName(), ip + ":" + port, e); + + return Arrays.asList( + new NamedOperator("socket.open_server", "ip::str port::int: Open a socket server") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj obj_port = blockEvaluator.pop(); + final Obj obj_ip = blockEvaluator.pop(); + if (obj_port.isa(Obj.NUM)) { + int port = Casting.asNumber(obj_port).toInt(); + String ip = obj_ip.str(); + int result = SocketManager.NULL_ID; + + try { + result = socket_manager.openServer(ip, port); + } catch (IOException e) { + result = SocketManager.NULL_ID; + throw new IOError(opName(), ip + ":" + port, e); + } + + blockEvaluator.push(Num.fromInt(result)); + } else { + throw new TypeError(this, "SN"); + } } - - blockEvaluator.push(Num.fromInt(result)); - } else { - throw new TypeError(this, "SN"); - } - } - }); - - - addInstruction(new NamedOperator("socket.accept", "server_id::int: Open a connection on the server") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - int id = getSingleIntArg(this, blockEvaluator); - int sock_id = socket_manager.accept(id); - blockEvaluator.push(Num.fromInt(sock_id)); - } - }); - - addInstruction(new NamedOperator("socket.open_client", "ip::str port::int: Open a socket client") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj obj_port = blockEvaluator.pop(); - final Obj obj_ip = blockEvaluator.pop(); - if (obj_port.isa(Obj.NUM)) { - int port = Casting.asNumber(obj_port).toInt(); - String ip = obj_ip.str(); - try { - int result = socket_manager.openClient(ip, port); - blockEvaluator.push(Num.fromInt(result)); - } catch (IOException e) { - throw new IOError(opName(), ip + ":" + port, e); + }, + + + new NamedOperator("socket.accept", "server_id::int: Open a connection on the server") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + int id = getSingleIntArg(this, blockEvaluator); + int sock_id = socket_manager.accept(id); + blockEvaluator.push(Num.fromInt(sock_id)); } - - } else { - throw new TypeError(this, "SN"); - } - } - }); - - - addInstruction(new NamedOperator("socket.send", "data::str id::int: Send data on a socket") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj obj_id = blockEvaluator.pop(); - final Obj obj_data = blockEvaluator.pop(); - if (obj_id.isa(Obj.NUM)) { - int id = Casting.asNumber(obj_id).toInt(); - AyaSocket sock = socket_manager.getSocket(id); - String data = obj_data.str(); - try { - sock.send(data); - } catch (IOException e) { - throw new IOError(opName(), sock.getAddr() + ":" + sock.getPort(), e); + }, + + new NamedOperator("socket.open_client", "ip::str port::int: Open a socket client") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj obj_port = blockEvaluator.pop(); + final Obj obj_ip = blockEvaluator.pop(); + if (obj_port.isa(Obj.NUM)) { + int port = Casting.asNumber(obj_port).toInt(); + String ip = obj_ip.str(); + try { + int result = socket_manager.openClient(ip, port); + blockEvaluator.push(Num.fromInt(result)); + } catch (IOException e) { + throw new IOError(opName(), ip + ":" + port, e); + } + + } else { + throw new TypeError(this, "SN"); + } + } + }, + + + new NamedOperator("socket.send", "data::str id::int: Send data on a socket") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj obj_id = blockEvaluator.pop(); + final Obj obj_data = blockEvaluator.pop(); + if (obj_id.isa(Obj.NUM)) { + int id = Casting.asNumber(obj_id).toInt(); + AyaSocket sock = socket_manager.getSocket(id); + String data = obj_data.str(); + try { + sock.send(data); + } catch (IOException e) { + throw new IOError(opName(), sock.getAddr() + ":" + sock.getPort(), e); + } + } else { + throw new TypeError(this, "SN"); + } + } + }, + + + new NamedOperator("socket.close", "id::num: Close a socket or server") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + int id = getSingleIntArg(this, blockEvaluator); + // May be either a socket or a server + socket_manager.closeSocket(id); + socket_manager.closeSocketServer(id); + } + }, + + + new NamedOperator("socket.recv", "id::num: Read from a socket") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + int id = getSingleIntArg(this, blockEvaluator); + AyaSocket sock = socket_manager.getSocket(id); + blockEvaluator.push(List.fromString(sock.recv())); + } + }, + + new NamedOperator("socket.get_addr", "id::num: Get the socket's connection addr") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + int id = getSingleIntArg(this, blockEvaluator); + blockEvaluator.push(List.fromString(socket_manager.getIP(id).toString())); + } + }, + + new NamedOperator("socket.get_port", "id::num: Get the socket's connection port") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + int id = getSingleIntArg(this, blockEvaluator); + blockEvaluator.push(Num.fromInt(socket_manager.getPort(id))); } - } else { - throw new TypeError(this, "SN"); } - } - }); - - - addInstruction(new NamedOperator("socket.close", "id::num: Close a socket or server") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - int id = getSingleIntArg(this, blockEvaluator); - // May be either a socket or a server - socket_manager.closeSocket(id); - socket_manager.closeSocketServer(id); - } - }); - - - addInstruction(new NamedOperator("socket.recv", "id::num: Read from a socket") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - int id = getSingleIntArg(this, blockEvaluator); - AyaSocket sock = socket_manager.getSocket(id); - blockEvaluator.push(List.fromString(sock.recv())); - } - }); - - addInstruction(new NamedOperator("socket.get_addr", "id::num: Get the socket's connection addr") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - int id = getSingleIntArg(this, blockEvaluator); - blockEvaluator.push(List.fromString(socket_manager.getIP(id).toString())); - } - }); - - addInstruction(new NamedOperator("socket.get_port", "id::num: Get the socket's connection port") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - int id = getSingleIntArg(this, blockEvaluator); - blockEvaluator.push(Num.fromInt(socket_manager.getPort(id))); - } - }); + ); } - + private static int getSingleIntArg(NamedOperator i, BlockEvaluator blockEvaluator) { final Obj obj_id = blockEvaluator.pop(); if (obj_id.isa(Obj.NUM)) { diff --git a/src/aya/ext/sys/SystemInstructionStore.java b/src/aya/ext/sys/SystemInstructionStore.java index a4ad4ad1..23c66dd4 100644 --- a/src/aya/ext/sys/SystemInstructionStore.java +++ b/src/aya/ext/sys/SystemInstructionStore.java @@ -3,6 +3,8 @@ import java.io.File; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import aya.AyaPrefs; import aya.eval.BlockEvaluator; @@ -13,162 +15,165 @@ import aya.obj.list.List; import aya.util.FileUtils; -public class SystemInstructionStore extends NamedInstructionStore { - +public class SystemInstructionStore implements NamedInstructionStore { + @Override - protected void init() { - // Exec - addInstruction(new SysExecInstruction()); - - // Readdir - addInstruction(new NamedOperator("sys.readdir", "list files in working dir") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj arg = blockEvaluator.pop(); - - if (arg.isa(Obj.STR)) { - String fstr = arg.str(); - Path path = FileUtils.resolvePath(fstr); - ArrayList dirs = AyaPrefs.listFilesAndDirsForFolder(path); - ArrayList obj_dirs = new ArrayList(dirs.size()); - for (String s : dirs) { - obj_dirs.add(List.fromString(s)); + public Collection getNamedInstructions() { + return Arrays.asList( + + // Exec + new SysExecInstruction(), + + // Readdir + new NamedOperator("sys.readdir", "list files in working dir") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj arg = blockEvaluator.pop(); + + if (arg.isa(Obj.STR)) { + String fstr = arg.str(); + Path path = FileUtils.resolvePath(fstr); + ArrayList dirs = AyaPrefs.listFilesAndDirsForFolder(path); + ArrayList obj_dirs = new ArrayList(dirs.size()); + for (String s : dirs) { + obj_dirs.add(List.fromString(s)); + } + blockEvaluator.push(new List(obj_dirs)); + } else { + throw new ValueError(":(sys.readdir) : arg must be a string. Received:\n" + arg.repr()); } - blockEvaluator.push(new List(obj_dirs)); - } else { - throw new ValueError(":(sys.readdir) : arg must be a string. Received:\n" + arg.repr()); } - } - }); - - // Get working dir - addInstruction(new NamedOperator("sys.wd", "get absolute path of working dir") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - blockEvaluator.push(List.fromString(AyaPrefs.getWorkingDir())); - } - }); + }, - // Get aya dir - addInstruction(new NamedOperator("sys.ad", "get absolute path of aya dir") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - blockEvaluator.push(List.fromString(AyaPrefs.getAyaDir())); - } - }); - - // Get aya dir - addInstruction(new NamedOperator("sys.set_ad", "set absolute path of aya dir") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - AyaPrefs.setAyaDir(blockEvaluator.pop().str()); - } - }); - - // Set working dir - addInstruction(new NamedOperator("sys.cd", "set the working dir (empy string resets to default)") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj arg = blockEvaluator.pop(); - - if (arg.isa(Obj.STR)) { - String dir = arg.str(); - if(dir.equals("")) { - AyaPrefs.resetWorkingDir(); - } else { - if (!AyaPrefs.setWorkingDir(arg.str())) { - throw new ValueError(":(sys.cd) : arg is not a valid path." - + " Did you include a '/' or '\' at the end? Received:\n" + arg.repr()); + // Get working dir + new NamedOperator("sys.wd", "get absolute path of working dir") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + blockEvaluator.push(List.fromString(AyaPrefs.getWorkingDir())); + } + }, + + // Get aya dir + new NamedOperator("sys.ad", "get absolute path of aya dir") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + blockEvaluator.push(List.fromString(AyaPrefs.getAyaDir())); + } + }, + + // Get aya dir + new NamedOperator("sys.set_ad", "set absolute path of aya dir") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + AyaPrefs.setAyaDir(blockEvaluator.pop().str()); + } + }, + + // Set working dir + new NamedOperator("sys.cd", "set the working dir (empy string resets to default)") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj arg = blockEvaluator.pop(); + + if (arg.isa(Obj.STR)) { + String dir = arg.str(); + if (dir.equals("")) { + AyaPrefs.resetWorkingDir(); + } else { + if (!AyaPrefs.setWorkingDir(arg.str())) { + throw new ValueError(":{sys.cd} : arg is not a valid path." + + " Did you include a '/' or '\' at the end? Received:\n" + arg.repr()); + } } + } else { + throw new ValueError(":{sys.cd} : arg must be a string. Received:\n" + arg.repr()); } - } else { - throw new ValueError(":(sys.cd) : arg must be a string. Received:\n" + arg.repr()); } - } - }); - - // Make dir - addInstruction(new NamedOperator("sys.mkdir", "create a directory") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj arg = blockEvaluator.pop(); - - if(arg.isa(Obj.STR)) { - String fstr = arg.str(); - if(!AyaPrefs.mkDir(fstr)) { - throw new ValueError(":(sys.mkdir) : arg must be a valid name. Received:\n" + fstr); + }, + + // Make dir + new NamedOperator("sys.mkdir", "create a directory") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj arg = blockEvaluator.pop(); + + if (arg.isa(Obj.STR)) { + String fstr = arg.str(); + if (!AyaPrefs.mkDir(fstr)) { + throw new ValueError(":{sys.mkdir} : arg must be a valid name. Received:\n" + fstr); + } + } else { + throw new ValueError(":{sys.mkdir} : arg must be a string. Received:\n" + arg.repr()); } - } else { - throw new ValueError(":(sys.mkdir) : arg must be a string. Received:\n" + arg.repr()); } - } - }); - - - // System.getProperty - addInstruction(new NamedOperator("sys.getprop", "call System.getProperty with the given key") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj arg = blockEvaluator.pop(); - String val = System.getProperty(arg.str()); - if (val == null) { - blockEvaluator.push(List.fromString("")); - } else { - blockEvaluator.push(List.fromString(val)); - } - } - }); - - // Delete file or directory - addInstruction(new NamedOperator("sys.rm", "remove a file or directory") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj arg = blockEvaluator.pop(); - - if(arg.isa(Obj.STR)) { - String arg_str = arg.str(); - if(arg_str.equals("")) { - throw new ValueError(":(sys.rm) : arg must be a valid name. Received:\n" + arg_str); + }, + + // System.getProperty + new NamedOperator("sys.getprop", "call System.getProperty with the given key") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj arg = blockEvaluator.pop(); + String val = System.getProperty(arg.str()); + if (val == null) { + blockEvaluator.push(List.fromString("")); + } else { + blockEvaluator.push(List.fromString(val)); } - File delFile = FileUtils.resolveFile(arg.str()); - if(!AyaPrefs.deleteFile(delFile)) { - throw new ValueError(":(sys.rm) : arg must be a valid name. Received:\n" + delFile.getAbsolutePath()); + } + }, + + // Delete file or directory + new NamedOperator("sys.rm", "remove a file or directory") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj arg = blockEvaluator.pop(); + + if (arg.isa(Obj.STR)) { + String arg_str = arg.str(); + if (arg_str.equals("")) { + throw new ValueError(":{sys.rm} : arg must be a valid name. Received:\n" + arg_str); + } + File delFile = FileUtils.resolveFile(arg.str()); + if (!AyaPrefs.deleteFile(delFile)) { + throw new ValueError(":{sys.rm} : arg must be a valid name. Received:\n" + delFile.getAbsolutePath()); + } + } else { + throw new ValueError(":{sys.rm} : arg must be a string. Received:\n" + arg.repr()); } - } else { - throw new ValueError(":(sys.rm) : arg must be a string. Received:\n" + arg.repr()); } - } - }); - - addInstruction(new FileExistsSystemInstruction()); - - // Resolve home (replace ~/ with /path/to/home) - addInstruction(new NamedOperator("sys.resolvehome", "replace ~/.. with /path/to/home/..") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj arg = blockEvaluator.pop(); - blockEvaluator.push(List.fromString(FileUtils.resolveHome(arg.str()))); - } - }); - - // Change the prompt text - addInstruction(new NamedOperator("sys.alterprompt", "change the prompt text") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - final Obj arg = blockEvaluator.pop(); - AyaPrefs.setPrompt(arg.str()); - } - }); + }, - addInstruction(new NamedOperator("sys.args", "CLI args") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - List args = new List(); - for (String a : AyaPrefs.getArgs()) { - args.mutAdd(List.fromString(a)); + // Test if file exists + new FileExistsSystemInstruction(), + + // Resolve home (replace ~/ with /path/to/home) + new NamedOperator("sys.resolvehome", "replace ~/.. with /path/to/home/..") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj arg = blockEvaluator.pop(); + blockEvaluator.push(List.fromString(FileUtils.resolveHome(arg.str()))); + } + }, + + // Change the prompt text + new NamedOperator("sys.alterprompt", "change the prompt text") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + final Obj arg = blockEvaluator.pop(); + AyaPrefs.setPrompt(arg.str()); + } + }, + + new NamedOperator("sys.args", "CLI args") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + List args = new List(); + for (String a : AyaPrefs.getArgs()) { + args.mutAdd(List.fromString(a)); + } + blockEvaluator.push(args); } - blockEvaluator.push(args); } - }); + ); } } diff --git a/src/aya/ext/thread/ThreadInstructionStore.java b/src/aya/ext/thread/ThreadInstructionStore.java index 15490cb9..81a851a4 100644 --- a/src/aya/ext/thread/ThreadInstructionStore.java +++ b/src/aya/ext/thread/ThreadInstructionStore.java @@ -1,6 +1,8 @@ package aya.ext.thread; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import aya.AyaThread; @@ -21,17 +23,17 @@ import aya.util.Casting; import aya.util.Pair; -public class ThreadInstructionStore extends NamedInstructionStore { - +public class ThreadInstructionStore implements NamedInstructionStore { + HashMap _thread_table; volatile int _thread_counter; volatile int _request_id_counter; - + public ThreadInstructionStore() { _thread_table = new HashMap(); _thread_counter = 0; } - + private Pair newThread(ExecutionContext context) { AyaThread thread = AyaThread.spawnChildThread(context); _thread_counter++; @@ -39,7 +41,7 @@ private Pair newThread(ExecutionContext context) { _thread_table.put(pair.first(), pair.second()); return pair; } - + // Throws an exception if the thread does not exist or is not alive private AyaThread getThread(int thread_id) { AyaThread thread = _thread_table.get(thread_id); @@ -51,125 +53,126 @@ private AyaThread getThread(int thread_id) { return thread; } } - + private int newRequestId() { return _request_id_counter++; } - + @Override - protected void init() { - - addInstruction(new NamedOperator("thread.new", "create a thread") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - Pair thread = newThread(blockEvaluator.getContext()); - thread.second().start(); - blockEvaluator.push(Num.fromInt(thread.first())); - } - }); - - addInstruction(new NamedOperator("thread.add_task", "add a task") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - Obj thread_id_obj = blockEvaluator.pop(); - Obj task_obj = blockEvaluator.pop(); - if (thread_id_obj.isa(Obj.NUM) && task_obj.isa(Obj.BLOCK)) { - int thread_id = Casting.asNumber(thread_id_obj).toInt(); - AyaThread thread = getThread(thread_id); - thread.queueInput(new ExecutionRequest(newRequestId(), Casting.asStaticBlock(task_obj))); - } else { - throw new TypeError(this, "N", thread_id_obj); - } - } - }); - - addInstruction(new NamedOperator("thread.wait_for_result", "wait for a result") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - Obj thread_id_obj = blockEvaluator.pop(); - if (thread_id_obj.isa(Obj.NUM)) { - int thread_id = Casting.asNumber(thread_id_obj).toInt(); - AyaThread thread = getThread(thread_id); - try { - ExecutionResult res = thread.waitForResponse(); - List out = new List(ExecutionResultUtils.getDataOrThrowIfException(res)); - blockEvaluator.push(out); - } catch (InterruptedException e) { - throw new ThreadError(e); - } catch (ThreadError te) { - throw new ThreadError(thread_id, te.getMessage()); + public Collection getNamedInstructions() { + return Arrays.asList( + new NamedOperator("thread.new", "create a thread") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + Pair thread = newThread(blockEvaluator.getContext()); + thread.second().start(); + blockEvaluator.push(Num.fromInt(thread.first())); } - } else { - throw new TypeError(this, "N", thread_id_obj); - } - } - }); - - addInstruction(new NamedOperator("thread.has_unfinished_tasks", "check if the thread has any unfinished tasks") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - Obj thread_id_obj = blockEvaluator.pop(); - if (thread_id_obj.isa(Obj.NUM)) { - int thread_id = Casting.asNumber(thread_id_obj).toInt(); - AyaThread thread = getThread(thread_id); - blockEvaluator.push(Num.fromBool(thread.hasUnfinishedTasks())); - } else { - throw new TypeError(this, "N", thread_id_obj); - } - } - }); - - addInstruction(new NamedOperator("thread.runall", "Run all blocks in parallel") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - ExecutionContext context = blockEvaluator.getContext(); - - final Obj blocks_obj = blockEvaluator.pop(); - - if (blocks_obj.isa(Obj.LIST)) { - List blocks = Casting.asList(blocks_obj); - - ArrayList tasks = new ArrayList(); - for (int i = 0; i < blocks.length(); i++) { - if (blocks.getExact(i).isa(Obj.BLOCK)) { - tasks.add(Casting.asStaticBlock(blocks.getExact(i))); + }, + + new NamedOperator("thread.add_task", "add a task") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + Obj thread_id_obj = blockEvaluator.pop(); + Obj task_obj = blockEvaluator.pop(); + if (thread_id_obj.isa(Obj.NUM) && task_obj.isa(Obj.BLOCK)) { + int thread_id = Casting.asNumber(thread_id_obj).toInt(); + AyaThread thread = getThread(thread_id); + thread.queueInput(new ExecutionRequest(newRequestId(), Casting.asStaticBlock(task_obj))); } else { - throw new TypeError(this, "L", blocks_obj); + throw new TypeError(this, "N", thread_id_obj); } } - - ArrayList threads = new ArrayList(); - - // Spawn a thread for each task - for (int i = 0; i < tasks.size(); i++) { - AyaThread thread = AyaThread.spawnChildThread(context); - thread.queueInput(new ExecutionRequest(-1, tasks.get(i))); - threads.add(thread); + }, + + new NamedOperator("thread.wait_for_result", "wait for a result") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + Obj thread_id_obj = blockEvaluator.pop(); + if (thread_id_obj.isa(Obj.NUM)) { + int thread_id = Casting.asNumber(thread_id_obj).toInt(); + AyaThread thread = getThread(thread_id); + try { + ExecutionResult res = thread.waitForResponse(); + List out = new List(ExecutionResultUtils.getDataOrThrowIfException(res)); + blockEvaluator.push(out); + } catch (InterruptedException e) { + throw new ThreadError(e); + } catch (ThreadError te) { + throw new ThreadError(thread_id, te.getMessage()); + } + } else { + throw new TypeError(this, "N", thread_id_obj); + } } - - for (AyaThread t : threads) t.start(); - - List out = new List(); - - for (AyaThread thread : threads) { - ExecutionResult result; - try { - result = thread.waitForResponse(); - } catch (InterruptedException e) { - throw new ThreadError(e); + }, + + new NamedOperator("thread.has_unfinished_tasks", "check if the thread has any unfinished tasks") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + Obj thread_id_obj = blockEvaluator.pop(); + if (thread_id_obj.isa(Obj.NUM)) { + int thread_id = Casting.asNumber(thread_id_obj).toInt(); + AyaThread thread = getThread(thread_id); + blockEvaluator.push(Num.fromBool(thread.hasUnfinishedTasks())); + } else { + throw new TypeError(this, "N", thread_id_obj); + } + } + }, + + new NamedOperator("thread.runall", "Run all blocks in parallel") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + ExecutionContext context = blockEvaluator.getContext(); + + final Obj blocks_obj = blockEvaluator.pop(); + + if (blocks_obj.isa(Obj.LIST)) { + List blocks = Casting.asList(blocks_obj); + + ArrayList tasks = new ArrayList(); + for (int i = 0; i < blocks.length(); i++) { + if (blocks.getExact(i).isa(Obj.BLOCK)) { + tasks.add(Casting.asStaticBlock(blocks.getExact(i))); + } else { + throw new TypeError(this, "L", blocks_obj); + } + } + + ArrayList threads = new ArrayList(); + + // Spawn a thread for each task + for (int i = 0; i < tasks.size(); i++) { + AyaThread thread = AyaThread.spawnChildThread(context); + thread.queueInput(new ExecutionRequest(-1, tasks.get(i))); + threads.add(thread); + } + + for (AyaThread t : threads) t.start(); + + List out = new List(); + + for (AyaThread thread : threads) { + ExecutionResult result; + try { + result = thread.waitForResponse(); + } catch (InterruptedException e) { + throw new ThreadError(e); + } + + ArrayList data = ExecutionResultUtils.getDataOrThrowIfException(result); + out.mutAdd(new List(data)); + } + + blockEvaluator.push(out); + + } else { + throw new TypeError(this, "L", blocks_obj); } - - ArrayList data = ExecutionResultUtils.getDataOrThrowIfException(result); - out.mutAdd(new List(data)); } - - blockEvaluator.push(out); - - } else { - throw new TypeError(this, "L", blocks_obj); } - } - }); - + ); + } } diff --git a/src/aya/instruction/named/NamedInstructionStore.java b/src/aya/instruction/named/NamedInstructionStore.java index 5dd3caef..fafd9d3b 100644 --- a/src/aya/instruction/named/NamedInstructionStore.java +++ b/src/aya/instruction/named/NamedInstructionStore.java @@ -1,34 +1,7 @@ package aya.instruction.named; -import java.util.HashMap; +import java.util.Collection; -import aya.StaticData; - -public abstract class NamedInstructionStore { - - private HashMap _instructions; - - public NamedInstructionStore() { - _instructions = new HashMap(); - init(); - } - - protected void addInstruction(NamedOperator inst) { - _instructions.put(inst.getName(), inst); - } - - public NamedOperator getInstruction(String name) { - return _instructions.get(name); - } - - public void initHelpData(StaticData staticData) { - for (HashMap.Entry pair : _instructions.entrySet()) { - NamedOperator i = pair.getValue(); - String doc = i._doc; - if (doc == null || doc.equals("")) continue; - staticData.addHelpText(":(" + i.getName() + ")\n " + doc); - } - } - - protected abstract void init(); +public interface NamedInstructionStore { + Collection getNamedInstructions(); } diff --git a/src/aya/instruction/named/NamedOperator.java b/src/aya/instruction/named/NamedOperator.java index 6a1ce1c1..4b5dce36 100644 --- a/src/aya/instruction/named/NamedOperator.java +++ b/src/aya/instruction/named/NamedOperator.java @@ -28,6 +28,10 @@ public String opName() { return ":(" + _name + ")"; } + public String getDoc() { + return _doc; + } + public ReprStream repr(ReprStream stream) { stream.print(opName()); return stream; diff --git a/src/web/AyaWeb.java b/src/web/AyaWeb.java index c16bb18d..26e3a7df 100644 --- a/src/web/AyaWeb.java +++ b/src/web/AyaWeb.java @@ -41,6 +41,7 @@ public static void main(String[] args) { // // Named Instructions // Web build only supports a limited set of named instructions + // We do not use the full initNamedInstructions method for web // WebAvailableNamedInstructionStore wsi = new WebAvailableNamedInstructionStore(); sd.addNamedInstructionStore(wsi); diff --git a/src/web/WebAvailableNamedInstructionStore.java b/src/web/WebAvailableNamedInstructionStore.java index c5a1eb77..fc5f440a 100644 --- a/src/web/WebAvailableNamedInstructionStore.java +++ b/src/web/WebAvailableNamedInstructionStore.java @@ -1,5 +1,8 @@ package web; +import java.util.Arrays; +import java.util.Collection; + import aya.eval.BlockEvaluator; import aya.exceptions.runtime.UnimplementedError; import aya.ext.sys.FileExistsSystemInstruction; @@ -8,7 +11,7 @@ import aya.obj.list.List; import aya.obj.list.Str; -public class WebAvailableNamedInstructionStore extends NamedInstructionStore { +public class WebAvailableNamedInstructionStore implements NamedInstructionStore { /** * This class provides some overrides for aya instructions so they work in the web implementation * @@ -16,32 +19,40 @@ public class WebAvailableNamedInstructionStore extends NamedInstructionStore { */ @Override - protected void init() { - - addInstruction(new FileExistsSystemInstruction()); - - addInstruction(new NamedOperator("sys.ad", "get absolute path of aya dir") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - blockEvaluator.push(List.fromStr(Str.EMPTY)); - } - }); - - addInstruction(new NamedOperator("sys.wd", "get absolute path of working dir") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - blockEvaluator.push(List.fromStr(Str.EMPTY)); + public Collection getNamedInstructions() { + return Arrays.asList( + new FileExistsSystemInstruction(), + + new NamedOperator("sys.ad", "get absolute path of aya dir") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + blockEvaluator.push(List.fromStr(Str.EMPTY)); + } + }, + + new NamedOperator("sys.wd", "get absolute path of working dir") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + blockEvaluator.push(List.fromStr(Str.EMPTY)); + } + }, + + new NamedOperator("debug.pause", "pause execution and open a repl") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + // Unimplemented + throw new UnimplementedError(); + } + }, + + new NamedOperator("library.load", "load a jar file") { + @Override + public void execute(BlockEvaluator blockEvaluator) { + // Unimplemented + throw new UnimplementedError(); + } } - }); - - addInstruction(new NamedOperator("debug.pause", "pause execution and open a repl") { - @Override - public void execute(BlockEvaluator blockEvaluator) { - // Unimplemented - throw new UnimplementedError(); - } - }); - + ); } }