diff --git a/aoc2024.ps1 b/aoc2024.ps1 new file mode 100644 index 0000000..4c3143a --- /dev/null +++ b/aoc2024.ps1 @@ -0,0 +1,86 @@ +#!/usr/bin/env pwsh +[CmdletBinding()] +param ( + [switch] $Release, + [switch] $Full, + [switch] $All, + [switch] $NoBuild, + [ValidateSet( + "day1" + # , "day2", "day3", "day4", "day5", "day6", "day7", "day8", "day9" + # , "day10", "day11", "day12", "day13", "day14", "day15", "day16" + # , "day17", "day18", "day19", "day20", "day21", "day22" + # , "day23", "day24", "day25" + )] + [string] $Day +) +function ExecSafe([scriptblock] $cmd) { + & $cmd + if ($LASTEXITCODE) { exit $LASTEXITCODE } +} + +$AllDays = @( + "day1", "day2", "day3", "day4", "day5", "day6", "day7", "day8", "day9" + , "day10", "day11", "day12", "day13", "day14", "day15", "day16" + , "day17", "day18", "day19", "day20", "day21", "day22" + , "day23", "day24", "day25" +) + +$root = $PSScriptRoot +$cliScript = Join-Path -Path $root -ChildPath "cli.ps1" -Resolve + +if ($All) { + $NoBuild = $false + + $SelectedDays = $AllDays + + if ($Day) { + $SelectedDays = @() + $DidFind = $false + foreach ($ad in $AllDays) { + if ($ad -eq $Day) { + $DidFind = $true + $SelectedDays += $ad + } + elseif ($DidFind) { + $SelectedDays += $ad + } + } + } + + foreach ($ad in $SelectedDays) { + $cliArgs = @( + "./visp/examples/aoc2023/$ad.visp" + ) + if ($Full) { + $cliArgs += "full" + } + if ($Release) { + $cliArgs += "--release" + } + + Write-Host "Running: $ad" + + ExecSafe { + & $cliScript -NoBuild:$NoBuild @cliArgs + } + + $NoBuild = $true + } +} +else { + $cliArgs = @( + "./visp/examples/aoc2024/$Day.visp" + ) + if ($Full) { + $cliArgs += "full" + } + if ($Release) { + $cliArgs += "--release" + } + + ExecSafe { + & $cliScript -NoBuild:$NoBuild @cliArgs + } +} + diff --git a/build/Build.cs b/build/Build.cs index db0c3bc..b18c9b1 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -135,7 +135,6 @@ from framework in TargetFrameworks // csharpier-ignore public Target PublishLanguageServer => _ => _ - .DependsOn(x => x.Compile) .Executes(() => { DotNetPublish(it => it diff --git a/src/Visp.LanguageServer/LanguageServer.fs b/src/Visp.LanguageServer/LanguageServer.fs index c83021f..cd80ecf 100644 --- a/src/Visp.LanguageServer/LanguageServer.fs +++ b/src/Visp.LanguageServer/LanguageServer.fs @@ -27,6 +27,16 @@ let NormalizePath (str: string) = if file.StartsWith('/') then file else "/" + file +let denormalizePath (uri: Uri) = + let full = uri.ToString().Replace("file://", "") + let probablyWindows = full.IndexOf("%3A") > -1 + let full = full.Replace("%3A", ":") + + if probablyWindows && full.StartsWith("/") then + full.Substring(1) + else + full + let ToFileUri (str: string) = str |> NormalizePath |> (+) "file://" |> Uri @@ -479,7 +489,7 @@ type VispDocumentItem = eprintfn "Parsing %s" (this.Uri.ToString()) let file = - Core.CoreParser.parseString (this.Text) (this.Uri.ToString()) + Core.CoreParser.parseString (this.Text) (denormalizePath this.Uri) |> Transforms.Helpers.transformParsedFile Core.CoreParser.expandExpr let syms = ResizeArray() diff --git a/visp/examples/aoc2024/.gitignore b/visp/examples/aoc2024/.gitignore new file mode 100644 index 0000000..9655069 --- /dev/null +++ b/visp/examples/aoc2024/.gitignore @@ -0,0 +1,2 @@ +inputs/*.txt +!inputs/*example.txt diff --git a/visp/examples/aoc2024/common.visp b/visp/examples/aoc2024/common.visp new file mode 100644 index 0000000..01149eb --- /dev/null +++ b/visp/examples/aoc2024/common.visp @@ -0,0 +1,44 @@ +;; Copyright 2024 Ville Penttinen +;; Distributed under the MIT License. +;; https://github.com/vipentti/visp-fs/blob/main/LICENSE.md +;; +;; for basic syntax highlighting +;; vim: set syntax=clojure: +(require SpanUtils "0.4.1") + +(open System) +(open System.Collections.Generic) +(open System.Text.RegularExpressions) +(open SpanUtils.Extensions) + +(let commonSplitOptions StringSplitOptions.TrimEntries) + +(let IS_EXAMPLE (not (Array.contains "full" ARGV))) + +(fn WriteResult (part value ex) + (printfn "%s: %A %A" part value (= value ex))) + +(fn EnumerateSpanSplitLines ([text: string]) + (.EnumerateSplitSubstrings text [| #\lf #\cr |] commonSplitOptions)) + +(fn EnumareteSpanSplitChars ([ch: array] [text: ReadOnlySpan]) + (.EnumerateSplitSubstrings text ch commonSplitOptions)) + +(fn ReadInput ([day: string]) + (let filepath (String.concat "" [| "./inputs/" day (if IS_EXAMPLE "_example" "") ".txt" |])) + (printfn "file: %s" filepath) + (System.IO.File.ReadAllText filepath)) + +(syntax-macro Macro_ReadWhileNotEmpty + ([_ (id enu) body ...] + (while (.MoveNext enu) + (let id (+Current enu)) + (unless (+IsEmpty id) + (begin body ...) + )))) + +(syntax-macro Macro_ReadNext + [(_ enu) + (begin + (ignore (.MoveNext enu)) + (+Current enu))]) diff --git a/visp/examples/aoc2024/day1.visp b/visp/examples/aoc2024/day1.visp new file mode 100644 index 0000000..ce0e1b4 --- /dev/null +++ b/visp/examples/aoc2024/day1.visp @@ -0,0 +1,72 @@ + +;; Copyright 2024 Ville Penttinen +;; Distributed under the MIT License. +;; https://github.com/vipentti/visp-fs/blob/main/LICENSE.md +;; +;; for basic syntax highlighting +;; vim: set syntax=clojure: + +;; day1 +;; +;; Include common utlities +(include "./common.visp") + +;; Functions & types + +(fn ParseFile ([text: string]) + (mut lines (EnumerateSpanSplitLines text)) + + (mut lhs_items (||)) + (mut rhs_items (||)) + + (Macro_ReadWhileNotEmpty [line lines] + (mut parts (.EnumerateSplitSubstrings line [| #\space |] (bor StringSplitOptions.TrimEntries StringSplitOptions.RemoveEmptyEntries))) + (let lhs (span->int64 (Macro_ReadNext parts))) + (let rhs (span->int64 (Macro_ReadNext parts))) + + (up! lhs_items (cons lhs)) + (up! rhs_items (cons rhs)) + + ()) + + (lhs_items . rhs_items)) + +(fn Part1 (parsedInput) + ;; Implement part1 + + (let (lhs, rhs) parsedInput) + + (let sorted_lhs (-> lhs List.sort)) + (let sorted_rhs (-> rhs List.sort)) + + (let zipper (List.zip sorted_lhs sorted_rhs)) + (-> zipper + (List.fold #(+ %1 (abs (- (fst %2) (snd %2)))) 0L) + )) + +(fn Part2 (parsedInput) + ;; Implement part2 + (let (lhs, rhs) parsedInput) + + (let result (-> lhs + (List.fold #(begin + (let cur %2) + (let counts (-> rhs (List.filter #(= cur %1)) List.length)) + (+ %1 (* cur (int64 counts))) + ) 0L) + )) + + result) + +;; Implementation + +(let parsed (-> (ReadInput "day1") ParseFile)) + +;; Expected results +(let PART1_EXPECTED_RESULT (if IS_EXAMPLE 11 2264607)) +(let PART2_EXPECTED_RESULT (if IS_EXAMPLE 31 19457120)) + +(WriteResult "part1" (-> parsed Part1) PART1_EXPECTED_RESULT) +(WriteResult "part2" (-> parsed Part2) PART2_EXPECTED_RESULT) + +() diff --git a/visp/examples/aoc2024/init.visp b/visp/examples/aoc2024/init.visp new file mode 100644 index 0000000..10dd171 --- /dev/null +++ b/visp/examples/aoc2024/init.visp @@ -0,0 +1,147 @@ +;; Copyright 2024 Ville Penttinen +;; Distributed under the MIT License. +;; https://github.com/vipentti/visp-fs/blob/main/LICENSE.md +;; +;; for basic syntax highlighting +;; vim: set syntax=clojure: +(require Flurl.Http "4.0.2") + +(open System) +(open System.IO) +(open Flurl.Http) + +(fn GetFileTemplate (day) + $$""" +;; Copyright 2024 Ville Penttinen +;; Distributed under the MIT License. +;; https://github.com/vipentti/visp-fs/blob/main/LICENSE.md +;; +;; for basic syntax highlighting +;; vim: set syntax=clojure: + +;; +;; {{day}} +;; +;; Include common utlities +(include "./common.visp") + +;; Functions & types + +(fn ParseFile ([text: string]) + (mut lines (EnumerateSpanSplitLines text)) + + (Macro_ReadWhileNotEmpty [line lines] + ;; Read contents here + ()) + ) + +(fn Part1 (parsedInput) + ;; Implement part1 + 0) + +(fn Part2 (parsedInput) + ;; Implement part2 + 0) + +;; Implementation + +(let parsed (-> (ReadInput "{{day}}") ParseFile)) + +;; Expected results +(let PART1_EXPECTED_RESULT (if IS_EXAMPLE -1 -1)) +(let PART2_EXPECTED_RESULT (if IS_EXAMPLE -1 -1)) + +(WriteResult "part1" (-> parsed Part1) PART1_EXPECTED_RESULT) +(WriteResult "part2" (-> parsed Part2) PART2_EXPECTED_RESULT) + +() +""" +) + +(fn TryGetNamedArg (name) + (match (Array.tryFindIndex #(= name %1) ARGV) + [(Some index) + (if (< (inc index) (+Length ARGV)) + (Some (.[(inc index)] ARGV)) + None) + ] + [None None])) + +(fn Run () + (let dayNr (match (TryGetNamedArg "--day") + [(Some it) it] + [None (failwithf "Missing --day")] + )) + + (let sessionToken (match (TryGetNamedArg "--session") + [(Some it) it] + [None (match (TryGetEnvVar "AOC_SESSION") + [(Some it) it] + [None (failwithf "Missing either --session or env:AOC_SESSION")] + )] + )) + + (printfn "Setting up day %s" dayNr) + + (let dayName $"day{dayNr}") + + (let exampleInput $"{dayName}_example.txt") + (let mainInput $"{dayName}.txt") + + (printfn "CWD: %A" (GetCurrentDirectory)) + + (let targetFile (->> + (Path.Combine ((GetCurrentDirectory) . $"{dayName}.visp")) + (Path.GetFullPath) + )) + + (let inputPath (->> + (Path.Combine ((GetCurrentDirectory) . "inputs")) + (Path.GetFullPath) + )) + + (let exampleInputPath (->> (-Combine Path (inputPath . exampleInput)) (Path.GetFullPath))) + (let mainInputPath (->> (-Combine Path (inputPath . mainInput)) (Path.GetFullPath))) + + (unless (.Exists File targetFile) + (printfn "new %s" targetFile) + (.WriteAllText System.IO.File targetFile (GetFileTemplate dayName)) + ) + + (unless (.Exists File exampleInputPath) + (printfn "new %s" exampleInputPath) + (.WriteAllText System.IO.File exampleInputPath "") + ) + + (unless (.Exists File mainInputPath) + (printfn "new %s" mainInputPath) + (->> (task-> + (let! content + (begin + (let url $"https://adventofcode.com/2024/day/{dayNr}/input") + (printfn "downloading: %s" url) + (->> url + #(-WithCookie %1 ("session" . sessionToken)) + .GetStringAsync + ) + ) + ) + (do! (.WriteAllTextAsync System.IO.File mainInputPath content))) + + (Async.AwaitTask) + (Async.RunSynchronously) + + ) + ) + + ;; (cond_ + ;; [(.Exists File targetFile) + ;; (printfn "%s found" targetFile) + ;; ] + ;; [_ + ;; (printfn "new %s" targetFile) + ;; ] + ;; ) +) + +(Run) diff --git a/visp/examples/aoc2024/inputs/day1_example.txt b/visp/examples/aoc2024/inputs/day1_example.txt new file mode 100644 index 0000000..b8af9ad --- /dev/null +++ b/visp/examples/aoc2024/inputs/day1_example.txt @@ -0,0 +1,6 @@ +3 4 +4 3 +2 5 +1 3 +3 9 +3 3