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