package de.peeeq.wurstscript; import com.google.common.collect.Maps; import de.peeeq.wurstscript.ast.*; import de.peeeq.wurstscript.parser.WPos; import java.util.Map; import java.util.Map.Entry; /** * general rules for syntactic sugar: *

* 1. operations must be idempotent: syntacticSugar(syntacticSugar(program)) = syntacticSugar(program) * 2. operations must not depend on other compilation units. */ public class SyntacticSugar { public void removeSyntacticSugar(CompilationUnit root, boolean hasCommonJ) { if (hasCommonJ) { addDefaultImports(root); } rewriteNegatedInts(root); addDefaultConstructors(root); addEndFunctionStatements(root); replaceTypeIdUse(root); } private void replaceTypeIdUse(CompilationUnit root) { final Map replacements = Maps.newLinkedHashMap(); root.accept(new WurstModel.DefaultVisitor() { @Override public void visit(ExprMemberVarDot e) { super.visit(e); if (e.getVarName().equals("typeId")) { replacements.put(e, Ast.ExprTypeId(e.getSource(), e.getLeft().copy())); } } }); doReplacements(replacements, "Cannot use typeId here"); } private void rewriteNegatedInts(CompilationUnit root) { final Map replacements = Maps.newLinkedHashMap(); root.accept(new WurstModel.DefaultVisitor() { @Override public void visit(ExprUnary e) { super.visit(e); if (e.getOpU() == WurstOperator.UNARY_MINUS && e.getRight() instanceof ExprIntVal) { ExprIntVal iv = (ExprIntVal) e.getRight(); ExprIntVal newExpr = Ast.ExprIntVal(e.getSource(), "-" + iv.getValIraw()); replacements.put(e, newExpr); } } }); doReplacements(replacements, "Cannot use typeId here"); } private void doReplacements(Map replacements, String msg) { for (Entry e : replacements.entrySet()) { Expr oldE = e.getKey(); Expr newE = e.getValue(); try { doSingleReplacement(oldE, newE); } catch (ClassCastException ex) { oldE.addError(msg); } } } public void doSingleReplacement(Expr oldE, Expr newE) throws Error { Element parent = oldE.getParent(); for (int i = 0; i < parent.size(); i++) { if (parent.get(i) == oldE) { parent.set(i, newE); return; } } throw new Error("could not replace " + oldE + " with " + newE); } private void addEndFunctionStatements(CompilationUnit root) { root.accept(new WurstModel.DefaultVisitor() { @Override public void visit(ExtensionFuncDef f) { super.visit(f); addEnd(f); } @Override public void visit(FuncDef f) { super.visit(f); addEnd(f); } @Override public void visit(ConstructorDef f) { super.visit(f); addEnd(f); } @Override public void visit(InitBlock f) { super.visit(f); addEnd(f); } @Override public void visit(OnDestroyDef f) { super.visit(f); addEnd(f); } @Override public void visit(ExprStatementsBlock f) { super.visit(f); addEnd(f); } private void addEnd(AstElementWithBody f) { WPos pos = f.attrSource(); pos = pos.withRightPos(pos.getLeftPos() - 1); f.getBody().add(Ast.EndFunctionStatement(pos)); f.getBody().add(0, Ast.StartFunctionStatement(pos)); } }); } private void addDefaultImports(CompilationUnit root) { nextPackage: for (WPackage p : root.attrGetByType().packageDefs) { // add 'import Wurst' if it does not exist for (WImport imp : p.getImports()) { if (imp.getPackagename().equals("Wurst")) { // wurst package already imported continue nextPackage; } if (imp.getPackagename().equals("NoWurst")) { // NoWurst package imported --> no standard lib wanted continue nextPackage; } } WPos source = p.getSource().artificial(); p.getImports().add(Ast.WImport(source, false, false, Ast.Identifier(source, "Wurst"))); } } /** * add a empty default constructor to every class without any constructor */ private void addDefaultConstructors(CompilationUnit root) { for (ClassDef c : root.attrGetByType().classes) { if (c.getConstructors().size() == 0) { // add default constructor if none exists: WPos source = c.getSource().withRightPos(c.getSource().getLeftPos() - 1); c.getConstructors().add(Ast.ConstructorDef( source, Ast.Modifiers(), Ast.WParameters(), Ast.NoSuperConstructorCall(), Ast.WStatements())); } } } }