c118996746
- SwiftUI macOS app with C++17 code analysis engine (ObjC++ bridge) - Agentic AI loop: LLM plans → tool calls → execution → feedback loop - 15 agent tools: file ops, terminal, git, xcode build, code intel - 7 persistent terminal tools with background session management - Chat sidebar with agent step rendering and auto-apply - NVIDIA NIM API integration (Llama 3.3 70B default) - OpenAI tool_calls format with prompt-based fallback - Code editor with syntax highlighting and multi-tab support - File tree, console view, terminal view - Git integration and workspace management
139 lines
4.9 KiB
Swift
139 lines
4.9 KiB
Swift
import Foundation
|
|
|
|
final class SandboxedSwiftEngine: CodeEngine, @unchecked Sendable {
|
|
private var variables: [String: String] = [:]
|
|
|
|
func run(_ source: String) async throws -> ExecutionResult {
|
|
let startTime = CFAbsoluteTimeGetCurrent()
|
|
variables.removeAll()
|
|
|
|
var stdout = ""
|
|
var stderr = ""
|
|
var exitCode: Int32 = 0
|
|
|
|
let lines = source.components(separatedBy: .newlines)
|
|
for (i, raw) in lines.enumerated() {
|
|
let line = raw.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if line.isEmpty || line.hasPrefix("//") || line.hasPrefix("import ") { continue }
|
|
|
|
do {
|
|
if let inner = extractPrintArgument(from: line) {
|
|
let value = try evaluate(inner)
|
|
stdout += value + "\n"
|
|
} else if let (name, value) = extractVariableDeclaration(from: line) {
|
|
variables[name] = try evaluate(value)
|
|
} else {
|
|
stderr += "Line \(i + 1): Unsupported statement in sandbox mode.\n"
|
|
exitCode = 1
|
|
}
|
|
} catch {
|
|
stderr += "Line \(i + 1): \(error.localizedDescription)\n"
|
|
exitCode = 1
|
|
}
|
|
}
|
|
|
|
let duration = CFAbsoluteTimeGetCurrent() - startTime
|
|
return ExecutionResult(stdout: stdout, stderr: stderr, exitCode: exitCode, duration: duration)
|
|
}
|
|
|
|
func cancel() { /* Sandbox runs synchronously */ }
|
|
|
|
// MARK: - Parsing
|
|
|
|
private func extractPrintArgument(from line: String) -> String? {
|
|
guard line.hasPrefix("print("), line.hasSuffix(")") else { return nil }
|
|
guard let open = line.firstIndex(of: "("),
|
|
let close = line.lastIndex(of: ")"),
|
|
open < close else { return nil }
|
|
return String(line[line.index(after: open)..<close]).trimmingCharacters(in: .whitespaces)
|
|
}
|
|
|
|
private func extractVariableDeclaration(from line: String) -> (String, String)? {
|
|
let prefixes = ["let ", "var "]
|
|
for prefix in prefixes {
|
|
guard line.hasPrefix(prefix) else { continue }
|
|
let rest = String(line.dropFirst(prefix.count))
|
|
guard let eqIdx = rest.firstIndex(of: "=") else { continue }
|
|
let name = rest[rest.startIndex..<eqIdx]
|
|
.trimmingCharacters(in: .whitespaces)
|
|
.components(separatedBy: ":").first?
|
|
.trimmingCharacters(in: .whitespaces) ?? ""
|
|
let value = rest[rest.index(after: eqIdx)...]
|
|
.trimmingCharacters(in: .whitespaces)
|
|
guard !name.isEmpty, !value.isEmpty else { continue }
|
|
return (name, value)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MARK: - Evaluation
|
|
|
|
private func evaluate(_ expr: String) throws -> String {
|
|
let trimmed = expr.trimmingCharacters(in: .whitespaces)
|
|
|
|
// String literal
|
|
if trimmed.hasPrefix("\""), trimmed.hasSuffix("\"") {
|
|
return unescapeString(String(trimmed.dropFirst().dropLast()))
|
|
}
|
|
// Integer literal
|
|
if let intVal = Int(trimmed) {
|
|
return String(intVal)
|
|
}
|
|
// Float literal
|
|
if let doubleVal = Double(trimmed) {
|
|
return String(doubleVal)
|
|
}
|
|
// Boolean literal
|
|
if trimmed == "true" || trimmed == "false" {
|
|
return trimmed
|
|
}
|
|
// Variable reference
|
|
if let value = variables[trimmed] {
|
|
return value
|
|
}
|
|
// String concatenation with +
|
|
if trimmed.contains(" + ") {
|
|
let parts = trimmed.components(separatedBy: " + ")
|
|
return try parts.map { try evaluate($0) }.joined()
|
|
}
|
|
|
|
throw SandboxError.unsupportedExpression(trimmed)
|
|
}
|
|
|
|
private func unescapeString(_ s: String) -> String {
|
|
var result = ""
|
|
var it = s.makeIterator()
|
|
while let ch = it.next() {
|
|
if ch == "\\" {
|
|
if let next = it.next() {
|
|
switch next {
|
|
case "n": result.append("\n")
|
|
case "t": result.append("\t")
|
|
case "\"": result.append("\"")
|
|
case "\\": result.append("\\")
|
|
case "0": result.append("\0")
|
|
default:
|
|
result.append("\\")
|
|
result.append(next)
|
|
}
|
|
} else {
|
|
result.append("\\")
|
|
}
|
|
} else {
|
|
result.append(ch)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
enum SandboxError: LocalizedError {
|
|
case unsupportedExpression(String)
|
|
var errorDescription: String? {
|
|
switch self {
|
|
case .unsupportedExpression(let expr):
|
|
return "Unsupported expression '\(expr)'. Sandbox supports: string/number literals, variables, print(), let/var."
|
|
}
|
|
}
|
|
}
|
|
}
|