Пример #1
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);
                }
            }
Пример #2
0
        private static StringBuilder ConcatCore(LNode node, out LNodeList attrs, IMessageSink sink, bool allowLastToBeCall = false)
        {
            attrs = node.Attrs;
            var args = node.Args;

            if (args.Count == 0)
            {
                return(null);
            }

            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < args.Count; i++)
            {
                LNode arg = args[i];
                attrs.AddRange(arg.Attrs);

                if (arg.IsLiteral)
                {
                    if (!arg.TextValue.IsNull)
                    {
                        arg.TextValue.AppendTo(sb);
                    }
                    else
                    {
                        sb.Append(arg.Value ?? "null");
                    }
                }
                else if (arg.IsId)
                {
                    sb.Append(arg.Name);
                }
                else                     // call
                {
                    if (i + 1 != args.Count || !arg.HasSimpleHead())
                    {
                        Reject(sink, arg, "Expected simple identifier or literal");
                        return(null);
                    }
                    sb.Append(arg.Name);
                }
            }
            return(sb);
        }
Пример #3
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);
             }
         }
     }
 }
Пример #4
0
            void ProcessEnsuresAttribute(LNodeList conditions, Symbol mode, LNode exceptionType, LNode variableName)
            {
                // Create a "Contract.Whatever()" check for each provided condition.
                bool haveCCRewriter = _haveCCRewriter && mode != sy_ensuresAssert && mode != sy_ensuresFinally;
                var  checks         = LNode.List();

                foreach (var condition_ in conditions)
                {
                    LNode condition = condition_;                       // make it writable so we can replace `_`
                    LNode conditionStr;

                    LNode  contractResult  = null;
                    string underscoreError = null;
                    if (mode == sy_ensuresOnThrow)
                    {
                        contractResult = Id__exception__;
                        if (haveCCRewriter)
                        {
                            underscoreError = "`ensuresOnThrow` does not support `_` in MS Code Contracts mode.";
                        }
                    }
                    else                                // @@ensures or @@ensuresAssert or @@ensuresFinally
                    {
                        contractResult = haveCCRewriter ? LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"Result"), ReturnType)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator)) : Id_return_value;
                        if (mode == sy_ensuresFinally)
                        {
                            underscoreError = "The macro for `{0}` does not support `_` because the return value is not available in `finally`";
                        }
                        else if (haveCCRewriter && ReturnType.IsIdNamed(S.Missing))
                        {
                            underscoreError = "The macro for `{0}` does not support `_` in this context when MS Code Contracts are enabled, because the return type is unknown.";
                        }
                        bool changed = ReplaceContractUnderscore(ref condition, contractResult);
                    }
                    if (ReplaceContractUnderscore(ref condition, contractResult) && underscoreError != null)
                    {
                        Context.Sink.Error(condition, underscoreError, mode);
                    }

                    if (haveCCRewriter)
                    {
                        if (mode == sy_ensuresOnThrow)
                        {
                            checks.Add(exceptionType != null
                                                        ? LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol)"EnsuresOnThrow"), exceptionType)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator), LNode.List(condition)) : LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Id((Symbol)"EnsuresOnThrow"))).SetStyle(NodeStyle.Operator), LNode.List(condition)));
                        }
                        else
                        {
                            checks.Add(LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Id((Symbol)"Contract"), LNode.Id((Symbol)"Ensures"))).SetStyle(NodeStyle.Operator), LNode.List(condition)));
                        }
                    }
                    else
                    {
                        conditionStr = ConditionToStringLit(condition,
                                                            mode == sy_ensuresOnThrow
                                                ? "Postcondition failed after throwing an exception: {1}" :
                                                            "Postcondition failed: {1}");


                        if (mode == sy_ensuresOnThrow)
                        {
                            var excType = GetExceptionTypeForEnsuresOnThrow();
                            checks.Add(LNode.Call(CodeSymbols.If, LNode.List(LNode.Call(CodeSymbols.Not, LNode.List(condition)).SetStyle(NodeStyle.Operator), LNode.Call(CodeSymbols.Throw, LNode.List(LNode.Call(CodeSymbols.New, LNode.List(LNode.Call(excType, LNode.List(conditionStr, Id__exception__)))))))));
                        }
                        else
                        {
                            LNode assertMethod;
                            if (mode == sy_ensuresAssert)
                            {
                                assertMethod = GetAssertMethod(Context);
                            }
                            else if (mode == sy_ensuresFinally)
                            {
                                assertMethod = GetAssertMethodForEnsuresFinally();
                            }
                            else
                            {
                                assertMethod = GetAssertMethodForEnsures();
                            }

                            checks.Add(LNode.Call(assertMethod, LNode.List(condition, conditionStr)));
                        }
                    }
                }

                // Request that the checks be added to the beginning of the method
                if (checks.Count > 0)
                {
                    if (_haveCCRewriter)
                    {
                        PrependStmts.AddRange(checks);
                    }
                    else if (mode == sy_ensuresOnThrow)
                    {
                        LNode excSpec = exceptionType == null ? Id__exception__ : LNode.Call(CodeSymbols.Var, LNode.List(exceptionType, Id__exception__));
                        PrependStmts.Add(LNode.Call((Symbol)"on_throw", LNode.List(excSpec, LNode.Call(CodeSymbols.Braces, LNode.List(checks)).SetStyle(NodeStyle.StatementBlock))).SetStyle(NodeStyle.Special));
                    }
                    else if (mode == sy_ensuresFinally)
                    {
                        PrependStmts.Add(LNode.Call((Symbol)"on_finally", LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(checks)).SetStyle(NodeStyle.StatementBlock))).SetStyle(NodeStyle.Special));
                    }
                    else                                // mode == @@ensures || mode == @@ensuresAssert
                    {
                        PrependStmts.Add(LNode.Call((Symbol)"on_return", LNode.List(Id_return_value, LNode.Call(CodeSymbols.Braces, LNode.List(checks)).SetStyle(NodeStyle.StatementBlock))).SetStyle(NodeStyle.Special));
                    }
                }
            }
Пример #5
0
        public static LNode CompileMacro(LNode pattern, LNode body, IMacroContext context, LNodeList attrs)
        {
            var modeNodes = attrs.Where(a => Enum.TryParse(a.Name.Name, out MacroMode _));
            // unwrap braces (they're not part of the pattern, they just enable statement syntax in EC#)
            var       pattern_apos = pattern.UnwrapBraces();
            MacroMode modes        = GetMacroMode(ref attrs, pattern_apos);

            // compileTime {...} can recognize macro method definitions.
            // Take advantage of this by generating a macro method which it will register for us.
            LNode macroName   = pattern_apos.Target ?? pattern_apos;
            LNode syntax      = F.Literal(pattern_apos.ToString());
            LNode description = attrs.FirstOrDefault(a => a.Value is string) ?? F.Literal("User-defined macro at {0}".Localized(pattern.Range.Start));

            attrs = attrs.SmartWhere(a => !(a.Value is string));                // remove docstring, if any
            var extraArgs = LNode.List();

            if (macroName.IsId)
            {
                extraArgs.Add(F.Literal(macroName.Name.Name));
            }
            else
            {
                Debug.Assert((modes & (MacroMode.MatchEveryCall | MacroMode.MatchEveryIdentifier | MacroMode.MatchEveryLiteral)) != 0);
            }

            // ensure operator macros like `'+` are not printed as `operator+` which C# will reject
            if (EcsValidators.IsOperator(macroName.Name))
            {
                macroName = F.Id(EcsValidators.SanitizeIdentifier(macroName.Name.Name));
            }

            LNode modesExpr = null;

            foreach (LNode mode in modeNodes)
            {
                modesExpr = LNode.MergeBinary(modesExpr, LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.ColonColon, LNode.List(LNode.Id((Symbol)"global"), LNode.Id((Symbol)"LeMP"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"MacroMode"))).SetStyle(NodeStyle.Operator), mode)).SetStyle(NodeStyle.Operator), S.OrBits);
            }
            if (modesExpr != null)
            {
                extraArgs.Add(LNode.Call(CodeSymbols.Assign, LNode.List(LNode.Id((Symbol)"Mode"), modesExpr)).SetStyle(NodeStyle.Operator));
            }

            LNode lmAttribute = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.ColonColon, LNode.List(LNode.Id((Symbol)"global"), LNode.Id((Symbol)"LeMP"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"LexicalMacroAttribute"))).SetStyle(NodeStyle.Operator), LNode.List().Add(syntax).Add(description).AddRange(extraArgs));

            if (!body.Calls(S.Braces))
            {
                body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.StatementBlock);
            }

            body = context.PreProcess(body);

            // Look for "using" statements above the macro() call
            LNodeList usingDirectives = LNode.List(context.PreviousSiblings.Where(n => n.Calls(S.Import)));

            // Look for "using" and "#r" statements at the beginning of the body
            if (body.Calls(S.Braces))
            {
                var bodyUsings = body.Args.TakeNowWhile(stmt => stmt.Calls(S.Import) || stmt.Calls(S.CsiReference));
                usingDirectives.AddRange(bodyUsings);
                body = body.WithArgs(body.Args.Slice(bodyUsings.Count));
            }

            // Create a matchCode statement unless the pattern is MacroName($(.._)), which always matches
            if (!(pattern_apos.HasSimpleHeadWithoutPAttrs() && pattern_apos.Target.IsId &&
                  pattern_apos.ArgCount == 1 && pattern_apos[0].Equals(LNode.Call(CodeSymbols.Substitute, LNode.List(LNode.Call(CodeSymbols.DotDot, LNode.List(LNode.Id((Symbol)"_"))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator))))
            {
                // Note: the body is already preprocessed; #noLexicalMacros prevents double-processing
                body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call((Symbol)"matchCode", LNode.List(LNode.Id((Symbol)"#node"), LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Case, LNode.List(pattern)), LNode.Call((Symbol)"#noLexicalMacros", LNode.List(body.AsList(S.Braces))))).SetStyle(NodeStyle.StatementBlock))).SetStyle(NodeStyle.Special), LNode.Call(CodeSymbols.Return, LNode.List(LNode.Literal(null))))).SetStyle(NodeStyle.StatementBlock);
            }

            return(LNode.Call((Symbol)"compileTime", LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(usingDirectives).Add(LNode.Call(LNode.List().Add(lmAttribute).AddRange(attrs).Add(LNode.Id(CodeSymbols.Public)).Add(LNode.Id(CodeSymbols.Static)), CodeSymbols.Fn, LNode.List(LNode.Id((Symbol)"LNode"), macroName, LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Id((Symbol)"LNode"), LNode.Id((Symbol)"#node"))), LNode.Call(CodeSymbols.Var, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.ColonColon, LNode.List(LNode.Id((Symbol)"global"), LNode.Id((Symbol)"LeMP"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"IMacroContext"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"#context"))))), body)))).SetStyle(NodeStyle.StatementBlock))).SetStyle(NodeStyle.Special));
        }