%s
" (c |> List.map renderInline |> String.concat "") + | Section(l, _, c) -> sprintf "%s
" (renderInlines children) - interface IConverter with - member _.Convert(doc, metadata) = - let bodyHtml = doc |> List.map renderBlock |> String.concat "\n\n" - let mutable finalHtml = template.Replace("{{body}}", bodyHtml) - for kvp in metadata do - finalHtml <- finalHtml.Replace(sprintf "{{%s}}" kvp.Key, WebUtility.HtmlEncode(kvp.Value)) - finalHtml +module Evaluators = + open System.IO + open System.Text + open FSharp.Compiler.Interactive.Shell -// ========================================== -// 5. Pipeline & Test -// ========================================== -module FibLib= - let processDocument (source: string) (template: string) (evaluator: IEvaluator) (converter: IConverter) = - let (metadata, rawAst) = Parser.parse source - let evaluatedAst = Execution.evaluateDocument metadata evaluator rawAst - converter.Convert(evaluatedAst, metadata) + type FsiEvaluator() = + let sbOut = new StringBuilder() + let sbErr = new StringBuilder() + let inStream = new StringReader("") + let outStream = new StringWriter(sbOut) + let errStream = new StringWriter(sbErr) + // Initiera FSI-sessionen + let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration() + let argv = [| "fsi.exe"; "--noninteractive" |] + let session = FsiEvaluationSession.Create(fsiConfig, argv, inStream, outStream, errStream) + + interface IEvaluator with + member _.Evaluate(code: string) = + sbOut.Clear() |> ignore + sbErr.Clear() |> ignore + + try + let result, _warnings = session.EvalInteractionNonThrowing(code) + + let output = sbOut.ToString() + let errors = sbErr.ToString().Trim() + + // Filtrera bort FSI:s automatiska typsignaturer från utskriften + let cleanOutput = + output.Replace("\r\n", "\n").Split('\n') + |> Array.filter (fun line -> + let l = line.TrimStart() + not (l.StartsWith("val ") || l.StartsWith("type ") || l.StartsWith("module ") || l.StartsWith("namespace ")) + ) + |> String.concat "\n" + |> fun s -> s.Trim() + + match result with + | Choice1Of2 (Some fsiValue) -> + // Plocka ut värdet. Om det är en sträng, undvik "%A" för att slippa citattecken. + let valStr = + if isNull fsiValue.ReflectionValue then "" + else + match fsiValue.ReflectionValue with + | :? string as s -> s + | v -> sprintf "%A" v + + if System.String.IsNullOrEmpty(cleanOutput) then valStr + elif System.String.IsNullOrEmpty(valStr) then cleanOutput + else cleanOutput + "\n" + valStr + + | Choice1Of2 None -> + if not (System.String.IsNullOrEmpty(errors)) then + cleanOutput + sprintf "%A" errors + else + cleanOutput + + | Choice2Of2 ex -> + let fsiErrorOutput = if System.String.IsNullOrEmpty(errors) then "Ingen ytterligare FSI-output." else errors + sprintf """ +%s%s+
%s%s+ //