/// <summary> /// Call a function /// </summary> /// <param name="tree">Tree to be executed</param> /// <returns>The result of the function</returns> private KObject Call(KermitAST tree) { string fName = tree.GetChild(0).Text; KFunction function = GetFunction(fName); if (function == null) { ThrowHelper.NameNotExists(fName, StackTrace); //Listener.Error($"Function name {fName} is not defined"); return(null); } int argCount = tree.ChildCount - 1; if (!function.IsNative && (function.Value.Arguments == null && argCount > 0 || function.Value.Arguments != null && argCount != function.Value.Arguments.Count)) { ThrowHelper.TypeError($"Function {fName} takes {argCount} arguments", StackTrace); //Listener.Error($"Function {fName}: argument list mismatch"); return(null); } List <KLocal> param = new List <KLocal>(argCount); var arguments = function.Value.Arguments.Values.GetEnumerator(); for (int i = 0; i < argCount; ++i) { arguments.MoveNext(); string name = function.IsNative ? "" : arguments.Current.Name; KermitAST argumentTree = (KermitAST)tree.GetChild(i + 1); KLocal var; if (argumentTree.Type == KermitParser.REF) { var = new KGlobal(name, argumentTree.GetChild(0).Text, _currentSpace); } else { KObject argumentValue = Execute(argumentTree); var = new KLocal(name, argumentValue); } param.Add(var); } return(CallFunction(function, param)); }
/// <summary> /// Execute a function inside the interpreter /// </summary> /// <param name="function">Function to be executed</param> /// <param name="parameters">Parameters to be passed to a function</param> /// <returns>The result of the function</returns> public override KObject CallFunction(KFunction function, List <KLocal> parameters) { FunctionSymbol fSymbol = function.Value; FunctionSpace fSpace = new FunctionSpace(fSymbol); MemorySpace savedSpace = _currentSpace; _currentSpace = fSpace; if (!function.IsNative) { parameters.ForEach(x => fSpace[x.Name] = x); } KObject result = null; _stack.Push(fSpace); try { if (function.IsNative) { FunctionCallbackInfo cInfo = new FunctionCallbackInfo(parameters, this); ((NativeFunctionSymbol)fSymbol).NativeFunction.SafeExecute(cInfo); result = cInfo.ReturnValue.Value; } else { Execute(fSymbol.BlockAst); } } catch (ReturnValue returnValue) { result = returnValue.Value; } finally { _currentSpace = savedSpace; } _stack.Pop(); return(result); }
/// <summary> /// Call a function /// </summary> /// <param name="function">The function to be called</param> /// <param name="parameters">The parameters to be passed to the function</param> /// <returns>The result of the call</returns> public abstract KObject CallFunction(KFunction function, List <KLocal> parameters);
private List <KFunction> CreateSqlFunctionsInDb(KDataStoreProject kDataStoreProject, string connectionString, string sqlText) { var functions = new List <KFunction>(); var scriptGen = new Sql120ScriptGenerator(new SqlScriptGeneratorOptions { IncludeSemicolons = true }); using (var sqlConnection = new SqlConnection(connectionString)) { sqlConnection.Open(); var parser = new TSql120Parser(false); var script2 = parser.Parse(new StringReader(sqlText), out var errors) as TSqlScript; if (errors.Count > 0) { var errorList = new StringBuilder(); foreach (var error in errors) { errorList.AppendLine($"{error.Message}<br/>"); } throw new ApplicationException(errorList.ToString()); } for (var batchNo = 0; batchNo < script2.Batches.Count; batchNo++) { var batch2 = script2.Batches[batchNo]; //get the doc above the stored proc var betweenBatchStart = 0; if (batchNo > 0) { betweenBatchStart = script2.Batches[batchNo - 1].StartOffset + script2.Batches[batchNo - 1].FragmentLength; } var betweenBatchEnd = batch2.StartOffset - 1; string batchText = null; if (betweenBatchEnd > 0) { batchText = sqlText.Substring(betweenBatchStart, betweenBatchEnd - betweenBatchStart); //clean up the doc batchText = batchText.Replace("GO", ""); batchText = batchText.Replace(Environment.NewLine, ""); batchText = batchText.Replace("\r", ""); batchText = batchText.Replace("/*", ""); batchText = batchText.Replace("*/", ""); batchText = batchText.Trim(); } foreach (var statement in batch2.Statements) { var createFunctionStatement = statement as CreateFunctionStatement; if (createFunctionStatement == null) { continue; } var viewSchemaName = createFunctionStatement.Name.SchemaIdentifier.Value; var createSchemaCommand = new SqlCommand( $@" IF NOT EXISTS (SELECT name FROM sys.schemas WHERE name = N'{viewSchemaName}') BEGIN EXEC sp_executesql N'CREATE SCHEMA {viewSchemaName}' END", sqlConnection); createSchemaCommand.ExecuteNonQuery(); scriptGen.GenerateScript(statement, out var scriptOut, out var errors2); //fixup CTE //var tempScript = scriptOut.Replace(Environment.NewLine, " ").ToUpper(); //might insert extra ; it won't hurt anything if (scriptOut.Contains(" WITH ")) { scriptOut = scriptOut.Replace(" WITH ", "; WITH "); } else if (scriptOut.Contains(Environment.NewLine + "WITH ")) { scriptOut = scriptOut.Replace(Environment.NewLine + "WITH ", ";" + Environment.NewLine + " WITH "); } var sqlCommand = new SqlCommand(scriptOut, sqlConnection); sqlCommand.ExecuteNonQuery(); var function = new KFunction(DataStoreTypes.SqlServer) { Schema = new CSchema() { SchemaName = createFunctionStatement.Name.SchemaIdentifier.Value }, FunctionName = createFunctionStatement.Name.BaseIdentifier.Value, FunctionText = scriptOut, //StoredProcedureDescription = batchText, ResultSetName = createFunctionStatement.Name.BaseIdentifier.Value + "Dto"// "ResultSet" }; /* * var oldStoredProc = kDataStoreProject.OldStoredProcedure.FirstOrDefault(s => s.StoredProcedureName == function.FunctionName); //todo: compare schema * if (oldStoredProc != null) * { * function.DerivedFrom = oldStoredProc.DerivedFrom; * } */ functions.Add(function); } } sqlConnection.Close(); } return(functions); }