├── src ├── literals.cs ├── wpf.tl ├── braidlang.sln ├── Properties │ └── AssemblyInfo.cs ├── untested.tl ├── BraidCore.csproj ├── braidlang.csproj ├── braidhelp.tl ├── runspaceManager.cs ├── console.tl ├── http.tl ├── graphics.tl ├── htmlutils.tl ├── symbol.cs ├── utils.cs └── BraidRepl.ps1 ├── Braid ├── Braid.ps.psm1 ├── Braid.psd1 ├── Braid.psm1 └── Build │ ├── Braid.GitHubWorkflow.PSDevOps.ps1 │ ├── GitHub │ ├── Steps │ │ └── BuildBraidStep.ps1 │ └── Jobs │ │ └── BuildBraid.psd1 │ └── Braid.PSSVG.ps1 ├── PSCONFEU23_payette_braid.pptx ├── README.md ├── Dockerfile ├── Tests ├── missing-help.tl └── untested.tl ├── Start-Braid.ps1 ├── LICENSE ├── Examples ├── webtasks.tl ├── wpfdemo.tl ├── mergesort.tl ├── ntp.tl ├── mandel.tl ├── json.grammar.tl ├── turtle.tl ├── hanoi.tl ├── snake.tl ├── consoleform.tl └── tictactoe.tl ├── Braid.svg ├── braid.vim └── .github └── workflows └── BuildBraid.yml /src/literals.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrucePay/BraidLang/HEAD/src/literals.cs -------------------------------------------------------------------------------- /Braid/Braid.ps.psm1: -------------------------------------------------------------------------------- 1 | $CommandsPath = Join-Path $PSScriptRoot "Commands" 2 | [include('*-*')]$CommandsPath 3 | -------------------------------------------------------------------------------- /PSCONFEU23_payette_braid.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrucePay/BraidLang/HEAD/PSCONFEU23_payette_braid.pptx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BraidLang 2 | 3 | The Braid Language Implementation. 4 | 5 | Braid is a shell and scripting language built on top of PowerShell. 6 | -------------------------------------------------------------------------------- /Braid/Braid.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | ModuleVersion = '0.1' 3 | Guid = '7f38ada8-7318-408c-a539-3b6b5d2bf84d' 4 | RootModule = 'Braid.psm1' 5 | } 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/powershell 2 | COPY . /Braid 3 | SHELL ["/bin/pwsh", "-nologo","-command"] 4 | RUN @( \ 5 | Get-ChildItem -Path /Braid -Recurse -Filter Braidlang.dll | \ 6 | Select-Object -First 1 | \ 7 | Copy-Item -Destination /Braid/stage/ -PassThru | Out-Host \ 8 | ) 9 | ENTRYPOINT [ "/bin/pwsh", "-nologo", "-noprofile", "-file", "/Braid/Start-Braid.ps1" ] -------------------------------------------------------------------------------- /Tests/missing-help.tl: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ; 3 | ; A Braid script to detect functions for which 4 | ; there is no help documentation. This script 5 | ; operates against the currently loaded functions. 6 | ; 7 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 8 | 9 | lambda [(^regex filterPattern #".")] 10 | 11 | (functions 12 | | filter -not (fn f -> (doc (.value f))) 13 | | map .key 14 | | filter filterPattern 15 | | list/WrapPrint info 16 | ) 17 | 18 | -------------------------------------------------------------------------------- /Braid/Braid.psm1: -------------------------------------------------------------------------------- 1 | $CommandsPath = Join-Path $PSScriptRoot "Commands" 2 | :ToIncludeFiles foreach ($file in (Get-ChildItem -Path "$CommandsPath" -Filter "*-*" -Recurse)) { 3 | if ($file.Extension -ne '.ps1') { continue } # Skip if the extension is not .ps1 4 | foreach ($exclusion in '\.[^\.]+\.ps1$') { 5 | if (-not $exclusion) { continue } 6 | if ($file.Name -match $exclusion) { 7 | continue ToIncludeFiles # Skip excluded files 8 | } 9 | } 10 | . $file.FullName 11 | } 12 | 13 | -------------------------------------------------------------------------------- /Braid/Build/Braid.GitHubWorkflow.PSDevOps.ps1: -------------------------------------------------------------------------------- 1 | 2 | #requires -Module PSDevOps 3 | 4 | Import-BuildStep -SourcePath ( 5 | Join-Path $PSScriptRoot 'GitHub' 6 | ) -BuildSystem GitHubWorkflow 7 | 8 | Push-Location ($PSScriptRoot | Split-Path | Split-Path) 9 | 10 | New-GitHubWorkflow -Job TestPowerShellOnLinux, TagReleaseAndPublish, BuildBraid -OutputPath @' 11 | .\.github\workflows\BuildBraid.yml 12 | '@ -Name "Build Braid" -On Push, PullRequest -Environment ([Ordered]@{ 13 | REGISTRY = 'ghcr.io' 14 | IMAGE_NAME = '${{ github.repository }}' 15 | }) 16 | 17 | Pop-Location 18 | 19 | -------------------------------------------------------------------------------- /Braid/Build/GitHub/Steps/BuildBraidStep.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = 'continue' 2 | 3 | $msBuildCommand = Get-Command msbuild -ErrorAction Ignore 4 | $dotNetCommand = Get-command dotnet -ErrorAction Ignore 5 | 6 | if (-not $msBuildCommand) { 7 | $msBuildCommand = $dotNetCommand | 8 | Split-Path | 9 | Split-Path | 10 | Get-ChildItem -Filter msbuild* -Recurse -file | 11 | Select-Object -First 1 -ExpandProperty FullName 12 | } 13 | 14 | 15 | if (-not $msBuildCommand) { 16 | Write-Warning "Could not find MSBuild, using .NET" 17 | & $dotNetCommand restore ./src/BraidCore.csproj 18 | & $dotNetCommand build ./src/BraidCore.csproj 19 | return 20 | } else { 21 | Set-Alias msbuild $msBuildCommand 22 | .\build.ps1 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /Start-Braid.ps1: -------------------------------------------------------------------------------- 1 | ####################################################### 2 | # 3 | # Loader for the braid programming language. 4 | # 5 | ####################################################### 6 | 7 | param ( 8 | [switch] $Optimize, 9 | [switch] $NoBuild, 10 | $cmd = $null 11 | ) 12 | 13 | if ($cmd) 14 | { 15 | # Just run the command 16 | ./stage/BraidRepl $cmd @args 17 | } 18 | else 19 | { 20 | # Build and start braid. 21 | if (-not $nobuild) 22 | { 23 | & "$PSScriptRoot/build.ps1" -optimize:$Optimize 24 | } 25 | 26 | if ($PSVersionTable.PSEdition -eq "Desktop") 27 | { 28 | powershell "$PSScriptRoot/stage/BraidRepl.ps1" 29 | } 30 | else 31 | { 32 | pwsh "$PSScriptRoot/stage/BraidRepl.ps1" 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Bruce Payette 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/wpf.tl: -------------------------------------------------------------------------------- 1 | 2 | ; load the WPF assembly 3 | (using-assembly PresentationFramework) 4 | 5 | (defn wpf-new 6 | "Parses the argument string into XAML then creates a Window out of it." 7 | [(^string xamltext)] 8 | 9 | (let xml (^xml? xamltext)) 10 | (let reader (new ^System.Xml.XmlNodeReader xml)) 11 | (let window (.Windows.Markup.XamlReader/Load reader)) 12 | window 13 | ) 14 | 15 | (defn wpf-control 16 | "Find a control matching the specified name" 17 | [(^system.windows.window window) (^string controlName)] 18 | 19 | (let control (.FindName window controlname)) 20 | (if (null? control) 21 | (throw "cannot find control '${controlname}' in the DOM.") 22 | ) 23 | control 24 | ) 25 | 26 | (defn wpf-click 27 | "Adds a click action to the passed control." 28 | [(^system.windows.window window) (^string controlName) action] 29 | 30 | (let control (wpf-control window controlname)) 31 | (.add_Click control 32 | (^System.Windows.RoutedEventHandler? action) 33 | ) 34 | ) 35 | 36 | (defn wpf-show 37 | "Shows a WPF window" 38 | [(^system.windows.window window)] 39 | 40 | (.ShowDialog window) 41 | ) 42 | -------------------------------------------------------------------------------- /src/braidlang.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33723.286 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "braidlang", "braidlang.csproj", "{7F38ADA8-7318-408C-A539-3B6B5D2BF84D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {7F38ADA8-7318-408C-A539-3B6B5D2BF84D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {7F38ADA8-7318-408C-A539-3B6B5D2BF84D}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {7F38ADA8-7318-408C-A539-3B6B5D2BF84D}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {7F38ADA8-7318-408C-A539-3B6B5D2BF84D}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {055AEF03-0942-4434-9035-6E3B5B714E0C} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Examples/webtasks.tl: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ; 3 | ; Script to demonstrate/test Task usage in braid. 4 | ; 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6 | 7 | lambda [ 8 | ; the number of reps to execute. 9 | (reps 10) 10 | ] 11 | 12 | (using-module http) 13 | 14 | (alert "Getting the main Wikipedia page ${reps} times, single-threaded") 15 | 16 | (time 17 | (repeat-all reps (http/get "https://wikipedia.org") 18 | | map .length 19 | | println) 20 | ) 21 | 22 | (alert "\n\nGetting the main Wikipedia page ${reps} times, using map-parallel") 23 | 24 | (time 25 | (range reps 26 | | map-parallel (fn _ -> (http/get "https://wikipedia.org")) 27 | | map .length 28 | | println 29 | ) 30 | ) 31 | 32 | (alert "\nGetting the main wikipedia page ${reps} times using async/await") 33 | 34 | (time 35 | (repeat-all reps (http/getAsync "https://wikipedia.org") 36 | | await 37 | | map .length 38 | | println) 39 | ) 40 | 41 | (alert "\n\nGetting the main Wikipedia page once using Invoke-WebRequest") 42 | 43 | (time 44 | (Invoke-WebRequest "https://wikipedia.org" 45 | | map .statuscode 46 | | println) 47 | ) 48 | 49 | -------------------------------------------------------------------------------- /Braid/Build/Braid.PSSVG.ps1: -------------------------------------------------------------------------------- 1 | 2 | $FontName = 'Noto Sans' 3 | $AnimateColors = [Ordered]@{ 4 | dur='10s' 5 | Values='#199ac1;#359DA8;#199ac1' 6 | RepeatCount='indefinite' 7 | } 8 | 9 | 10 | Push-Location ($psScriptRoot | Split-Path | Split-Path) 11 | 12 | svg -ViewBox 300, 100 @( 13 | SVG.GoogleFont -FontName $FontName 14 | 15 | SVG.path -D @( 16 | "M 90, 0" 17 | 18 | $pixelRange = 0..100 19 | $angleStart = 180 20 | $angleIncrease = 360 / $pixelRange.Length 21 | 22 | foreach ($t in $pixelRange) { 23 | 24 | "$((100 + ([Math]::Cos((($angleStart + ($t*$angleIncrease)) * [Math]::PI)/180) * 10)), $t)" 25 | } 26 | "M 110, 0" 27 | foreach ($t in $pixelRange) { 28 | "$((100 + ([Math]::Cos((($angleStart + ($t*$angleIncrease)) * [Math]::PI)/180) * -10)), $t)" 29 | } 30 | ) -Stroke "#199ac1" -Fill 'transparent' @( 31 | SVG.animate -AttributeName stroke @AnimateColors 32 | ) 33 | 34 | 35 | svg.text -X 50% -Y 50% -TextAnchor 'middle' -DominantBaseline 'middle' -Style "font-family: '$FontName', sans-serif" -Fill '#199AC1' -Class 'foreground-fill' -Content @( 36 | SVG.tspan -FontSize .5em -Content 'Braid' 37 | SVG.animate -AttributeName fill @AnimateColors 38 | ) -FontSize 4em -FontWeight 500 39 | 40 | ) -OutputPath (Join-Path $pwd Braid.svg) 41 | 42 | Pop-Location -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("braidlang")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("braidlang")] 13 | [assembly: AssemblyCopyright("Copyright © 2023")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7f38ada8-7318-408c-a539-3b6b5d2bf84d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Examples/wpfdemo.tl: -------------------------------------------------------------------------------- 1 | 2 | (using-module wpf) 3 | 4 | (let window (wpf-new " 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 23 |