Exemple #1
0
 public TerminalPred Merge(TerminalPred r, bool ignoreActions = false)
 {
     if (!ignoreActions && (PreAction != r.PreAction || PostAction != r.PostAction))
     {
         throw new InvalidOperationException("Internal error: cannot merge TerminalPreds that have actions");
     }
     return(new TerminalPred(Basis, Set.Union(r.Set), true)
     {
         PreAction = PreAction, PostAction = PostAction
     });
 }
Exemple #2
0
        public static Pred Or(Pred a, Pred b, bool slashJoined, LNode basis, BranchMode aMode = BranchMode.None, BranchMode bMode = BranchMode.None, IMessageSink sink = null)
        {
            TerminalPred a_ = a as TerminalPred, b_ = b as TerminalPred;

            if (a_ != null && b_ != null && aMode == BranchMode.None && bMode == BranchMode.None)
            {
                return(new TerminalPred(a_.Basis, a_.Set.Union(b_.Set), true));
            }
            else
            {
                return(Alts.Merge(basis, a, b, slashJoined, aMode, bMode, sink));
            }
        }
Exemple #3
0
 public override void Visit(TerminalPred term)
 {
     if (_recognizerMode)
     {
         _target.Add(CGH.GenerateMatch(term.Set, false, _recognizerMode));
     }
     else if (term.Set.ContainsEverything || (term.Prematched ?? false))
     {
         _target.Add(term.AutoSaveResult(CGH.GenerateSkip(term.ResultSaver != null)));
     }
     else
     {
         _target.Add(term.AutoSaveResult(CGH.GenerateMatch(term.Set, term.ResultSaver != null, false)));
     }
 }
Exemple #4
0
            public override void Visit(TerminalPred term)
            {
                LNode matchExpr;
                bool  savingResult = term.ResultSaver != null && !_recognizerMode;

                if (term.Set.ContainsEverything || (term.Prematched ?? false))
                {
                    matchExpr = CGH.GenerateSkip(savingResult);
                }
                else
                {
                    matchExpr = CGH.GenerateMatch(term.Set, savingResult, _recognizerMode);
                }

                _target.Add(_recognizerMode ? matchExpr : term.AutoSaveResult(matchExpr));
            }
Exemple #5
0
 public override void Visit(TerminalPred term)
 {
     if (_index < _path.Count)
     {
         if (term.Prematched != false)
         {
             IPGTerminalSet predicted = _path[_index].Terminals;
             bool           pm        = predicted.IsSubsetOf(term.Set);
             if (pm || !_reachedInnerAlts)
             {
                 term.Prematched = pm;
             }
         }
         _index++;
     }
     else if (!_reachedInnerAlts)
     {
         term.Prematched = false;
     }
 }
Exemple #6
0
 public virtual void Visit(TerminalPred term)
 {
     VisitOther(term);
 }
Exemple #7
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);
        }
Exemple #8
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);
        }
Exemple #9
0
 // For combining with | operator; cannot merge if PreAction/PostAction differs between arms
 public virtual bool CanMerge(TerminalPred r)
 {
     return(r.PreAction == PreAction && r.PostAction == PostAction);
 }
Exemple #10
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);
        }