Status: Implemented (Phase 1) Version: 1.0.0 Date: 2025-10-26 Branch: powershell-target-language
This document describes the pure PowerShell implementation for UnifyWeaver’s PowerShell target language feature. Pure PowerShell mode generates native PowerShell code with no bash dependency, providing better integration with Windows environments and satisfying firewall restrictions.
The following data sources have pure PowerShell templates that use native PowerShell cmdlets:
Import-Csvcsv_source_unary_powershell_pure - Arity 1 predicatescsv_source_binary_plus_powershell_pure - Arity 2+ predicatesExample:
function user {
param([string]$Key)
$data = Import-Csv -Path 'users.csv'
# ... filtering logic ...
}
ConvertFrom-Jsonjson_file_source_powershell_pure - File-based JSONjson_stdin_source_powershell_pure - Piped JSON dataExample:
function product {
param([string]$Key)
$data = Get-Content 'products.json' | ConvertFrom-Json
# ... filtering logic ...
}
Invoke-RestMethodhttp_source_powershell_pure - HTTP API callsExample:
function api_user {
param([string]$Key)
$response = Invoke-RestMethod -Uri 'https://api.example.com/users'
# ... filtering logic ...
}
The following features still use Bash-as-a-Service (BaaS) mode and will be implemented in future phases:
-split, regex, Select-StringThe PowerShell compiler automatically selects between pure PowerShell and BaaS based on the data source type:
% Automatically uses pure PowerShell for CSV
:- dynamic_source(user/2, external(csv, 'users.csv')).
?- compile_to_powershell(user/2, Code).
% Generates pure PowerShell using Import-Csv
% Automatically uses BaaS for AWK
:- dynamic_source(log/3, external(awk, "awk '{print $1,$2,$3}' app.log")).
?- compile_to_powershell(log/3, Code).
% Generates BaaS wrapper (uw-bash + AWK)
Users can force a specific mode:
% Force pure PowerShell (will fail if not supported)
?- compile_to_powershell(user/2, [powershell_mode(pure)], Code).
% Force BaaS (even for CSV/JSON/HTTP)
?- compile_to_powershell(user/2, [powershell_mode(baas)], Code).
% Auto-detect (default)
?- compile_to_powershell(user/2, [powershell_mode(auto)], Code).
compile_to_powershell(Predicate, Options, Code)
|
+--> Determine mode: pure, baas, or auto
|
+--> Check if pure mode supported
| |
| +--> supports_pure_powershell/2
| - Checks for source_type(csv|json|http)
|
+--> If pure supported:
| +--> compile_to_pure_powershell/3
| +--> Adds template_suffix('_powershell_pure')
| +--> Calls dynamic_source_compiler
| +--> CSV/JSON/HTTP source plugins
| +--> render_named_template with suffix
| +--> Pure PowerShell templates
|
+--> Else (BaaS fallback):
+--> compile_to_baas_powershell/3
+--> Generate bash code
+--> Wrap in powershell_wrapper
+--> uw-bash compatibility layer
Import-Csv, Invoke-RestMethod)When a Prolog program uses both pure-supported and BaaS-only sources, the generated code will be mixed:
Prolog:
:- dynamic_source(user/2, external(csv, 'users.csv')). % Pure PS
:- dynamic_source(log/3, external(awk, "awk '...' app.log")). % BaaS
process_data(User, LogEntry) :-
user(UserId, UserName),
log(UserId, Timestamp, LogEntry).
Generated PowerShell:
# user/2 - Pure PowerShell
function user {
param([string]$Key)
$data = Import-Csv -Path 'users.csv'
# ... pure PowerShell ...
}
# log/3 - BaaS
$bashScript = @'
awk '{print $1 ":" $2 ":" $3}' app.log
'@
function log {
uw-bash -c $bashScript
}
# process_data/2 - Mixes both
function process_data {
$users = user
$logs = log
# ... join logic ...
}
Result: The system handles this automatically based on what each source type supports.
src/unifyweaver/sources/csv_source.pl
csv_source_unary_powershell_pure templatecsv_source_binary_plus_powershell_pure templategenerate_csv_bash/10 to accept template_suffix optionsrc/unifyweaver/sources/json_source.pl
json_file_source_powershell_pure templatejson_stdin_source_powershell_pure templatesrc/unifyweaver/sources/http_source.pl
http_source_powershell_pure templatesrc/unifyweaver/core/powershell_compiler.pl
powershell_mode(baas|pure|auto) optionsupports_pure_powershell/2 - checks source typecompile_to_pure_powershell/3 - generates pure codecompile_to_baas_powershell/3compile_to_powershell/3Prolog:
:- dynamic_source(employee/3, external(csv, 'employees.csv')).
?- compile_to_powershell(employee/3, [output_file('employee.ps1')], _).
Generated (employee.ps1):
function employee {
param([string]$Key)
$data = Import-Csv -Path 'employees.csv'
if ($Key) {
$keyColumn = $data[0].PSObject.Properties.Name[0]
$matches = $data | Where-Object { $_.$keyColumn -eq $Key }
foreach ($row in $matches) {
$values = $row.PSObject.Properties | ForEach-Object { $_.Value }
$values -join ":"
}
} else {
foreach ($row in $data) {
$values = $row.PSObject.Properties | ForEach-Object { $_.Value }
$values -join ":"
}
}
}
Run:
. .\employee.ps1
employee # List all employees
employee "E001" # Lookup employee E001
Prolog:
:- dynamic_source(github_repo/2, external(http,
'https://api.github.com/users/octocat/repos'
)).
?- compile_to_powershell(github_repo/2, [output_file('github.ps1')], _).
Generated (github.ps1):
function github_repo {
param([string]$Key)
try {
$response = Invoke-RestMethod -Uri 'https://api.github.com/users/octocat/repos'
foreach ($item in $response) {
$values = @($item.id, $item.name)
$values -join ":"
}
}
catch {
Write-Error "HTTP request failed: $_"
}
}
Run:
. .\github.ps1
github_repo # List all repos
% Load PowerShell compiler
?- [unifyweaver(core/powershell_compiler)].
% Test pure mode
?- compile_to_powershell(test_pred/2, [
source_type(csv),
csv_file('test.csv'),
powershell_mode(pure)
], Code),
write(Code).
% Test auto mode (should detect CSV and use pure)
?- compile_to_powershell(test_pred/2, [
source_type(csv),
csv_file('test.csv')
], Code),
sub_string(Code, _, _, _, 'Import-Csv'). % Should succeed
Create test CSV/JSON files and verify generated PowerShell works:
# Generate test script
swipl -g "compile_to_powershell(user/2, [source_type(csv), csv_file('test.csv'), output_file('test.ps1')], _)" -t halt
# Run in PowerShell
pwsh -File test.ps1
These three source types have superior native PowerShell support compared to bash:
| Feature | Bash | PowerShell | Winner |
|---|---|---|---|
| CSV parsing | AWK field splitting | Import-Csv (automatic headers, types) |
PowerShell |
| JSON parsing | jq (external tool) |
ConvertFrom-Json (built-in) |
PowerShell |
| HTTP requests | curl (external tool) |
Invoke-RestMethod (built-in, auto-parse) |
PowerShell |
| AWK text processing | Native AWK | Complex regex + -split |
Bash |
| Python integration | python (subprocess) |
python (subprocess) |
Tie (BaaS) |
Decision: Implement pure PowerShell where PowerShell is better or equal. Keep BaaS where bash/AWK is superior.
By allowing both pure and BaaS in the same pipeline, users get:
What we built:
What users get:
What’s next:
Created: 2025-10-26 Authors: John William Creighton (@s243a), Claude Code (Sonnet 4.5)