/****************************************************************************** * * Copyright 2014 Paphus Solutions Inc. * * Licensed under the Eclipse Public License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ package org.botlibre.self; import java.io.IOException; import java.io.StringWriter; import java.lang.reflect.Method; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import org.botlibre.aiml.AIMLParser; import org.botlibre.api.knowledge.Network; import org.botlibre.api.knowledge.Relationship; import org.botlibre.api.knowledge.Vertex; import org.botlibre.knowledge.BinaryData; import org.botlibre.knowledge.Primitive; import org.botlibre.sense.service.RemoteService; import org.botlibre.thought.language.Language; import org.botlibre.util.Utils; /** * Self language runtime interpreter. * This class evaluates a compiled Self expression or function. */ public class SelfInterpreter { public static long TIMEOUT = 10000; public static int MAX_STACK = 500; protected static SelfInterpreter interpreter; public static SelfInterpreter getInterpreter() { if (interpreter == null) { interpreter = new SelfInterpreter(); } return interpreter; } public static void setInterpreter(SelfInterpreter interpreter) { SelfInterpreter.interpreter = interpreter; } /** * Evaluate the function and return the result. */ public Vertex evaluateFunction(Vertex function, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { try { // Check for byte-code. if (function.getData() instanceof BinaryData) { function = SelfDecompiler.getDecompiler().parseFunctionByteCode(function, (BinaryData)function.getData(), function.getNetwork()); return evaluateFunction(function, variables, network, startTime, maxTime, stack); } } catch (IOException exception) { network.getBot().log(this, exception); throw new SelfExecutionException(function, exception); } // function { x; y; z; } // Apply each expression in the function. Vertex result = null; Vertex returnPrimitive = network.createVertex(Primitive.RETURN); List<Relationship> operations = function.orderedRelationships(Primitive.DO); if (operations != null) { for (Relationship expression : operations) { result = evaluateExpression(expression.getTarget(), variables, network, startTime, maxTime, stack); if (variables.containsKey(returnPrimitive)) { variables.remove(returnPrimitive); return result; } } } if (result == null) { result = function; } return result; } /** * Evaluate the expression and return the result. */ @SuppressWarnings("unchecked") public Vertex evaluateExpression(Vertex expression, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (stack > MAX_STACK) { throw new SelfExecutionException(expression, "Stack overflow: " + stack); } stack++; if ((System.currentTimeMillis() - startTime) > maxTime) { throw new SelfExecutionException(expression, "Max time exceeded: " + maxTime); } Vertex result = null; boolean isDebug = network.getBot().isDebugFiner(); if (expression.isVariable()) { result = variables.get(expression); if (result == null) { if (expression.hasName()) { result = variables.get(expression.getName()); } if (result == null) { result = network.createVertex(Primitive.NULL); } } } else if (expression.instanceOf(Primitive.EXPRESSION)) { try { // Check for byte-code. if (expression.getData() instanceof BinaryData) { Vertex equation = SelfDecompiler.getDecompiler().parseExpressionByteCode(expression, (BinaryData)expression.getData(), expression.getNetwork()); if (!(equation.getData() instanceof BinaryData)) { return evaluateExpression(equation, variables, network, startTime, maxTime, stack); } } Vertex operator = expression.getRelationship(Primitive.OPERATOR); if (operator == null) { return network.createVertex(Primitive.NULL); } List<Relationship> arguments = expression.orderedRelationships(Primitive.ARGUMENT); if (arguments == null) { arguments = Collections.EMPTY_LIST; } if (isDebug) { Vertex source = expression.getRelationship(Primitive.SOURCE); String sourceCode = ""; if (source != null) { sourceCode = String.valueOf(source.getData()).trim(); } else if (operator.isPrimitive()) { if (operator.is(Primitive.CALL)) { sourceCode = ((Primitive)operator.getData()).getIdentity().toUpperCase() + "(" + String.valueOf(expression.getRelationship(Primitive.FUNCTION)) + expression.orderedRelations(Primitive.ARGUMENT) + ")"; } else { sourceCode = ((Primitive)operator.getData()).getIdentity().toUpperCase() + "(" + expression.orderedRelations(Primitive.ARGUMENT) + ")"; } } Vertex number = expression.getRelationship(Primitive.LINE_NUMBER); if (number != null) { sourceCode = String.valueOf(number.getData()) + ":" + sourceCode; } network.getBot().log(this, sourceCode, Level.FINER); } // NOT :0 // Check if negated. if (operator.is(Primitive.NOT)) { result = evaluateNOT(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.FOR)) { result = evaluateFOR(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.WHILE)) { result = evaluateWHILE(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.ASSIGN)) { // x = y // Assign a variable a new value. Vertex variable = arguments.get(0).getTarget(); Vertex value = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if (value != null) { variables.put(variable, value); } if (isDebug) { network.getBot().log(this, "" + variable + " = " + value, Level.FINER); } result = value; } else if (operator.is(Primitive.INCREMENT)) { // x++ // Increment the value. Vertex variable = arguments.get(0).getTarget(); Vertex value = evaluateExpression(variable, variables, network, startTime, maxTime, stack); if (value != null && value.getData() instanceof Number) { value = network.createVertex(((Number)value.getData()).intValue() + 1); variables.put(variable, value); } if (isDebug) { network.getBot().log(this, "" + variable + " = " + value, Level.FINER); } result = value; } else if (operator.is(Primitive.DECREMENT)) { // x-- // Decrement the value. Vertex variable = arguments.get(0).getTarget(); Vertex value = evaluateExpression(variable, variables, network, startTime, maxTime, stack); if (value != null && value.getData() instanceof Number) { value = network.createVertex(((Number)value.getData()).intValue() - 1); variables.put(variable, value); } if (isDebug) { network.getBot().log(this, "" + variable + " = " + value, Level.FINER); } result = value; } else if (operator.is(Primitive.IF)) { result = evaluateIF(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.EQUALS)) { result = evaluateEQUALS(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.NOTEQUALS)) { result = evaluateNOTEQUALS(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.OR)) { result = evaluateOR(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.AND)) { result = evaluateAND(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.DO)) { result = evaluateDO(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.THINK)) { result = evaluateTHINK(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.GET)) { result = evaluateGET(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.SET)) { result = evaluateSET(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.ADD)) { result = evaluateADD(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.REMOVE)) { result = evaluateREMOVE(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.NEW)) { result = evaluateNEW(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.CALL)) { result = evaluateCALL(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.RETURN)) { // RETURN :0 if (arguments == null || arguments.isEmpty()) { result = network.createVertex(Primitive.NULL); } else { result = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); } variables.put(network.createVertex(Primitive.RETURN), result); } else if (operator.is(Primitive.BREAK)) { return operator; } else if (operator.is(Primitive.CONTINUE)) { return operator; } else if (operator.is(Primitive.RANDOM)) { result = evaluateRANDOM(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.DEBUG)) { result = evaluateDEBUG(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.GREATERTHAN)) { result = evaluateGREATERTHAN(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.GREATERTHANEQUAL)) { result = evaluateGREATERTHANEQUAL(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.LESSTHAN)) { result = evaluateLESSTHAN(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.LESSTHANEQUAL)) { result = evaluateLESSTHANEQUAL(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.PLUS)) { result = evaluatePLUS(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.MINUS)) { result = evaluateMINUS(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.MULTIPLY)) { result = evaluateMULTIPLY(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.DIVIDE)) { result = evaluateDIVIDE(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.SYMBOL)) { result = evaluateSYMBOL(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.EVALCOPY)) { result = evaluateEVALCOPY(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.LEARN)) { result = evaluateLEARN(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.SRAI) || operator.is(Primitive.REDIRECT)) { result = evaluateSRAI(expression, arguments, variables, network, startTime, maxTime, stack); } else if (operator.is(Primitive.SRAIX) || operator.is(Primitive.REQUEST)) { result = evaluateSRAIX(expression, arguments, variables, network, startTime, maxTime, stack); } } catch (SelfExecutionException exception) { throw exception; } catch (Exception exception) { network.getBot().log(this, exception); throw new SelfExecutionException(expression, exception); } } else if (expression.instanceOf(Primitive.FUNCTION)) { result = evaluateFunction(expression, variables, network, startTime, maxTime, stack); } else if (expression.instanceOf(Primitive.EQUATION)) { result = expression.applyQuotient(variables, network); } else { result = expression; } if (result == null) { result = network.createVertex(Primitive.NULL); } if (result.getNetwork() != network) { result = network.createVertex(result); } // Check for formula and transpose if (result.instanceOf(Primitive.FORMULA)) { Language language = network.getBot().mind().getThought(Language.class); Vertex newResult = language.evaluateFormula(result, variables, network); if (newResult == null) { language.log("Formula cannot be evaluated", Level.FINE, result); result = network.createVertex(Primitive.NULL); } else { result = language.getWord(newResult, network); } } if (isDebug && !result.equals(expression)) { network.getBot().log(this, "result: ", Level.FINER, result, expression); } return result; } public boolean checkArguments(Vertex expression, List<Relationship> arguments, int expected, Network network) { if (arguments.size() != expected) { network.getBot().log(this, "Invalid number of arguments (operation, arguments, expected)", Level.WARNING, expression, arguments.size(), expected); return false; } return true; } public boolean checkMinArguments(Vertex expression, List<Relationship> arguments, int expected, Network network) { if (arguments.size() < expected) { network.getBot().log(this, "Invalid number of arguments (operation, arguments, expected)", Level.WARNING, expression, arguments.size(), expected); return false; } return true; } /** * Evaluate the IF operation. * if (x == y || z != q) { x; y; } else { z; q; } */ public Vertex evaluateIF(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 1, network)) { return network.createVertex(Primitive.NULL); } Vertex value = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex result = network.createVertex(Primitive.NULL); if (value.is(Primitive.TRUE)) { List<Vertex> thens = expression.orderedRelations(Primitive.THEN); if (thens != null) { Vertex returnPrimitive = network.createVertex(Primitive.RETURN); for (Vertex then :thens) { result = evaluateExpression(then, variables, network, startTime, maxTime, stack); if (variables.containsKey(returnPrimitive)) { return result; } } } } else { List<Vertex> elseifs = expression.orderedRelations(Primitive.ELSEIF); boolean match = false; if (elseifs != null) { for (Vertex elseif : elseifs) { Vertex returnPrimitive = network.createVertex(Primitive.RETURN); result = evaluateExpression(elseif, variables, network, startTime, maxTime, stack); if (variables.containsKey(returnPrimitive)) { return result; } if (!result.is(Primitive.NULL)) { match = true; break; } } } if (!match) { List<Vertex> elses = expression.orderedRelations(Primitive.ELSE); if (elses != null) { Vertex returnPrimitive = network.createVertex(Primitive.RETURN); for (Vertex elseExpressions :elses) { result = evaluateExpression(elseExpressions, variables, network, startTime, maxTime, stack); if (variables.containsKey(returnPrimitive)) { return result; } } } } } return result; } /** * Evaluate the WHILE operation. * while (x < 100) { x = x + 1; } */ public Vertex evaluateWHILE(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 1, network)) { return network.createVertex(Primitive.NULL); } // Process a while loop, repeat the operation until true or max depth int depth = 0; boolean condition = true; List<Relationship> doEquations = expression.orderedRelationships(Primitive.DO); Vertex result = network.createVertex(Primitive.NULL); while (condition && depth < Language.MAX_STACK) { Vertex first = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); if (arguments.size() == 1) { condition = first.is(Primitive.TRUE); } if (condition) { for (Relationship doEquation: doEquations) { result = evaluateExpression(doEquation.getTarget(), variables, network, startTime, maxTime, stack); if (variables.containsKey(network.createVertex(Primitive.RETURN))) { return result; } else if (result.is(Primitive.BREAK)) { return result; } else if (result.is(Primitive.CONTINUE)) { break; } } } depth++; } if (depth >= Language.MAX_STACK) { network.getBot().log(this, "Max stack exceeded on while loop", Level.WARNING, Language.MAX_STACK); } return result; } /** * Evaluate the FOR operation. * for (word in sentence.word) { x; y; z; } */ public Vertex evaluateFOR(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { // Process a for loop, repeat the operation for each element in the sequence. List<List<Relationship>> sequences = new ArrayList<List<Relationship>>(); List<Vertex> forVariables = new ArrayList<Vertex>(); // Process the pairs of variable, source.relationship. int maxSequenceSize = 0; for (int index = 0; index < arguments.size(); index = index + 2) { Vertex variable = arguments.get(index).getTarget(); Vertex getExpression = arguments.get(index + 1).getTarget(); List<Vertex> values = getExpression.orderedRelations(Primitive.ARGUMENT); if (values == null) { continue; } Vertex source = evaluateExpression(values.get(0), variables, network, startTime, maxTime, stack); Vertex relationship = evaluateExpression(values.get(1), variables, network, startTime, maxTime, stack); List<Relationship> sequence = source.orderedRelationships(relationship); if (sequence == null) { sequence = new ArrayList<Relationship>(0); } // Keep track of the biggest sequence to null pads others. if (sequence.size() > maxSequenceSize) { maxSequenceSize = sequence.size(); } sequences.add(sequence); forVariables.add(variable); } List<Relationship> doEquations = expression.orderedRelationships(Primitive.DO); Vertex result; for (int index = 0; index < maxSequenceSize; index++) { for (int variableIndex = 0; variableIndex < forVariables.size(); variableIndex++) { Vertex variable = forVariables.get(variableIndex); if (variable != null) { List<Relationship> sequence = sequences.get(variableIndex); Vertex value = null; if (index >= sequence.size()) { value = network.createVertex(Primitive.NULL); } else { value = sequence.get(index).getTarget(); } variables.put(variable, value); } } for (Relationship doEquation: doEquations) { result = evaluateExpression(doEquation.getTarget(), variables, network, startTime, maxTime, stack); if (variables.containsKey(network.createVertex(Primitive.RETURN))) { return result; } else if (result.is(Primitive.BREAK)) { return result; } else if (result.is(Primitive.CONTINUE)) { break; } } } return network.createVertex(Primitive.NULL); } /** * Evaluate the literal object into a copy. * evalcopy { name : speaker.name.toUpperCase(), salary : speaker.salary } */ public Vertex evaluateEVALCOPY(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 1, network)) { return network.createVertex(Primitive.NULL); } Relationship literal = arguments.get(0); if (literal.getTarget().hasData()) { // Return return literal.getTarget(); } // Copy. Vertex result = network.createVertex(); for (Iterator<Relationship> iterator = literal.getTarget().orderedAllRelationships(); iterator.hasNext(); ) { Relationship relationship = iterator.next(); Vertex value = evaluateExpression(relationship.getTarget(), variables, network, startTime, maxTime, stack); result.addRelationship(network.createVertex(relationship.getType()), value); } return result; } /** * Evaluate the DO operation. * do { x; y; z; } */ public Vertex evaluateDO(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { List<Relationship> doEquations = expression.orderedRelationships(Primitive.DO); Vertex result = network.createVertex(Primitive.NULL); if (doEquations == null) { return result; } Vertex returnPrimitive = network.createVertex(Primitive.RETURN); for (Relationship doEquation: doEquations) { result = evaluateExpression(doEquation.getTarget(), variables, network, startTime, maxTime, stack); if (variables.containsKey(returnPrimitive)) { variables.remove(returnPrimitive); return result; } else if (result.is(Primitive.BREAK)) { return result; } } return result; } /** * Evaluate the THINK operation. * think { x; y; z; } * THINK is the same as DO but returns #return to avoid printing the result in a template. */ public Vertex evaluateTHINK(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { List<Relationship> doEquations = expression.orderedRelationships(Primitive.DO); Vertex result = network.createVertex(Primitive.NULL); Vertex returnPrimitive = network.createVertex(Primitive.RETURN); for (Relationship doEquation: doEquations) { result = evaluateExpression(doEquation.getTarget(), variables, network, startTime, maxTime, stack); if (variables.containsKey(returnPrimitive)) { variables.remove(returnPrimitive); return result; } else if (result.is(Primitive.BREAK)) { return result; } } return returnPrimitive; } /** * Evaluate the LEARN operation. * learn ({pattern : "hello", template : "Hello world"}) * Evaluate and add the new response. */ public Vertex evaluateLEARN(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) throws Exception { if (! checkArguments(expression, arguments, 1, network)) { return network.createVertex(Primitive.NULL); } Vertex learning = arguments.get(0).getTarget(); // Cannot evaluate evalcopy as will evaluate templates. if (learning.instanceOf(Primitive.EXPRESSION)) { // Check for byte-code. if (learning.getData() instanceof BinaryData) { learning = SelfDecompiler.getDecompiler().parseExpressionByteCode(learning, (BinaryData)learning.getData(), learning.getNetwork()); } Vertex operator = learning.getRelationship(Primitive.OPERATOR); if (operator == null) { return network.createVertex(Primitive.NULL); } if (operator.is(Primitive.EVALCOPY)) { List<Relationship> learnArguments = learning.orderedRelationships(Primitive.ARGUMENT); if (learnArguments != null && !learnArguments.isEmpty()) { learning = learnArguments.get(0).getTarget(); } } else { learning = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); } } else { learning = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); } Vertex pattern = learning.getRelationship(Primitive.PATTERN); if (pattern == null) { return network.createVertex(Primitive.NULL); } pattern = evaluateEVAL(pattern, arguments, variables, network, startTime, maxTime, stack); Vertex template = learning.getRelationship(Primitive.TEMPLATE); if (template == null) { return network.createVertex(Primitive.NULL); } template = evaluateEVAL(template, arguments, variables, network, startTime, maxTime, stack); Relationship relationship = pattern.addRelationship(Primitive.RESPONSE, template); template.addRelationship(Primitive.QUESTION, pattern); Vertex that = learning.getRelationship(Primitive.THAT); if (that != null) { that = evaluateEVAL(that, arguments, variables, network, startTime, maxTime, stack); Vertex meta = network.createMeta(relationship); meta.addRelationship(Primitive.PREVIOUS, that); meta.addRelationship(Primitive.REQUIRE, Primitive.PREVIOUS); } Vertex topic = learning.getRelationship(Primitive.TOPIC); if (topic != null) { topic = evaluateEVAL(topic, arguments, variables, network, startTime, maxTime, stack); Vertex meta = network.createMeta(relationship); meta.addRelationship(Primitive.TOPIC, topic); meta.addRelationship(Primitive.REQUIRE, Primitive.TOPIC); } network.getBot().log(this, "New response learned", Level.FINER, pattern, template, that, topic); if (!pattern.instanceOf(Primitive.PATTERN)) { pattern.associateAll(Primitive.WORD, pattern, Primitive.QUESTION); } else { // Check for state and extend. Vertex state = variables.get(network.createVertex(Primitive.STATE)); if (state != null) { // Get first case that gets sentence from input. List<Vertex> instructions = state.orderedRelations(Primitive.DO); Vertex sentenceState = null; if (instructions != null) { for (Vertex instruction : instructions) { if (instruction.instanceOf(Primitive.CASE)) { Vertex variable = instruction.getRelationship(Primitive.CASE); if ((variable != null) && variable.isVariable() && variable.hasRelationship(Primitive.INPUT)) { sentenceState = instruction.getRelationship(Primitive.GOTO); break; } } } } if (sentenceState != null) { if (sentenceState.getNetwork() != network) { sentenceState = network.createVertex(sentenceState); } Vertex child = AIMLParser.parser().createState(pattern, sentenceState, network); Vertex equation = network.createInstance(Primitive.CASE); equation.addRelationship(Primitive.PATTERN, pattern); if (that != null) { equation.addRelationship(Primitive.THAT, that); } if (topic != null) { equation.addRelationship(Primitive.TOPIC, topic); } equation.addRelationship(Primitive.TEMPLATE, template); child.addRelationship(Primitive.DO, equation); } } } return pattern; } /** * Evaluate the SRAI operation. * srai ("Hello") * Return the response to processing the input. */ public Vertex evaluateSRAI(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) throws Exception { if (! checkArguments(expression, arguments, 1, network)) { return network.createVertex(Primitive.NULL); } Vertex sentence = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); if (!sentence.instanceOf(Primitive.SENTENCE) && sentence.instanceOf(Primitive.FRAGMENT)) { sentence.addRelationship(Primitive.INSTANTIATION, Primitive.SENTENCE); } Vertex input = variables.get(network.createVertex(Primitive.INPUT_VARIABLE)); input = input.copy(); input.setRelationship(Primitive.INPUT, sentence); Vertex response = network.getBot().mind().getThought(Language.class).input(input, sentence, variables, network); if (response == null) { return network.createVertex(Primitive.NULL); } return response; } /** * Evaluate the SRAIX operation. * sraix ("what is love", {bot : "Brain Bot", limit : 5, service : #botlibre, apikey : 12345, botid : 12345, hint : "google", default : "Brain Bot is offline"}) * Execute the remote service call, and return the response. */ public Vertex evaluateSRAIX(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) throws Exception { if (! checkMinArguments(expression, arguments, 1, network)) { return network.createVertex(Primitive.NULL); } Vertex sentence = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); String apikeyValue = null; int limitValue = -1; String botValue = null; String botidValue = null; String serverValue = null; Primitive serviceValue = null; String hintValue = null; String defaultValue = null; if (arguments.size() > 1) { Vertex argument = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); Vertex apikey = argument.getRelationship(Primitive.APIKEY); if (apikey != null) { apikey = evaluateExpression(apikey, variables, network, startTime, maxTime, stack); apikeyValue = apikey.printString(); } Vertex limit = argument.getRelationship(Primitive.LIMIT); if (limit != null) { limit = evaluateExpression(limit, variables, network, startTime, maxTime, stack); limitValue = Integer.parseInt(limit.getDataValue()); } Vertex bot = argument.getRelationship(Primitive.BOT); if (bot != null) { bot = evaluateExpression(bot, variables, network, startTime, maxTime, stack); botValue = bot.printString(); } Vertex botid = argument.getRelationship(Primitive.BOTID); if (botid != null) { botid = evaluateExpression(botid, variables, network, startTime, maxTime, stack); botidValue = botid.printString(); } Vertex server = argument.getRelationship(Primitive.SERVER); if (server != null) { server = evaluateExpression(server, variables, network, startTime, maxTime, stack); serverValue = server.printString(); } Vertex service = argument.getRelationship(Primitive.SERVICE); if (service != null) { service = evaluateExpression(service, variables, network, startTime, maxTime, stack); if (service.isPrimitive()) { serviceValue = (Primitive)service.getData(); } } Vertex hint = argument.getRelationship(Primitive.HINT); if (hint != null) { hint = evaluateExpression(hint, variables, network, startTime, maxTime, stack); hintValue = hint.printString(); } Vertex defaultResponse = argument.getRelationship(Primitive.DEFAULT); if (defaultResponse != null) { defaultResponse = evaluateExpression(defaultResponse, variables, network, startTime, maxTime, stack); defaultValue = defaultResponse.printString(); } } try { String message = sentence.printString(); String response = network.getBot().awareness().getSense(RemoteService.class).request(message, botValue, botidValue, serverValue, serviceValue, apikeyValue, limitValue, hintValue, network); if (response == null) { if (defaultValue != null && !defaultValue.isEmpty()) { return network.createSentence(defaultValue); } return network.createVertex(Primitive.NULL); } return network.createSentence(response); } catch (Exception exception) { network.getBot().log(this, exception); if (defaultValue != null && !defaultValue.isEmpty()) { return network.createSentence(defaultValue); } return network.createVertex(Primitive.NULL); } } /** * Evaluates any eval functions in the equation or formula.. * This is used by learn. */ public Vertex evaluateEVAL(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { Vertex result = null; try { if (expression.isVariable()) { result = variables.get(this); if (result == null) { if (expression.hasName()) { result = variables.get(expression.getName()); } if (result == null) { result = network.createVertex(Primitive.NULL); } } } else if (expression.instanceOf(Primitive.EXPRESSION)) { // Check for byte-code. if (expression.getData() instanceof BinaryData) { expression = SelfDecompiler.getDecompiler().parseExpressionByteCode(expression, (BinaryData)expression.getData(), network); return evaluateEVAL(expression, arguments, variables, network, startTime, maxTime, stack); } Vertex operator = expression.getRelationship(Primitive.OPERATOR); List<Relationship> evalArguments = expression.orderedRelationships(Primitive.ARGUMENT); if (operator.is(Primitive.EVAL)) { // eval (x) return evaluateExpression(evalArguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); } } else { result = (Vertex)(Object)expression; } if (result == null) { result = network.createVertex(Primitive.NULL); } if (result.getNetwork() != network) { result = network.createVertex(result); } boolean formula = result.instanceOf(Primitive.FORMULA); boolean pattern = result.instanceOf(Primitive.PATTERN); // Check for formula and transpose if (formula || pattern) { List<Vertex> words = result.orderedRelations(Primitive.WORD); if (words == null) { return result; } List<Vertex> newWords = new ArrayList<Vertex>(words.size()); boolean eval = false; boolean formulaRequired = false; for (Vertex word: words) { if (word.instanceOf(Primitive.EXPRESSION)) { // Check for byte-code. if (word.getData() instanceof BinaryData) { word = SelfDecompiler.getDecompiler().parseExpressionByteCode(word, (BinaryData)word.getData(), network); } Vertex operator = word.getRelationship(Primitive.OPERATOR); if (operator != null && operator.is(Primitive.EVAL)) { eval = true; Vertex newWord = evaluateEVAL(word, arguments, variables, network, startTime, maxTime, stack); if (newWord.instanceOf(Primitive.EXPRESSION) || newWord.instanceOf(Primitive.FORMULA)) { formulaRequired = true; } newWords.add(newWord); } else { formulaRequired = true; newWords.add(word); } } else if (word.instanceOf(Primitive.VARIABLE)) { formulaRequired = true; newWords.add(word); } else { newWords.add(word); } } if (eval) { if (pattern) { result = network.createTemporyVertex(); result.addRelationship(Primitive.INSTANTIATION, Primitive.PATTERN); } else if (formulaRequired) { result = network.createInstance(Primitive.FORMULA); } else { result = network.createTemporyVertex(); result.addRelationship(Primitive.INSTANTIATION, Primitive.SENTENCE); } int index = 0; for (Vertex word : newWords) { result.addRelationship(Primitive.WORD, word, index); index++; } if (!formulaRequired) { Language language = network.getBot().mind().getThought(Language.class); result = language.createSentenceText(result, network); if (pattern) { result = network.createSentence(Utils.reduce(result.printString())); } } } } } catch (SelfExecutionException exception) { throw exception; } catch (Exception exception) { throw new SelfExecutionException(expression, exception); } return result; } /** * Evaluate the GET operation. * x.y, x[#y], x.y[2], x[#y, #z, #q], x.get(#y), x.get(#y, 2), x.getLast(#y, 2), x.getAssociate(#y, #z, #q) * Get the single relationship value of the type. */ public Vertex evaluateGET(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkMinArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex result = null; Vertex source = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex relationship = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); Vertex index = expression.getRelationship(Primitive.INDEX); if ((index != null) && (index.getData() instanceof Number)) { int position = ((Number)index.getData()).intValue(); List<Vertex> values = source.orderedRelations(relationship); if (values == null) { return network.createVertex(Primitive.NULL); } if (position < 0) { if ((position * -1) > values.size()) { return network.createVertex(Primitive.NULL); } // Negative means from end result = values.get(values.size() + position); } else { if (position >= values.size()) { return network.createVertex(Primitive.NULL); } result = values.get(position); } } else { if (arguments.size() > 3) { Vertex associate = evaluateExpression(arguments.get(2).getTarget(), variables, network, startTime, maxTime, stack); Vertex associateRelationship = evaluateExpression(arguments.get(3).getTarget(), variables, network, startTime, maxTime, stack); result = source.mostConsciousWithAssoiate(relationship, associate, associateRelationship); } else if (relationship.getData() instanceof Number && source.instanceOf(Primitive.ARRAY)) { List<Vertex> values = source.orderedRelations(Primitive.ELEMENT); if (values == null) { return network.createVertex(Primitive.NULL); } int position = ((Number)relationship.getData()).intValue(); if (position < 0) { if ((position * -1) >= values.size()) { return network.createVertex(Primitive.NULL); } // Negative means from end result = values.get(values.size() + position); } else { if (position >= values.size()) { return network.createVertex(Primitive.NULL); } result = values.get(position); } } else if (relationship.getData() instanceof Number && (source.instanceOf(Primitive.FRAGMENT) || source.instanceOf(Primitive.SENTENCE))) { List<Vertex> values = source.orderedRelations(Primitive.WORD); if (values == null) { return network.createVertex(Primitive.NULL); } int position = ((Number)relationship.getData()).intValue(); if (position < 0) { if ((position * -1) >= values.size()) { return network.createVertex(Primitive.NULL); } // Negative means from end result = values.get(values.size() + position); } else { if (position >= values.size()) { return network.createVertex(Primitive.NULL); } result = values.get(position); } } else { result = source.mostConscious(relationship); } } if (result == null) { // Check all meanings of all words. Collection<Relationship> words = relationship.getRelationships(Primitive.WORD); if (words != null) { Set<Vertex> processed = new HashSet<Vertex>(); processed.add(relationship); for (Relationship word : words) { Collection<Relationship> otherMeanings = word.getTarget().getRelationships(Primitive.MEANING); if (otherMeanings != null) { for (Relationship meaning : otherMeanings) { if (!processed.contains(meaning.getTarget())) { processed.add(meaning.getTarget()); result = source.mostConscious(meaning.getTarget()); if (result != null) { break; } } } } } } if (result == null) { result = network.createVertex(Primitive.NULL); } } return result; } /** * Evaluate the SET operation. * x.y = q * SET the left with the right by the relationship, replace any existing relationship. */ public Vertex evaluateSET(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 3, network)) { return network.createVertex(Primitive.NULL); } Vertex source = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex relationship = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); Vertex target = evaluateExpression(arguments.get(2).getTarget(), variables, network, startTime, maxTime, stack); Vertex index = expression.getRelationship(Primitive.INDEX); if ((index != null) && (index.getData() instanceof Number)) { int position = ((Number)index.getData()).intValue(); List<Vertex> values = source.orderedRelations(relationship); if (position < 0) { // Negative means from end source.addRelationship(relationship, target, (values.size() + position)); } else { source.addRelationship(relationship, target, position); } } else { if (target.is(Primitive.NULL)) { source.internalRemoveRelationships(relationship); } else { source.setRelationship(relationship, target); } } // Following some crazy AIML implied rules here... if (relationship.isPrimitive() && (relationship.is(Primitive.IT) || relationship.is(Primitive.HE) || relationship.is(Primitive.SHE))) { return relationship; } return target; } /** * Evaluate the ADD operation. * x.y =+ q * ADD the relationship from the left to the right. */ public Vertex evaluateADD(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 3, network)) { return network.createVertex(Primitive.NULL); } Vertex source = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex relationship = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); Vertex target = evaluateExpression(arguments.get(2).getTarget(), variables, network, startTime, maxTime, stack); source.addRelationship(relationship, target); return source; } /** * Evaluate the REMOVE operation. * x.y =- q * REMOVE the relationship from the left to the right. * This will define an inverse relationship. */ public Vertex evaluateREMOVE(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 3, network)) { return network.createVertex(Primitive.NULL); } Vertex source = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex relationship = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); Vertex target = evaluateExpression(arguments.get(2).getTarget(), variables, network, startTime, maxTime, stack); source.removeRelationship(relationship, target); return source; } /** * Evaluate the EQUALS operation. * x == y * Return if the left is matches the right, or not. */ public Vertex evaluateEQUALS(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex left = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex right = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); Boolean matches = left.matches(right, variables); if (matches == null) { matches = false; } if (matches) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } /** * Evaluate the NOTEQUALS operation. * x != y * Return if the left is matches the right, or not. */ public Vertex evaluateNOTEQUALS(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex left = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex right = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); Boolean matches = left.matches(right, variables); if (matches == null) { matches = false; } if (!matches) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } /** * Evaluate the PLUS operation. * x + y * Add the two numbers. */ public Vertex evaluatePLUS(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex left = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex right = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if ((left.getData() instanceof Number) && (right.getData() instanceof Number)) { return new org.botlibre.tool.Math().instance.plus(expression, left, right); } return network.createVertex(left.printString() + right.printString()); } /** * Evaluate the MINUS operation. * x - y * Subtract the two numbers. */ public Vertex evaluateMINUS(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex left = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex right = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if ((left.getData() instanceof Number) && (right.getData() instanceof Number)) { return new org.botlibre.tool.Math().instance.minus(expression, left, right); } expression.getNetwork().getBot().log(this, "Invalid numbers for operation", Level.WARNING, expression, left, right); return network.createVertex(Primitive.NULL); } /** * Evaluate the MULTIPLY operation. * x * y * Multiply the two numbers. */ public Vertex evaluateMULTIPLY(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex left = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex right = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if ((left.getData() instanceof Number) && (right.getData() instanceof Number)) { return new org.botlibre.tool.Math().instance.multiply(expression, left, right); } expression.getNetwork().getBot().log(this, "Invalid numbers for operation", Level.WARNING, expression, left, right); return network.createVertex(Primitive.NULL); } /** * Evaluate the DIVIDE operation. * x / y * Divide the two numbers. */ public Vertex evaluateDIVIDE(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex left = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex right = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if ((left.getData() instanceof Number) && (right.getData() instanceof Number)) { return new org.botlibre.tool.Math().instance.divide(expression, left, right); } expression.getNetwork().getBot().log(this, "Invalid numbers for operation", Level.WARNING, expression, left, right); return network.createVertex(Primitive.NULL); } /** * Evaluate the LESSTHAN operation. * x < y * Return if the left is less than the right, or not. */ public Vertex evaluateLESSTHAN(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex left = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex right = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if ((left.getData() instanceof Number) && (right.getData() instanceof Number)) { if (((Number)left.getData()).doubleValue() < ((Number)right.getData()).doubleValue()) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } if ((left.getData() instanceof String) && (right.getData() instanceof String)) { if (((String)left.getData()).compareTo((String)right.getData()) < 0) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } if ((left.getData() instanceof java.util.Date) && (right.getData() instanceof java.util.Date)) { if (((java.util.Date)left.getData()).compareTo((java.util.Date)right.getData()) < 0) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } return network.createVertex(Primitive.UNKNOWN); } /** * Evaluate the LESSTHANEQUAL operation. * x <= y * Return if the left is less than or equal the right, or not. */ public Vertex evaluateLESSTHANEQUAL(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex left = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex right = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if ((left.getData() instanceof Number) && (right.getData() instanceof Number)) { if (((Number)left.getData()).doubleValue() <= ((Number)right.getData()).doubleValue()) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } if ((left.getData() instanceof String) && (right.getData() instanceof String)) { if (((String)left.getData()).compareTo((String)right.getData()) <= 0) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } if ((left.getData() instanceof java.util.Date) && (right.getData() instanceof java.util.Date)) { if (((java.util.Date)left.getData()).compareTo((java.util.Date)right.getData()) <= 0) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } if (left.matches(right, variables) == Boolean.TRUE) { return network.createVertex(Primitive.TRUE); } return network.createVertex(Primitive.UNKNOWN); } /** * Evaluate the GREATERTHANEQUAL operation. * x >= y * Return if the left is greater than or equal the right, or not. */ public Vertex evaluateGREATERTHANEQUAL(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex left = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex right = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if ((left.getData() instanceof Number) && (right.getData() instanceof Number)) { if (((Number)left.getData()).doubleValue() >= ((Number)right.getData()).doubleValue()) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } if ((left.getData() instanceof String) && (right.getData() instanceof String)) { if (((String)left.getData()).compareTo((String)right.getData()) >= 0) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } if ((left.getData() instanceof java.util.Date) && (right.getData() instanceof java.util.Date)) { if (((java.util.Date)left.getData()).compareTo((java.util.Date)right.getData()) >= 0) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } if (left.matches(right, variables) == Boolean.TRUE) { return network.createVertex(Primitive.TRUE); } return network.createVertex(Primitive.UNKNOWN); } /** * Evaluate the GREATERTHAN operation. * x > y * Return if the left is greater than the right, or not. */ public Vertex evaluateGREATERTHAN(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 2, network)) { return network.createVertex(Primitive.NULL); } Vertex left = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); Vertex right = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if ((left.getData() instanceof Number) && (right.getData() instanceof Number)) { if (((Number)left.getData()).doubleValue() > ((Number)right.getData()).doubleValue()) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } if ((left.getData() instanceof String) && (right.getData() instanceof String)) { if (((String)left.getData()).compareTo((String)right.getData()) > 0) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } if ((left.getData() instanceof java.util.Date) && (right.getData() instanceof java.util.Date)) { if (((java.util.Date)left.getData()).compareTo((java.util.Date)right.getData()) > 0) { return network.createVertex(Primitive.TRUE); } else { return network.createVertex(Primitive.FALSE); } } return network.createVertex(Primitive.UNKNOWN); } /** * Evaluate the NOT operation. * ! (x == y) */ public Vertex evaluateNOT(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 1, network)) { return network.createVertex(Primitive.NULL); } Vertex argument = arguments.get(0).getTarget(); Vertex result = evaluateExpression(argument, variables, network, startTime, maxTime, stack); if (result.is(Primitive.TRUE)) { result = network.createVertex(Primitive.FALSE); } else if (result.is(Primitive.FALSE)) { result = network.createVertex(Primitive.TRUE); } else if (result.is(Primitive.UNKNOWN)) { result = network.createVertex(Primitive.UNKNOWN); } return result; } /** * Evaluate the OR condition. * (x == y || y == z) */ public Vertex evaluateOR(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { Vertex first = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); if (first.is(Primitive.TRUE)) { return first; } if (arguments.size() == 1) { return network.createVertex(Primitive.FALSE); } Vertex second = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if (second.is(Primitive.TRUE)) { return second; } return network.createVertex(Primitive.FALSE); } /** * Evaluate the OR condition. * (x == y || y == z) */ public Vertex evaluateAND(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { Vertex first = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); if (!first.is(Primitive.TRUE)) { return network.createVertex(Primitive.FALSE); } if (arguments.size() == 1) { return network.createVertex(Primitive.TRUE); } Vertex second = evaluateExpression(arguments.get(1).getTarget(), variables, network, startTime, maxTime, stack); if (second.is(Primitive.TRUE)) { return network.createVertex(Primitive.TRUE); } return network.createVertex(Primitive.FALSE); } /** * Evaluate the NEW operation. * new (#number, #sequence) * Create a new vertex as an instance of the argument types. */ public Vertex evaluateNEW(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { Vertex newVertex = null; newVertex = network.createVertex(); for (Relationship argument : arguments) { Vertex type = evaluateExpression(argument.getTarget(), variables, network, startTime, maxTime, stack); newVertex.addRelationship(Primitive.INSTANTIATION, type); // Assign the name of the type to the default name of the instance. /*Collection<Relationship> names = type.getRelationships(Primitive.WORD); if (names != null) { for (Relationship name : names) { newVertex.addRelationship(Primitive.WORD, name.getTarget()); } }*/ // Check if the type is a classification, if not, make its instantiations, specializations. if (!type.hasRelationship(Primitive.INSTANTIATION, Primitive.CLASSIFICATION)) { Collection<Relationship> specializations = type.getRelationships(Primitive.INSTANTIATION); if (specializations != null) { for (Relationship specialization : specializations) { type.addRelationship(Primitive.SPECIALIZATION, specialization.getTarget()); } type.addRelationship(Primitive.INSTANTIATION, Primitive.CLASSIFICATION); } } } return newVertex; } /** * Evaluate the function invocation. * x.y(a, b, c) * i.e. #Context.push(x) * Invoke the function declared on the object, or Sense/Thought/Tool, or primitive. */ @SuppressWarnings("rawtypes") public Vertex evaluateCALL(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) throws Exception { Vertex source = evaluateExpression(expression.getRelationship(Primitive.THIS), variables, network, startTime, maxTime, stack); Vertex function = evaluateExpression(expression.getRelationship(Primitive.FUNCTION), variables, network, startTime, maxTime, stack); Object sourceObject = null; if (source.isPrimitive()) { String name = ((Primitive)source.getData()).getIdentity().toLowerCase(); if (name.equals("avatar")) { sourceObject = network.getBot().avatar(); } else if (name.equals("memory")) { sourceObject = network.getBot().memory(); } else if (name.equals("mood")) { sourceObject = network.getBot().mood(); } else if (name.equals("mind")) { sourceObject = network.getBot().mind(); } else if (name.equals("awareness")) { sourceObject = network.getBot().awareness(); } if (sourceObject == null) { sourceObject = network.getBot().awareness().getSense(name); } if (sourceObject == null) { sourceObject = network.getBot().mind().getThought(name); } if (sourceObject == null) { sourceObject = network.getBot().awareness().getTool(name); } } if (sourceObject == null) { sourceObject = this; } if (!function.isPrimitive()) { return network.createVertex(Primitive.NULL); } String functionName = ((Primitive)function.getData()).getIdentity(); Object[] methodArguments = new Object[arguments.size() + 1]; Class[] argumentTypes = new Class[arguments.size() + 1]; methodArguments[0] = source; argumentTypes[0] = Vertex.class; Vertex[] values = new Vertex[arguments.size()]; for (int index = 0; index < arguments.size(); index++) { Vertex argument = evaluateExpression(arguments.get(index).getTarget(), variables, network, startTime, maxTime, stack); values[index] = argument; methodArguments[index + 1] = argument; argumentTypes[index + 1] = Vertex.class; } Method method = null; try { method = sourceObject.getClass().getMethod(functionName, argumentTypes); } catch (Exception missing) { methodArguments = new Object[2]; argumentTypes = new Class[2]; methodArguments[0] = source; methodArguments[1] = values; argumentTypes[0] = Vertex.class; argumentTypes[1] = Vertex[].class; try { method = sourceObject.getClass().getMethod(functionName, argumentTypes); } catch (Exception reallyMissing) { throw new SelfExecutionException(expression, "Missing function: " + functionName + " on: " + source); } } Vertex result = null; try { result = (Vertex)method.invoke(sourceObject, methodArguments); } catch (Exception exception) { network.getBot().log(sourceObject, exception); } if (result == null) { result = network.createVertex(Primitive.NULL); } else { result = network.createVertex(result); } return result; } /** * Evaluate the RANDOM operation. * random (x, y, z) * Return a random argument. * Only evaluate the selected argument. */ public Vertex evaluateRANDOM(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (arguments.isEmpty()) { return network.createVertex(Primitive.NULL); } return evaluateExpression(Utils.random(arguments).getTarget(), variables, network, startTime, maxTime, stack); } /** * Evaluate the SYMBOL operation. * Symbol(x) * Return a random argument. * Only evaluate the selected argument. */ public Vertex evaluateSYMBOL(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (! checkArguments(expression, arguments, 1, network)) { return network.createVertex(Primitive.NULL); } Vertex argument = arguments.get(0).getTarget(); Vertex result = evaluateExpression(argument, variables, network, startTime, maxTime, stack); return network.createVertex(new Primitive(((String.valueOf(result.getData()).toLowerCase())))); } /** * Evaluate the REDIRECT or SRAI operation. * redirect("Hello"), srai("Hello") * Return the response to processing the input. */ public Vertex evaluateREDIRECT(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) throws Exception { if (! checkArguments(expression, arguments, 1, network)) { return network.createVertex(Primitive.NULL); } Vertex sentence = evaluateExpression(arguments.get(0).getTarget(), variables, network, startTime, maxTime, stack); if (!sentence.instanceOf(Primitive.SENTENCE) && sentence.instanceOf(Primitive.FRAGMENT)) { sentence.addRelationship(Primitive.INSTANTIATION, Primitive.SENTENCE); } Vertex input = variables.get(network.createVertex(Primitive.INPUT_VARIABLE)); input = input.copy(); input.setRelationship(Primitive.INPUT, sentence); Vertex response = network.getBot().mind().getThought(Language.class).input(input, sentence, variables, network); if (response == null) { return network.createVertex(Primitive.NULL); } return response; } /** * Evaluate the DEBUG operation. * debug ("debug", :0, :2) * Log the arguments to the log. */ public Vertex evaluateDEBUG(Vertex expression, List<Relationship> arguments, Map<Vertex, Vertex> variables, Network network, long startTime, long maxTime, int stack) { if (network.getBot().isDebugFine()) { StringWriter writer = new StringWriter(); boolean first = true; for (Relationship argument : arguments) { if (!first) { writer.write(" : "); } first = false; Vertex value = evaluateExpression(argument.getTarget(), variables, network, startTime, maxTime, stack); writer.write(value.printString()); } network.getBot().log("DEBUG", writer.toString(), Level.FINE); } return network.createVertex(Primitive.NULL); } /** * Set the relationship from the source of the type, to the target object. * This first clears any existing relationships of the same type. */ public Vertex set(Vertex source, Vertex type, Vertex target) { if (target.is(Primitive.NULL)) { source.internalRemoveRelationships(type); } else { source.setRelationship(type, target); } // Following some crazy AIML implied rules here... if (type.isPrimitive() && (type.is(Primitive.IT) || type.is(Primitive.HE) || type.is(Primitive.SHE))) { return type; } return target; } /** * Array or Set add operation. * Array elements use the #element type. */ public Vertex add(Vertex source, Vertex value) { if (source.instanceOf(Primitive.SET)) { source.addRelationship(source.getNetwork().createVertex(Primitive.ELEMENT), value); } else { source.addRelationship(source.getNetwork().createVertex(Primitive.ELEMENT), value, Integer.MAX_VALUE); } return source; } /** * Add the relationship from the source of the type, to the target object. * If the relationship already exists, increase its correctness. */ public Vertex add(Vertex source, Vertex type, Vertex target) { source.addRelationship(type, target); return source; } /** * Add a weak relationship from the source of the type, to the target object. * Weak relationships have a low correctness value. */ public Vertex weakAdd(Vertex source, Vertex type, Vertex target) { source.addWeakRelationship(type, target, 0.1f); return source; } public Vertex addWithMeta(Vertex source, Vertex relationship, Vertex value, Vertex metaType, Vertex metaValue) { Relationship relation = source.addRelationship(relationship, value); if (!metaValue.is(Primitive.NULL)) { Vertex meta = source.getNetwork().createMeta(relation); meta.addRelationship(metaType, metaValue); } return source; } public Vertex weakAddWithMeta(Vertex source, Vertex relationship, Vertex value, Vertex metaType, Vertex metaValue) { Relationship relation = source.addWeakRelationship(relationship, value, 0.1f); if (!metaValue.is(Primitive.NULL)) { Vertex meta = source.getNetwork().createMeta(relation); meta.addRelationship(metaType, metaValue); } return source; } public Vertex append(Vertex source, Vertex relationship, Vertex value) { source.addRelationship(relationship, value, Integer.MAX_VALUE); return source; } public Vertex appendWithMeta(Vertex source, Vertex relationship, Vertex value, Vertex metaType, Vertex metaValue) { Relationship relation = source.addRelationship(relationship, value, Integer.MAX_VALUE); if (!metaValue.is(Primitive.NULL)) { Vertex meta = source.getNetwork().createMeta(relation); meta.addRelationship(metaType, metaValue); } return source; } public Vertex remove(Vertex source, Vertex type, Vertex target) { source.removeRelationship(type, target); return source; } public Vertex removeWithMeta(Vertex source, Vertex relationship, Vertex value, Vertex metaType, Vertex metaValue) { Relationship relation = source.removeRelationship(relationship, value); if (!metaValue.is(Primitive.NULL)) { Vertex meta = source.getNetwork().createMeta(relation); meta.addRelationship(metaType, metaValue); } return source; } /** * Determine the size of the relationship type. */ public Vertex size(Vertex source, Vertex type) { Collection<Relationship> elements = source.getRelationships(type); if (elements == null) { return source.getNetwork().createVertex(0); } return source.getNetwork().createVertex(elements.size()); } /** * Determine the size, by elements for an array, words for sentence, otherwise total relationships. */ public Vertex size(Vertex source) { if (source.instanceOf(Primitive.ARRAY)) { Collection<Relationship> elements = source.getRelationships(Primitive.ELEMENT); if (elements == null) { return source.getNetwork().createVertex(0); } return source.getNetwork().createVertex(elements.size()); } else if (source.instanceOf(Primitive.SENTENCE) || source.instanceOf(Primitive.FRAGMENT)) { Collection<Relationship> elements = source.getRelationships(Primitive.WORD); if (elements == null) { return source.getNetwork().createVertex(0); } return source.getNetwork().createVertex(elements.size()); } return source.getNetwork().createVertex(source.getAllRelationships().size()); } /** * Array or Set delete operation. * Array elements use the #element type. */ public Vertex delete(Vertex source, Vertex target) { return delete(source, source.getNetwork().createVertex(Primitive.ELEMENT), target); } public Vertex deleteAll(Vertex source, Vertex type) { source.internalRemoveRelationships(type); return source; } public Vertex remove(Vertex source, Vertex type) { source.internalRemoveRelationships(type); return source; } public Vertex delete(Vertex source, Vertex type, Vertex target) { source.internalRemoveRelationship(type, target); return source; } public Vertex delete(Vertex source) { source.getNetwork().removeVertex(source); return source.getNetwork().createVertex(Primitive.NULL); } /** * Search what references the object by the relationship. * x.findReferenceBy(y) */ public Vertex findReferenceBy(Vertex source, Vertex type) { Vertex result = null; List<Relationship> relationships = source.getNetwork().findAllRelationshipsTo(source, type); for (Relationship relationship : relationships) { if (!relationship.isInverse() && ((result == null) || (relationship.getSource().getConsciousnessLevel() > result.getConsciousnessLevel()))) { result = relationship.getSource(); } } if (result != null) { source.getNetwork().getBot().log(this, "Found reference", Level.FINER, source, type, result); } else { result = source.getNetwork().createVertex(Primitive.NULL); source.getNetwork().getBot().log(this, "No references", Level.FINER, source, type); } return result; } /** * Search what references the object. * x.findReference() */ public Vertex findReference(Vertex source) { Vertex result = null; List<Relationship> relationships = source.getNetwork().findAllRelationshipsTo(source); for (Relationship relationship : relationships) { if (!relationship.isInverse() && ((result == null) || (relationship.getSource().getConsciousnessLevel() > result.getConsciousnessLevel()))) { result = relationship.getSource(); } } if (result != null) { source.getNetwork().getBot().log(this, "Found reference", Level.FINER, source, result); } else { result = source.getNetwork().createVertex(Primitive.NULL); source.getNetwork().getBot().log(this, "No references", Level.FINER, source); } return result; } public Vertex set(Vertex source, Vertex type, Vertex target, Vertex index) { List<Vertex> values = source.orderedRelations(type); int size = 0; if (values != null) { size = values.size(); } int indexValue = size; if (index.getData() instanceof Number) { indexValue = ((Number)index.getData()).intValue(); if (indexValue < 0) { indexValue = size + indexValue; } } else { try { indexValue = Integer.valueOf(index.printString()); if (indexValue < 0) { indexValue = size + indexValue; } } catch (Exception invalid) {}; } source.addRelationship(type, target, indexValue); return source; } public Vertex all(Vertex source, Vertex type) { List<Vertex> values = source.orderedRelations(type); if (values == null) { return source.getNetwork().createVertex(Primitive.NULL); } Vertex all = source.getNetwork().createVertex(); all.addRelationship(Primitive.INSTANTIATION, Primitive.ARRAY); int index = 0; for (Vertex value : values) { all.addRelationship(Primitive.ELEMENT, value, index); index++; } all.addRelationship(Primitive.LENGTH, source.getNetwork().createVertex(values.size())); return all; } public Vertex keys(Vertex source) { Vertex all = source.getNetwork().createVertex(); all.addRelationship(Primitive.INSTANTIATION, Primitive.ARRAY); int index = 0; for (Vertex value : source.getRelationships().keySet()) { all.addRelationship(Primitive.ELEMENT, value, index); index++; } all.addRelationship(Primitive.LENGTH, source.getNetwork().createVertex(source.getRelationships().keySet().size())); return all; } public Vertex creationDate(Vertex source) { return source.getNetwork().createVertex(source.getCreationDate()); } public Vertex accessCount(Vertex source) { return source.getNetwork().createVertex(source.getAccessCount()); } public Vertex hasData(Vertex source) { if (source.hasData()) { return source.getNetwork().createVertex(Primitive.TRUE); } else { return source.getNetwork().createVertex(Primitive.FALSE); } } public Vertex dataType(Vertex source) { if (source.hasData()) { return source.getNetwork().createVertex(Primitive.NULL); } else { return source.getNetwork().createVertex(new Primitive(source.getDataType())); } } public Vertex pin(Vertex source) { source.setPinned(true); return source; } public Vertex unpin(Vertex source) { source.setPinned(false); return source; } public Vertex get(Vertex source, Vertex type) { Vertex value = source.mostConscious(type); if (value == null) { return source.getNetwork().createVertex(Primitive.NULL); } return value; } public Vertex get(Vertex source, Vertex type, Vertex index) { List<Vertex> values = source.orderedRelations(type); if (values == null) { return source.getNetwork().createVertex(Primitive.NULL); } int indexValue = 0; if (index.getData() instanceof Number) { indexValue = ((Number)index.getData()).intValue(); } else { try { indexValue = Integer.valueOf(index.printString()); } catch (Exception invalid) {}; } if (indexValue < 0) { indexValue = values.size() + indexValue; } if (indexValue >= 0 && indexValue < values.size()) { return values.get(indexValue); } source.getNetwork().getBot().log(this, "Invalid GET index", Level.FINE, source, type, index); return source.getNetwork().createVertex(Primitive.NULL); } public Vertex getWithAssociate(Vertex source, Vertex type, Vertex associate, Vertex associateType) { Vertex value = source.mostConsciousWithAssoiate(type, associate, associateType); if (value == null) { return source.getNetwork().createVertex(Primitive.NULL); } return value; } public Vertex has(Vertex source, Vertex type, Vertex target) { Relationship relationship = source.getRelationship(type, target); if (relationship == null) { return source.getNetwork().createVertex(Primitive.UNKNOWN); } else if (relationship.isInverse()) { return source.getNetwork().createVertex(Primitive.FALSE); } else { return source.getNetwork().createVertex(Primitive.TRUE); } } public Vertex hasOrInherits(Vertex source, Vertex type, Vertex target) { if (source.hasOrInheritsRelationship(type, target)) { return source.getNetwork().createVertex(Primitive.TRUE); } else if (source.hasOrInheritsInverseRelationship(type, target)) { return source.getNetwork().createVertex(Primitive.FALSE); } return source.getNetwork().createVertex(Primitive.UNKNOWN); } public Vertex hasOtherMeaning(Vertex source, Vertex type, Vertex target) { Relationship relationship = source.getRelationship(type, target); if (relationship != null) { if (relationship.isInverse()) { return source.getNetwork().createVertex(Primitive.FALSE); } else { return source.getNetwork().createVertex(Primitive.TRUE); } } if (source.hasOrInheritsRelationship(type, target)) { // Left has the relationship, return true. return source.getNetwork().createVertex(Primitive.TRUE); } else if (source.hasOrInheritsInverseRelationship(type, target)) { // Left has an inverse relationship to the right, return false. return source.getNetwork().createVertex(Primitive.FALSE); } else { if (type.is(Primitive.IS)) { if (source.hasAnyRelationshipToTarget(target)) { // Left has a relationship to right, return true. return source.getNetwork().createVertex(Primitive.TRUE); } } if (target.getData() instanceof String) { // Check case. Vertex lower = source.getNetwork().createVertex(((String)target.getData()).toLowerCase()); if (source.hasOrInheritsRelationship(type, lower)) { // Left has the relationship, return true. return source.getNetwork().createVertex(Primitive.TRUE); } else if (source.hasOrInheritsInverseRelationship(type, lower)) { // Left has an inverse relationship to the right, return false. return source.getNetwork().createVertex(Primitive.FALSE); } Vertex caps = source.getNetwork().createVertex(Utils.capitalize(((String)target.getData()).toLowerCase())); if (source.hasOrInheritsRelationship(type, caps)) { // Left has the relationship, return true. return source.getNetwork().createVertex(Primitive.TRUE); } else if (source.hasOrInheritsInverseRelationship(type, caps)) { // Left has an inverse relationship to the right, return false. return source.getNetwork().createVertex(Primitive.FALSE); } } Vertex result = null; // Check all meanings of all words. Collection<Relationship> words = target.getRelationships(Primitive.WORD); result = checkRelationTargetForAllWords(words, source, type, target, source.getNetwork()); if (result != null) { return result; } // Check synonyms as well. words = target.getRelationships(Primitive.SYNONYM); result = checkRelationTargetForAllWords(words, source, type, target, source.getNetwork()); if (result != null) { return result; } // Check all meanings of all words for relation. // Check all meanings of all words. words = type.getRelationships(Primitive.WORD); result = checkRelationRelationshipForAllWords(words, source, target, source.getNetwork()); if (result != null) { return result; } // Check synonyms as well. words = type.getRelationships(Primitive.SYNONYM); result = checkRelationRelationshipForAllWords(words, source, target, source.getNetwork()); if (result != null) { return result; } } // TODO: clean this up, and handle all other cases. return source.getNetwork().createVertex(Primitive.UNKNOWN); } public Vertex meta(Vertex source, Vertex type, Vertex target) { Relationship relationship = source.getRelationship(type, target); if (relationship == null) { return source.getNetwork().createVertex(Primitive.NULL); } else { return source.getNetwork().createMeta(relationship); } } /** * Check if any of the words have the relationship. */ public Vertex checkRelationRelationshipForAllWords(Collection<Relationship> words, Vertex source, Vertex target, Network network) { // Check all meanings of all words. if (words != null && !target.instanceOf(Primitive.WORD)) { Set<Vertex> processed = new HashSet<Vertex>(); processed.add(target); for (Relationship word : words) { Collection<Relationship> otherMeanings = word.getTarget().getRelationships(Primitive.MEANING); if (otherMeanings != null) { for (Relationship meaning : otherMeanings) { if (!processed.contains(meaning.getTarget())) { processed.add(meaning.getTarget()); if (source.hasOrInheritsRelationship(meaning.getTarget(), target)) { // Left has the relationship, return true. return network.createVertex(Primitive.TRUE); } else if (source.hasOrInheritsInverseRelationship(meaning.getTarget(), target)) { // Left has an inverse relationship to the right, return false. return network.createVertex(Primitive.FALSE); } } } } } } return null; } /** * Check if any of the words have the relationship. */ public Vertex checkRelationTargetForAllWords(Collection<Relationship> words, Vertex source, Vertex type, Vertex target, Network network) { // Check all meanings of all words. if (words != null && !target.instanceOf(Primitive.WORD)) { Set<Vertex> processed = new HashSet<Vertex>(); processed.add(target); for (Relationship word : words) { Collection<Relationship> otherMeanings = word.getTarget().getRelationships(Primitive.MEANING); if (otherMeanings != null) { for (Relationship meaning : otherMeanings) { if (!processed.contains(meaning.getTarget())) { processed.add(meaning.getTarget()); if (source.hasOrInheritsRelationship(type, meaning.getTarget())) { // Left has the relationship, return true. return network.createVertex(Primitive.TRUE); } else if (source.hasOrInheritsInverseRelationship(type, meaning.getTarget())) { // Left has an inverse relationship to the right, return false. return network.createVertex(Primitive.FALSE); } } } } } } return null; } /** * Array or Set has operation. * Array elements use the #element type. */ public Vertex has(Vertex source, Vertex target) { return has(source, source.getNetwork().createVertex(Primitive.ELEMENT), target); } public Vertex hasAny(Vertex source, Vertex type) { if (source.hasRelationship(type)) { return source.getNetwork().createVertex(Primitive.TRUE); } else { return source.getNetwork().createVertex(Primitive.FALSE); } } public Vertex random(Vertex source, Vertex type) { Collection<Relationship> relationships = source.getRelationships(type); if (relationships == null) { return source.getNetwork().createVertex(Primitive.NULL); } return Utils.random(relationships).getTarget(); } public Vertex getLast(Vertex source, Vertex relationship) { List<Vertex> values = source.orderedRelations(relationship); if (values.isEmpty()) { return source.getNetwork().createVertex(Primitive.NULL); } return values.get(values.size() - 1); } public Vertex getLast(Vertex source, Vertex relationship, Vertex index) { List<Vertex> values = source.orderedRelations(relationship); if (values.isEmpty()) { return source.getNetwork().createVertex(Primitive.NULL); } int value = 1; if (index.getData() instanceof Number) { value = ((Number)index.getData()).intValue(); if (value <= 0 || value > values.size()) { return source.getNetwork().createVertex(Primitive.NULL); } } else { return source.getNetwork().createVertex(Primitive.NULL); } return values.get(values.size() - value); } public Vertex toUpperCase(Vertex text) { Vertex fragment = text.getNetwork().createFragment(text.printString().toUpperCase()); fragment.addRelationship(Primitive.TYPE, Primitive.CASESENSITVE); return fragment; } public Vertex trim(Vertex text) { return text.getNetwork().createVertex(text.printString().trim()); } public Vertex concat(Vertex source, Vertex argument) { return source.getNetwork().createVertex(source.printString() + argument.printString()); } public Vertex includes(Vertex source, Vertex argument) { if (source.printString().indexOf(argument.printString()) == -1) { return source.getNetwork().createVertex(Primitive.FALSE); } else { return source.getNetwork().createVertex(Primitive.TRUE); } } public Vertex startsWith(Vertex source, Vertex argument) { if (source.printString().startsWith(argument.printString()) == false) { return source.getNetwork().createVertex(Primitive.FALSE); } else { return source.getNetwork().createVertex(Primitive.TRUE); } } public Vertex endsWith(Vertex source, Vertex argument) { if (source.printString().endsWith(argument.printString()) == false) { return source.getNetwork().createVertex(Primitive.FALSE); } else { return source.getNetwork().createVertex(Primitive.TRUE); } } public Vertex charAt(Vertex source, Vertex index) { if (index.getData() instanceof Number) { return source.getNetwork().createVertex(Primitive.NULL); } return source.getNetwork().createVertex(String.valueOf(source.printString().charAt(((Number)index.getData()).intValue()))); } public Vertex indexOf(Vertex source, Vertex argument) { if (source.instanceOf(Primitive.ARRAY)) { Relationship relationship = source.getRelationship(Primitive.ELEMENT, argument); if (relationship == null) { return source.getNetwork().createVertex(-1); } return source.getNetwork().createVertex(relationship.getIndex()); } int index = source.printString().indexOf(argument.printString()); return source.getNetwork().createVertex(index); } public Vertex substring(Vertex source, Vertex start, Vertex end) { if ((start.getData() instanceof Number) || (end.getData() instanceof Number)) { return source.getNetwork().createVertex(Primitive.NULL); } return source.getNetwork().createVertex(source.printString().substring(((Number)start.getData()).intValue(), ((Number)end.getData()).intValue())); } public Vertex replace(Vertex source, Vertex token, Vertex replacement) { return source.getNetwork().createVertex(source.printString().replace(token.printString(), replacement.printString())); } public Vertex toLowerCase(Vertex text) { Vertex fragment = text.getNetwork().createFragment(text.printString().toLowerCase()); fragment.addRelationship(Primitive.TYPE, Primitive.CASESENSITVE); return fragment; } public Vertex toNumber(Vertex text) { try { String value = text.printString(); if (value.indexOf('.') == -1) { return text.getNetwork().createVertex(new BigDecimal(value)); } else { return text.getNetwork().createVertex(new BigInteger(value)); } } catch (Exception exception) { return null; } } @Override public String toString() { return getClass().getSimpleName(); } }