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

com.bigcustard.glide.language.Syntax Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
package com.bigcustard.glide.language;

import com.badlogic.gdx.utils.Disposable;
import com.bigcustard.glide.code.SyntaxPart;
import com.bigcustard.util.Tokenizer;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.tuple.Pair;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;

import static com.bigcustard.glide.code.SyntaxPart.Type.*;

public class Syntax implements Disposable {
    private static String[] TOKENS = new String[] {
            " ", "\t", "\n", "\r", "\f", "(", ")", "{", "}", "\"", ".", "[", "]", "==", "<", ">", "<=", ">=",
            "!", "!=", "=", "++", "*=", "/=", "--", "+=", "-=", "+", "-", " / ", "*", "&&", "||", ",", "$", "%", ";", ":"};
    private Keywords languageKeywords;
    private Function> errorChecker;

    private AtomicReference> lastKnownResult = new AtomicReference<>();
    private ExecutorService executorService = Executors.newFixedThreadPool(2);
    private Future futureSyntaxCheck;

    public Syntax(Keywords languageKeywords, Function> errorChecker) {
        this.languageKeywords = languageKeywords;
        this.errorChecker = errorChecker;
    }

    public List parse(String program) {
        List classifiedWordsAndSpaces = categoriseWordsIntoTypes(program);
        return collapseAdjacentPartsWithSameType(classifiedWordsAndSpaces);
    }

    public boolean isValid(String program) {
        return error(program) == null;
    }

    public Pair error(String program) {
        if (futureSyntaxCheck == null || futureSyntaxCheck.isDone()) {
            futureSyntaxCheck = executorService.submit(() -> {
                Pair error = errorChecker.apply(program);
                lastKnownResult.set(error);
            });
        }
        return lastKnownResult.get();
    }

    @SuppressWarnings("unchecked")
    private List categoriseWordsIntoTypes(String program) {
        List wordsAndSpaces = new Tokenizer(program, TOKENS).run();
        return Lists.transform(wordsAndSpaces, word -> new SyntaxPart(word, getType(word)));
    }

    private List collapseAdjacentPartsWithSameType(List classifiedWordsAndSpaces) {
        List collapsed = new ArrayList<>();
        for (SyntaxPart newElement : classifiedWordsAndSpaces) {
            if (!collapsed.isEmpty()) {
                SyntaxPart lastElement = collapsed.get(collapsed.size() - 1);
                if (lastElement.type() == Comment && !newElement.text().contains("\n")) {
                    newElement.type(Comment);
                }
                if (lastElement.type() == UnclosedQuote) {
                    if (newElement.type() == UnclosedQuote) {
                        lastElement.type(Quoted);
                        newElement.type(Quoted);
                    } else {
                        newElement.type(UnclosedQuote);
                    }
                }

                if (lastElement.type() == newElement.type()) {
                    newElement = new SyntaxPart(lastElement.text() + newElement.text(), newElement.type());
                    collapsed.remove(collapsed.size() - 1);
                }

            }
            collapsed.add(newElement);
        }
        return collapsed;
    }

    private SyntaxPart.Type getType(String word) {
        if (Sets.newHashSet(keywords()).contains(word)) {
            return Keyword;
        } else if (word.startsWith(languageKeywords.comment())) {
            return Comment;
        } else if (word.equals("\"")) {
            return UnclosedQuote;
        } else if (Arrays.asList(TOKENS).contains(word)) {
            return Operator;
        }
        return Unclassified;
    }

    private String[] keywords() {
        return ObjectArrays.concat(new FrameworkKeywords().get(), languageKeywords.get(), String.class);
    }

    @Override
    public void dispose() {
        executorService.shutdown();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy