private NovelExpression HandleOperand(NovelExpression expression, string operand) { int index = -1; if (IsVariable(operand)) { expression.Term.Add(new NovelExpressionVariable(operand, Variables.GetStackIndex(operand))); } else if (IsFunction(operand)) { //TODO update offset??? expression.Term.Add(new NovelExpressionFunctionCall(operand, 0, false)); } else if ((index = IsDelegateFunction(operand)) >= 0) { expression.Term.Add(new NovelExpressionFunctionCall(operand, index, true)); } else if (IsLiteral(operand)) { expression.Term.Add(new NovelExpressionLiteral(GetLiteral(operand))); } else if (IsString(operand)) { expression.Term.Add(new NovelExpressionLiteral(operand.Substring(1, operand.Count() - 2))); } else { throw new NovelException("Undefined object " + operand + ".", ParsedFile, ParsedLine); } return(expression); }
public NovelCondition ParseCondition(string text, out int conditionLevel, ref List <NovelInstruction> instructions) { conditionLevel = -1; var conditionStart = new string [] { "if", "else if", "else" }; for (int i = 0; i < conditionStart.Length; i++) { if (text.IndexOf(conditionStart[i]) == 0) { conditionLevel = i; break; } } var conditionText = text.Substring( conditionStart[conditionLevel].Length).Trim(); var novelCondition = new NovelCondition(); if (conditionLevel == 0 || conditionLevel == 1) { var unfold = ParseExpression(conditionText); if (unfold.Last() is NovelExpandStack) { for (int i = 0; i < unfold.Count - 1; i++) { instructions.Add(unfold[i]); } novelCondition.StackInstruction = unfold.Last() as NovelExpandStack; var lastExpression = unfold[unfold.Count - 2] as NovelExpression; novelCondition.ConditionOperand = lastExpression.Term[0] as NovelExpressionOperand; } else { var lastExpression = unfold.Last() as NovelExpression; novelCondition.ConditionOperand = lastExpression.Term[0] as NovelExpressionOperand; } } else if (conditionLevel == 2) { var expression = new NovelExpression(); expression.Term.Add(new NovelExpressionLiteral(true)); novelCondition.ConditionOperand = new NovelExpressionLiteral(true); } return(novelCondition); }
private void ExecuteExpression(NovelExpression expression) { if (expression.Term.Count == 5) { var result = expression.Term[0] as NovelExpressionOperand; var operand1 = expression.Term[1] as NovelExpressionOperand; var operand2 = expression.Term[2] as NovelExpressionOperand; var oper = expression.Term[3] as NovelExpressionOperator; var assignOper = expression.Term[4] as NovelExpressionOperator; //Assuming that assign operator is = if (assignOper is NovelAssignOperator) { var var1 = OperandToValue(operand1); var var2 = OperandToValue(operand2); //TODO EXECUTION TIME EXCEPTIONS if (var1 == null) { throw new NovelException("Object " + var1.ToString() + " is undefined", "", 0); } if (var2 == null) { throw new NovelException("Object " + var2.ToString() + " is undefined", "", 0); } var varRes = oper.Operate(var1, var2); Stack.SetVariableAt(StackPointer, (result as NovelExpressionVariable).StackOffset, varRes); } } else if (expression.Term.Count == 3) { var result = expression.Term[0] as NovelExpressionOperand; var operand1 = expression.Term[1] as NovelExpressionOperand; var assignOper = expression.Term[2] as NovelExpressionOperator; //Assuming that assign operator is = if (assignOper is NovelAssignOperator) { var var1 = OperandToValue(operand1); //TODO EXECUTION TIME EXCEPTIONS if (var1 == null) { throw new NovelException("Object " + var1.ToString() + " is undefined", "", 0); } Stack.SetVariableAt(StackPointer, (result as NovelExpressionVariable).StackOffset, var1); } } else if (expression.Term.Count == 1) { if (expression.Term[0] is NovelExpressionFunctionCall) { var exprFunc = expression.Term[0] as NovelExpressionFunctionCall; var argList = new List <object>(); foreach (var arg in exprFunc.Arguments) { argList.Add(OperandToValue(arg).Value); } if (!exprFunc.IsDelegated) { CallScriptFunction(exprFunc.Name, argList.ToArray()); InstructionPointer--; } else { Stack.ExpandStack(1); var result = Script.DelegateFunctionList.Call(exprFunc.Offset, argList.ToArray()); //Possible for Actions that returns null if (result == null) { result = new int(); result = 0; } Stack.SetVariableAtLast(new NovelVariable(result)); } } } }
void Advance(bool doNotIncrement = false) { //Debug.Log("advance:"+doNotIncrement); lastToken = currentBranch.frames[currentFrame].token; if (!doNotIncrement) { currentFrame++; } if (currentFrame >= currentBranch.frames.Count) { running = false; characterGraphic.gameObject.SetActive(false); if (callBack != null) { callBack.Invoke(); } return; } NovelFrame frame = currentBranch.frames[currentFrame]; switch (frame.token) { case Tokens.background: { title.text = string.Empty; message.text = string.Empty; background.sprite = marshal.Background((string)frame.payload); StartTimer(); } break; case Tokens.monologue: { title.text = "monologue"; message.text = (string)frame.payload; state = RunnerStates.waitOnInput; } break; case Tokens.character: { NovelCharacter character = ((NovelCharacter)frame); if (character.name != "You" && character.name != "player") { characterGraphic.gameObject.SetActive(true); characterGraphic.sprite = marshal.Character(character.name, null); characterGraphic.rectTransform.sizeDelta = Scale(characterGraphic.sprite.rect.size.y, 1080, characterGraphic.sprite.rect.size); } title.text = ((NovelCharacter)frame).name; message.text = string.Empty; state = RunnerStates.waitOnTimer; } break; case Tokens.expression: { NovelExpression expression = ((NovelExpression)frame); if (expression.character != "You" && expression.character != "player") { characterGraphic.gameObject.SetActive(true); characterGraphic.sprite = marshal.Character(expression.character, (string)expression.payload); characterGraphic.rectTransform.sizeDelta = Scale(characterGraphic.sprite.rect.size.y, 1080, characterGraphic.sprite.rect.size); } title.text = ((NovelExpression)frame).character; StartTimer(); } break; case Tokens.line: { if (lastToken == Tokens.character || lastToken == Tokens.expression || lastToken == Tokens.line) { /* Do Nothing */ } else { title.text = ((NovelExpression)frame).character + " " + ((NovelExpression)frame).payload; } message.text = (string)frame.payload; state = RunnerStates.waitOnInput; } break; case Tokens.hidecharacter: { characterGraphic.gameObject.SetActive(false); StartTimer(); } break; case Tokens.directive: { marshal.ExecuteProcedure((string)frame.payload); state = RunnerStates.waitOnTimer; StartTimer(); } break; case Tokens.jump: { StartTimer(); Jump((string)frame.payload); } break; case Tokens.TEXT: { NovelText text = (NovelText)frame; state = RunnerStates.waitOnInput; phone.PostTextMessage(text.character == "You", text.character, text.line); } break; case Tokens.options: { novelAssembly.SetActive(true); state = RunnerStates.waitOnChoice; NovelOptions options = (NovelOptions)frame; normalDisplay.SetActive(false); optionDisplay.SetActive(true); Transform[] old = optionContent.GetComponentsInChildren <Transform>(); Debug.Log(old.Length); foreach (Transform go in old) { if (go == optionContent.transform) { continue; } go.transform.parent = null; GameObject.Destroy(go.gameObject); } foreach (NovelOption option in options.options) { GameObject g = GameObject.Instantiate(providedButton, optionContent.transform.position, optionContent.transform.rotation, optionContent.transform); g.GetComponentInChildren <Text>().text = (string)option.payload; g.GetComponent <Button>().onClick.AddListener( () => { Jump(option.target); EndOptions(); } /// CLOSURE! to the rescue!! ); } } break; default: { throw new System.Exception("Unexpected token " + frame.token + " in switch statement."); } } }
public List <NovelInstruction> ParseExpression(string text) { //Trim the expression text = text.Trim(); //Create empty expression object NovelExpression novelExpression = new NovelExpression(); //Declare instructions List <NovelInstruction> instructions = new List <NovelInstruction>(); //For RPN algorithm purpose string output = ""; string buffer = ""; for (int i = 0; i < text.Length; i++) { //Check if the i is pointing at operator name var operatorIndex = IsOperator(text, i); //operatorIndex = -1 means that its regular character if (operatorIndex >= 0) { //Build expression here based on whats in buffer if (!buffer.Equals("")) { if (IsDeclaredVariable(buffer)) { buffer = buffer.Substring(3); if (!Variables.ContainsVariable(buffer)) { instructions.Add(new NovelExpandStack(1)); Variables.AddVaraible(buffer); } //TODO functions name else { throw new NovelException("Variable or function name " + buffer + " already exists.", ParsedFile, ParsedLine); } } //Handle the operands novelExpression = HandleOperand(novelExpression, buffer); //Push variable to the output output += buffer; buffer = ""; } //Get the new operator var op = Operators[operatorIndex]; //Parentheses close operator if (op is NovelCloseCurvedParenthesesOperator) { //Pop all operators till ( while (OperatorStack.Count() > 0) { var opFromStack = OperatorStack.Pop(); if (opFromStack is NovelOpenCurvedParenthesesOperator) { var parentheses = parenthesesType.Pop(); if (parentheses == ParenthesesType.Function) { novelExpression.Term.Add(new NovelFunctionEndOperator()); } break; } else { if (!(opFromStack is NovelOpenCurvedParenthesesOperator || opFromStack is NovelCloseCurvedParenthesesOperator)) { novelExpression.Term.Add(opFromStack); } } } } //If every other operator else { //Iteratore over OperatorStack while (OperatorStack.Count() > 0) { //If priority of new operator is lower or equal pop stack operators // if (op.GetPriority() <= OperatorStack.First().GetPriority() && !(op is NovelOpenCurvedParenthesesOperator)) { var opFromStack = OperatorStack.Pop(); if (!(opFromStack is NovelOpenCurvedParenthesesOperator || opFromStack is NovelCloseCurvedParenthesesOperator)) { novelExpression.Term.Add(opFromStack); } } else { break; } } } //Now put the operator on the stack if not close curved if (!(op is NovelCloseCurvedParenthesesOperator)) { //If previous term part was function call if (novelExpression.Term.Count >= 1 && op is NovelOpenCurvedParenthesesOperator && novelExpression.Term[novelExpression.Term.Count - 1] is NovelExpressionFunctionCall) { parenthesesType.Push(ParenthesesType.Function); novelExpression.Term.Add(new NovelFunctionStartOperator()); } //If normal paretheses else if (op is NovelOpenCurvedParenthesesOperator) { parenthesesType.Push(ParenthesesType.Normal); } OperatorStack.Push(op); } //Move pointer by a length of operator i += op.GetName().Length - 1; } //If its not an operator else { if (text[i].Equals(' ')) { continue; } else if (text[i].Equals('\t')) { continue; } else if (text[i].Equals('\r')) { continue; } else if (text[i].Equals('\n')) { continue; } //If its a quote if (text[i].Equals('\"')) { int len = text.IndexOf('\"', i + 1) - i + 1; buffer += text.Substring(i, len); i += len - 1; } //If its not add single character else { buffer += text[i]; } } } //Empty buffer first if (!buffer.Equals("")) { novelExpression = HandleOperand(novelExpression, buffer); } //Empty operator stack while (OperatorStack.Count() > 0) { var opFromStack = OperatorStack.Pop(); if (!(opFromStack is NovelOpenCurvedParenthesesOperator || opFromStack is NovelCloseCurvedParenthesesOperator)) { novelExpression.Term.Add(opFromStack); } } Variables.AddScope(); int reservedVariables = Variables.GetStackVariables(); while (novelExpression.Term.Count > 0) { novelExpression = UnfoldOperations(novelExpression, ref instructions); novelExpression = UnfoldArguments(novelExpression, ref instructions); //For single variables or literals if (novelExpression.Term.Count == 1) { var newExpression = new NovelExpression(); newExpression.Term.Add(novelExpression.Term[0]); instructions.Add(newExpression); novelExpression.Term.Clear(); } } //How many of temporary variables expression has reservedVariables = Variables.GetStackVariables() - reservedVariables; //Shrink stack to remove them if (reservedVariables > 0) { instructions.Add(new NovelExpandStack(-reservedVariables)); } Variables.RemoveScope(); foreach (var instruction in instructions) { string buff = ""; buff += " " + instruction; Console.WriteLine(buff); } Console.WriteLine(""); return(instructions); }
private NovelExpression UnfoldArguments(NovelExpression expression, ref List <NovelInstruction> instructions) { //Get the term var term = expression.Term; for (int i = 0; i < term.Count; i++) { int functionEndIndex = -1; int functionElements = 2; //Look for function start operator if (term[i] is NovelFunctionStartOperator && term[i - 1] is NovelExpressionFunctionCall) { //Check if inside function are only comma characters bool onlyCommas = true; for (int j = i + 1; j < term.Count; j++) { var test = term[j]; functionElements++; //Read until novel function end if (term[j] is NovelFunctionEndOperator) { functionEndIndex = j; break; } //If its an operator if (term[j] is NovelExpressionOperator) { //If its different than comma if (!(term[j] is NovelCommaOperator)) { onlyCommas = false; break; } } } if (onlyCommas) { //Fill function with arguments var function = term[i - 1] as NovelExpressionFunctionCall; for (int j = i; j < functionEndIndex; j++) { if (term[j] is NovelExpressionOperand) { function.Arguments.Add(term[j] as NovelExpressionOperand); } } //TODO //here i have number of arguments in function //so i can check if its the right number int newIndex = ParsedScript.DelegateFunctionList. ContainsFunction(function.Name, function.Arguments.Count); //If found new delegated function if (newIndex > -1) { function.Offset = newIndex; } else { throw new NovelException("Could not find delegated method " + function.Name + " with " + function.Arguments.Count() + " arguments.", "", 0); } //Now create new expression var lastStackOperator = Variables.GetStackVariables(); var temporaryVariable = new NovelExpressionVariable("temp_" + lastStackOperator, lastStackOperator); Variables.AddVaraible(temporaryVariable.Name); //instructions.Add(new NovelExpandStack(1)); var newExpression = new NovelExpression(); //newExpression.Term.Add(temporaryVariable); newExpression.Term.Add(function); //newExpression.Term.Add(new NovelAssignOperator()); instructions.Add(newExpression); //Remove from expression for (int j = 0; j < functionElements; j++) { expression.Term.RemoveAt(i - 1); } if (expression.Term.Count > 0) { expression.Term.Insert(i - 1, temporaryVariable); } i -= 1; } } } return(expression); }
private NovelExpression UnfoldOperations(NovelExpression expression, ref List <NovelInstruction> instructions) { //Get the term var term = expression.Term; //Look for for (int i = 0; i < term.Count; i++) { var part = term[i]; //Look for operator different //comma //fnc start //fnc end //fnc call if (part is NovelExpressionOperator) { if (!(part is NovelExpressionFunctionCall) && !(part is NovelCommaOperator) && !(part is NovelFunctionStartOperator) && !(part is NovelFunctionEndOperator)) { //If its one argument operator if (part is NovelNegationOperator && term[i - 1] is NovelExpressionOperand) { var operand = term[i - 1] as NovelExpressionOperand; var lastStackOperator = Variables.GetStackVariables(); var temporaryVariable = new NovelExpressionVariable("temp_" + lastStackOperator, lastStackOperator); Variables.AddVaraible(temporaryVariable.Name); instructions.Add(new NovelExpandStack(1)); var newExpression = new NovelExpression(); newExpression.Term.Add(temporaryVariable); newExpression.Term.Add(operand); newExpression.Term.Add(part); newExpression.Term.Add(new NovelAssignOperator()); instructions.Add(newExpression); //Replace last operation with temporary variable expression.Term.RemoveAt(i - 1); expression.Term.RemoveAt(i - 1); //Don't put temporary variable to expression if its empty if (expression.Term.Count > 0) { expression.Term.Insert(i - 1, temporaryVariable); } i -= 1; } //Get the two operands if its not negation else { //If its the end of expression if (part is NovelAssignOperator && expression.Term.Count == 3 && term[i - 1] is NovelExpressionOperand && term[i - 2] is NovelExpressionOperand) { var newExpression = new NovelExpression(); newExpression.Term.Add(term[i - 2]); newExpression.Term.Add(term[i - 1]); newExpression.Term.Add(part); instructions.Add(newExpression); expression.Term.Clear(); } //If both previous parts in term are operands else if ( term[i - 1] is NovelExpressionOperand && term[i - 2] is NovelExpressionOperand) { var operandLeft = term[i - 2] as NovelExpressionOperand; var operandRight = term[i - 1] as NovelExpressionOperand; var lastStackOperator = Variables.GetStackVariables(); var temporaryVariable = new NovelExpressionVariable("temp_" + lastStackOperator, lastStackOperator); Variables.AddVaraible(temporaryVariable.Name); instructions.Add(new NovelExpandStack(1)); //Create new operation of two operands //and assign the result to temporary variable var newExpression = new NovelExpression(); newExpression.Term.Add(temporaryVariable); newExpression.Term.Add(operandLeft); newExpression.Term.Add(operandRight); newExpression.Term.Add(part); newExpression.Term.Add(new NovelAssignOperator()); instructions.Add(newExpression); //Replace last operation with temporary variable expression.Term.RemoveAt(i - 2); expression.Term.RemoveAt(i - 2); expression.Term.RemoveAt(i - 2); if (expression.Term.Count > 0) { expression.Term.Insert(i - 2, temporaryVariable); } i -= 2; } } } } } return(expression); }