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

prerna.sablecc2.PixelRunner Maven / Gradle / Ivy

The newest version!
package prerna.sablecc2;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PushbackReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import prerna.om.Insight;
import prerna.om.Pixel;
import prerna.om.PixelList;
import prerna.reactor.PixelPlanner;
import prerna.sablecc2.lexer.Lexer;
import prerna.sablecc2.lexer.LexerException;
import prerna.sablecc2.node.ARoutineConfiguration;
import prerna.sablecc2.node.PRoutine;
import prerna.sablecc2.node.Start;
import prerna.sablecc2.om.PixelDataType;
import prerna.sablecc2.om.PixelOperationType;
import prerna.sablecc2.om.execptions.SemossPixelException;
import prerna.sablecc2.om.nounmeta.NounMetadata;
import prerna.sablecc2.parser.Parser;
import prerna.sablecc2.parser.ParserException;
import prerna.util.Constants;
import prerna.util.insight.InsightUtility;
import prerna.util.usertracking.IUserTracker;
import prerna.util.usertracking.UserTrackerFactory;

public class PixelRunner {

	private static final Logger classLogger = LogManager.getLogger(PixelRunner.class);

	private static List errorOpTypes = new ArrayList<>();
	static {
		errorOpTypes.add(PixelOperationType.ERROR);
		errorOpTypes.add(PixelOperationType.UNEXECUTED_PIXELS);
		errorOpTypes.add(PixelOperationType.FRAME_SIZE_LIMIT_EXCEEDED);
		errorOpTypes.add(PixelOperationType.USER_INPUT_REQUIRED);
		errorOpTypes.add(PixelOperationType.LOGGIN_REQUIRED_ERROR);
		errorOpTypes.add(PixelOperationType.ANONYMOUS_USER_ERROR);
		errorOpTypes.add(PixelOperationType.INVALID_SYNTAX);
	}
	
	/**
	 * Runs a given pixel expression (can be multiple if semicolon delimited) on a provided data maker 
	 * @param expression			The sequence of semicolon delimited pixel expressions.
	 * 								If just one expression, still must end with a semicolon
	 * @param frame					The data maker to run the pixel expression on
	 */
	
	protected transient GreedyTranslation translation = null;
	protected Insight insight = null;
	protected boolean maintainErrors = false;
	
	protected List results = new ArrayList<>();
	protected List returnPixelList = new ArrayList<>();

	protected List encodingList = new ArrayList<>();
	protected Map encodedTextToOriginal = new HashMap<>();
	
	public void runPixel(String expression, Insight insight) {
		this.insight = insight;
		expression = PixelPreProcessor.preProcessPixel(expression.trim(), this.encodingList, this.encodedTextToOriginal);
		
		try {
			Parser p = new Parser(new Lexer(new PushbackReader(new InputStreamReader(new ByteArrayInputStream(expression.getBytes("UTF-8")), "UTF-8"), expression.length())));
			translation = new GreedyTranslation(this, insight);

			// parsing the pixel - this process also determines if expression is syntactically correct
			Start tree = p.parse();
			// apply the translation.
			tree.apply(translation);
		} catch(SemossPixelException e) {
			classLogger.error(Constants.ERROR_MESSAGE, e);
			if(!e.isContinueThreadOfExecution()) {
				throw e;
			}
		} catch (ParserException | LexerException | IOException e) {
			// we only need to catch invalid syntax here
			// other exceptions are caught in lazy translation
			trackInvalidSyntaxError(expression, e);
			classLogger.error(Constants.STACKTRACE, e);
			String eMessage = e.getMessage();
			if(eMessage.startsWith("[")) {
				Pattern pattern = Pattern.compile("\\[\\d+,\\d+\\]");
				Matcher matcher = pattern.matcher(eMessage);
				if(matcher.find()) {
					String location = matcher.group(0);
					location = location.substring(1, location.length()-1);
					int findIndex = Integer.parseInt(location.split(",")[1]);
					eMessage += ". Error in syntax around " + expression.substring(Math.max(findIndex - 10, 0), Math.min(findIndex + 10, expression.length())).trim();
				}
			}
			// treat this as a META so that FE doesn't record it
			addInvalidSyntaxResult(expression, new NounMetadata(eMessage, PixelDataType.INVALID_SYNTAX, PixelOperationType.ERROR, PixelOperationType.INVALID_SYNTAX), false);
		} finally {
			// help clean up
			if (translation != null) {
				PixelPlanner planner = translation.getPlanner();
				planner.dropGraph();
				planner.getVarStore().remove("$RESULT");
			}
			this.encodingList.clear();
			this.encodedTextToOriginal.clear();
		}
	}
	
	/**
	 * Track the error
	 * @param pixel
	 * @param ex
	 */
	private void trackInvalidSyntaxError(String pixel, Exception ex) {
		IUserTracker tracker = UserTrackerFactory.getInstance();
		if(tracker.isActive()) {
			tracker.trackError(this.insight, pixel, "INVALID_SYNTAX", "INVALID_SYNTAX", false, ex);
		}
	}
	
	/**
	 * Store the terminal output of the pixel statement
	 * @param pixelExpression
	 * @param result
	 * @param isMeta
	 */
	public void addResult(String pixelExpression, NounMetadata result, boolean isMeta) {
		String origExpression = PixelUtility.recreateOriginalPixelExpression(pixelExpression, this.encodingList, this.encodedTextToOriginal);
		this.results.add(result);
		
		// we will start to add to the insight recipe
		// when we have an expression that is returned
		// create the pixel via the correct id
		// or if meta - assign random one
		Pixel pixel = null;
		if(!isMeta) {
			PixelList pixelList = this.insight.getPixelList();
			pixel = pixelList.addPixel(origExpression);
			// add if there is an error or warning
			determineErrorOrWarning(pixel, result);
			pixel.setEndingFrameHeaders(InsightUtility.getAllFrameHeaders(this.insight.getVarStore()));
			if(this.translation != null) {
				Pixel.translationMerge(pixel, this.translation.getPixelObj());
			}
			if(pixel.isReturnedError() && !this.maintainErrors) {
				// we actually need to remove this from the pixel list
				// there is also no sync required 
				List removeId = new ArrayList();
				removeId.add(pixel.getId());
				pixelList.removeIds(removeId, false);
			} else {
				pixelList.syncLastPixel();
			}
			// store this pixel
			// in the return pixel list
			this.returnPixelList.add(pixel);
		} else {
			// store this pixel
			// in the return pixel list
			pixel = new Pixel("meta_unstored", origExpression);
			// make sure the pixel is set to meta
			pixel.setMeta(true);
			// also set the time to run
			if(this.translation != null && this.translation.getPixelObj() != null) {
				pixel.setTimeToRun(this.translation.getPixelObj().getTimeToRun());
			}
			this.returnPixelList.add(pixel);
			// add if there is an error or warning
			determineErrorOrWarning(pixel, result);
		}
	}
	
	/**
	 * Same as addResult but since this is an error we do not want to store it in the pixel recipe
	 * @param pixelExpression
	 * @param result
	 * @param isMeta
	 */
	private void addInvalidSyntaxResult(String pixelExpression, NounMetadata result, boolean isMeta) {
		String origExpression = PixelUtility.recreateOriginalPixelExpression(pixelExpression, this.encodingList, this.encodedTextToOriginal);
		Pixel pixel = new Pixel("meta_unstored", origExpression);
		pixel.setReturnedError(true);
		pixel.setMeta(true);
		// also set the time to run
		if(this.translation.getPixelObj() != null) {
			pixel.setTimeToRun(this.translation.getPixelObj().getTimeToRun());
		}
		this.returnPixelList.add(pixel);
		this.results.add(result);
	}
	
	private void determineErrorOrWarning(Pixel pixel, NounMetadata result) {
		// if the result is a direct error
		if(!Collections.disjoint(errorOpTypes, result.getOpType())) {
			pixel.setReturnedError(true);
			pixel.addErrorMessage(result.getValue() + "");
			return;
		}
		
		// if the result is a direct warning
		if(result.getOpType().contains(PixelOperationType.WARNING)) {
			pixel.setReturnedWarning(true);
			pixel.addWarningMessage(result.getValue() + "");
			return;
		}
		
		// if the result has an additional type
		if(result.getAdditionalReturn() != null) {
			for(NounMetadata addReturn : result.getAdditionalReturn()) {
				// check if add return is an error
				if(!Collections.disjoint(errorOpTypes, addReturn.getOpType())) {
					pixel.setReturnedError(true);
					pixel.addErrorMessage(result.getValue() + "");
					return;
				}
				
				// check if add return is a warning
				if(addReturn.getOpType().contains(PixelOperationType.WARNING)) {
					pixel.setReturnedWarning(true);
					pixel.addWarningMessage(result.getValue() + "");
					return;
				}
			}
		}
	}
	
	public List getResults() {
		return this.results;
	}
	
	public List getReturnPixelList() {
		return this.returnPixelList;
	}
	
	public Insight getInsight() {
		return this.insight;
	}
	
	public void setInsight(Insight insight) {
		this.insight = insight;
	}
	
	public boolean isMaintainErrors() {
		return maintainErrors;
	}

	public void setMaintainErrors(boolean maintainErrors) {
		this.maintainErrors = maintainErrors;
	}

	public void clear() {
		this.results.clear();
		this.returnPixelList.clear();
		this.encodingList.clear();
		this.encodedTextToOriginal.clear();
	}
	
	////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////

	/*
	 * Other methods here
	 */
//	
//	public static void main(String[] args) throws Exception {
//		String pixel = "A = 10; B = \"Apple\";";
//		List x = parsePixel(pixel);
//		logger.info(Utility.cleanLogString(Arrays.toString(x.toArray())));
//	}
	
	/**
	 * 
	 * @param expression
	 * @return
	 * 
	 * Method to take a string and return the parsed value of the pixel
	 */
	public static List parsePixel(String expression) throws ParserException, LexerException, IOException {
		Parser p = new Parser(new Lexer(new PushbackReader(new InputStreamReader(new ByteArrayInputStream(expression.getBytes("UTF-8")), "UTF-8"), expression.length())));
		Start tree = p.parse();

		ARoutineConfiguration configNode = (ARoutineConfiguration)tree.getPConfiguration();

		List pixelList = new ArrayList<>();
		for(PRoutine script : configNode.getRoutine()) {
			pixelList.add(script.toString());
		}
		return pixelList;
	}
	
	/**
	 * 
	 * @param expression
	 * @return
	 * 
	 * returns set of reactors that are not implemented
	 * throws exception if pixel cannot be parsed
	 */
	public static Set validatePixel(String expression) throws ParserException, LexerException, IOException {
		Parser p = new Parser(new Lexer(new PushbackReader(new InputStreamReader(new ByteArrayInputStream(expression.getBytes("UTF-8")), "UTF-8"), expression.length())));
		ValidatorTranslation translation = new ValidatorTranslation();
		// parsing the pixel - this process also determines if expression is syntactically correct
		Start tree = p.parse();
		// apply the translation.
		tree.apply(translation);
		return translation.getUnimplementedReactors();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy