#!/bin/bash # If this file has already been sourced, just return test $(SPECIALFORMS_LET_SH+true)TODO && return declare -g SPECIALFORMS_LET_SH = 'true' source ${BASH_SOURCE%/*}/common.sh source ${BASH_SOURCE%/*}/test.sh source ${BASH_SOURCE%/*}/specialforms.sh # # LET # # The inits are evaluated in the current environment (in some unspecified order), # the variables are bound to fresh locations holding the results, the expressions # are evaluated sequentially in the extended environment, and the value of the # last expression is returned. Each binding of a variable has the expressions as # its region. # # (let ((x 2) (y 3)) # (* x y)) # proc evaluator::specialforms::letTODO { declare env = $(1)TODO declare functionName = $(2)TODO # let declare args = $(3) # list of , ,..., variable::LinkedList::length $argsTODO ; declare -i length = $(RESULT) if [[ $length < 2 ]] { stderr "usage: (let .. )" exit 1 } variable::LinkedList::first $argsTODO ; declare bindings = $(RESULT) variable::LinkedList::rest $argsTODO ; declare expressions = $(RESULT) # set values environment::pushScope $envTODO ; declare runningEnv = $(RESULT)TODO declare thisBinding = '', thisKey = '', thisValue = '', thisResult = '' while ! variable::LinkedList::isEmpty_c $(bindings) { variable::LinkedList::first $(bindings) ; setglobal thisBinding = $(RESULT) variable::LinkedList::rest $(bindings) ; setglobal bindings = $(RESULT) variable::LinkedList::length $(thisBinding) if [[ "${RESULT}" != 2 ]] { stderr "let binding must have exactly 2 elements" } variable::LinkedList::index $(thisBinding) 0 ; setglobal thisKey = $(RESULT) variable::LinkedList::index $(thisBinding) 1 ; setglobal thisValue = $(RESULT) evaluator::eval $env $thisValue environment::setVariable $(runningEnv) $thisKey $RESULT }TODO # evaluate expressions declare currentSexp = '', currentResult = '' while ! variable::LinkedList::isEmpty_c $(expressions) { variable::LinkedList::first $(expressions) ; setglobal currentSexp = $(RESULT) variable::LinkedList::rest $(expressions) ; setglobal expressions = $(RESULT) evaluator::eval $runningEnv $currentSexp setglobal currentResult = $(RESULT) } setglobal RESULT = $(currentResult) } # # ====================================================== if test $0 != $BASH_SOURCE { return } assert::report if test $(1+isset) && test $1 == "debug" { variable::printMetadata }