comparison src/luan/modules/parsers/Theme.java @ 775:1a68fc55a80c

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