Пример #1
0
        void NewType()
        {
            scanner.InjectBlock();
            var extends = false;
            var opened = false;

            if (la.kind == 45) {
            Get();
            } else if (la.kind == 48) {
            Get();
            extends=true;
            } else if (la.kind == 49) {
            Get();
            opened=true;
            } else SynErr(114);
            var nt = new ElaNewtype(t) { Extends=extends,Opened=opened };
            if (la.kind == 1) {
            Get();
            nt.Prefix = t.val;
            Expect(27);
            Expect(2);
            nt.Name = t.val;
            } else if (la.kind == 2) {
            Get();
            nt.Name = t.val;
            } else SynErr(115);
            nt.And = Program.Types;
            Program.Types = nt;

            if (la.kind == 51 || la.kind == 57) {
            if (la.kind == 57) {
                Get();
                if (la.kind == 23) {
                    Get();
                }
                NewTypeConstructor(nt);
                while (la.kind == 23) {
                    Get();
                    NewTypeConstructor(nt);
                }
            } else {
                Get();
                nt.Header = true;
                Expect(1);
                nt.Flags = ProcessAttribute(t.val,nt.Flags);
                while (la.kind == 1) {
                    Get();
                    nt.Flags = ProcessAttribute(t.val,nt.Flags);
                }
            }
            }
            if (la.kind == 65) {
            Get();
            var tt = t;
            string pf;
            string nm;

            while (la.kind == 1 || la.kind == 2) {
                if (la.kind == 1) {
                    Get();
                    pf=t.val;
                    Expect(27);
                    Expect(2);
                    nm=t.val;
                } else {
                    Get();
                    pf=null;nm=t.val;
                }
                var ci = new ElaClassInstance(tt);
                ci.And = Program.Instances;
                Program.Instances = ci;
                ci.TypeName = nt.Name;
                ci.TypePrefix = nt.Prefix;
                ci.TypeClassPrefix = pf;
                ci.TypeClassName = nm;

            }
            }
            EndBlock();
        }
Пример #2
0
        void NewTypeConstructor(ElaNewtype nt)
        {
            var flags = ElaVariableFlags.None;
            var exp = default(ElaExpression);

            OpExpr1(out exp);
            if (la.kind == 51) {
            Get();
            Expect(1);
            flags = ProcessAttribute(t.val,flags);
            while (la.kind == 1) {
                Get();
                flags = ProcessAttribute(t.val,flags);
            }
            }
            nt.Constructors.Add(exp);
            nt.ConstructorFlags.Add(flags);
        }
Пример #3
0
        //Checks if a constructor is actually a list constructor which implementation can be optimized.
        private bool IsCons(ElaExpression exp, ElaNewtype t)
        {
            if (exp.Type != ElaNodeType.Juxtaposition)
                return false;

            var j = (ElaJuxtaposition)exp;

            //We check that a constructor is in the form 'a :: a'
            return j.Parameters.Count == 2
                && j.Parameters[0].Type == ElaNodeType.NameReference
                && j.Parameters[1].Type == ElaNodeType.NameReference
                && !Char.IsUpper(j.Parameters[0].GetName()[0])
                && !Char.IsUpper(j.Parameters[1].GetName()[0]);
        }
Пример #4
0
 //An entry method for type compilation. Ensures that types ('type') are
 //always compiled before type extensions ('data').
 private void CompileTypes(ElaNewtype v, LabelMap map)
 {
     CompileHeaders(v);
     CompileTypeOnly(v, map);
     CompileDataOnly(v, map);
 }
Пример #5
0
        //This method only compiles types declared through 'type' keyword
        //and not type extensions ('data' declarations).
        private void CompileTypeOnly(ElaNewtype nt, LabelMap map)
        {
            var v = nt;

            while (v != null)
            {
                if (!v.Extends && !v.Header)
                    CompileTypeBody(v, map);

                v = v.And;
            }
        }
Пример #6
0
        //Main method for type compilation
        private void CompileTypeBody(ElaNewtype v, LabelMap map)
        {
            //We need to obtain typeId for a type
            var tc = -1;
            var sca = -1;
            var flags = v.Flags;

            //A body may be null only if this is a built-in type
            if (!v.HasBody && v.Extends)
                AddError(ElaCompilerError.ExtendsNoDefinition, v, v.Name);
            else if (!v.HasBody)
            {
                tc = (Int32)TCF.GetTypeCode(v.Name);
                tc = tc == 0 ? -1 : tc;
                sca = AddVariable("$$" + v.Name, v, flags | ElaVariableFlags.ClosedType, tc);

                //OK, type is built-in
                if (tc > 0)
                {
                    //We add a special variable that contains a global type ID
                    cw.Emit(Op.PushI4, tc);
                    PopVar(sca);
                }
            }
            else
            {
                var tf = flags;

                if (!v.Opened)
                    tf |= ElaVariableFlags.ClosedType;

                sca = v.Extends ? AddVariable() : AddVariable("$$" + v.Name, v, tf, -1);
            }

            //Type is already declared within the same module (types from different
            //modules can shadow each, so this is perfectly OK).
            if (!v.Extends && frame.InternalTypes.ContainsKey(v.Name))
            {
                AddError(ElaCompilerError.TypeAlreadyDeclared, v, v.Name);
                frame.InternalTypes.Remove(v.Name);
            }

               if (v.Prefix != null && !v.Extends)
                AddError(ElaCompilerError.InvalidTypeDefinition, v);

            if (!v.Extends)
                frame.InternalTypes.Add(v.Name, tc);

            AddLinePragma(v);

            //-1 mean "this" module (considered by default).
            var typeModuleId = -1;

            //Add a type var for a non built-in type with a body
            if (tc == -1)
            {
                //Add a special variable with global type ID which will be calculated at run-time
                if (v.Extends)
                {
                    var sv = EmitSpecName(v.Prefix, "$$" + v.Name, v, ElaCompilerError.UndefinedType, out typeModuleId);

                    //We can only extend type that are explicitly declared as open
                    if ((sv.Flags & ElaVariableFlags.ClosedType) == ElaVariableFlags.ClosedType)
                        AddError(ElaCompilerError.UnableExtendOpenType, v, v.Name);
                }
                else
                    cw.Emit(Op.Typeid, AddString(v.Name));

                PopVar(sca);

                if (v.HasBody)
                {
                    for (var i = 0; i < v.Constructors.Count; i++)
                    {
                        var c = v.Constructors[i];
                        var cf = v.ConstructorFlags[i];
                        cf = cf == ElaVariableFlags.None ? flags : cf|flags;
                        CompileConstructor(v.Name, sca, c, cf, typeModuleId);
                    }
                }
            }
            else
                cw.Emit(Op.Nop);
        }
Пример #7
0
        //Builds a list of attribute headers for types
        private void CompileHeaders(ElaNewtype v)
        {
            var t = v;
            var oldt = default(ElaNewtype);

            while (t != null)
            {
                if (t.Header)
                {
                    if (oldt == null || t.Extends != oldt.Extends || t.Opened != oldt.Opened)
                        AddError(ElaCompilerError.TypeHeaderNotConnected, t, t.Name);
                    else
                        oldt.Flags = t.Flags;
                }
                else
                    oldt = t;

                t = t.And;
            }
        }