public void GenerateAssignment(string assignType, LexerToken[] assignTokens, int start, int end) { string delimeter = assignType == "set" ? "to" : "into"; int t = start; for (; t <= end; t++) { LexerToken token = assignTokens[t]; if (token.type == delimeter) { bool switchSides = assignType != "set"; int leftStart = !switchSides ? start : t + 1; int leftEnd = !switchSides ? t - 1 : end; int rightStart = !switchSides ? t + 1: start; int rightEnd = !switchSides ? end : t - 1; GenerateExpression(assignTokens, leftStart, leftEnd); Code.Buffer.Append(" = "); GenerateExpression(assignTokens, rightStart, rightEnd); return; } } throw new StoryFormatTranscodeException(string.Format("The '{0}' assignment was not written correctly.", assignType)); }
public void GenerateExpression(LexerToken[] tokens, int start = 0, int end = -1, bool asString = false) { // Skip whitespace at beginning of expression while (start < tokens.Length && tokens[start].type == "whitespace") { start++; } for (int t = start; t < (end > 0 ? end + 1 : tokens.Length); t++) { LexerToken token = tokens[t]; string expr = BuildExpressionSegment(tokens, ref t, asString); if (expr == null) { continue; } // This is used when texts need to be evaluated as strings if (asString && t > start) { Code.Buffer.Append(" + "); } Code.Buffer.Append(expr); } }
public void GenerateExpression(LexerToken[] tokens, int start = 0, int end = -1) { // Skip whitespace at beginning of expression while (start < tokens.Length && tokens[start].type == "whitespace") { start++; } for (int t = start; t < (end > 0 ? end + 1 : tokens.Length); t++) { LexerToken token = tokens[t]; string expr = BuildExpressionSegment(tokens, ref t); if (expr != null) { Code.Buffer.Append(expr); } } }
string BuildInverseAssignment(LexerToken[] tokens, ref int tokenIndex, bool moveAssignment) { string statement = string.Format(".{0}(vref(Vars, \"", moveAssignment ? "MoveInto" : "PutInto"); tokenIndex++; for (; tokenIndex < tokens.Length; tokenIndex++) { LexerToken token = tokens[tokenIndex]; if (token.type == "whitespace") { continue; } if (token.type != "variable") { break; } statement += token.name + "\"))"; return(statement); } throw new StoryFormatTranscodeException(string.Format("{0} macro was not formatted correctly", moveAssignment ? "Move" : "Put")); }
public int GenerateMacro(LexerToken[] tokens, int macroTokenIndex, MacroUsage usage) { LexerToken macroToken = tokens[macroTokenIndex]; HarloweCodeGenMacro macro; if (!CodeGenMacros.TryGetValue(macroToken.name, out macro)) { macro = BuiltInCodeGenMacros.RuntimeMacro; } if (macro != null) { if (usage != MacroUsage.Inline) { Code.Indent(); } return(macro(this, tokens, macroTokenIndex, usage)); } else { return(macroTokenIndex); } }
string BuildExpressionSegment(LexerToken[] tokens, ref int tokenIndex) { LexerToken token = tokens[tokenIndex]; switch (token.type) { case "variable": return(BuildVariableRef(token)); case "identifier": if (token.text == "time") { return("this.PassageTime"); } if (_lastVariable == null) { throw new StoryFormatTranscodeException("'it' or 'its' used without first mentioning a variable"); } return(_lastVariable); case "macro": GenerateMacro(tokens, tokenIndex, MacroUsage.Inline); return(null); case "hookRef": return(string.Format("hookRef(\"{0}\")", token.name)); case "string": return(WrapInVarIfNecessary(string.Format("\"{0}\"", token.innerText), tokens, tokenIndex)); case "number": return(WrapInVarIfNecessary(token.text, tokens, tokenIndex)); case "cssTime": return(WrapInVarIfNecessary(string.Format("{0}/1000f", token.value), tokens, tokenIndex)); case "colour": return(WrapInVarIfNecessary(string.Format("\"{0}\"", token.text), tokens, tokenIndex)); case "text": return(token.text == "null" ? "StoryVar.Empty" : token.text); case "grouping": if (IsWrapInVarRequired(tokens, tokenIndex)) { Code.Buffer.Append(" v"); } Code.Buffer.Append("("); GenerateExpression(token.tokens); Code.Buffer.Append(")"); return(null); case "itsProperty": if (_lastVariable == null) { throw new StoryFormatTranscodeException("'it' or 'its' used without first mentioning a variable"); } return(string.Format("{0}[\"{1}\"]", _lastVariable, token.name)); case "property": string prop = string.Format("[\"{0}\"]", token.name); if (_lastVariable != null) { _lastVariable += prop; } return(prop); case "belongingProperty": Code.Buffer.AppendFormat("v(\"{0}\").AsMemberOf[", token.name); AdvanceToNextNonWhitespaceToken(tokens, ref tokenIndex); GenerateExpressionSegment(tokens, ref tokenIndex); Code.Buffer.Append("]"); return(null); case "contains": //FollowedBy("grouping", tokens, tokenIndex, true, true); //return ".Contains"; Code.Buffer.Append(".Contains("); AdvanceToNextNonWhitespaceToken(tokens, ref tokenIndex); GenerateExpressionSegment(tokens, ref tokenIndex); Code.Buffer.Append(")"); return(null); case "isIn": //FollowedBy("grouping", tokens, tokenIndex, true, true); //return ".ContainedBy"; Code.Buffer.Append(".ContainedBy("); AdvanceToNextNonWhitespaceToken(tokens, ref tokenIndex); GenerateExpressionSegment(tokens, ref tokenIndex); Code.Buffer.Append(")"); return(null); case "possessiveOperator": Code.Buffer.Append("["); AdvanceToNextNonWhitespaceToken(tokens, ref tokenIndex); GenerateExpressionSegment(tokens, ref tokenIndex); Code.Buffer.Append("]"); return(null); case "belongingOperator": Code.Buffer.Append(".AsMemberOf["); AdvanceToNextNonWhitespaceToken(tokens, ref tokenIndex); GenerateExpressionSegment(tokens, ref tokenIndex); Code.Buffer.Append("]"); return(null); case "and": return("&&"); case "or": return("||"); case "is": return("=="); case "isNot": return("!="); case "not": return("!"); case "spread": return("(HarloweSpread)"); case "to": case "into": throw new StoryFormatTranscodeException(string.Format("'{0}' is an assignment keyword and cannot be used inside an expression.", token.type)); default: return(token.text); } }
string BuildVariableRef(LexerToken token) { Importer.RegisterVar(token.name); _lastVariable = string.Format("Vars.{0}", EscapeReservedWord(token.name)); return(_lastVariable); }
public void GenerateBody(LexerToken[] tokens, bool breaks = true) { if (tokens != null) { for (int t = 0; t < tokens.Length; t++) { LexerToken token = tokens[t]; switch (token.type) { case "text": Code.Indent(); GenerateText(token.text, true); break; case "verbatim": Code.Indent(); GenerateText(token.innerText, true); break; case "bulleted": case "numbered": case "heading": Code.Indent(); GenerateStyleScope(string.Format("\"{0}\", {1}", token.type, token.depth), token.tokens); break; case "italic": case "bold": case "em": case "del": case "strong": case "sup": Code.Indent(); GenerateStyleScope(string.Format("\"{0}\", true", token.type), token.tokens); break; case "collapsed": bool wasCollapsed = Code.Collapsed; Code.Collapsed = true; GenerateBody(token.tokens, false); Code.Collapsed = wasCollapsed; break; case "br": if (!Code.Collapsed) { Code.Indent(); GenerateLineBreak(); } break; case "whitespace": if (!Code.Collapsed) { Code.Indent(); GenerateText(token.text, true); } break; case "variable": Code.Indent(); int hookIndex = FollowedBy("hook", tokens, t, true, false); if (hookIndex >= 0) { GenerateStyleScope(BuildVariableRef(token), tokens[hookIndex].tokens, true); t = hookIndex; } else { GenerateText(BuildVariableRef(token), false); } break; case "macro": { // Can't reference variables from other macros _lastVariable = null; // If macro is followed by a hook, tell the macro t = GenerateMacro(tokens, t, FollowedBy("hook", tokens, t, true, false) >= 0 ? MacroUsage.LineAndHook : MacroUsage.Line ); break; } case "hook": // This is only for unhandled hooks GenerateStyleScope(string.Format("\"hook\", \"{0}\"", token.name), tokens[t].tokens); break; default: break; } } } if (breaks) { Code.Indent(); Code.Buffer.Append("yield break;"); } }