Пример #1
0
        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
            });
        }
Пример #2
0
        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);
        }
Пример #3
0
        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;
                }
            }
        }