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); }
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); }