//Only in effect when extended debug info mode is on. private void AddVarPragma(string name, int address, int offset, ElaVariableFlags flags, int data) { if (debug) { pdb.AddVarSym(name, address, offset, (Int32)flags, data); } }
//A main method to add named variables. private int AddVariable(string name, ElaExpression exp, ElaVariableFlags flags, int data) { //Hiding is allowed in parameter list if ((flags & ElaVariableFlags.Parameter) == ElaVariableFlags.Parameter) { CurrentScope.Locals.Remove(name); } else if (CurrentScope.Locals.ContainsKey(name)) { //But for other cases hiding in the same scope is not allowed CurrentScope.Locals.Remove(name); AddError(ElaCompilerError.NoHidingSameScope, exp, name.TrimStart('$')); } CurrentScope.Locals.Add(name, new ScopeVar(flags, currentCounter, data)); //Additional debug info is only generated when a debug flag is set. if (debug && exp != null) { cw.Emit(Op.Nop); AddVarPragma(name, currentCounter, cw.Offset, flags, data); AddLinePragma(exp); } return(AddVariable()); }
internal Global(string name, ElaVariableFlags flags, int address, int data) { Name = name; Address = address; Data = data; Flags = flags; }
internal void AddFlagsAndData(string name, ElaVariableFlags flags, int data) { var sv = Locals[name]; sv = new ScopeVar(sv.Flags | flags, sv.Address, data); Locals[name] = sv; }
internal void RemoveFlags(string name, ElaVariableFlags flags) { var sv = Locals[name]; sv = new ScopeVar(sv.Flags ^ flags, sv.Address, sv.Data); Locals[name] = sv; }
internal ExportVarData(ElaBuiltinKind kind, ElaVariableFlags flags, int data, int moduleHandle, int address) { Kind = kind; ModuleHandle = moduleHandle; Address = address; Flags = flags; Data = data; }
//Generic compilation logic for a constructor, compiles both functions and constants. //Parameter sca is an address of variable that contains real type ID. private void CompileConstructor(string typeName, int sca, ElaExpression exp, ElaVariableFlags flags, int typeModuleId) { //Constructor name var name = String.Empty; switch (exp.Type) { case ElaNodeType.NameReference: { var n = (ElaNameReference)exp; name = n.Name; if (!n.Uppercase) { AddError(ElaCompilerError.InvalidConstructor, n, FormatNode(n)); } else { CompileConstructorConstant(typeName, n, sca, flags, typeModuleId); } } break; case ElaNodeType.Juxtaposition: { var n = (ElaJuxtaposition)exp; if (n.Target.Type == ElaNodeType.NameReference) { var m = (ElaNameReference)n.Target; name = m.Name; //If a name is uppercase or if this is an infix/postfix/prefix constructor //we assume that this is a correct case and is a constructor function if (m.Uppercase || (Format.IsSymbolic(m.Name) && n.Parameters.Count <= 2)) { CompileConstructorFunction(typeName, m.Name, n, sca, flags, typeModuleId); break; } } AddError(ElaCompilerError.InvalidConstructor, exp, FormatNode(exp)); } break; default: AddError(ElaCompilerError.InvalidConstructor, exp, FormatNode(exp)); break; } //To prevent redundant errors CurrentScope.Locals.Remove("$$$$" + name); var ab = AddVariable("$$$$" + name, exp, flags | ElaVariableFlags.CompilerGenerated, -1); cw.Emit(Op.Ctorid, frame.InternalConstructors.Count - 1); PopVar(ab); }
//Generic compilation logic for a constructor, compiles both functions and constants. //Parameter sca is an address of variable that contains real type ID. private void CompileConstructor(string typeName, int sca, ElaExpression exp, ElaVariableFlags flags, int typeModuleId) { //Constructor name var name = String.Empty; switch (exp.Type) { case ElaNodeType.NameReference: { var n = (ElaNameReference)exp; name = n.Name; if (!n.Uppercase) AddError(ElaCompilerError.InvalidConstructor, n, FormatNode(n)); else CompileConstructorConstant(typeName, n, sca, flags, typeModuleId); } break; case ElaNodeType.Juxtaposition: { var n = (ElaJuxtaposition)exp; if (n.Target.Type == ElaNodeType.NameReference) { var m = (ElaNameReference)n.Target; name = m.Name; //If a name is uppercase or if this is an infix/postfix/prefix constructor //we assume that this is a correct case and is a constructor function if (m.Uppercase || (Format.IsSymbolic(m.Name) && n.Parameters.Count <= 2)) { CompileConstructorFunction(typeName, m.Name, n, sca, flags, typeModuleId); break; } } AddError(ElaCompilerError.InvalidConstructor, exp, FormatNode(exp)); } break; default: AddError(ElaCompilerError.InvalidConstructor, exp, FormatNode(exp)); break; } //To prevent redundant errors CurrentScope.Locals.Remove("$$$$" + name); var ab = AddVariable("$$$$" + name, exp, flags, -1); cw.Emit(Op.Ctorid, frame.InternalConstructors.Count - 1); PopVar(ab); }
//Compiles a simple parameterless constructor private void CompileConstructorConstant(string typeName, ElaNameReference exp, int sca, ElaVariableFlags flags, int typeModuleId) { frame.InternalConstructors.Add(new ConstructorData { TypeName = typeName, Name = exp.Name, Code = -1, TypeModuleId = typeModuleId }); AddLinePragma(exp); cw.Emit(Op.Ctorid, frame.InternalConstructors.Count - 1); PushVar(sca); cw.Emit(Op.Newtype0); var a = AddVariable(exp.Name, exp, ElaVariableFlags.TypeFun|flags, 0); PopVar(a); }
private ElaVariableFlags ProcessAttribute(string attribute, ElaVariableFlags flags) { if (attribute == "private") { return(flags | ElaVariableFlags.Private); } else if (attribute == "qualified") { return(flags | ElaVariableFlags.Qualified); } else if (attribute == "nowarnings") { return(flags | ElaVariableFlags.NoWarnings); } else { AddError(ElaParserError.UnknownAttribute, attribute); return(flags); } }
//A main method to add named variables. private int AddVariable(string name, ElaExpression exp, ElaVariableFlags flags, int data) { //Hiding is allowed in parameter list if ((flags & ElaVariableFlags.Parameter) == ElaVariableFlags.Parameter) CurrentScope.Locals.Remove(name); else if (CurrentScope.Locals.ContainsKey(name)) { //But for other cases hiding in the same scope is not allowed CurrentScope.Locals.Remove(name); AddError(ElaCompilerError.NoHindingSameScope, exp, name.TrimStart('$')); } CurrentScope.Locals.Add(name, new ScopeVar(flags, currentCounter, data)); //Additional debug info is only generated when a debug flag is set. if (debug && exp != null) { cw.Emit(Op.Nop); AddVarPragma(name, currentCounter, cw.Offset, flags, data); AddLinePragma(exp); } return AddVariable(); }
//Compiles a type constructor private void CompileConstructorFunction(string typeName, string name, ElaJuxtaposition juxta, int sca, ElaVariableFlags flags, int typeModuleId) { Label funSkipLabel; int address; LabelMap newMap; var pars = new List<String>(); var len = juxta.Parameters.Count; AddLinePragma(juxta); CompileFunctionProlog(name, len, juxta.Line, juxta.Column, out funSkipLabel, out address, out newMap); var sys = new int[len]; var types = new ScopeVar[len]; var bangs = new bool[len]; //Here we have to validate all constructor parameters for (var i = 0; i < len; i++) { var ce = juxta.Parameters[i]; sys[i] = AddVariable(); if (bangs[i] = IsBang(ce)) cw.Emit(Op.Force); PopVar(sys[i]); //This can be type a type constraint so we should compile here type check logic if (ce.Type == ElaNodeType.Juxtaposition) { var jc = (ElaJuxtaposition)ce; //First we check if a constraint is actually valid if (IsInvalidConstructorParameterConstaint(jc)) AddError(ElaCompilerError.InvalidConstructorParameter, juxta, FormatNode(ce), name); else if (jc.Target.Type == ElaNodeType.NameReference) { //A simple direct type reference var nt = (ElaNameReference)jc.Target; PushVar(sys[i]); types[i] = TypeCheckConstructor(name, null, nt.Name, nt, false); pars.Add(jc.Parameters[0].GetName()); } else if (jc.Target.Type == ElaNodeType.FieldReference) { //A type is qualified with a module alias var fr = (ElaFieldReference)jc.Target; PushVar(sys[i]); types[i] = TypeCheckConstructor(name, fr.TargetObject.GetName(), fr.FieldName, fr, false); pars.Add(jc.Parameters[0].GetName()); } } else if (ce.Type == ElaNodeType.NameReference && !IsInvalidConstructorParameter(ce)) { pars.Add(ce.GetName()); types[i] = ScopeVar.Empty; } else AddError(ElaCompilerError.InvalidConstructorParameter, juxta, FormatNode(ce), name); } frame.InternalConstructors.Add(new ConstructorData { TypeName = typeName, Name = name, Code = -1, Parameters = pars, TypeModuleId = typeModuleId }); //For optimization purposes we use a simplified creation algorythm for constructors //with 1 and 2 parameters if (len == 1) PushVar(sys[0]); else if (len == 2) { PushVar(sys[0]); PushVar(sys[1]); } else { cw.Emit(Op.Newtup, len); for (var i = 0; i < len; i++) { PushVar(sys[i]); cw.Emit(Op.Tupcons, i); } } var ctid = frame.InternalConstructors.Count - 1; cw.Emit(Op.Ctorid, ctid); //Refering to captured name, need to recode its address PushVar((Byte.MaxValue & sca) + 1 | (sca << 8) >> 8); if (len == 1) cw.Emit(Op.Newtype1); else if (len == 2) cw.Emit(Op.Newtype2); else cw.Emit(Op.Newtype); CompileFunctionEpilog(name, len, address, funSkipLabel); var a = AddVariable(name, juxta, ElaVariableFlags.TypeFun|ElaVariableFlags.Function|flags, len); PopVar(a); //We need to add special variable that would indicate that a constructor parameter //should be strictly evaluated. Used when inlining constructors. This variable is for //metadata only, it is never initialized. for (var i = 0; i < bangs.Length; i++) { if (bangs[i]) { CurrentScope.Locals.Remove("$-!" + i + name); //To prevent redundant errors AddVariable("$-!" + i + name, juxta, ElaVariableFlags.None, -1); } } //We need to add special variable that would store type check information. //This information is used when inlining constructors. for (var i = 0; i < types.Length; i++) { var sv = types[i]; //There is a type constraint, we have to memoize it for inlining if (!sv.IsEmpty()) { CurrentScope.Locals.Remove("$-" + i + name); //To prevent redundant errors var av = AddVariable("$-" + i + name, juxta, ElaVariableFlags.None, -1); //This ScopeVar was obtained in a different scope, we have to patch it here if ((sv.Flags & ElaVariableFlags.External) == ElaVariableFlags.External) PushVar(sv); //No need to patch an external else { //Roll up one scope sv.Address = ((sv.Address & Byte.MaxValue) - 1) | (sv.Address >> 8) << 8; PushVar(sv); } PopVar(av); } } //To prevent redundant errors CurrentScope.Locals.Remove("$-" + name); CurrentScope.Locals.Remove("$--" + name); //We add special variables that can be used lately to inline this constructor call. var consVar = AddVariable("$-" + name, juxta, flags, len); var typeVar = AddVariable("$--" + name, juxta, flags, len); cw.Emit(Op.Ctorid, ctid); PopVar(consVar); PushVar(sca); PopVar(typeVar); }
//Compiles a type constructor private void CompileConstructorFunction(string typeName, string name, ElaJuxtaposition juxta, int sca, ElaVariableFlags flags, int typeModuleId) { Label funSkipLabel; int address; LabelMap newMap; var pars = new List <String>(); var len = juxta.Parameters.Count; AddLinePragma(juxta); CompileFunctionProlog(name, len, juxta.Line, juxta.Column, out funSkipLabel, out address, out newMap); var sys = new int[len]; var types = new ScopeVar[len]; var bangs = new bool[len]; //Here we have to validate all constructor parameters for (var i = 0; i < len; i++) { var ce = juxta.Parameters[i]; sys[i] = AddVariable(); if (bangs[i] = IsBang(ce)) { cw.Emit(Op.Force); } PopVar(sys[i]); //This can be type a type constraint so we should compile here type check logic if (ce.Type == ElaNodeType.Juxtaposition) { var jc = (ElaJuxtaposition)ce; //First we check if a constraint is actually valid if (IsInvalidConstructorParameterConstaint(jc)) { AddError(ElaCompilerError.InvalidConstructorParameter, juxta, FormatNode(ce), name); } else if (jc.Target.Type == ElaNodeType.NameReference) { //A simple direct type reference var nt = (ElaNameReference)jc.Target; PushVar(sys[i]); types[i] = TypeCheckConstructor(name, null, nt.Name, nt, false); pars.Add(jc.Parameters[0].GetName()); } else if (jc.Target.Type == ElaNodeType.FieldReference) { //A type is qualified with a module alias var fr = (ElaFieldReference)jc.Target; PushVar(sys[i]); types[i] = TypeCheckConstructor(name, fr.TargetObject.GetName(), fr.FieldName, fr, false); pars.Add(jc.Parameters[0].GetName()); } } else if (ce.Type == ElaNodeType.NameReference && !IsInvalidConstructorParameter(ce)) { pars.Add(ce.GetName()); types[i] = ScopeVar.Empty; } else { AddError(ElaCompilerError.InvalidConstructorParameter, juxta, FormatNode(ce), name); } } frame.InternalConstructors.Add(new ConstructorData { TypeName = typeName, Name = name, Code = -1, Parameters = pars, TypeModuleId = typeModuleId }); //For optimization purposes we use a simplified creation algorythm for constructors //with 1 and 2 parameters if (len == 1) { PushVar(sys[0]); } else if (len == 2) { PushVar(sys[0]); PushVar(sys[1]); } else { cw.Emit(Op.Newtup, len); for (var i = 0; i < len; i++) { PushVar(sys[i]); cw.Emit(Op.Tupcons, i); } } var ctid = frame.InternalConstructors.Count - 1; cw.Emit(Op.Ctorid, ctid); //Refering to captured name, need to recode its address PushVar((Byte.MaxValue & sca) + 1 | (sca << 8) >> 8); if (len == 1) { cw.Emit(Op.Newtype1); } else if (len == 2) { cw.Emit(Op.Newtype2); } else { cw.Emit(Op.Newtype); } CompileFunctionEpilog(name, len, address, funSkipLabel); var a = AddVariable(name, juxta, ElaVariableFlags.TypeFun | ElaVariableFlags.Function | flags, len); PopVar(a); //We need to add special variable that would indicate that a constructor parameter //should be strictly evaluated. Used when inlining constructors. This variable is for //metadata only, it is never initialized. for (var i = 0; i < bangs.Length; i++) { if (bangs[i]) { CurrentScope.Locals.Remove("$-!" + i + name); //To prevent redundant errors AddVariable("$-!" + i + name, juxta, ElaVariableFlags.CompilerGenerated, -1); } } //We need to add special variable that would store type check information. //This information is used when inlining constructors. for (var i = 0; i < types.Length; i++) { var sv = types[i]; //There is a type constraint, we have to memoize it for inlining if (!sv.IsEmpty()) { CurrentScope.Locals.Remove("$-" + i + name); //To prevent redundant errors var av = AddVariable("$-" + i + name, juxta, ElaVariableFlags.CompilerGenerated, -1); //This ScopeVar was obtained in a different scope, we have to patch it here if ((sv.Flags & ElaVariableFlags.External) == ElaVariableFlags.External) { PushVar(sv); //No need to patch an external } else { //Roll up one scope sv.Address = ((sv.Address & Byte.MaxValue) - 1) | (sv.Address >> 8) << 8; PushVar(sv); } PopVar(av); } } //To prevent redundant errors CurrentScope.Locals.Remove("$-" + name); CurrentScope.Locals.Remove("$--" + name); //We add special variables that can be used lately to inline this constructor call. var consVar = AddVariable("$-" + name, juxta, flags | ElaVariableFlags.CompilerGenerated, len); var typeVar = AddVariable("$--" + name, juxta, flags | ElaVariableFlags.CompilerGenerated, len); cw.Emit(Op.Ctorid, ctid); PopVar(consVar); PushVar(sca); PopVar(typeVar); }
//Only in effect when extended debug info mode is on. private void AddVarPragma(string name, int address, int offset, ElaVariableFlags flags, int data) { if (debug) pdb.AddVarSym(name, address, offset, (Int32)flags, data); }
public void AddVariable(string name, ElaBuiltinKind kind, ElaVariableFlags flags, int data, int moduleHandle, int address) { variables.Remove(name); variables.Add(name, new ExportVarData(kind, flags, data, moduleHandle, address)); }
internal ScopeVar(ElaVariableFlags flags, int address, int data) { Address = address; Flags = flags; Data = data; }
//Compiles a simple parameterless constructor private void CompileConstructorConstant(string typeName, ElaNameReference exp, int sca, ElaVariableFlags flags, int typeModuleId) { frame.InternalConstructors.Add(new ConstructorData { TypeName = typeName, Name = exp.Name, Code = -1, TypeModuleId = typeModuleId }); AddLinePragma(exp); cw.Emit(Op.Ctorid, frame.InternalConstructors.Count - 1); PushVar(sca); cw.Emit(Op.Newtype0); var a = AddVariable(exp.Name, exp, ElaVariableFlags.TypeFun | flags, 0); PopVar(a); }
private ElaVariableFlags ProcessAttribute(string attribute, ElaVariableFlags flags) { if (attribute == "private") return flags | ElaVariableFlags.Private; else if (attribute == "qualified") return flags | ElaVariableFlags.Qualified; else { AddError(ElaParserError.UnknownAttribute, attribute); return flags; } }