public static FunctionDeclaration AddHardwiredFunction( string name, Module module, TypeDefinition returnType, params string[] parameters) { var res = new FunctionDeclaration(name, returnType, new Block(module.Block, module), parameters) { IsInternal = true }; return(res); }
/// <summary> /// Create a score to create a best fit for a function given a parameter list. /// </summary> /// <param name="func">The function to check the parameters for</param> /// <param name="parameters">The list of parameters</param> /// <returns>A score (see remarks). In case of -1 no match is possible (see cases in code)</returns> /// <remarks> /// How the score is calculated: /// * Start with a score of 0 /// * For each parameter /// ** If IsVar and types match exactly --> +1000 (super match) /// ** If ByValue and types match exactly --> + 1000 (only checked for simple types) /// ** If ByValue and types are compatible (e.g. INTEGER can be assigned to REAL) --> +1 /// In the unlikely event of having more than 1000 parameters, this algorithm might fail. /// </remarks> private static int GenerateFunctionParameterScore(FunctionDeclaration func, IReadOnlyList <CallParameter> parameters) { int paramNo = 0; int score = 0; var procParams = func.Block.Declarations.OfType <ProcedureParameterDeclaration>().ToArray(); if (parameters.Count != procParams.Length) { return(-1); // will never match } foreach (var procedureParameter in procParams) { if (procedureParameter.IsVar) { if (!GenerateVarParameterCount(parameters[paramNo], procedureParameter, ref score)) { return(-1); } } else if (procedureParameter.Type.Type.HasFlag(BaseTypes.Simple) && procedureParameter.Type.Name == parameters[paramNo].TypeName) { score += 1000; } else if (!procedureParameter.Type.IsAssignable(parameters[paramNo].TargetType)) { return(-1); } else { score++; // match as assignable --> small increment } paramNo++; } return(score); }
private void DeclareStandardFunctions() { foreach (var function in _hardwiredFunctions) { Block.Procedures.Add(FunctionDeclaration.AddHardwiredFunction(function.Name, this, function.Type == null ? SimpleTypeDefinition.VoidType : Block.LookupType(function.Type), function.ParameterTypes)); } Assembly asm = null; var sysAsm = Assembly.Load("Oberon0.System"); asm = sysAsm; // reached only if no exception foreach (var type in asm.GetExportedTypes()) { if (type.GetCustomAttribute <Oberon0LibraryAttribute>() != null) { LoadLibraryMembers(type); } } }
#pragma warning disable CS3001 // Argument type is not CLS-compliant private FunctionDeclaration LookupFunction(string procedureName, IToken token, IReadOnlyList <CallParameter> callParameters) #pragma warning restore CS3001 // Argument type is not CLS-compliant { var b = this; FunctionDeclaration resFunc = null; // try to find the function with the best match (score) (e.g. ABS(REAL) and ABS(INTEGER) share the same function name // of not found on current block level, move up (until root) to find something appropriate. int score = -1; while (b != null) { var res = b.Procedures.Where(x => x.Name == procedureName); foreach (var func in res) { int newScore = GenerateFunctionParameterScore(func, callParameters); if (newScore <= score) { continue; } resFunc = func; score = newScore; } if (score >= 0) { break; // found } b = b.Parent; } if (resFunc == null) { var parameterList = new List <ProcedureParameterDeclaration>(callParameters.Count); int n = 0; parameterList.AddRange( callParameters.Select( expression => new ProcedureParameterDeclaration("param_" + n++, this, expression.TargetType, false))); string prototype = FunctionDeclaration.BuildPrototype( procedureName, SimpleTypeDefinition.VoidType, parameterList.ToArray()); if (Module.CompilerInstance != null) { Module.CompilerInstance.Parser.NotifyErrorListeners( token, $"No procedure/function with prototype '{prototype}' found", null); } else { throw new InvalidOperationException($"No procedure/function with prototype '{prototype}' found"); } } return(resFunc); }