diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/Main.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/Main.java index cb92678..f4e1b2a 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/Main.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/Main.java @@ -4,7 +4,7 @@ import me.tapeline.quailj.typing.classes.QObject; // TODO fix error display - +// TODO fix in operator and add contains method to list public class Main { public static void main(String[] args) { diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/docgen/DocumentationGenerator.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/docgen/DocumentationGenerator.java index ea4294c..3a34532 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/docgen/DocumentationGenerator.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/docgen/DocumentationGenerator.java @@ -25,7 +25,7 @@ public class DocumentationGenerator { ); private final String documentationHeader = "\n" + - "\n" + + "\n" + "\n" + " \n" + " \n" + " Docs\n" + + " \n" + "\n" + ""; private final String documentationFooter = "\n" + diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/launcher/LaunchCommandParser.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/launcher/LaunchCommandParser.java index 797918e..1c0f64d 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/launcher/LaunchCommandParser.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/launcher/LaunchCommandParser.java @@ -14,6 +14,7 @@ public class LaunchCommandParser { private final HashMap userFlags; private String selectedRunStrategy; private String targetScript; + private String scriptArgString; private String outputFile; @@ -35,6 +36,8 @@ public static boolean toBoolean(String strValue) { public void parseReceivedArgs() { boolean strategySet = false; boolean waitingOutputFile = false; + boolean waitingScriptArgString = false; + StringBuilder scriptArgString = new StringBuilder(); for (String arg : receivedConsoleArgs) { if (arg.startsWith("-")) parseFlag(arg); else if (!strategySet) { @@ -47,14 +50,17 @@ else if (!strategySet) { } else if (waitingOutputFile) { outputFile = arg; break; + } else if (waitingScriptArgString) { + scriptArgString.append(arg).append(" "); } else { targetScript = arg; if (selectedRunStrategy.equalsIgnoreCase("run") || selectedRunStrategy.equalsIgnoreCase("profile") || selectedRunStrategy.equalsIgnoreCase("debug")) - break; + waitingScriptArgString = true; } } + this.scriptArgString = scriptArgString.toString(); } private void parseFlag(String flag) { @@ -114,4 +120,9 @@ public String getTargetScript() { public String getOutputFile() { return outputFile; } + + public String getScriptArgString() { + return scriptArgString; + } + } diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/launcher/QuailLauncher.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/launcher/QuailLauncher.java index b23cae9..46aee9e 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/launcher/QuailLauncher.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/launcher/QuailLauncher.java @@ -28,9 +28,9 @@ public class QuailLauncher { public static final int QUAIL_MAJOR_VERSION = 2; public static final int QUAIL_MINOR_VERSION = 0; public static final int QUAIL_PATCH_VERSION = 0; - public static final String QUAIL_VERSION_STATUS = "alpha"; - public static final int QUAIL_SUBVERSION = 7; - public static final String QUAIL_VERSION_SUFFIX = "RC-2"; + public static final String QUAIL_VERSION_STATUS = "beta"; + public static final int QUAIL_SUBVERSION = 8; + public static final String QUAIL_VERSION_SUFFIX = "RC-3"; private HashMap localFlags; @@ -125,6 +125,7 @@ public QObject launch(String[] args) throws IOException, PreprocessorException, new File(launchCommandParser.getTargetScript()), scriptHome, new DefaultIO(), doProfile, doDebug); QObject returnValue = QObject.Val(0); + runtime.setScriptArgs(launchCommandParser.getScriptArgString()); try { runtime.run(parsedCode, runtime.getMemory()); } catch (RuntimeStriker striker) { @@ -172,6 +173,8 @@ public QObject launchWithAnonymousCode(String code, File scriptHome, String[] ar Runtime runtime = new Runtime(parsedCode, preprocessedCode, new File(""), scriptHome, io, doProfile, doDebug); + runtime.setScriptArgs(launchCommandParser.getScriptArgString()); + QObject returnValue = QObject.Val(0); try { runtime.run(parsedCode, runtime.getMemory()); diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/lexing/Lexer.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/lexing/Lexer.java index 7fb888a..f1de7ac 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/lexing/Lexer.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/lexing/Lexer.java @@ -166,6 +166,21 @@ private char peekNext() { return sourceCode.charAt(current + 1); } + /** + * Gets next non-whitespace character index + * @return -1 if next char is out of code bounds. If not - target char index + */ + private int findNextSignificantIndex() { + int offset = 0; + while (current + offset < sourceCode.length()) { + if (isSignificant(sourceCode.charAt(current + offset))) + return offset; + else + offset++; + } + return -1; + } + /** * @param c target character * @return whether the character is a digit @@ -192,6 +207,14 @@ private boolean isAlphaNumeric(char c) { return isAlpha(c) || isDigit(c); } + /** + * @param c target character + * @return whether the character is significant + */ + private boolean isSignificant(char c) { + return c != '\n' && c != '\t' && c != '\r' && c != ' '; + } + /** * Checks for short assign operators and adds binary op token * @param type binary operator token diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/lexing/TokenType.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/lexing/TokenType.java index 971e359..9f729cf 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/lexing/TokenType.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/lexing/TokenType.java @@ -113,6 +113,7 @@ public enum TokenType { DOT, VAR, IN, + NOT_IN, INSTANCEOF, LIKE, DOCS, diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/parsing/Parser.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/parsing/Parser.java index 5a8f5d6..f0f9f56 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/parsing/Parser.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/parsing/Parser.java @@ -444,40 +444,6 @@ private BlockNode parsePythonBlock() throws ParserException { } } - @Deprecated // TODO Remove?? - private Node newNode(Class node, Object... args) { - Constructor foundConstructor = null; - for (Constructor constructor : node.getConstructors()) { - if (constructor.getParameterCount() != args.length) - continue; - boolean matches = true; - for (int i = 0; i < args.length; i++) { - if (args[i] == null) continue; - Class parameterClass = constructor.getParameterTypes()[i]; - if (constructor.getParameterTypes()[i].isPrimitive()) - parameterClass = ClassUtils.primitiveToWrapper( - constructor.getParameterTypes()[i]); - if (!parameterClass.isAssignableFrom(args[i].getClass())) { - matches = false; - break; - } - } - if (matches) { - foundConstructor = constructor; - break; - } - } - if (foundConstructor == null) - throw new RuntimeException("Cannot find suitable constructor"); - try { - return applyDecorations(pendingDecorations, - (Node) foundConstructor.newInstance(args)); - } catch (InstantiationException | IllegalAccessException | - InvocationTargetException e) { - throw new RuntimeException(e); - } - } - /** * Transforms given node with provided decorations in reverse order * E.g.: @Decorator(...) function f() ... will be transformed into @@ -859,9 +825,11 @@ else if (name.getLexeme().equals("call")) Node statement = parseStatement(); function = new LiteralFunction(funcToken, "_constructor", args, statement); } - if (decorations != null) - return applyDecorations(decorations, function); - else + if (decorations != null) { + Node node = applyDecorations(decorations, function); + pendingDecorations.clear(); + return node; + } else return function; } @@ -883,9 +851,12 @@ private Node parseClass() throws ParserException { else if (expr instanceof VariableNode) contents.add(new VarAssignNode(expr.getToken(), ((VariableNode) expr), getDefaultNodeFor(((VariableNode) expr).modifiers))); - else if (expr instanceof LiteralFunction) - methods.put(((LiteralFunction) expr).name, ((LiteralFunction) expr)); - else + else if (expr instanceof LiteralFunction) { + if (methods.containsKey(((LiteralFunction) expr).name)) + initialize.add(expr); // In case there is an overloaded method + else + methods.put(((LiteralFunction) expr).name, ((LiteralFunction) expr)); + } else initialize.add(expr); } return new LiteralClass(classToken, className.getLexeme(), like, contents, methods, initialize); @@ -944,8 +915,17 @@ private Node parseAnd(ParsingPolicy policy) throws ParserException { private Node parseEquality(ParsingPolicy policy) throws ParserException { Node left = parseComparison(policy); - while (matchMultiple(EQUALS, NOT_EQUALS, INSTANCEOF, IN) != null) - left = new BinaryOperatorNode(getPrevious(), left, parseComparison(policy)); + while (true) { + Token op = matchMultiple(EQUALS, NOT_EQUALS, INSTANCEOF, IN); + if (op == null && forseePattern(NOT, IN)) { + Token notToken = require(NOT); + Token inToken = require(IN); + op = new Token(NOT_IN, "not in", notToken.getLine(), notToken.getCharacter(), + inToken.getCharacter() + inToken.getLength() - notToken.getCharacter()); + } + if (op == null) break; + left = new BinaryOperatorNode(op, left, parseComparison(policy)); + } return left; } diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/Runtime.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/Runtime.java index a7aed27..3272257 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/Runtime.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/Runtime.java @@ -26,11 +26,13 @@ import me.tapeline.quailj.runtime.std.basic.common.*; import me.tapeline.quailj.runtime.std.basic.numbers.*; import me.tapeline.quailj.runtime.std.basic.threading.QThread; +import me.tapeline.quailj.runtime.std.cli.CliLibrary; import me.tapeline.quailj.runtime.std.event.EventLibrary; import me.tapeline.quailj.runtime.std.fs.FSLibrary; import me.tapeline.quailj.runtime.std.ji.JILibrary; import me.tapeline.quailj.runtime.std.math.MathLibrary; import me.tapeline.quailj.runtime.std.qml.QMLLibrary; +import me.tapeline.quailj.runtime.std.reflect.ReflectLibrary; import me.tapeline.quailj.runtime.std.storage.StorageLibrary; import me.tapeline.quailj.typing.classes.*; import me.tapeline.quailj.typing.classes.errors.*; @@ -55,6 +57,7 @@ public class Runtime { protected final boolean doProfile; protected final boolean doDebug; protected final String code; + protected String scriptArgs; protected final IO io; protected Node current = new Node(Token.UNDEFINED) { @Override @@ -93,6 +96,14 @@ public Runtime(Node root, String code, File scriptFile, File scriptHome, io.resetCwd(); } + public String getScriptArgs() { + return scriptArgs; + } + + public void setScriptArgs(String scriptArgs) { + this.scriptArgs = scriptArgs; + } + public File getScriptFile() { return scriptFile; } @@ -255,6 +266,8 @@ private void registerDefaults() { libraryLoader.addBuiltinLibrary(new FSLibrary()); libraryLoader.addBuiltinLibrary(new StorageLibrary()); libraryLoader.addBuiltinLibrary(new MathLibrary()); + libraryLoader.addBuiltinLibrary(new ReflectLibrary()); + libraryLoader.addBuiltinLibrary(new CliLibrary()); } public void error(String message) throws RuntimeStriker { @@ -442,6 +455,8 @@ private QObject performBinaryOperation(QObject operandA, TokenType op, QObject o case LESS_EQUAL: return operandA.lessEqual(this, operandB); case EQUALS: return operandA.equalsObject(this, operandB); case NOT_EQUALS: return operandA.notEqualsObject(this, operandB); + case IN: return operandB.containsObject(this, operandA); + case NOT_IN: return operandB.notContainsObject(this, operandA); case INSTANCEOF: return Val(operandA.instanceOf(operandB)); default: error(new QInternalException("Unknown binary operation " + op)); } diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliGetConsoleArgString.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliGetConsoleArgString.java new file mode 100644 index 0000000..fae644e --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliGetConsoleArgString.java @@ -0,0 +1,33 @@ +package me.tapeline.quailj.runtime.std.cli; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class CliGetConsoleArgString extends QBuiltinFunc { + + public CliGetConsoleArgString(Runtime runtime) { + super( + "getConsoleArgString", + Arrays.asList( + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + return Val(runtime.getScriptArgs()); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliLibrary.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliLibrary.java new file mode 100644 index 0000000..f1bc927 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliLibrary.java @@ -0,0 +1,51 @@ +package me.tapeline.quailj.runtime.std.cli; + +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.runtime.librarymanagement.BuiltinLibrary; +import me.tapeline.quailj.runtime.std.cli.decorators.CliCommand; +import me.tapeline.quailj.runtime.std.cli.decorators.CliTick; +import me.tapeline.quailj.runtime.std.math.MathFuncGcd; +import me.tapeline.quailj.runtime.std.math.MathFuncLcm; +import me.tapeline.quailj.runtime.std.math.MathFuncProduct; +import me.tapeline.quailj.typing.classes.QObject; + +import java.util.ArrayList; +import java.util.HashMap; + +public class CliLibrary implements BuiltinLibrary { + + @Override + public String id() { + return "lang/cli"; + } + + @Override + public Runtime initializeRuntime() { + return new Runtime(); + } + + @Override + public QObject constructLibrary(Runtime runtime) { + HashMap contents = new HashMap<>(); + runtime.getMemory().set("prefix", QObject.Val("> ")); + runtime.getMemory().set("commands", QObject.Val(new HashMap<>())); + runtime.getMemory().set("ticking", QObject.Val(new ArrayList<>())); + runtime.getMemory().set("isRunning", QObject.Val(false)); + runtime.getMemory().set("unknownCommandMessage", QObject.Val("Unknown command")); + + contents.put("getConsoleArgString", new CliGetConsoleArgString(runtime)); + contents.put("parseConsoleArgs", new CliParseConsoleArgs(runtime)); + contents.put("runApp", new CliRunApp(runtime)); + contents.put("stopApp", new CliStopApp(runtime)); + contents.put("setPrefix", new CliSetPrefix(runtime)); + contents.put("setUnknownCommandMessage", new CliSetUnknownCommandMessage(runtime)); + + contents.put("command", new CliCommand(runtime)); + contents.put("tick", new CliTick(runtime)); + + runtime.getMemory().table.putAll(contents); + + return QObject.Val(contents); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliParseConsoleArgs.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliParseConsoleArgs.java new file mode 100644 index 0000000..ac03eea --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliParseConsoleArgs.java @@ -0,0 +1,84 @@ +package me.tapeline.quailj.runtime.std.cli; + +import me.tapeline.quailj.lexing.LexerException; +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.runtime.std.cli.argparser.ArgLexer; +import me.tapeline.quailj.runtime.std.cli.argparser.ArgParser; +import me.tapeline.quailj.runtime.std.cli.argparser.ArgToken; +import me.tapeline.quailj.runtime.std.cli.argparser.ArgTokenType; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; +import me.tapeline.quailj.utils.Dict; +import me.tapeline.quailj.utils.Pair; + +import java.util.*; +import java.util.stream.Collectors; + +public class CliParseConsoleArgs extends QBuiltinFunc { + + public CliParseConsoleArgs(Runtime runtime) { + super( + "parseConsoleArgs", + Arrays.asList( + new FuncArgument( + "argString", + QObject.Val(), + new int[] {ModifierConstants.STR}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + ArgLexer lexer = new ArgLexer(args.get("argString").strValue()); + try { + List tokens = lexer.scan(); + ArgParser parser = new ArgParser(tokens); + parser.parse(); + HashMap kwargs = new HashMap<>(); + for (Map.Entry entry : parser.getKwargs().entrySet()) { + if (entry.getValue() instanceof Double) + kwargs.put(entry.getKey(), Val((Double) entry.getValue())); + if (entry.getValue() instanceof String) + kwargs.put(entry.getKey(), Val((String) entry.getValue())); + if (entry.getValue() instanceof Boolean) + kwargs.put(entry.getKey(), Val((Boolean) entry.getValue())); + } + HashMap flags = new HashMap<>(); + for (Map.Entry entry : parser.getBoolFlags().entrySet()) + flags.put(entry.getKey(), Val(entry.getValue())); + List arguments = parser.getArguments().stream() + .map(arg -> { + if (arg instanceof Double) + return Val((Double) arg); + if (arg instanceof String) + return Val((String) arg); + if (arg instanceof Boolean) + return Val((Boolean) arg); + return Val(); + }) + .collect(Collectors.toList()); + return Val(Dict.make( + new Pair<>("kwargs", Val(kwargs)), + new Pair<>("flags", Val(flags)), + new Pair<>("args", Val(arguments)) + )); + } catch (LexerException e) { + return Val(Dict.make( + new Pair<>("kwargs", Val(new HashMap<>())), + new Pair<>("flags", Val(new HashMap<>())), + new Pair<>("args", Val(new ArrayList<>())) + )); + } + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliRunApp.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliRunApp.java new file mode 100644 index 0000000..89967ad --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliRunApp.java @@ -0,0 +1,59 @@ +package me.tapeline.quailj.runtime.std.cli; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.classes.QDict; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; + +import java.util.*; + +public class CliRunApp extends QBuiltinFunc { + + public CliRunApp(Runtime runtime) { + super( + "runApp", + Arrays.asList( + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + boundRuntime.getMemory().set("isRunning", Val(true)); + while (boundRuntime.getMemory().get("isRunning").boolValue()) { + for (QObject ticking : Objects.requireNonNull(boundRuntime.getMemory().get("ticking").listValue())) + if (ticking.isFunc()) ticking.call(runtime, new ArrayList<>(), new HashMap<>()); + String command = boundRuntime.getMemory().get("input").call( + boundRuntime, Collections.singletonList(boundRuntime.getMemory().get("prefix")), new HashMap<>() + ).strValue(); + assert command != null; + command = command.trim(); + String commandName = command.indexOf(' ') == -1? + command : command.substring(0, command.indexOf(' ')); + String commandArgs = command.indexOf(' ') == -1? + "" : command.substring(command.indexOf(' ') + 1); + QDict argDict = (QDict) boundRuntime.getMemory().get("parseConsoleArgs").call( + boundRuntime, + Collections.singletonList(Val(commandArgs)), + new HashMap<>() + ); + + QObject executor = boundRuntime.getMemory().get("commands").get(commandName); + if (!executor.isFunc()) { + runtime.getIo().println(boundRuntime.getMemory().get("unknownCommandMessage").strValue()); + continue; + } + + executor.call(runtime, Collections.singletonList(argDict), new HashMap<>()); + } + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliSetPrefix.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliSetPrefix.java new file mode 100644 index 0000000..7184b2e --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliSetPrefix.java @@ -0,0 +1,40 @@ +package me.tapeline.quailj.runtime.std.cli; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class CliSetPrefix extends QBuiltinFunc { + + public CliSetPrefix(Runtime runtime) { + super( + "setPrefix", + Arrays.asList( + new FuncArgument( + "prefix", + QObject.Val(), + new int[] {ModifierConstants.STR}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + boundRuntime.getMemory().set("prefix", args.get("prefix")); + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliSetUnknownCommandMessage.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliSetUnknownCommandMessage.java new file mode 100644 index 0000000..e83d120 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliSetUnknownCommandMessage.java @@ -0,0 +1,40 @@ +package me.tapeline.quailj.runtime.std.cli; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.runtime.RuntimeStriker; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.utils.FuncArgument; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class CliSetUnknownCommandMessage extends QBuiltinFunc { + + public CliSetUnknownCommandMessage(Runtime runtime) { + super( + "setUnknownCommandMessage", + Arrays.asList( + new FuncArgument( + "message", + QObject.Val(), + new int[] {ModifierConstants.STR}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + boundRuntime.getMemory().set("unknownCommandMessage", args.get("message")); + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliStopApp.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliStopApp.java new file mode 100644 index 0000000..ceda282 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/CliStopApp.java @@ -0,0 +1,34 @@ +package me.tapeline.quailj.runtime.std.cli; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class CliStopApp extends QBuiltinFunc { + + public CliStopApp(Runtime runtime) { + super( + "stopApp", + Arrays.asList( + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + boundRuntime.getMemory().set("isRunning", Val(false)); + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgLexer.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgLexer.java new file mode 100644 index 0000000..5f35a3e --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgLexer.java @@ -0,0 +1,216 @@ +package me.tapeline.quailj.runtime.std.cli.argparser; + +import me.tapeline.quailj.lexing.LexerException; + +import java.util.ArrayList; +import java.util.List; + +import static me.tapeline.quailj.runtime.std.cli.argparser.ArgTokenType.*; + +public class ArgLexer { + + private final String sourceCode; + private final List tokens = new ArrayList<>(); + private int start = 0; + private int current = 0; + private int startOfCurrentLine = 0; + private int line = 1; + + public ArgLexer(String code) { + sourceCode = code; + } + + private void error(String message) throws LexerException { + throw new LexerException( + message, + line - 1, + start, + current - start, + sourceCode + ); + } + + private boolean reachedEnd() { + return current >= sourceCode.length(); + } + + private char next() { + return sourceCode.charAt(current++); + } + + private void addToken(ArgTokenType type) { + String text = sourceCode.substring(start, current); + tokens.add(new ArgToken(type, text)); + } + + private void addStringToken(String contents) { + tokens.add(new ArgToken(STRING, contents)); + } + + private boolean match(char expected) { + if (reachedEnd()) return false; + if (sourceCode.charAt(current) != expected) return false; + current++; + return true; + } + + private boolean match(String expected) { + if (reachedEnd()) return false; + + if (!sourceCode.substring(current).startsWith(expected)) return false; + + current += expected.length(); + return true; + } + + private char peek() { + if (reachedEnd()) return '\0'; + return sourceCode.charAt(current); + } + + private char peekNext() { + if (current + 1 >= sourceCode.length()) return '\0'; + return sourceCode.charAt(current + 1); + } + + private int findNextSignificantIndex() { + int offset = 0; + while (current + offset < sourceCode.length()) { + if (isSignificant(sourceCode.charAt(current + offset))) + return offset; + else + offset++; + } + return -1; + } + + private boolean isDigit(char c) { + return c >= '0' && c <= '9'; + } + + private boolean isAlpha(char c) { + return (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + c == '_'; + } + + private boolean isAlphaNumeric(char c) { + return isAlpha(c) || isDigit(c); + } + + private boolean isSignificant(char c) { + return c != '\n' && c != '\t' && c != '\r' && c != ' '; + } + + public List scan() throws LexerException { + while (!reachedEnd()) { + start = current; + scanToken(); + } + return tokens; + } + + private void scanToken() throws LexerException { + char c = next(); + switch (c) { + case '-': { + if (match('-')) { + scanId(); + addToken(KEYWORD_FLAG); + } else { + scanId(); + addToken(BOOL_FLAG); + } + break; + } + case '+': { + scanId(); + addToken(BOOL_FLAG); + break; + } + case '=': { + addToken(EQUALS); + break; + } + case '\n': + line++; + startOfCurrentLine = current; + break; + case '"': scanString(); addToken(STRING); break; + case ' ': + case '\r': + case '\t': + break; + default: + if (isDigit(c)) { + scanNumber(); + addToken(NUMBER); + } + else if (isAlpha(c)) { + scanId(); + addToken(ARGUMENT); + } + else + error("Unexpected character " + c); + break; + } + } + + private void scanString() throws LexerException { + StringBuilder content = new StringBuilder(); + while (peek() != '"' && !reachedEnd()) { + if (match("\\\\")) { + content.append('\\'); + continue; + } + if (match("\\\"")) { + content.append("\""); + continue; + } + if (match("\\n")) { + content.append("\n"); + continue; + } + if (match("\\t")) { + content.append("\t"); + continue; + } + if (match("\\r")) { + content.append("\r"); + continue; + } + if (peek() == '\n') { + line++; + startOfCurrentLine = current; + content.append('\n'); + } + content.append(next()); + } + if (reachedEnd()) { + error("Unexpected string end"); + return; + } + next(); + } + + private void scanNumber() { + while (isDigit(peek())) next(); + + if (peek() == '.' && isDigit(peekNext())) { + next(); + while (isDigit(peek())) next(); + } + } + + private String scanId() { + while (isAlphaNumeric(peek())) next(); + String content = sourceCode.substring(start, current); + if (content.equalsIgnoreCase("false") || + content.equalsIgnoreCase("true")) { + addToken(BOOL); + return null; + } + return sourceCode.substring(start, current); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgParser.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgParser.java new file mode 100644 index 0000000..f99e68e --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgParser.java @@ -0,0 +1,70 @@ +package me.tapeline.quailj.runtime.std.cli.argparser; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import static me.tapeline.quailj.runtime.std.cli.argparser.ArgTokenType.*; + +public class ArgParser { + + private List tokens; + private int pos = 0; + private HashMap kwargs = new HashMap<>(); + private HashMap boolFlags = new HashMap<>(); + private List arguments = new ArrayList<>(); + + public ArgParser(List tokens) { + this.tokens = tokens; + } + + public void parse() { + while (pos < tokens.size()) { + ArgToken token = tokens.get(pos++); + if (token.getType().equals(BOOL_FLAG)) { + boolean value = token.getLexeme().charAt(0) == '+'; + for (int i = 1; i < token.getLexeme().length(); i++) + boolFlags.put(String.valueOf(token.getLexeme().charAt(i)), value); + } else if (token.getType().equals(KEYWORD_FLAG)) { + String name = token.getLexeme().substring(2); + if (pos < tokens.size() && tokens.get(pos).getType() == EQUALS) { + pos++; + if (pos >= tokens.size()) return; + ArgToken value = tokens.get(pos++); + if (value.getType() == NUMBER) + kwargs.put(name, Double.valueOf(value.getLexeme())); + else if (value.getType() == BOOL) + kwargs.put(name, value.getLexeme().equalsIgnoreCase("true")); + else if (value.getType() == STRING) + kwargs.put(name, value.getLexeme().substring(1, value.getLexeme().length() - 1)); + else if (value.getType() == ARGUMENT) { + kwargs.put(name, value.getLexeme()); + } + } else return; + } else { + if (token.getType() == NUMBER) + arguments.add(Double.valueOf(token.getLexeme())); + else if (token.getType() == BOOL) + arguments.add(token.getLexeme().equalsIgnoreCase("true")); + else if (token.getType() == STRING) + arguments.add(token.getLexeme().substring(1, token.getLexeme().length() - 1)); + else if (token.getType() == ARGUMENT) { + arguments.add(token.getLexeme()); + } + } + } + } + + public HashMap getKwargs() { + return kwargs; + } + + public HashMap getBoolFlags() { + return boolFlags; + } + + public List getArguments() { + return arguments; + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgToken.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgToken.java new file mode 100644 index 0000000..56d7414 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgToken.java @@ -0,0 +1,21 @@ +package me.tapeline.quailj.runtime.std.cli.argparser; + +public class ArgToken { + + private String lexeme; + private ArgTokenType type; + + public ArgToken( ArgTokenType type, String lexeme) { + this.lexeme = lexeme; + this.type = type; + } + + public String getLexeme() { + return lexeme; + } + + public ArgTokenType getType() { + return type; + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgTokenType.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgTokenType.java new file mode 100644 index 0000000..0f26b8d --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/argparser/ArgTokenType.java @@ -0,0 +1,13 @@ +package me.tapeline.quailj.runtime.std.cli.argparser; + +public enum ArgTokenType { + + KEYWORD_FLAG, + BOOL_FLAG, + ARGUMENT, + NUMBER, + BOOL, + STRING, + EQUALS + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/decorators/CliCommand.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/decorators/CliCommand.java new file mode 100644 index 0000000..628c393 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/decorators/CliCommand.java @@ -0,0 +1,46 @@ +package me.tapeline.quailj.runtime.std.cli.decorators; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class CliCommand extends QBuiltinFunc { + + public CliCommand(Runtime runtime) { + super( + "command", + Arrays.asList( + new FuncArgument( + "f", + QObject.Val(), + new int[0], + LiteralFunction.Argument.POSITIONAL + ), + new FuncArgument( + "commandName", + QObject.Val(), + new int[] {ModifierConstants.STR}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + boundRuntime.getMemory().get("commands").indexSet(boundRuntime, args.get("commandName"), args.get("f")); + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/decorators/CliTick.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/decorators/CliTick.java new file mode 100644 index 0000000..27fb52b --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/cli/decorators/CliTick.java @@ -0,0 +1,47 @@ +package me.tapeline.quailj.runtime.std.cli.decorators; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; + +public class CliTick extends QBuiltinFunc { + + public CliTick(Runtime runtime) { + super( + "tick", + Arrays.asList( + new FuncArgument( + "f", + QObject.Val(), + new int[0], + LiteralFunction.Argument.POSITIONAL + ), + new FuncArgument( + "this", + QObject.Val(), + new int[0], + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + Objects.requireNonNull(boundRuntime.getMemory().get("ticking").listValue()).add(args.get("f")); + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/math/MathFuncGcd.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/math/MathFuncGcd.java new file mode 100644 index 0000000..e6db236 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/math/MathFuncGcd.java @@ -0,0 +1,46 @@ +package me.tapeline.quailj.runtime.std.math; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; +import org.apache.commons.math3.util.ArithmeticUtils; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class MathFuncGcd extends QBuiltinFunc { + + public MathFuncGcd(Runtime runtime) { + super( + "gcd", + Arrays.asList( + new FuncArgument( + "a", + QObject.Val(), + new int[] {ModifierConstants.NUM}, + LiteralFunction.Argument.POSITIONAL + ), + new FuncArgument( + "b", + QObject.Val(), + new int[] {ModifierConstants.NUM}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + return Val(ArithmeticUtils.gcd((long) args.get("a").numValue(), (long) args.get("b").numValue())); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/math/MathFuncLcm.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/math/MathFuncLcm.java new file mode 100644 index 0000000..817a199 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/math/MathFuncLcm.java @@ -0,0 +1,46 @@ +package me.tapeline.quailj.runtime.std.math; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; +import org.apache.commons.math3.util.ArithmeticUtils; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class MathFuncLcm extends QBuiltinFunc { + + public MathFuncLcm(Runtime runtime) { + super( + "lcm", + Arrays.asList( + new FuncArgument( + "a", + QObject.Val(), + new int[] {ModifierConstants.NUM}, + LiteralFunction.Argument.POSITIONAL + ), + new FuncArgument( + "b", + QObject.Val(), + new int[] {ModifierConstants.NUM}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + return Val(ArithmeticUtils.lcm((long) args.get("a").numValue(), (long) args.get("b").numValue())); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/math/MathLibrary.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/math/MathLibrary.java index 14e0948..796f50b 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/math/MathLibrary.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/math/MathLibrary.java @@ -26,6 +26,8 @@ public Runtime initializeRuntime() { public QObject constructLibrary(Runtime runtime) { HashMap contents = new HashMap<>(); contents.put("product", new MathFuncProduct(runtime)); + contents.put("gcd", new MathFuncGcd(runtime)); + contents.put("lcm", new MathFuncLcm(runtime)); runtime.getMemory().table.putAll(contents); diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectCallFunction.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectCallFunction.java new file mode 100644 index 0000000..ec06ab5 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectCallFunction.java @@ -0,0 +1,47 @@ +package me.tapeline.quailj.runtime.std.reflect; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.runtime.RuntimeStriker; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.classes.QString; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.utils.FuncArgument; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class ReflectCallFunction extends QBuiltinFunc { + + public ReflectCallFunction(Runtime runtime) { + super( + "callFunction", + Arrays.asList( + new FuncArgument( + "f", + QObject.Val(), + new int[] {ModifierConstants.FUNC}, + LiteralFunction.Argument.POSITIONAL + ), + new FuncArgument( + "args", + QObject.Val(), + new int[] {ModifierConstants.LIST}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + args.get("f").call(runtime, args.get("args").listValue(), new HashMap<>()); + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectLibrary.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectLibrary.java new file mode 100644 index 0000000..8d7bcf7 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectLibrary.java @@ -0,0 +1,39 @@ +package me.tapeline.quailj.runtime.std.reflect; + +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.runtime.librarymanagement.BuiltinLibrary; +import me.tapeline.quailj.runtime.std.storage.StorageLoadJson; +import me.tapeline.quailj.runtime.std.storage.StorageLoadYaml; +import me.tapeline.quailj.runtime.std.storage.StorageSaveJson; +import me.tapeline.quailj.runtime.std.storage.StorageSaveYaml; +import me.tapeline.quailj.typing.classes.QObject; + +import java.util.HashMap; + +public class ReflectLibrary implements BuiltinLibrary { + + @Override + public String id() { + return "lang/reflect"; + } + + @Override + public Runtime initializeRuntime() { + return new Runtime(); + } + + @Override + public QObject constructLibrary(Runtime runtime) { + HashMap contents = new HashMap<>(); + contents.put("setBoolValue", new ReflectSetBoolValue(runtime)); + contents.put("setFuncValue", new ReflectSetFuncValue(runtime)); + contents.put("setNumberValue", new ReflectSetNumberValue(runtime)); + contents.put("setStringValue", new ReflectSetStringValue(runtime)); + contents.put("callFunction", new ReflectCallFunction(runtime)); + + runtime.getMemory().table.putAll(contents); + + return QObject.Val(contents); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetBoolValue.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetBoolValue.java new file mode 100644 index 0000000..20f64b0 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetBoolValue.java @@ -0,0 +1,47 @@ +package me.tapeline.quailj.runtime.std.reflect; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.classes.QBool; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class ReflectSetBoolValue extends QBuiltinFunc { + + public ReflectSetBoolValue(Runtime runtime) { + super( + "setBoolValue", + Arrays.asList( + new FuncArgument( + "obj", + QObject.Val(), + new int[] {ModifierConstants.BOOL}, + LiteralFunction.Argument.POSITIONAL + ), + new FuncArgument( + "value", + QObject.Val(), + new int[] {ModifierConstants.BOOL}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + ((QBool) args.get("obj")).setValue(args.get("value").boolValue()); + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetFuncValue.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetFuncValue.java new file mode 100644 index 0000000..6e0e2d8 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetFuncValue.java @@ -0,0 +1,51 @@ +package me.tapeline.quailj.runtime.std.reflect; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.classes.QBool; +import me.tapeline.quailj.typing.classes.QFunc; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class ReflectSetFuncValue extends QBuiltinFunc { + + public ReflectSetFuncValue(Runtime runtime) { + super( + "setFuncValue", + Arrays.asList( + new FuncArgument( + "obj", + QObject.Val(), + new int[] {ModifierConstants.FUNC}, + LiteralFunction.Argument.POSITIONAL + ), + new FuncArgument( + "value", + QObject.Val(), + new int[] {ModifierConstants.FUNC}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + ((QFunc) args.get("obj")).setAlternatives(((QFunc) args.get("value")).getAlternatives()); + ((QFunc) args.get("obj")).setCode(((QFunc) args.get("value")).getCode()); + ((QFunc) args.get("obj")).setBoundRuntime(((QFunc) args.get("value")).getBoundRuntime()); + ((QFunc) args.get("obj")).setArguments(((QFunc) args.get("value")).getArguments()); + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetNumberValue.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetNumberValue.java new file mode 100644 index 0000000..9b0fcb3 --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetNumberValue.java @@ -0,0 +1,48 @@ +package me.tapeline.quailj.runtime.std.reflect; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.classes.QBool; +import me.tapeline.quailj.typing.classes.QNumber; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class ReflectSetNumberValue extends QBuiltinFunc { + + public ReflectSetNumberValue(Runtime runtime) { + super( + "setNumberValue", + Arrays.asList( + new FuncArgument( + "obj", + QObject.Val(), + new int[] {ModifierConstants.NUM}, + LiteralFunction.Argument.POSITIONAL + ), + new FuncArgument( + "value", + QObject.Val(), + new int[] {ModifierConstants.NUM}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + ((QNumber) args.get("obj")).setValue(args.get("value").numValue()); + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetStringValue.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetStringValue.java new file mode 100644 index 0000000..4bc981f --- /dev/null +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/runtime/std/reflect/ReflectSetStringValue.java @@ -0,0 +1,48 @@ +package me.tapeline.quailj.runtime.std.reflect; + +import me.tapeline.quailj.parsing.nodes.literals.LiteralFunction; +import me.tapeline.quailj.runtime.Runtime; +import me.tapeline.quailj.typing.classes.QBool; +import me.tapeline.quailj.typing.classes.QString; +import me.tapeline.quailj.typing.modifiers.ModifierConstants; +import me.tapeline.quailj.typing.classes.QObject; +import me.tapeline.quailj.typing.utils.FuncArgument; +import me.tapeline.quailj.typing.classes.utils.QBuiltinFunc; +import me.tapeline.quailj.runtime.RuntimeStriker; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class ReflectSetStringValue extends QBuiltinFunc { + + public ReflectSetStringValue(Runtime runtime) { + super( + "setStringValue", + Arrays.asList( + new FuncArgument( + "obj", + QObject.Val(), + new int[] {ModifierConstants.STR}, + LiteralFunction.Argument.POSITIONAL + ), + new FuncArgument( + "value", + QObject.Val(), + new int[] {ModifierConstants.STR}, + LiteralFunction.Argument.POSITIONAL + ) + ), + runtime, + runtime.getMemory(), + false + ); + } + + @Override + public QObject action(Runtime runtime, HashMap args, List argList) throws RuntimeStriker { + ((QString) args.get("obj")).setValue(args.get("value").strValue()); + return Val(); + } + +} diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QDict.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QDict.java index 7550266..6e64dda 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QDict.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QDict.java @@ -92,6 +92,18 @@ public QObject defaultIndexSet(Runtime runtime, QObject index, QObject value) { return value; } + @Override + public QObject defaultContainsObject(Runtime runtime, QObject other) throws RuntimeStriker { + if (other.isStr()) return Val(values.containsKey(other.strValue())); + return super.defaultContainsObject(runtime, other); + } + + @Override + public QObject defaultNotContainsObject(Runtime runtime, QObject other) throws RuntimeStriker { + if (other.isStr()) return Val(!values.containsKey(other.strValue())); + return super.defaultNotContainsObject(runtime, other); + } + @Override public QObject defaultIterateStart(Runtime runtime) { iterator = 0; diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QList.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QList.java index a48d640..d6ae194 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QList.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QList.java @@ -143,6 +143,20 @@ public QObject defaultLessEqual(Runtime runtime, QObject other) throws RuntimeSt return super.lessEqual(runtime, other); } + @Override + public QObject defaultContainsObject(Runtime runtime, QObject other) throws RuntimeStriker { + for (QObject value : values) + if (value.equalsObject(runtime, other).boolValue()) return Val(true); + return Val(false); + } + + @Override + public QObject defaultNotContainsObject(Runtime runtime, QObject other) throws RuntimeStriker { + for (QObject value : values) + if (value.equalsObject(runtime, other).boolValue()) return Val(false); + return Val(true); + } + @Override public QObject defaultIndex(Runtime runtime, QObject index) throws RuntimeStriker { if (index.isNum()) { diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QObject.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QObject.java index 3549e6a..1e17f28 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QObject.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QObject.java @@ -149,6 +149,22 @@ else if (parent != null) return new QNull(); } + public boolean containsKey(String name) { + if (name.startsWith("_")) { + if (name.equals("_className") || + name.equals("_superClass") || + name.equals("_objectPrototype") || + name.equals("_isPrototype") || + name.equals("_isInheritable")) return true; + } + if (table.containsKey(name)) + return true; + else if (parent != null) + return parent.containsKey(name); + else + return false; + } + public void set(Runtime runtime, String name, QObject value) throws RuntimeStriker { table.put(runtime, name, value); } @@ -177,8 +193,10 @@ else if (table.containsKey("_set_" + name)) public QObject callFromThis(Runtime runtime, QObject func, List args, HashMap kwargs) throws RuntimeStriker { - if (!isPrototype()) + if (!isPrototype()) { + args = new ArrayList<>(args); args.add(0, this); + } return func.call(runtime, args, kwargs); } @@ -352,6 +370,18 @@ public QObject defaultNotEqualsObject(Runtime runtime, QObject other) return Val(this != other); } + public QObject defaultContainsObject(Runtime runtime, QObject other) + throws RuntimeStriker { + runtime.error(new QUnsupportedOperationException(this, "in", other)); + return Val(); + } + + public QObject defaultNotContainsObject(Runtime runtime, QObject other) + throws RuntimeStriker { + runtime.error(new QUnsupportedOperationException(this, "not in", other)); + return Val(); + } + public QObject defaultGreater(Runtime runtime, QObject other) throws RuntimeStriker { runtime.error(new QUnsupportedOperationException(this, ">", other)); @@ -471,8 +501,9 @@ public QObject call(Runtime runtime, List args, HashMap() + ); + return defaultContainsObject(runtime, other); + } + + public QObject notContainsObject(Runtime runtime, QObject other) throws RuntimeStriker { + if (table.containsKey("_notcontains")) + return callFromThis( + runtime, + "_notcontains", + Collections.singletonList(other), + new HashMap<>() + ); + return defaultNotContainsObject(runtime, other); + } + public QObject greater(Runtime runtime, QObject other) throws RuntimeStriker { if (table.containsKey("_cmpg")) return callFromThis( diff --git a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QString.java b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QString.java index f0464f5..46d8c1d 100644 --- a/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QString.java +++ b/QuailRuntimeEnvironment/src/main/java/me/tapeline/quailj/typing/classes/QString.java @@ -8,6 +8,7 @@ import me.tapeline.quailj.utils.QStringUtils; import org.apache.commons.lang3.StringUtils; +import java.util.Objects; import java.util.regex.Pattern; public class QString extends QObject { @@ -126,6 +127,18 @@ public QObject defaultNotEqualsObject(Runtime runtime, QObject other) throws Run return super.equalsObject(runtime, other); } + @Override + public QObject defaultContainsObject(Runtime runtime, QObject other) throws RuntimeStriker { + if (other.isStr()) return Val(value.contains(Objects.requireNonNull(other.strValue()))); + return super.defaultContainsObject(runtime, other); + } + + @Override + public QObject defaultNotContainsObject(Runtime runtime, QObject other) throws RuntimeStriker { + if (other.isStr()) return Val(!value.contains(Objects.requireNonNull(other.strValue()))); + return super.defaultNotContainsObject(runtime, other); + } + @Override public QObject defaultGreater(Runtime runtime, QObject other) throws RuntimeStriker { if (other.isStr()) diff --git a/docs-md/core/core.q b/docs-md/core/core.q index 4612753..b2e4435 100644 --- a/docs-md/core/core.q +++ b/docs-md/core/core.q @@ -6,6 +6,7 @@ #?toc-entry Dict #?toc-entry Func #?toc-entry Null +#?toc-entry Thread #?toc-html


Standard exceptions

#?toc-entry Exception #?toc-entry AssertionException @@ -22,6 +23,13 @@ #?toc-entry UnsupportedStepSubscriptException #?toc-entry UnsupportedSubscriptException #?toc-entry UnsupportedUnaryOperationException +#?toc-entry IndexOutOfBoundsException +#?toc-entry ClarificationException +#?toc-entry ArgumentClarificationException +#?toc-entry FinalAssignedException +#?toc-entry InternalException +#?toc-entry UnpackingException +#?toc-entry UnknownLibraryException #?toc-html


Standard functions

#?toc-entry all #?toc-entry any @@ -31,6 +39,7 @@ #?toc-entry map #?toc-entry hash #?toc-entry millis +#?toc-entry zip #?toc-entry input #?toc-entry print #?toc-entry put @@ -41,6 +50,7 @@ #?toc-entry atan2 #?toc-entry cos #?toc-entry cosh +#?toc-entry sum #?toc-entry max #?toc-entry min #?toc-entry sin @@ -51,6 +61,8 @@ #?toc-entry dec #?toc-entry hex #?toc-entry oct +#?toc-entry writeFile +#?toc-entry readFile #?html

Overview

#?html
@@ -312,6 +324,10 @@ class List like Object { class Dict like Object { #? A string key -> object value data structure + void clear(this) { + #? Clears this dict + } + list keys(this) { #? List all keys in this dict } @@ -346,14 +362,46 @@ class Dict like Object { } -class Func { +class Func like Object { #? Resembles functions and methods } -class Null { +class Null like Object { #? Resembles the null value } +class Thread like Object { + #? An asynchronous thread + + constructor (this, func f, list args) { + #? Create a thread with specific function and save arguments + } + + void start(this) { + #? Starts execution of the function with defined arguments + #? Thread ends when function ends + } + + void stop(this) { + #? Stops the thread + } + + void|object getResult(this) { + #? Returns the value that function returned + #? If function is not over yet, returns null + } + + object waitForResult(this) { + #? Hangs while thread is alive and returns + #? the value that function will return + } + + bool isAlive(this) { + #? Check whether the thread is alive or not + } + +} + #?html
#?html

Standard exceptions

@@ -441,6 +489,53 @@ class UnsupportedUnaryOperationException like Exception { object operand } +class IndexOutOfBoundsException like Exception { + #? Thrown when indexing is out of bounds + + num index + num size +} + +class ClarificationException like Exception { + #? Thrown when clarified variable is assigned to unsupported value + + string clarifiers + object value +} + +class ArgumentClarificationException like Exception { + #? Thrown when clarified argument is assigned to unsupported value + + string clarifiers + object value + string name +} + +class FinalAssignedException like Exception { + #? Thrown when finalized variable is reassigned + + object value +} + +class InternalException like Exception { + #? Thrown when something in Quail goes wrong + #? Usually indicates bugs in QRE + #? Report occasions to the developer +} + +class UnpackingException like Exception { + #? Thrown when for loop tries to unpack a value to wrong + #? number of variables. E.g. for a, b, c in some_dict + #? (dict can unpack only to key, value - 2 variables) + + num present + num expected +} + +class UnknownLibraryException like Exception { + #? Thrown when unknown library is being imported +} + #?html
#?html

Standard functions

@@ -482,6 +577,11 @@ num millis() { #? Get current time in milliseconds } +list zip(list a, list b) { + #? Zips two lists into one list of pairs. E.g.: + #? zip([1, 2], ["a", "b"]) -> [[1, "a"], [2, "b"]] +} + string input(string prompt = "") { #? Put given prompt to console, wait for user input and return it } @@ -565,3 +665,11 @@ string hex(num n) { string oct() { #? Convert given number to base-8 (integer only) } + +void writeFile(string path, string contents) { + #? Writes file as plain text +} + +string readFile(string path) { + #? Reads file as plain text +} diff --git a/docs-md/core/index.html b/docs-md/core/index.html index d5ce2d9..cca0a17 100644 --- a/docs-md/core/index.html +++ b/docs-md/core/index.html @@ -1,5 +1,5 @@ - + Docs +