Esempio n. 1
0
        Pred NodeToPredCore(LNode expr, Context ctx = Context.Rule)
        {
            if (expr.IsCall)
            {
                bool slash = false, not;
                if (expr.Calls(S.Tuple))
                {
                    // sequence: (a, b, c)
                    if (expr.Calls(S.Tuple, 1))
                    {
                        return(NodeToPred(expr.Args[0], ctx));
                    }
                    return(ArgsToSeq(expr, ctx));
                }
                else if (expr.Calls(S.Braces))
                {
                    // Just code: use an empty sequence
                    var seq = new Seq(expr);
                    seq.PostAction = RemoveBraces(expr);
                    return(seq);
                }
                else if (expr.Calls(S.OrBits, 2) || (slash = expr.Calls(S.Div, 2)))
                {
                    // alternatives: a | b, a || b, a / b
                    LNode      lhs = expr.Args[0], rhs = expr.Args[1];
                    BranchMode lhsMode, rhsMode;
                    Pred       left  = BranchToPred(lhs, out lhsMode, ctx);
                    Pred       right = BranchToPred(rhs, out rhsMode, ctx);
                    return(Pred.Or(left, right, slash, expr, lhsMode, rhsMode, _sink));
                }
                else if (expr.Calls(_Star, 1) || expr.Calls(_Plus, 1) || expr.Calls(_Opt, 1))
                {
                    // loop (a+, a*) or optional (a?)
                    return(TranslateLoopExpr(expr, ctx));
                }
                else if (expr.Calls(_Gate, 1) || expr.Calls(_EqGate, 1))
                {
                    // => foo (LES-based parser artifact)
                    return(new Gate(expr, new Seq(F._Missing),
                                    NodeToPred(expr.Args[0], Context.GateRight))
                    {
                        IsEquivalency = expr.Calls(_EqGate)
                    });
                }
                else if (expr.Calls(_Gate, 2) || expr.Calls(_EqGate, 2))
                {
                    if (ctx == Context.GateLeft)
                    {
                        _sink.Write(Severity.Error, expr, "Cannot use a gate in the left-hand side of another gate");
                    }

                    return(new Gate(expr, NodeToPred(expr.Args[0], Context.GateLeft),
                                    NodeToPred(expr.Args[1], Context.GateRight))
                    {
                        IsEquivalency = expr.Calls(_EqGate)
                    });
                }
                else if ((not = expr.Calls(_AndNot, 1)) || expr.Calls(_And, 1))
                {
                    expr = expr.Args[0];
                    var   subpred = AutoNodeToPred(expr, Context.And);
                    LNode subexpr = subpred as LNode, subexpr0 = subexpr;
                    bool  local = false;
                    if (subexpr != null)
                    {
                        if ((subexpr = subexpr.WithoutAttrNamed(_Local)) != subexpr0)
                        {
                            local = true;
                        }
                        // we should default to [Local] eventually, so recognize [Hoist] too
                        subexpr = subexpr.WithoutAttrNamed(_Hoist);
                    }
                    return(new AndPred(expr, subexpr ?? subpred, not, local));
                }
                else if (expr.Calls(S.NotBits, 1))
                {
                    var subpred = NodeToPred(expr.Args[0], ctx);
                    if (subpred is TerminalPred)
                    {
                        var term = (TerminalPred)subpred;
                        term.Set = term.Set.Inverted().WithoutEOF();
                        return(term);
                    }
                    else
                    {
                        _sink.Write(Severity.Error, expr,
                                    "The set-inversion operator ~ can only be applied to a single terminal, not a '{0}'", subpred.GetType().Name);
                        return(subpred);
                    }
                }
                else if (expr.Calls(_Any, 2) && expr.Args[0].IsId)
                {
                    return(Translate_any_in_Expr(expr, ctx));
                }
                else if ((expr.Name.Name.EndsWith(":") || expr.Name.Name.EndsWith("=")) && expr.ArgCount == 2)
                {
                    return(TranslateLabeledExpr(expr, ctx));
                }
            }

            // expr is an Id, literal, or non-special call
            Rule rule = TryGetRule(expr);

            if (rule != null)
            {
                //int ruleArgc = rule.Basis.Args[2].ArgCount;
                //if (expr.ArgCount > ruleArgc) // don't complain about too few args, in case there are default args (I'm too lazy to check)
                //    _sink.Write(MessageSink.Error, expr, "Rule '{0}' takes {1} arguments ({2} given)", rule.Name, ruleArgc, expr.ArgCount);
                return(new RuleRef(expr, rule)
                {
                    Params = expr.Args
                });
            }

            string errorMsg = null;
            Pred   terminal = _helper.CodeToTerminalPred(expr, ref errorMsg);

            if (terminal == null)
            {
                errorMsg = errorMsg ?? "LLLPG: unrecognized expression";
                terminal = new TerminalPred(expr, _helper.EmptySet);
                _sink.Write(Severity.Error, expr, errorMsg);
            }
            else if (errorMsg != null)
            {
                _sink.Write(Severity.Warning, expr, errorMsg);
            }
            return(terminal);
        }
Esempio n. 2
0
        Pred NodeToPredCore(LNode expr, Context ctx = Context.Rule)
        {
            if (expr.IsCall)
            {
                bool slash = false, not;
                var  name = expr.Name;
                if (name == S.Tuple)
                {
                    // sequence: (a, b, c)
                    if (expr.Calls(S.Tuple, 1))
                    {
                        return(NodeToPred(expr.Args[0], ctx));
                    }
                    return(TranslateToSeq(expr, ctx));
                }
                else if (name == S.Braces)
                {
                    // User action {block}
                    if (ctx == Context.And || ctx == Context.GateLeft)
                    {
                        _sink.Error(expr, ctx == Context.And ?
                                    "Cannot use an action block inside an '&' or '&!' predicate; these predicates are for prediction only." :
                                    "Cannot use an action block on the left side of a '=>' gate; the left side is for prediction only.");
                    }
                    return(new ActionPred(expr, expr.Args));
                }
                else if (expr.Calls(S.OrBits, 2) || (slash = expr.Calls(S.Div, 2)))
                {
                    // alternatives: a | b, a || b, a / b
                    LNode      lhs = expr.Args[0], rhs = expr.Args[1];
                    BranchMode lhsMode, rhsMode;
                    Pred       left  = BranchToPred(lhs, out lhsMode, ctx);
                    Pred       right = BranchToPred(rhs, out rhsMode, ctx);
                    return(Pred.Or(left, right, slash, expr, lhsMode, rhsMode, _sink));
                }
                else if (expr.Calls(_Star, 1) || expr.Calls(_Plus, 1) || expr.Calls(_Opt, 1))
                {
                    // loop (a+, a*) or optional (a?)
                    return(TranslateLoopExpr(expr, ctx));
                }
                else if (expr.Calls(_Gate, 1) || expr.Calls(_EqGate, 1))
                {
                    // => foo (LES-based parser artifact)
                    return(new Gate(expr, new Seq(F.Missing),
                                    NodeToPred(expr.Args[0], Context.GateRight))
                    {
                        IsEquivalency = expr.Calls(_EqGate)
                    });
                }
                else if (expr.Calls(_Gate, 2) || expr.Calls(_EqGate, 2))
                {
                    if (ctx == Context.GateLeft)
                    {
                        _sink.Error(expr, "Cannot use a gate in the left-hand side of another gate");
                    }

                    return(new Gate(expr, NodeToPred(expr.Args[0], Context.GateLeft),
                                    NodeToPred(expr.Args[1], Context.GateRight))
                    {
                        IsEquivalency = expr.Calls(_EqGate)
                    });
                }
                else if ((not = expr.Calls(_AndNot, 1)) || expr.Calls(_And, 1))
                {
                    return(TranslateAndPred(expr, not));
                }
                else if (expr.Calls(S.NotBits, 1))
                {
                    var subpred = NodeToPred(expr.Args[0], ctx);
                    if (subpred is TerminalPred)
                    {
                        var term = (TerminalPred)subpred;
                        term.Set = term.Set.Inverted().WithoutEOF();
                        return(term);
                    }
                    else
                    {
                        _sink.Error(expr,
                                    "The set-inversion operator ~ can only be applied to a single terminal, not a '{0}'", subpred.GetType().Name);
                        return(subpred);
                    }
                }
                else if ((name.Name.EndsWith(":") || name.Name.EndsWith("=")) && expr.ArgCount == 2)
                {
                    return(TranslateLabeledExpr(expr, ctx));
                }
                else if (expr.Calls(_Any, 2) && expr.Args[0].IsId)
                {
                    return(Translate_any_in_Expr(expr, ctx));
                }
            }

            // expr is an Id, literal, or non-special call
            Rule rule = TryGetRule(expr);

            if (rule != null)
            {
                LNode _, args;
                if (EcsValidators.MethodDefinitionKind(rule.Basis, out _, out _, out args, out _, false) == S.Fn)
                {
                    if (expr.ArgCount > args.ArgCount)                     // don't complain about too few args, in case there are default args (I'm too lazy to check)
                    {
                        _sink.Error(expr, "Rule '{0}' takes {1} arguments ({2} given)", rule.Name, args.ArgCount, expr.ArgCount);
                    }
                }

                return(new RuleRef(expr, rule)
                {
                    Params = expr.Args
                });
            }

            string errorMsg = null;
            Pred   terminal = _helper.CodeToTerminalPred(expr, ref errorMsg);

            if (terminal == null)
            {
                errorMsg = errorMsg ?? "LLLPG: unrecognized expression";
                terminal = new TerminalPred(expr, _helper.EmptySet);
                _sink.Error(expr, errorMsg);
            }
            else if (errorMsg != null)
            {
                _sink.Warning(expr, errorMsg);
            }
            return(terminal);
        }