view nworker_c.rhope @ 170:ac5c2d78663f

Inline calls to If@Boolean when static type info is present
author Mike Pavone <pavone@retrodev.com>
date Sun, 08 May 2011 18:21:19 -0700
parents fd06fb07762a
children a32afde77abb
line wrap: on
line source

Import number_c.rhope
Import boolean.rhope

Blueprint Condition Set
{
	Variables
	Subsets
	Condition Type
}

AndSet[:out]
{
	out <- [[[Build[Condition Set()]]Variables <<[Dictionary[]]]Subsets <<[()]]Condition Type <<["And"]
}

OrSet[:out]
{
	out <- [[[Build[Condition Set()]]Variables <<[Dictionary[]]]Subsets <<[()]]Condition Type <<["Or"]
}

To String@Condition Set[set:out]
{
	out <- [[[[[set]Condition Type >>
	]Append["Set:\n\tVariables:\n\t\t"]
	]Append[ Join[Keys[[set]Variables >>], "\n\t\t"] ]
	]Append["\n\tSubsets:\n\t\t"]
	]Append[ Join[Keys[[set]Subsets >>], "\n\t\t"] ]
}

Add Condition@Condition Set[set,cond:out]
{
	If[[Blueprint Of[cond]] = [Condition Set()]]
	{
		If[[[set]Condition Type >>]=[[cond]Condition Type >>]]
		{
			out <- [[set]Variables <<[ Combine[[set]Variables >>, [cond]Variables >>] ]
				]Subsets <<[ Concatenate[[set]Subsets >>, [cond]Subsets >>] ]
		}{
			[cond]Empty?
			{
				[cond]Simple?
				{ out <- [set]Variables <<[ Combine[[set]Variables >>, [cond]Variables >>] ] }
				{ out <- [set]Subsets <<[ [[set]Subsets>>]Append[cond] ] }
			}{
				out <- set
			}
		}
	}{
		out <- [set]Variables <<[ [[set]Variables >>]Set[cond, Yes] ]
	}
}

=@Condition Set[set1,set2:out]
{
	,out <- If[[[set1]Condition Type >>] = [[set2]Condition Type >>]]
	{
		,out <- If[[[set1]Variables >>] = [[set2]Variables >>]]
		{
			out,out <- If[[[set1]Subsets >>] = [[set2]Subsets >>]]
		}
	}
}

_For Backend Var[current,junk,variable,type:out]
{
	If[[type]=["And"]]
	{ cond <- Val[AndCond[?]] }
	{ cond <- Val[OrCond[?]] }
	out <- [cond]Call[current, variable]
}

_For Backend Subset[current,subset,type:out]
{
	[subset]For Backend
	{
		If[[type]=["And"]]
		{ cond <- Val[AndCond[?]] }
		{ cond <- Val[OrCond[?]] }
		out <- out <- [cond]Call[current, ~]
	}{
		out <- current
	}
}

Empty?@Condition Set[set:not empty,empty]
{
	[[set]Variables >>]First
	{
		not empty <- Yes
	}{
		,empty <- [[set]Subsets >>]First
		{
			not empty <- Yes
		}
	}
}

Simple?@Condition Set[set:simple,not simple]
{
	,not simple <- If[[Length[[set]Variables >>]]=[1]]
	{
		simple,not simple <- If[[Blueprint Of[[set]Subsets >>]]=[Empty Dictionary()]]
	}
}

For Backend@Condition Set[set:out,none]
{
	firstvar <- [[set]Variables >>]First
	{
		[[set]Variables >>]Next[~]
		{
			vars <- _Fold[[set]Variables >>, ~, firstvar, _For Backend Var[?, ?, ?, [set]Condition Type >>]]
		}{
			vars <- Val[firstvar]
		}
		out <- Fold[_For Backend Subset[?, ?, [set]Condition Type >>], vars, [set]Subsets >>]
	}{
		[[set]Subsets >>]First
		{
			firstsub <- [[[set]Subsets >>]Index[~]]For Backend
			[[set]Subsets >>]Next[~]
			{
				out <- _Fold[[set]Subsets >>, ~, firstsub, _For Backend Subset[?, ?, [set]Condition Type >>]]
			}{
				out <- Val[firstsub]
			}
		}{
			none <- Yes
		}
	}
}

List of Lists[num:out]
{
	out <- Fold[Append[?, ()],(), Range[0,num]]
}

Blueprint Worker Ref
{
	Name
	Convention
	Inputs
	Min Inputs
	Outputs
	Min Outputs
	Is Method?
}

Worker Ref[name,convention,inputs,outputs,ismethod?:out]
{
	out <- [[[[[[[Build[Worker Ref()]]Name <<[name]]Convention <<[convention]]Inputs <<[inputs]]Outputs <<[outputs]]Is Method? <<[ismethod?]]Min Inputs <<[inputs]]Min Outputs <<[outputs]
}

String@Worker Ref[ref:out]
{
	out <- [[[[[[[["Worker Ref["
		]Append[[ref]Name >>]
		]Append[", "]
		]Append[[ref]Convention >>]
		]Append[", "]
		]Append[String[[ref]Inputs >>]]
		]Append[", "]
		]Append[String[[ref]Outputs >>]]
		]Append["]"]
}

Blueprint Node Ref
{
	Index
	IO Num
}

Node Ref[index,ionum:out]
{
	out <- [[Build[Node Ref()]]Index <<[index]]IO Num <<[ionum]
}

=@Node Ref[left,right:out]
{
	,out <- If[[[left]Index >>] = [[right]Index >>]]
	{
		out <- [[left]IO Num>>] = [[right]IO Num >>]
	}
}

Blueprint NWorker Node
{
	Type
	Data
	Inputs
	Min Inputs
	Input Types
	Outputs
	Min Outputs
	Output Types
	Wires From
	Wires To
	Conditions
}

Wire To@NWorker Node[node,from,output,pre input:out]
{
	existing cons <- [[node]Wires To >>]Index[input] {}
	{ existing cons <- () }
	input <- [pre input]+[1]
	out <- [node]Wires To <<[
		[[node]Wires To >>]Set[input,
			[existing cons]Append[Node Ref[from,output]]
		]
	]
}

Wire From@NWorker Node[node,to,input,output:out]
{
	existing cons <- [[node]Wires From >>]Index[output] {}
	{ existing cons <- () }
	out <- [node]Wires From <<[
		[[node]Wires From >>]Set[output,
			[existing cons]Append[Node Ref[to,input]]
		]
	]
}

_Has Input Types@NWorker Node[node,input num:does,does not]
{
	does <- If[[input num] >= [[node]Inputs >>]] {}
	{
		,does not <- [[node]Input Types >>]Index[input num]
		{
			Print[[[[[["Input: "]Append[String[input num]]]Append[", count: "]]Append[String[count]]]Append[", wires: "]]Append[String[[[[node]Wires To >>]Index[ [input num]+[1] ]]Length]]]
			count <- [~]Index[1]
			,does not <- If[[count] = [[[[node]Wires To >>]Index[[input num]+[1]]]Length]]
			{
				does,does not <- [node]_Has Input Types[[input num]+[1]]
			}
		}
	}
}

Has Input Types?@NWorker Node[node:does,does not]
{
	If[[[node]Inputs >>] > [0]]
	{
		does,does not <- _Has Input Types[node,0]
		{ Print["does have input types"] }
		{ Print["does not have input types"] }
	}{
		does <- Yes
	}
}

_Dependency[dlist,ref:out]
{
	[dlist]Find[=[ref, ?]]
	{
		out <- dlist
	}{
		out <- [dlist]Append[ref]
	}
}

Dependencies@NWorker Node[node:out]
{
	out <- Fold[Fold[_Dependency[?], ?], (), [node]Wires To >>]
}


NWorker Node[type,data,inputs,outputs:out]
{
	out <- [[[[[[[[[[[Build[NWorker Node()]
		]Type <<[type]
		]Data <<[data]
		]Inputs <<[inputs]
		]Min Inputs <<[inputs]
		]Outputs <<[outputs]
		]Min Outputs <<[outputs]
		]Wires From <<[List of Lists[outputs]]
		]Wires To <<[List of Lists[[inputs]+[1]]]
		]Conditions <<[AndSet[]]
		]Input Types <<[()]
		]Output Types <<[()]
}

Blueprint NWorker
{
	Convention
	Nodes
	Inputs
	Input Types
	Outputs
	Output Types
	Uses
	NodeResults
	Free Temps
	Name
	Builtin?
	Library
}

NWorker[convention:out]
{
	out <- [[[[[[[[[[Build[NWorker()]]Convention <<[convention]]Nodes <<[()]]Inputs <<[()]]Outputs <<[()]]Input Types <<[()]]Output Types <<[()]]Name <<["Anonymous"]]Builtin? <<[No]]Library << [""]]Uses <<[()]
}

String@NWorker[worker:out]
{
	out <- ["NWorker"]Append[[worker]Name >>]
}

Add Node@NWorker[worker,type,data,inputs,outputs:out,node index]
{
	out <- [worker]Nodes <<[[[worker]Nodes >>]Append[NWorker Node[type,data,inputs,outputs]]]
	node index <- [[worker]Nodes >>]Length
}

Add Full Node@NWorker[worker,type,data,inputs,min inputs,outputs,min outputs:out,node index]
{
	out <- [worker]Nodes <<[[[worker]Nodes >>]Append[ 
		[[[NWorker Node[type,data,inputs,outputs]
		]Min Inputs <<[min inputs]
		]Min Outputs <<[min outputs]
		]Wires To <<[List of Lists[[min inputs]+[1]]]
	]]
	node index <- [[worker]Nodes >>]Length
}

Propagate Type[nodelist,dest,prog,worker,type:out]
{
	If[[[dest]IO Num >>] >= [0]]
	{
		Print[[[["Propagate Type, Index: "]Append[String[[dest]Index >>]]]Append[" io num: "]]Append[String[[dest]IO Num >>]]]
		node <- [nodelist]Index[[dest]Index >>]
	
		[[node]Input Types >>]Index[[dest]IO Num >>]
		{	
			Print[["Existing type: "]Append[[existing type]Name >>]]
			existing type <- [~]Index[0]
			new count <- [[~]Index[1]]+[1]
			If[[[existing type]Name >>] = [[type]Name >>]]
			{
				If[[[existing type]Variant >>] = [[type]Variant >>]]
				{
					If[[[existing type]Params >>] = [[type]Params >>]]
					{
						new type <- Val[existing type]
					}{
						new variant <- [existing type]Variant >>
						new params <- ()
					}
				}{
					new variant <- "Boxed"
					If[[[existing type]Params >>] = [[type]Params >>]]
					{
						new params <- [existing type]Params >>
					}{
						new params <- ()
					}
				}
				new type <- [[existing type]Set Variant[new variant]]Params <<[new params]
			}{
				new type <- Type Instance["Any Type"]
			}
		}{
			Print["No existing type info for this input"]
			new type <- Val[type]
			new count <- 1
		}
		Print[[[["new type: "]Append[[new type]Name >>]]Append[", new count: "]]Append[String[new count]]]
		new node <- [node]Input Types <<[  		
			[ [node]Input Types >> ]Set[ [dest]IO Num >>, [[()]Append[new type]]Append[new count] ]
		]
		{ Print["got new node"] }
		out <- Infer Types Node[[nodelist]Set[[dest]Index >>, new node], new node, [dest]Index >>, prog, worker]
	}{
		out <- nodelist
	}
}

Propagate Types[nodelist,dests,output num,prog,worker,source node:out]
{
	[[source node]Output Types >>]Index[output num]
	{
		out <- Fold[Propagate Type[?, ?, prog, worker, ~], nodelist, dests]
	}{
		Print[["Output type is missing for output #"]Append[String[output num]]]
		out <- nodelist
	}
}

Infer Types Node[nodelist,node,index,prog,worker:out]
{
	If[[[node]Type >>]=["call"]]
	{
		extra <- [", worker: "]Append[[[node]Data >>]Name >>]
	}{
		extra <- ""
	}
	Print[[[[["Infer Types Node: "]Append[String[index]]]Append[", type: "]]Append[[node]Type >>]]Append[extra]]
	If[[[node]Type >>] = ["const"]]
	{
		const type <- Blueprint Of[[node]Data >>]
		[(Int8(),UInt8(),Int16(),UInt16(),Int32(),UInt32(),Int64(),UInt64(),	
			Type Instance(),Worker Literal(),List(),List Leaf(),String(),String Slice(),String Cat())]Find[=[const type, ?]]
		{
			outtype <- [("Int8","UInt8","Int16","UInt16","Int32","UInt32","Int64","UInt64",
			"Blueprint","Worker","List","List Leaf","String","String","String")]Index[~]
		}{
			outtype <- "Any Type"
		}
		nextnode <- [node]Output Types <<[ [()]Append[Type Instance[outtype]] ]
		
	}{
		If[[[node]Type >>] = ["setglobal"]]
		{
			out <- nodelist
		}{
			If[[[node]Type >>] = ["input"]]
			{
				nextnode <- [node]Output Types <<[ [()]Append[ [[worker]Input Types >>]Index[[node]Data >>] ] ]
			}{
				If[[[node]Type >>] = ["output"]]
				{
					out <- nodelist

				}{
					If[[[node]Type >>] = ["getglobal"]]
					{
						nextnode <- [node]Output Types <<[ [()]Append[Type Instance["Any Type"]] ]
					}{
						[node]Has Input Types?
						{
							If[[[node]Type >>] = ["setfield"]]
							{
								nextnode <- [node]Output Types <<[ [()]Append[ [[[node]Input Types >>]Index[0]]Index[0] ] ]
							}{
								If[[[node]Type >>] = ["getfield"]]
								{
									type <- [[[node]Input Types >>]Index[0]]Index[0]
									If[[[type]Name >>] = ["Any Type"]]
									{
										outtype <- Val[type]
									}{
										outtype <- [prog]Find Field[[node]Data >>, type] {}
										{
											//TODO: Return errors rather than printing them
											Print[
												[[[[["Type "
												]Append[[type]Name >>]
												]Append[" does not have a field named "]
												]Append[[node]Data >>]
												]Append[" in worker "]
												]Append[worker name]]
										}
									}
									nextnode <- [node]Output Types <<[ [()]Append[outtype] ]
								}{
									worker name <- [[node]Data >>]Name >>
									[prog]Is Method?[worker name]
									{
										Print[[["Infer Types: "]Append[worker name]]Append[" is a method"]]
										first arg type <- [[[node]Input Types >>]Index[0]]Index[0]
										If[[[first arg type]Name >>] = ["Any Type"]]
										{
											Print["No type info for first arg"]
											outtypes <- Fold[Append[?, Type Instance["Any Type"]], (), Range[0, [node]Inputs >>]]
											Print[["outtypes length: "]Append[String[Length[outtypes]]]]
											nextnode <- [node]Output Types <<[ outtypes ]
										}{
											worker def <- [prog]Find Method[worker name, first arg type]
											{
												new worker name <- [[worker name]Append["@"]]Append[[first arg type]Name >>]
												new ref <- [prog]Find Worker[new worker name] {} {
													Print[["Could not find worker ref for "]Append[new worker name]]
												}
												nextnode <- [[node]Output Types <<[outtypes]
													]Data <<[new ref]
												Print[["New worker name:"]Append[new worker name]]
											}{
												//TODO: Return errors instead of printing them
												Print[
													[[[[["Type "
													]Append[[first arg type]Name >>]
													]Append[" does not support method "]
													]Append[worker name]
													]Append[" in worker "]
													]Append[ [worker]Name >> ]]
											}
										}
									}{
										Print[[["Infer Types: "]Append[worker name]]Append[" is not a method"]]
										worker def <- [prog]Find Worker Def[worker name] {}
										{ Print["Error, could not find worker def"] }
										nextnode <- [node]Output Types <<[ outtypes ]
									}
									outtypes <- [worker def]Output Types >>
								}
							}
						}{
							Print["Skipping node because input type info not present"]
							out <- nodelist
						}
					}
				}
			}
		}
	}
	
	Val[nextnode]
	{
		nextlist <- [nodelist]Set[index, nextnode]
		{ Print["Calling Propagate types on descdendants of this node"] }
		out <- Fold[Propagate Types[?, ?, ?, prog, worker, nextnode], nextlist, [nextnode]Wires From >>]
	}
}

Infer Types@NWorker[worker,prog:out]
{
	Print[["Infer Types: "]Append[[worker]Name >>]]
	out <- [worker]Nodes <<[Fold[Infer Types Node[?, ?, ?, prog, worker], [worker]Nodes >>, [worker]Nodes >>]]
}

Add Worker Call@NWorker[worker,tocall:out,node index]
{
	out, node index <- [worker]Add Full Node["call",tocall,[tocall]Inputs >>, [tocall]Min Inputs >>,[tocall]Outputs >>, [tocall]Min Outputs >>]
}

Add Constant@NWorker[worker,constant:out,node index]
{
	out, node index <- [worker]Add Node["const",constant,0,1]
}

Add Input@NWorker[worker,name,number:out,node index]
{
	out,node index <- [worker]Add Typed Input[name,number,Type Instance["Any Type"]]
}

Add Anon Input@NWorker[worker,number:out]
{
	If[[number]>[Length[[worker]Inputs >>]]]
	{
		prepped <- [worker]Add Anon Input[[number]-[1]]
	}{
		prepped <- Val[worker]
	}
	out <- out <- [[prepped]Inputs <<[[[prepped]Inputs >>]Set[number,[" unnamed"]Append[String[number]]]]
		]Input Types <<[[[prepped]Input Types >>]Set[number,Type Instance["Any Type"]]]
}

Add Typed Input@NWorker[worker,name,number,type:out,node index]
{
	If[[number]>[Length[[worker]Inputs >>]]]
	{
		prepped <- [worker]Add Anon Input[[number]-[1]]
	}{
		prepped <- Val[worker]
	}
	,node index <- [prepped]Add Node["input",number,0,1]
	{ 
		out <- [[~]Inputs <<[[[~]Inputs >>]Set[number,name]]
		]Input Types <<[[[~]Input Types >>]Set[number,type]]
	}
}

Add Output@NWorker[worker,name,number:out,node index]
{
	out,node index <- [worker]Add Typed Output[name,number,Type Instance["Any Type"]]
}

Add Typed Output@NWorker[worker,name,number,type:out,node index]
{
	,node index <- [worker]Add Node["output",number,1,0]
	{ 
		out <- [[~]Outputs <<[[[~]Outputs >>]Set[number,name]]
		]Output Types <<[[[~]Output Types >>]Set[number,type]]
	}
}

Add Object Get@NWorker[worker,fieldname:out,node index]
{
	out, node index <- [worker]Add Node["getfield",fieldname,1,1]
}

Add Object Set@NWorker[worker,fieldname:out,node index]
{
	out, node index <- [worker]Add Node["setfield",fieldname,2,1]
}

Add Global Get@NWorker[worker,store,var:out,node index]
{
	out, node index <- [worker]Add Node["getglobal",[[()]Append[store]]Append[var],0,1]
}

Add Global Set@NWorker[worker,store,var:out,node index]
{
	out, node index <- [worker]Add Node["setglobal",[[()]Append[store]]Append[var],1,1]
}

Add Wire@NWorker[worker,from,output,to,input:out]
{
	fromw <- [[[worker]Nodes >>]Index[from]]Wire From[to,input,output]
	tow <- [[[worker]Nodes >>]Index[to]]Wire To[from,output,input]
	nodes <- [[[worker]Nodes >>]Set[from, fromw]]Set[to, tow]
	out <- [worker]Nodes <<[nodes]
}

Uses@NWorker[worker,uses:out]
{
	out <- [worker]Uses <<[uses]
}

_No Dependencies[list,node,index:out]
{
	[[node]Wires To>>]Index[1]
	{
		out <- Val[list]
	}{
		[[[node]Wires To>>]Index[0]]First
		{
			out <- Val[list]
		}{
			out <- [list]Append[index]
		}
	}
}

No Dependencies@NWorker[worker:out]
{
	out <- Fold[_No Dependencies[?], (), [worker]Nodes >>]
}

_Collect Dests[candidates,wire:out]
{
	out <- [candidates]Set[[wire]Index >>, Yes]
}

Collect Dests@NWorker[worker,candidates,node index:out]
{
	out <- Fold[Fold[_Collect Dests[?], ?], candidates, [[[worker]Nodes >>]Index[node index]]Wires From >>]
}

Check Dependency@NWorker[worker,nodes,wires,wire index:met?]
{
	ref <- [wires]Index[wire index]
	[nodes]Find[=[[ref]Index >>, ?]]
	{
		[wires]Next[wire index]
		{
			met? <- [worker]Check Dependency[nodes,wires,~]
		}{
			met? <- Yes
		}
	}{
		met? <- No
	}
}
_Check Dependencies@NWorker[worker,nodes,inputs,input index:met?]
{
	wires <- [inputs]Index[input index]
	[wires]First
	{
		current met? <- [worker]Check Dependency[nodes, wires, ~]
	}{
		current met? <- Yes
	}
	If[current met?]
	{
		[inputs]Next[input index]
		{
			met? <- [worker]_Check Dependencies[nodes,inputs,~]
		}{
			met? <- Yes
		}
	}{
		met? <- No
	}
}

Check Dependencies@NWorker[worker,nodes,candidate:met?]
{
	inputs <- [[[worker]Nodes >>]Index[candidate]]Wires To >>
	[inputs]First
	{
		met? <- [worker]_Check Dependencies[nodes, inputs, ~]
	}{
		met? <- Yes
	}
}

Dependants@NWorker[worker,direct nodes,nodes:out]
{
	candidates <- Keys[Fold[Collect Dests[worker, ?], (), direct nodes]]
	out <- Filter[candidates, Check Dependencies[worker, nodes, ?]]
}

_Dependency Groups@NWorker[worker,last,all,grouped:out]
{
	current <- [worker]Dependants[last,all]
	[current]First
	{
		out <- [worker]_Dependency Groups[current, [all]Concatenate[current], [grouped]Append[current]]
	}{
		out <- grouped
	}
}
Dependency Groups@NWorker[worker:out]
{
	no deps <- [worker]No Dependencies
	out <- [worker]_Dependency Groups[no deps, no deps, [()]Append[no deps]]
}

Const Name[val,node index,worker name:out]
{
	valtype <- Blueprint Of[val]
	If[[valtype] = [Type Instance()]]
	{
		//TODO: Support parametric types
		datstring <- [val]Name >>
		typename <- "Blueprint"
	}{
		[(Int8(),UInt8(),Int16(),UInt16(),Int32(),UInt32(),Int64(),UInt64())]Find[=[valtype,?]]
		{
			size <- [("8","16","32","64")]Index[[~]/[2]]
			typename <- [("Int8","UInt8","Int16","UInt16","Int32","UInt32","Int64","UInt64")]Index[~]
			If[[~]Mod[2]]
			{ s <- "UI" }
			{ s <- "I" }
			datstring <- [[String[val]]Append[s]]Append[size]
		}{
			If[[valtype] = [Worker Literal()]]
			{
				typename <- "Worker"
				If[[[[val]Args >>]Length] > [0]]
				{
					datstring <- [[["Arg "]Append[String[node index]]]Append[" "]]Append[worker name]
				}{
					datstring <- [val]Name >>
				}
			}{
				[(List(),List Leaf())]Find[=[valtype,?]]
				{
					typename <- "List"
					If[[[val]Length] > [0]]
					{
						datstring <- [[["Arg "]Append[String[node index]]]Append[" "]]Append[worker name]
					}{
						datstring <- "Empty"
					}
				}{
					[(String(),String Cat(),String Slice())]Find[=[valtype, ?]]
					{
						typename <- "String"
						datstring <- val
					}{
						typename <- "Unknown"
						datstring <- String[val]
					}
					
				}
			}
		}
	}
	out <- [[typename]Append["_"]]Append[datstring]
}

Format Input@NWorker[worker,noderef:out]
{
	node <- [[worker]Nodes >>]Index[[noderef]Index >>]
	
	[("call","getfield","setfield")]Find[=[[node]Type >>, ?]]
	{
		maybe addref <- Result Var Name[[noderef]IO Num >>, [noderef]Index >>]
	}{
		conditions <- [node]Conditions >>
		
		If[[[node]Type >>] = ["input"]]
		{
			input name <- [[worker]Inputs >>]Index[ [node]Data >> ]
			[conditions]Empty?
			{
				out <- AddRef[Result Var Name[[noderef]IO Num >>, [noderef]Index >>]]
			}{
				out <- AddRef[input name] 
			}
		}{
			If[[[node]Type >>] = ["const"]]
			{
				[conditions]Empty?
				{
					out <- AddRef[Result Var Name[[noderef]IO Num >>, [noderef]Index >>]]
				}{
					out <- Constant[Const Name[[node]Data >>, [noderef]Index >>, [worker]Name >>]]
				}
			}{
				If[[[node]Type >>]=["getglobal"]]
				{
					[conditions]Empty?
					{
						out <- AddRef[Result Var Name[[noderef]IO Num >>, [noderef]Index >>]]
					}{
						out <- AddRef[Global Get[[[node]Data >>]Index[0], [[node]Data >>]Index[1]]]
					}
				}
			}
		}
	}

	Val[maybe addref]
	{
		If[[Length[[[node]Wires From >>]Index[[noderef]IO Num >>]]] > [1]]
		{
			out <- AddRef[maybe addref]
		}{
			out <- Val[maybe addref]
		}
	}
}

Collect Input@NWorker[worker,nodeinput:out]
{
	inputchoices <- Map[nodeinput, Format Input[worker, ?]]

	[inputchoices]First
	{
		first <- [inputchoices]Index[~]
		[inputchoices]Next[~]
		{
			out <- _Fold[inputchoices, ~, first, OrValue[?]]
		}{
			out <- Val[first]
		}
	}{
		out <- "Missing"
	}
}

Collect Inputs@NWorker[worker,node:out]
{
	out <- Map[Tail[[node]Wires To>>, 1], Collect Input[worker, ?]]
}

Collect Input Condition@NWorker[worker,set,noderef:out]
{
	node <- [[worker]Nodes >>]Index[ [noderef]Index >> ]
	If[[[node]Outputs >>] > [1]]
	{
		out <- [set]Add Condition[ Result Var Name[[noderef]IO Num >>, [noderef]Index >>] ]
	}{
		out <- [set]Add Condition[[node]Conditions >>]
	}
}

Collect Condition@NWorker[worker,set,nodeinput:out]
{
	out <- [set]Add Condition[Fold[Collect Input Condition[worker, ?], OrSet[], nodeinput]]
}

Collect Conditions@NWorker[worker,node:out]
{
	out <- Fold[Collect Condition[worker, ?], AndSet[], [node]Wires To>>]
}

Save Result[func,num,node index:out]
{
	out <- [func]Move[Result[num], Result Var Name[num, node index]]	
}

Save Maybe Result[func,num,node index:out]
{
	out <- [func]Move[Check Result[num], Result Var Name[num, node index]]
}

Max Used Output[node,cur:out]
{
	If[[cur] < [0]]
	{
		out <- cur
	}{
		[[[node]Wires From >>]Index[cur]]Index[0]
		{
			out <- cur
		}{
			out <- Max Used Output[node, [cur]-[1]]
		}
	}
}

Compile Call Node[node,program,func,inputs,node index:out]
{
	If[[[node]Type >>] = ["getfield"]]
	{
		with call <- [func]Get Field Call[[node]Data >>, [inputs]Index[0]]
		save outs <- [node]Outputs >>
		out <- Val[after save]
	}{
		If[[[node]Type >>] = ["setfield"]]
		{
			with call <- [func]Set Field Call[[node]Data >>, [inputs]Index[0], [inputs]Index[1]]
			save outs <- [node]Outputs >>
			out <- Val[after save]
		}{
			fname <- [[node]Data >>]Name >>
			[program]Method?[fname]
			{
				with call <- [func]Method Call[fname, inputs]
			}{
				justfunc,,,normal call <- [fname]Partition["@"]
				{
					//Check for inline on static method calls
					//TODO: Deal with unused output
					If[[[inputs]Length]=[2]]
					{
						out,normal call <- Compile Number Inline Check[func, justfunc, [[[node]Input Types >>]Index[0]]Index[0], [[[node]Input Types >>]Index[1]]Index[0], [inputs]Index[0], [inputs]Index[1], Result Var Name[0, node index]]
					}{
						,normal call <- If[[[inputs]Length]=[1]]
						{
							out,normal call <- Compile Boolean Inline Check[func, justfunc, [[[node]Input Types >>]Index[0]]Index[0], [inputs]Index[0], Result Var Name[0, node index], Result Var Name[1, node index]]
						}
					}
				}
				
				Val[normal call]
				{
					with call <- [func]Call[fname, inputs]
				}
			}
			first unused <- [Max Used Output[node, [[node]Outputs >>]-[1]]]+[1]
			If[[first unused] > [[node]Min Outputs >>]]
			{
				save outs <- [node]Min Outputs >>
				after maybe <- Fold[Save Maybe Result[?, ?, node index], after save, Range[save outs, first unused]]
			}{
				save outs <- Val[first unused]
				after maybe <- Val[after save]
			}
			If[[first unused] < [[node]Outputs >>]]
			{
				out <- [after maybe]Discard Outputs[first unused]
			}{
				out <- Val[after maybe]
			}
		}
	}
	after save <- Fold[Save Result[?, ?, node index], with call, Range[0, save outs]]
	Print[["Last NumParams is now "]Append[String[[after save]Last NumParams >>]]]
}

Compile Node[worker,program,func,nodes,current:out,out worker]
{
	node index <- [nodes]Index[current]
	node <- [[worker]Nodes >>]Index[node index]
	conditions <- [node]Conditions >>
	[("call","getfield","setfield")]Find[=[[node]Type >>, ?]]
	{
		inputs <- [worker]Collect Inputs[node]
		[conditions]For Backend
		{
			stream <- [func]Instruction Stream
			nfunc <- [func]Do If[~, nstream]
		}{
			stream <- Val[func]
			nfunc <- Val[nstream]
		}
		nstream <- Compile Call Node[node, program, stream, inputs, node index]
	}{
		If[[[node]Type >>] = ["output"]]
		{
			inputs <- [worker]Collect Inputs[node]
			[conditions]For Backend
			{
				stream <- [func]Instruction Stream
				nfunc <- [func]Do If[~, nstream]
			}{
				stream <- Val[func]
				nfunc <- Val[nstream]
			}
			nstream <- [stream]Move[[inputs]Index[0], [[worker]Outputs >>]Index[ [node]Data >> ] ]
		}{
			If[[[node]Type >>] = ["const"]]
			{
				constname <- Const Name[[node]Data >>, node index, [worker]Name >>]
				withconst <- [func]Register Constant[constname, [node]Data >>]
				[conditions]For Backend
				{
					stream <- [[withconst]Instruction Stream
						]Move[Strip Addref[Constant[constname]], Result Var Name[0, node index]]
					nfunc <- [withconst]Do If[~, stream]
				}{
					nfunc <- Val[withconst]
				}
			}{
				If[[[node]Type >>]=["getglobal"]]
				{
					[conditions]For Backend
					{
						stream <- [[func]Instruction Stream
							]Move[Global Get[[[node]Data >>]Index[0], [[node]Data >>]Index[1]], Result Var Name[0, node index]]
						nfunc <- [func]Do If[~, stream]
					}{
						nfunc <- Val[func]
					}
				}{
					If[[[node]Type >>]=["setglobal"]]
					{
						inputs <- [worker]Collect Inputs[node]
						[conditions]For Backend
						{
							stream <- [func]Instruction Stream
							nfunc <- [func]Do If[~, nstream]
						}{
							stream <- Val[func]
							nfunc <- Val[nstream]
						}
						nstream <- [stream]Set Global[[[node]Data >>]Index[0], [[node]Data >>]Index[1], [inputs]Index[0]]
					}{
						[conditions]For Backend
						{
							input name <- [[worker]Inputs >>]Index[ [node]Data >> ]
							stream <- [[func]Instruction Stream
								]Move[input name, Result Var Name[0, node index]]
							nfunc <- [func]Do If[~, stream]
						}{
							nfunc <- Val[func]
						}
					}
				}
			}
			
		}
	}
	[nodes]Next[current]
	{
		out,out worker <- [worker]Compile Node[program,nfunc,nodes,~]
	}{
		out <- Val[nfunc]
		out worker <- Val[worker]
	}
}

Save Node Conditions[worker,node index:out]
{
	node <- [[worker]Nodes >>]Index[node index]
	conditions <- [worker]Collect Conditions[node]
	out <- [worker]Nodes <<[ [[worker]Nodes >>]Set[node index, [node]Conditions <<[conditions]] ]
	
}

Save Group Conditions[worker, groups,current:out]
{
	nodes <- [groups]Index[current]
	nworker <- Fold[Save Node Conditions[?], worker, nodes]

	[groups]Next[current]
	{
		out <- [nworker]Save Group Conditions[groups,~]
	}{
		out <- Val[nworker]
	}
}

Compile Group[worker,program,func,groups,current:out,out worker]
{
	nodes <- [groups]Index[current]
	[nodes]First
	{
		nfunc,nworker <- [worker]Compile Node[program,func,nodes,~]
	}{
		nfunc <- Val[func]
		nworker <- Val[worker]
	}
	[groups]Next[current]
	{
		out,out worker <- [nworker]Compile Group[program,nfunc,groups,~]
	}{
		out <- Val[nfunc]
		out worker <- Val[nworker]
	}
}

Release Var@NWorker[worker,func,name:out]
{
	//__result_index_ionum
	parts <- [name]Split["_"]
	index <- Int32[ [parts]Index[3] ]
	io num <- Int32[ [parts]Index[4] ]
	node <- [[worker]Nodes >>]Index[index]
	dests <- [[node]Wires From >>]Index[io num] {}

	,normal <- If[[[dests]Length] = [1]]
	{
		[dests]Index[0]
		{
			dest index <- [~]Index >>
			dest IO <- [~]IO Num >>
		}
		normal <- If[[dest IO] = [-1]] {}
		{
			dest node <- [[worker]Nodes >>]Index[dest index]
			
			[[dest node]Conditions >>]For Backend
			{
				out <- [func]Do If[AndCond[NotCond[~], name],  [[func]Instruction Stream]Release[name]]
			}{
				out <- func
			}
		}
	}

	Val[normal]
	{
		do if <- If[[[node]Outputs >>] > [1]] {}
		{
			do if <- [[node]Conditions >>]Empty? {}
			{
				out <- [func]Release[name]
			}
		}
	
		Val[do if]
		{
			stream <- [[func]Instruction Stream]Release[name]
			out <- [func]Do If[name, stream]
		}
	}
}

Result Var Name[io num, index:out]
{
	out <- [[["__result_"]Append[String[index]]]Append["_"]]Append[String[io num]]
}

Result Var[vars,io num,index:out]
{
	out <- [vars]Append[Result Var Name[io num, index]]
}

Node Result Vars[vars,node,index:out]
{
	[("call","getfield","setfield","getglobal")]Find[=[[node]Type >>, ?]]
	{
		If[[[node]Type >>]=["call"]]
		{
			save outs <- [Max Used Output[node, [[node]Outputs >>]-[1]]]+[1]
		}{
			save outs <- [node]Outputs >>
		}
		out <- Fold[Result Var[?, ?, index], vars, Range[0, save outs]]
	}{
		out <- vars
	}
}

Result Vars@NWorker[worker:out]
{
	out <- Fold[Node Result Vars[?], (), [worker]Nodes >>]
}

_No Release[vars,node,index,worker:out]
{
	[("const","input")]Find[=[[node]Type >>, ?]]
	{
		[[node]Conditions >>]Empty?
		{
			out <- Result Var[vars, 0, index]
		}{	
			out <- vars
		}
	}{
		out <- vars
	}
}

No Release Results@NWorker[worker:out]
{
	out <- Fold[_No Release[?, ?, ?, worker], (), [worker]Nodes >>]
}

Make Basic Type[type:out]
{
	out <- [Type Instance[[type]Name >>]]Params <<[ [type]Params >> ]
}

FInputs[ifunc, input type, index, inputs:out]
{	
	func <- [ifunc]Set Input Type[Make Basic Type[input type], index]
	name <- [inputs]Index[index]
	If[[[input type]Variant >>] = ["Naked"]]
	{
		
		naked <- [" naked"]Append[name]
		
		out <- [[[func]Allocate Var[naked, input type]
		]Unbox[name, naked]
		]Release[name]
	}{
		If[[input type]Mutable? >>]
		{
			name <- [inputs]Index[index]
			copied <- [func]Copy[name, name]
			
		}{
			copied <- Val[func]
		}
		If[[[input type]Variant >>] = ["Raw Pointer"]]
		{
			raw <- [" raw"]Append[name]
			If[[[input type]Name >>]=["Array"]]
			{
				
				out <- [[copied]Allocate Var[raw, input type]
				]Array Raw Pointer[name, raw]
			}{
				out <- [[copied]Allocate Var[raw, input type]
				]Get Raw Pointer[name, raw]
			}
		}{
			out <- Val[copied]
		}
	}
}

Release Raw Inputs[func,input type,index,inputs,outputs:out]
{
	If[[[input type]Variant >>] = ["Raw Pointer"]]
	{
		name <- [inputs]Index[index]
		If[[input type]Mutable? >>]
		{
			[outputs]Find[=[?,[inputs]Index[index]]]
			{
				out <- func
			}{
				out <- [func]Release[name]	
			}
		}{
			out <- [func]Release[name]
		}
	}{
		out <- func
	}
}

FParams[input:out]
{
	iname <- [input]Index[0]
	type <- [input]Index[1]
	If[[[type]Variant >>] = ["Naked"]]
	{ out <- [" naked"]Append[iname] }
	{ 
		If[[[type]Variant >>] = ["Raw Pointer"]]
		{ out <- [" raw"]Append[iname] }
		{ out <- Val[iname] }
	}
}
_Return Param[outputs, inputs, input types, index:out,none]
{
	output <- [outputs]Index[index]
	[inputs]Find[=[output, ?]]
	{
		If[[[input types]Index[~]]Mutable? >>]	
		{
			,none <- [outputs]Next[index]
			{
				out,none <- _Return Param[outputs, inputs, input types, ~]
			}
		} { 
			out <- index
		}
	}{
		out <- index
	}
}

Return Param[outputs, inputs, input types:out,none]
{
	,none <- [outputs]First
	{ out,none <- _Return Param[outputs, inputs, input types, ~] }
	
}

Save Foreign Result[func, output, index, output types, inputs, input types:out]
{
	type <- [output types]Index[index]
	If[[[type]Variant >>] = ["Naked"]]
	{
		out <- [func]Box[[" naked"]Append[output], output, type]
	}{
		[inputs]Find[=[output, ?]]
		{
			If[[[input types]Index[~]]Mutable? >>]
			{ 
				out <- [func]Move[output, Output[output]]
			}{
				out <- func
			}
		}{	
			out <- func
		}
	}
}

Compile Foreign Stub[worker,program,name:out]
{
	ifunc <- [[program]Create Function[name, [worker]Inputs >>, [worker]Outputs >>, "rhope"]
	]Output Types <<[Map[[worker]Output Types >>, Make Basic Type[?]]]
	
	rp num <- Return Param[[worker]Outputs >>, [worker]Inputs >>, [worker]Input Types >>]
	{
		rbase <- [[worker]Outputs >>]Index[rp num]
		If[[[[[worker]Output Types >>]Index[rp num]]Variant >>] = ["Naked"]]
		{
			rparam <- [" naked"]Append[rbase]
			rfunc <- [ifunc]Allocate Var[rparam, [[worker]Output Types >>]Index[rp num]]
		}{
			rparam <- Val[rbase]
			rfunc <- Val[ifunc]
		}
	}{
		rparam <- ""
		rfunc <- Val[ifunc]
	}
	
	Fold[FInputs[?, ?, ?, [worker]Inputs >>], rfunc, [worker]Input Types >>]
	{ [~]Call Foreign[name, [worker]Convention >>, Map[Zip[[worker]Inputs >>, [worker]Input Types >>], FParams[?]], rparam]
	{ Fold[Release Raw Inputs[?, ?, ?, [worker]Inputs >>, [worker]Outputs >>], ~, [worker]Input Types >>]
	{ Fold[Save Foreign Result[?, ?, ?, [worker]Output Types >>, [worker]Inputs >>, [worker]Input Types >>], ~, [worker]Outputs >>]
	{ out <- [program]Store Function[~] }}}}
}		

Compile Worker@NWorker[worker,program,name:out]
{
	If[[worker]Builtin? >>]
	{
		out <- program
	}{
		If[[[worker]Library >>] = [""]]
		{	
			ifunc <- Fold[Set Output Type[?], Fold[Set Input Type[?], [[program]Create Function[name,[worker]Inputs >>, [worker]Outputs >>, [worker]Convention >>]]Uses <<[[worker]Uses >>], [worker]Input Types >>], [worker]Output Types >>]
			
			groups <- [worker]Dependency Groups
			
			fgroup <- [groups]First
			{
				with conds <- [worker]Save Group Conditions[groups, ~]
				final func <- [with conds]Compile Group[program,func,groups, ~]
			}{
				final func <- Val[func]
			}
			res vars <- [worker]Result Vars
			init vars <- Concatenate[res vars, [with conds]No Release Results]
			
			func <- Fold[Set Null[?], Fold[Set Null[?], Fold[Allocate Var[?, ?, "Any Type"], ifunc, init vars], init vars], [worker]Outputs >>]
			out <- [program]Store Function[Fold[Release[?], Fold[Release Var[with conds, ?], final func, res vars], [worker]Inputs >>]]
		}{
			out <- Compile Foreign Stub[worker,[program]Link[[worker]Convention >>, [worker]Library >> ],name]
		}
	}
}

Blueprint NBlueprint
{
	Fields
	Methods
}

String@NBlueprint[nbp:out]
{
	out <- [[[["NBlueprint: Fields("
		]Append[Join[Map[[nbp]Fields >>, [?]Index[0]], ", "]]
		]Append["), Methods("]
		]Append[Join[Keys[[nbp]Methods >>], ", "]]
		]Append[")"]
}

NBlueprint[:out]
{
	out <- [[Build[NBlueprint()]]Fields <<[()]]Methods <<[Dictionary[]]
}

Add Field@NBlueprint[bp,name,type:out]
{
	out <- [bp]Fields <<[ [[bp]Fields >>]Append[ [[()]Append[name]]Append[type] ] ]
}

Add Method@NBlueprint[bp,name:out]
{
	out <- [bp]Methods <<[ [[bp]Methods >>]Set[name, Yes] ]

}

Understands Method@NBlueprint[bp,name:out]
{
	out <- [[bp]Methods >>]Index[name] {}
	{ out <- No }
}

Eq Field Name[field,name:out]
{
	out <- [[field]Index[0]]=[name]
}

Get Field Type@NBlueprint[bp,name:out,notfound]
{
	,not found <- [[bp]Fields >>]Find[Eq Field Name[?, name]]
	{ out <- [[[bp]Fields >>]Index[~]]Index[1] }
}

_Compile Blueprint Fields[type,field:out]
{
	name <- [field]Index[0]
	ftype <- [field]Index[1]
	out <- [type]Add Field[name,ftype]
}

_Compile Blueprint Methods[type,junk,name:out]
{
	If[[[name]=["Call"]] And [[[type]Name >>] = ["Worker"]]]
	{
		out <- type
	}{
		out <- [type]Add Method[name]
	}
}

Make Init[func,field:out]
{
	name <- [field]Index[0]
	variant <- [[field]Index[1]]Variant >>
	If[[variant] = ["Boxed"]]
	{
		out <- [func]Set Field Null["obj", name]
	}{
		out <- func
	}
}

Make Copy[func,field:out]
{
	name <- [field]Index[0]
	variant <- [[field]Index[1]]Variant >>
	If[[variant] = ["Boxed"]]
	{
		got <- [func]Read Field["obj", name] {}
		{ 
			stream <- [[got]Instruction Stream
				]AddRef No Dest[~] 
			out <- [got]Do If[~, stream]
		}
	}{
		out <- func
	}
}

Make Cleanup[func,field:out]
{
	name <- [field]Index[0]
	variant <- [[field]Index[1]]Variant >>
	If[[variant] = ["Boxed"]]
	{
		got <- [func]Read Field["obj", name] {}
		{ 
			stream <- [[got]Instruction Stream
				]Release[~] 
			out <- [got]Do If[~, stream]
		}
	}{
		out <- func
	}
}

Make Special@NBlueprint[bp,backend,info,bp name:out]
{
	func name <- [info]Index[0]
	pop worker <- [info]Index[1]
	func <- [[backend]Create Function[func name,("obj"),(),"cdecl"]
		]Set Input Type[Type Instance[bp name], 0]
	out <- [backend]Store Function[Fold[pop worker, func, [bp]Fields >>]]
}

Getters Setters[backend,field,type name:out]
{
	//TODO: Throw an exception or something if we read a field that is empty
	name <- [field]Index[0]
	type <- [field]Index[1]
	mytype <- Type Instance[type name]
	start getter,getref <- [[[[backend]Create Function[ [[[name]Append[" >>"]]Append["@"]]Append[type name], ("obj"), ("out"), "rhope"]
		]Set Input Type[mytype, 0]
		]Set Output Type[[type]Set Variant["Boxed"], 0]
		]Read Field["obj", name]
	If[[[type]Variant >>] = ["Boxed"]]
	{
		getter <- [[start getter]Do AddRef[getref, "out"]]Release["obj"]
	}{
		getter <- [[start getter]Box[getref, "out", type]]Release["obj"]
	}
		
	begin setter <- [[[[[backend]Create Function[ [[[name]Append[" <<"]]Append["@"]]Append[type name], ("obj","newval"), ("out"), "rhope"]
		]Set Input Type[mytype, 0]
		]Set Input Type[[type]Set Variant["Boxed"], 1]
		]Set Output Type[mytype, 0]
		]Copy["obj"]
		
	If[[[type]Variant >>] = ["Boxed"]]
	{
		,origref <- [begin setter]Read Field["obj", name]
		{ 
			stream <- [[~]Instruction Stream
			]Release[origref]
			,setref <- [[~]Do If[origref, stream]
			]Write Field["obj", name]
			{
				setter <- [[~]Move["newval", setref]
				]Move["obj", "out"]
			}
		}
	}{
		,setref <- [begin setter]Write Field["obj", name]
		{ 
			setter <- [[[~]Unbox["newval", setref]
			]Release["newval"]
			]Move["obj", "out"]
		}
	}
	
	out <- [[backend]Store Function[getter]]Store Function[setter]
	
}

Compile Blueprint@NBlueprint[bp,backend,name:out]
{
	//Rhope identifiers can't start with spaces, so we can use identifiers that start with spaces for special functions
	init name <- [" init "]Append[name]
	[("Array","Boxed Array","Worker")]Find[=[?,name]]
	{
		[("internalarraynaked","internalarrayboxed","internalworker")]Index[~]
		{
			copy name <- [~]Append["copy"]
			cleanup name <- [~]Append["cleanup"]
		}
	}{
		copy name <- [" copy "]Append[name]
		cleanup name <- [" cleanup "]Append[name]
	}
	type <- [[[Fold[_Compile Blueprint Methods[?], Fold[_Compile Blueprint Fields[?], [backend]Create Type[name], [bp]Fields >>], [bp]Methods >>]
	]Init <<[init name]
	]Copy <<[copy name]
	]Cleanup <<[cleanup name]
	
	out <- [backend]Register Type[type]
}

Compile Special@NBlueprint[bp,backend,name:out]
{
	makespecial <- [[[Dictionary[]	
		]Set["init", Make Init[?]]
		]Set["copy", Make Copy[?]]
		]Set["cleanup", Make Cleanup[?]]
		
	after specials <- Fold[[bp]Make Special[?, ?, name], backend, [backend]Needed Specials[name,makespecial]]
	out <- Fold[Getters Setters[?, ?, name], after specials, [bp]Fields >>]
}

Blueprint NProgram
{
	Blueprints
	Workers
	Worker Refs
	Numtypes
	Global Stores
}

NProgram[:out]
{
	out <- [[[[[Build[NProgram()]
		]Blueprints <<[Dictionary[]]
		]Workers <<[Dictionary[]]
		]Worker Refs <<[Dictionary[]]
		]Numtypes << [("Int8","Int16","Int32","Int64","UInt8","UInt16","UInt32","UInt64")]
		]Global Stores <<[Dictionary[]]
}

Supported Number Types@NProgram[program:out]
{
	out <- [program]Numtypes >>
}

Bind Worker@NProgram[prog,name,worker:out]
{	
	after bind <- [prog]Workers << [ [[prog]Workers >>]Set[name, [worker]Name <<[name]] ]
	parts <- [name]Split["@"]
	bpname <- [parts]Index[1]
	{
		If[[~]=[""]]
		{
			out <- Val[after bind]
		}{
			orig bp <- [[after bind]Blueprints >>]Index[bpname] {}
			{ orig bp <- NBlueprint[] }
			out <- [after bind]Blueprints <<[ [[after bind]Blueprints >>]Set[bpname, [orig bp]Add Method[[parts]Index[0]] ] ]
		}
	}{
		out <- Val[after bind]
	}
}

Bind Blueprint@NProgram[prog,name,blueprint:out]
{
	out <- [prog]Blueprints << [ [[prog]Blueprints >>]Set[name, blueprint] ]
}

_Compile Program BP[backend, blueprint, name:out]
{
	out <- [blueprint]Compile Blueprint[backend, name]
}

_Compile Program BP Special[backend, blueprint, name:out]
{
	out <- [blueprint]Compile Special[backend, name]
}

_Compile Program[backend, worker, name:out]
{
	out <- [worker]Compile Worker[backend, name]
}

Compile Program@NProgram[prog, backend:out]
{
	backend with bps <- Generate Boolean Methods[Generate Number Methods[Fold[_Compile Program BP Special[?], Fold[_Compile Program BP[?], [backend]Global Stores <<[[prog]Global Stores >>], [prog]Blueprints >>], [prog]Blueprints >>]]]
	workers with infer <- Map[[prog]Workers >>, Infer Types[?, prog]]
	out <- Fold[_Compile Program[?], backend with bps,  workers with infer]
}

Register Method@NProgram[prog, name, convention, inputs, outputs: out]
{
	[[prog]Worker Refs >>]Index[name]
	{
		ref <- [[[[[~]Inputs <<[ Max[[~]Inputs >>, inputs] ]
		]Min Inputs <<[ Min[[~]Min Inputs >>, inputs] ]
		]Outputs <<[ Max[[~]Outputs >>, outputs] ]
		]Min Outputs <<[ Min[[~]Min Outputs >>, outputs] ]
		]Is Method? <<[Yes]
	}{
		ref <- Worker Ref[name, convention, inputs, outputs, Yes]
	}
	out <- [prog]Worker Refs <<[ [[prog]Worker Refs >>]Set[name, ref]]
}

Register Worker@NProgram[prog, name, convention, inputs, outputs: out]
{
	[[prog]Worker Refs >>]Index[name]
	{
		ref <- [[[[~]Inputs <<[ Max[[~]Inputs >>, inputs] ]
		]Min Inputs <<[ Min[[~]Min Inputs >>, inputs] ]
		]Outputs <<[ Max[[~]Outputs >>, outputs] ]
		]Min Outputs <<[ Min[[~]Min Outputs >>, outputs] ]
	}{
		ref <- Worker Ref[name, convention, inputs, outputs, No]
	}
	after reg <- [prog]Worker Refs <<[ 
		[ [prog]Worker Refs >> ]Set[name, ref]
	]

	parts <- [name]Split["@"]
	[parts]Index[1]
	{
		If[[~]=[""]]
		{
			out <- [after reg]Register Worker[[parts]Index[0], convention, inputs, outputs]
		}{
			out <- [after reg]Register Method@NProgram[[parts]Index[0], convention, inputs, outputs]
		}
	}{
		out <- Val[after reg]
	}
}

Register Builtins@NProgram[prog:out]
{
	registered <- [[[[[[[[[[[prog]Register Worker["Print", "rhope", 1, 1]
	]Register Worker["If@Boolean", "rhope", 1, 2]
	]Register Worker["Build", "rhope", 1, 1]
	]Register Worker["Blueprint Of", "rhope", 1, 1]
	]Register Worker["Call", "rhope", 1, 1]//This will ensure that min outputs is 1
	]Register Worker["Call@Worker", "rhope", 1, 10]//10 is a quick workaround for the lack of proper varargs
	]Register Worker["ID", "rhope", 1, 1]
	]Register Worker["Blueprint From ID", "rhope", 1, 2]
	]Register Worker["Pause", "rhope", 1, 1]
	]Register Worker["Resume", "rhope", 2, 2]
	]Register Number Methods
	
	out <- [[[[[[[[[registered]Bind Worker["If@Boolean",
		[[[[[NWorker["rhope"]
		]Inputs <<[("condition")]
		]Input Types <<[ [()]Append[Type Instance["Boolean"]] ]
		]Outputs <<[("isyes","isno")]
		]Output Types <<[ [[()]Append[Type Instance["Boolean"]]]Append[Type Instance["Boolean"]] ]
		]Builtin? <<[Yes]]
	]Bind Worker["Print",
		[[[[[NWorker["rhope"]
		]Inputs <<[("value")]
		]Input Types <<[ [()]Append[Type Instance["Any Type"]] ]
		]Outputs <<[("out")]
		]Output Types <<[ [()]Append[Type Instance["Int32"]] ]
		]Builtin? <<[Yes]] 
	]Bind Worker["Build",
		[[[[[NWorker["rhope"]
		]Inputs <<[("type")]
		]Input Types <<[ [()]Append[Type Instance["Blueprint"]] ]
		]Outputs <<[("out")]
		]Output Types <<[ [()]Append[Type Instance["Any Type"]] ]
		]Builtin? <<[Yes]] 
	]Bind Worker["Blueprint Of",
		[[[[[NWorker["rhope"]
		]Inputs <<[("object")]
		]Input Types <<[ [()]Append[Type Instance["Any Type"]]]
		]Outputs <<[("type")]
		]Output Types <<[ [()]Append[Type Instance["Blueprint"]]]
		]Builtin? <<[Yes]]
	]Bind Worker["Call@Worker",
		[[[[[NWorker["rhope"]
		]Inputs <<[("worker")]
		]Input Types <<[ [()]Append[Type Instance["Worker"]] ]
		]Outputs <<[("ret1","ret2","ret3","ret4","ret5","ret6","ret7","ret8","ret9","ret10")]
		]Output Types <<[ [[()]Append[Type Instance["Any Type"]]]Append[Type Instance["Any Type"]] ]
		]Builtin? << [Yes]]
	]Bind Worker["ID",
		[[[[[NWorker["rhope"]
		]Inputs <<[("bp")]
		]Input Types <<[ [()]Append[Type Instance["Blueprint"]]]
		]Outputs <<[("id")]
		]Output Types <<[ [()]Append[Type Instance["UInt32"]]]
		]Builtin? << [Yes]]
	]Bind Worker["Blueprint From ID",
		[[[[[NWorker["rhope"]
		]Inputs <<[("id")]
		]Input Types <<[ [()]Append[Type Instance["UInt32"]]]
		]Outputs <<[("bp","none")]
		]Output Types <<[ [[()]Append[Type Instance["Blueprint"]]]Append[Type Instance["Any Type"]]]
		]Builtin? << [Yes]]
	]Bind Worker["Pause",
		[[[[[NWorker["rhope"]
		]Inputs <<[("tocall")]
		]Input Types <<[ [()]Append[Type Instance["Worker"]]]
		]Outputs <<[("resumeval")]
		]Output Types <<[ [()]Append[Type Instance["Any Type"]] ]
		]Builtin? <<[Yes]]
	]Bind Worker["Resume",
		[[[[[NWorker["rhope"]
		]Inputs <<[("toresume","resumeval")]
		]Input Types <<[ [[()]Append[Type Instance["Contest"]]]Append[Type Instance["Any Type"]] ]
		]Outputs <<[("success","cantresume")]
		]Output Types <<[ [[()]Append[Type Instance["Any Type"]]]Append[Type Instance["Any Type"]] ]
		]Builtin? <<[Yes]]
}

Find Worker@NProgram[prog, name:out,notfound]
{
	out,notfound <- [[prog]Worker Refs >>]Index[name]
}

Find Worker Def@NProgram[prog,name:out,notfound]
{
	out,notfound <- [[prog]Workers >>]Index[name]
}

Find Method@NProgram[prog, name, type:out,notfound]
{
	bp,notfound <- [[prog]Blueprints >>]Index[[type]Name >>]
	,notfound <- If[[bp]Understands Method[name]]
	{
		out <- [[prog]Workers >>]Index[[[name]Append["@"]]Append[[type]Name >>]]
	}
}

Find Field@NProgram[prog, name, type:fieldtype,notfound]
{
	bp,notfound <- [[prog]Blueprints >>]Index[[type]Name >>]
	fieldtype,notfound <- [bp]Get Field Type[name]
}

Implicit Conversion@NProgram[prog, fromtype, totype:func,notfound]
{
	notfound <- No
}

Is Method?@NProgram[prog,name:is,is not]
{
	,is not <- [[prog]Worker Refs>>]Index[name]
	{
		is,is not <- If[[~]Is Method? >>]
	}
}