-
Notifications
You must be signed in to change notification settings - Fork 0
/
Parser.impl
148 lines (134 loc) · 3.85 KB
/
Parser.impl
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
146
147
148
IMPLEMENTATION Parser
-- IMPORTS {{{1
IMPORT Bool ONLY or
Seq ONLY :: <> % empty?
Token COMPLETELY
-- GLOBAL FUNCTIONS {{{1
/*
* Parse tokens into abstract syntax tree.
*/
DEF parse (tokens) ==
LET
r1 == parseOpenTag(tokens)
(title, r2) == parseTitle(r1)
(body, r3) == parseBody(r2)
r4 == parseCloseTag(r3)
IN
IF empty?(r4) THEN (html(title, body), r4)
ELSE (fail, r4) FI
-- LOCAL FUNCTIONS {{{1
/*
* Parse opening tags.
*/
FUN parseOpenTag : seq[token] -> seq[token]
DEF parseOpenTag (t :: rest) ==
IF openHtml? (t) or
openTitle?(t) or
openBody? (t) THEN rest
ELSE error :: (t :: rest) FI
/*
* Parse closing tags.
*/
FUN parseCloseTag : seq[token] -> seq[token]
DEF parseCloseTag (<>) == %(error)
DEF parseCloseTag (t :: rest) ==
IF closeHtml? (t) or
closeTitle?(t) or
closeBody? (t) or
closePar? (t) THEN rest
ELSE error :: (t :: rest) FI
/*
* Parse title.
*/
FUN parseTitle : seq[token] -> title ** seq[token]
DEF parseTitle (tokens) ==
LET
r1 == parseOpenTag(tokens)
(words, r2) == parseWords(r1)
r3 == parseCloseTag(r2)
IN
IF error?(r3) THEN (fail, r3)
ELSE (title(words), r3) FI
/*
* Parse words.
*/
FUN parseWords : seq[token] -> seq[string] ** seq[token]
DEF parseWords (token :: rest) ==
IF word?(token) THEN
LET
(words, r1) == parseWords(rest)
IN
(data(token) :: words, r1)
ELSE
(<>, token :: rest) FI
/*
* Parse body.
*/
FUN parseBody : seq[token] -> body ** seq[token]
DEF parseBody (tokens) ==
LET
r1 == parseOpenTag(tokens)
(pars, r2) == parsePars(r1)
r3 == parseCloseTag(r2)
IN
IF error?(r3) THEN (fail, r3)
ELSE (body(pars), r3) FI
/*
* Parse paragraphs.
*/
FUN parsePars : seq[token] -> seq[par] ** seq[token]
DEF parsePars (token :: rest) ==
IF openPar?(token) THEN
LET
(par, r1) == parsePar(token :: rest)
(pars, r2) == parsePars(r1)
IN
(par :: pars, r2)
ELSE
(<>, token :: rest) FI
/*
* Parse opening paragraphs.
*/
FUN openPar? : token -> bool
DEF openPar? (token) ==
openParLeft? (token) or
openParRight? (token) or
openParCenter? (token) or
openParJustify?(token)
/*
* Parse a paragraph.
*/
FUN parsePar : seq[token] -> par ** seq[token]
DEF parsePar (<>) == (fail, %(error))
DEF parsePar (openParLeft :: rest) ==
LET
(words, r1) == parseWords(rest)
r2 == parseCloseTag(r1)
IN
IF error?(r2) THEN (fail, r2)
ELSE (par(words, left), r2) FI
DEF parsePar (openParRight :: rest) ==
LET
(words, r1) == parseWords(rest)
r2 == parseCloseTag(r1)
IN
IF error?(r2) THEN (fail, r2)
ELSE (par(words, right), r2) FI
DEF parsePar (openParCenter :: rest) ==
LET
(words, r1) == parseWords(rest)
r2 == parseCloseTag(r1)
IN
IF error?(r2) THEN (fail, r2)
ELSE (par(words, center), r2) FI
DEF parsePar (openParJustify :: rest) ==
LET
(words, r1) == parseWords(rest)
r2 == parseCloseTag(r1)
IN
IF error?(r2) THEN (fail, r2)
ELSE (par(words, justify), r2) FI
DEF parsePar (tokens) == (fail, error :: tokens)
FUN error? : seq[token] -> bool
DEF error? (error :: _) == true
DEF error? (_) == false