 	'true': true
 	'false': false
 	'nil': null
-_context = STD_CONTEXT
+
+_context = [STD_CONTEXT]
+
+ctx = ->
+	_context[_context.length-1]
+
+getvar = (x) ->
+	for i in [_context.length-1..0]
+		if _context[i].hasOwnProperty x
+			debug "Found variable #{x} in context ##{i}"
+			return _context[i][x]
+	return undefined
+
+setvar = (x, val, overwrite_outer_scope = false) ->
+	if overwrite_outer_scope
+		for i in [_context.length-1..0]
+			if _context[i].hasOwnProperty x
+				_context[i][x] = val
+				debug "Assigned var #{x} = #{val} in context ##{i}", 2
+				return
+		err "Variable #{x} not found in any context!"
+	else
+		ctx()[x] = val
+		debug "Assigned variable #{x} = #{val} in context ##{_context.length-1}", 2
 
 # current lineno (lines start at 1)
 _lineno = 1


	if tok[1] == '='
		# var (re)assign (a = expr)
		if _context[fst] == undefined
			err "Variable #{fst} not in context!"
			return
		_context[fst] = evaluate tok[2..]
		debug "Var reassign: #{fst} = #{_context[fst]}"
		return lineno + 1

	if tok[1] == ':='
		#var first assign (a := expr) - may shadow a pre-existing variable
		_context[fst] = evaluate tok[2..]
		debug "Var define: #{fst} := #{_context[fst]}"
		return lineno + 1
	
	err "[aborted] Invalid line: #{line} @ #{lineno}"

	a = parseFloat name
	if a == a
		return a
	return getvar name # may be nil

# evaluates a series of tokens, which may be:
# var1 (arith-op) var2
