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

org.watertemplate.interpreter.parser.Lexer Maven / Gradle / Ivy

There is a newer version: 1.2.2
Show newest version
package org.watertemplate.interpreter.parser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static org.watertemplate.interpreter.parser.Terminal.TEXT;


public class Lexer {
    private static final int BUFFER_SIZE = 8192;

    private final char[] buffer = new char[BUFFER_SIZE];
    private List previousCandidates = new ArrayList<>();


    public List lex(final InputStream stream) {

        try (final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream))) {

            List tokens = tokenize(bufferedReader);
            tokens.add(Token.END_OF_INPUT);
            return tokens;

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private List tokenize(final BufferedReader bufferedReader) throws IOException {
        StringBuilder accumulator = new StringBuilder();
        List tokens = new ArrayList<>();

        for (int nReadChars; (nReadChars = bufferedReader.read(buffer, 0, BUFFER_SIZE)) != -1; ) {
            for (int i = 0; i < nReadChars; i++) {
                i = process(accumulator, tokens, i, buffer[i]);
            }
        }

        process(accumulator, tokens, 0, '\0');
        return tokens;
    }

    private int process(final StringBuilder accumulator, final List tokens, int i, char c) {
        String previous = accumulator.toString();
        String current = accumulator.append(c).toString();

        Token accepted = tryToAcceptFrom(previous, current);

        if (accepted != null) {
            tokens.add(accepted);
            accumulator.setLength(0);
            return i - 1;
        }

        return i;
    }

    private Token tryToAcceptFrom(final String previous, final String current) {

        final List currentCandidates = Arrays.asList(Terminal.values()).stream()
                .filter(terminal -> terminal.isCandidateFrom(current))
                .collect(Collectors.toList());

        if (containsOnly(TEXT, currentCandidates) && previousCandidates.isEmpty()) {
            return null;
        }

        if (currentCandidates.isEmpty() && previousCandidates.isEmpty()) {
            return new Token(previous, TEXT);
        }

        if ((currentCandidates.isEmpty() || containsOnly(TEXT, currentCandidates)) && !previousCandidates.isEmpty()) {
            return acceptFrom(previous);
        }

        previousCandidates = currentCandidates;
        return null;
    }

    private Token acceptFrom(final String string) {
        List allAcceptable = previousCandidates.stream()
                .filter(terminal -> terminal.isAcceptableFrom(string))
                .collect(Collectors.toList());

        previousCandidates.clear();
        return new Token(string, allAcceptable);
    }

    private Boolean containsOnly(final Terminal terminal, final List list) {
        return list.size() == 1 && list.contains(terminal);
    }

    //
    // tests only
    List tokenize(String input) {
        StringBuilder accumulator = new StringBuilder();
        List tokens = new ArrayList<>();
        input += '\0';

        for (int i = 0; i < input.length(); i++) {
            i = process(accumulator, tokens, i, input.charAt(i));
        }

        return tokens;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy