]> gitweb.factorcode.org Git - factor.git/blob - extra/html/parser/parser.factor
Resolved merge.
[factor.git] / extra / html / parser / parser.factor
1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays hashtables sequence-parser
4 html.parser.utils kernel namespaces sequences math
5 unicode.case unicode.categories combinators.short-circuit
6 quoting fry ;
7 IN: html.parser
8
9 TUPLE: tag name attributes text closing? ;
10
11 SINGLETON: text
12 SINGLETON: dtd
13 SINGLETON: comment
14
15 <PRIVATE
16
17 SYMBOL: tagstack
18
19 : push-tag ( tag -- )
20     tagstack get push ;
21
22 : closing-tag? ( string -- ? )
23     [ f ]
24     [ { [ first CHAR: / = ] [ last CHAR: / = ] } 1|| ] if-empty ;
25
26 : <tag> ( name attributes closing? -- tag )
27     tag new
28         swap >>closing?
29         swap >>attributes
30         swap >>name ;
31
32 : make-tag ( string attribs -- tag )
33     [ [ closing-tag? ] keep "/" trim1 ] dip rot <tag> ;
34
35 : new-tag ( text name -- tag )
36     tag new
37         swap >>name
38         swap >>text ; inline
39
40 : (read-quote) ( sequence-parser ch -- string )
41     '[ [ current _ = ] take-until ] [ advance drop ] bi ;
42
43 : read-single-quote ( sequence-parser -- string )
44     CHAR: ' (read-quote) ;
45
46 : read-double-quote ( sequence-parser -- string )
47     CHAR: " (read-quote) ;
48
49 : read-quote ( sequence-parser -- string )
50     dup get+increment CHAR: ' =
51     [ read-single-quote ] [ read-double-quote ] if ;
52
53 : read-key ( sequence-parser -- string )
54     skip-whitespace
55     [ current { [ CHAR: = = ] [ blank? ] } 1|| ] take-until ;
56
57 : read-token ( sequence-parser -- string )
58     [ current blank? ] take-until ;
59
60 : read-value ( sequence-parser -- string )
61     skip-whitespace
62     dup current quote? [ read-quote ] [ read-token ] if
63     [ blank? ] trim ;
64
65 : read-comment ( sequence-parser -- )
66     [ "-->" take-until-sequence comment new-tag push-tag ]
67     [ '[ _ advance drop ] 3 swap times ] bi ;
68
69 : read-dtd ( sequence-parser -- )
70     [ ">" take-until-sequence dtd new-tag push-tag ]
71     [ advance drop ] bi ;
72
73 : read-bang ( sequence-parser -- )
74     advance dup { [ current CHAR: - = ] [ peek-next CHAR: - = ] } 1&&
75     [ advance advance read-comment ] [ read-dtd ] if ;
76
77 : read-tag ( sequence-parser -- string )
78     [ [ current "><" member? ] take-until ]
79     [ dup current CHAR: < = [ advance ] unless drop ] bi ;
80
81 : read-until-< ( sequence-parser -- string )
82     [ current CHAR: < = ] take-until ;
83
84 : parse-text ( sequence-parser -- )
85     read-until-< [ text new-tag push-tag ] unless-empty ;
86
87 : parse-key/value ( sequence-parser -- key value )
88     [ read-key >lower ]
89     [ skip-whitespace "=" take-sequence ]
90     [ swap [ read-value ] [ drop dup ] if ] tri ;
91
92 : (parse-attributes) ( sequence-parser -- )
93     skip-whitespace
94     dup sequence-parse-end? [
95         drop
96     ] [
97         [ parse-key/value swap set ] [ (parse-attributes) ] bi
98     ] if ;
99
100 : parse-attributes ( sequence-parser -- hashtable )
101     [ (parse-attributes) ] H{ } make-assoc ;
102
103 : (parse-tag) ( string -- string' hashtable )
104     [
105         [ read-token >lower ] [ parse-attributes ] bi
106     ] parse-sequence ;
107
108 : read-< ( sequence-parser -- string/f )
109     advance dup current [
110         CHAR: ! = [ read-bang f ] [ read-tag ] if
111     ] [
112         drop f
113     ] if* ;
114
115 : parse-tag ( sequence-parser -- )
116     read-< [ (parse-tag) make-tag push-tag ] unless-empty ;
117
118 : (parse-html) ( sequence-parser -- )
119     dup peek-next [
120         [ parse-text ] [ parse-tag ] [ (parse-html) ] tri
121     ] [ drop ] if ;
122
123 : tag-parse ( quot -- vector )
124     V{ } clone tagstack [ parse-sequence ] with-variable ; inline
125
126 PRIVATE>
127
128 : parse-html ( string -- vector )
129     [ (parse-html) tagstack get ] tag-parse ;