#!/bin/bash # If this file has already been sourced, just return test $(SPECIALFORMS_IF_SH+true) && return declare -g SPECIALFORMS_IF_SH=true source ${BASH_SOURCE%/*}/common.sh source ${BASH_SOURCE%/*}/test.sh source ${BASH_SOURCE%/*}/specialforms.sh # # IF # # Predicate, consequent, and alternative are expressions. An if expression is # evaluated as follows: first, predicate is evaluated. If it yields a true # value, then consequent is evaluated and its value is returned. Otherwise # alternative is evaluated and its value is returned. If predicate yields a # false value and no alternative is specified, then the result of the expression # is unspecified. # # An if expression evaluates either consequent or alternative, never # both. Programs should not depend on the value of an if expression that has no # alternative. # # (if (> 3 2) 'yes 'no) => yes # (if (> 2 3) 'yes 'no) => no # (if (> 3 2) # (- 3 2) # (+ 3 2)) => 1 # proc evaluator::specialforms::if { declare env="$(1)" declare functionName="$(2)" # if declare args="$(3)" # list of condition, , variable::LinkedList::length $args ; declare -i length="$(RESULT)" if [[ $length != 3 ]] { stderr "usage: (if condition true-branch false-branch)" exit 1 } variable::LinkedList::index $args 0 ; declare condition=$(RESULT) variable::LinkedList::index $args 1 ; declare trueBranch=$(RESULT) variable::LinkedList::index $args 2 ; declare falseBranch=$(RESULT) evaluator::eval $env $condition ; declare conditionResult=$(RESULT) variable::type::instanceOfOrExit $conditionResult Boolean variable::value $conditionResult if [[ "true" == "${RESULT}" ]] { evaluator::eval $env $trueBranch } else { evaluator::eval $env $falseBranch } setglobal RESULT = $(RESULT) } # # ====================================================== if test $0 != $BASH_SOURCE { return } # # TRUE # # # not using env # createTestEnv ; setglobal env = $(RESULT) variable::LinkedList::new ; setglobal command = $(RESULT) appendToList $command Identifier "if" variable::LinkedList::new ; setglobal conditional = $(RESULT) appendToList $conditional Identifier "=" Integer 3 Integer 3 variable::LinkedList::append $command $conditional appendToList $command String yes String no evaluator::eval $env $command variable::debug $(RESULT) ; \ assert::equals "String :: yes" $(RESULT) "(if (= 3 3) 'yes 'no)" # # FALSE # createTestEnv ; setglobal env = $(RESULT) variable::LinkedList::new ; setglobal command = $(RESULT) appendToList $command Identifier "if" variable::LinkedList::new ; setglobal conditional = $(RESULT) appendToList $conditional Identifier "=" Integer 3 Integer 4 variable::LinkedList::append $command $conditional appendToList $command String yes String no evaluator::eval $env $command variable::debug $(RESULT) ; \ assert::equals "String :: no" $(RESULT) "(if (= 3 4) 'yes 'no)" # # Evaluates result # createTestEnv ; setglobal env = $(RESULT) setInEnv $env "v" Integer 10 variable::LinkedList::new ; setglobal command = $(RESULT) appendToList $command Identifier "if" variable::LinkedList::new ; setglobal conditional = $(RESULT) appendToList $conditional Identifier "=" Integer 3 Integer 4 variable::LinkedList::append $command $conditional appendToList $command Integer 5 Identifier v evaluator::eval $env $command variable::debug $(RESULT) ; \ assert::equals "Integer :: 10" $(RESULT) "(if (= 3 4) 'yes 'no)" assert::report if test $(1+isset) && test $1 == "debug" { variable::printMetadata }