Exemple #1
0
            public void ShouldBeAppliedIfFunctionDoesNotEndWithReturn()
            {
                const string name    = "test";
                var          funcAst = new AstMemberFunction(name, new List <Parameter>(), new Position(0, 0));

                funcAst.Expressions.Add(
                    new AstFunctionCall("println", new List <AstExpression>
                {
                    new AstBinaryMathOperation(BinaryMath.Plus,
                                               new AstIntegerConstant(5, null),
                                               new AstIntegerConstant(5, null),
                                               null)
                }, null));
                funcAst.Expressions.Add(
                    new AstFunctionCall("println", new List <AstExpression>
                {
                    new AstStringConstant("hello world", null)
                }, null)
                    );
                var klass = new AstClass(name, null);

                klass.Functions.Add(funcAst);
                var env = new ScriptEnvironment(new OperationCodeFactory(), new ValueFactory());

                Compiler.Compile(env,
                                 new AstRoot(new Position(0, 0))
                {
                    Classes = { klass }
                });
                Assert.Equal(typeof(Return),
                             env.Classes[GetGlobalName(name)].Functions[name].Code.Last().Op.GetType());
            }
Exemple #2
0
            public void ShouldBeAppliedIfFunctionIsEmpty()
            {
                const string name    = "test";
                var          funcAst = new AstMemberFunction(name, new List <Parameter>(), new Position(0, 0));
                var          klass   = new AstClass(name, null);

                klass.Functions.Add(funcAst);
                var env = new ScriptEnvironment(new OperationCodeFactory(), new ValueFactory());

                Compiler.Compile(env,
                                 new AstRoot(new Position(0, 0))
                {
                    Classes = { klass }
                });
                Assert.Equal(typeof(Return),
                             env.Classes[GetGlobalName(name)].Functions[name].Code.Last().Op.GetType());
            }
        public SemanticAtom Visit(AstClass n)
        {
            var baseClassUtilizedType = n.ClassExtension?.Accept(this) as UtilizedType;
            var c = new Class(n.Name, baseClassUtilizedType, n.Location);

            AddToGlobalUtilization(baseClassUtilizedType, s => { c.BaseClass = s as Class; });

            foreach (var v in n.ClassDeclarationList.OfType <Property>())
            {
                var p = (ClassProperty)v.Accept(this);

                if (c.Properties.ContainsKey(p.Name))
                {
                    Globals.Errors.Add($"[{p.DeclarationLocation.StartLine}, {p.DeclarationLocation.StartColumn}] Property ({p.Name}) is already defined in {c.Name}.");
                }
                else
                {
                    c.Properties.Add(p.Name, p);
                }
            }

            foreach (var m in n.ClassDeclarationList.OfType <Method>())
            {
                var method = (ClassMethod)m.Accept(this);
                method.OwnerClass = c;

                if (c.Methods.ContainsKey(method.Name))
                {
                    Globals.Errors.Add($"[{method.DeclarationLocation.StartLine}, {method.DeclarationLocation.StartColumn}] Method ({method.Name}) is already defined in {c.Name}.");
                }
                else
                {
                    c.Methods.Add(method.Name, method);
                }
            }

            AddToTypeTable(c);

            return(c);
        }
Exemple #4
0
        public void Visit(AstClass n)
        {
            Helpers.Write(_tab);
            Helpers.WriteColor("class ", ConsoleColor.DarkCyan, ConsoleColor.Black);
            Helpers.WriteColor(n.Name, ConsoleColor.Green, ConsoleColor.Black);

            n.ClassExtension?.Accept(this);

            Helpers.WriteLine(" { ");
            Tab();
            foreach (var v in n.ClassDeclarationList.OfType <Property>())
            {
                v.Accept(this);
                Helpers.WriteLine();
            }
            foreach (var m in n.ClassDeclarationList.OfType <Method>())
            {
                m.Accept(this);
                Helpers.WriteLine();
            }
            Untab();
            Helpers.WriteLine($"{_tab}}}");
        }
        public void Visit(AstClass n)
        {
            Helpers.WriteLine($"{_tab}{n.Text} ({n.Name}) [{n.Location.StartLine}, {n.Location.StartColumn}]");
            Tab();
            n.ClassExtension?.Accept(this);

            Helpers.WriteLine($"{_tab}Variables");
            Tab();
            foreach (var v in n.ClassDeclarationList.OfType <Property>())
            {
                v.Accept(this);
            }
            Untab();

            Helpers.WriteLine($"{_tab}Methods");
            Tab();
            foreach (var m in n.ClassDeclarationList.OfType <Method>())
            {
                m.Accept(this);
            }
            Untab();

            Untab();
        }
        AstClass FlattenClass(AstClass astClass, List <string> parentSources, IEnumerable <AstBlockMember> parentItems)
        {
            AstClass result;

            if (_flattenedClasses.TryGetValue(astClass, out result))
            {
                return(result);
            }

            var partials = new List <AstClass>();

            foreach (var item in parentItems)
            {
                var cd = item as AstClass;
                if (cd != null && cd.Modifiers.HasFlag(Modifiers.Partial) && cd.Name.Symbol == astClass.Name.Symbol)
                {
                    if (astClass.OptionalGeneric != null && cd.OptionalGeneric == null ||
                        cd.OptionalGeneric != null && astClass.OptionalGeneric == null)
                    {
                        continue;
                    }

                    if (astClass.OptionalGeneric != null &&
                        astClass.OptionalGeneric.Parameters.Count != cd.OptionalGeneric.Parameters.Count)
                    {
                        continue;
                    }

                    partials.Add(cd);
                }
            }

            Modifiers modifiers     = 0;
            string    comment       = null;
            var       attributes    = new List <AstAttribute>();
            var       swizzlerTypes = new List <AstExpression>();
            var       baseTypes     = new List <AstExpression>();
            var       items         = new List <AstBlockMember>();

            foreach (var part in partials)
            {
                modifiers |= part.Modifiers;
                comment    = comment ?? part.DocComment;
                attributes.AddRange(part.Attributes);
                swizzlerTypes.AddRange(part.Swizzlers);
                baseTypes.AddRange(part.Bases);
                items.AddRange(part.Members);
            }

            IReadOnlyList <AstIdentifier> genericParameters  = null;
            IReadOnlyList <AstConstraint> genericConstraints = null;

            if (astClass.OptionalGeneric != null)
            {
                genericParameters  = astClass.OptionalGeneric.Parameters;
                genericConstraints = astClass.OptionalGeneric.Constraints;
            }

            foreach (var part in partials)
            {
                if (part.Type != astClass.Type)
                {
                    Log.Error(part.Name.Source, ErrorCode.E0000, "All partials must be either 'class', 'struct' or 'interface'");
                }

                var partProtection = part.Modifiers & Modifiers.ProtectionModifiers;
                if (partProtection != 0 && partProtection != (modifiers & Modifiers.ProtectionModifiers))
                {
                    Log.Error(part.Name.Source, ErrorCode.E3025, "Partial class cannot have conflicting protection modifier");
                }

                if (part.Modifiers.HasFlag(Modifiers.Sealed) && modifiers.HasFlag(Modifiers.Abstract))
                {
                    Log.Error(part.Name.Source, ErrorCode.E0000, "Partial class cannot specify 'sealed', because it is declared 'abstract' somewhere else");
                }
                else if (part.Modifiers.HasFlag(Modifiers.Abstract) && modifiers.HasFlag(Modifiers.Sealed))
                {
                    Log.Error(part.Name.Source, ErrorCode.E0000, "Partial class cannot specify 'abstract', because it is declared 'sealed' somewhere else");
                }

                if (part.OptionalCondition != null)
                {
                    Log.Error(part.Name.Source, ErrorCode.E0000, "Partial class does not support 'extern(CONDITION)'");
                }

                if (part.OptionalGeneric != null && part != astClass)
                {
                    for (int i = 0; i < genericParameters.Count; i++)
                    {
                        if (part.OptionalGeneric.Parameters[i].Symbol != genericParameters[i].Symbol)
                        {
                            Log.Error(part.Name.Source, ErrorCode.E3027, "Partial generic class must use the same type parameter names in the same order");
                        }
                    }

                    if (part.OptionalGeneric.Constraints.Count != 0)
                    {
                        // TODO: C# does not have this limitation
                        if (genericConstraints.Count == 0)
                        {
                            genericConstraints = part.OptionalGeneric.Constraints;
                        }
                        else
                        {
                            Log.Error(part.Name.Source, ErrorCode.E3027, "Only one of the partials may specify generic constraints");
                        }
                    }
                }
            }

            result = new AstClass(
                comment, attributes, modifiers, null,
                astClass.Type, astClass.Name, baseTypes,
                astClass.OptionalGeneric != null
                    ? new AstGenericSignature(genericParameters, genericConstraints)
                    : null,
                items, swizzlerTypes);

            foreach (var part in partials)
            {
                parentSources.Add(part.Name.Source.FullPath);

                if (_flattenedClasses.ContainsKey(part))
                {
                    Log.Error(part.Name.Source, ErrorCode.E0000, "Found more than one partial master definition for: " + part.Name.Symbol);
                    continue;
                }

                _flattenedClasses.Add(part, result);
            }

            return(result);
        }
Exemple #7
0
 public void Visit(AstClass n)
 {
     // Unneeded.
     throw new NotImplementedException();
 }
 public override bool Visit(AstClass node)
 {
     Log(node.ToString());
     return true;
 }
Exemple #9
0
        private void CompileClass(AstClass node, Syt syt, StringBuilder sb)
        {
            syt.Add(Ksyte.Class, node.StName, node.StName);

            CompileRecursive(node.RgclassDecl, syt, sb);

            foreach (var astSubroutine in node.Rgsubroutine)
            {
                Ksyte ksyte;
                switch (astSubroutine.Ksubroutine)
                {
                    case Ksubroutine.Constructor: ksyte = Ksyte.Constructor; break;
                    case Ksubroutine.MemberFunction: ksyte = Ksyte.MemberFunction; break;
                    case Ksubroutine.StaticFunction: ksyte = Ksyte.StaticFunction; break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
                syt.Add(ksyte, astSubroutine.StName, null);
            }
            CompileRecursive(node.Rgsubroutine, syt, sb);
        }
Exemple #10
0
        void PopulateClass(AstClass astClass, DataType result)
        {
            var parameterizedType = Parameterize(result);
            var fieldInitializers = new List <AstExpression>();
            var deferredActions   = new List <Action>();

            parameterizedType.AssignBaseType();
            parameterizedType.Base?.PopulateMembers();

            foreach (var it in result.Interfaces)
            {
                it.PopulateMembers();
            }

            // Create dummies for members
            foreach (var item in astClass.Members)
            {
                if (item is AstClassMember)
                {
                    var m = (AstClassMember)item;
                    if (!_compiler.Environment.Test(((item as AstNamedMember)?.Name ?? astClass.Name).Source, m.OptionalCondition))
                    {
                        continue;
                    }
                }

                switch (item.MemberType)
                {
                case AstMemberType.Method:
                {
                    var md = item as AstMethod;

                    ClassType gt = null;
                    if (md.OptionalGenericSignature != null)
                    {
                        gt = new ClassType(md.Name.Source, parameterizedType, md.DocComment, Modifiers.Private | Modifiers.Static | Modifiers.Generated, md.Name.Symbol);
                        CreateGenericSignature(gt, md.OptionalGenericSignature, md.Modifiers.HasFlag(Modifiers.Override) || md.OptionalInterfaceType != null);
                    }

                    var pl = _compiler.CompileParameterList(gt ?? parameterizedType, md.Parameters, deferredActions);
                    var rt = _resolver.GetType(gt ?? parameterizedType, md.ReturnType);
                    var me = new Method(md.Name.Source, result, md.DocComment, GetMemberModifiers(md.Name.Source, parameterizedType, md.Modifiers), md.Name.Symbol, gt, rt, pl);
                    result.Methods.Add(me);

                    if (md.Attributes.Count > 0)
                    {
                        EnqueueAttributes(me, x => me.SetAttributes(_compiler.CompileAttributes(parameterizedType, md.Attributes)));
                    }

                    gt?.Methods.Add(me);

                    EnqueueCompiler(new FunctionCompiler(_compiler, me, parameterizedType, md.OptionalBody));

                    if (md.OptionalInterfaceType != null)
                    {
                        var it = _resolver.GetType(parameterizedType, md.OptionalInterfaceType);

                        if (!it.IsInvalid)
                        {
                            var im = TryImplementMethod(it, me);

                            if (im == null)
                            {
                                Log.Error(md.OptionalInterfaceType.Source, ErrorCode.E0000, "Method " + (me.UnoName + me.Parameters.BuildString()).Quote() + " does not exist in interface " + it.Quote());
                            }
                            else
                            {
                                me.SetImplementedMethod(im);
                            }
                        }
                    }
                    break;
                }

                case AstMemberType.Constructor:
                {
                    var md   = item as AstConstructor;
                    var pl   = _compiler.CompileParameterList(parameterizedType, md.Parameters, deferredActions);
                    var ctor = new Constructor(md.Source, result, md.DocComment, md.Modifiers, pl);

                    if (md.Attributes.Count > 0)
                    {
                        EnqueueAttributes(ctor, x => ctor.SetAttributes(_compiler.CompileAttributes(parameterizedType, md.Attributes)));
                    }

                    var fc = new FunctionCompiler(_compiler, ctor, parameterizedType, md.OptionalBody);
                    EnqueueCompiler(fc);

                    if (ctor.IsStatic)
                    {
                        if (result.Initializer != null)
                        {
                            Log.Error(ctor.Source, ErrorCode.E3002, parameterizedType.Quote() + " already has a static constructor");
                        }

                        result.Initializer = ctor;
                    }
                    else
                    {
                        ctor.Modifiers = GetMemberModifiers(md.Source, parameterizedType, md.Modifiers);
                        result.Constructors.Add(ctor);
                    }

                    if (md.OptionalBody != null)
                    {
                        ctor.SetBody(new Scope(ctor.Source));
                    }

                    if (md.CallType == AstConstructorCallType.This && parameterizedType.IsStruct && md.CallArguments.Count == 0)
                    {
                        ctor.Body.Statements.Add(new StoreThis(ctor.Source, new Default(ctor.Source, parameterizedType)));
                    }
                    else if (md.CallType != AstConstructorCallType.None)
                    {
                        if (ctor.Body == null)
                        {
                            Log.Error(md.Source, ErrorCode.E0000, ctor.Quote() + " cannot call constructor without method body");
                        }
                        else if (md.CallType != AstConstructorCallType.Base || parameterizedType.Base != DataType.Invalid)
                        {
                            _enqueuedActions.Add(() =>
                                {
                                    var bt = md.CallType == AstConstructorCallType.Base ? parameterizedType.Base : parameterizedType;
                                    bt.PopulateMembers();

                                    Constructor callCtor;
                                    Expression[] callArgs;
                                    if (!fc.TryResolveConstructorOverload(md.Source, bt.Constructors, md.CallArguments, out callCtor, out callArgs))
                                    {
                                        Log.Error(md.Source, ErrorCode.E3003, bt.Quote() + " does not have a constructor that matches this argument list");
                                    }
                                    else
                                    {
                                        ctor.Body.Statements.Add(new CallConstructor(md.Source, callCtor, callArgs));
                                    }
                                });
                        }
                    }
                    else if (!ctor.IsStatic &&
                             parameterizedType.Base != null &&
                             parameterizedType.TypeType != TypeType.Struct &&
                             ctor.Body != null)
                    {
                        _enqueuedActions.Add(() =>
                            {
                                Constructor callCtor;
                                Expression[] callArgs;
                                if (!fc.TryResolveConstructorOverload(md.Source, parameterizedType.Base.Constructors, AstArgument.Empty, out callCtor, out callArgs))
                                {
                                    Log.Error(md.Source, ErrorCode.E3004, "Base class " + parameterizedType.Base.Quote() + " does not have a default constructor");
                                }
                                else
                                {
                                    ctor.Body.Statements.Add(new CallConstructor(md.Source, callCtor, callArgs));
                                }
                            });
                    }
                    break;
                }

                case AstMemberType.Finalizer:
                {
                    var fd        = item as AstFinalizer;
                    var pl        = _compiler.CompileParameterList(parameterizedType, fd.Parameters, deferredActions);
                    var finalizer = new Finalizer(fd.Source, result, fd.DocComment, fd.Modifiers, pl);

                    if (fd.Attributes.Count > 0)
                    {
                        EnqueueAttributes(finalizer, x => finalizer.SetAttributes(_compiler.CompileAttributes(parameterizedType, fd.Attributes)));
                    }

                    if (result.Finalizer != null)
                    {
                        Log.Error(fd.Source, ErrorCode.E3002, parameterizedType.Quote() + " already has a finalizer");
                    }

                    result.Finalizer = finalizer;
                    EnqueueCompiler(new FunctionCompiler(_compiler, finalizer, parameterizedType, fd.OptionalBody));
                    break;
                }

                case AstMemberType.Property:
                {
                    var pd   = item as AstProperty;
                    var dt   = _resolver.GetType(parameterizedType, pd.ReturnType);
                    var prop = new Property(pd.Name.Source, pd.DocComment, GetMemberModifiers(pd.Name.Source, parameterizedType, pd.Modifiers), pd.Name.Symbol, result, dt);
                    result.Properties.Add(prop);

                    bool hasImplicitImplementation = false;

                    // Implicit implementation
                    if (!prop.IsAbstract)
                    {
                        if (pd.Get != null && pd.Get.OptionalBody == null ||
                            pd.Set != null && pd.Set.OptionalBody == null)
                        {
                            if (pd.Set != null && pd.Set.OptionalBody == null && (pd.Get == null || pd.Get?.OptionalBody != null))
                            {
                                if (!prop.IsExtern)
                                {
                                    Log.Error(pd.Set.Source, ErrorCode.E3042, prop.Quote(".set") + " must declare a body because it is not marked abstract or extern. Automatically implemented properties must define both get and set accessors");
                                }
                            }
                            else if (pd.Get != null && pd.Get.OptionalBody == null && (pd.Set == null || pd.Set?.OptionalBody != null))
                            {
                                if (!prop.IsExtern)
                                {
                                    Log.Error(pd.Get.Source, ErrorCode.E3041, prop.Quote(".get") + " must declare a body because it is not marked abstract or extern. Automatically implemented properties must define both get and set accessors");
                                }
                            }
                            else
                            {
                                prop.CreateImplicitField(prop.Source);

                                var getScope = new Scope(pd.Get.Source);
                                prop.CreateGetMethod(pd.Get.Source, GetAccessorModifiers(pd.Get.Source, prop, pd.Get.Modifiers) | Modifiers.Generated, getScope);

                                var setScope  = new Scope(pd.Set.Source);
                                var setMethod = prop.CreateSetMethod(pd.Set.Source, GetAccessorModifiers(pd.Set.Source, prop, pd.Set.Modifiers) | Modifiers.Generated, setScope);
                                var propIndex = result.Properties.Count - 1;

                                _enqueuedActions.Add(() =>
                                    {
                                        parameterizedType.PopulateMembers();

                                        var obj   = prop.Modifiers.HasFlag(Modifiers.Static) ? null : new This(prop.Source, parameterizedType).Address;
                                        var field = parameterizedType.Properties[propIndex].ImplicitField;

                                        getScope.Statements.Add(
                                            new Return(pd.Get.Source, new LoadField(pd.Get.Source, obj, field)));
                                        setScope.Statements.Add(
                                            new StoreField(pd.Set.Source, obj, field, new LoadArgument(pd.Set.Source, setMethod, 0)));
                                    });

                                hasImplicitImplementation = true;
                            }
                        }
                    }

                    if (pd.Attributes.Count > 0)
                    {
                        EnqueueAttributes(prop,
                                          x =>
                            {
                                prop.SetAttributes(_compiler.CompileAttributes(parameterizedType, pd.Attributes));
                                prop.GetMethod?.SetAttributes(prop.Attributes);
                                prop.SetMethod?.SetAttributes(prop.Attributes);
                                prop.ImplicitField?.SetAttributes(prop.Attributes);
                            });
                    }

                    if (!hasImplicitImplementation)
                    {
                        if (pd.Get != null)
                        {
                            EnqueueCompiler(new FunctionCompiler(_compiler, prop.CreateGetMethod(pd.Get.Source, GetAccessorModifiers(pd.Get.Source, prop, pd.Get.Modifiers)), parameterizedType, pd.Get.OptionalBody));
                        }
                        if (pd.Set != null)
                        {
                            EnqueueCompiler(new FunctionCompiler(_compiler, prop.CreateSetMethod(pd.Set.Source, GetAccessorModifiers(pd.Set.Source, prop, pd.Set.Modifiers)), parameterizedType, pd.Set.OptionalBody));
                        }
                    }

                    if (pd.OptionalInterfaceType != null)
                    {
                        var it = _compiler.NameResolver.GetType(parameterizedType, pd.OptionalInterfaceType);

                        if (!it.IsInvalid)
                        {
                            var im = TryImplementProperty(it, prop);

                            if (im == null)
                            {
                                Log.Error(pd.OptionalInterfaceType.Source, ErrorCode.E0000, "Property " + prop.UnoName.Quote() + " does not exist in interface " + it.Quote());
                            }
                            else
                            {
                                prop.SetImplementedProperty(im);
                            }
                        }
                    }
                    break;
                }

                case AstMemberType.Field:
                {
                    var f  = item as AstField;
                    var dt = _compiler.NameResolver.GetType(parameterizedType, f.ReturnType);

                    if (f.FieldModifiers.HasFlag(FieldModifiers.Const))
                    {
                        var m = new Literal(f.Name.Source, result, f.Name.Symbol, f.DocComment, GetMemberModifiers(f.Name.Source, parameterizedType, f.Modifiers), dt, f.InitValue);
                        result.Literals.Add(m);

                        if (f.Attributes.Count > 0)
                        {
                            EnqueueAttributes(m, x => m.SetAttributes(_compiler.CompileAttributes(parameterizedType, f.Attributes)));
                        }

                        if (f.InitValue == null)
                        {
                            Log.Error(f.Name.Source, ErrorCode.E3007, "'const' fields must provide a constant value");
                        }
                        else
                        {
                            deferredActions.Add(() => m.Value = _compiler.CompileConstant(f.InitValue, parameterizedType, dt).Value);
                        }
                    }
                    else
                    {
                        var m = new Field(f.Name.Source, result, f.Name.Symbol, f.DocComment, GetMemberModifiers(f.Name.Source, parameterizedType, f.Modifiers), f.FieldModifiers, dt);
                        fieldInitializers.Add(f.InitValue);
                        result.Fields.Add(m);

                        if (f.Attributes.Count > 0)
                        {
                            EnqueueAttributes(m, x => m.SetAttributes(_compiler.CompileAttributes(parameterizedType, f.Attributes)));
                        }
                    }
                    break;
                }

                case AstMemberType.Operator:
                {
                    var od = item as AstOperator;
                    var rt = _resolver.GetType(parameterizedType, od.ReturnType);
                    var pl = _compiler.CompileParameterList(parameterizedType, od.Parameters, deferredActions);
                    var op = new Operator(od.Source, result, od.Operator, od.DocComment, GetMemberModifiers(od.Source, parameterizedType, od.Modifiers), rt, pl);
                    result.Operators.Add(op);

                    if (od.Attributes.Count > 0)
                    {
                        EnqueueAttributes(op, x => op.SetAttributes(_compiler.CompileAttributes(parameterizedType, od.Attributes)));
                    }

                    EnqueueCompiler(new FunctionCompiler(_compiler, op, parameterizedType, od.OptionalBody));
                    break;
                }

                case AstMemberType.Converter:
                {
                    var cd   = item as AstConverter;
                    var rt   = _resolver.GetType(parameterizedType, cd.TargetType);
                    var pl   = _compiler.CompileParameterList(parameterizedType, cd.Parameters, deferredActions);
                    var type = cd.Modifiers.HasFlag(Modifiers.Implicit) ? CastModifier.Implicit : CastModifier.Explicit;
                    var cast = new Cast(cd.TargetType.Source, result, type, cd.DocComment, GetMemberModifiers(cd.TargetType.Source, parameterizedType, cd.Modifiers), rt, pl);
                    result.Casts.Add(cast);

                    if (cd.Attributes.Count > 0)
                    {
                        EnqueueAttributes(cast, x => cast.SetAttributes(_compiler.CompileAttributes(parameterizedType, cd.Attributes)));
                    }

                    EnqueueCompiler(new FunctionCompiler(_compiler, cast, parameterizedType, cd.OptionalBody));
                    break;
                }

                case AstMemberType.Indexer:
                {
                    var id      = item as AstIndexer;
                    var rt      = _resolver.GetType(parameterizedType, id.ReturnType);
                    var pl      = _compiler.CompileParameterList(parameterizedType, id.Parameters, deferredActions);
                    var indexer = new Property(id.Source, id.DocComment, GetMemberModifiers(id.Source, parameterizedType, id.Modifiers), "Item", result, rt, pl);
                    result.Properties.Add(indexer);

                    if (id.Attributes.Count > 0)
                    {
                        EnqueueAttributes(indexer,
                                          x =>
                            {
                                indexer.SetAttributes(_compiler.CompileAttributes(parameterizedType, id.Attributes));
                                indexer.GetMethod?.SetAttributes(indexer.Attributes);
                                indexer.SetMethod?.SetAttributes(indexer.Attributes);
                            });
                    }

                    if (id.Get != null)
                    {
                        EnqueueCompiler(new FunctionCompiler(_compiler, indexer.CreateGetMethod(id.Get.Source, GetAccessorModifiers(id.Get.Source, indexer, id.Get.Modifiers)), parameterizedType, id.Get.OptionalBody));
                    }
                    if (id.Set != null)
                    {
                        EnqueueCompiler(new FunctionCompiler(_compiler, indexer.CreateSetMethod(id.Set.Source, GetAccessorModifiers(id.Set.Source, indexer, id.Set.Modifiers)), parameterizedType, id.Set.OptionalBody));
                    }

                    if (id.OptionalInterfaceType != null)
                    {
                        var it = _resolver.GetType(parameterizedType, id.OptionalInterfaceType);

                        if (!it.IsInvalid)
                        {
                            var im = TryImplementProperty(it, indexer);

                            if (im == null)
                            {
                                Log.Error(id.OptionalInterfaceType.Source, ErrorCode.E0000, "Indexer 'this" + indexer.Parameters.BuildString("[", "]") + "' does not exist in interface " + it.Quote());
                            }
                            else
                            {
                                indexer.SetImplementedProperty(im);
                            }
                        }
                    }
                    break;
                }

                case AstMemberType.Event:
                {
                    var ed = item as AstEvent;
                    var dt = _resolver.GetType(parameterizedType, ed.DelegateType);

                    if (dt.IsInvalid)
                    {
                        break;
                    }

                    if (!dt.IsDelegate)
                    {
                        Log.Error(ed.Name.Source, ErrorCode.E3012, "Events must have delegate type. " + dt + " is a " + dt.TypeType);
                    }

                    var ev = new Event(ed.Name.Source, ed.DocComment, GetMemberModifiers(ed.Name.Source, parameterizedType, ed.Modifiers), result, dt, ed.Name.Symbol);
                    result.Events.Add(ev);

                    if (ed.Attributes.Count > 0)
                    {
                        EnqueueAttributes(ev,
                                          x =>
                            {
                                ev.SetAttributes(_compiler.CompileAttributes(parameterizedType, ed.Attributes));
                                ev.AddMethod?.SetAttributes(ev.Attributes);
                                ev.RemoveMethod?.SetAttributes(ev.Attributes);
                                ev.ImplicitField?.SetAttributes(ev.Attributes);
                            });
                    }

                    // Implicit implementation
                    if (ed.Add == null && ed.Remove == null)
                    {
                        if (!ev.IsAbstract)
                        {
                            ev.CreateImplicitField(ed.Name.Source);

                            var addScope     = new Scope(ed.Name.Source);
                            var addMethod    = ev.CreateAddMethod(ev.Source, ev.Modifiers | Modifiers.Generated, addScope);
                            var removeScope  = new Scope(ed.Name.Source);
                            var removeMethod = ev.CreateRemoveMethod(ev.Source, ev.Modifiers | Modifiers.Generated, removeScope);
                            var eventIndex   = result.Events.Count - 1;

                            _enqueuedActions.Add(() =>
                                {
                                    parameterizedType.PopulateMembers();

                                    var obj   = ev.IsStatic ? null : new This(ev.Source, parameterizedType).Address;
                                    var field = parameterizedType.Events[eventIndex].ImplicitField;

                                    addScope.Statements.Add(
                                        new StoreField(ev.Source, obj, field,
                                                       new CastOp(ev.Source, ev.ReturnType,
                                                                  _ilf.CallMethod(ev.Source, _ilf.Essentials.Delegate, "Combine",
                                                                                  new CastOp(ev.Source, _ilf.Essentials.Delegate, new LoadField(ev.Source, obj, field)),
                                                                                  new LoadArgument(ev.Source, addMethod, 0)))));
                                    removeScope.Statements.Add(
                                        new StoreField(ev.Source, obj, field,
                                                       new CastOp(ev.Source, ev.ReturnType,
                                                                  _ilf.CallMethod(ev.Source, _ilf.Essentials.Delegate, "Remove",
                                                                                  new CastOp(ev.Source, _ilf.Essentials.Delegate, new LoadField(ev.Source, obj, field)),
                                                                                  new LoadArgument(ev.Source, removeMethod, 0)))));
                                });
                        }
                        else
                        {
                            ev.CreateAddMethod(ev.Source, ev.Modifiers);
                            ev.CreateRemoveMethod(ev.Source, ev.Modifiers);
                        }

                        break;
                    }

                    if (ed.Add != null && ed.Add.Modifiers != 0 || ed.Remove != null && ed.Remove.Modifiers != 0)
                    {
                        Log.Error(ed.Name.Source, ErrorCode.E3040, "Modifiers can not be placed on event accessor declarations");
                    }

                    if (ed.Add != null)
                    {
                        EnqueueCompiler(new FunctionCompiler(_compiler, ev.CreateAddMethod(ed.Add.Source, ev.Modifiers), parameterizedType, ed.Add.OptionalBody));
                    }
                    if (ed.Remove != null)
                    {
                        EnqueueCompiler(new FunctionCompiler(_compiler, ev.CreateRemoveMethod(ed.Remove.Source, ev.Modifiers), parameterizedType, ed.Remove.OptionalBody));
                    }

                    if (ed.OptionalInterfaceType != null)
                    {
                        var it = _resolver.GetType(parameterizedType, ed.OptionalInterfaceType);

                        if (!it.IsInvalid)
                        {
                            var im = TryImplementEvent(it, ev);

                            if (im == null)
                            {
                                Log.Error(ed.OptionalInterfaceType.Source, ErrorCode.E0000, "Event " + ev.UnoName.Quote() + " does not exist in interface " + it.Quote());
                            }
                            else
                            {
                                ev.SetImplementedEvent(im);
                            }
                        }
                    }
                    break;
                }
                }

                switch (item.MemberType)
                {
                case AstMemberType.Method:
                case AstMemberType.Property:
                case AstMemberType.Indexer:
                case AstMemberType.Event:
                    switch (parameterizedType.TypeType)
                    {
                    case TypeType.Class:
                    case TypeType.Interface:
                    case TypeType.Struct:
                        continue;
                    }
                    break;

                case AstMemberType.Field:
                case AstMemberType.Constructor:
                case AstMemberType.Operator:
                case AstMemberType.Converter:
                case AstMemberType.Class:
                case AstMemberType.Enum:
                case AstMemberType.Delegate:
                    switch (parameterizedType.TypeType)
                    {
                    case TypeType.Class:
                    case TypeType.Struct:
                        continue;
                    }
                    break;

                case AstMemberType.Finalizer:
                case AstMemberType.MetaMethod:
                case AstMemberType.MetaProperty:
                case AstMemberType.NodeBlock:
                case AstMemberType.Block:
                case AstMemberType.ApplyStatement:
                    switch (parameterizedType.TypeType)
                    {
                    case TypeType.Class:
                        continue;
                    }
                    break;
                }

                Log.Error(((item as AstNamedMember)?.Name ?? astClass.Name).Source, ErrorCode.E3013, "<" + item.MemberType + "> is not allowed in this scope");
            }

            // Compile swizzle types
            if (astClass.Swizzlers != null)
            {
                foreach (var e in astClass.Swizzlers)
                {
                    result.Swizzlers.Add(_resolver.GetType(parameterizedType, e));
                }
            }

            // Compile field initializers
            if (fieldInitializers.Count > 0)
            {
                _enqueuedActions.Add(() => CompileFieldInitializers(result, parameterizedType, fieldInitializers));
            }

            // Create default constructor in non-static classes
            if (result.IsClass && !result.IsStatic && result.Constructors.Count == 0)
            {
                var ctor = new Constructor(parameterizedType.Source, parameterizedType, null,
                                           (parameterizedType.IsAbstract ? Modifiers.Protected : Modifiers.Public) | Modifiers.Generated,
                                           ParameterList.Empty, new Scope(parameterizedType.Source));
                result.Constructors.Add(ctor);
                _enqueuedActions.Add(() =>
                {
                    parameterizedType.AssignBaseType();
                    parameterizedType.Base.PopulateMembers();

                    Constructor callCtor  = null;
                    Expression[] callArgs = null;
                    if (parameterizedType.Base != DataType.Invalid && !new FunctionCompiler(_compiler, parameterizedType).TryResolveConstructorOverload(parameterizedType.Source, parameterizedType.Base.Constructors, AstArgument.Empty, out callCtor, out callArgs))
                    {
                        Log.Error(parameterizedType.Source, ErrorCode.E3001, parameterizedType.Base.Quote() + " does not have a default constructor");
                    }
                    else
                    {
                        ctor.Body.Statements.Add(new CallConstructor(ctor.Source, callCtor, callArgs));
                    }
                });
            }

            // Resolve overridden members
            foreach (var m in result.Methods)
            {
                m.SetOverriddenMethod(TryOverrideMethod(m));

                if (m.IsGenericDefinition)
                {
                    if (m.ImplementedMethod != null || m.OverriddenMethod != null)
                    {
                        // Inherit base generic constraints
                        var baseParams = (m.OverriddenMethod ?? m.ImplementedMethod).GenericDefinition.GenericParameters;

                        for (int i = 0; i < m.GenericParameters.Length; i++)
                        {
                            var baseParam = baseParams[i];
                            var thisParam = m.GenericParameters[i];

                            baseParam.AssignBaseType();
                            thisParam.AssignBaseType();
                            thisParam.SetBase(baseParam.Base);
                            thisParam.SetConstraintType(baseParam.ConstraintType);
                            thisParam.SetInterfaces(baseParam.Interfaces);

                            if (baseParam.Constructors.Count > 0)
                            {
                                thisParam.Constructors.Add(new Constructor(baseParam.Constructors[0].Source, thisParam, null,
                                                                           Modifiers.Public | Modifiers.Generated | Modifiers.Extern, ParameterList.Empty));
                            }
                        }
                    }

                    Parameterize(m.Source, m, m.GenericParameters);
                }
            }

            foreach (var m in result.Properties)
            {
                m.SetOverriddenProperty(TryOverrideProperty(m));
            }
            foreach (var m in result.Events)
            {
                m.SetOverriddenEvent(TryOverrideEvent(m));
            }

            if (!result.IsInterface && result.Interfaces.Length > 0)
            {
                ImplementInterfaces(result);
            }

            _compiler.BlockBuilder.PopulateBlock(astClass, result.Block);

            foreach (var action in deferredActions)
            {
                action();
            }
        }
 public SemanticAtom Visit(AstClass n)
 {
     throw new NotImplementedException();
 }
Exemple #12
0
        public void CreateClass(AstClass astClass, Namescope parent, IEnumerable <AstBlockMember> parentItems)
        {
            var sources = new List <string>();

            if (astClass.Modifiers.HasFlag(Modifiers.Partial))
            {
                astClass = FlattenClass(astClass, sources, parentItems);
            }

            DataType result;

            if (_cachedClasses.TryGetValue(astClass, out result))
            {
                return;
            }

            var src       = astClass.Name.Source;
            var modifiers = GetTypeModifiers(parent, astClass.Modifiers);

            switch (astClass.Type)
            {
            case AstClassType.Struct:
                result = new StructType(src, parent, astClass.DocComment, modifiers, astClass.Name.Symbol);
                break;

            case AstClassType.Class:
                result = new ClassType(src, parent, astClass.DocComment, modifiers, astClass.Name.Symbol);
                break;

            case AstClassType.Interface:
                if (modifiers.HasFlag(Modifiers.Abstract))
                {
                    Log.Error(src, ErrorCode.E0000, "'abstract' is not valid for interface");
                }

                result = new InterfaceType(src, parent, astClass.DocComment, modifiers | Modifiers.Abstract, astClass.Name.Symbol);
                break;

            default:
                Log.Error(src, ErrorCode.I3045, "<" + astClass.Type + "> is not a class, struct or interface type");
                return;
            }

            if (parent is DataType)
            {
                (parent as DataType).NestedTypes.Add(result);
            }
            else if (parent is Namespace)
            {
                (parent as Namespace).Types.Add(result);
            }
            else
            {
                Log.Error(result.Source, ErrorCode.I3046, "<" + astClass.Type + "> is not allowed in this context");
            }

            _cachedClasses.Add(astClass, result);

            if (astClass.OptionalGeneric != null)
            {
                CreateGenericSignature(result, astClass.OptionalGeneric, false);
            }

            result.SetBlock(new Block(src, result, null, result.Modifiers & Modifiers.ProtectionModifiers, ".block"));

            foreach (var s in sources)
            {
                result.SourceFiles.Add(s);
            }

            foreach (var b in astClass.Members)
            {
                if (b is AstBlockBase)
                {
                    _compiler.AstProcessor.CreateBlock(b as AstBlockBase, result, astClass.Members);
                }
            }

            if (astClass.Attributes.Count > 0)
            {
                EnqueueAttributes(result, x =>
                {
                    result.SetAttributes(_compiler.CompileAttributes(result.Parent, astClass.Attributes));

                    // Remove default constructor if TargetSpecificType
                    if (result.HasAttribute(_ilf.Essentials.TargetSpecificTypeAttribute) &&
                        result.Constructors.Count == 1 && result.Constructors[0].IsGenerated)
                    {
                        result.Constructors.Clear();
                    }
                });
            }

            EnqueueType(result,
                        x => CompileBaseTypes(x, astClass.Bases),
                        x => PopulateClass(astClass, x));
        }
Exemple #13
0
        private AstClass ParseClass()
        {
            var _class = new AstClass();
            Expect(Ktoken.Class);

            _class.StName = Expect(Ktoken.Id).St;

            Expect(Ktoken.Lbrace);

            _class.RgclassDecl = ParseRgClassDecl().ToArray();
            _class.Rgsubroutine = ParseRgSubroutine().ToArray();

            Expect(Ktoken.Rbrace);
            Expect(Ktoken.Eof);
            return _class;
        }