001/*
002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others
003 *
004 * This program and the accompanying materials are made available under the
005 * terms of the Eclipse Public License 2.0 which is available at
006 * http://www.eclipse.org/legal/epl-2.0.
007 *
008 * SPDX-License-Identifier: EPL-2.0
009 */
010
011package org.eclipse.golo.cli.command;
012
013import com.beust.jcommander.IParameterValidator;
014import com.beust.jcommander.Parameter;
015import com.beust.jcommander.ParameterException;
016import com.beust.jcommander.Parameters;
017import com.beust.jcommander.ParametersDelegate;
018import org.eclipse.golo.cli.command.spi.CliCommand;
019import org.eclipse.golo.compiler.GoloCompilationException;
020import org.eclipse.golo.compiler.GoloCompiler;
021import gololang.ir.GoloModule;
022import gololang.ir.IrTreeDumper;
023import org.eclipse.golo.compiler.parser.ASTCompilationUnit;
024
025import java.io.File;
026import java.io.IOException;
027import java.util.LinkedList;
028import java.util.List;
029
030import static gololang.Messages.*;
031
032@Parameters(commandNames = {"diagnose"}, resourceBundle = "commands", commandDescriptionKey = "diagnose")
033public class DiagnoseCommand implements CliCommand {
034
035  @Parameter(names = "--tool", hidden = true, descriptionKey = "diagnose.tool", validateWith = DiagnoseModeValidator.class)
036  String mode = "ir";
037
038  @Parameter(names = "--stage", descriptionKey = "diagnose.stage", validateWith = DiagnoseStageValidator.class)
039  String stage = "refined";
040
041  @Parameter(description = "source_files")
042  List<String> files = new LinkedList<>();
043
044  @ParametersDelegate
045  ClasspathOption classpath = new ClasspathOption();
046
047  GoloCompiler compiler;
048
049  @Override
050  public void execute() throws Throwable {
051    if ("ast".equals(this.stage) && !"ast".equals(this.mode)) {
052      this.mode = "ast";
053    }
054    if ("ast".equals(this.mode) && !"ast".equals(this.stage)) {
055      this.stage = "ast";
056    }
057    compiler = classpath.initGoloClassLoader().getCompiler();
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        switch (this.stage) {
123          case "raw":
124            break;
125          case "refined":
126            compiler.refine(module);
127            break;
128          default:
129            break;
130        }
131        module.accept(dumper);
132      } catch (IOException e) {
133        error(message("file_not_found", goloFile));
134      }
135      System.out.println();
136    }
137  }
138
139  public static final class DiagnoseModeValidator implements IParameterValidator {
140
141    @Override
142    public void validate(String name, String value) throws ParameterException {
143      warning(message("diagnose_tool_warning"));
144      switch (value) {
145        case "ast":
146        case "ir":
147          return;
148        default:
149          throw new ParameterException(message("diagnose_tool_error", "{ast, ir}"));
150      }
151    }
152  }
153
154  public static final class DiagnoseStageValidator implements IParameterValidator {
155
156    @Override
157    public void validate(String name, String value) throws ParameterException {
158      switch (value) {
159        case "ast":
160        case "raw":
161        case "refined":
162          return;
163        default:
164          throw new ParameterException(message("diagnose_stage_error", "{ast, raw, refined}"));
165      }
166    }
167  }
168
169}