//Adds a variable with NoInit flag to the current scope //This method also calculates additional flags and metadata for variables. //If a given binding if defined by pattern matching then all variables from //patterns are traversed using AddPatternVariable method. private bool AddNoInitVariable(ElaEquation exp) { var flags = exp.VariableFlags | ElaVariableFlags.NoInit; //This binding is not defined by PM if (exp.IsFunction()) { var name = exp.GetFunctionName(); if (name == null || Char.IsUpper(name[0])) { AddError(ElaCompilerError.InvalidFunctionDeclaration, exp, FormatNode(exp.Left)); return(false); } AddVariable(name, exp.Left, flags | ElaVariableFlags.Function, exp.GetArgumentNumber()); } else if (exp.Left.Type == ElaNodeType.NameReference && !((ElaNameReference)exp.Left).Uppercase) { var data = -1; if (exp.Right.Type == ElaNodeType.Builtin) { //Adding required hints for a built-in data = (Int32)((ElaBuiltin)exp.Right).Kind; flags |= ElaVariableFlags.Builtin; } else if (exp.Right.Type == ElaNodeType.Lambda) { var fun = (ElaLambda)exp.Right; flags |= ElaVariableFlags.Function; data = fun.GetParameterCount(); } else if (exp.Right.IsLiteral()) { flags |= ElaVariableFlags.ObjectLiteral; } AddVariable(exp.Left.GetName(), exp, flags, data); } else { AddPatternVariables(exp.Left); } return(true); }
//Compile an instance member. Argument classPrefix (module alias) is null if a class is //not prefixed, otherwise it should be used to lookup class members. private void CompileInstanceMember(string className, string classPrefix, ElaEquation s, LabelMap map, string currentTypePrefix, string currentType) { //Obtain a 'table' function of a class var name = s.GetLeftName(); var btVar = ObtainClassFunction(classPrefix, className, name, s.Line, s.Column); if (btVar.IsEmpty()) { AddError(ElaCompilerError.MemberInvalid, s, name, className); } var builtin = (btVar.Flags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin; var args = 0; //Here we need to understand how many arguments a class function has. //If our declaration has less arguments (allowed by Ela) we need to do //eta expansion. if (builtin) { args = BuiltinParams((ElaBuiltinKind)btVar.Data); } else { args = btVar.Data; } //First we check if this binding is simply a function reference if (!TryResolveInstanceBinding(args, s.Right, map)) { //Eta expansion should be done if a member is not a function literal //(it can be a partially applied function) or if a number of arguments //doesn't match. if (!s.IsFunction()) { EtaExpand(null, s.Right, map, args); } else if (s.GetArgumentNumber() < args) { EtaExpand(null, s, map, args); } else { CompileFunction(s, map); } } AddLinePragma(s); //It is possible if we are compiling a default instance (that can be //used to automatically generate instances). if (currentType != null) { //Depending whether this is a built-in class or a different approach is //used to add a member function. if (!builtin) { PushVar(btVar); } else { cw.Emit(Op.PushI4, (Int32)btVar.Data); } //We need to obtain a 'real' global ID of the type that we are extending. This //is done using this helper method. EmitSpecName(currentTypePrefix, "$$" + currentType, s, ElaCompilerError.UndefinedType); //Finally adding a member function. cw.Emit(Op.Addmbr); } else { var nm = "$default$" + name; //We are double binding the same default member which is not allowed within //the same module. if (globalScope.Locals.ContainsKey(nm)) { AddError(ElaCompilerError.DefaultMemberAlreadyExist, s, name, className); globalScope.Locals.Remove(name); } var flags = ElaVariableFlags.None; var data = -1; if (s.Right.Type == ElaNodeType.Builtin) { flags = ElaVariableFlags.Builtin; data = (Int32)((ElaBuiltin)s.Right).Kind; } var dv = AddVariable(nm, s, flags, data); PopVar(dv); } }
//Compile an instance member. Argument classPrefix (module alias) is null if a class is //not prefixed, otherwise it should be used to lookup class members. private void CompileInstanceMember(string className, string classPrefix, ElaEquation s, LabelMap map, string currentTypePrefix, string currentType) { //Obtain a 'table' function of a class var name = s.GetLeftName(); var btVar = ObtainClassFunction(classPrefix, className, name, s.Line, s.Column); if (btVar.IsEmpty()) AddError(ElaCompilerError.MemberInvalid, s, name, className); var builtin = (btVar.Flags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin; var args = 0; //Here we need to understand how many arguments a class function has. //If our declaration has less arguments (allowed by Ela) we need to do //eta expansion. if (builtin) args = BuiltinParams((ElaBuiltinKind)btVar.Data); else args = btVar.Data; //First we check if this binding is simply a function reference if (!TryResolveInstanceBinding(args, s.Right, map)) { //Eta expansion should be done if a member is not a function literal //(it can be a partially applied function) or if a number of arguments //doesn't match. if (!s.IsFunction()) EtaExpand(null, s.Right, map, args); else if (s.GetArgumentNumber() < args) EtaExpand(null, s, map, args); else CompileFunction(s); } AddLinePragma(s); //It is possible if we are compiling a default instance (that can be //used to automatically generate instances). if (currentType != null) { //Depending whether this is a built-in class or a different approach is //used to add a member function. if (!builtin) PushVar(btVar); else cw.Emit(Op.PushI4, (Int32)btVar.Data); //We need to obtain a 'real' global ID of the type that we are extending. This //is done using this helper method. EmitSpecName(currentTypePrefix, "$$" + currentType, s, ElaCompilerError.UndefinedType); //Finally adding a member function. cw.Emit(Op.Addmbr); } else { var nm = "$default$" + name; //We are double binding the same default member which is not allowed within //the same module. if (globalScope.Locals.ContainsKey(nm)) { AddError(ElaCompilerError.DefaultMemberAlreadyExist, s, name, className); globalScope.Locals.Remove(name); } var flags = ElaVariableFlags.None; var data = -1; if (s.Right.Type == ElaNodeType.Builtin) { flags = ElaVariableFlags.Builtin; data = (Int32)((ElaBuiltin)s.Right).Kind; } var dv = AddVariable(nm, s, flags, data); PopVar(dv); } }