()
| 102 | } |
| 103 | |
| 104 | executeQuery() { |
| 105 | let queryText = this.input.value.trim(); |
| 106 | if (!queryText) return; |
| 107 | |
| 108 | // Add to history |
| 109 | this.history.push(queryText); |
| 110 | this.historyIndex = undefined; |
| 111 | |
| 112 | // Display query |
| 113 | const queryDiv = document.createElement('div'); |
| 114 | queryDiv.className = 'repl-query'; |
| 115 | queryDiv.innerHTML = `<span class="repl-prompt">?-</span> ${this.escapeHtml(queryText)}`; |
| 116 | this.output.appendChild(queryDiv); |
| 117 | |
| 118 | // Clear input |
| 119 | this.input.value = ''; |
| 120 | |
| 121 | try { |
| 122 | // Normalize query: strip ?- prefix and ensure trailing period |
| 123 | queryText = queryText.replace(/^\?-\s*/, '').trim(); |
| 124 | if (!queryText.endsWith('.')) { |
| 125 | queryText += '.'; |
| 126 | } |
| 127 | |
| 128 | // Parse query as a program (treating it as a fact/clause) |
| 129 | // parseProgram returns an array of clauses directly |
| 130 | let clauses; |
| 131 | try { |
| 132 | clauses = parseProgram(queryText); |
| 133 | } catch (parseError) { |
| 134 | this.showError(`Parse error: ${parseError.message}`); |
| 135 | return; |
| 136 | } |
| 137 | |
| 138 | if (!clauses || clauses.length === 0) { |
| 139 | this.showError('Syntax error: Could not parse query (no clauses generated)'); |
| 140 | return; |
| 141 | } |
| 142 | |
| 143 | // Get goals from query (body of first clause, or head if it's a fact) |
| 144 | const clause = clauses[0]; |
| 145 | const goals = clause.body && clause.body.length > 0 ? clause.body : [clause.head]; |
| 146 | |
| 147 | // Execute query |
| 148 | const program = this.getProgram(); |
| 149 | const ctx = { |
| 150 | bpm: 120, // default BPM for built-ins that need it |
| 151 | stateManager: this.stateManager |
| 152 | }; |
| 153 | |
| 154 | const solutions = []; |
| 155 | const maxSolutions = 100; // Limit solutions to prevent infinite loops |
| 156 | |
| 157 | for (const env of resolveGoals(goals, {}, program, ctx, this.builtins)) { |
| 158 | solutions.push(env); |
| 159 | if (solutions.length >= maxSolutions) { |
| 160 | this.showWarning(`Showing first ${maxSolutions} solutions (limit reached)`); |
| 161 | break; |
no test coverage detected