예제 #1
0
        private static void DSOCM_DistributeAttributes(LNodeList attrs, ref LNode newArg, ref LNode propOrFieldDecl)
        {
            // Some word attributes like `public` and `static` move to the field
            // or property, as well as named parameters representing an attribute
            // target `field:` or `property:`; all others belong on the argument.
            // Example: given `[A] [field: B] public params T _arg = value`, we want
            // a field `[B] public T arg` and a parameter `[A] params T arg = value`.
            LNodeList argAttrs = LNodeList.Empty, fieldAttrs = LNodeList.Empty;

            foreach (var attr in attrs)
            {
                var name = attr.Name;
                if (attr.IsId && (FieldCreationAttributes.Contains(name) || name == S.Readonly))
                {
                    fieldAttrs.Add(attr);
                }
                else if (name == S.TriviaSLComment || name == S.TriviaNewline)
                {
                    fieldAttrs.Add(attr);                     // Put doc comments and leading newline on the field/prop
                }
                else if (attr.Calls(S.NamedArg, 2) && (attr.Args[0].IsIdNamed("field") || attr.Args[0].IsIdNamed("property")))
                {
                    fieldAttrs.Add(attr.Args[1]);
                }
                else
                {
                    argAttrs.Add(attr);
                }
            }
            propOrFieldDecl = propOrFieldDecl.WithAttrs(fieldAttrs);
            newArg          = newArg.WithAttrs(argAttrs);
        }
예제 #2
0
            // Generates a class declaration for the current alt and its subtypes
            internal void GenerateOutput(ref LNodeList list)
            {
                bool isAbstract = _classAttrs.Any(a => a.IsIdNamed(S.Abstract));

                var baseParts = new List <AdtParam>();

                for (var type = ParentType; type != null; type = type.ParentType)
                {
                    baseParts.InsertRange(0, type.Parts);
                }
                var allParts = baseParts.Concat(Parts);

                var initialization = Parts.Select(p => LNode.Call(CodeSymbols.Assign, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id(CodeSymbols.This), p.NameId)).SetStyle(NodeStyle.Operator), p.NameId)).SetStyle(NodeStyle.Operator)).ToList();

                if (baseParts.Count > 0)
                {
                    initialization.Insert(0, F.Call(S.Base, baseParts.Select(p => p.NameId)));
                }

                var args = new LNodeList(allParts.Select(p => p.OriginalDecl));

                if (!_constructorAttrs.Any(a => a.IsIdNamed(S.Public)))
                {
                    _constructorAttrs.Add(F.Id(S.Public));
                }
                LNode constructor = LNode.Call(LNode.List(_constructorAttrs), CodeSymbols.Constructor, LNode.List(LNode.Missing, _typeNameStem, LNode.Call(CodeSymbols.AltList, LNode.List(args)), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(initialization).AddRange(_extraConstrLogic)).SetStyle(NodeStyle.StatementBlock)));

                var outBody = new LNodeList();

                outBody.Add(constructor);
                outBody.AddRange(Parts.Select(p => p.GetFieldDecl()));
                outBody.AddRange(baseParts.Select(p => GetWithFn(p, isAbstract, S.Override, allParts)));
                outBody.AddRange(Parts.Select(p => GetWithFn(p, isAbstract, _children.Count > 0 ? S.Virtual : null, allParts)));
                outBody.AddRange(Parts.WithIndexes()
                                 .Where(kvp => kvp.Value.NameId.Name.Name != "Item" + (baseParts.Count + kvp.Key + 1))
                                 .Select(kvp => kvp.Value.GetItemDecl(baseParts.Count + kvp.Key + 1)));
                outBody.AddRange(_classBody);

                list.Add(LNode.Call(LNode.List(_classAttrs), CodeSymbols.Class, LNode.List(TypeName, LNode.Call(CodeSymbols.AltList, LNode.List(BaseTypes)), LNode.Call(CodeSymbols.Braces, LNode.List(outBody)).SetStyle(NodeStyle.StatementBlock))));
                if (_genericArgs.Count > 0 && Parts.Count > 0)
                {
                    var argNames = allParts.Select(p => p.NameId);
                    list.Add(LNode.Call(LNode.List().AddRange(_classAttrs).Add(LNode.Id(CodeSymbols.Static)).Add(LNode.Id(CodeSymbols.Partial)), CodeSymbols.Class, LNode.List(_typeNameStem, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(LNode.List(LNode.Id(CodeSymbols.Public), LNode.Id(CodeSymbols.Static)), CodeSymbols.Fn, LNode.List(TypeNameWithoutAttrs, LNode.Call(CodeSymbols.Of, LNode.List().Add(LNode.Id((Symbol)"New")).AddRange(_genericArgs)).SetStyle(NodeStyle.Operator), LNode.Call(CodeSymbols.AltList, LNode.List(args)), LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(LNode.Call(CodeSymbols.New, LNode.List(LNode.Call(TypeNameWithoutAttrs, LNode.List(argNames)))))))).SetStyle(NodeStyle.StatementBlock))))).SetStyle(NodeStyle.StatementBlock))));
                }
                foreach (var child in _children)
                {
                    child.GenerateOutput(ref list);
                }
            }
예제 #3
0
        internal static LNodeList GetArgNamesFromFormalArgList(LNode args, Action <LNode> onError)
        {
            LNodeList formalArgs = args.Args;
            LNodeList argList    = LNodeList.Empty;

            foreach (var formalArg in formalArgs)
            {
                if (!formalArg.Calls(S.Var, 2))
                {
                    onError(formalArg);
                }
                else
                {
                    LNode argName = formalArg.Args[1];
                    if (argName.Calls(S.Assign, 2))
                    {
                        argName = argName.Args[0];
                    }
                    LNode @ref = formalArg.AttrNamed(S.Ref) ?? formalArg.AttrNamed(S.Out);
                    if (@ref != null)
                    {
                        argName = argName.PlusAttr(@ref);
                    }
                    argList.Add(argName);
                }
            }
            return(argList);
        }
예제 #4
0
            internal LNode GetWithFn(AdtParam part, bool isAbstract, Symbol virtualOverride, IEnumerable <AdtParam> allParts)
            {
                int totalParts = allParts.Count();
                var withField  = F.Id("With" + part.NameId.Name);

                var args = LNode.List();

                foreach (AdtParam otherPart in allParts)
                {
                    if (part == otherPart)
                    {
                        args.Add(F.Id("newValue"));
                    }
                    else
                    {
                        args.Add(otherPart.NameId);
                    }
                }

                var attrs = new LNodeList(F.Id(S.Public));

                if (isAbstract)
                {
                    attrs.Add(F.Id(S.Abstract));
                }
                if (virtualOverride != null && (!isAbstract || virtualOverride == S.Override))
                {
                    attrs.Add(F.Id(virtualOverride));
                }

                LNode method;
                LNode type    = part.Type;
                LNode retType = part.ContainingType.TypeNameWithoutAttrs;

                if (isAbstract)
                {
                    method = LNode.Call(LNode.List(attrs), CodeSymbols.Fn, LNode.List(retType, withField, LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(LNode.List(part.OriginalDecl.Attrs), CodeSymbols.Var, LNode.List(type, LNode.Id((Symbol)"newValue")))))));
                }
                else
                {
                    method = LNode.Call(LNode.List(attrs), CodeSymbols.Fn, LNode.List(retType, withField, LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(LNode.List(part.OriginalDecl.Attrs), CodeSymbols.Var, LNode.List(type, LNode.Id((Symbol)"newValue"))))), LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(LNode.Call(CodeSymbols.New, LNode.List(LNode.Call(TypeNameWithoutAttrs, LNode.List(args)))))))).SetStyle(NodeStyle.StatementBlock)));
                }
                return(method);
            }
예제 #5
0
            internal CodeGeneratorForMatchCase(IMacroContext context, LNode input, LNodeList handler)
            {
                _context = context;
                _input   = input;
                _handler = handler;
                var @break = LNode.Call(CodeSymbols.Break);

                if (_handler.IsEmpty || !_handler.Last.Equals(@break))
                {
                    _handler.Add(@break);
                }
            }
예제 #6
0
            void ProcessRequiresAttribute(LNodeList conditions, Symbol mode, LNode variableName)
            {
                // Create a "Contract.Requires()" check for each provided condition.
                foreach (var condition_ in conditions)
                {
                    LNode condition = condition_;                       // make it writable so we can replace `_`
                    LNode conditionStr;

                    if (ReplaceContractUnderscore(ref condition, variableName))
                    {
                        if (variableName == null)
                        {
                            Context.Sink.Error(condition, "`{0}`: underscore has no meaning in this location.", mode);
                        }
                    }
                    if (mode == sy_assert)
                    {
                        PrependStmts.Add(LNode.Call((Symbol)"assert", LNode.List(condition)));                          // relies on assert() macro
                    }
                    else if (_haveCCRewriter)
                    {
                        PrependStmts.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Id((Symbol)"Requires"))).SetStyle(NodeStyle.Operator), LNode.List(condition)));
                    }
                    else
                    {
                        conditionStr = ConditionToStringLit(condition, "Precondition failed: {1}");
                        PrependStmts.Add(LNode.Call(GetAssertMethodForRequires(), LNode.List(condition, conditionStr)));
                    }
                }
            }
예제 #7
0
        /// <summary>Creates the default method definition wrapped around the body
        /// of the rule, which was generated by the caller. Returns <see cref="Basis"/>
        /// with the specified new method body. If Basis is null, a simple default
        /// method signature is used, e.g. <c>public void R() {...}</c> where R is
        /// the rule name.</summary>
        /// <param name="methodBody">The parsing code that was generated for this rule.</param>
        /// <returns>A method.</returns>
        public virtual LNode CreateRuleMethod(Rule rule, LNodeList methodBody)
        {
            LNode method = rule.GetMethodSignature();
            var   parts  = method.Args.ToWList();

            if (parts[0].IsIdNamed(S.Missing))
            {
                parts[0] = F.Id(rule.Name);
            }
            Debug.Assert(parts.Count == 3);
            if (rule.IsRecognizer)
            {
                methodBody.Add(F.Call(S.Return, F.True));
            }
            parts.Add(F.OnNewLine(F.Braces(methodBody)));
            return(method.WithArgs(parts.ToLNodeList()));
        }
예제 #8
0
 static LNode GrabContractAttrs(LNode node, ref LNodeList cAttrs, ContractAppliesTo kinds = ContractAppliesTo.Both)
 {
     if (node.HasAttrs)
     {
         LNodeList cAttrs2 = cAttrs;                     // because lambdas cannot access cAttrs directly
         var       r       = node.WithAttrs(attr => {
             if ((PropertyContractInterpretation(attr) & kinds) != 0)
             {
                 cAttrs2.Add(attr);
                 return(NoValue.Value);                          // remove
             }
             return(attr);
         });
         cAttrs = cAttrs2;
         return(r);
     }
     return(node);
 }
예제 #9
0
 internal void ScanClassBody(LNodeList body)
 {
     foreach (var stmt in body)
     {
         int?i;
         {
             LNode     altName;
             LNodeList attrs, childBody = default(LNodeList), parts, rest;
             if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Fn, 3) && stmt.Args[0].IsIdNamed((Symbol)"alt") && (altName = stmt.Args[1]) != null && stmt.Args[2].Calls(CodeSymbols.AltList) && (parts = stmt.Args[2].Args).IsEmpty | true || (attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Fn, 4) && stmt.Args[0].IsIdNamed((Symbol)"alt") && (altName = stmt.Args[1]) != null && stmt.Args[2].Calls(CodeSymbols.AltList) && (parts = stmt.Args[2].Args).IsEmpty | true && stmt.Args[3].Calls(CodeSymbols.Braces) && (childBody = stmt.Args[3].Args).IsEmpty | true)
             {
                 LNode genericAltName = altName;
                 if (altName.CallsMin(CodeSymbols.Of, 1))
                 {
                 }
                 else
                 {
                     if (_genericArgs.Count > 0)
                     {
                         genericAltName = LNode.Call(CodeSymbols.Of, LNode.List().Add(altName).AddRange(_genericArgs.ToVList())).SetStyle(NodeStyle.Operator);
                     }
                 }
                 var child = new AltType(attrs, genericAltName, LNode.List(), this);
                 child.AddParts(parts);
                 child.ScanClassBody(childBody);
                 _children.Add(child);
             }
             else if ((attrs = stmt.Attrs).IsEmpty | true && (i = attrs.FirstIndexWhere(a => a.IsIdNamed(__alt))) != null && stmt.CallsMin(CodeSymbols.Constructor, 3) && stmt.Args[1].IsIdNamed((Symbol)"#this") && stmt.Args[2].Calls(CodeSymbols.AltList) && (rest = new LNodeList(stmt.Args.Slice(3))).IsEmpty | true && rest.Count <= 1)
             {
                 parts = stmt.Args[2].Args;
                 attrs.RemoveAt(i.Value);
                 _constructorAttrs.AddRange(attrs);
                 if (rest.Count > 0 && rest[0].Calls(S.Braces))
                 {
                     _extraConstrLogic.AddRange(rest[0].Args);
                 }
                 AddParts(parts);
             }
             else
             {
                 _classBody.Add(stmt);
             }
         }
     }
 }
예제 #10
0
        protected LNode SingleExprInside(Token group, string stmtType, bool allowUnassignedVarDecl, ref LNodeList list)
        {
            int oldCount = list.Count;

            list = AppendExprsInside(group, list, false, allowUnassignedVarDecl);
            if (list.Count != oldCount + 1)
            {
                if (list.Count <= oldCount)
                {
                    LNode result = F.Id(S.Missing, group.StartIndex + 1, group.StartIndex + 1);
                    list.Add(result);
                    Error(result, "Missing expression inside '{0}'", stmtType);
                    return(result);
                }
                else
                {
                    Error(list[1], "There should be only one expression inside '{0}'", stmtType);
                    list.Resize(oldCount + 1);
                }
            }
            return(list[0]);
        }
예제 #11
0
        public LNodeList RulesAndStuff()
        {
            LNodeList result = default(LNodeList);

            // Line 176: ( Rule | HostCall | HostBlock )
            switch ((TT)LA0)
            {
            case TT.At:
            case TT.AttrKeyword:
            case TT.LBrack:
                result.Add(Rule());
                break;

            case TT.Id:
            {
                switch ((TT)LA(1))
                {
                case TT.Id:
                case TT.LBrack:
                    result.Add(Rule());
                    break;

                case TT.LParen:
                {
                    switch ((TT)LA(3))
                    {
                    case TT.At:
                    case TT.Colon:
                    case TT.Id:
                    case TT.Returns:
                    case TT.StartColon:
                        result.Add(Rule());
                        break;

                    case TT.Semicolon:
                        result.Add(HostCall());
                        break;

                    default:
                    {
                        // line 179
                        Error(0, "Expected a rule definition here (or a block of code in the host language)");
                    }
                    break;
                    }
                }
                break;

                case TT.At:
                case TT.Colon:
                case TT.Returns:
                case TT.StartColon:
                    result.Add(Rule());
                    break;

                case TT.LBrace:
                    result.Add(HostBlock());
                    break;

                default:
                {
                    // line 179
                    Error(0, "Expected a rule definition here (or a block of code in the host language)");
                }
                break;
                }
            }
            break;

            case TT.LParen:
                result.Add(HostCall());
                break;

            case TT.LBrace:
                result.Add(HostBlock());
                break;

            default:
            {
                // line 179
                Error(0, "Expected a rule definition here (or a block of code in the host language)");
            }
            break;
            }
            // Line 176: ( Rule | HostCall | HostBlock )*
            for (;;)
            {
                switch ((TT)LA0)
                {
                case TT.At:
                case TT.AttrKeyword:
                case TT.LBrack:
                    result.Add(Rule());
                    break;

                case TT.Id:
                {
                    switch ((TT)LA(1))
                    {
                    case TT.Id:
                    case TT.LBrack:
                        result.Add(Rule());
                        break;

                    case TT.LParen:
                    {
                        switch ((TT)LA(3))
                        {
                        case TT.At:
                        case TT.Colon:
                        case TT.Id:
                        case TT.Returns:
                        case TT.StartColon:
                            result.Add(Rule());
                            break;

                        case TT.Semicolon:
                            result.Add(HostCall());
                            break;

                        default:
                        {
                            // line 179
                            Error(0, "Expected a rule definition here (or a block of code in the host language)");
                        }
                        break;
                        }
                    }
                    break;

                    case TT.At:
                    case TT.Colon:
                    case TT.Returns:
                    case TT.StartColon:
                        result.Add(Rule());
                        break;

                    case TT.LBrace:
                        result.Add(HostBlock());
                        break;

                    default:
                    {
                        // line 179
                        Error(0, "Expected a rule definition here (or a block of code in the host language)");
                    }
                    break;
                    }
                }
                break;

                case TT.LParen:
                    result.Add(HostCall());
                    break;

                case TT.LBrace:
                    result.Add(HostBlock());
                    break;

                case EOF:
                    goto stop;

                default:
                {
                    // line 179
                    Error(0, "Expected a rule definition here (or a block of code in the host language)");
                }
                break;
                }
            }
            stop :;
            Skip();
            return(result);
        }
예제 #12
0
        // A sequence of expressions separated by commas OR semicolons.
        // The `ref endMarker` parameter tells the caller if semicolons were used.
        public virtual LNodeList ExprList(ref TokenType endMarker, LNodeList list = default(LNodeList))
        {
            TT    la0;
            LNode e   = default(LNode);
            Token end = default(Token);

            // Line 1: ( / TopExpr)
            switch ((TT)LA0)
            {
            case EOF:
            case TT.Comma:
            case TT.RBrace:
            case TT.RBrack:
            case TT.RParen:
            case TT.Semicolon:
            { }
            break;

            default:
                e = TopExpr();
                break;
            }
            // Line 61: ((TT.Comma|TT.Semicolon) ({..} / TopExpr))*
            for (;;)
            {
                la0 = (TT)LA0;
                if (la0 == TT.Comma || la0 == TT.Semicolon)
                {
                    end = MatchAny();
                    e   = e ?? MissingExpr(end);
                    // line 63
                    list.Add(e.WithRange(e.Range.StartIndex, end.EndIndex));
                    // line 64
                    CheckEndMarker(ref endMarker, ref end);
                    // Line 65: ({..} / TopExpr)
                    switch ((TT)LA0)
                    {
                    case EOF:
                    case TT.Comma:
                    case TT.RBrace:
                    case TT.RBrack:
                    case TT.RParen:
                    case TT.Semicolon:
                        // line 65
                        e = null;
                        break;

                    default:
                        e = TopExpr();
                        break;
                    }
                }
                else
                {
                    break;
                }
            }
            // line 67
            if ((e != null || end.Type() == TT.Comma))
            {
                list.Add(e ?? MissingExpr(end));
            }
            // line 68
            return(list);
        }
예제 #13
0
        // Types of (normal) expressions:
        // - particles: ids, literals, (parenthesized), {braced}
        // - ++prefix_operators
        // - infix + operators
        // - suffix_operators++
        // - Special primary expressions:
        //   method_calls(with arguments), indexers[with indexes], generic!arguments
        LNode Expr(Precedence context)
        {
            TT    la0;
            LNode e        = default(LNode);
            Token lit_excl = default(Token);
            Token t        = default(Token);
            // line 128
            Precedence prec;

            e = PrefixExpr(context);
            // Line 132: greedy( &{context.CanParse(prec = InfixPrecedenceOf(LT($LI)))} (TT.Assignment|TT.BQOperator|TT.Dot|TT.NormalOp) Expr | &{context.CanParse(P.Primary)} FinishPrimaryExpr | &{context.CanParse(P.Of)} TT.Not (TT.LParen ExprList TT.RParen / Expr) | &{context.CanParse(SuffixPrecedenceOf(LT($LI)))} TT.PreOrSufOp )*
            for (;;)
            {
                switch ((TT)LA0)
                {
                case TT.Assignment:
                case TT.BQOperator:
                case TT.Dot:
                case TT.NormalOp:
                {
                    if (context.CanParse(prec = InfixPrecedenceOf(LT(0))))
                    {
                        // line 133
                        if ((!prec.CanMixWith(context)))
                        {
                            Error(0, "Operator '{0}' is not allowed in this context. Add parentheses to clarify the code's meaning.", LT0.Value);
                        }
                        t = MatchAny();
                        var rhs = Expr(prec);
                        // line 138
                        e = F.Call(t, e, rhs, e.Range.StartIndex, rhs.Range.EndIndex, NodeStyle.Operator);
                    }
                    else
                    {
                        goto stop;
                    }
                }
                break;

                case TT.LBrack:
                case TT.LParen:
                {
                    if (context.CanParse(P.Primary))
                    {
                        e = FinishPrimaryExpr(e);
                    }
                    else
                    {
                        goto stop;
                    }
                }
                break;

                case TT.Not:
                {
                    if (context.CanParse(P.Of))
                    {
                        lit_excl = MatchAny();
                        // line 145
                        var args = new LNodeList {
                            e
                        };
                        int endIndex;
                        // Line 146: (TT.LParen ExprList TT.RParen / Expr)
                        la0 = (TT)LA0;
                        if (la0 == TT.LParen)
                        {
                            Skip();
                            args = ExprList(args);
                            var c = Match((int)TT.RParen);
                            // line 146
                            endIndex = c.EndIndex;
                        }
                        else
                        {
                            var T = Expr(P.Of);
                            // line 147
                            args.Add(T);
                            endIndex = T.Range.EndIndex;
                        }
                        // line 149
                        e = F.Call(S.Of, args, e.Range.StartIndex, endIndex, lit_excl.StartIndex, lit_excl.EndIndex, NodeStyle.Operator);
                    }
                    else
                    {
                        goto stop;
                    }
                }
                break;

                case TT.PreOrSufOp:
                {
                    if (context.CanParse(SuffixPrecedenceOf(LT(0))))
                    {
                        t = MatchAny();
                        // line 153
                        e = F.Call(ToSuffixOpName((Symbol)t.Value), e, e.Range.StartIndex, t.EndIndex, t.StartIndex, t.EndIndex, NodeStyle.Operator);
                    }
                    else
                    {
                        goto stop;
                    }
                }
                break;

                default:
                    goto stop;
                }
            }
            stop :;
            // line 155
            return(e);
        }
예제 #14
0
            private void MakeArgListTests(LNodeList patternArgs, ref LNode candidate)
            {
                // Note: at this point we can assume that the quantity of
                // arguments has already been checked and is not too small.
                Symbol varArgSym  = null;
                LNode  varArgCond = null;
                int    i;

                for (i = 0; i < patternArgs.Count; i++)
                {
                    MakeTestExpr(patternArgs[i], LNode.Call(CodeSymbols.IndexBracks, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), F.Literal(i))).SetStyle(NodeStyle.Operator), out varArgSym, out varArgCond);
                    if (varArgSym != null)
                    {
                        break;
                    }
                }
                int i2 = i + 1;

                for (int left = patternArgs.Count - i2; i2 < patternArgs.Count; i2++)
                {
                    Symbol varArgSym2  = null;
                    LNode  varArgCond2 = null;
                    MakeTestExpr(patternArgs[i2], LNode.Call(CodeSymbols.IndexBracks, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Call(CodeSymbols.Sub, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Count"))).SetStyle(NodeStyle.Operator), F.Literal(left))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator), out varArgSym2, out varArgCond2);
                    if (varArgSym2 != null)
                    {
                        Context.Sink.Error(patternArgs[i2], "More than a single $(...varargs) variable is not supported in a single argument list.");
                        break;
                    }
                    left--;
                }
                if (varArgSym != null && (varArgSym != __ || varArgCond != null))
                {
                    // Extract variable arg list
                    LNode varArgSymId = F.Id(varArgSym);
                    LNode grabVarArgs;
                    if (i == 0 && patternArgs.Count == 1)
                    {
                        grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator);
                    }
                    else if (i == 0 && patternArgs.Count > 1)
                    {
                        var fixedArgsLit = F.Literal(patternArgs.Count - 1);
                        grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"WithoutLast"))).SetStyle(NodeStyle.Operator), LNode.List(fixedArgsLit)))).SetStyle(NodeStyle.Operator);
                    }
                    else
                    {
                        var varArgStartLit = F.Literal(i);
                        var fixedArgsLit   = F.Literal(patternArgs.Count - 1);
                        if (i + 1 == patternArgs.Count)
                        {
                            grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.New, LNode.List(LNode.Call((Symbol)"LNodeList", LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Slice"))).SetStyle(NodeStyle.Operator), LNode.List(varArgStartLit)))))))).SetStyle(NodeStyle.Operator);
                        }
                        else
                        {
                            grabVarArgs = LNode.Call(CodeSymbols.Assign, LNode.List(varArgSymId, LNode.Call(CodeSymbols.New, LNode.List(LNode.Call((Symbol)"LNodeList", LNode.List(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Slice"))).SetStyle(NodeStyle.Operator), LNode.List(varArgStartLit, LNode.Call(CodeSymbols.Sub, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(candidate, LNode.Id((Symbol)"Args"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"Count"))).SetStyle(NodeStyle.Operator), fixedArgsLit)).SetStyle(NodeStyle.Operator))))))))).SetStyle(NodeStyle.Operator);
                        }
                    }

                    // Add an extra condition on the $(...list) if requested by user
                    if (varArgCond != null || IsMultiCase)
                    {
                        Tests.Add(LNode.Call(CodeSymbols.OrBits, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(grabVarArgs.PlusAttrs(LNode.List(LNode.InParensTrivia)), LNode.Id((Symbol)"IsEmpty"))).SetStyle(NodeStyle.Operator), LNode.Literal(true))).SetStyle(NodeStyle.Operator));
                        Tests.Add(varArgCond);
                    }
                    else
                    {
                        ThenClause.Add(grabVarArgs);
                    }
                }
            }
예제 #15
0
            public LNode Quote(LNode node)
            {
                // TODO: When quoting, ignore injected trivia (trivia with the TriviaInjected flag)
                if (node.Equals(LNode.InParensTrivia))
                {
                    return(LNode_InParensTrivia);
                }
                if (node.Equals(LNode.Missing))
                {
                    return(LNode_Missing);
                }

                LNodeList creationArgs = new LNodeList();

                // Translate attributes (if any)
                var attrList = MaybeQuoteList(node.Attrs, isAttributes: true);

                if (attrList != null)
                {
                    creationArgs.Add(attrList);
                }

                LNode result;

                switch (node.Kind)
                {
                case LNodeKind.Literal:                 // => F.Literal(value)
                    creationArgs.Add(node.WithoutAttrs());
                    result = F.Call(LNode_Literal, creationArgs);
                    break;

                case LNodeKind.Id:                 // => F.Id(string), F.Id(CodeSymbols.Name)
                    creationArgs.Add(QuoteSymbol(node.Name));
                    result = F.Call(LNode_Id, creationArgs);
                    break;

                default:                 // NodeKind.Call => F.Dot(...), F.Of(...), F.Call(...), F.Braces(...)
                    bool preserveStyle = true;
                    if (_doSubstitutions && node.Calls(S.Substitute, 1))
                    {
                        preserveStyle = false;
                        result        = node.Args[0];
                        if (attrList != null)
                        {
                            if (result.IsCall)
                            {
                                result = result.InParens();
                            }
                            result = F.Call(F.Dot(result, Id_PlusAttrs), attrList);
                        }
                    }
                    else if (!_ignoreTrivia && node.ArgCount == 1 && node.TriviaValue != NoValue.Value && node.Target.IsId)
                    {
                        // LNode.Trivia(Symbol, object)
                        result = F.Call(LNode_Trivia, QuoteSymbol(node.Name), F.Literal(node.TriviaValue));
                    }

                    /*else if (node.Calls(S.Braces)) // F.Braces(...)
                     *      result = F.Call(LNode_Braces, node.Args.SmartSelect(arg => QuoteOne(arg, substitutions)));
                     * else if (node.Calls(S.Dot) && node.ArgCount.IsInRange(1, 2))
                     *      result = F.Call(LNode_Dot, node.Args.SmartSelect(arg => QuoteOne(arg, substitutions)));
                     * else if (node.Calls(S.Of))
                     *      result = F.Call(LNode_Of, node.Args.SmartSelect(arg => QuoteOne(arg, substitutions)));*/
                    else
                    {
                        // General case: F.Call(<Target>, <Args>)
                        if (node.Target.IsId)
                        {
                            creationArgs.Add(QuoteSymbol(node.Name));
                        }
                        else
                        {
                            creationArgs.Add(Quote(node.Target));
                        }

                        var argList = MaybeQuoteList(node.Args);
                        if (argList != null)
                        {
                            creationArgs.Add(argList);
                        }
                        result = F.Call(LNode_Call, creationArgs);
                    }
                    // Note: don't preserve prefix notation because if $op is +,
                    // we want $op(x, y) to generate code for x + y (there is no
                    // way to express this with infix notation.)
                    if (preserveStyle && node.BaseStyle != NodeStyle.Default && node.BaseStyle != NodeStyle.PrefixNotation)
                    {
                        result = F.Call(F.Dot(result, F.Id("SetStyle")), F.Dot(F.Id("NodeStyle"), F.Id(node.BaseStyle.ToString())));
                    }
                    break;
                }
                return(result);
            }
예제 #16
0
            void GetPatternComponents(LNode pattern, out LNode propName,
                                      out LNode varBinding, out bool refExistingVar,
                                      out LNode cmpExpr, out LNode isType, out LNode inRange,
                                      out LNodeList subPatterns, out LNodeList conditions)
            {
                // Format: PropName: is DerivedClass name(...) in Range
                // Here's a typical pattern (case expr):
                //  is Shape(ShapeType.Circle, ref size, Location: p is Point<int>(x, y))
                // When there is an arg list, we decode its Target and return the args.
                //
                // The caller is in charge of stripping out "Property:" prefix, if any,
                // so the most complex pattern that this method considers is something
                // like `expr is Type x(subPatterns) in Range && conds` where `expr` is
                // a varName or $varName to deconstruct, or some expression to test for
                // equality. Assuming it's an equality test, the output will be
                //
                //   varBinding = null
                //   refExistingVar = false
                //   cmpExpr = quote(expr);
                //   isType = quote(Type);
                //   inRange = quote(Range);
                //   conds will have "conds" pushed to the front.
                //
                subPatterns    = LNodeList.Empty;
                refExistingVar = pattern.AttrNamed(S.Ref) != null;

                propName = varBinding = cmpExpr = isType = inRange = null;
                // Deconstruct `PropName: pattern` (fun fact: we can't use `matchCode`
                // to detect a named parameter here, because if we write
                // `case { $propName: $subPattern; }:` it is parsed as a goto-label,
                // not as a named parameter.)
                if (pattern.Calls(S.NamedArg, 2) || pattern.Calls(S.Colon, 2))
                {
                    propName = pattern[0]; pattern = pattern[1];
                }
                // Deconstruct `pattern && condition` (iteratively)
                conditions = LNodeList.Empty;
                while (pattern.Calls(S.And, 2))
                {
                    conditions.Add(pattern.Args.Last);
                    pattern = pattern.Args[0];
                }

                // deconstruct `pattern in Range`
                {
                    LNode lhs;
                    if (pattern.Calls(CodeSymbols.In, 2) && (lhs = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null || pattern.Calls((Symbol)"in", 2) && (lhs = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null || pattern.Calls(CodeSymbols.In, 2) && (lhs = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null)
                    {
                        pattern = lhs;
                    }
                }
                // Deconstruct `PropName is Type` with optional list of subpatterns.
                // In LES let's accept ``PropName `is` (Type `with` (subpatterns))`` instead.
                LNode subpatterns = null;

                {
                    LNode lhs, type;
                    if (pattern.Calls(CodeSymbols.Is, 2) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null || pattern.Calls(CodeSymbols.Is, 3) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null && (subpatterns = pattern.Args[2]) != null || pattern.Calls((Symbol)"is", 2) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null || pattern.Calls(CodeSymbols.Is, 2) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null)
                    {
                        if (subpatterns == null)
                        {
                            // Check for syntax for LES with `with`
                            if (type.Calls((Symbol)"with", 2) && (isType = type.Args[0]) != null && (subpatterns = type.Args[1]) != null || type.Calls(CodeSymbols.With, 2) && (isType = type.Args[0]) != null && (subpatterns = type.Args[1]) != null)
                            {
                            }
                        }
                        if (type.Calls(CodeSymbols.Var, 2) && (isType = type.Args[0]) != null && (varBinding = type.Args[1]) != null)
                        {
                        }
                        else
                        {
                            isType = type;
                        }
                        if (lhs.Calls(S.Substitute, 1))
                        {
                            if (varBinding != null)
                            {
                                _context.Sink.Error(varBinding, "match: cannot bind two variable names to one value");
                            }
                            varBinding = lhs[0];
                        }
                        else if (propName != null)
                        {
                            _context.Sink.Error(varBinding, "match: property name already set to {0}", propName.Name);
                            if (varBinding == null)
                            {
                                varBinding = lhs;                                       // assume it was intended as a variable binding
                            }
                        }
                        if (type.IsIdNamed("")                          // is var x
                            )
                        {
                            isType = null;
                        }
                    }
                    else if (pattern.Calls(CodeSymbols.DotDotDot, 2) || pattern.Calls(CodeSymbols.DotDot, 2) || pattern.Calls(CodeSymbols.DotDotDot, 1) || pattern.Calls(CodeSymbols.DotDot, 1))
                    {
                        inRange = pattern;
                    }
                    else if (pattern.Calls(CodeSymbols.AltList) || pattern.Calls(CodeSymbols.Tuple))
                    {
                        subpatterns = pattern;
                    }
                    else
                    {
                        if (pattern.Calls(S.Substitute, 1))
                        {
                            varBinding = pattern[0];
                        }
                        else
                        {
                            cmpExpr = pattern;
                        }
                    }
                }

                if (subpatterns != null)
                {
                    if (subpatterns.Calls(S.Tuple) || subpatterns.Calls(S.AltList))
                    {
                        subPatterns = subpatterns.Args;
                    }
                    else
                    {
                        _context.Sink.Error(subpatterns, "match: expected list of subpatterns (at '{0}')", subpatterns);
                    }
                }
                if (cmpExpr != null)
                {
                    if (cmpExpr.IsIdNamed(__))
                    {
                        cmpExpr = null;
                    }
                    else if (refExistingVar && varBinding == null)                              // Treat `ref expr` as var binding
                    {
                        varBinding = cmpExpr;
                        cmpExpr    = null;
                    }
                }
                if (varBinding != null)
                {
                    if (varBinding.AttrNamed(S.Ref) != null)
                    {
                        varBinding     = varBinding.WithoutAttrNamed(S.Ref);
                        refExistingVar = true;
                    }
                    else if (varBinding.IsIdNamed(__))
                    {
                        varBinding = null;
                    }
                    else if (!varBinding.IsId)
                    {
                        _context.Sink.Error(varBinding, "match: expected variable name (at '{0}')", varBinding);
                        varBinding = null;
                    }
                }
            }
예제 #17
0
        public static LNode SetOrCreateMember(LNode fn, IMessageSink sink)
        {
            // Expecting #fn(Type, Name, #(args), {body})
            if (fn.ArgCount < 3 || !fn.Args[2].Calls(S.AltList))
            {
                return(null);
            }
            var args = fn.Args[2].Args;

            LNodeList propOrFieldDecls             = LNodeList.Empty;
            Dictionary <Symbol, LNode> assignments = null;

            for (int i = 0; i < args.Count; i++)
            {
                var    arg = args[i];
                Symbol relevantAttribute, fieldName, paramName;
                LNode  plainArg, propOrFieldDecl;
                if (DetectSetOrCreateMember(arg, out relevantAttribute, out fieldName, out paramName, out plainArg, out propOrFieldDecl))
                {
                    if (fn.ArgCount < 4)
                    {
                        return(Reject(sink, arg, Localize.Localized("'{0}': to set or create a field or property, the method must have a body in braces {{}}.", relevantAttribute)));
                    }

                    args[i]                = plainArg;
                    assignments            = assignments ?? new Dictionary <Symbol, LNode>();
                    assignments[fieldName] = F.Id(paramName);
                    if (propOrFieldDecl != null)
                    {
                        propOrFieldDecls.Add(propOrFieldDecl);
                    }
                }
            }

            if (assignments != null)             // if this macro has been used...
            {
                var parts = fn.Args;
                parts[2] = parts[2].WithArgs(args);
                var body = parts[3];

                // Ensure the method has a normal braced body
                if (!body.Calls(S.Braces))
                {
                    if (parts[0].IsIdNamed(S.Void))
                    {
                        body = F.Braces(body);
                    }
                    else
                    {
                        body = F.Braces(F.Call(S.Return, body));
                    }
                }

                // In case one constructor calls another, we have to ensure that the
                // assignments are inserted _after_ that call, and if the constructor
                // call refers to properties or fields that will be set, we must remap
                // those references onto parameters, e.g.
                //   this(public int X) { base(X); } => this(int x) { base(x); X = x; }
                var bodyStmts = body.Args;
                int indexAtWhichToDoAssignments = 0;
                if (fn.Calls(S.Constructor))
                {
                    LNode baseCall = bodyStmts[0, LNode.Missing];
                    if (baseCall.Calls(S.Base) || baseCall.Calls(S.This))
                    {
                        bodyStmts[0] = baseCall.ReplaceRecursive(n => {
                            LNode param;
                            if (n.IsId && assignments.TryGetValue(n.Name, out param))
                            {
                                return(param);
                            }
                            return(null);
                        });
                        indexAtWhichToDoAssignments = 1;
                    }
                }

                // Insert assignment statements
                parts[3] = body.WithArgs(bodyStmts.InsertRange(indexAtWhichToDoAssignments, assignments.Select(p => {
                    if (p.Key == p.Value.Name)
                    {
                        return(F.Call(S.Assign, F.Dot(F.@this, F.Id(p.Key)), p.Value));
                    }
                    else
                    {
                        return(F.Call(S.Assign, F.Id(p.Key), p.Value));
                    }
                }).ToList()));

                // Return output code
                fn = fn.WithArgs(parts);
                if (propOrFieldDecls.IsEmpty)
                {
                    return(fn);
                }
                else
                {
                    propOrFieldDecls.Add(fn);
                    return(F.Call(S.Splice, propOrFieldDecls));
                }
            }
            return(null);
        }
예제 #18
0
        public static LNodeList UseSymbolsCore(LNodeList symbolAttrs, LNodeList options, LNodeList body, IMacroContext context, bool inType)
        {
            // Decode options (TODO: invent a simpler approach)
            string prefix    = "sy_";
            var    inherited = new HashSet <Symbol>();

            foreach (var pair in MacroContext.GetOptions(options))
            {
                if (pair.Key.Name.Name == "prefix" && pair.Value.IsId)
                {
                    prefix = pair.Value.Name.Name;
                }
                else if (pair.Key.Name.Name == "inherit" && pair.Value.Value is Symbol)
                {
                    inherited.Add((Symbol)pair.Value.Value);
                }
                else if (pair.Key.Name.Name == "inherit" && (pair.Value.Calls(S.Braces) || pair.Value.Calls(S.Tuple)) && pair.Value.Args.All(n => n.Value is Symbol))
                {
                    foreach (var arg in pair.Value.Args)
                    {
                        inherited.Add((Symbol)arg.Value);
                    }
                }
                else
                {
                    context.Sink.Warning(pair.Key, "Unrecognized parameter. Expected prefix:id or inherit:{@@A; @@B; ...})");
                }
            }

            // Replace all symbols while collecting a list of them
            var       symbols = new Dictionary <Symbol, LNode>();
            LNodeList output  = body.SmartSelect(stmt =>
                                                 stmt.ReplaceRecursive(n => {
                if (!inType && n.ArgCount == 3)
                {
                    // Since we're outside any type, we must avoid creating symbol
                    // fields. When we cross into a type then we can start making
                    // Symbols by calling ourself recursively with inType=true
                    var kind = EcsValidators.SpaceDefinitionKind(n);
                    if (kind == S.Class || kind == S.Struct || kind == S.Interface || kind == S.Alias || kind == S.Trait)
                    {
                        var body2 = n.Args[2];
                        return(n.WithArgChanged(2, body2.WithArgs(UseSymbolsCore(symbolAttrs, options, body2.Args, context, true))));
                    }
                }
                var sym = n.Value as Symbol;
                if (n.IsLiteral && sym != null)
                {
                    return(symbols[sym] = LNode.Id(prefix + sym.Name));
                }
                return(null);
            })
                                                 );

            // Return updated code with variable declaration at the top for all non-inherit symbols used.
            var _Symbol = F.Id("Symbol");
            var vars    = (from sym in symbols
                           where !inherited.Contains(sym.Key)
                           select F.Call(S.Assign, sym.Value,
                                         F.Call(S.Cast, F.Literal(sym.Key.Name), _Symbol))).ToList();

            if (vars.Count > 0)
            {
                output.Insert(0, F.Call(S.Var, ListExt.Single(_Symbol).Concat(vars))
                              .WithAttrs(symbolAttrs.Add(F.Id(S.Static)).Add(F.Id(S.Readonly))));
            }
            return(output);
        }