001/*
002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 */
009
010package org.eclipse.golo.cli.command;
011
012import com.beust.jcommander.IParameterValidator;
013import com.beust.jcommander.Parameter;
014import com.beust.jcommander.ParameterException;
015import com.beust.jcommander.Parameters;
016import com.beust.jcommander.ParametersDelegate;
017import org.eclipse.golo.cli.command.spi.CliCommand;
018import org.eclipse.golo.compiler.GoloCompilationException;
019import org.eclipse.golo.compiler.GoloCompiler;
020import org.eclipse.golo.compiler.ir.GoloModule;
021import org.eclipse.golo.compiler.ir.IrTreeDumper;
022import org.eclipse.golo.compiler.parser.ASTCompilationUnit;
023
024import java.io.File;
025import java.io.IOException;
026import java.util.LinkedList;
027import java.util.List;
028
029import static gololang.Messages.*;
030
031@Parameters(commandNames = {"diagnose"}, resourceBundle = "commands", commandDescriptionKey = "diagnose")
032public class DiagnoseCommand implements CliCommand {
033
034  @Parameter(names = "--tool", hidden = true, descriptionKey = "diagnose.tool", validateWith = DiagnoseModeValidator.class)
035  String mode = "ir";
036
037  @Parameter(names = "--stage", descriptionKey = "diagnose.stage", validateWith = DiagnoseStageValidator.class)
038  String stage = "refined";
039
040  @Parameter(description = "source_files")
041  List<String> files = new LinkedList<>();
042
043  @ParametersDelegate
044  ClasspathOption classpath = new ClasspathOption();
045
046  GoloCompiler compiler = new GoloCompiler();
047
048  @Override
049  public void execute() throws Throwable {
050    if ("ast".equals(this.stage) && !"ast".equals(this.mode)) {
051      this.mode = "ast";
052    }
053    if ("ast".equals(this.mode) && !"ast".equals(this.stage)) {
054      this.stage = "ast";
055    }
056
057    classpath.initGoloClassLoader();
058    try {
059      switch (this.mode) {
060        case "ast":
061          dumpASTs(this.files);
062          break;
063        case "ir":
064          dumpIRs(this.files);
065          break;
066        default:
067          throw new AssertionError("WTF?");
068      }
069    } catch (GoloCompilationException e) {
070      handleCompilationException(e);
071    }
072  }
073
074
075  private void dumpASTs(List<String> files) {
076    for (String file : files) {
077      dumpAST(file);
078    }
079  }
080
081  private void dumpAST(String goloFile) {
082    File file = new File(goloFile);
083    if (file.isDirectory()) {
084      File[] directoryFiles = file.listFiles();
085      if (directoryFiles != null) {
086        for (File directoryFile : directoryFiles) {
087          dumpAST(directoryFile.getAbsolutePath());
088        }
089      }
090    } else if (file.getName().endsWith(".golo")) {
091      System.out.println(">>> AST: " + goloFile);
092      try {
093        ASTCompilationUnit ast = compiler.parse(goloFile);
094        ast.dump("% ");
095        System.out.println();
096      } catch (IOException e) {
097        error(message("file_not_found", goloFile));
098      }
099    }
100  }
101
102  private void dumpIRs(List<String> files) {
103    IrTreeDumper dumper = new IrTreeDumper();
104    for (String file : files) {
105      dumpIR(file, dumper);
106    }
107  }
108
109  private void dumpIR(String goloFile, IrTreeDumper dumper) {
110    File file = new File(goloFile);
111    if (file.isDirectory()) {
112      File[] directoryFiles = file.listFiles();
113      if (directoryFiles != null) {
114        for (File directoryFile : directoryFiles) {
115          dumpIR(directoryFile.getAbsolutePath(), dumper);
116        }
117      }
118    } else if (file.getName().endsWith(".golo")) {
119      System.out.println(">>> IR: " + file);
120      try {
121        GoloModule module = compiler.transform(compiler.parse(goloFile));
122        if ("refined".equals(this.stage)) {
123          compiler.refine(module);
124        }
125        module.accept(dumper);
126      } catch (IOException e) {
127        error(message("file_not_found", goloFile));
128      }
129      System.out.println();
130    }
131  }
132
133  public static final class DiagnoseModeValidator implements IParameterValidator {
134
135    @Override
136    public void validate(String name, String value) throws ParameterException {
137      warning(message("diagnose_tool_warning"));
138      switch (value) {
139        case "ast":
140        case "ir":
141          return;
142        default:
143          throw new ParameterException(message("diagnose_tool_error", "{ast, ir}"));
144      }
145    }
146  }
147
148  public static final class DiagnoseStageValidator implements IParameterValidator {
149
150    @Override
151    public void validate(String name, String value) throws ParameterException {
152      switch (value) {
153        case "ast":
154        case "raw":
155        case "refined":
156          return;
157        default:
158          throw new ParameterException(message("diagnose_stage_error", "{ast, raw, refined}"));
159      }
160    }
161  }
162
163}