view src/editor.tp @ 251:2557ce4e671f

Fix a couple of compiler bugs. topenv was getting initialized in multiple places. This resulted in multiple copies of modules getting created which caused problems for macro expansion. Additionally, arguments were not being marked as declared during code generation so assigning to an argument that was not closed over generated invalid C code.
author Michael Pavone <pavone@retrodev.com>
date Fri, 11 Apr 2014 22:29:32 -0700
parents 15aac5334b64
children
line wrap: on
line source

#{
//mquery functions
q <- foreign: :query {}
qall <- foreign: :query {}
each <- foreign: :iterable fun {}
addClass <- foreign: :node className {}
removeClass <- foreign: :node className {}
hasClass <- foreign: :node className {}
get <- foreign: :url onSuccess onFail onOther {}
newEl <- foreign: :tagname props {}

//editor.js functions
getEl <- foreign: :from idx {}
setEl <- foreign: :to idx val {}
goFullScreen <- foreign: {}
create_symbol <- foreign: :name {}

//TP Parser
parser <- foreign: #{
	parse <- foreign: :str {}
}
isLambda <- foreign: :astnode {}

//js builtins
console <- foreign: #{
	log <- foreign: :val {}
}
window <- foreign: #{}
Object <- foreign: #{
	keys <- foreign: :object {}
}

filter <- :arr pred {
	output <- arr slice: 0 0
	each: arr :idx el {
		if: (pred: el) {
			output push: el
		} else: {}
	}
	output
}

//editor code
selection <- #{
	valid? <- false
}

setSelection:withInNode <- :astnode :innode {
	fakeEvent <- #{
		stopPropagation <- :Blah {
		}
	}

	selection <- #{
		valid? <- true
		in <- {
			(innode domNode) onclick: fakeEvent
		}
		out <- {
			((astnode up) domNode) onclick: fakeEvent
		}
		next <- {
			(((astnode up) getNext: astnode) domNode) onclick: fakeEvent
		}

		previous <- {
			(((astnode up) getPrev: astnode) domNode) onclick: fakeEvent
		}
	}
}

setSelection <- :astnode {
	fakeEvent <- #{
		stopPropagation <- :Blah {
		}
	}
	selection <- #{
		valid? <- true
		in <- {
		}
		out <- {
			fakeEvent <- #{
				stopPropagation <- :Blah {
				}
			}
			((astnode up) domNode) onclick: fakeEvent
		}
		next <- {
			console log: "selection next"
			(((astnode up) getNext: astnode) domNode) onclick: fakeEvent
		}
		previous <- {
			(((astnode up) getPrev: astnode) domNode) onclick: fakeEvent
		}
	}
}

editFile <- :path {
	get: path :request {
		addClass: (q: "body") "editorMode"
		src <- request responseText
		ast <- parser parse: src
		ast populateSymbols: (foreign: null)
		ast toHTML: (q: "#src")
	}
}

selectNode <- :node {
	each: (qall: ".selected") :idx el {
		removeClass: el "selected"
	}
	addClass: node "selected"
}

selectQuery <- :selector {
	selectQuery: selector in: (foreign: undefined)
}

selectQuery:in <- :selector :context {
	each: (qall: ".selected") :idx el {
		removeClass: el "selected"
	}
	each: (qall: selector context) :idx el {
		addClass: el "selected"
	}
}

selectParent <- :node {
	each: (qall: ".selectParent") :idx el {
		removeClass: el "selectParent"
	}
	addClass: node "selectParent"
}

popInscope:onClick <- :syms :handler {
	inscope <- q: "#inscope"
	inscope innerHTML!: ""
	each: syms :idx key {
		inscope appendChild: (newEl: "li" #{
			textContent <- key
			onclick <- :Event { handler: key }
		})
	}
}

scalarClick <- :domnode astnode event {
	selectNode: domnode
	setSelection: astnode
	event stopPropagation: (foreign: undefined)
	//TODO: set focus
}

symbolClick <- :domnode astnode event {
	selectNode: domnode
	popInscope: ((astnode symbols) allSymbols: (foreign: undefined)) onClick: :key {
		domnode textContent!: key
		astnode name!: key
	}
	setSelection: astnode
	event stopPropagation: (foreign: undefined)
}

assignClick <- :domnode astnode event {
	selectParent: domnode
	selectQuery: ".selectParent > .varname" in: domnode
	popInscope: ((astnode symbols) allSymbols: (foreign: undefined)) onClick: :key {
		(domnode firstChild) textContent!: key
		(astnode symbol) name!: key
	}
	setSelection: astnode withInNode: (astnode expression)
	event stopPropagation: (foreign: undefined)
}

opClick <- :domnode astnode event {
	selectParent: domnode
	selectQuery: ".selectParent > .opname" in: domnode
	showOps
	setSelection: astnode withInNode: (astnode left)
	event stopPropagation: (foreign: undefined)
}

funClick <- :domnode astnode event {
	selectParent: domnode
	selectQuery: ".selectParent > .funpart" in: domnode
	symtable <- astnode symbols
	syms <- filter: (symtable allSymbols: (foreign: undefined)) :sym {
		isLambda: ((symtable find: sym) def)
	}
	inner <- if: (astnode receiver) != (foreign: null) {
		astnode receiver
	} else: {
		(astnode args) getEl: 0
	}
	setSelection: astnode withInNode: inner
	popInscope: syms onClick: :key {
		astnode name!: key
		parts <- key split: ":"
		nodes <- []
		each: (domnode children) :idx val{
			nodes push: val
		}
		partIdx <- 0
		nodeIdx <- 0
		lastWasNamePart <- true
		while: { partIdx < (parts length) || nodeIdx < (nodes length) } do: {
			if: nodeIdx < (nodes length) {
				node <-getEl: nodes nodeIdx
				nodeIdx <- nodeIdx + 1
				if: (hasClass: node "funpart") {
					if: partIdx < (parts length) {
						postfix <- if: partIdx = 0 && nodeIdx = 2 && (parts length) = 1 && (nodes length) = 2 { "" } else: { ":" }
						t <- (getEl: parts partIdx)
						node textContent!: (getEl: parts partIdx) . postfix
						partIdx <- partIdx + 1
					} else: {
						domnode removeChild: node
					}
					lastWasNamePart <- true
				} else: {
					if: (not: lastWasNamePart) && partIdx < (parts length) && nodeIdx > 0 {
						domnode insertBefore: (newEl: "span" #{
							className <- "funpart selected"
							textContent <- (getEl: parts partIdx) . ":"
						}) node
						partIdx <- partIdx + 1
					}
					lastWasNamePart <- false
				}
			} else: {
				console log: "part: " . (getEl: parts partIdx)
				domnode appendChild: (newEl: "span" #{
					className <- "funpart selected"
					textContent <- (getEl: parts partIdx) . ":"
				})
				partIdx <- partIdx + 1
			}
		}
	}
	event stopPropagation: (foreign: undefined)
}

replaceNode:with <- :astnode domnode :newnode {

}

lambdaClick <- :domnode astnode event {
	selectNode: domnode
	popInscope: ((astnode symbols) allSymbols: (foreign: undefined)) onClick: :key {
		replaceNode: astnode domnode with: (create_symbol: key)
	}
	inner <- if: ((astnode args) length) > 0 {
		(astnode args) getEl: 0
	} else: {
		(astnode expressions) getEl: 0
	}
	setSelection: astnode withInNode: inner
	event stopPropagation: (foreign: undefined)
}

objectClick <- :domnode astnode event {
	selectNode: domnode
	popInscope: ((astnode symbols) allSymbols: (foreign: undefined)) onClick: :key {
		console log: "fooobar!"
	}
	setSelection: astnode withInNode: ((astnode messages) getEl: 0)
	event stopPropagation: (foreign: undefined)
}

visible <- "showops"

showOps <- {
	each: (qall: ".controls") :idx el {
		removeClass: el visible
		addClass: el "showops"
	}
	visible <- "showops"
}

showLit <- {
	each: (qall: ".controls") :idx el {
		removeClass: el visible
		addClass: el "showlit"
	}
	visible <- "showlit"
}

main <- {
	get: "/src/" :data {
		fakeEl <- newEl: "div" #{
			innerHTML <- data response
		}
		each: (qall: "a" fakeEl) :idx el {
			if: ((el textContent) = "../") {} else: {
				nel <- newEl: "a" #{
					href <- "/edit/src/" + (el textContent)
					textContent <- el textContent
				}
				nel onclick!: :event {
					link <- foreign: this
					path <- link href
					path <- path substr: (path indexOf: "/edit/") + 5
					editFile: path
					foreign: false
				}
				li <- newEl: "li"
				li appendChild: nel
				(q: "#browser ul") appendChild: li
			}
		}
	}

	//bind handlers for editor buttons
	each: (qall: ".controls li") :idx el {
		el onclick!: :event {
			srcel <- (q: "#src")
			srcel textContent!: (srcel textContent) + (el textContent)
		}
	}
	(q: "#ops_button") onclick!: :event {
		showOps
	}
	(q: "#lit_button") onclick!: :event {
		showLit
	}

	(q: "#in") onclick!: :event {
		console log: "inwards"
		if: (selection valid?) {
			selection in
		}
	}

	(q: "#out") onclick!: :event {
		console log: "outwards"
		if: (selection valid?) {
			selection out
		}
	}

	(q: "#next") onclick!: :event {
		if: (selection valid?) {
			selection next
		}
	}

	(q: "#prev") onclick!: :event {
		if: (selection valid?) {
			selection previous
		}
	}

	path <- (window location) pathname
	if: (path indexOf: "/edit/") = 0 {
		editFile: (path substr: 5)
	}
	(q: "#fullscreen") onclick!: :event {
		goFullScreen:
	}
}

}