File indexing completed on 2024-06-16 04:26:01
0001 package mso.generator; 0002 0003 import java.io.File; 0004 import java.io.FileWriter; 0005 import java.io.IOException; 0006 import java.io.PrintWriter; 0007 import java.util.regex.Matcher; 0008 import java.util.regex.Pattern; 0009 0010 import org.eclipse.jdt.annotation.Nullable; 0011 0012 import mso.generator.utils.Choice; 0013 import mso.generator.utils.Limitation; 0014 import mso.generator.utils.MSO; 0015 import mso.generator.utils.Member; 0016 import mso.generator.utils.Option; 0017 import mso.generator.utils.Struct; 0018 import mso.generator.utils.Type; 0019 import mso.generator.utils.TypeRegistry; 0020 0021 public class QtApiGenerator { 0022 0023 public class QtApiConfiguration { 0024 @Nullable 0025 public final String namespace; 0026 public final String basename; 0027 public final String outputdir; 0028 public boolean createHeader; 0029 0030 QtApiConfiguration(@Nullable String namespace, String basename, 0031 String outputdir) { 0032 this.namespace = namespace; 0033 this.basename = basename; 0034 this.outputdir = outputdir; 0035 } 0036 } 0037 0038 final public QtApiConfiguration config; 0039 0040 final private String generatedWarning = "/* This code was generated by msoscheme (http://gitorious.org/msoscheme) */"; 0041 0042 public QtApiGenerator(@Nullable String namespace, String basename, 0043 String outputdir) { 0044 config = new QtApiConfiguration(namespace, basename, outputdir); 0045 } 0046 0047 void generate(MSO mso) throws IOException { 0048 FileWriter fout; 0049 if (config.createHeader) { 0050 fout = new FileWriter( 0051 config.outputdir + File.separator + config.basename + ".h"); 0052 } else { 0053 fout = new FileWriter(config.outputdir + File.separator 0054 + config.basename + ".cpp"); 0055 } 0056 PrintWriter out = new PrintWriter(fout); 0057 out.println(generatedWarning); 0058 if (config.createHeader) { 0059 out.println("#ifndef " + config.basename.toUpperCase() + "_H"); 0060 out.println("#define " + config.basename.toUpperCase() + "_H"); 0061 } 0062 out.println("#include \"leinput.h\""); 0063 out.println("namespace " + config.namespace + "{"); 0064 0065 for (Struct s : mso.structs) { 0066 out.println("class " + s.name + ";"); 0067 } 0068 for (Struct s : mso.structs) { 0069 printStructureClassDeclaration(out, s); 0070 } 0071 0072 if (config.createHeader) { 0073 out.println("} // close namespace"); 0074 out.println("#endif"); 0075 out.close(); 0076 fout = new FileWriter(config.outputdir + File.separator 0077 + config.basename + ".cpp"); 0078 out = new PrintWriter(fout); 0079 out.println(generatedWarning); 0080 out.println("#include \"" + config.basename + ".h\""); 0081 } 0082 0083 for (Struct s : mso.structs) { 0084 printStructureDefinition(out, s); 0085 } 0086 0087 if (!config.createHeader) { 0088 out.println("}");// close namespace 0089 } 0090 out.close(); 0091 fout.close(); 0092 } 0093 0094 private static void printStructureClassDeclaration(PrintWriter out, Struct s) { 0095 if (s.size == -1) { 0096 out.println("class " + s.name + " : public ParsedObject {"); 0097 } else { 0098 out.println( 0099 "class " + s.name + " : public FixedSizeParsedObject {"); 0100 } 0101 out.println("private:"); 0102 if (s.size == -1) { 0103 out.println("public:"); 0104 out.println(" " + s.name + "() {}"); 0105 out.println(" explicit " + s.name 0106 + "(const char* data, const quint32 maxsize);"); 0107 } else { 0108 out.println(" static const quint32 _size;"); 0109 out.println("public:"); 0110 out.println( 0111 " static inline quint32 getSize() { return _size; }"); 0112 out.println(" " + s.name + "() {}"); 0113 out.println(" " + s.name 0114 + "(const char* data, quint32/*ignored*/ = 0);// " 0115 + (s.size / 8) + " bytes"); 0116 } 0117 for (Member m : s.members) { 0118 printMemberDeclaration(out, m, s.name); 0119 } 0120 out.println("};"); 0121 } 0122 0123 private String definitionPrefix() { 0124 final String namespace = config.namespace; 0125 return (namespace == null || namespace.length() == 0) ? "" 0126 : config.namespace + "::"; 0127 } 0128 0129 private void printStructureDefinition(PrintWriter out, Struct s) { 0130 // constructor 0131 String c = definitionPrefix() + s.name + "::"; 0132 if (s.size == -1) { 0133 out.println(c + s.name + "(const char* _d, quint32 _maxsize) {"); 0134 } else { 0135 out.println("const quint32 " + c + "_size = " + (s.size / 8) + ";"); 0136 out.println(c + s.name + "(const char* _d, quint32/*ignored*/) {"); 0137 } 0138 out.println(" quint32 _position = 0;"); 0139 out.println(" quint32 _msize;"); 0140 int bytepos = 0; 0141 String sp; 0142 for (Member m : s.members) { 0143 sp = " "; 0144 int msize = getSize(m); 0145 String condition = m.condition; 0146 if (m.isSimple && condition != null) { 0147 condition = fixForMemberName(condition); 0148 out.println( 0149 sp + "bool _has_" + m.name + " = " + condition + ";"); 0150 condition = "_has_" + m.name; 0151 } 0152 if (condition != null) { 0153 condition = fixForMemberName(condition); 0154 out.println(sp + "if (" + condition + ") {"); 0155 sp = " "; 0156 } 0157 if (msize != -1 && s.size == -1) { 0158 out.print(sp + "if (_position + " + msize); 0159 if (m.isOptional) { 0160 sp += " "; 0161 out.println(" <= _maxsize) {"); 0162 } else { 0163 out.println(" > _maxsize) return;"); 0164 } 0165 } 0166 bytepos = printMemberParser(out, sp, s, m, bytepos); 0167 printLimitationCheck(out, sp, m.name, m); 0168 out.println(sp + "_position += _msize;"); 0169 while (sp.length() > 4) { 0170 sp = sp.substring(sp.length() - 4); 0171 out.println(sp + "}"); 0172 } 0173 } 0174 if (s.size == -1) { 0175 out.println(" ParsedObject::init(_d, _position);"); 0176 } else { 0177 out.println(" FixedSizeParsedObject::init(_d);"); 0178 } 0179 out.println("}"); 0180 // access functions 0181 for (Member m : s.members) { 0182 if (m.isArray && m.isStruct) { 0183 // printStructArrayAccessor(out, s, m); 0184 } else if (m.isChoice) { 0185 printChoiceAccessor(out, s, m); 0186 } 0187 } 0188 } 0189 0190 private static int printMemberParser(PrintWriter out, String sp, Struct s, 0191 Member m, int bytepos) { 0192 if (m.isArray) { 0193 if (m.isSimple) { 0194 printSimpleArrayMemberParser(out, sp, s, m); 0195 } else { 0196 printStructArrayMemberParser(out, sp, s, m); 0197 } 0198 if (m.isChoice) { 0199 throw new Error("There should be no choice in an array."); 0200 } 0201 } else { 0202 if (m.isSimple) { 0203 return printSimpleMemberParser(out, sp, s, m, bytepos); 0204 } else if (m.isStruct) { 0205 printStructMemberParser(out, sp, s, m); 0206 } else if (m.isChoice) { 0207 printChoiceMemberParser(out, sp, s, m); 0208 } 0209 } 0210 return 0; 0211 } 0212 0213 private static int printSimpleMemberParser(PrintWriter out, String sp, Struct s, 0214 Member m, int bytepos) { 0215 out.println(sp + "m_" + m.name + " = read" + m.type().name 0216 + ((bytepos > 0) ? "_" + String.valueOf(bytepos) : "") 0217 + "(_d + _position);"); 0218 int size = m.type().size / 8; 0219 if (bytepos != 0 && ((bytepos + m.type().size) % 8) == 0) { 0220 size += 1; 0221 } 0222 bytepos = (bytepos + m.type().size) % 8; 0223 out.println(sp + "_msize = " + size + ";"); 0224 return bytepos; 0225 } 0226 0227 /** return size in bytes **/ 0228 private static int getSize(Member m) { 0229 int size = -1; 0230 if (m.count != null && m.isArray && m.type().size != -1) { 0231 try { 0232 size = m.type().size * Integer.parseInt(m.count) / 8; 0233 } catch (NumberFormatException e) { 0234 size = -1; 0235 } 0236 } else if (m.size != null) { 0237 try { 0238 size = Integer.parseInt(m.size); 0239 } catch (NumberFormatException e) { 0240 size = -1; 0241 } 0242 } else if (!m.isArray) { 0243 return m.type().size / 8; 0244 } 0245 return size; 0246 } 0247 0248 private static void printSimpleArrayMemberParser(PrintWriter out, String sp, 0249 Struct s, Member m) { 0250 if (m.type().size % 8 != 0) { 0251 throw new Error( 0252 "only arrays of types with a size of a multiple of 8 bits are allowed."); 0253 } 0254 // get the expression for the size 0255 int size = getSize(m); 0256 String count = String.valueOf(size * 8 / m.type().size); 0257 if (size == -1) { 0258 if (m.count != null) { 0259 count = m.count; 0260 } else { 0261 count = "(" + m.size + ")/" + (m.type().size / 8); 0262 } 0263 } else { 0264 if (size % (m.type().size / 8) != 0) { 0265 throw new Error( 0266 "array size must be a multiple of the size of the type for " 0267 + m.type().name + " and size " + size); 0268 } 0269 } 0270 count = fixForMemberName(count); 0271 String type = getTypeName(m.type()); 0272 if ("quint8".equals(type)) 0273 type = "char"; 0274 out.println(sp + "m_" + m.name + " = MSOCastArray<" + type + ">((const " 0275 + type + "*)(_d + _position), " + count + ");"); 0276 out.println( 0277 sp + "_msize = (" + count + ")*" + (m.type().size / 8) + ";"); 0278 } 0279 0280 private static void printStructArrayMemberParser(PrintWriter out, String sp, 0281 Struct s, Member m) { 0282 final String mcount = m.count; 0283 if (mcount != null) { 0284 String size = "_maxsize - _position, "; 0285 String count = fixForMemberName(mcount); 0286 if (m.type().size != -1) { 0287 size = (m.type().size / 8) + " * " + count + ", "; 0288 } 0289 out.println(sp + "m_" + m.name + " = MSOArray<" + m.type().name 0290 + ">(_d + _position, " + size + count + ");"); 0291 out.println(sp + "if (m_" + m.name + ".getCount() != " + count 0292 + ") return;"); 0293 } else if (m.size != null) { 0294 String size = fixForMemberName(m.size); 0295 out.println( 0296 sp + "if (_maxsize - _position < " + size + ") return;"); 0297 out.println(sp + "m_" + m.name + " = MSOArray<" + m.type().name 0298 + ">(_d + _position, " + size + ");"); 0299 out.println(sp + "if (m_" + m.name + ".getSize() != " + size 0300 + ") return;"); 0301 } else { 0302 out.println(sp + "m_" + m.name + " = MSOArray<" + m.type().name 0303 + ">(_d + _position, _maxsize - _position);"); 0304 out.println(sp + "if (!m_" + m.name + ".isValid()) return;"); 0305 } 0306 out.println(sp + "_msize = m_" + m.name + ".getSize();"); 0307 } 0308 0309 private static void printStructMemberParser(PrintWriter out, String sp, Struct s, 0310 Member m) { 0311 if (m.type().size == -1) { 0312 out.println(sp + "m_" + m.name + " = " + m.type().name 0313 + "(_d + _position, _maxsize - _position);"); 0314 } else { 0315 out.println(sp + "m_" + m.name + " = " + m.type().name 0316 + "(_d + _position);"); 0317 } 0318 if (m.isOptional) { 0319 out.println(sp + "_msize = (m_" + m.name + ".isPresent()) ?m_" 0320 + m.name + ".getSize() :0;"); 0321 } else if (m.condition != null) { 0322 out.println(sp + "if (!m_" + m.name + ".isPresent()) return;"); 0323 out.println(sp + "_msize = m_" + m.name + ".getSize();"); 0324 } else { 0325 out.println(sp + "if (!m_" + m.name + ".isValid()) return;"); 0326 out.println(sp + "_msize = m_" + m.name + ".getSize();"); 0327 } 0328 } 0329 0330 private static void printChoiceMemberParser(PrintWriter out, String sp, Struct s, 0331 Member m) { 0332 Choice c = (Choice) m.type(); 0333 // try all options until one has non-zero size 0334 // String s = ""; 0335 boolean first = true; 0336 String sp2 = sp; 0337 for (Option o : c.options) { 0338 Type t = o.type; 0339 if (!first) { 0340 out.println(sp + "if (_msize == 0) {"); 0341 } 0342 String name = "m_" + m.name + "._" + t.name; 0343 if (t.size == -1) { 0344 out.println(sp2 + name + " = " + t.name 0345 + "(_d + _position, _maxsize - _position);"); 0346 out.println(sp2 + "_msize = " + name + ".getSize();"); 0347 } else { 0348 out.println(sp2 + name + " = " + t.name + "(_d + _position);"); 0349 out.println(sp2 + "_msize = (" + name + ".isValid()) ?" + t.name 0350 + "::getSize() : 0;"); 0351 } 0352 if (!first) { 0353 out.println(sp + "}"); 0354 } else { 0355 sp2 = sp + " "; 0356 } 0357 first = false; 0358 } 0359 if (!m.isOptional) { 0360 out.println(sp + "if (_msize == 0) return;"); 0361 } 0362 } 0363 0364 private static String getTypeName(Type t) { 0365 TypeRegistry r = t.registry; 0366 if (t instanceof Choice) { 0367 return t.name; 0368 } else if (t == r.bit) { 0369 return "bool"; 0370 } else if (t == r.uint2 || t == r.uint3 || t == r.uint4 || t == r.uint5 0371 || t == r.uint6 || t == r.uint7 || t == r.uint8) { 0372 return "quint8"; 0373 } else if (t == r.uint9 || t == r.uint12 || t == r.uint13 0374 || t == r.uint14 || t == r.uint15 || t == r.uint16) { 0375 return "quint16"; 0376 } else if (t == r.uint20 || t == r.uint30 || t == r.uint32) { 0377 return "quint32"; 0378 } else if (t == r.int16) { 0379 return "qint16"; 0380 } else if (t == r.int32) { 0381 return "qint32"; 0382 } 0383 return t.name; 0384 } 0385 0386 private void printChoiceAccessor(PrintWriter out, Type s, 0387 Member m) { 0388 Choice c = (Choice) m.type(); 0389 out.println("namespace " + config.namespace + " {"); 0390 for (Option o : c.options) { 0391 String t = o.type.name; 0392 out.println(" template <> " + t + " " + s.name + "::C_" + m.name 0393 + "::get<" + t + ">() const {"); 0394 out.println(" return _" + t + ";"); 0395 0396 out.println(" }"); 0397 out.println(" template <> bool " + s.name + "::C_" + m.name 0398 + "::is<" + t + ">() const {"); 0399 out.println(" return _" + t + ".isValid();"); 0400 0401 out.println(" }"); 0402 } 0403 out.println("}"); 0404 } 0405 0406 private static void printMemberDeclaration(PrintWriter out, Member m, 0407 String className) { 0408 String t = getTypeName(m.type()); 0409 if (m.isArray) { 0410 if (m.isSimple) { 0411 if ("quint8".equals(t)) 0412 t = "char"; 0413 out.println("private:"); 0414 out.println(" MSOCastArray<" + t + "> m_" + m.name + ";"); 0415 out.println("public:"); 0416 out.println(" const MSOCastArray<" + t + ">& " + m.name 0417 + "() const { return m_" + m.name + "; }"); 0418 } 0419 if (m.isStruct || m.isChoice) { 0420 if (m.type().size == -1) { 0421 out.println("private:"); 0422 out.println(" MSOArray<" + t + "> m_" + m.name + ";"); 0423 out.println("public:"); 0424 out.println(" inline const MSOArray<" + t + ">& " 0425 + m.name + "() const { return m_" + m.name + "; }"); 0426 } else { 0427 out.println("private:"); 0428 out.println(" MSOArray<" + t + "> m_" + m.name + ";"); 0429 out.println("public:"); 0430 out.println(" inline const MSOArray<" + t + ">& " 0431 + m.name + "() const { return m_" + m.name + "; }"); 0432 } 0433 } 0434 } else if (m.isChoice) { 0435 Choice c = (Choice) m.type(); 0436 out.println("public:"); 0437 out.println(" class C_" + m.name + " {"); 0438 out.println(" friend class " + className + ";"); 0439 out.println(" private:"); 0440 for (Option o : c.options) { 0441 Type ct = o.type; 0442 out.println(" " + ct.name + " _" + ct.name + ";"); 0443 } 0444 out.println(" public:"); 0445 out.println(" template <typename A> A get() const;"); 0446 out.println(" template <typename A> bool is() const;"); 0447 out.println(" };"); 0448 out.println("private:"); 0449 out.println(" C_" + m.name + " m_" + m.name + ";"); 0450 out.println("public:"); 0451 out.println(" C_" + m.name + " " + m.name 0452 + "() const { return m_" + m.name + "; }"); 0453 } else { 0454 if (m.isOptional || m.condition != null) { 0455 if (m.isSimple) { 0456 t = "MSOBasicNullable<" + t + ">"; 0457 } else { 0458 t = "MSONullable<" + t + ">"; 0459 } 0460 } 0461 out.println("private:"); 0462 out.println(" " + t + " m_" + m.name + ";"); 0463 out.println("public:"); 0464 if (!m.isSimple || (m.isOptional || m.condition != null)) { 0465 t = "const " + t + "&"; 0466 } 0467 out.println(" inline " + t + " " + m.name 0468 + "() const { return m_" + m.name + "; }"); 0469 } 0470 } 0471 0472 private static void printLimitationCheck(PrintWriter out, String s, String name, 0473 Member m) { 0474 if (m.type() instanceof Choice) 0475 return; 0476 for (Limitation l : m.limitations) { 0477 String mname = l.name; 0478 if (!"".equals(mname)) { 0479 mname = name + "." + mname; 0480 } else { 0481 mname = name; 0482 } 0483 if (!m.isStruct) { 0484 if (m.condition == null) { 0485 mname = "((" + getTypeName(m.type()) + ")m_" + mname + ")"; 0486 } else { 0487 mname = "((" + getTypeName(m.type()) + ")*m_" + mname + ")"; 0488 } 0489 } 0490 0491 String condition = QtParserGenerator.getLimit(mname, l); 0492 if (m.isStruct) { 0493 condition = fixForMemberName(condition); 0494 } 0495 out.println(s + "if (!(" + condition + ")) {"); 0496 out.println(s + " return;"); 0497 out.println(s + "}"); 0498 } 0499 } 0500 0501 private static boolean isNumber(String n) { 0502 boolean isNumber = true; 0503 try { 0504 Integer.decode(n); 0505 } catch (NumberFormatException e) { 0506 isNumber = false; 0507 } 0508 return isNumber; 0509 } 0510 0511 private final static Pattern pattern1 = Pattern 0512 .compile("(?<=\\W)([a-zA-Z]\\w*)(?=\\W|$)"); 0513 private final static Pattern pattern2 = Pattern 0514 .compile("(^[a-zA-Z]\\w*)(?=\\W|$)"); 0515 0516 private static String fix(String condition, Pattern regex) { 0517 Matcher m = regex.matcher(condition); 0518 StringBuffer sb = new StringBuffer(); 0519 while (m.find()) { 0520 String var = m.group(1); 0521 if (!isNumber(var)) { 0522 var = var + "()"; 0523 } 0524 m.appendReplacement(sb, var); 0525 } 0526 m.appendTail(sb); 0527 return sb.toString(); 0528 } 0529 0530 private static String fixForMemberName(String condition) { 0531 if (condition.startsWith("_has_")) { 0532 return condition; 0533 } 0534 condition = fix(condition, pattern1); 0535 condition = fix(condition, pattern2); 0536 condition = condition.replaceAll("false\\(\\)", "false"); 0537 condition = condition.replaceAll("true\\(\\)", "true"); 0538 return condition; 0539 } 0540 }