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(); }
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); }
//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]); }
//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); }
//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; } }
//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); }
//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; } }