jweinst1
5/17/2016 - 1:24 AM

jsonlang.js

//bool comparison functions

var BoolFuncs = {
	"==":function(a, b){
		return a.value === b.value;
	},
	"!=":function(a, b){
		return a.value !== b.value;
	},
	"<":function(a, b){
		return a.value < b.value;
	},
	">":function(a, b){
		return a.value > b.value;
	},
	"<=":function(a, b){
		return a.value <= b.value;
	},
	">=":function(a, b){
		return a.value >= b.value;
	},
	"&&":function(a, b){
		return a.value && b.value;
	},
	"||":function(a, b){
		return a.value || b.value;
	}
};

//processes, or mini functions that facilitate operations
//dest is always the destination of where the resulting value is stored.
var procfuncs = {
	//math funcs
	"+":function(a, b, dest){
		dest.value = a.value + b.value;
	},
	"-":function(a, b, dest){
		dest.value = a.value - b.value;
	},
	"*":function(a, b, dest){
		dest.value = a.value * b.value;
	},
	"/":function(a, b, dest){
		dest.value = a.value / b.value;
	},
	"//":function(a, b, dest){
		dest.value = Math.floor(a.value / b.value);
	},
	"%":function(a, b, dest){
		dest.value = a.value % b.value;
	},
	"**":function(a, b, dest){
		dest.value = Math.pow(a.value, b.value);
	},
	//concat oper, for strings or arrays
	"+~":function(a, b, dest){
		dest.value = a.concat(b);
	},
	//pushes or appends onto arrays
	"push":function(a, b, dest){
		a.value.push(b.value);
	},
	//pop operator only uses one operand, but needs both to be called
	"pop":function(a, b, dest){
		dest.value = a.value.pop();
	},
	//indexing operator
	"get":function(a, b, dest){
		dest.value = a.value[b.value];
	},
	//setitem oper for objects or arrays
	"set":function(a, b, dest){
		dest.value[a.value] = b.value;
	},
	//takes the length of a string or array
	"len":function(a, b, dest){
		dest.value = a.value.length;
	}
};

//class to implement variable collection and storage
var Vardict = (function(){
	//private object to hold values in the dictionary
	function Valobj(value){
		this.value = value;
	}
	function Vardict(){
		
	}
	Vardict.prototype.init = function(key, value){
		this[key] = new Valobj(value);
	};
	Vardict.prototype.del = function(key){
		delete this[key];
	};
	Vardict.prototype.check = function(key){
		return key in this;
	};
	//declares variable without assigning value
	Vardict.prototype.declare = function(key){
		this[key] = null;
	};
	//gets the entire value with it's object reference
	//if key does not exist in object, creates a key that is null valued
	Vardict.prototype.get = function(key){
		if(this.check(key)){
			return this[key];
		}
		else{
			this.init(key, null);
			return this[key];
		}
	};
	//gets only the value associated with the reference
	Vardict.prototype.getValue = function(key){
		if(this.check(key)){
			return this[key].value;
		}
		else{
			return false;
		}
	};
	//modifies the value of a preexisting object
	Vardict.prototype.set = function(key, value){
		if(this.check(key)){
			this[key].value = value;
		}
		else {
			return false;
		}
	};
	return Vardict;
})();


//main class for virtual machine
var VirtualMachine = (function(){
	//private object to hold values in the dictionary
	function Valobj(value){
		this.value = value;
	}
	function VirtualMachine(){
		this.variables = new Vardict();
		this.endstate = false;
		this.comps = BoolFuncs;
		this.procs = procfuncs;
		this.beginstate = true;
	}
	//loads variables from a variable object, as a preprocessor arrangement
	VirtualMachine.prototype.loadVars = function(obj){
		for(var key in obj){
			this.variables.init(key, obj[key]);
		}
	};
	//method that turns values into value object for easy referencing.
	VirtualMachine.prototype.setupVars = function(obj){
			for(var key in obj){
				//loads an object from memory if its already a variable
				if(typeof obj[key] === 'string' && obj[key][0] === "@"){
					obj[key] = this.variables.get(obj[key]);
				}
				//strings that don't start with @ will not be loaded
				else if(key !== "op") {
					obj[key] = new Valobj(obj[key]);
				}
			}
	};
	//evaluates one process
	VirtualMachine.prototype.assembleProc = function(obj){
		if("a" in obj && "b" in obj && "dest" in obj && "op"in obj){
			this.procs[obj.op](obj.a, obj.b, obj.dest);
		}
		else{
			throw "Process Error, invalid keys";
		}
	};
	//evaluates if a condition object is true
	VirtualMachine.prototype.assembleCond = function(obj){
		if("a" in obj && "b" in obj && "op"in obj){
			if(!(obj.op in this.comps)) throw "OPER ERROR";
			return this.comps[obj.op](obj.a, obj.b);
		}
	};
	//determines if an object is a block
	VirtualMachine.prototype.isBlock = function(obj){
		return "type" in obj && obj.type === "block" && "stmts" in obj;
	};
	//parses and assembles a block statement
	VirtualMachine.prototype.parseBlock = function(obj){
		if("vars" in obj){
			this.loadVars(obj.vars);
		}
		for(var i=0;i<obj.stmts.length;i++){
			this.setupVars(obj.stmts[i]);
			this.assembleProc(obj.stmts[i]);
		}
	};
	VirtualMachine.prototype.Assemble = function(obj){
		//continues down the JSON tree as long as end state is false.
		//reference for back jumping
		var pointer = obj;
		while(this.endstate === false){
			if(this.beginstate){
				this.loadVars(pointer.vars);
				pointer = obj.program;
				//turns off beginstate after preprocessing.
				this.beginstate = false;
			}
			else{
				if (this.isBlock(pointer)){
					this.parseBlock(pointer);
					if("next" in pointer) {
						pointer = pointer.next;
					}
					else {
						throw "Ending Error, no END command before termination"
					}
				}
			}
		}
	}
	return VirtualMachine;
})();