view jsbackend.rhope @ 135:18a4403fe576

Javascript backend can now produce broken output. Needs fixes plus port of standard lib
author Mike Pavone <pavone@retrodev.com>
date Sun, 14 Nov 2010 03:09:49 -0500
parents e1911b2fd5cc
children fc3815b7462f
line wrap: on
line source

Import backendutils_c.rhope

Blueprint JS Method Registry
{
	Lookup
	Next ID
}

JS Method Registry[:out]
{
	builtins <- [[[[[[[[[[[[[Dictionary[]
		]Set["+", "METHOD_ADD"]
		]Set["-", "METHOD_SUB"]
		]Set["/", "METHOD_DIV"]
		]Set["*", "METHOD_MUL"]
		]Set["LShift", "METHOD_LSHIFT"]
		]Set["RShift", "METHOD_RSHIFT"]
		]Set["=", "METHOD_EQUALS"]
		]Set[">", "METHOD_GREATER"]
		]Set["<", "METHOD_LESS"]
		]Set["If", "METHOD_IF"]
		]Set["Set Missing Field", "METHOD_SETFIELDMISSING"]
		]Set["Get Missing Field", "METHOD_GETFIELDMISSING"]
		]Set["Missing Method", "METHOD_MISSING"]
	out <- [[Build[JS Method Registry()]]Lookup <<[builtins]]Next ID<<[0]

}

Register Method@JS Method Registry[reg,method:out]
{
	[[reg]Lookup >>]Index[method]
	{
		out <- reg
	}{
		method ID <- [reg]Next ID>>
		new lookup <- [[reg]Lookup >>]Set[method, ["METHOD_FIRST_USER+"]Append[String[method ID]]]
		out <- [[reg]Lookup <<[new lookup]]Next ID <<[[method ID]+[1]]
	}
}

Method ID@JS Method Registry[reg,method:out,notfound]
{
	out,notfound <- [[reg]Lookup >>]Index[method]
}

Blueprint JS Field Registry
{
	Lookup
	Next ID
}

JS Field Registry[:out]
{
	out <- [[Build[JS Field Registry()]]Lookup <<[Dictionary[]]]Next ID<<[1]

}

Register Field@JS Field Registry[reg,field:out]
{
	[[reg]Lookup >>]Index[field]
	{
		out <- reg
	}{
		field ID <- [reg]Next ID>>
		new lookup <- [[reg]Lookup >>]Set[field, field ID]
		out <- [[reg]Lookup <<[new lookup]]Next ID <<[[field ID]+[1]]
	}
}

Field ID@JS Field Registry[reg,field:out,notfound]
{
	out,notfound <- [[reg]Lookup >>]Index[field]
}

Blueprint JS Type
{
	Name
	Fields
	Methods
	Init
	Copy
	Cleanup
	
}

JS Type[name:out]
{
	out <- [[[[[[Build[JS Type()]]Name <<[name]]Fields <<[()]]Methods <<[()]]Init <<["NULL"]]Copy <<["NULL"]]Cleanup <<["NULL"]
}

Add Field@JS Type[ctype,name,type:out]
{
	out <- [ctype]Fields <<[ [[ctype]Fields >>]Append[ [[()]Append[name]]Append[type] ] ]
}

Add Method@JS Type[ctype,name:out]
{
	out <- [ctype]Methods <<[ [[ctype]Methods >>]Append[name] ]
}

Register Methods@JS Type[ctype,method reg:out]
{
	out <- Fold[Register Method[?], method reg, [ctype]Methods >>]
}

_Register Field JS[reg,field:out]
{
	name <- [field]Index[0]
	out <- [reg]Register Field[name]
}

Register Fields@JS Type[ctype,field reg:out]
{
	out <- Fold[_Register Field JS[?], field reg, [ctype]Fields >>]
}


Type Init@JS Type[jstype,id,method reg,field reg,p:out]
{
	ename <- Escape Rhope Name[[jstype]Name >>,p]
	
	[("Array", "Worker")]Find[=[[jstype]Name >>, ?]]
	{
		constructor <- [[[["var t_"]Append[ename]]Append[" = "]]Append[ [("Array","Function")]Index[~] ]]Append[";\n"]
	}{
		constructor <- [["function t_"]Append[ename]]Append["\n{}\n"]
	}
	out <- [[[[[constructor
		]Append[ [[[["t_"]Append[ename]]Append[".prototype.type_id = "]]Append[id]]Append[";\n"] ]
		]Append[ [["t_"]Append[ename]]Append[".prototype.conversions = new Array();\n"] ]
		]Append[ [["t = new t_Blueprint;\nt.id = "]Append[id]]Append[";\n"] ]
		]Append[ [["t.construct = t_"]Append[ename]]Append[";\n"] ]
		]Append[ [["registered_types["]Append[id]]Append["] = t;\n\n"] ]
}

Blueprint JS Type Registry
{
	Lookup
	Definitions
	Next ID
	Escape Pattern
}

JS Type Registry[p:out]
{
	out <- [[[[Build[JS Type Registry()]]Lookup << [
			[[[[[[[[[[[[[[[[[[Dictionary[]
			]Set["UInt8", "TYPE_UINT8"]			//1
			]Set["UInt16", "TYPE_UINT16"]		//2
			]Set["UInt32", "TYPE_UINT32"]		//3
			]Set["UInt64", "TYPE_UINT64"]		//4
			]Set["Int8", "TYPE_INT8"]			//5
			]Set["Int16", "TYPE_INT16"]			//6
			]Set["Int32", "TYPE_INT32"]			//7
			]Set["Int64", "TYPE_INT64"]			//8
			]Set["Boolean", "TYPE_BOOLEAN"]		//9
			]Set["Float32", "TYPE_FLOAT32"]		//10
			]Set["Float64", "TYPE_FLOAT64"]		//11
			]Set["Blueprint", "TYPE_BLUEPRINT"]	//12
			]Set["Array", "TYPE_ARRAY"]			//13
			]Set["Boxed Array", "TYPE_BOXEDARRAY"]//14
			]Set["Worker", "TYPE_WORKER"]		//15
			]Set["Method Missing Exception", "TYPE_METHODMISSINGEXCEPTION"]	//16
			]Set["Field Missing Exception", "TYPE_FIELDMISSINGEXCEPTION"]	//17
			]Set["Wrong Type Exception", "TYPE_WRONGTYPEEXCEPTION"]]		//18
		]Definitions << [Dictionary[]]
		]Next ID <<[0]
		]Escape Pattern <<[p]
}

_Type Inits JS[reg,method reg,field reg,text,def,name:out]
{
	out <- [[text]Append[ [def]Type Init[[reg]Type ID[name], method reg, field reg,[reg]Escape Pattern >>] ]]Append["\n\n"]
}

Type Inits@JS Type Registry[reg,method reg,field reg:out]
{
	out <- Fold[_Type Inits JS[reg, method reg, field reg, ?], "", [reg]Definitions >>]
}

Register Type@JS Type Registry[reg,def:out]
{
	name <- [def]Name >>
	[[reg]Lookup >>]Index[name]
	{
		[[reg]Definitions >>]Index[name]
		{
			out <- reg
		}{
			out <- [reg]Definitions <<[[[reg]Definitions >>]Set[name, def]]
		}
	}{
		out <- [[[reg]Lookup <<[ [[reg]Lookup >>]Set[name, ["TYPE_FIRST_USER+"]Append[String[[reg]Next ID >>]]] ]
			]Definitions <<[ [[reg]Definitions >>]Set[name, def] ]
			]Next ID <<[ [[reg]Next ID >>]+[1] ]
	}
}

Type ID@JS Type Registry[reg,name:out,notfound]
{
	out <- [[reg]Lookup >>]Index[name] {}
	{
		,notfound <- If[[name]=["Any Type"]]
		{ out <- "0" }
	}
}

Simple Type?@JS Type Registry[reg,name:yep,nope,notfound]
{
	,notfound <- [[reg]Definitions >>]Index[name]
	{
		yep,nope <- If[[[[~]Fields >>]Length] = [1]]
	}
}

Defined?@JS Type Registry[reg,name:yep,nope]
{
	yep,nope <- [[reg]Definitions >>]Index[name]
}

Blueprint JS Function
{
	Name
	Inputs
	Outputs
	Convention
	Variables
	Statements
	Method Registry
	Field Registry
	Type Registry
	Constants
	Input Types
	Output Types
	Resume Index
	Last NumParams
	Escape Pattern
}

JS Function[name,inputs,outputs,convention,p:out]
{
	out <- JS Function With Registry[name,inputs,outputs,convention, JS Method Registry[], JS Field Registry[], JS Type Registry[p],p]
}

JS Function With Registry[name,inputs,outputs,convention,registry,field reg,type reg,p:out]
{
	out <- [[[[[[[[[[[[[[[Build[JS Function()]
		]Name <<[name]
		]Inputs <<[inputs]
		]Outputs <<[outputs]
		]Convention <<[convention]
		]Variables <<[Dictionary[]]
		]Statements <<[()]
		]Method Registry <<[registry]
		]Field Registry <<[field reg]
		]Type Registry <<[type reg]
		]Constants <<[Dictionary[]]
		]Input Types <<[ Fold[Append[?, "Any Type"], (), inputs] ]
		]Output Types <<[ Fold[Append[?, "Any Type"], (), outputs] ]
		]Resume Index <<[1]
		]Last NumParams <<[-1]
		]Escape Pattern <<[p]
}

Set Input Type@JS Function[func,type,input num:out]
{
	out <- [func]Input Types <<[ [[func]Input Types >>]Set[input num, type] ]
}

Set Output Type@JS Function[func,type,output num:out]
{
	out <- [func]Output Types <<[ [[func]Output Types >>]Set[output num, type] ]
}

Register Constant@JS Function[func,name,constant:out]
{
	out <- [func]Constants <<[ [[func]Constants >>]Set[name, constant] ]
}

Allocate Var@JS Function[func,name,type:out]
{
	out <- [func]Variables <<[ [[func]Variables >>]Set[name,type] ]
}

Add Statement@JS Function[func,statement:out]
{
	out <- [func]Statements <<[ [[func]Statements >>]Append[["\t"]Append[[statement]Append[";\n"]]] ]
}

Add Raw Line@JS Function[func,line:out]
{
	out <- [func]Statements <<[ [[func]Statements >>]Append[["\t"]Append[[line]Append["\n"]]] ]
}

Add Operator Statement@JS Function[func,psource1,psource2,pdest,op:out]
{
	source1 <- [psource1]Make Op[func]
	source2 <- [psource2]Make Op[func]
	dest <- [pdest]Make Op[func]
	out <- [func]Add Statement[[[[[dest]Append[" = "]]Append[source1]]Append[op]]Append[source2]]
}

Add@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," + "]
}

Sub@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," - "]
}

Multiply@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," * "]
}

Get Constant Type@JS Function[func,const:out]
{
	//TODO: Support more types as needed, particularly Float64 when support for that type is added in general
	val <- [[func]Constants >>]Index[const] {}
	{ typename <- "Any Type" }
	[(Int32(),UInt8(),UInt32())]Find[=[val,?]]
	{ typename <- [("Int32","UInt8","UInt32")]Index[~] }
	{ typename <- "Any Type" }
	out <- Type Instance[typename]
}

Name Match[field,target name:out]
{
	out <- [[field]Index[0]]=[target name]
}

Get Field Type@JS Function[func,otype,field:out]
{
	def <- [[[func]Type Registry >>]Definitions >>]Index[[otype]Name >>]
	{
		[[~]Fields >>]Find[Name Match[?,field]]
		{ out <- [[[def]Fields >>]Index[~]]Index[1] }
		{ out <- Type Instance["Any Type"] }
	}{
		out <- Type Instance["Any Type"]
	}
}

Get Var Type@JS Function[func,varname:out]
{
	[[func]Inputs >>]Find[=[varname,?]]
	{
		out <- [[func]Input Types >>]Index[~]
	}{
		[[func]Outputs >>]Find[=[varname,?]]
		{
			out <- [[func]Output Types >>]Index[~]
		}{
			out <- [[func]Variables >>]Index[varname] {}
			{ out <- Type Instance["Any Type"] }
		}
	}
}

Divide@JS Function[func,source1,source2,dest:out]
{
	sourcetype <- [source1]Get Type[func]
	If[[[sourcetype]Name >>]=["Float64"]]
	{
		out <- [func]Add Operator Statement[source1,source2,dest," / "]
	}{
		out <- [func]Add Statement[ [[[[[Make Op[dest, func]]Append[" = Math.floor(("]]Append[ Make Op[source1,func] ]]Append[") / ("]]Append[Make Op[source2, func]]]Append["))"]  ]
	}
}

DoLShift@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," << "]
}

DoRShift@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," >> "]
}

BitAnd@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," & "]
}

BitOr@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," | "]
}

CompLess@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," < "]
}

CompGreater@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," > "]
}

CompEqual@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," == "]
}

CompLessEqual@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," <= "]
}

CompGreaterEqual@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," >= "]
}

CompNotEqual@JS Function[func,source1,source2,dest:out]
{
	out <- [func]Add Operator Statement[source1,source2,dest," != "]
}

Move@JS Function[func,psource,pdest:out]
{
	source <- [psource]Make Op[func]
	dest <- [pdest]Make Op[func]
	out <- [func]Add Statement[[[dest]Append[" = "]]Append[source]]
}

Do AddRef@JS Function[func,psource,pdest:out]
{
	out <- [func]Move[psource,pdest]
}

AddRef No Dest@JS Function[func,psource:out]
{
	out <- func
}

Release@JS Function[func,psource:out]
{
	out <- func
}

Set Null@JS Function[func,pdest:out]
{
	dest <- [pdest]Make Op[func]
	out <- [func]Add Statement[[dest]Append[" = NULL"]]
}

Lookup Constant@JS Function[func,const,doaddref:out]
{
	out <- ["_const_"]Append[Escape Rhope Name[const,[func]Escape Pattern >>]]
}

Field Result@JS Function[func,var,field:out]
{
	as op <- [var]Make Op[func]
	out <- [[as op]Append[".p_"]]Append[Escape Rhope Name[field,[func]Escape Pattern >>]]
}

Read Field@JS Function[func,var,field:out,result op]
{
	out <- func
	result op <- Field Ref[var,field]
}

Write Field@JS Function[func,var,field:out,result op]
{
	out <- func
	result op <- Field Ref[var,field]
}

Set Field Null@JS Function[func,var,field:out]
{
	out <- [func]Add Statement[ [[func]Field Result[var,field]]Append[" = NULL"] ]
}

Copy@JS Function[func,pdest:out]
{
	dest <- [pdest]Make Op[func]
	out <- [func]Add Statement[ [dest]Append[[[" = copy_object("]Append[dest]]Append[")"]] ]
}

Box@JS Function[func,psource,pdest,type:out]
{
	out <- func
}

Unbox@JS Function[func,psource,pdest:out]
{
	out <- func
}

Get Raw Pointer@JS Function[func,psource,pdest:out]
{
	out <- func
}

Array Raw Pointer@JS Function[func,psource,pdest:out]
{
	dest <- [pdest]Make Op[func]
	source <- [psource]Make Op[func]
	out <- [func]Add Statement[ [[[dest]Append[" = ((char *)"]]Append[source]]Append[")+ sizeof(t_Array)"] ]
}

_Function Arg JS[func,val,inputnum:out]
{
	out <- [func]Add Raw Line[
		[[[["SetParam("
		]Append[String[inputnum]]
		]Append[", "]
		]Append[val]
		]Append[")"]
	]
}

_Val Function Arg JS[func,val,inputnum,worker:out]
{
	out <- [func]Add Raw Line[
		[[[[[["VCSetParam("
		]Append[worker]
		]Append[", "]
		]Append[String[inputnum]]
		]Append[", "]
		]Append[val]
		]Append[")"]
	]
}

Method Call@JS Function[func,method,args:out]
{
	If[[method]=["Call"]]
	{
		out <- [[[[[func]Add Raw Line[[["if ("]Append[Make Op[[args]Index[0], func]]]Append[".type_id == TYPE_WORKER) {"]]
			]Val Call[[args]Index[0], Tail[args,1]]
			]Add Raw Line["} else {"]
			]Func Base["Call",args, "MCall"]
			]Add Raw Line["}"]
	}{
		out <- [func]Func Base[Escape Rhope Name[method,[func]Escape Pattern >>],args, "MCall"]
	}
	
}

Val Call@JS Function[func,to call,args:out]
{
	worker <- Make Op[to call, func]
	rargs <- Map[args, Make Op[?, func]]

	out <- [[[[[func]Add Raw Line[[[[["if ("]Append[worker]]Append[".Args.length > 0 || "]]Append[worker]]Append[".IsMethod) { "]]
		]Add Statement[[[[["	res = valcall("]Append[worker]]Append["["]]Append[ [rargs]Join[","] ]]Append["])"]]
		]Add Raw Line["} else {"]
		]Add Statement[[[[["	res = "]Append[worker]]Append["("]]Append[ [rargs]Join[","] ]]Append[")"]]
		]Add Raw Line["}"]
}

Call@JS Function[func,name,args:out]
{
	If[[name]=["Call@Worker"]]
	{
		//TODO: Handle case when user explicitly calls the fully qualified version, but the type of the first arg isn't Worker
		out <- [func]Val Call[[args]Index[0], Tail[args,1]]
	}{
		out <- [func]Func Base[Escape Rhope Name[name,[func]Escape Pattern >>],args, "Call"]
	}
}

Func Base@JS Function[func,tocall,args,type:out]
{
	
	Print[ [[func]Name >>]Append[ [": Func Base("]Append[tocall] ] ]
	rargs <- Map[args, Make Op[?, func]]
	
	If[[type]=["MCall"]]
	{
		out <- [func]Add Statement[[[[[[["res = "]Append[[rargs]Index[0]]]Append[".f_"]]Append[tocall]]Append["("]]Append[ [Tail[rargs, 1]]Join[","] ]]Append[")"]]
	}{
		out <- [func]Add Statement[[[[["res = f_"]Append[tocall]]Append["("]]Append[ [rargs]Join[","] ]]Append[")"]]
	}
}

Call Foreign@JS Function[func,name,language,args,store result:out]
{
	rargs <- Map[args, Make Op[?, func]]
	//Assume language = "JS" for now
	If[[name]Ends With["@"]]
	{
		base <- [[[[[[rargs]Index[0]]Append["."]]Append[ [name]Slice[ [[name]Length]-[1] ] ]]Append["("]]Append[ [Tail[rargs,1]]Join[","] ]]Append[")"]
	}{
		base <- [[[name]Append["("]]Append[ Join[rargs, ", "] ]]Append[")"]
	}
	,do store <- [(String(), String Slice(), String Cat())]Find[=[Blueprint Of[store result], ?]]
	{ 
		,do store <- If[[store result]=[""]]
		{ stmt <- Val[base] }
	}
	
	Val[do store]
	{ stmt <- [[Make Op[store result, func]]Append[" = "]]Append[base] }
	out <- [func]Add Statement[stmt]
}

Get Field Call@JS Function[func,field,source:out]
{
	//This will need to change later when I add support for "Field Missing"
	[func]Escape Pattern >>
	{
		esource <- Escape Rhope Name[Make Op[source,func], ~]
		efield <- Escape Rhope Name[field, ~]
	}
	out <- [func]Add Statement[[[["res = "]Append[esource]]Append[".p_"]]Append[efield]]
}

Set Field Call@JS Function[func,field,object,value:out]
{
	out <- [func]Func Base[Escape Rhope Name[[field]Append[" <<"],[func]Escape Pattern >>], [[()]Append[object]]Append[value], "Call"]
}

Tail Method Call@JS Function[func,method,args:out]
{
	//Javascript doesn't support tail calls, at least not directly anyway
	out <- [func]Method Call[method,args]
}

Tail Call@JS Function[func,name,args:out]
{
	If[[name]=[[func]Name >>]]
	{
		//TODO: Support simple tail recursion
		out <- func
	}{
		out <- [func]Call[name,args]
	}
}

Resolve@JS Function[func,op:out]
{
	If[[[func]Convention >>] = ["rhope"]]
	{
		out <- ["lv_"]Append[Escape Rhope Name[op, [func]Escape Pattern >>]]
	}{
		out <- Escape Rhope Name[op,[func]Escape Pattern >>]
	}
}

Resolve Output@JS Function[func,name:out]
{
	If[[[func]Convention >>] = ["rhope"]]
	{
		out <- ["lv_"]Append[Escape Rhope Name[name, [func]Escape Pattern >>]]
	}{
		out <- Escape Rhope Name[name,[func]Escape Pattern >>]
	}
}

Instruction Stream@JS Function[func:out]
{
	out <- [func]Statements <<[()]
}

_If JS[func, statement:out]
{
	out <- [func]Statements <<[ [[func]Statements >>]Append[ ["\t"]Append[statement] ] ]
}

Do If@JS Function[func,condition,stream:out]
{
	cond <- [condition]Make Op[func]
	out <- [Fold[_If JS[?], [[func
		]Add Raw Line[ [["if("]Append[cond]]Append[")"] ]
		]Add Raw Line["{"], [stream]Statements >>]
		]Add Raw Line["}"]
}

Discard Outputs@JS Function[func,first to discard:out]
{
	out <- func
}

Result Reference@JS Function[func,output:out]
{
	out <- [["res["]Append[String[output]]]Append["]"]
}

Checked Result Reference@JS Function[func,output:out]
{
	out <- [func]Result Reference[output]
}


If Null Else@JS Function[func,left,right:out]
{
	check <- [Make Condition[left]]Make Op[func]
	l <- [left]Make Op[func]
	r <- [right]Make Op[func]
	out <- [[[[[["("
		]Append[check]
		]Append[" != null ? "]
		]Append[l]
		]Append[" : "]
		]Append[r]
		]Append[")"]
}

Set Outputs@JS Function[func:out]
{
	If[[[func]Convention >>] = ["rhope"]]
	{
		out <- [["\treturn ["]Append[ [Map[[func]Outputs >>, Escape Rhope Name[?, [func]Escape Pattern >>]]]Join[","] ]]Append["];\n"]
	}{
		[[func]Outputs >>]Index[0]
		{
			out <- [["\treturn "]Append[Escape Rhope Name[~,[func]Escape Pattern >>]]]Append[";\n"]
		}{
			out <- ""
		}
	}
}

Check Param Type JS[text,type,input num,func:out]
{
	[(String(),String Cat(),String Slice())]Find[=[Blueprint Of[type],?]]
	{
		typename <- type
	}{
		typename <- [type]Name >>
	}
	If[[typename] = ["Any Type"]]
	{
		out <- text
	}{
		input <- ["lv_"]Append[Escape Rhope Name[[[func]Inputs >>]Index[input num], [func]Escape Pattern >>]]
		out <- [text]Append[ [[[["\t"]Append[input]]Append["= check_type("]]Append[input]]Append[ [[", "]Append[ [[func]Type Registry >>]Type ID[typename] ]]Append[");"] ] ]
	}
}

_Add Prefix[val:out]
{
		out <- ["lv_"]Append[val]
}

Text@JS Function[func:out]
{	
	Print[["Text@JS Function: "]Append[[func]Name >>]]
	If[ [[func]Convention >>] = ["rhope"] ]
	{
		
		before <- [[func]Name >>]Partition["@"] {} {}
		{
			ivars <- Tail[[func]Inputs >>, 1]
			cname <- [["t_"]Append[Escape Rhope Name[~,[func]Escape Pattern >>]]
				]Append[[".f_"]Append[Escape Rhope Name[before,[func]Escape Pattern >>]]]
			[[func]Inputs >>]Index[0]
			{ move this <- ["\tlv_"]Append[[Escape Rhope Name[~, [func]Escape Pattern >>]]Append[" = this;"]] }
			{ move this <- "" }
		}{
			ivars <- [func]Inputs >>
			fname <- Escape Rhope Name[[func]Name >>,[func]Escape Pattern >>]
			move this <- ""
		}
		inproc <- Val[Map[?, _Add Prefix[?]]]
	}{
		fname <- Escape Rhope Name[[func]Name >>,[func]Escape Pattern >>]
		ivars <- Inputs >>[func]
		move this <- ""
		inproc <- Val[Val[?]]
	}
	cname <- ["var "]Append[fname]
	param check <- Fold[Check Param Type JS[?, ?, ?, func], "", [func]Input Types >>]

	out <- [[[[[[[[[cname
		]Append[" = function("]
		]Append[ [[inproc]Call[Map[ivars, Escape Rhope Name[?, [func]Escape Pattern >>]]]]Join[","] ]
		]Append[")\n{\n"]
		]Append[move this]
		]Append[param check]
		]Append[ [["\tvar "]Append[ [ [inproc]Call[Concatenate[[func]Outputs >>, Keys[[func]Variables >>]]] ]Join[","] ]]Append[";\n"] ]
		]Append[ [[func]Statements >>]Join[""] ]
		]Append[[func]Set Outputs]
		]Append["}"]
}

Blueprint JS Program
{
	Functions
	Method Registry
	Field Registry
	Type Registry
	Libraries
	Escape Pattern
}

JS Program[:out]
{
	p <- Pattern[("_",  "@",  " ",  ":",  "?",  "+",  "-",  "*",  "/",  "<",  ">",  "(",  ")",  "!",  "=",  "'",  
			"\"", "\t", ",",  ".",  "\n", "{",  "}",   "[",   "]",   "#",   "\\",  "\r",  ";",   "&",   "|",   "%",   "^",   "`",   "~")]
	out <- [[[[[[Build[JS Program()]]Functions <<[Dictionary[]]]Method Registry <<[JS Method Registry[]]]Type Registry <<[JS Type Registry[p]]]Field Registry <<[JS Field Registry[]]]Libraries <<[Dictionary[]]]Escape Pattern <<[p]
}

Supported Number Types@JS Program[program:out]
{
	out <- ("Int32","UInt8","UInt32")
}

Needed Specials@JS Program[program,typename,makespecial:out]
{
	out <- ()
}

Link@JS Program[program,language,library:out]
{
	If[[library] = ["runtime"]]
	{
		out <- program
	}{
		langlibs <- [[program]Libraries >>]Index[language] {}
		{ langlibs <- Dictionary[] }
		out <- [program]Libraries <<[ [[program]Libraries >>]Set[language, [langlibs]Set[library, Yes]] ]
	}
}

Register Type@JS Program[program,def:out]
{
	out <- [[[program]Type Registry <<[ [[program]Type Registry >>]Register Type[def] ]
		]Method Registry <<[ [def]Register Methods[[program]Method Registry >>] ]
		]Field Registry <<[ [def]Register Fields[[program]Field Registry >>] ]
}

Create Type@JS Program[program,name:out]
{
	out <- JS Type[name]
}

Create Function@JS Program[program,name,inputs,outputs,convention:out]
{
	out <- JS Function With Registry[name,inputs,outputs,convention, [program]Method Registry >>, [program]Field Registry >>, [program]Type Registry >>, [program]Escape Pattern >>]
}

Store Function@JS Program[program,func:out]
{
	out <- [program]Functions <<[ [[program]Functions >>]Set[ [func]Name >>, func] ]
}

Method?@JS Program[program,funcname:is,isnot]
{
	is,isnot <- [[program]Method Registry >>]Method ID[funcname]
}

_Text JS Program[text,func,type reg:out]
{
	out <- [text]Append[[[ [func]Type Registry <<[type reg] ]Text]Append["\n\n"]]
}

Combine Consts[consts,func:out]
{
	out <- Combine[[func]Constants >>, consts]
}

_List Literal El[text,val,index,type reg:out]
{
	out <- [[[[text
		]Append[", "]
		]Append[index]
		]Append[", "]
		]Append[Const Construct JS[val, type reg]]
}

Const Construct JS[value,type reg:out]
{
	valtype <- Blueprint Of[value]
	[(Int8(),UInt8(),Int16(),UInt16(),Int32(),UInt32(),Int64(),UInt64())]Find[=[valtype,?]]
	{
		size <- [("8","16","32","64")]Index[[~]/[2]]
		If[[~]Mod[2]]
		{ s <- "UI" }
		{ s <- "I" }
		
		out <- [[[[[["make_"
			]Append[s]
			]Append["nt"]
			]Append[size]
			]Append["("]
			]Append[String[value]]
			]Append[")"]
	}{
		If[[valtype] = [Type Instance()]]
		{
			//TODO: Support parametric types
			typeid <- [type reg]Type ID[[value]Name >>]

			out <- [["make_Blueprint("]Append[typeid]]Append[")"]
		}{
			If[[valtype] = [Boolean()]]
			{
				If[value]
				{
					out <- "make_Bool(true)"
				}{
					out <- "make_Bool(false)"
				}
			}{

				[(String(),String Slice(),String Cat())]Find[=[valtype,?]]
				{
					out <- [["make_String(\""]Append[ [[[[value]Replace["\\", "\\\\"]]Replace["\n", "\\n"]]Replace["\"", "\\\""]]Replace["\r", "\\r"] ]]Append["\")"]
				}{
					If[[valtype]=[Worker Literal()]]
					{
						//TODO: Figure out how to fully support these in nested cases
						//or workaround the problem higher up in the food chain
						[[value]Args >>]Last
						{ size <- String[[~]+[1]] }
						{ size <- "0" }
						out <- [[[[[["make_Worker(f_"
								]Append[Escape Rhope Name[[value]Name >>,[type reg]Escape Pattern >>]]
								]Append[", "]
								]Append[size]
								]Append[", "]
								]Append[String[Fold[+[1,?], 0, [value]Args >>]]]
								]Append[")"]
					}{
						[(List(), List Leaf())]Find[=[?,valtype]]
						{
							out <- [Fold[_List Literal El[?, ?, ?, type reg], ["make_List("]Append[String[[value]Length]], value]]Append[")"]
						}{
							out <- "UnhandledLiteralType"
						}
					}
				}
			}
		}
			
	}
}

_Set Worker Params JS[text,param,num,type reg,name:out]
{
	out <- [text]Append[
		[[[[[["\t((object **)(((t_Worker *)_const_"
			]Append[name]
			]Append[")+1))["]
			]Append[String[num]]
			]Append["] = "]
			]Append[Const Construct JS[param, type reg]]
			]Append[";\n"] ]
}

_Set Consts JS Program[text,value,name,type reg:out]
{
	valtype <- Blueprint Of[value]
	[(String(),String Cat(),String Slice(),Worker Literal(),List(),List Leaf())]Find[=[valtype,?]]
	{
		out <- text
	}{
		Const Construct JS[value,type reg]
		{ out <- [text]Append[ [[[["var _const_"]Append[Escape Rhope Name[name,[type reg]Escape Pattern >>]]]Append[" = "]]Append[~]]Append[";\n"] ] }
	}
}

_Set List Els[text,el,index,type reg:out]
{
	out <- [[text]Append[
		[["\tinout[1] = "
		]Append[Const Construct JS[index,type reg]]
		]Append[
			[[";\n\tinout[2] = "
			]Append[Const Construct JS[el, type reg]]
			]Append[";\n"]
		]]]Append["\trhope(FUNC_Set, inout, 3, 3);\n"]
}

_Set Late Consts JS[text,value,name,type reg:out]
{
	valtype <- Blueprint Of[value]
	[(String(),String Cat(),String Slice(),Worker Literal(),List(),List Leaf())]Find[=[valtype,?]]
	{
		If[[~]>[3]]
		{
			out <- [Fold[_Set List Els[?, ?, ?, type reg], [text]Append["\trhope(FUNC_List, inout, 0, 1);\n"], value]
				]Append[[["var _const_"]Append[Escape Rhope Name[name,[type reg]Escape Pattern >>]]]Append[" = inout[0];\n"]]
		}{
			Const Construct JS[value,type reg]
			{ init <- [text]Append[ [[[["var _const_"]Append[Escape Rhope Name[name,[type reg]Escape Pattern >>]]]Append[" = "]]Append[~]]Append[";\n"] ] }
		
			If[[valtype]=[Worker Literal()]]
			{
				out <- Fold[_Set Worker Params JS[?, ?, ?, type reg, Escape Rhope Name[name,[type reg]Escape Pattern >>]], init, [value]Args >>]
			}{
				out <- Val[init]
			}
		}
	}{
		out <- text
	}
}

Text Filename@JS Program[program,source name:out]
{
	out <- [source name]Append[".js"]
}

Text@JS Program[program:out]
{
	p <- [program]Escape Pattern >>
	constants <- Fold[Combine Consts[?], Dictionary[], [program]Functions >>]

	out <- [[[[[["
var i = 0;
var TYPE_ANY = i++;
var TYPE_INT32 = i++;
var TYPE_UINT8 = i++;
var TYPE_UINT32 = i++;
var TYPE_BOOLEAN = i++;
var TYPE_FLOAT64 = i++;
var TYPE_BLUEPRINT = i++;
var TYPE_ARRAY = i++;
var TYPE_WORKER = i++;
var TYPE_FIRST_USER = i;

registered_types = new Array();

function t_Blueprint()
{
}

t_Blueprint.prototype.type_id = TYPE_BLUEPRINT;
t_Blueprint.prototype.conversions = new Array();
var t = new t_Blueprint;
t.id = TYPE_BLUEPRINT;
t.construct = t_Blueprint;
registered_types[TYPE_BLUEPRINT] = t;\n\n"
		]Append[ [[program]Type Registry >>]Type Inits[[program]Method Registry >>, [program]Field Registry >>] ]
		]Append["

function make_Int32(val)
{
	var out = new t_Int32;
	out.p_Val = val;
	return out;
}

function make_UInt8(val)
{
	var out = new t_UInt8;
	out.p_Val = val & 255;
	return out;
}

function make_UInt32(val)
{
	var out = new t_UInt32;
	out.p_Val = val;
	return out;
}

function make_Boolean(val)
{
	var out = new t_Boolean;
	out.p_Val = val;
	return out;
}

function make_Float64(val)
{
	var out = new t_Float64;
	out.p_Val = val;
	return out;
}

function make_Blueprint(typeid)
{
	return registered_types[typeid];
}

function check_type(val,typeid)
{
	if (val.type_id = typeid) {
		return val;
	}
	if (val.conversions[type_id] != undefined) {
		var out = val.conversions[type_id](val);
		return out[0];
	}
	throw new Error(\"Conversion needed\");
}

function f_Build(type)
{
	type = check_type(type, TYPE_BLUEPRINT);
	return [new type.construct()];
}

function f_BlueprintSP_Of(val)
{
	return [registered_types[val.type_id]];
}

function f_ID(type)
{
	type = check_type(type, TYPE_BLUEPRINT);
	return [type.id];
}

function f_BlueprintSP_FromSP_ID(id)
{
	id = check_type(id, TYPE_UINT32);
	if (id.p_Val > 0 && registered_types[id.p_Val] != null) {
		return [registered_types[id.p_Val], null];
	} else {
		return [null,id];
	}
}\n"]
		]Append[Fold[_Text JS Program[?, ?, [program]Type Registry >>], "", [program]Functions >>]]
		]Append[Fold[_Set Consts JS Program[?, ?, ?, [program]Type Registry >>], "", constants]]
		]Append[Fold[_Set Late Consts JS[?, ?, ?, [program]Type Registry >>], "", constants]]
		]Append["
var args = f_List()[0];
for (var i in arguments) {
	args = args.f_Append(make_String(arguments[i]))[0];
}
f_Main(args);"]

}