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

com.github.bloodshura.x.venus.executor.VenusExecutor Maven / Gradle / Ivy

/*
 * Copyright (c) 2013-2018, João Vitor Verona Biazibetti - All Rights Reserved
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see .
 *
 * https://www.github.com/BloodShura
 */

package com.github.bloodshura.x.venus.executor;

import com.github.bloodshura.x.activity.logging.XLogger;
import com.github.bloodshura.x.collection.list.XListIterator;
import com.github.bloodshura.x.collection.store.impl.XQueue;
import com.github.bloodshura.x.runnable.ThreadPool;
import com.github.bloodshura.x.runnable.XThread;
import com.github.bloodshura.x.venus.component.AsyncContainer;
import com.github.bloodshura.x.venus.component.Component;
import com.github.bloodshura.x.venus.component.Container;
import com.github.bloodshura.x.venus.component.SimpleComponent;
import com.github.bloodshura.x.venus.component.branch.*;
import com.github.bloodshura.x.venus.exception.runtime.InvalidValueTypeException;
import com.github.bloodshura.x.venus.exception.runtime.ScriptRuntimeException;
import com.github.bloodshura.x.venus.expression.Expression;
import com.github.bloodshura.x.venus.function.Definition;
import com.github.bloodshura.x.venus.origin.ScriptMode;
import com.github.bloodshura.x.venus.value.BoolValue;
import com.github.bloodshura.x.venus.value.DecimalValue;
import com.github.bloodshura.x.venus.value.IntegerValue;
import com.github.bloodshura.x.venus.value.IterableValue;
import com.github.bloodshura.x.venus.value.NumericValue;
import com.github.bloodshura.x.venus.value.Value;

import java.util.function.Supplier;

public class VenusExecutor {
	private final XQueue asyncExceptions;
	private final ThreadPool asyncThreads;
	private boolean breaking;
	private boolean continuing;
	private boolean shouldRun;

	public VenusExecutor() {
		this.asyncExceptions = new XQueue<>();
		this.asyncThreads = new ThreadPool();
		this.shouldRun = true;
	}

	public Value run(Container container, ScriptMode mode) throws ScriptRuntimeException {
		return run(container, mode, () -> shouldRun);
	}

	public void stop() {
		this.shouldRun = false;
	}

	protected Value run(Container container, ScriptMode mode, Supplier shouldRun) throws ScriptRuntimeException {
		Context context = container.getContext();
		XListIterator iterator = container.getChildren().iterator();
		Value result = new IntegerValue(0);
		boolean hadIfAndNotProceed = false;

		container.getApplicationContext().setExecutor(this);

		while (shouldRun.get() && iterator.hasNext()) {
			Component component = iterator.next();

			if (breaking || continuing) {
				break;
			}

			if (!asyncExceptions.isEmpty()) {
				throw asyncExceptions.poll();
			}

			container.getApplicationContext().setCurrentLine(component.getSourceLine());

			if (component instanceof Container) {
				if (component instanceof AsyncContainer) {
					AsyncContainer asyncContainer = (AsyncContainer) component;
					XThread thread = new XThread("AsyncVenusThread", () -> {
						VenusExecutor executor = new VenusExecutor();

						try {
							executor.run(asyncContainer, mode, () -> VenusExecutor.this.shouldRun);
						}
						catch (ScriptRuntimeException exception) {
							asyncExceptions.push(exception);
						}
						catch (Exception exception) {
							XLogger.println(exception);
						}
					});

					asyncThreads.add(thread);
					thread.setDaemon(asyncContainer.isDaemon());
					thread.start();
				}
				else if (component instanceof ForEachContainer) {
					ForEachContainer forContainer = (ForEachContainer) component;
					Expression expression = forContainer.getIterable();
					Value value = expression.resolve(context);

					if (value instanceof IterableValue) {
						IterableValue iterable = (IterableValue) value;

						for (Value element : iterable) {
							context.setVar(forContainer.getVarName(), element);
							run(forContainer, mode, shouldRun);

							if (breaking) {
								this.breaking = false;

								break;
							}

							if (continuing) {
								this.continuing = false;
							}
						}
					}
					else {
						throw new InvalidValueTypeException(context, "For value \"" + value + "\" is not iterable");
					}
				}
				else if (component instanceof ForRangeContainer) {
					ForRangeContainer forContainer = (ForRangeContainer) component;
					Value from = forContainer.getFrom().resolve(context);
					Value to = forContainer.getTo().resolve(context);

					if (from instanceof NumericValue) {
						if (to instanceof NumericValue) {
							NumericValue numericFrom = (NumericValue) from;
							NumericValue numericTo = (NumericValue) to;
							boolean isDecimal = numericFrom instanceof DecimalValue || numericTo instanceof DecimalValue;
							Value count = isDecimal ? new DecimalValue(numericFrom.value().doubleValue()) : new IntegerValue(numericFrom.value().longValue());

							while (count.lowerEqualThan(to).value().equals(true)) {
								context.setVar(forContainer.getVarName(), count);
								run(forContainer, mode, shouldRun);

								if (breaking) {
									this.breaking = false;

									break;
								}

								if (continuing) {
									this.continuing = false;
								}

								count = forContainer.getAdjustment().resolve(context);
							}
						}
						else {
							throw new InvalidValueTypeException(context, "For end \"" + to + "\" is not a numeric value");
						}
					}
					else {
						throw new InvalidValueTypeException(context, "For start \"" + from + "\" is not a numeric value");
					}
				}
				else if (component instanceof WhileContainer) {
					WhileContainer whileContainer = (WhileContainer) component;

					while (true) {
						Value value = whileContainer.getCondition().resolve(context);

						if (value instanceof BoolValue) {
							BoolValue boolValue = (BoolValue) value;

							if (boolValue.value()) {
								run(whileContainer, mode, shouldRun);

								if (breaking) {
									this.breaking = false;

									break;
								}

								if (continuing) {
									this.continuing = false;
								}
							}
							else {
								break;
							}
						}
						else {
							throw new InvalidValueTypeException(context, "Cannot apply while condition in value of type " + value.getType());
						}
					}
				}
				else if (component instanceof DoWhileContainer) {
					DoWhileContainer doWhileContainer = (DoWhileContainer) component;

					while (true) {
						run(doWhileContainer, mode, shouldRun);

						if (breaking) {
							this.breaking = false;

							break;
						}

						if (continuing) {
							this.continuing = false;
						}

						if (!doWhileContainer.hasCondition()) {
							break;
						}

						Value value = doWhileContainer.getCondition().resolve(context);

						if (value instanceof BoolValue) {
							BoolValue boolValue = (BoolValue) value;

							if (!boolValue.value()) {
								break;
							}
						}
						else {
							throw new InvalidValueTypeException(context, "Cannot apply while condition in value of type " + value.getType());
						}
					}
				}
				else if (component instanceof IfContainer || (component instanceof ElseIfContainer && hadIfAndNotProceed)) {
					IfContainer ifContainer = (IfContainer) component;
					Value value = ifContainer.getCondition().resolve(context);

					if (value instanceof BoolValue) {
						BoolValue boolValue = (BoolValue) value;

						if (boolValue.value()) {
							run(ifContainer, mode, shouldRun);
						}
						else {
							hadIfAndNotProceed = true;

							continue;
						}
					}
					else {
						throw new InvalidValueTypeException(context, "Cannot apply if condition in value of type " + value.getType());
					}
				}
				else if (component instanceof ElseContainer) {
					if (hadIfAndNotProceed) {
						run((Container) component, mode, shouldRun);
					}
				}
				else if (!(component instanceof Definition)) {
					run((Container) component, mode, shouldRun);
				}
			}
			else if (component instanceof Break) {
				this.breaking = true;
			}
			else if (component instanceof Continue) {
				this.continuing = true;
			}
			else if (component instanceof Return) {
				Return returner = (Return) component;
				Value value = returner.getExpression().resolve(context);

				if (value != null) {
					result = value;
				}

				break;
			}
			else if (component instanceof SimpleComponent) {
				SimpleComponent simple = (SimpleComponent) component;
				Value value = simple.getExpression().resolve(context);

				if (value != null) {
					if (mode == ScriptMode.EVALUATION) {
						result = value;
					}
					else if (mode == ScriptMode.INTERACTIVE) {
						result = value;
						XLogger.println(value);
					}
				}
			}

			hadIfAndNotProceed = false;
		}

		//asyncThreads.join(); // TODO Bugged. Removed temporarily.

		if (!asyncExceptions.isEmpty()) {
			throw asyncExceptions.poll();
		}

		return result;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy