Posted to tcl by aspect at Wed Nov 23 23:05:31 GMT 2016view pretty

proc proc* {name arglist body} {
	set upargs [lsearch -inline -all $arglist _*]
	if {[llength $upargs]} {
		set upvar [list ::upvar 1]
		foreach a $upargs {
			append upvar " \$$a [list [string range $a 1 end]]"
		}
		set body "$upvar;$body"
	}
	tailcall ::proc $name $arglist $body
}


# clamp saves some tedium and getting max/min confused
proc* clamp {_x min max} {
    if {$x < $min} {set x $min}
    if {$x > $max} {set x $max}
    return $x
}

# incrmod 10 i 3 -> 0 3 6 9 2 5 8 1 4 7 ..
proc* incrmod {modulus _var {increment 1}} {
    set var [expr {($var + $increment) % $modulus}]
}

# assertions, if nothing else, are a nice default error message
proc assert {x {msg ""}} {
    if {![uplevel 1 expr [list $x]]} {
        catch {
            set y [uplevel 1 [list subst -noc $x]]
            if {$y ne $x} {
                set x "{$y} from {$x}"
            }
        }
        throw ASSERT "[concat "Assertion failed!" $msg] $x"
    }
}


proc test {} {
	set a 12
	assert {[clamp a 0 10] == 10}
	assert {[clamp a 5 15] == 10}
	assert {[clamp a 12 20] == 12}
	assert {[incrmod 12 a 1] == 1}
}

test