Example #1
0
        public override AstNode Visit(DelegateDefinition node)
        {
            // Parse the generic signature.
            GenericSignature genericSign = node.GetGenericSignature();
            GenericPrototype genProto = GenericPrototype.Empty;
            PseudoScope protoScope = null;
            if(genericSign != null)
            {
                // Visit the generic signature.
                genericSign.Accept(this);

                // Connect the generic prototype.
                genProto = genericSign.GetPrototype();

                // Create the placeholders scope.
                protoScope = new PseudoScope(currentScope, genProto);
                node.SetGenericScope(protoScope);
            }

            // Prevent redefinition.
            ScopeMember old = currentContainer.FindType(node.GetName(), GenericPrototype.Empty);
            if(old != null)
                Error(node, "trying to redefine a delegate.");

            // Create the structure
            MemberFlags flags = node.GetFlags();
            // TODO: Check the flags.
            Class building = new Class(node.GetName(), flags, currentContainer);
            building.SetGenericPrototype(genProto);
            building.Position = node.GetPosition();
            node.SetStructure(building);

            // Add into the current scope.
            if(currentContainer.IsNamespace())
            {
                Namespace space = (Namespace)currentContainer;
                space.AddType(building);
            }
            else if(currentContainer.IsStructure() || currentContainer.IsInterface() || currentContainer.IsClass())
            {
                Structure parent = (Structure)currentContainer;
                parent.AddType(building);
            }
            else
            {
                Error(node, "unexpected place for a delegate.");
            }

            // Register the compute binding delegate.
            if(building.GetFullName() == "Chela.Compute.ComputeBinding")
                currentModule.RegisterComputeBindingDelegate(building);

            return node;
        }
Example #2
0
        private void DefineGeneratorBody(FunctionDefinition node)
        {
            // Get entry function.
            Function entryFunction = node.GetFunction();

            // Rebase his locals.
            entryFunction.RebaseLocals();

            // Create the generator class.
            Scope spaceScope = entryFunction.GetParentScope();
            Class generatorClass =
                new Class(GenSym(), MemberFlags.Internal, spaceScope);
            node.GeneratorClass = generatorClass;

            // Use the same generic prototype as the entry point function.
            generatorClass.SetGenericPrototype(entryFunction.GetGenericPrototype());

            // Add the generator class to the same scope as the function.
            if(spaceScope.IsClass() || spaceScope.IsStructure())
            {
                Structure parentClass = (Structure)spaceScope;
                parentClass.AddType(generatorClass);
            }
            else if(spaceScope.IsNamespace())
            {
                Namespace parentSpace = (Namespace)spaceScope;
                parentSpace.AddMember(generatorClass);
            }
            else
            {
                Error(node, "Cannot create generator class in {0}", spaceScope.GetFullName());
            }

            // Add the enumerable interface.
            Structure enumerableIface = null;
            if(node.IsEnumerable)
            {
                enumerableIface = currentModule.GetEnumerableIface();
                if(node.IsGenericIterator)
                {
                    enumerableIface = currentModule.GetEnumerableGIface();
                    GenericInstance gargs = new GenericInstance(enumerableIface.GetGenericPrototype(),
                        new IChelaType[]{node.YieldType});
                    enumerableIface = (Structure)enumerableIface.InstanceGeneric(gargs, currentModule);
                }

                generatorClass.AddInterface(enumerableIface);
            }

            // Add the enumerator interface.
            Structure enumeratorIface = currentModule.GetEnumeratorIface();
            if(node.IsGenericIterator)
            {
                enumeratorIface = currentModule.GetEnumeratorGIface();
                GenericInstance gargs = new GenericInstance(enumeratorIface.GetGenericPrototype(),
                    new IChelaType[]{node.YieldType});
                enumeratorIface = (Structure)enumeratorIface.InstanceGeneric(gargs, currentModule);
            }
            generatorClass.AddInterface(enumeratorIface);

            // Create the yielded field.
            FieldVariable yieldedValue = new FieldVariable("yielded", MemberFlags.Private, node.YieldType, generatorClass);
            generatorClass.AddField(yieldedValue);
            node.YieldedValue = yieldedValue;

            // Create the generator state variable.
            FieldVariable generatorState = new FieldVariable("state", MemberFlags.Private, ChelaType.GetIntType(), generatorClass);
            generatorClass.AddField(generatorState);
            node.GeneratorState = generatorState;

            // Encapsulate the locals in fields.
            foreach(LocalVariable local in entryFunction.GetLocals())
            {
                if(!local.IsPseudoLocal)
                    continue;

                // Variables containing arguments must be public.
                MemberFlags access = MemberFlags.Private;
                if(local.ArgumentIndex >= 0)
                    access = MemberFlags.Public;

                // Create the field to hold the state.
                FieldVariable localField = new FieldVariable(GenSym(), access, local.GetVariableType(), generatorClass);
                generatorClass.AddField(localField);
                local.ActualVariable = localField;
            }

            // Create an instance of the generator class.
            Structure generatorClassInstance = generatorClass.GetClassInstance();
            if(generatorClass.GetGenericPrototype().GetPlaceHolderCount() != 0)
            {
                // Create an instance using the same placeholders.
                GenericPrototype proto = generatorClass.GetGenericPrototype();
                int numargs = proto.GetPlaceHolderCount();
                IChelaType[] protoInstance = new IChelaType[numargs];
                for(int i = 0; i < numargs; ++i)
                    protoInstance[i] = proto.GetPlaceHolder(i);

                // Instance the generic class.
                GenericInstance instance = new GenericInstance(proto, protoInstance);
                generatorClassInstance = (Structure)generatorClassInstance.InstanceGeneric(instance, currentModule);
            }
            node.GeneratorClassInstance = generatorClassInstance;

            // Create the trivial constructor.
            Function ctor = CreateTrivialConstructor(generatorClass, generatorClassInstance);
            if(generatorClass.IsGeneric())
                ctor = FindFirstConstructor(generatorClassInstance);

            // Create a local to hold the created closure.
            LexicalScope topScope = (LexicalScope)node.GetScope();
            LocalVariable closureLocal = new LocalVariable("closure", topScope, ReferenceType.Create(generatorClassInstance));

            // Create the entry point content.
            BasicBlock entryBlock = CreateBasicBlock();
            entryBlock.SetName("entry");
            builder.SetBlock(entryBlock);

            // Create the closure and store it in his local.
            builder.CreateNewObject(generatorClassInstance, ctor, 0);
            builder.CreateStoreLocal(closureLocal);

            // Load the closure.
            builder.CreateLoadLocal(closureLocal);

            // Store the arguments into the closure.
            FunctionPrototype prototype = node.GetPrototype();
            AstNode argument = prototype.GetArguments();
            byte index = 0;
            while(argument != null)
            {
                FunctionArgument argNode = (FunctionArgument) argument;

                // TODO: Forbid ref, out, stream arguments here.

                // Store the argument in the closure.
                LocalVariable argVar = argNode.GetVariable();
                if(argVar != null)
                {
                    // Load the closure
                    builder.CreateDup1();

                    // Load the argument.
                    builder.CreateLoadArg(index);

                    // Store it into the field.
                    builder.CreateStoreField((FieldVariable)argVar.ActualVariable);
                }

                // Process the next argument.
                argument = argument.GetNext();
                index++;
            }

            // Encapsulate the argument variables.
            foreach(ArgumentVariable argVar in node.ArgumentVariables)
            {
                if(!argVar.IsPseudoArgument)
                    continue;

                // Create the argument field.
                FieldVariable argField = new FieldVariable(GenSym(), MemberFlags.Public, argVar.GetVariableType(), generatorClass);
                generatorClass.AddField(argField);
                argVar.ActualVariable = argField;

                // Store the self field.
                if(!currentFunction.IsStatic() && argVar.GetArgumentIndex() == 0)
                    node.GeneratorSelf = argField;

                // Load the closure.
                builder.CreateDup1();

                // Load the argument.
                builder.CreateLoadArg((byte)argVar.GetArgumentIndex());

                // Store it into the closure.
                builder.CreateStoreField(argField);
            }

            // Return the generator.
            builder.CreateRet();

            // Notify the yields about their states.
            int stateIndex = 2;
            foreach(ReturnStatement yieldStmtn in node.Yields)
            {
                yieldStmtn.YieldState = stateIndex;
                stateIndex += 2;
            }

            // Implement IEnumerator.
            if(node.IsEnumerable)
            {
                // Create the object GetEnumerator method.
                CreateGenerator_GetEnumerator(node, currentModule.GetEnumeratorIface(), false);

                // Create the generic GetEnumerator method
                if(node.IsGenericIterator)
                    CreateGenerator_GetEnumerator(node, enumeratorIface, true);
            }

            // Create the Current property.
            CreateGenerator_Current(node, false);
            if(node.IsGenericIterator)
                CreateGenerator_Current(node, true);

            // Create the Reset method.
            CreateGenerator_Reset(node);

            // Create the MoveNext method.
            Function moveNext = CreateGenerator_MoveNext(node);

            // Create the Dispose method.
            CreateGenerator_Dispose(node, moveNext);

            // Fix the inheritance.
            generatorClass.FixInheritance();
        }
Example #3
0
        public override AstNode Visit(ClassDefinition node)
        {
            // Check the partial flag.
            bool isPartial = (node.GetFlags() & MemberFlags.ImplFlagMask) == MemberFlags.Partial;

            // Add the parent static flag.
            if(currentContainer.IsStatic())
            {
                MemberFlags oldInstance = node.GetFlags() & MemberFlags.InstanceMask;
                if(oldInstance == MemberFlags.Static || oldInstance == MemberFlags.Instanced)
                {
                    MemberFlags flags = node.GetFlags() & ~MemberFlags.InstanceMask;
                    node.SetFlags(flags | MemberFlags.Static);
                }
                else
                    Error(node, "static class member cannot be {0}.", oldInstance.ToString().ToLower());
            }

            // Static classes are automatically sealed.
            if((node.GetFlags() & MemberFlags.InstanceMask) == MemberFlags.Static)
            {
                MemberFlags flags = node.GetFlags() & ~MemberFlags.InheritanceMask;
                node.SetFlags(flags | MemberFlags.Sealed);
            }

            // Parse the generic signature.
            GenericSignature genericSign = node.GetGenericSignature();
            GenericPrototype genProto = GenericPrototype.Empty;
            PseudoScope protoScope = null;
            if(genericSign != null)
            {
                // Visit the generic signature.
                genericSign.Accept(this);

                // Connect the generic prototype.
                genProto = genericSign.GetPrototype();

                // Create the placeholders scope.
                protoScope = new PseudoScope(currentScope, genProto);
                node.SetGenericScope(protoScope);
            }

            // Prevent redefinition.
            ScopeMember old = currentContainer.FindType(node.GetName(), genProto);
            if(old != null && (!isPartial || !old.IsClass()))
                Error(node, "trying to redefine a class.");

            // Create the structure
            Class clazz = (Class)old;
            if(clazz != null)
            {
                if(!clazz.IsPartial())
                    Error(node, "incompatible partial class definitions.");
            }
            else
            {
                clazz = new Class(node.GetName(), node.GetFlags(), currentContainer);
                clazz.Position = node.GetPosition();
                clazz.SetGenericPrototype(genProto);
            }
            node.SetStructure(clazz);

            // Use the prototype scope.
            if(protoScope != null)
                PushScope(protoScope);

            // Register type maps.
            string fullName = clazz.GetFullName();
            IChelaType alias;
            if(typeMaps.TryGetValue(fullName, out alias))
                currentModule.RegisterTypeMap(alias, clazz);

            // Register type association.
            IChelaType assoc;
            if(assocClasses.TryGetValue(fullName, out assoc))
                currentModule.RegisterAssociatedClass(assoc, clazz);

            // Array base class is special.
            if(fullName == "Chela.Lang.Array")
                currentModule.RegisterArrayClass(clazz);
            else if(fullName == "Chela.Lang.Attribute")
                currentModule.RegisterAttributeClass(clazz);
            else if(fullName == "Chela.Lang.ValueType")
                currentModule.RegisterValueTypeClass(clazz);
            else if(fullName == "Chela.Lang.Enum")
                currentModule.RegisterEnumClass(clazz);
            else if(fullName == "Chela.Lang.Type")
                currentModule.RegisterTypeClass(clazz);
            else if(fullName == "Chela.Lang.Delegate")
                currentModule.RegisterDelegateClass(clazz);
            else if(fullName == "Chela.Compute.StreamHolder")
                currentModule.RegisterStreamHolderClass(clazz);
            else if(fullName == "Chela.Compute.StreamHolder1D")
                currentModule.RegisterStreamHolder1DClass(clazz);
            else if(fullName == "Chela.Compute.StreamHolder2D")
                currentModule.RegisterStreamHolder2DClass(clazz);
            else if(fullName == "Chela.Compute.StreamHolder3D")
                currentModule.RegisterStreamHolder3DClass(clazz);
            else if(fullName == "Chela.Compute.UniformHolder")
                currentModule.RegisterUniformHolderClass(clazz);

            // Add into the current scope.
            if(currentContainer.IsNamespace())
            {
                Namespace space = (Namespace)currentContainer;
                if(old == null)
                    space.AddType(clazz);
            }
            else if(currentContainer.IsStructure() || currentContainer.IsInterface() || currentContainer.IsClass())
            {
                Structure parent = (Structure)currentContainer;
                if(old == null)
                    parent.AddType(clazz);
            }
            else
            {
                Error(node, "unexpected place for a class.");
            }

            // Push the class unsafe.
            if(clazz.IsUnsafe())
                PushUnsafe();

            // Update the scope.
            PushScope(clazz);

            // Visit the building children.
            VisitList(node.GetChildren());

            // Restore the scope.
            PopScope();

            // Restore the scope.
            if(protoScope != null)
                PopScope();

            // Pop the class unsafe.
            if(clazz.IsUnsafe())
                PopUnsafe();

            return node;
        }