PageRenderTime 449ms CodeModel.GetById 151ms app.highlight 181ms RepoModel.GetById 111ms app.codeStats 0ms

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