All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencypher.generator.InteractiveChoices Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2015-2018 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Attribution Notice under the terms of the Apache License 2.0
 *
 * This work was created by the collective efforts of the openCypher community.
 * Without limiting the terms of Section 6, any Derivative Work that is not
 * approved by the public consensus process of the openCypher Implementers Group
 * should not be described as “Cypher” (and Cypher® is a registered trademark of
 * Neo4j Inc.) or as "openCypher". Extensions by implementers or prototypes or
 * proposals for change that have been documented or implemented should only be
 * described as "implementation extensions to Cypher" or as "proposed changes to
 * Cypher that are not yet approved by the openCypher community".
 */
package org.opencypher.generator;

import java.util.function.Function;

import org.opencypher.grammar.BiasedTerms;
import org.opencypher.grammar.CharacterSet;
import org.opencypher.grammar.Grammar;
import org.opencypher.grammar.Optional;
import org.opencypher.grammar.Repetition;
import org.opencypher.tools.grammar.ISO14977;
import org.opencypher.tools.io.LineInput;
import org.opencypher.tools.io.Output;

import static java.lang.Integer.parseUnsignedInt;

import static org.opencypher.tools.Functions.requireNonNull;

public class InteractiveChoices implements Choices
{
    private final Interface repl;

    public InteractiveChoices( LineInput input, Output output, Choices defaultChoices )
    {
        repl = new Interface(
                requireNonNull( LineInput.class, input ),
                requireNonNull( Output.class, output ),
                defaultChoices );
    }

    private interface Default
    {
        T of( Choices defaultChoices, Node location, S in );
    }

    private interface Body
    {
        void write( Output output, S in, T defaultChoice );
    }

    private static class Interface
    {
        private final LineInput input;
        private final Output output;
        private final Choices defaultChoices;

        private Interface( LineInput input, Output output, Choices defaultChoices )
        {
            this.input = input;
            this.output = output;
            this.defaultChoices = defaultChoices;
        }

         T eval( Node loc, S in, Default def, Body body, Function parse )
        {
            T defaultChoice = defaultChoices == null ? null : def.of( defaultChoices, loc, in );
            for (; ; )
            {
                output.append( "At " );
                TracingChoices.location( output, loc );
                body.write( output, in, defaultChoice );
                output.flush();
                String line = input.read().trim();
                if ( line.isEmpty() )
                {
                    if ( defaultChoice != null )
                    {
                        return defaultChoice;
                    }
                    else
                    {
                        output.append( "Invalid input, no default choices available." );
                    }
                }
                else
                {
                    try
                    {
                        T result = parse.apply( line );
                        if ( result == null )
                        {
                            output.append( "Invalid input." );
                        }
                        else
                        {
                            return result;
                        }
                    }
                    catch ( Exception e )
                    {
                        output.append( "Invalid input: " ).append( e.getMessage() );
                    }
                }
                output.println();
            }
        }
    }

    @Override
    public Grammar.Term choose( Node location, BiasedTerms alternatives )
    {
        return repl.eval( location, alternatives, Choices::choose, InteractiveChoices::alternatives,
                          in -> alternatives.term( parseUnsignedInt( in ) ) );
    }

    @Override
    public int repetition( Node location, Repetition repetition )
    {
        return repl.eval( location, repetition, Choices::repetition, InteractiveChoices::repetition,
                          parseInt( repetition ) );
    }

    @Override
    public boolean includeOptional( Node location, Optional optional )
    {
        return repl.eval( location, optional, Choices::includeOptional, InteractiveChoices::optional,
                          InteractiveChoices::parseYesNo );
    }

    @Override
    public int codePoint( Node location, CharacterSet characters )
    {
        return repl.eval( location, characters, Choices::codePoint, InteractiveChoices::character,
                          parseChar( characters ) );
    }

    private static void alternatives( Output output, BiasedTerms alternatives, Grammar.Term def )
    {
        output.println( ", chose one of:" );
        for ( int i = 0, terms = alternatives.terms(); i < terms; i++ )
        {
            output.append( i ).append( ". " );
            Grammar.Term term = alternatives.term( i );
            ISO14977.append( term, output );
            output.append( term == def ? " [default]" : "" );
            output.println();
        }
        output.append( "Chose an alternative [0-" ).append( alternatives.terms() - 1 ).append( "]: " );
    }

    private static void repetition( Output output, Repetition repetition, Integer def )
    {
        output.append( ", how many times should " );
        ISO14977.append( repetition.term(), output );
        output.append( " be repeated? " );
        if ( repetition.limited() )
        {
            output.append( '[' ).append( repetition.minTimes() ).append( repetition.maxTimes() ).append( ']' );
        }
        else
        {
            output.append( "[min " ).append( repetition.minTimes() ).append( ']' );
        }
        if ( def != null )
        {
            output.append( " [default=" ).append( def ).append( ']' );
        }
        output.append( ": " );
    }

    private static void optional( Output output, Optional optional, Boolean def )
    {
        output.append( ", should optional " );
        ISO14977.append( optional.term(), output );
        output.append( " be included? " );
        if ( def == null )
        {
            output.append( "[yn]: " );
        }
        else if ( def )
        {
            output.append( "[Yn]: " );
        }
        else
        {
            output.append( "[yN]: " );
        }
    }

    private static void character( Output output, CharacterSet characters, Integer def )
    {
        output.append( ", emit character" );
        if ( def != null )
        {
            output.append( " [default: 0x" ).append( Integer.toHexString( def ) ).append( "]" );
        }
        output.append( ": " );
    }

    private static Function parseChar( CharacterSet characters )
    {
        return in -> {
            int cp;
            if ( in.length() >= 1 && Character.charCount( in.codePointAt( 0 ) ) == in.length() )
            {
                cp = in.codePointAt( 0 );
            }
            else if ( in.startsWith( "0x" ) )
            {
                cp = Integer.parseInt( in.substring( 2 ), 16 );
            }
            else
            {
                cp = parseUnsignedInt( in );
            }
            return characters.contains( cp ) ? cp : null;
        };
    }

    private static Function parseInt( Repetition repetition )
    {
        return in -> {
            int result = parseUnsignedInt( in );
            return (result < repetition.minTimes() || (repetition.limited() && result > repetition.maxTimes()))
                   ? null : result;
        };
    }

    private static Boolean parseYesNo( String in )
    {
        switch ( in.toLowerCase() )
        {
        case "y":
        case "yes":
            return true;
        case "n":
        case "no":
            return false;
        default:
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy