package com.tr.rp; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.util.Arrays; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.BailErrorStrategy; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.TokenStream; import org.antlr.v4.runtime.misc.ParseCancellationException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import com.tr.rp.ast.statements.Program; import com.tr.rp.base.ExecutionContext; import com.tr.rp.base.Rank; import com.tr.rp.base.RankedItem; import com.tr.rp.exceptions.RPLException; import com.tr.rp.exceptions.RPLInterruptedException; import com.tr.rp.exceptions.RPLMiscException; import com.tr.rp.parser.ConcreteParser; import com.tr.rp.parser.RankPLLexer; import com.tr.rp.parser.RankPLParser; public class RankPL { protected static int maxRank = 0; protected static int rankCutOff = Rank.MAX; protected static int timeOut = Integer.MAX_VALUE; protected static boolean noExecStats = false; protected static boolean noRanks = false; protected static boolean terminateAfterFirst = false; protected static String fileName = null; public static void main(String[] args) { // Handle options if (!parseOptions(args)) { return; } // Parse input String source = ""; try { source = getFileContent(fileName); } catch (IOException e) { System.err.println("I/O Exception while reading source file: " + e.getMessage()); return; } // Parse Program program = null; try { program = parse(source); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } if (program == null) { System.exit(-1); } // Execute try { execute(program, rankCutOff, maxRank, noRanks, terminateAfterFirst); } catch (RPLException e) { System.out.println(e.getDetailedDescription()); System.exit(-1); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } public static Program parse(String source) { RankPLLexer lexer = new RankPLLexer(new ANTLRInputStream(source)); TokenStream tokens = new CommonTokenStream(lexer); RankPLParser parser = new RankPLParser(tokens); parser.setErrorHandler(new BailErrorStrategy()); ConcreteParser classVisitor = new ConcreteParser(); // Parse Program program = null; try { program = (Program) classVisitor.visit(parser.program()); } catch (ParseCancellationException e) { System.out.println("Syntax error"); lexer = new RankPLLexer(new ANTLRInputStream(source)); tokens = new CommonTokenStream(lexer); parser = new RankPLParser(tokens); classVisitor = new ConcreteParser(); try { program = (Program) classVisitor.visit(parser.program()); } catch (Exception ex) { // Ignore } return null; } return program; } /** * Execute program, keeping track of timeout, and print results to console. * * @param program Program to execute * @throws RPLException Exception occurring during execution of program */ public static Map<Integer, Set<String>> execute(Program program, int rankCutOff, int maxRank, boolean noRanks, boolean terminateAfterFirst) throws RPLException { final Map<Integer, Set<String>> resultMap = new LinkedHashMap<Integer, Set<String>>(); ExecutionContext c = new ExecutionContext(); c.setRankCutOff(rankCutOff); long startTime = System.currentTimeMillis(); if (!noRanks) { System.out.println("Rank Outcome"); } try { program.run(c, new Function<RankedItem<String>, Boolean>() { @Override public Boolean apply(RankedItem<String> item) { // Normal termination if (item == null) { return false; } // Terminate due to maxRank if (item.rank > maxRank) { return false; } // Print outcome if (noRanks) { System.out.println(item.item); } else { System.out.println(String.format(" %3d ", item.rank) + item.item); } // Store outcome in map Set<String> rankResults = resultMap.get(item.rank); if (rankResults == null) { rankResults = new LinkedHashSet<String>(); resultMap.put(item.rank, rankResults); } rankResults.add(item.item); // Terminate after first if (terminateAfterFirst) { return false; } // Terminate after time-out if (System.currentTimeMillis() - startTime > timeOut) { System.out.println("Remaining results omitted due to timeout."); return false; } // Continue return true; } }); } catch (RPLInterruptedException ie) { // Thrown due to timeOut, terminateAfterFirst or maxRank } catch (RPLException re) { throw re; } // Print exec stats if (!noExecStats) { System.out.println("Took: " + (System.currentTimeMillis() - startTime) + " ms"); } return resultMap; } /** * @return Options object */ private static Options createOptions() { Options options = new Options(); options.addOption(Option.builder("source").hasArg().argName("source_file") .desc("source file to execute").build()); options.addOption(Option.builder("rank").hasArg().type(Number.class).argName("max_rank") .desc("generate outcomes with ranks up to max_rank (defaults to 0)").build()); options.addOption(Option.builder("all") .desc("generate all outcomes").build()); options.addOption(Option.builder("c").hasArg().type(Number.class).argName("rank_cutoff") .desc("discard computations above this rank (default ∞)").build()); options.addOption(Option.builder("f") .desc("terminate after first answer").build()); options.addOption(Option.builder("t").hasArg().type(Number.class).argName("timeout") .desc("execution time-out (in milliseconds)").build()); options.addOption(Option.builder("ns").desc("don't print execution stats").build()); options.addOption(Option.builder("nr").desc("don't print ranks").build()); options.addOption(Option.builder("help").desc("show help message").build()); options.addOption(Option.builder("version").desc("show version").build()); return options; } /** * Parse options and set static fields. Returns true if successful. * * @param args Options to parse * @return True if execution can proceed */ private static boolean parseOptions(String[] args) { try { CommandLineParser parser = new DefaultParser(); CommandLine cmd = parser.parse(createOptions(), args); if (cmd.hasOption("version")) { printVersion(); return false; } if (cmd.hasOption("help")) { printUsage(); return false; } if (cmd.hasOption("source")) { fileName = cmd.getOptionValue("source"); } else { System.err.println("Missing -source argument"); printUsage(); return false; } if (cmd.hasOption("rank")) { try { maxRank = ((Number) cmd.getParsedOptionValue("rank")).intValue(); } catch (Exception e) { System.err.println("Illegal value provided for -rank option."); return false; } } if (cmd.hasOption("all")) { if (cmd.hasOption("rank")) { System.err.println("Cannot use both -rank and -all options."); return false; } maxRank = Rank.MAX; } if (cmd.hasOption("t")) { try { timeOut = ((Number) cmd.getParsedOptionValue("t")).intValue(); } catch (Exception e) { System.err.println("Illegal value provided for -t option."); return false; } } if (cmd.hasOption("c")) { try { rankCutOff = ((Number) cmd.getParsedOptionValue("c")).intValue(); } catch (Exception e) { System.err.println("Illegal value provided for -c option."); return false; } } if (cmd.hasOption("f")) { terminateAfterFirst = true; } if (cmd.hasOption("ns")) { noExecStats = true; } if (cmd.hasOption("nr")) { noRanks = true; } } catch (ParseException pe) { System.out.println(pe.getMessage()); return false; } return true; } private static void printUsage() { HelpFormatter formatter = new HelpFormatter(); formatter.setWidth(160); List<String> order = Arrays.asList("source", "r", "t", "c", "d", "m", "f", "ns", "nr", "help"); formatter.setOptionComparator(new Comparator<Option>() { @Override public int compare(Option o1, Option o2) { String s1 = ((Option) o1).getOpt(); String s2 = ((Option) o2).getOpt(); return order.indexOf(s1) - order.indexOf(s2); } }); formatter.printHelp("java -jar RankPL.jar", createOptions(), true); } private static void printVersion() { final Properties properties = new Properties(); try { properties.load(new RankPL().getClass().getClassLoader().getResourceAsStream(".properties")); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } System.out.println(properties.getProperty("version")); } public static String getFileContent(String sourceFile) throws IOException { File file = new File(sourceFile); FileInputStream fis = new FileInputStream(file); StringBuilder sb = new StringBuilder(); Reader r = new InputStreamReader(fis, "UTF-8"); // or whatever encoding int ch = r.read(); while (ch >= 0) { sb.append((char) ch); ch = r.read(); } r.close(); return sb.toString(); } }