edu.clemson.resolve.misc.Utils.java Source code

Java tutorial

Introduction

Here is the source code for edu.clemson.resolve.misc.Utils.java

Source

/*
 * [The "BSD license"]
 * Copyright (c) 2015 Clemson University
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * 3. The name of the author may not be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package edu.clemson.resolve.misc;

import edu.clemson.resolve.RESOLVECompiler;
import edu.clemson.resolve.parser.ResolveParser;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.tree.ParseTreeProperty;
import org.antlr.v4.runtime.tree.Trees;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/** Some generally useful methods and interfaces. */
public class Utils {

    /**
     * Applies the provided function, {@code f} to all elements of {@code l}, returning a new list of elements of type
     * corresponding to the range of {@code f}.
     *
     * @param l   a starting {@link Collection} of elements
     * @param f   a function to be applied to the elements of {@code l}
     * @param <T> type of the starting collection
     * @param <R> type of resulting list
     *
     * @return a new list of type {@code R}
     */
    @NotNull
    public static <T, R> List<R> apply(@NotNull Collection<T> l, @NotNull Function<T, R> f) {
        return l.stream().map(f).collect(Collectors.toList());
    }

    public static <T, R> void apply(@NotNull Collection<T> input, @NotNull Collection<R> accumulator,
            @NotNull Function<T, Collection<R>> f) {
        for (T t : input) {
            accumulator.addAll(f.apply(t));
        }
    }

    @NotNull
    public static <T> String join(@NotNull Collection<T> data, @NotNull String separator, Function<T, String> f) {
        for (T t : data) {
            f.apply(t);
        }
        return join(data.iterator(), separator, "", "");
    }

    @NotNull
    public static <T> String join(@NotNull Collection<T> data, @NotNull String separator) {
        return join(data.iterator(), separator, "", "");
    }

    @NotNull
    public static <T> String join(@NotNull Collection<T> data, @NotNull String separator, @NotNull String left,
            @NotNull String right) {
        return join(data.iterator(), separator, left, right);
    }

    @NotNull
    public static <T> String join(@NotNull Iterator<T> iter, @NotNull String separator, @NotNull String left,
            @NotNull String right) {
        StringBuilder buf = new StringBuilder();

        while (iter.hasNext()) {
            buf.append(iter.next());
            if (iter.hasNext()) {
                buf.append(separator);
            }
        }
        return left + buf.toString() + right;
    }

    @NotNull
    public static <T> String join(@NotNull T[] array, @NotNull String separator) {
        StringBuilder builder = new StringBuilder();

        for (int i = 0; i < array.length; ++i) {
            builder.append(array[i]);
            if (i < array.length - 1) {
                builder.append(separator);
            }
        }
        return builder.toString();
    }

    @NotNull
    public static <T, R> Map<T, R> zip(@NotNull List<T> l1, @NotNull List<R> l2) throws IllegalArgumentException {
        if (l1.size() != l2.size()) {
            throw new IllegalArgumentException("attempt to zip differently sized lists");
        }
        Map<T, R> result = new LinkedHashMap<>();
        Iterator<R> l2iter = l2.iterator();
        for (T t : l1) {
            result.put(t, l2iter.next());
        }
        return result;
    }

    /**
     * Returns a list of {@code E} given: an expected type {@code T}, some number of concrete syntax {@code nodes},
     * and a mapping from rule contexts to some number of elements descending from {@code E}.
     *
     * @param expectedType the class type to inhabit the returned list
     * @param nodes        a list of concrete syntax nodes, as obtained through a visitor, listener, etc.
     * @param annotations  a map from rule context to the primary supertype of {@code expectedType} ({@code E}).
     * @param <E>          super type of {@code expectedType}.
     * @param <T>          the expected type.
     *
     * @return a list of {@code T}.
     */
    @NotNull
    public static <E, T extends E> List<T> collect(@NotNull Class<T> expectedType,
            @NotNull List<? extends ParseTree> nodes, @NotNull ParseTreeProperty<? extends E> annotations) {
        return nodes.stream().map(x -> expectedType.cast(annotations.get(x))).collect(Collectors.toList());
    }

    @NotNull
    public static Token getModuleCtxName(@NotNull ParseTree ctx) {
        if (ctx instanceof ResolveParser.ModuleDeclContext)
            ctx = ctx.getChild(0);

        if (ctx instanceof ResolveParser.PrecisModuleDeclContext) {
            return ((ResolveParser.PrecisModuleDeclContext) ctx).name;
        } else if (ctx instanceof ResolveParser.PrecisExtModuleDeclContext) {
            return ((ResolveParser.PrecisExtModuleDeclContext) ctx).name;
        } else if (ctx instanceof ResolveParser.FacilityModuleDeclContext) {
            return ((ResolveParser.FacilityModuleDeclContext) ctx).name;
        } else if (ctx instanceof ResolveParser.ConceptModuleDeclContext) {
            return ((ResolveParser.ConceptModuleDeclContext) ctx).name;
        } else if (ctx instanceof ResolveParser.ConceptRealizationModuleDeclContext) {
            return ((ResolveParser.ConceptRealizationModuleDeclContext) ctx).name;
        } else if (ctx instanceof ResolveParser.EnhancementModuleDeclContext) {
            return ((ResolveParser.EnhancementModuleDeclContext) ctx).name;
        } else if (ctx instanceof ResolveParser.EnhancementRealizationModuleDeclContext) {
            return ((ResolveParser.EnhancementRealizationModuleDeclContext) ctx).name;
        } else {
            throw new IllegalArgumentException("unrecognized module");
        }
    }

    /**
     * A general purpose builder for objects of type {@code T}. This interface should be implemented by classes that
     * might benefit from incremental construction -- meaning through chained calls to a series of builder methods that
     * return back a {@code Builder} subclass.
     *
     * @param <T> the type of the object to be built
     *
     * @see edu.clemson.resolve.proving.absyn.PApply.PApplyBuilder for an example usage
     */
    @FunctionalInterface
    public interface Builder<T> {
        @NotNull
        T build();
    }

    /**
     * Returns a new {@link CommonToken} from some arbtrary existing {@code Token}. This is useful for when you want
     * create a {@code Token} consisting of {@code desiredText}, but using existing location information from {@code t}.
     * <p>
     * <strong>NOTE:</strong> if {@code desiredText} is {@code null}, then the text for the resulting {@code Token}
     * will contain whatever text was already in {@code t} starting out.</p>
     *
     * @param t           an existing token (preferably near where {@code desiredText} should appear)
     * @param desiredText the text we want the resulting token to hold
     *
     * @return a new token
     */
    @NotNull
    public static CommonToken createTokenFrom(@NotNull Token t, @Nullable String desiredText) {
        CommonToken result = new CommonToken(t);
        if (desiredText != null) {
            result.setText(desiredText);
        }
        return result;
    }

    /**
     * Returns the raw text encapsulated by a {@link ParserRuleContext} exactly as it appears within whatever
     * sourcecode the user typed in.
     *
     * @param ctx the rule context
     *
     * @return the raw sourcecode represented by {@code ctx}
     * @deprecated use {@link Trees#getNodeText)} instead
     */
    @Deprecated
    @NotNull
    public static String getRawText(@Nullable ParserRuleContext ctx) {
        if (ctx == null)
            return "";
        Interval interval = new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex());
        return ctx.start.getInputStream().getText(interval);
    }

    @Nullable
    public static ParserRuleContext getFirstAncestorOfType(@Nullable ParserRuleContext t,
            @NotNull Class<?>... clazzes) {
        return getFirstAncestorOfType(t, Arrays.asList(clazzes));
    }

    /**
     * Return first ancestor node up the chain towards the root that is in {@code clazzes}. Search includes the
     * current node.
     *
     * @return the found parent, {@code null} if not found.
     */
    @Nullable
    public static ParserRuleContext getFirstAncestorOfType(@Nullable ParserRuleContext t,
            @NotNull List<Class<?>> clazzes) {
        while (t != null) {
            for (Class<?> clazz : clazzes) {
                if (t.getClass() == clazz) {
                    return t;
                }
            }
            t = t.getParent();
        }
        return null;
    }

    /**
     * Strips leading directories off a file's name; for example:
     * {@code ../Foo/precis/Nat_Num_Theory.resolve} grooms to {@code Nat_Num_Theory.resolve}.
     *
     * @param name a file name with zero or more '/' delimited directories
     *
     * @return the extensionless filename
     */
    @NotNull
    public static String groomFileName(@NotNull String name) {
        int start = name.lastIndexOf(File.separatorChar);
        if (start == -1) {
            return name;
        }
        return name.substring(start + 1, name.length());
    }

    @NotNull
    public static String stripFileExtension(@NotNull String name) {
        int lastDot = name.lastIndexOf('.');
        if (lastDot < 0)
            return name;
        return name.substring(0, lastDot);
    }

    //TODO: Add charset parameter 'StandardCharset.' etc.
    @Nullable
    public static String readFile(@Nullable String file) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(file));
        String line = null;
        StringBuilder stringBuilder = new StringBuilder();
        String ls = System.getProperty("line.separator");
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(ls);
        }
        return stringBuilder.toString();
    }

    public static void writeFile(@Nullable String dir, @Nullable String fileName, @Nullable String content) {
        try {
            org.antlr.v4.runtime.misc.Utils.writeFile(dir + File.separator + fileName, content, "UTF-8");
        } catch (IOException ioe) {
            System.err.println("can't write file");
            ioe.printStackTrace(System.err);
        }
    }
}