-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOutput.fs
145 lines (126 loc) · 4.83 KB
/
Output.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
module Output
open System
open GeneralTypes
let addWord lastWord lastLength thisWord indent goal built =
match lastWord with
| s when String.length s = 0 -> // first
let newBuilt = built + indent + thisWord
let newLength = (String.length indent) + (String.length) thisWord
(newBuilt, newLength)
| _ -> // lastWord was a word
let padding =
if thisWord.[0] = '(' && lastWord.[0] = '(' then
""
else if lastWord = "~" then
""
else
" "
if lastLength + (String.length padding) + (String.length thisWord) <= goal then
let newBuilt = built + padding + thisWord
let newLength = lastLength + (String.length padding) + (String.length thisWord)
(newBuilt, newLength)
else
let newBuilt = built + "\n" + indent + thisWord
let newLength = (String.length indent) + (String.length thisWord)
(newBuilt, newLength)
let wordWrap indent lineLength str =
let indent = sprintf "%*s" indent " "
let stringParsed = Parser.preparedForOutput str
let rec aux lastW lastL build consume =
match consume with
| [] -> build + "\n"
| h::t ->
let newBuild, newLength =
addWord lastW lastL h indent lineLength build
aux h newLength newBuild t
aux "" 0 "" stringParsed
let namePart (n: Node) =
match n.Name with
| Some x -> "#" + x
| None ->
printfn "Warning: Unnamed node"
"#unnamed"
let displayPart (n: Node) indentAt wrapAt =
match n.Display with
| None -> ""
| Some x -> "(display *)\n" + (wordWrap indentAt wrapAt x)
let divertPart (n: Node) =
match n.Divert with
| None -> ""
| Some "END" -> "(terminating *)\n"
| Some x -> sprintf "(* flows to #%s)\n" x
let oneChoice (n: Node) indentAt wrapAt =
match n.Condition with
| None -> sprintf "(* offers %s)\n" (namePart n)
| Some x when x.[0] = '(' || x.[0] = '~' ->
sprintf "(* offers %s)\n%s\n" (namePart n) (wordWrap indentAt wrapAt x)
| Some x ->
sprintf "(* offers %s)\n%*s(#%s is exposed)\n" (namePart n) indentAt " " x
let defaultChoice (n: Node) l indentAt =
let rec getName (x: string list) =
match x with
| [] -> []
| (h::t) ->
let choiceName = System.Text.RegularExpressions.Regex.Match(h, "(#\w+)")
let fullChoice = sprintf "%*s(%s is exposed)" indentAt " " choiceName.Value
fullChoice::(getName t)
let otherChoices = getName l |> String.concat "\n"
sprintf "(* flows to %s)\n%s\n" (namePart n) otherChoices
let choicesFor n indentAt wrapAt=
let rec aux consume acc =
match consume with
| [] -> List.rev acc
| h::t when h.Kind = ChoiceNode && h.Label = None && h.Display = None ->
aux t ((defaultChoice h acc indentAt)::acc)
| h::t when h.Kind = ChoiceNode ->
aux t (oneChoice h indentAt wrapAt :: acc)
| _::t -> aux t acc
aux n.Children [] |> String.concat ""
let labelFor (n: Node) indentAt wrapAt =
match n.Label with
| None -> ""
| Some x -> sprintf ("(label *)\n%s") (wordWrap indentAt wrapAt x)
let isSticky (n: Node) =
match n.Sticky with
| false -> ""
| true -> "(sticky *)\n"
let positionPart (n: Node) =
match n.Position with
| None -> ""
| Some x -> sprintf "%%%% source line %d\n" x
let posPart (n: Node) =
match n.Position with
| None -> "[ERROR! No position recorded]"
| Some x -> sprintf "%d" x
let outputKnot indentAt wrapAt n =
let position = positionPart n
let name = namePart n
let display = displayPart n indentAt wrapAt
let divert = divertPart n
let choices = choicesFor n indentAt wrapAt
let label = labelFor n indentAt wrapAt
let sticky = isSticky n
sprintf "%s%s\n%s%s%s%s%s" position name display label divert choices sticky
let warnLooseEnd n =
match n.Kind with
| GatherNode when n.Divert = None && n.Children = [] ->
eprintfn "WARNING: Loose end in node output as %s (node begins at source line %s)?" (namePart n) (posPart n)
| KnotNode when n.Divert = None && n.Children = [] ->
eprintfn "WARNING: Loose end in node output as %s (node begins at source line %s)?" (namePart n) (posPart n)
| _ -> ()
let catalogueNode (n: Node) =
match n.Name with
| None -> ""
| Some x -> x
let catalogueNodes t =
Tree.outputTree catalogueNode t
|> List.filter
(fun (a) -> a <> "")
let checkNode catalogue (n: Node) =
match n.Divert with
| None -> ()
| Some x when List.contains x catalogue -> ()
| Some x when x = "END" -> ()
| Some x ->
eprintfn "WARNING: External divert to '%s' in node output as %s (node begins at source line %s)"
x (namePart n) (posPart n)