org.lightjason.agentspeak.language.CLiteral.java Source code

Java tutorial

Introduction

Here is the source code for org.lightjason.agentspeak.language.CLiteral.java

Source

/*
 * @cond LICENSE
 * ######################################################################################
 * # LGPL License                                                                       #
 * #                                                                                    #
 * # This file is part of the LightJason AgentSpeak(L++)                                #
 * # Copyright (c) 2015-16, LightJason (info@lightjason.org)                            #
 * # This program is free software: you can redistribute it and/or modify               #
 * # it under the terms of the GNU Lesser General Public License as                     #
 * # published by the Free Software Foundation, either version 3 of the                 #
 * # License, or (at your option) any later version.                                    #
 * #                                                                                    #
 * # This program is distributed in the hope that it will be useful,                    #
 * # but WITHOUT ANY WARRANTY; without even the implied warranty of                     #
 * # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                      #
 * # GNU Lesser General Public License for more details.                                #
 * #                                                                                    #
 * # You should have received a copy of the GNU Lesser General Public License           #
 * # along with this program. If not, see http://www.gnu.org/licenses/                  #
 * ######################################################################################
 * @endcond
 */

package org.lightjason.agentspeak.language;

import com.google.common.base.Charsets;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.hash.Hasher;
import org.lightjason.agentspeak.common.CPath;
import org.lightjason.agentspeak.common.IPath;
import org.lightjason.agentspeak.grammar.CASTVisitorType;
import org.lightjason.agentspeak.grammar.CErrorListener;
import org.lightjason.agentspeak.grammar.IASTVisitorType;
import org.lightjason.agentspeak.grammar.IParserBase;
import org.lightjason.agentspeak.grammar.TypeLexer;
import org.lightjason.agentspeak.grammar.TypeParser;
import org.lightjason.agentspeak.language.execution.IContext;
import org.lightjason.agentspeak.language.variable.IVariable;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * default generic literal class for agent beliefs
 * a literal consists of a functor, an optional list of values and
 * an optional set of annotations, e.g. velocity(50)[source(self)]
 */
public final class CLiteral implements ILiteral {
    /**
     * negation symbol
     */
    private static final String NEGATION = "~";
    /**
     * at symbol
     */
    private static final String AT = "@";
    /**
     * literal annotations
     */
    private final ImmutableMultimap<IPath, ILiteral> m_annotations;
    /**
     * literal values
     */
    private final ImmutableMultimap<IPath, ITerm> m_values;
    /**
     * literal values as list
     */
    private final List<ITerm> m_orderedvalues;
    /**
     * literals functor
     */
    private final IPath m_functor;
    /**
     * negated option
     */
    private final boolean m_negated;
    /**
     * @ prefix is set
     */
    private final boolean m_at;
    /**
     * hash code
     */
    private final int m_hash;
    /**
     * hash of the annotations
     */
    private final int m_annotationhash;
    /**
     * hash of the values
     */
    private final int m_valuehash;

    /**
     * ctor
     *
     * @param p_at @ prefix is set
     * @param p_negated negated flag
     * @param p_functor functor of the literal
     * @param p_values initial list of values
     * @param p_annotations initial set of annotations
     */
    public CLiteral(final boolean p_at, final boolean p_negated, final IPath p_functor,
            final Collection<ITerm> p_values, final Collection<ILiteral> p_annotations) {
        m_at = p_at;
        m_negated = p_negated;
        // create a full copy of the functor, because concurrency modification
        m_functor = new CPath(p_functor);

        // create immutable structures
        final Multimap<IPath, ILiteral> l_annotations = HashMultimap.create();
        p_annotations.forEach(i -> l_annotations.put(i.fqnfunctor(), i));
        m_annotations = ImmutableSetMultimap.copyOf(l_annotations);

        final Multimap<IPath, ITerm> l_values = LinkedListMultimap.create();
        p_values.forEach(i -> l_values.put(i.fqnfunctor(), i));
        m_values = ImmutableListMultimap.copyOf(l_values);

        m_orderedvalues = Collections.unmodifiableList(new LinkedList<>(p_values));

        // calculates hash value
        m_hash = m_functor.hashCode()
                ^ IntStream.range(0, m_orderedvalues.size()).boxed()
                        .mapToInt(i -> (i + 1) * m_orderedvalues.get(i).hashCode()).sum()
                ^ m_annotations.values().stream().mapToInt(Object::hashCode).sum() ^ (m_negated ? 0 : 55529)
                ^ (m_at ? 0 : 8081);

        // calculates the structure hash value (Murmur3) of the value and annotation definition
        // functor will be added iif no literal data exists ( hasher must be existing twice )
        final String l_functor = p_functor.getPath();

        final Hasher l_valuehasher = CCommon.getTermHashing();
        if (m_orderedvalues.stream().filter(i -> i instanceof ILiteral)
                .map(i -> l_valuehasher.putInt(((ILiteral) i).valuehash())).count() == 0) {
            l_valuehasher.putBoolean(m_negated);
            l_valuehasher.putString(l_functor, Charsets.UTF_8);
        }

        final Hasher l_annotationhasher = CCommon.getTermHashing();
        if (m_annotations.values().stream().map(i -> l_annotationhasher.putInt(i.valuehash())).count() == 0) {
            l_annotationhasher.putBoolean(m_negated);
            l_annotationhasher.putString(l_functor, Charsets.UTF_8);
        }

        m_annotationhash = l_annotationhasher.hash().asInt();
        m_valuehash = l_valuehasher.hash().asInt();
    }

    /**
     * factory
     *
     * @param p_functor functor string
     * @param p_values value term
     * @return literal
     */
    public static ILiteral from(final String p_functor, final ITerm... p_values) {
        return from(p_functor, (p_values == null) || (p_values.length == 0) ? Collections.emptySet()
                : Arrays.stream(p_values).collect(Collectors.toList()), Collections.emptySet());
    }

    /**
     * factory
     *
     * @param p_functor functor string
     * @param p_values value ter
     * @return literal
     */
    public static ILiteral from(final String p_functor, final Collection<ITerm> p_values) {
        return from(p_functor, p_values, Collections.emptySet());
    }

    /**
     * factory
     *
     * @param p_functor functor string
     * @param p_values value term
     * @param p_annotations annotation literals
     * @return literal
     */
    public static ILiteral from(final String p_functor, final Collection<ITerm> p_values,
            final Collection<ILiteral> p_annotations) {
        return new CLiteral(p_functor.contains(AT), p_functor.contains(NEGATION),
                CPath.from(p_functor.replace(AT, "").replace(NEGATION, "")), p_values, p_annotations);
    }

    /**
     * stream factory
     *
     * @param p_functor functor
     * @param p_values value stream
     * @param p_annotations annotation stream
     * @return literal
     */
    public static ILiteral from(final String p_functor, final Stream<ITerm> p_values,
            final Stream<ILiteral> p_annotations) {
        return from(p_functor, p_values.collect(Collectors.toList()), p_annotations.collect(Collectors.toList()));
    }

    /**
     * stream factory
     *
     * @param p_functor functor
     * @param p_values value stream
     * @return literal
     */
    public static ILiteral from(final String p_functor, final Stream<ITerm> p_values) {
        return from(p_functor, p_values.collect(Collectors.toList()));
    }

    /**
     * factory
     *
     * @param p_literal literal string
     * @return literal
     *
     * @throws Exception parsing and stream exception
     */
    public static ILiteral parse(final String p_literal) throws Exception {
        return new CParser().parse(new ByteArrayInputStream(p_literal.getBytes(Charset.forName("UTF-8"))))
                .literal();
    }

    @Override
    public final Stream<ITerm> values(final IPath... p_path) {
        return (p_path == null) || (p_path.length < 1) ? m_values.values().stream()
                : p_path.length == 1 ? m_values.asMap().get(p_path[0]).stream()
                        : m_values.asMap().get(p_path[0]).stream().filter(i -> i instanceof ILiteral)
                                .flatMap(i -> ((ILiteral) i).values(Arrays.copyOfRange(p_path, 1, p_path.length)));
    }

    @Override
    public final Stream<ITerm> orderedvalues(final IPath... p_path) {
        return (p_path == null) || (p_path.length < 1) ? m_orderedvalues.stream().sequential()
                : p_path.length == 1
                        ? m_orderedvalues.stream().filter(i -> i.fqnfunctor().equals(p_path[0])).sequential()
                        : m_orderedvalues.stream().filter(i -> i.fqnfunctor().equals(p_path[0]))
                                .filter(i -> i instanceof ILiteral).flatMap(i -> ((ILiteral) i)
                                        .orderedvalues(Arrays.copyOfRange(p_path, 1, p_path.length)));
    }

    @Override
    public final Stream<ILiteral> annotations(final IPath... p_path) {
        return (p_path == null) || (p_path.length < 1) ? m_annotations.values().stream()
                : Arrays.stream(p_path).parallel().flatMap(i -> m_annotations.asMap().get(i).stream());
    }

    @Override
    public final boolean emptyValues() {
        return m_values.isEmpty();
    }

    @Override
    public final boolean emptyAnnotations() {
        return m_annotations.isEmpty();
    }

    @Override
    public final int annotationhash() {
        return m_annotationhash;
    }

    @Override
    public final int valuehash() {
        return m_valuehash;
    }

    @Override
    public final boolean negated() {
        return m_negated;
    }

    @Override
    public final boolean hasAt() {
        return m_at;
    }

    @Override
    public final boolean hasVariable() {
        return Stream
                .concat(m_orderedvalues.parallelStream(),
                        m_annotations.entries().parallelStream().map(Map.Entry::getValue))
                .anyMatch(ITerm::hasVariable);
    }

    @Override
    @SuppressWarnings("unchecked")
    public final ILiteral unify(final IContext p_context) {
        return new CLiteral(m_at, m_negated, m_functor, m_orderedvalues.stream().map(i -> {
            if (i instanceof IVariable<?>) {
                final IVariable<?> l_variable = p_context.instancevariables().get(i.fqnfunctor());
                return (l_variable == null) || (l_variable.allocated()) ? CRawTerm.from(l_variable) : l_variable;
            }
            if (i instanceof ILiteral)
                return ((ILiteral) i).unify(p_context);
            return i;
        }).collect(Collectors.toList()),
                m_annotations.values().stream().map(i -> i.unify(p_context)).collect(Collectors.toSet()));
    }

    @Override
    public final ILiteral allocate(final IContext p_context) {
        return new CLiteral(m_at, m_negated, m_functor, m_orderedvalues.stream().map(i -> {
            if (i instanceof IVariable<?>) {
                final IVariable<?> l_variable = p_context.instancevariables().get(((IVariable<?>) i).fqnfunctor());
                return l_variable == null ? CRawTerm.EMPTY : l_variable;
            }
            if (i instanceof ILiteral)
                return ((ILiteral) i).unify(p_context);
            return i;
        }).collect(Collectors.toList()),
                m_annotations.values().stream().map(i -> i.unify(p_context)).collect(Collectors.toSet()));
    }

    @Override
    public final String functor() {
        return m_functor.getSuffix();
    }

    @Override
    public final IPath functorpath() {
        return m_functor.getSubPath(0, m_functor.size() - 1);
    }

    @Override
    public final IPath fqnfunctor() {
        return m_functor;
    }

    @Override
    @SuppressWarnings("unchecked")
    public final <T> T raw() {
        return (T) this;
    }

    @Override
    public final int hashCode() {
        return m_hash;
    }

    @Override
    public final boolean equals(final Object p_object) {
        return (p_object != null) && (p_object instanceof ILiteral) && (this.hashCode() == p_object.hashCode());
    }

    @Override
    public final ILiteral shallowcopy(final IPath... p_prefix) {
        return (p_prefix == null) || (p_prefix.length == 0)

                ? new CLiteral(m_at, m_negated, m_functor, m_values.values(), m_annotations.values())

                : new CLiteral(m_at, m_negated, p_prefix[0].append(m_functor), m_values.values(),
                        m_annotations.values());
    }

    @Override
    public final ILiteral shallowcopysuffix() {
        return new CLiteral(m_at, m_negated, CPath.from(m_functor.getSuffix()), m_values.values(),
                m_annotations.values());
    }

    @Override
    public final String toString() {
        return MessageFormat.format("{0}{1}{2}{3}{4}", m_negated ? NEGATION : "", m_at ? AT : "", m_functor,
                m_orderedvalues, m_annotations.values());
    }

    @Override
    public final int compareTo(final ILiteral p_literal) {
        return Integer.compare(this.hashCode(), p_literal.hashCode());
    }

    @Override
    @SuppressWarnings("unchecked")
    public final synchronized ITerm deepcopy(final IPath... p_prefix) {
        return (p_prefix == null) || (p_prefix.length == 0)

                ? new CLiteral(m_at, m_negated, m_functor,
                        m_values.values().stream().map(i -> i.deepcopy()).collect(Collectors.toList()),
                        m_annotations.values().stream().map(i -> (ILiteral) i.deepcopy())
                                .collect(Collectors.toSet()))

                : new CLiteral(m_at, m_negated, p_prefix[0].append(m_functor),
                        m_values.values().stream().map(i -> i.deepcopy()).collect(Collectors.toList()),
                        m_annotations.values().stream().map(i -> (ILiteral) i.deepcopy())
                                .collect(Collectors.toSet()));
    }

    @Override
    @SuppressWarnings("unchecked")
    public final synchronized ITerm deepcopysuffix() {
        return new CLiteral(m_at, m_negated, CPath.from(m_functor.getSuffix()),
                m_values.values().stream().map(i -> i.deepcopy()).collect(Collectors.toList()),
                m_annotations.values().stream().map(i -> (ILiteral) i.deepcopy()).collect(Collectors.toSet()));
    }

    /**
     * literal parser
     */
    private static final class CParser extends IParserBase<IASTVisitorType, TypeLexer, TypeParser> {

        /**
         * ctor
         * @throws NoSuchMethodException on ctor-method call
         */
        CParser() throws NoSuchMethodException {
            super(new CErrorListener());
        }

        @Override
        public final IASTVisitorType parse(final InputStream p_stream) throws Exception {
            final IASTVisitorType l_visitor = new CASTVisitorType();
            l_visitor.visit(this.parser(p_stream).literal_type());
            return l_visitor;
        }

        @Override
        protected final Class<TypeLexer> lexerclass() {
            return TypeLexer.class;
        }

        @Override
        protected final Class<TypeParser> parserclass() {
            return TypeParser.class;
        }
    }
}