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

prompto.literal.DictLiteral Maven / Gradle / Ivy

The newest version!
package prompto.literal;

import prompto.compiler.CompilerUtils;
import prompto.compiler.Flags;
import prompto.compiler.MethodConstant;
import prompto.compiler.MethodInfo;
import prompto.compiler.Opcode;
import prompto.compiler.ResultInfo;
import prompto.error.PromptoError;
import prompto.intrinsic.PromptoDict;
import prompto.runtime.Context;
import prompto.transpiler.Transpiler;
import prompto.type.DictType;
import prompto.type.IType;
import prompto.type.MissingType;
import prompto.type.TypeMap;
import prompto.utils.CodeWriter;
import prompto.value.DictionaryValue;
import prompto.value.IValue;
import prompto.value.TextValue;


public class DictLiteral extends Literal {

	// we can only compute keys by evaluating key expressions
	// so we can't just inherit from Map. 
	// so we keep the full entry list.
	boolean mutable;
	DictEntryList entries;
	IType itemType = null;
	
	public DictLiteral(boolean mutable) {
		super("<:>",new DictionaryValue(MissingType.instance(), mutable));
		this.entries = new DictEntryList();
		this.mutable = mutable;
	}
	
	public DictLiteral(DictEntryList entries, boolean mutable) {
		super(()->entries.toString(), new DictionaryValue(MissingType.instance(), mutable));
		this.entries = entries;
		this.mutable = mutable;
	}

	public boolean isMutable() {
		return mutable;
	}
	
	@Override
	public void toDialect(CodeWriter writer) {
		if(mutable)
			writer.append("mutable ");
		this.entries.toDialect(writer);
	}
	
	@Override
	public IType check(Context context) {
		if(itemType==null)
			itemType = inferElementType(context);
		return new DictType(itemType); 
	}
	
	private IType inferElementType(Context context) {
		if(entries.isEmpty())
			return MissingType.instance();
		TypeMap types = new TypeMap();
		entries.forEach(e -> types.add(e.getValue().check(context)));
		return types.inferType(context, this);
	}	
	
	@Override
	public IValue interpret(Context context) throws PromptoError {
		if(entries.size()>0) {
			check(context); // to compute itemType
			PromptoDict dict = new PromptoDict(true);
			for(DictEntry e : entries) {
				TextValue key = e.getKey().interpret(context);
				IValue val = e.getValue().interpret(context); 
				dict.put(key, val);
			}
			dict.setMutable(mutable);
			return new DictionaryValue(itemType, dict);
		} else
			return value;
	}
	
	@Override
	public ResultInfo compile(Context context, MethodInfo method, Flags flags) {
		ResultInfo info = CompilerUtils.compileNewRawInstance(method, PromptoDict.class);
		method.addInstruction(Opcode.DUP);
		method.addInstruction(Opcode.ICONST_1);
		CompilerUtils.compileCallConstructor(method, PromptoDict.class, boolean.class);
		addEntries(context, method, flags.withPrimitive(false));
		if(!mutable) {
			method.addInstruction(Opcode.DUP);
			method.addInstruction(Opcode.ICONST_0);
			MethodConstant m = new MethodConstant(PromptoDict.class, "setMutable", boolean.class, void.class);
			method.addInstruction(Opcode.INVOKEVIRTUAL, m);
		}
		return info;
	}

	private void addEntries(Context context, MethodInfo method, Flags flags) {
		for(DictEntry e : entries) {
			method.addInstruction(Opcode.DUP); // need to keep a reference to the map on top of stack
			ResultInfo info = e.getKey().compile(context, method, flags);
			if(info.getType()!=String.class) {
				MethodConstant m = new MethodConstant(info.getType(), "toString", 
						String.class);
				method.addInstruction(Opcode.INVOKEVIRTUAL, m);
			}
			e.getValue().compile(context, method, flags);
			MethodConstant m = new MethodConstant(PromptoDict.class, "put", 
					Object.class, Object.class, Object.class);
			method.addInstruction(Opcode.INVOKEVIRTUAL, m);
			method.addInstruction(Opcode.POP); // consume the returned value (null since this is a new Map)
		}
	}

	@Override
	public void declare(Transpiler transpiler) {
	    transpiler.require("Dictionary");
	    this.entries.declare(transpiler);
	}
	
	@Override
	public boolean transpile(Transpiler transpiler) {
		boolean simple = transpiler.getEngine().supportsComputedPropertyNames();
		if(!simple)
			simple = entries.stream().allMatch(e->e.getKey() instanceof DictTextKey);
		if(simple) {
		   transpiler.append("new Dictionary(").append(this.mutable).append(", ");
			entries.transpile(transpiler);
		    transpiler.append(")");
		} else {
			transpiler.append("(function() {")
				.append("var $entries = {};");
			entries.forEach(entry->{
				transpiler.append("$entries[");
				entry.getKey().transpile(transpiler);
				transpiler.append("] = ");
				entry.getValue().transpile(transpiler);
				transpiler.append(";");
			});
			transpiler.append("return new Dictionary(").append(this.mutable).append(", $entries);}())");
		}
	    return false;
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy