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

prompto.constraint.MatchingCollectionConstraint Maven / Gradle / Ivy

The newest version!
package prompto.constraint;

import prompto.compiler.CompilerUtils;
import prompto.compiler.Flags;
import prompto.compiler.IInstructionListener;
import prompto.compiler.MethodConstant;
import prompto.compiler.MethodInfo;
import prompto.compiler.OffsetListenerConstant;
import prompto.compiler.Opcode;
import prompto.compiler.ResultInfo;
import prompto.compiler.StackState;
import prompto.compiler.StringConstant;
import prompto.error.PromptoError;
import prompto.expression.IExpression;
import prompto.grammar.Identifier;
import prompto.intrinsic.PromptoException;
import prompto.runtime.Context;
import prompto.runtime.Variable;
import prompto.store.InvalidValueError;
import prompto.transpiler.Transpiler;
import prompto.type.IType;
import prompto.utils.CodeWriter;
import prompto.value.IContainer;
import prompto.value.IValue;

public class MatchingCollectionConstraint extends MatchingConstraintBase {
	
	IExpression collection;
	
	public MatchingCollectionConstraint(IExpression collection) {
		this.collection = collection;
	}
	
	@Override
	public void checkValue(Context context, IValue value) throws PromptoError {
		Object container = collection.interpret(context);
		if(container instanceof IContainer) {
			if(!((IContainer)container).hasItem(context, value))
				throw new InvalidValueError(String.valueOf(value) + collectionToString());
		} else
			throw new InvalidValueError("Not a collection: " + collection.toString());
	}
	
	private String collectionToString() {
		return " is not in collection: " + collection.toString();
	}

	@Override
	public void toDialect(CodeWriter writer) {
		writer.append(" in ");
		collection.toDialect(writer);
	}
	
	@Override
	public void compile(Context context, MethodInfo method, Flags flags) {
		ResultInfo info = collection.compile(context, method, flags.withPrimitive(true));
		CompilerUtils.compileALOAD(method, "value");
		MethodConstant m = new MethodConstant(info.getType(), "contains", Object.class, boolean.class);
		method.addInstruction(Opcode.INVOKEVIRTUAL, m);
		// 1 = success
		IInstructionListener finalListener = method.addOffsetListener(new OffsetListenerConstant());
		method.activateOffsetListener(finalListener);
		method.addInstruction(Opcode.IFNE, finalListener); 
		StackState finalState = method.captureStackState();
		// build failure message
		method.addInstruction(Opcode.LDC, new StringConstant("INVALID_VALUE"));
		CompilerUtils.compileALOAD(method, "value");
		m = new MethodConstant(String.class, "valueOf", Object.class, String.class);
		method.addInstruction(Opcode.INVOKESTATIC, m);
		String message = " does not match:" + collectionToString();
		method.addInstruction(Opcode.LDC, new StringConstant(message));
		m = new MethodConstant(String.class, "concat", String.class, String.class);
		method.addInstruction(Opcode.INVOKEVIRTUAL, m);
		// throw exception
		m = new MethodConstant(PromptoException.class, "throwEnumeratedException", String.class, String.class, void.class);
		method.addInstruction(Opcode.INVOKESTATIC, m);
		// success/final
		method.restoreFullStackState(finalState);
		method.placeLabel(finalState);
		method.inhibitOffsetListener(finalListener);		
	}
	
	@Override
	public void declare(Transpiler transpiler, String name, IType type) {
	    transpiler = transpiler.newChildTranspiler();
	    Identifier id = new Identifier("value");
	    transpiler.getContext().registerInstance(new Variable(id, type));
	    this.collection.declare(transpiler);
	    this.transpileFunction = t -> this.transpileChecker(t, name, type);
	    transpiler.declare(this);
	    transpiler.require("StrictSet");
	}

	private boolean transpileChecker(Transpiler transpiler, String name, IType type) {
	    transpiler.append("function $check_").append(name).append("(value) {").indent();
	    transpiler = transpiler.newChildTranspiler();
	    Identifier id = new Identifier("value");
	    transpiler.getContext().registerInstance(new Variable(id, type));
	    transpiler.append("if(");
	    this.collection.transpile(transpiler);
	    transpiler.append(".has(value))").indent();
	    transpiler.append("return value;").dedent();
	    transpiler.append("else").indent();
	    transpiler.append("throw new IllegalValueError((value == null ? 'null' : value.toString()) + ' is not in: \"").append(this.collection.toString()).append("\"');").dedent();
	    transpiler.dedent().append("}").newLine();
	    transpiler.flush();
	    return true;
	}
	
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy