internal static KirinFunction ParseFunction( KirinFunctionStart startNode, KirinFunctionEnd endNode, KirinStatement statement ) { if (endNode.NodeType == "KirinFunctionEnd" && endNode.Name != startNode.Name) { throw new Exception($"Method '{startNode.Name}' does not end with the same name"); } var firstNode = statement.Body.First() as KirinNode; var lastNode = statement.Body.Last() as KirinNode; statement.Start = firstNode.Start; statement.Length = (lastNode.Start + lastNode.Length) - firstNode.Start; return(new KirinFunction(startNode, endNode) { Statement = statement }); }
internal static KirinStatement ParseStatement(KirinNode[] nodes, string content) { var statement = new KirinStatement(-1, -1); for (int i = 0; i < nodes.Length; i++) { var node = nodes[i]; switch (node.NodeType) { case "KirinProgramStart": case "KirinProgramEnd": case "KirinFunctionStart": case "KirinFunctionEnd": case "KirinElseIfStatement": case "KirinIfStatementEnd": case "KirinSwitchCase": case "KirinSwitchCaseDefault": case "KirinLoopEnd": { var line = FiMHelper.GetIndexPair(content, node.Start).Line; throw new Exception($"Illegal statement node at line {line}"); } case "KirinIfStatementStart": { var startingNode = node as KirinIfStatementStart; var statementNodes = KirinLoop.GetStatementNodes( startingNode, nodes, i, content, out i ); var endingNode = nodes[i] as KirinIfStatementEnd; statement.PushNode( KirinIfStatement.ParseNodes(startingNode, statementNodes, endingNode, content) ); } break; case "KirinForInLoop": { var startingNode = node as KirinForInLoop; var statementNodes = KirinLoop.GetStatementNodes( startingNode, nodes, i, content, out i ); var endingNode = nodes[i] as KirinLoopEnd; statement.PushNode( KirinForInLoop.ParseNodes(startingNode, statementNodes, endingNode, content) ); } break; case "KirinForToLoop": { var startingNode = node as KirinForToLoop; var statementNodes = KirinLoop.GetStatementNodes( startingNode, nodes, i, content, out i ); var endingNode = nodes[i] as KirinLoopEnd; statement.PushNode( KirinForToLoop.ParseNodes(startingNode, statementNodes, endingNode, content) ); } break; case "KirinWhileLoop": { var startingNode = node as KirinWhileLoop; var statementNodes = KirinLoop.GetStatementNodes( startingNode, nodes, i, content, out i ); var endingNode = nodes[i] as KirinLoopEnd; statement.PushNode( KirinWhileLoop.ParseNodes(startingNode, statementNodes, endingNode, content) ); } break; case "KirinSwitchStart": { var startingNode = node as KirinSwitchStart; var statementNodes = KirinLoop.GetStatementNodes( startingNode, nodes, i, content, out i ); var endingNode = nodes[i] as KirinLoopEnd; statement.PushNode( KirinSwitch.ParseNodes(startingNode, statementNodes, endingNode, content) ); } break; case "KirinPostScript": { // Ignore } break; default: { statement.PushNode(node); } break; } } var firstNode = statement.Body.First() as KirinNode; var lastNode = statement.Body.Last() as KirinNode; statement.Start = firstNode.Start; statement.Length = (lastNode.Start + lastNode.Length) - firstNode.Start; return(statement); }
private static void TranspileStatements( StringBuilder sb, JavascriptContainer container, KirinStatement statement, string indent, int depth = 1 ) { string _i = string.Concat(Enumerable.Repeat(indent, depth)); string __i = string.Concat(Enumerable.Repeat(indent, depth + 1)); string ___i = string.Concat(Enumerable.Repeat(indent, depth + 2)); foreach (var node in statement.Body) { switch (node.NodeType) { case "KirinPrint": { var n = (KirinPrint)node; sb.AppendLine($"{_i}{ (n.NewLine ? container.outputNewline : container.output) }({ SanitizeValue(n.RawParameters, container) });"); } break; case "KirinFunctionCall": { var n = (KirinFunctionCall)node; string args = ""; if (n.RawParameters != string.Empty) { args = string.Join(", ", n.RawParameters .Split(new string[] { " and " }, StringSplitOptions.None) .Select(v => SanitizeValue(v, container)) ); } sb.AppendLine($"{_i}this.{ SanitizeName(n.FunctionName, container) }({ args });"); } break; case "KirinVariableDeclaration": { var n = (KirinVariableDeclaration)node; string val = SanitizeValue(n.RawValue, container, n.ExpectedType); string modif = n.Constant ? "const" : "let"; sb.AppendLine($"{_i}{modif} { SanitizeName(n.Name, container) } = { val };"); } break; case "KirinListModify": { var n = (KirinListModify)node; string index = SanitizeValue(n.RawIndex, container); string value = SanitizeValue(n.RightOp, container); sb.AppendLine($"{_i}{ SanitizeName(n.LeftOp, container) }[{ index }] = { value };"); } break; case "KirinUnary": { var n = (KirinUnary)node; string value = SanitizeValue(n.RawVariable, container); if (n.Increment) { sb.AppendLine($"{_i}{ value } = ({ value } || 0) + 1.0"); } else { sb.AppendLine($"{_i}{ value } = ({ value } || 0) - 1.0"); } } break; case "KirinInput": { var n = (KirinInput)node; string name = SanitizeName(n.RawVariable, container); string prompt = $"{ n.RawVariable } is asking for an input: "; if (n.PromptString != string.Empty) { prompt = n.PromptString; } sb.AppendLine($"{_i}{name} = { container.input }(\"{ prompt }\");"); } break; case "KirinIfStatement": { var n = (KirinIfStatement)node; for (int i = 0; i < n.Conditions.Count; i++) { var c = n.Conditions[i]; string ifType = i == 0 ? "if" : "else if"; if (i + 1 == n.Conditions.Count && c.Condition.Left == "correct" && c.Condition.Expression == "==" && c.Condition.Right == "correct") { ifType = "else"; } string check = ParseConditionalNodes(c.Condition, container); if (ifType != "else") { ifType += $" ({ check })"; } sb.AppendLine($"{_i}{ifType} {{"); TranspileStatements(sb, container, c.Statement, indent, depth + 1); sb.AppendLine($"{_i}}}"); } } break; case "KirinForToLoop": { var n = (KirinForToLoop)node; string name = SanitizeName(n.VariableName, container); string min = SanitizeValue(n.RawFrom, container); string max = SanitizeValue(n.RawTo, container); string interval = SanitizeValue(n.RawInterval, container); // HACK: uh. if (interval == string.Empty) { interval = $"({min} <= {max} ? 1 : -1)"; } string check = $"({interval} > 0 ? {name} <= {max} : {name} >= {max})"; sb.AppendLine($"{_i}for (let { name } = {min}; {check}; { name } += { interval }) {{"); TranspileStatements(sb, container, n.Statement, indent, depth + 1); sb.AppendLine($"{_i}}}"); } break; case "KirinForInLoop": { var n = (KirinForInLoop)node; string name = SanitizeName(n.VariableName, container); string value = SanitizeValue(n.RawValue, container); sb.AppendLine($"{_i}for (let {name} of fim_forin({value})) {{"); TranspileStatements(sb, container, n.Statement, indent, depth + 1); sb.AppendLine($"{_i}}}"); } break; case "KirinWhileLoop": { var n = (KirinWhileLoop)node; sb.AppendLine($"{_i}while ({ ParseConditionalNodes(n.Condition, container) }) {{"); TranspileStatements(sb, container, n.Statement, indent, depth + 1); sb.AppendLine($"{_i}}}"); } break; case "KirinSwitch": { var n = (KirinSwitch)node; sb.AppendLine($"{_i}switch ({ SanitizeName(n.RawVariable, container) }) {{"); if (n.Cases.Count > 0) { foreach (var c in n.Cases) { string condition = SanitizeName(c.Key, container); if (KirinSwitchCase.IsValidNumberPlace(condition, out var index)) { condition = index.ToString(); } sb.AppendLine($"{__i}case ({ condition }): {{"); TranspileStatements(sb, container, c.Value, indent, depth + 2); sb.AppendLine($"{__i}}}"); sb.AppendLine($"{__i}break;"); } } if (n.DefaultCase != null) { sb.AppendLine($"{__i}default: {{"); TranspileStatements(sb, container, n.DefaultCase, indent, depth + 2); sb.AppendLine($"{__i}}}"); sb.AppendLine($"{__i}break;"); } sb.AppendLine($"{_i}}}"); } break; case "KirinVariableModify": { var n = (KirinVariableModify)node; sb.AppendLine($"{_i}{SanitizeName(n.LeftOp, container)} = {SanitizeValue(n.RightOp, container)};"); } break; case "KirinReturn": { var n = (KirinReturn)node; sb.AppendLine($"{_i}return { SanitizeValue(n.RawParameters, container) };"); } break; default: { sb.AppendLine($"{_i}{node.NodeType}"); } break; } } }