Mercurial Hosting > luan
annotate src/luan/modules/parsers/Theme.java @ 1402:27efb1fcbcb5
move luan.lib to goodjava
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 17 Sep 2019 01:35:01 -0400 |
parents | 88b5b81cad4a |
children |
rev | line source |
---|---|
687 | 1 package luan.modules.parsers; |
2 | |
3 import luan.LuanException; | |
1402
27efb1fcbcb5
move luan.lib to goodjava
Franklin Schmidt <fschmidt@gmail.com>
parents:
1111
diff
changeset
|
4 import goodjava.parser.Parser; |
27efb1fcbcb5
move luan.lib to goodjava
Franklin Schmidt <fschmidt@gmail.com>
parents:
1111
diff
changeset
|
5 import goodjava.parser.ParseException; |
687 | 6 |
7 | |
8 public final class Theme { | |
9 | |
10 public static String toLuan(String source) throws LuanException { | |
11 try { | |
12 return new Theme(source).parse(); | |
13 } catch(ParseException e) { | |
14 throw new LuanException(e.getMessage()); | |
15 } | |
16 } | |
17 | |
18 private final Parser parser; | |
19 | |
20 private Theme(String source) { | |
21 this.parser = new Parser(source); | |
22 } | |
23 | |
24 private ParseException exception(String msg) { | |
25 // parser.failure(); | |
26 return new ParseException(parser,msg); | |
27 } | |
28 | |
29 private String parse() throws ParseException { | |
30 StringBuilder stmts = new StringBuilder(); | |
31 stmts.append( "local M = {}; " ); | |
32 while( !parser.endOfInput() ) { | |
33 String def = parseDef(); | |
34 if( def != null ) { | |
35 stmts.append(def); | |
36 } else { | |
37 // parser.anyChar(); | |
38 stmts.append(parsePadding()); | |
39 } | |
40 } | |
41 stmts.append( "\n\nreturn M\n" ); | |
42 return stmts.toString(); | |
43 } | |
44 | |
45 private String parsePadding() throws ParseException { | |
46 int start = parser.currentIndex(); | |
47 if( parser.match("--") ) { | |
48 while( parser.noneOf("\r\n") ); | |
49 } else if( !parser.anyOf(" \t\r\n") ) { | |
50 throw exception("unexpected text"); | |
51 } | |
52 return parser.textFrom(start); | |
53 } | |
54 | |
55 private String parseDef() throws ParseException { | |
56 int start = parser.begin(); | |
769
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
57 if( !parser.match('{') ) |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
58 return parser.failure(null); |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
59 spaces(); |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
60 if( !parser.match("define:") ) |
687 | 61 return parser.failure(null); |
62 String name = parseName(); | |
63 if( name==null ) | |
64 throw exception("invalid block name"); | |
769
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
65 spaces(); |
687 | 66 if( !parser.match('}') ) |
67 throw exception("unclosed define tag"); | |
68 String block = parseBody("define:"+name); | |
688 | 69 String rtn = "function M." + name + "(env) " + block + " end; "; |
687 | 70 return parser.success(rtn); |
71 } | |
72 | |
73 private String parseBody(String tagName) throws ParseException { | |
74 StringBuilder stmts = new StringBuilder(); | |
75 int start = parser.currentIndex(); | |
76 int end = start; | |
77 while( !matchEndTag(tagName) ) { | |
78 if( parser.endOfInput() ) { | |
79 parser.failure(); | |
80 throw exception("unclosed block"); | |
81 } | |
82 String block = parseBlock(); | |
83 if( block != null ) { | |
84 addText(start,end,stmts); | |
85 start = parser.currentIndex(); | |
86 stmts.append(block); | |
87 continue; | |
88 } | |
89 String simpleTag = parseSimpleTag(); | |
90 if( simpleTag != null ) { | |
91 addText(start,end,stmts); | |
92 start = parser.currentIndex(); | |
93 stmts.append(simpleTag); | |
94 continue; | |
95 } | |
690 | 96 if( parser.match("<%") ) { |
97 addText(start,end,stmts); | |
98 start = parser.currentIndex(); | |
99 stmts.append("%><%='<%'%><%"); | |
100 continue; | |
101 } | |
687 | 102 parser.anyChar(); |
103 end = parser.currentIndex(); | |
104 } | |
105 addText(start,end,stmts); | |
106 return stmts.toString(); | |
107 } | |
108 | |
109 private boolean matchEndTag(String tagName) { | |
110 parser.begin(); | |
769
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
111 if( !parser.match('{') ) |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
112 return parser.failure(); |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
113 spaces(); |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
114 if( !(parser.match('/') && parser.match(tagName)) ) |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
115 return parser.failure(); |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
116 spaces(); |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
117 if( !parser.match('}') ) |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
118 return parser.failure(); |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
119 return parser.success(); |
687 | 120 } |
121 | |
122 private void addText(int start,int end,StringBuilder stmts) { | |
123 if( start < end ) { | |
688 | 124 stmts.append( "%>" ).append( parser.text.substring(start,end) ).append( "<%" ); |
687 | 125 } |
126 } | |
127 | |
128 private String parseBlock() throws ParseException { | |
129 int start = parser.begin(); | |
769
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
130 if( !parser.match('{') ) |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
131 return parser.failure(null); |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
132 spaces(); |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
133 if( !parser.match("block:") ) |
687 | 134 return parser.failure(null); |
135 String name = parseName(); | |
136 if( name==null ) { | |
137 parser.failure(); | |
138 throw exception("invalid block name"); | |
139 } | |
769
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
140 spaces(); |
687 | 141 if( !parser.match('}') ) |
142 return parser.failure(null); | |
143 String block = parseBody("block:"+name); | |
688 | 144 String rtn = " env."+ name + "( env, function(env) " + block + "end); "; |
687 | 145 // String rtn = "<% env." + tag.name + "(" + (tag.attrs.isEmpty() ? "nil" : table(tag.attrs)) + ",env,function(env) %>" + block + "<% end) %>"; |
146 return parser.success(rtn); | |
147 } | |
148 | |
149 private String parseSimpleTag() throws ParseException { | |
150 int start = parser.begin(); | |
151 if( !parser.match('{') ) | |
152 return parser.failure(null); | |
769
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
153 spaces(); |
687 | 154 String name = parseName(); |
155 if( name==null ) | |
156 return parser.failure(null); | |
769
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
157 spaces(); |
687 | 158 if( !parser.match('}') ) |
159 return parser.failure(null); | |
160 // rtn = "<% env." + name + (attrs.isEmpty() ? "()" : table(attrs)) + " %>"; | |
688 | 161 String rtn = " env." + name + "(env); "; |
687 | 162 return parser.success(rtn); |
163 } | |
164 | |
165 private boolean BlankLine() { | |
166 parser.begin(); | |
167 while( parser.anyOf(" \t") ); | |
168 return EndOfLine() ? parser.success() : parser.failure(); | |
169 } | |
170 | |
171 private boolean EndOfLine() { | |
172 return parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' ); | |
173 } | |
174 | |
175 private String parseName() throws ParseException { | |
176 int start = parser.begin(); | |
177 if( parser.match('/') ) { | |
178 parser.failure(); | |
179 throw exception("bad closing tag"); | |
180 } | |
181 if( parser.match("define:") ) { | |
182 parser.failure(); | |
183 throw exception("unexpected definition"); | |
184 } | |
185 if( !FirstNameChar() ) | |
186 return parser.failure(null); | |
187 while( NameChar() ); | |
188 String match = parser.textFrom(start); | |
189 return parser.success(match); | |
190 } | |
191 | |
192 private boolean FirstNameChar() { | |
193 return parser.inCharRange('a', 'z') || parser.inCharRange('A', 'Z') || parser.match('_'); | |
194 } | |
195 | |
196 private boolean NameChar() { | |
197 return FirstNameChar() || parser.inCharRange('0', '9'); | |
198 } | |
199 | |
769
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
200 private void spaces() { |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
201 while( parser.anyOf(" \t") ); |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
202 } |
c5f5b655f1f7
allow spaces in theme tags
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
203 |
687 | 204 } |