/src/org/ooc/backend/cdirty/CGenerator.java

http://github.com/nddrylliog/ooc · Java · 518 lines · 432 code · 82 blank · 4 comment · 45 complexity · 075062166551fe804d737cbbf0702969 MD5 · raw file

  1. package org.ooc.backend.cdirty;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.util.Iterator;
  5. import org.ooc.backend.CachedFileWriter;
  6. import org.ooc.backend.Generator;
  7. import org.ooc.frontend.BuildParams;
  8. import org.ooc.frontend.Visitor;
  9. import org.ooc.frontend.model.Add;
  10. import org.ooc.frontend.model.AddressOf;
  11. import org.ooc.frontend.model.ArrayAccess;
  12. import org.ooc.frontend.model.ArrayLiteral;
  13. import org.ooc.frontend.model.Assignment;
  14. import org.ooc.frontend.model.BinaryCombination;
  15. import org.ooc.frontend.model.BinaryNegation;
  16. import org.ooc.frontend.model.Block;
  17. import org.ooc.frontend.model.BoolLiteral;
  18. import org.ooc.frontend.model.BuiltinType;
  19. import org.ooc.frontend.model.Case;
  20. import org.ooc.frontend.model.Cast;
  21. import org.ooc.frontend.model.CharLiteral;
  22. import org.ooc.frontend.model.ClassDecl;
  23. import org.ooc.frontend.model.CommaSequence;
  24. import org.ooc.frontend.model.Compare;
  25. import org.ooc.frontend.model.ControlStatement;
  26. import org.ooc.frontend.model.CoverDecl;
  27. import org.ooc.frontend.model.Dereference;
  28. import org.ooc.frontend.model.Div;
  29. import org.ooc.frontend.model.Else;
  30. import org.ooc.frontend.model.Expression;
  31. import org.ooc.frontend.model.FloatLiteral;
  32. import org.ooc.frontend.model.FlowControl;
  33. import org.ooc.frontend.model.For;
  34. import org.ooc.frontend.model.Foreach;
  35. import org.ooc.frontend.model.FuncType;
  36. import org.ooc.frontend.model.FunctionCall;
  37. import org.ooc.frontend.model.FunctionDecl;
  38. import org.ooc.frontend.model.If;
  39. import org.ooc.frontend.model.Import;
  40. import org.ooc.frontend.model.Include;
  41. import org.ooc.frontend.model.IntLiteral;
  42. import org.ooc.frontend.model.InterfaceDecl;
  43. import org.ooc.frontend.model.Line;
  44. import org.ooc.frontend.model.Match;
  45. import org.ooc.frontend.model.MemberAccess;
  46. import org.ooc.frontend.model.MemberArgument;
  47. import org.ooc.frontend.model.MemberAssignArgument;
  48. import org.ooc.frontend.model.MemberCall;
  49. import org.ooc.frontend.model.Mod;
  50. import org.ooc.frontend.model.Module;
  51. import org.ooc.frontend.model.Mul;
  52. import org.ooc.frontend.model.Node;
  53. import org.ooc.frontend.model.NodeList;
  54. import org.ooc.frontend.model.Not;
  55. import org.ooc.frontend.model.NullLiteral;
  56. import org.ooc.frontend.model.OpDecl;
  57. import org.ooc.frontend.model.Parenthesis;
  58. import org.ooc.frontend.model.RangeLiteral;
  59. import org.ooc.frontend.model.RegularArgument;
  60. import org.ooc.frontend.model.Return;
  61. import org.ooc.frontend.model.Statement;
  62. import org.ooc.frontend.model.StringLiteral;
  63. import org.ooc.frontend.model.Sub;
  64. import org.ooc.frontend.model.Ternary;
  65. import org.ooc.frontend.model.Type;
  66. import org.ooc.frontend.model.TypeDecl;
  67. import org.ooc.frontend.model.Use;
  68. import org.ooc.frontend.model.ValuedReturn;
  69. import org.ooc.frontend.model.VarArg;
  70. import org.ooc.frontend.model.VariableAccess;
  71. import org.ooc.frontend.model.VariableDecl;
  72. import org.ooc.frontend.model.VersionBlock;
  73. import org.ooc.frontend.model.While;
  74. import org.ooc.frontend.parser.TypeArgument;
  75. import org.ooc.middle.OocCompilationError;
  76. import org.ooc.middle.structs.MultiMap;
  77. import org.ooc.middle.structs.NodeMap;
  78. import org.ubi.SourceReader;
  79. public class CGenerator extends Generator implements Visitor {
  80. public final AwesomeWriter hw;
  81. public final AwesomeWriter cw;
  82. public final AwesomeWriter fw;
  83. public AwesomeWriter current;
  84. public BuildParams params;
  85. public CGenerator(File outPath, Module module) {
  86. super(outPath, module);
  87. String basePath = module.getOutPath();
  88. File hFile = new File(outPath, basePath + ".h");
  89. hFile.getParentFile().mkdirs();
  90. this.hw = new AwesomeWriter(new CachedFileWriter(hFile));
  91. File hForwardFile = new File(outPath, basePath + "-fwd.h");
  92. hForwardFile.getParentFile().mkdirs();
  93. this.fw = new AwesomeWriter(new CachedFileWriter(hForwardFile));
  94. File cFile = new File(outPath, basePath + ".c");
  95. this.cw = new AwesomeWriter(new CachedFileWriter(cFile));
  96. this.current = hw;
  97. }
  98. @Override
  99. public void generate(BuildParams params) throws IOException {
  100. this.params = params;
  101. module.accept(this);
  102. fw.close();
  103. hw.close();
  104. cw.close();
  105. }
  106. public void visit(Module module) throws IOException {
  107. ModuleWriter.write(module, this);
  108. }
  109. public void visit(Add add) throws IOException {
  110. add.getLeft().accept(this);
  111. current.app(" + ");
  112. add.getRight().accept(this);
  113. }
  114. public void visit(Mul mul) throws IOException {
  115. mul.getLeft().accept(this);
  116. current.app(" * ");
  117. mul.getRight().accept(this);
  118. }
  119. public void visit(Sub sub) throws IOException {
  120. if(sub.getLeft() instanceof IntLiteral && ((IntLiteral) sub.getLeft()).getValue().intValue() == 0) {
  121. current.app("-");
  122. } else {
  123. sub.getLeft().accept(this);
  124. current.app(" - ");
  125. }
  126. sub.getRight().accept(this);
  127. }
  128. public void visit(Div div) throws IOException {
  129. div.getLeft().accept(this);
  130. current.app(" / ");
  131. div.getRight().accept(this);
  132. }
  133. public void visit(Not not) throws IOException {
  134. current.app('!');
  135. not.getInner().accept(this);
  136. }
  137. public void visit(BinaryNegation binaryNeg) throws IOException {
  138. current.app('~');
  139. binaryNeg.getInner().accept(this);
  140. }
  141. public void visit(Mod mod) throws IOException {
  142. mod.getLeft().accept(this);
  143. current.app(" % ");
  144. mod.getRight().accept(this);
  145. }
  146. public void visit(Compare compare) throws IOException {
  147. compare.getLeft().accept(this);
  148. switch(compare.getCompareType()) {
  149. case GREATER: current.app(" > "); break;
  150. case GREATER_OR_EQUAL: current.app(" >= "); break;
  151. case LESSER: current.app(" < "); break;
  152. case LESSER_OR_EQUAL: current.app(" <= "); break;
  153. case EQUAL: current.app(" == "); break;
  154. case NOT_EQUAL: current.app(" != "); break;
  155. }
  156. compare.getRight().accept(this);
  157. }
  158. public void visit(FunctionCall functionCall) throws IOException {
  159. CallWriter.write(functionCall, this);
  160. }
  161. public void visit(MemberCall memberCall) throws IOException {
  162. CallWriter.writeMember(memberCall, this);
  163. }
  164. public void visit(Parenthesis parenthesis) throws IOException {
  165. current.app('(');
  166. parenthesis.getExpression().accept(this);
  167. current.app(')');
  168. }
  169. public void visit(Assignment assignment) throws IOException {
  170. Expression left = assignment.getLeft();
  171. if(left instanceof VariableAccess) {
  172. AccessWriter.write((VariableAccess) left, false, this);
  173. } else {
  174. left.accept(this);
  175. }
  176. current.app(' ').app(assignment.getSymbol()).app(' ');
  177. assignment.getRight().accept(this);
  178. }
  179. public void visit(ValuedReturn return1) throws IOException {
  180. current.app("return ");
  181. return1.getExpression().accept(this);
  182. }
  183. public void visit(Return return1) throws IOException {
  184. current.app("return");
  185. }
  186. public void visit(NullLiteral nullLiteral) throws IOException {
  187. LiteralWriter.writeNull(this);
  188. }
  189. public void visit(IntLiteral numberLiteral) throws IOException {
  190. LiteralWriter.writeInt(numberLiteral, this);
  191. }
  192. public void visit(FloatLiteral floatLiteral) throws IOException {
  193. LiteralWriter.writeFloat(floatLiteral, this);
  194. }
  195. public void visit(StringLiteral stringLiteral) throws IOException {
  196. LiteralWriter.writeString(stringLiteral, this);
  197. }
  198. public void visit(RangeLiteral rangeLiteral) throws IOException {
  199. throw new OocCompilationError(rangeLiteral, module,
  200. "Using a range literal outside a foreach is not supported yet.");
  201. }
  202. public void visit(BoolLiteral boolLiteral) throws IOException {
  203. current.app(boolLiteral.getValue() ? "true" : "false");
  204. }
  205. public void visit(CharLiteral charLiteral) throws IOException {
  206. current.app('\'');
  207. current.app(SourceReader.spelled(charLiteral.getValue()));
  208. current.app('\'');
  209. }
  210. public void visit(Line line) throws IOException {
  211. current.nl();
  212. if(params.debug && params.lineDirectives) {
  213. current.app("#line ");
  214. current.app(String.valueOf(module.getReader().getLocation(line.startToken).getLineNumber()));
  215. current.app(" \"");
  216. SourceReader.spelled(module.getReader().getFileName(), current, true);
  217. current.app("\"");
  218. current.nl();
  219. }
  220. if(line.getStatement() instanceof FunctionCall) CallWriter.bypassPrelude = (FunctionCall) line.getStatement();
  221. line.getStatement().accept(this);
  222. if(!(line.getStatement() instanceof ControlStatement || line.getStatement() instanceof VersionBlock || line.getStatement() instanceof Match)) {
  223. current.app(';');
  224. }
  225. }
  226. public void visit(Include include) throws IOException {}
  227. public void visit(If if1) throws IOException {
  228. ControlStatementWriter.writeIf(if1, this);
  229. }
  230. public void visit(Else else1) throws IOException {
  231. ControlStatementWriter.writeElse(else1, this);
  232. }
  233. public void visit(While while1) throws IOException {
  234. ControlStatementWriter.writeWhile(while1, this);
  235. }
  236. public void visit(Foreach foreach) throws IOException {
  237. ControlStatementWriter.writeForeach(foreach, this);
  238. }
  239. public void visit(MemberAccess memberAccess) throws IOException {
  240. AccessWriter.write(memberAccess, this);
  241. }
  242. public void visit(VariableAccess variableAccess) throws IOException {
  243. AccessWriter.write(variableAccess, this);
  244. }
  245. public void visit(ArrayAccess arrayAccess) throws IOException {
  246. AccessWriter.write(arrayAccess, this);
  247. }
  248. public void visit(VariableDecl variableDecl) throws IOException {
  249. VariableDeclWriter.write(variableDecl, this);
  250. }
  251. public void visit(FunctionDecl functionDecl) throws IOException {
  252. FunctionDeclWriter.write(functionDecl, this);
  253. }
  254. public void visit(ClassDecl classDecl) throws IOException {
  255. ClassDeclWriter.write(classDecl, this);
  256. }
  257. public void visit(CoverDecl cover) throws IOException {
  258. CoverDeclWriter.write(cover, this);
  259. }
  260. public void visit(TypeArgument typeArgument) throws IOException {
  261. typeArgument.getType().accept(this);
  262. }
  263. public void visit(RegularArgument regularArgument) throws IOException {
  264. Type type = regularArgument.getType();
  265. if(type.isArray()) {
  266. current.app(((TypeDecl)type.getRef()).getUnderName()).app(' ').app(regularArgument.getName());
  267. for(int i = 0; i < type.getPointerLevel(); i++) {
  268. current.app("[]");
  269. }
  270. } else {
  271. if(type instanceof FuncType) {
  272. TypeWriter.writeFuncPointer((FunctionDecl) type.getRef(), regularArgument.getName(), this);
  273. } else {
  274. TypeWriter.writeSpaced(type, this);
  275. current.app(regularArgument.getName());
  276. }
  277. }
  278. }
  279. public void visit(MemberArgument memberArgument) throws IOException {}
  280. public void visit(MemberAssignArgument memberArgument) throws IOException {}
  281. public void visit(Type type) throws IOException {
  282. TypeWriter.write(type, this);
  283. }
  284. public void visit(VarArg varArg) throws IOException {
  285. current.app("...");
  286. }
  287. public void visit(NodeList<? extends Node> list) throws IOException {
  288. list.acceptChildren(this);
  289. }
  290. public void visit(Block block) throws IOException {
  291. current.nl().openBlock();
  292. block.acceptChildren(this);
  293. current.closeBlock();
  294. }
  295. public void visit(BuiltinType builtinType) throws IOException {}
  296. public void visit(Cast cast) throws IOException {
  297. CastWriter.write(cast, this);
  298. }
  299. public void visit(AddressOf addressOf) throws IOException {
  300. // bitchjump the unnecessary casts
  301. Expression expression = addressOf.getExpression().bitchJumpCasts();
  302. if(expression instanceof VariableAccess) {
  303. VariableAccess varAcc = (VariableAccess) expression;
  304. if(varAcc.getRef() == null) {
  305. System.out.println("Null ref for varAcc to "+varAcc+" (addressOf is "+addressOf);
  306. }
  307. Type varAccType = varAcc.getRef().getType();
  308. if(varAccType.isGeneric()) {
  309. AccessWriter.write(varAcc, false, this);
  310. return;
  311. }
  312. if(varAccType.getReferenceLevel() == 1) {
  313. AccessWriter.write(varAcc, false, this, -1);
  314. return;
  315. }
  316. }
  317. if(expression instanceof Dereference) {
  318. ((Dereference) expression).getExpression().accept(this);
  319. return;
  320. }
  321. current.app('&');
  322. boolean paren = !(addressOf.getExpression() instanceof VariableAccess);
  323. if(paren) current.app('(');
  324. Expression expr = addressOf.getExpression();
  325. while(expr instanceof Cast) {
  326. expr = ((Cast) expr).getInner();
  327. }
  328. expr.accept(this);
  329. if(paren) current.app(')');
  330. }
  331. public void visit(Dereference dereference) throws IOException {
  332. current.app("(*");
  333. dereference.getExpression().accept(this);
  334. current.app(')');
  335. }
  336. public void visit(OpDecl opDecl) throws IOException {
  337. opDecl.getFunc().accept(this);
  338. }
  339. public void visit(Import import1) throws IOException {}
  340. public void visit(ArrayLiteral arrayLiteral) throws IOException {
  341. current.app("(");
  342. Type groundType = arrayLiteral.getType().getGroundType();
  343. if(groundType.getPointerLevel() == 2) {
  344. // awful workaround for array of pointers (e.g. string arrays) - j/ooc's handling of types is broken anyway.
  345. current.app(groundType.getName()).app("*[]");
  346. } else {
  347. arrayLiteral.getType().accept(this);
  348. }
  349. current.app(") {");
  350. Iterator<Expression> iter = arrayLiteral.getElements().iterator();
  351. while(iter.hasNext()) {
  352. Expression element = iter.next();
  353. boolean doCasting = false;
  354. if(!element.getType().getName().equals(arrayLiteral.getType().getName())) {
  355. doCasting = true;
  356. current.app("((");
  357. arrayLiteral.getInnerType().accept(this);
  358. current.app(") ");
  359. }
  360. element.accept(this);
  361. if(doCasting) {
  362. current.app(")");
  363. }
  364. if(iter.hasNext()) current.app(", ");
  365. }
  366. current.app('}');
  367. }
  368. public void visit(Use use) throws IOException {}
  369. public void visit(BinaryCombination binaryCombination) throws IOException {
  370. binaryCombination.getLeft().accept(this);
  371. current.app(' ').app(binaryCombination.getOpString()).app(' ');
  372. binaryCombination.getRight().accept(this);
  373. }
  374. public void visit(MultiMap<?, ?> list) throws IOException {}
  375. public void visit(FlowControl flow) throws IOException {
  376. current.app(flow.getKeyword()).app(";");
  377. }
  378. public void visit(InterfaceDecl interfaceDecl) throws IOException {
  379. // huh.. slack off?
  380. }
  381. public void visit(Ternary ternary) throws IOException {
  382. ternary.getCondition().accept(this);
  383. current.app(" ? ");
  384. ternary.getValueIfTrue().accept(this);
  385. current.app(" : ");
  386. ternary.getValueIfFalse().accept(this);
  387. }
  388. public void visit(Match match) throws IOException {
  389. boolean isFirst = true;
  390. for(Case case1: match.getCases()) {
  391. if(!isFirst) {
  392. current.app(" else ");
  393. }
  394. if(case1.getExpr() == null) {
  395. if(isFirst) current.app(" else ");
  396. } else {
  397. if(case1.isFallthrough()) current.app(' ');
  398. current.app("if (");
  399. case1.getExpr().accept(this);
  400. current.app(")");
  401. }
  402. current.app("{").tab();
  403. for(Line line: case1.getBody()) {
  404. current.newLine();
  405. if(line.getStatement() instanceof FunctionCall) {
  406. CallWriter.bypassPrelude = (FunctionCall) line.getStatement();
  407. }
  408. line.accept(this);
  409. }
  410. current.untab().nl().app("}");
  411. if(isFirst) isFirst = false;
  412. }
  413. }
  414. public void visit(Case case1) throws IOException {
  415. // hmmm... no
  416. }
  417. public void visit(VersionBlock versionBlock) throws IOException {
  418. VersionBlockWriter.writeVersionBlockStart(versionBlock, this);
  419. visit((Block) versionBlock);
  420. VersionBlockWriter.writeVersionBlockEnd(this);
  421. }
  422. public void visit(NodeMap<?, ? extends Node> list) throws IOException {}
  423. public void visit(For for1) throws IOException {
  424. ControlStatementWriter.writeFor(for1, this);
  425. }
  426. public void visit(CommaSequence seq) throws IOException {
  427. current.app("(");
  428. boolean isFirst = true;
  429. for(Statement statement: seq.getBody()) {
  430. if(isFirst) isFirst = false;
  431. else current.app(", ");
  432. statement.accept(this);
  433. }
  434. current.app(")");
  435. }
  436. }