Esempio n. 1
0
 private void AddArg(Stack <OpEntry> stack, ActionQueryRunner <ResolverValue> .Constructor constr)
 {
     if (stack.Count > 0)
     {
         var entry = stack.Peek();
         entry.Arguments++;
     }
 }
Esempio n. 2
0
        public ActionQueryRunner <ResolverValue> Compile(string query)
        {
            Stack <OpEntry> opstack = new Stack <OpEntry>();

            ActionQueryRunner <ResolverValue> .Constructor runner = new ActionQueryRunner <ResolverValue> .Constructor();

            OpEntry undecided = OpEntry.Empty;
            OpEntry entry;
            int     pos   = 0; // used and updated only for additional error checking. The algorithm does not depend on this.
            int     level = 0;


            Match match = _regex.Match(query);

            while (match.Success)
            {
                if (pos != match.Index)
                {
                    return(runner.Complete(ReportError("Syntax error at {0} - unrecognized text", match.Index, query)));
                }
                pos = match.Index + match.Length;
                if (match.Groups[0].Success)
                {
                    for (int i = 1; i < match.Groups.Count; i++)
                    {
                        if (match.Groups[i].Success)
                        {
                            string curval = match.Groups[i].Value;
                            switch ((Terms)i)
                            {
                            case Terms.keyword:
                                if (!undecided.IsEmpty)
                                {
                                    return(runner.Complete(ReportError("Syntax error at {0}.", match, query)));
                                }
                                undecided = new OpEntry(curval, Terms.keyword, match.Index);
                                goto nextTerm;

                            case Terms.varidentifier:
                                if (!undecided.IsEmpty)
                                {
                                    return(runner.Complete(ReportError("Syntax error at {0}.", match, query)));
                                }
                                undecided = new OpEntry(curval, Terms.varidentifier, match.Index);
                                goto nextTerm;

                            case Terms.identifier:
                                if (!undecided.IsEmpty)
                                {
                                    return(runner.Complete(ReportError("Syntax error at {0}.", match, query)));
                                }
                                undecided = new OpEntry(curval, Terms.identifier, match.Index);
                                goto nextTerm;

                            case Terms.openbracket:
                                if (undecided.Term == Terms.varidentifier)
                                {
                                    opstack.Push(undecided);     // Var set
                                    undecided = OpEntry.Empty;
                                }
                                else if (undecided.Term == Terms.identifier)
                                {
                                    opstack.Push(undecided);     // Function call
                                    undecided = OpEntry.Empty;
                                }
                                else if (undecided.Term == Terms.keyword)
                                {
                                    undecided.Op0Address = runner.Address;
                                    opstack.Push(undecided);
                                    undecided = OpEntry.Empty;
                                }
                                else if (undecided.IsEmpty)
                                {
                                    opstack.Push(new OpEntry(null, Terms.compound, match.Index));
                                }
                                level++;
                                goto nextTerm;

                            case Terms.closebracket:
                                if (undecided.Term == Terms.varidentifier)
                                {
                                    AddArg(opstack, runner);
                                    runner.Add(new Instruction(Instructions.PushVar, undecided.Value));    // GetVar varidentifier
                                    undecided = OpEntry.Empty;
                                }
                                else if (undecided.Term == Terms.identifier)
                                {
                                    AddArg(opstack, runner);
                                    runner.Add(new Instruction(Instructions.PushParam, undecided.Value));
                                    undecided = OpEntry.Empty;
                                }
                                // *** Function call
                                if (opstack.Count == 0)
                                {
                                    return(runner.Complete(ReportError("Syntax error - function call has no function name at {0}", match, query)));
                                }
                                entry = opstack.Pop();
                                if (entry.Term == Terms.varidentifier)
                                {
                                    AddArg(opstack, runner);
                                    // TODO - what about empty argument list? (BUG)
                                    runner.Add(new Instruction(Instructions.PullVar, entry.Value, entry.Arguments));
                                }
                                else if (entry.Term == Terms.identifier)
                                {
                                    AddArg(opstack, runner);
                                    // TODO - what about empty argument list? (BUG)
                                    runner.Add(new Instruction(Instructions.Call, entry.Value, entry.Arguments));
                                }
                                else if (entry.Term == Terms.keyword)
                                {
                                    AddArg(opstack, runner);
                                    // TODO: Operator completion
                                    if (entry.Value == "if")
                                    {
                                        if (entry.Arguments == 2)
                                        {
                                            runner.Add(new Instruction(Instructions.Jump, runner.Address + 2));

                                            // Update initial jumpIfNot
                                            runner.Update(entry.Op1Address, runner.Address);
                                            // Add dummy else
                                            runner.Add(new Instruction(Instructions.PushNull));
                                        }
                                        else if (entry.Arguments == 3)
                                        {
                                            // Update else unconditional jump
                                            runner.Update(entry.Op2Address, runner.Address);
                                        }
                                        else
                                        {
                                            return(runner.Complete(ReportError("if must have 2 or 3 arguments at {0}", match, query)));
                                        }
                                    }
                                    else if (entry.Value == "while")
                                    {
                                        if (entry.Arguments == 2)
                                        {
                                            runner.Add(new Instruction(Instructions.Dump, null, 1));
                                            runner.Add(new Instruction(Instructions.Jump, entry.Op0Address)); // Jump to the initial condition
                                            runner.Update(entry.Op1Address, runner.Address);                  // Update initial JumpIfNot to go after the end
                                            runner.Add(new Instruction(Instructions.PushNull));               // Push something to keep the illusion that something is returned.
                                        }
                                        else
                                        {
                                            return(runner.Complete(ReportError("while must have 2 arguments at {0}", match, query)));
                                        }
                                    }
                                    else
                                    {
                                        return(runner.Complete(ReportError("Unexpected end of control operator at {0}", match, query)));
                                    }
                                }
                                else if (entry.Term == Terms.compound)
                                {
                                    AddArg(opstack, runner);
                                }
                                else
                                {
                                    return(runner.Complete(ReportError("Syntax error - function call has no function name at {0}", match, query)));
                                }
                                level--;
                                goto nextTerm;

                            case Terms.comma:
                                if (undecided.Term == Terms.varidentifier)
                                {
                                    AddArg(opstack, runner);
                                    runner.Add(new Instruction(Instructions.PushVar, undecided.Value));
                                    undecided = OpEntry.Empty;
                                }
                                else if (undecided.Term == Terms.identifier)
                                {
                                    AddArg(opstack, runner);
                                    runner.Add(new Instruction(Instructions.PushParam, undecided.Value));
                                    undecided = OpEntry.Empty;
                                }
                                else if (!undecided.IsEmpty)         // If this happend it will be our mistake. Nothing but identifiers should appear in the undecided
                                {
                                    return(runner.Complete(ReportError("Syntax error at {0}", undecided.Pos, query)));
                                }
                                // TODO: Consider root level behavior! Multiple results may be useful?
                                if (opstack.Count == 0 || opstack.Peek().Term == Terms.compound)
                                {
                                    // A coma in compond operator or on root level - only the last one must remain in the stack
                                    // For this reason we dump the last entry.
                                    runner.Add(new Instruction(Instructions.Dump, null, 1));
                                }
                                else if (opstack.Peek().Term == Terms.keyword)
                                {
                                    // TODO: operator midtime
                                    entry = opstack.Peek();
                                    if (entry.Arguments == 1)
                                    {
                                        // We are at addr(1)
                                        entry.Op1Address = runner.Address;
                                        runner.Add(new Instruction(Instructions.JumpIfNot, -1, 1));
                                    }
                                    else if (entry.Arguments == 2)
                                    {
                                        if (entry.Op1Address >= 0)
                                        {
                                            if (entry.Value == "if")
                                            {
                                                // Finish successful part
                                                entry.Op2Address = runner.Address;
                                                runner.Add(new Instruction(Instructions.Jump, -1));
                                                // Jump here if condition is not met
                                                runner.Update(entry.Op1Address, runner.Address);
                                                //AddArg(opstack, runner);
                                            }
                                            else if (entry.Value == "while")
                                            {
                                                return(runner.Complete(ReportError("while has more than two arguments at {0}", match, query)));
                                            }
                                            else
                                            {
                                                // This is completely unexpected
                                                return(runner.Complete(ReportError("syntax error at {0}", match, query)));
                                            }
                                        }
                                        else
                                        {
                                            return(runner.Complete(ReportError("while or if operator cannot be composed correctly {0}", undecided.Pos, query)));
                                        }
                                    }
                                }
                                goto nextTerm;

                            case Terms.numliteral:
                                if (!undecided.IsEmpty)
                                {
                                    return(runner.Complete(ReportError("Syntax error at {0}", undecided.Pos, query)));
                                }
                                if (curval.IndexOf('.') >= 0)       // double
                                {
                                    if (double.TryParse(curval, NumberStyles.Any, CultureInfo.InvariantCulture, out double t))
                                    {
                                        runner.Add(new Instruction(Instructions.PushDouble, t));
                                        AddArg(opstack, runner);
                                    }
                                    else
                                    {
                                        return(runner.Complete(ReportError("Invalid double number at {0}", match, query)));
                                    }
                                }
                                else
                                {
                                    if (int.TryParse(curval, NumberStyles.Any, CultureInfo.InvariantCulture, out int n))
                                    {
                                        runner.Add(new Instruction(Instructions.PushInt, n));
                                        AddArg(opstack, runner);
                                    }
                                    else
                                    {
                                        return(runner.Complete(ReportError("Invalid integer number at {0}", match, query)));
                                    }
                                }
                                goto nextTerm;

                            case Terms.specialliteral:
                                if (!undecided.IsEmpty)
                                {
                                    return(runner.Complete(ReportError("Syntax error at {0}", undecided.Pos, query)));
                                }
                                if (curval == "null")
                                {
                                    runner.Add(new Instruction(Instructions.PushNull));
                                }
                                else if (curval == "true")
                                {
                                    runner.Add(new Instruction(Instructions.PushBool, true));
                                }
                                else if (curval == "false")
                                {
                                    runner.Add(new Instruction(Instructions.PushBool, false));
                                }
                                else
                                {
                                    return(runner.Complete(ReportError("Syntax error at {0}", match, query)));
                                }
                                AddArg(opstack, runner);
                                goto nextTerm;

                            case Terms.stringliteral:
                                if (!undecided.IsEmpty)
                                {
                                    return(runner.Complete(ReportError("Syntax error at {0}", undecided.Pos, query)));
                                }
                                runner.Add(new Instruction(Instructions.PushString, curval));
                                AddArg(opstack, runner);
                                goto nextTerm;

                            case Terms.space:
                            case Terms.comment:
                                // do nothing - we simply ignore the space
                                goto nextTerm;

                            case Terms.end:
                                if (undecided.Term == Terms.varidentifier)
                                {
                                    AddArg(opstack, runner);
                                    runner.Add(new Instruction(Instructions.PushVar, undecided.Value));
                                    undecided = OpEntry.Empty;
                                }
                                else if (undecided.Term == Terms.identifier)
                                {
                                    AddArg(opstack, runner);
                                    runner.Add(new Instruction(Instructions.PushParam, undecided.Value));
                                    undecided = OpEntry.Empty;
                                }
                                if (opstack.Count == 0)
                                {
                                    // The stack must be empty at this point
                                    return(runner.Complete());
                                }
                                else
                                {
                                    return(runner.Complete("Syntax error at the expression end - check for matching brackets"));
                                }

                            // break;
                            default:
                                return(runner.Complete(ReportError("Syntax error at {0}", match, query)));
                            }
                        } // catch actual group
                    }     // Check every possible group
                }
                else
                {
                    // Unrecognized or end
                }
nextTerm:
                match = match.NextMatch();
            } // next term
            var _serr = "";

            if (pos > query.Length)
            {
                _serr = " Unparsed:[" + query.Substring(pos) + "]";
            }
            return(runner.Complete("Parsing the query failed at pos:" + pos + _serr));
        }