1 USING: accessors assocs globs io.pathnames kernel memoize
2 namespaces regexp sequences sorting splitting strings
3 unicode xml xml.data xml.syntax xml.traversal xmode.loader
4 xmode.rules xmode.utilities ;
7 TUPLE: mode file file-name-glob first-line-glob ;
9 TAGS: parse-mode-tag ( modes tag -- )
11 TAG: MODE parse-mode-tag
15 { "FILE_NAME_GLOB" f file-name-glob<< }
16 { "FIRST_LINE_GLOB" f first-line-glob<< }
18 [ [ >case-fold <glob> ] [ f ] if* ] change-file-name-glob
19 [ [ >case-fold <glob> ] [ f ] if* ] change-first-line-glob
23 : parse-modes-tag ( tag -- modes )
25 swap children-tags [ parse-mode-tag ] with each
28 MEMO: modes ( -- modes )
29 "vocab:xmode/modes/catalog"
30 file>xml parse-modes-tag ;
32 MEMO: mode-names ( -- modes )
33 modes keys natural-sort ;
35 : reset-catalog ( -- )
36 \ modes reset-memoized ;
38 MEMO: (load-mode) ( name -- rule-sets )
41 "vocab:xmode/modes/" prepend parse-mode
48 : no-such-rule-set ( name -- * )
49 "No such rule set: " prepend throw ;
51 : get-rule-set ( name -- rule-sets rules )
52 dup "::" split1 [ swap (load-mode) ] [ rule-sets get ] if*
53 [ at* [ nip ] [ drop no-such-rule-set ] if ] keep swap ;
55 DEFER: finalize-rule-set
57 : resolve-delegate ( rule -- )
58 dup delegate>> dup string? [
60 dup rule-set? [ "not a rule set" throw ] unless
61 swap rule-sets [ dup finalize-rule-set ] with-variable
65 : each-rule ( rule-set quot -- )
66 [ rules>> values concat ] dip each ; inline
68 : resolve-delegates ( ruleset -- )
69 [ resolve-delegate ] each-rule ;
71 : ?update ( keyword-map/f keyword-map -- keyword-map )
72 over [ assoc-union! ] [ nip clone ] if ;
74 : import-keywords ( parent child -- )
75 over [ [ keywords>> ] bi@ ?update ] dip keywords<< ;
77 : import-rules ( parent child -- )
78 swap [ add-rule ] curry each-rule ;
80 : resolve-imports ( ruleset -- )
82 get-rule-set swap rule-sets [
83 [ nip resolve-delegates ]
90 : finalize-rule-set ( ruleset -- )
91 dup finalized?>> [ drop ] [
98 : finalize-mode ( rulesets -- )
100 [ nip finalize-rule-set ] assoc-each
103 : load-mode ( name -- rule-sets )
104 (load-mode) dup finalize-mode ;
107 \ (load-mode) reset-memoized ;
109 : ?matches ( string glob/f -- ? )
110 [ >case-fold ] dip dup [ matches? ] [ 2drop f ] if ;
112 : suitable-mode? ( file-name first-line mode -- ? )
113 [ nip ] 2keep first-line-glob>> ?matches
114 [ 2drop t ] [ file-name-glob>> ?matches ] if ;
116 : ?find-mode ( file-name first-line -- mode/f )
119 [ nip [ 2dup ] dip suitable-mode? ] assoc-find
122 : find-mode ( file-name first-line -- mode )
123 ?find-mode "text" or ; inline