/// <summary> /// <para>Create a <see cref="ReadOnlyCollection<T>"/> of <see cref="PlQueryVariables"/>.</para> /// <para>If calling ToList() all solutions of the query are generated and stored in the Collection.</para> /// </summary> /// <returns>A ReadOnlyCollection of PlQueryVariables containing all solutions of the query.</returns> /// <example> /// <code source="..\..\TestSwiPl\LinqSwiPl.cs" region="Test_multi_goal_ToList_doc" /> /// </example> public ReadOnlyCollection <PlQueryVariables> ToList() { var list = new List <PlQueryVariables>(); EraseRecords(); while (NextSolution()) { for (int i = 0; i < _queryVariables.Count; i++) { _records.Add(LibPl.PL_record(_queryVariables[i].Value.TermRef)); // to keep the PlTerms } } var qv = new PlQueryVariables(); // dummy to make the compiler happy int avIdx = _queryVariables.Count; foreach (uintptr_t recordTerm in _records) { var ptrTerm = LibPl.PL_new_term_ref(); LibPl.PL_recorded(recordTerm, ptrTerm); if (avIdx == _queryVariables.Count) { qv = new PlQueryVariables(); list.Add(qv); avIdx = 0; } //qv.Add(new PlQueryVar(GetVariableName(avIdx), new PlTerm(term))); // If this line is deleted -> update comment in PlTern(term_ref) qv.Add(new PlQueryVar(_queryVariables[avIdx].Name, new PlTerm(ptrTerm))); // If this line is deleted -> update comment in PlTern(term_ref) avIdx++; //av[avIdx++].TermRef = term_t; } return(new ReadOnlyCollection <PlQueryVariables>(list)); }
/// <summary> /// Provide the next solution to the query. Prolog exceptions are mapped to C# exceptions. /// </summary> /// <returns>return true if successful and false if there are no (more) solutions.</returns> /// <remarks> /// <para>If the query is closed it will be opened. If the last solution was generated the query will be closed.</para> /// <para>If an exception is thrown while parsing (open) the query the _qid is set to zero.</para> /// </remarks> /// <exception cref="PlException">Is thrown if <see href="http://gollem.science.uva.nl/SWI-Prolog/Manual/foreigninclude.html#PL_next_solution()">SWI-Prolog Manual PL_next_solution()</see> returns false </exception> public bool NextSolution() { if (0 == _qid) { Check.Require(!string.IsNullOrEmpty(_name), "PlQuery.NextSolution() _name is required"); IntPtr p = LibPl.PL_predicate(_name, _av.Size, _module); _qid = LibPl.PL_open_query((IntPtr)0, LibPl.PL_Q_CATCH_EXCEPTION, p, _av.A0); } int rval = LibPl.PL_next_solution(_qid); if (0 == rval) { // error uintptr_t ex; // term_t if ((ex = LibPl.PL_exception(_qid)) > 0) { _qid = 0; // to avoid an AccessViolationException on Dispose. E.g. if the query is miss spelled. var etmp = new PlException(new PlTerm(ex)); etmp.Throw(); } } if (rval <= 0) { Free(false); } return(rval > 0); }
/// <summary> /// Discards the query, but does not delete any of the data created by the query if discardData is false. /// It just invalidate qid, allowing for a new PlQuery object in this context. /// </summary> /// <remarks>see <see href="http://gollem.science.uva.nl/SWI-Prolog/Manual/foreigninclude.html#PL_cut_query()"/></remarks> /// <param name="discardData">if true all bindings of the query are destroyed</param> private void Free(bool discardData) { if (_qid > 0 && PlEngine.IsInitialized) { try { if (discardData) { // <"leider werden dann die gebundenen variablen der query wieder frei e.g. in PlCall(goal)"/> // unfortunately this statement detaches the bound variables of the query e.g. in PlCall(goal) LibPl.PL_close_query(_qid); } else { LibPl.PL_cut_query(_qid); } } catch (AccessViolationException ex) { TraceAccessViolationException(ex); } } _qid = 0; }
/// <summary> /// <para>Obtain status information on the Prolog system. The actual argument type depends on the information required. /// The parameter queryType describes what information is wanted.</para> /// <para>Returning pointers and integers as a long is bad style. The signature of this function should be changed.</para> /// <see>PlQuerySwitch</see> /// </summary> /// <example> /// <para>This sample shows how to get SWI-Prologs version number</para> /// <code source="..\..\TestSwiPl\PlQuery.cs" region="get_prolog_version_number_doc" /> /// </example> /// <param name="queryType">A <see>PlQuerySwitch</see>.</param> /// <returns>A int depending on the given queryType</returns> public static long Query(PlQuerySwitch queryType) { Check.Require(queryType != PlQuerySwitch.None, "PlQuerySwitch (None) is not valid"); return(LibPl.PL_query((uint)queryType)); }
#pragma warning disable 1573 /// <inheritdoc cref="PlQuery(string)" /> /// <summary>locating the predicate in the named module.</summary> /// <param name="module">locating the predicate in the named module.</param> public PlQuery(string module, string goal) { if (string.IsNullOrEmpty(goal)) { throw new ArgumentNullException("goal"); } _module = module; var queryString = goal; try { // call read_term(Term_of_query_string, [variable_names(VN)]). // read_term_from_atom('noun(ş,C)', T, [variable_names(Vars)]). // befor 2014 with redirected IO-Streams (PlQuery_Old_Kill_unused) var atom = new PlTerm("'" + goal.Replace("'", @"\'") + "'"); PlTerm term = PlTerm.PlVar(); PlTerm options = PlTerm.PlVar(); PlTerm variablenames = PlTerm.PlVar(); PlTerm l = PlTerm.PlTail(options); l.Append(PlTerm.PlCompound("variable_names", variablenames)); l.Close(); var args = new PlTermV(atom, term, options); if (!PlCall("read_term_from_atom", args)) { throw new PlLibException("PlCall read_term_from_atom/3 fails! goal:" + queryString); } // set list of variables and variable_names into _queryVariables foreach (PlTerm t in variablenames.ToList()) { // t[0]='=' , t[1]='VN', t[2]=_G123 _queryVariables.Add(new PlQueryVar(t[1].ToString(), t[2])); } // Build the query _name = term.Name; // is ok e.g. for listing/0. // Check.Require(term.Arity > 0, "PlQuery(PlTerm t): t.Arity must be greater than 0."); _av = new PlTermV(term.Arity); for (int index = 0; index < term.Arity; index++) { if (0 == LibPl.PL_get_arg(index + 1, term.TermRef, _av[index].TermRef)) { throw new PlException("PL_get_arg in PlQuery " + term.ToString()); } } } #if _DEBUG catch (Exception ex) { System.Diagnostics.Debug.Print(ex.Message); Console.WriteLine(ex.Message); } #endif finally { // NBT } }