added metadata
This commit is contained in:
parent
78598d71e7
commit
14697b3dd9
2 changed files with 31 additions and 223 deletions
|
|
@ -8,7 +8,7 @@ open System.Collections.Generic
|
|||
|
||||
module Utils =
|
||||
let smartDedent (input: string) =
|
||||
let lines = input.Replace("\r\n", "\n").Split('\n') |> List.ofArray
|
||||
let lines = input.Replace("\r\n", "\n").Split '\n' |> List.ofArray
|
||||
|
||||
// 1. Hitta den minsta indenteringen bland alla rader som har text
|
||||
let minIndent =
|
||||
|
|
@ -20,6 +20,7 @@ module Utils =
|
|||
| indents -> List.min indents
|
||||
|
||||
// 2. Dra av exakt så många mellanslag från alla rader
|
||||
// för att dessa inte ska vara med i det slutgiltiga dokumentet.
|
||||
let dedented =
|
||||
lines
|
||||
|> List.map (fun l ->
|
||||
|
|
@ -29,30 +30,7 @@ module Utils =
|
|||
|
||||
// 3. Slå ihop och städa bort överflödiga radbrytningar i början/slutet
|
||||
(String.concat "\n" dedented).Trim('\n', '\r')
|
||||
|
||||
module Utils3 =
|
||||
let smartDedent (input: string) =
|
||||
let text = input.Trim('\n', '\r')
|
||||
let lines = text.Replace("\r\n", "\n").Split('\n') |> List.ofArray
|
||||
|
||||
let rec loop lines currentBase acc =
|
||||
match lines with
|
||||
| [] -> List.rev acc |> String.concat "\n"
|
||||
| line :: tail ->
|
||||
if System.String.IsNullOrWhiteSpace(line) then
|
||||
loop tail currentBase ("" :: acc)
|
||||
else
|
||||
let indent = line.Length - line.TrimStart().Length
|
||||
|
||||
if indent = 0 then
|
||||
loop tail 0 (line :: acc)
|
||||
else
|
||||
let newBase = if currentBase = 0 then indent else currentBase
|
||||
let toStrip = min newBase indent
|
||||
let stripped = line.Substring toStrip
|
||||
loop tail newBase (stripped :: acc)
|
||||
|
||||
loop lines 0 []
|
||||
|
||||
|
||||
// ==========================================
|
||||
// 1. AST & Utils
|
||||
|
|
@ -71,26 +49,10 @@ module Ast =
|
|||
|
||||
type Document = BlockNode list
|
||||
|
||||
type TagRenderer = string list -> InlineNode list -> InlineNode
|
||||
type TagRenderer = Map<string,string> -> string list -> InlineNode list -> InlineNode
|
||||
|
||||
module Utils2 =
|
||||
let smartDedent (input: string) =
|
||||
let text = input.Trim('\n', '\r')
|
||||
let lines = text.Replace("\r\n", "\n").Split '\n' |> List.ofArray
|
||||
|
||||
let rec loop lines currentBase acc =
|
||||
match lines with
|
||||
| [] -> List.rev acc |> String.concat "\n"
|
||||
| line :: tail ->
|
||||
if System.String.IsNullOrWhiteSpace line then
|
||||
loop tail currentBase ("" :: acc)
|
||||
else
|
||||
let indent = line.Length - line.TrimStart().Length
|
||||
let newBase = if currentBase = 0 then indent else currentBase
|
||||
let toStrip = min newBase indent
|
||||
loop tail newBase (line.Substring toStrip :: acc)
|
||||
|
||||
loop lines 0 []
|
||||
|
||||
// ==========================================
|
||||
// 2. Parser
|
||||
|
|
@ -121,7 +83,7 @@ module Parser =
|
|||
pchar '{' >>. pRawBodyRef.Value .>> pchar '}' |>> sprintf "{%s}"
|
||||
]) |>> String.concat ""
|
||||
|
||||
let pBody =
|
||||
let pBody: Parser<InlineNode list,unit> =
|
||||
between (pstring "{") (pstring "}") pRawBodyRef.Value >>= fun raw ->
|
||||
match run (many pInline .>> eof) (Utils.smartDedent raw) with
|
||||
| Success(n, _, _) -> preturn n
|
||||
|
|
@ -214,112 +176,6 @@ module Parser =
|
|||
| Failure(e, _, _) -> failwith e
|
||||
|
||||
|
||||
module Parser2 =
|
||||
open Ast
|
||||
|
||||
let pInline, pInlineRef = createParserForwardedToRef<InlineNode, unit>()
|
||||
|
||||
// --- De saknade hjälpfunktionerna ---
|
||||
let getSectionLevel (name: string) =
|
||||
if name = "section" then 1
|
||||
elif name = "subsection" then 2
|
||||
elif name.StartsWith("sub") && name.EndsWith "section" then (name.Length - 7) / 3 + 1
|
||||
else 1
|
||||
|
||||
let isSection (name: string) = name.EndsWith "section"
|
||||
|
||||
let pNewline = newline
|
||||
|
||||
let pArg = spaces >>. manyChars (noneOf ",]") .>> spaces
|
||||
let pArgs = between (pstring "[") (pstring "]") (sepBy pArg (pstring ","))
|
||||
// ------------------------------------
|
||||
|
||||
let pRawBody, pRawBodyRef = createParserForwardedToRef<string, unit>()
|
||||
pRawBodyRef.Value <-
|
||||
many (choice [
|
||||
many1Chars (noneOf "{}")
|
||||
pchar '{' >>. pRawBodyRef.Value .>> pchar '}' |>> sprintf "{%s}"
|
||||
]) |>> String.concat ""
|
||||
|
||||
let pBody =
|
||||
between (pstring "{") (pstring "}") pRawBodyRef.Value >>= fun raw ->
|
||||
match run (many pInline .>> eof) (Utils.smartDedent raw) with
|
||||
| Success(n, _, _) -> preturn n
|
||||
| Failure(m, _, _) -> fail m
|
||||
|
||||
let pMultilineCode =
|
||||
pstring "@\"\"\"" >>. manyCharsTill anyChar (pstring "\"\"\"")
|
||||
|>> fun c -> Expr(Utils.smartDedent c, None)
|
||||
|
||||
let pParenBody, pParenBodyRef = createParserForwardedToRef<string, unit>()
|
||||
pParenBodyRef.Value <-
|
||||
many (choice [
|
||||
many1Chars (noneOf "()")
|
||||
pchar '(' >>. pParenBodyRef.Value .>> pchar ')' |>> sprintf "(%s)"
|
||||
]) |>> String.concat ""
|
||||
|
||||
// let pExpr2 =
|
||||
// attempt (pstring "@(") >>. manyChars (noneOf ")") .>> pstring ")"
|
||||
// |>> fun c -> Expr(c, None)
|
||||
|
||||
let pExpr =
|
||||
attempt (pstring "@(") >>. pParenBodyRef.Value .>> pstring ")"
|
||||
|>> fun c -> Expr(c, None)
|
||||
|
||||
let pInlineCommand =
|
||||
attempt (
|
||||
pchar '@' >>. many1Chars asciiLetter >>= fun name ->
|
||||
if isSection name then fail "Sektioner är block-element."
|
||||
else preturn name
|
||||
)
|
||||
.>>. opt pArgs
|
||||
.>>. opt pBody
|
||||
|>> fun ((n, a), b) -> Element(n, defaultArg a [], defaultArg b [])
|
||||
|
||||
pInlineRef.Value <- choice [
|
||||
pMultilineCode
|
||||
pExpr
|
||||
pInlineCommand
|
||||
many1Chars (noneOf "@{}\n\r") |>> Text
|
||||
attempt (pNewline .>> notFollowedBy pNewline) |>> fun _ -> Text "\n"
|
||||
]
|
||||
|
||||
let pSectionBlock =
|
||||
attempt (
|
||||
pchar '@' >>. many1Chars asciiLetter >>= fun name ->
|
||||
if isSection name then preturn name
|
||||
else fail "Inte en sektion."
|
||||
)
|
||||
.>>. opt pArgs
|
||||
.>>. opt pBody
|
||||
|>> fun ((name, argsOpt), bodyOpt) ->
|
||||
Section(getSectionLevel name, defaultArg argsOpt [], defaultArg bodyOpt [])
|
||||
|
||||
let pParagraphBlock = many1 pInline |>> Paragraph
|
||||
|
||||
let pBlock = choice [ pSectionBlock; pParagraphBlock ]
|
||||
|
||||
let pDocument =
|
||||
spaces
|
||||
>>. opt (
|
||||
pstring "---"
|
||||
// HÄR ÄR FIXEN: attempt runt pNewline och pstring
|
||||
>>. manyCharsTill anyChar (attempt (pNewline >>. pstring "---"))
|
||||
|>> fun yamlStr ->
|
||||
let deserializer = DeserializerBuilder().Build()
|
||||
let dict = deserializer.Deserialize<Dictionary<string, string>>(yamlStr)
|
||||
if isNull dict then Map.empty
|
||||
else dict |> Seq.map (fun kvp -> kvp.Key, kvp.Value) |> Map.ofSeq
|
||||
)
|
||||
.>> spaces
|
||||
.>>. sepEndBy pBlock (many1 pNewline)
|
||||
|>> fun (headerOpt, blocks) ->
|
||||
(defaultArg headerOpt Map.empty, blocks)
|
||||
|
||||
let parse i =
|
||||
match run pDocument i with
|
||||
| Success(r, _, _) -> r
|
||||
| Failure(e, _, _) -> failwith e
|
||||
// ==========================================
|
||||
// 3. Execution & Printer
|
||||
// ==========================================
|
||||
|
|
@ -329,11 +185,13 @@ type IEvaluator =
|
|||
module Execution =
|
||||
open Ast
|
||||
|
||||
let rec transform (prelude: Map<string, TagRenderer>) (eval: IEvaluator) =
|
||||
function
|
||||
| Element(n, a, c) when prelude.ContainsKey n -> prelude.[n] a (c |> List.map (transform prelude eval))
|
||||
| Element(n, a, c) -> Element(n, a, c |> List.map (transform prelude eval))
|
||||
| Expr(c, _) -> RawHtml(eval.Evaluate c)
|
||||
let rec transform (metadata: Map<string, string>) (prelude: Map<string, TagRenderer>) (eval: IEvaluator) = function
|
||||
| Element(n, a, c) when prelude.ContainsKey n ->
|
||||
// Skicka in metadata som första argument till din funktion
|
||||
prelude.[n] metadata a (c |> List.map (transform metadata prelude eval))
|
||||
| Element(n, a, c) ->
|
||||
Element(n, a, c |> List.map (transform metadata prelude eval))
|
||||
| Expr(c, _) -> RawHtml (eval.Evaluate c)
|
||||
| n -> n
|
||||
|
||||
module HtmlPrinter =
|
||||
|
|
@ -427,49 +285,4 @@ module Evaluators =
|
|||
<strong>Kritiskt FSI-systemfel:</strong> %s
|
||||
</div>""" ex.Message
|
||||
|
||||
// interface IEvaluator with
|
||||
// member _.Evaluate(code: string) =
|
||||
// sbOut.Clear() |> ignore
|
||||
// sbErr.Clear() |> ignore
|
||||
|
||||
// try
|
||||
// printfn "%s" code
|
||||
|
||||
// // Kör koden i FSI
|
||||
// let result, _warnings = session.EvalInteractionNonThrowing code
|
||||
|
||||
// // Läs av vad kompilatorn spottade ut
|
||||
// let output = sbOut.ToString().Trim()
|
||||
// let errors = sbErr.ToString().Trim()
|
||||
|
||||
// match result with
|
||||
// | Choice1Of2 (Some fsiValue) ->
|
||||
// // Det gick bra och koden returnerade ett värde
|
||||
// let valStr = sprintf "%A" fsiValue.ReflectionValue
|
||||
// if System.String.IsNullOrEmpty(output) then valStr
|
||||
// else output + "\n" + valStr
|
||||
|
||||
// | Choice1Of2 None ->
|
||||
// // Det gick bra, men koden returnerade inget värde (t.ex. en let-bindning)
|
||||
// // Om det fanns utskrifter i sbErr (t.ex. varningar), kan vi visa dem här:
|
||||
// if not (System.String.IsNullOrEmpty(errors)) then
|
||||
// output + sprintf "\n %A" errors
|
||||
// else
|
||||
// output
|
||||
|
||||
// | Choice2Of2 ex ->
|
||||
// // FSI kastade ett exception (t.ex. syntaxfel eller runtime-fel)
|
||||
// let fsiErrorOutput = if System.String.IsNullOrEmpty(errors) then "Ingen ytterligare FSI-output." else errors
|
||||
// sprintf """
|
||||
// <div style="color: #721c24; background-color: #f8d7da; border-color: #f5c6cb; padding: 10px; margin-bottom: 10px; border-radius: 5px;">
|
||||
// <strong>FSI Exekveringsfel!</strong><br/>
|
||||
// <strong>Kod som kördes:</strong> <code>%s</code><br/><br/>
|
||||
// <strong>Exception:</strong> %s<br/>
|
||||
// <strong>FSI Stderr:</strong> <pre style="margin:0; background: rgba(255,255,255,0.5); padding: 5px;">%s</pre>
|
||||
// </div>""" code ex.Message fsiErrorOutput
|
||||
|
||||
// with ex ->
|
||||
// // Fångar upp om själva anropet till session.EvalInteractionNonThrowing kraschar helt
|
||||
// sprintf """<div style="color: red; border: 1px solid red; padding: 10px;">
|
||||
// <strong>Kritiskt FSI-systemfel:</strong> %s
|
||||
// </div>""" ex.Message
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue