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?)
                    Symbol type   = expr.Name;
                    bool?  greedy = null;
                    bool   g;
                    expr = expr.Args[0];
                    if ((g = expr.Calls(_Greedy, 1)) || expr.Calls(_Nongreedy, 1))
                    {
                        greedy = g;
                        expr   = expr.Args[0];
                    }
                    BranchMode branchMode;
                    Pred       subpred = BranchToPred(expr, out branchMode, ctx);

                    if (branchMode != BranchMode.None)
                    {
                        _sink.Write(Severity.Warning, expr, "'default' and 'error' only apply when there are multiple arms (a|b, a/b)");
                    }

                    if (type == _Star)
                    {
                        return(new Alts(expr, LoopMode.Star, subpred, greedy));
                    }
                    else if (type == _Plus)
                    {
                        return(new Seq(subpred, new Alts(expr, LoopMode.Star, subpred.Clone(), greedy), expr));
                    }
                    else                       // type == _Opt
                    {
                        return(new Alts(expr, LoopMode.Opt, subpred, greedy));
                    }
                }
                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;
                    bool  local   = false;
                    if (subexpr != null && (subpred = subexpr.WithoutAttrNamed(_Local)) != subexpr)
                    {
                        local = true;
                    }
                    return(new AndPred(expr, 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.Name.Name.EndsWith("=") && expr.ArgCount == 2)
                {
                    var lhs  = expr.Args[0];
                    var pred = NodeToPred(expr.Args[1], ctx);
                    if (expr.Calls(S.AddSet))
                    {
                        pred.ResultSaver = result => F.Call(F.Dot(lhs, _Add), result);
                    }
                    else if (expr.Calls(S.QuickBindSet))
                    {
                        pred.ResultSaver = result => F.Call(S.Var, F._Missing, F.Call(S.Assign, lhs, result));
                    }
                    else
                    {
                        pred.ResultSaver = result => F.Call(expr.Target, lhs, result);
                    }
                    return(pred);
                }
            }

            // expr is an Id, literal, or non-special call
            Rule rule;

            if (!expr.IsLiteral && _rules.TryGetValue(expr.Name, out rule))
            {
                //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.CodeToPred(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;
                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.CodeToPred(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);
        }