@ -30,8 +30,8 @@ ValuePtr Eval::evalDef(const ValueVector& nodes, EnvironmentPtr env)
VALUE_CAST ( symbol , Symbol , nodes . front ( ) ) ;
VALUE_CAST ( symbol , Symbol , nodes . front ( ) ) ;
// Eval second argument
// Eval second argument
m_ast = * std : : next ( nodes . begin ( ) ) ;
m_ast_stack . push ( * std : : next ( nodes . begin ( ) ) ) ;
m_env = env ;
m_env_stack . push ( env ) ;
ValuePtr value = evalImpl ( ) ;
ValuePtr value = evalImpl ( ) ;
// Dont overwrite symbols after an error
// Dont overwrite symbols after an error
@ -52,8 +52,8 @@ ValuePtr Eval::evalDefMacro(const ValueVector& nodes, EnvironmentPtr env)
VALUE_CAST ( symbol , Symbol , nodes . front ( ) ) ;
VALUE_CAST ( symbol , Symbol , nodes . front ( ) ) ;
// Eval second argument
// Eval second argument
m_ast = * std : : next ( nodes . begin ( ) ) ;
m_ast_stack . push ( * std : : next ( nodes . begin ( ) ) ) ;
m_env = env ;
m_env_stack . push ( env ) ;
ValuePtr value = evalImpl ( ) ;
ValuePtr value = evalImpl ( ) ;
VALUE_CAST ( lambda , Lambda , value ) ;
VALUE_CAST ( lambda , Lambda , value ) ;
@ -111,55 +111,6 @@ ValuePtr Eval::evalQuote(const ValueVector& nodes)
return nodes . front ( ) ;
return nodes . front ( ) ;
}
}
// (try* x (catch* y z))
ValuePtr Eval : : evalTry ( const ValueVector & nodes , EnvironmentPtr env )
{
CHECK_ARG_COUNT_AT_LEAST ( " try* " , nodes . size ( ) , 1 ) ;
// Try 'x'
m_ast = nodes . front ( ) ;
m_env = env ;
auto result = evalImpl ( ) ;
if ( ! Error : : the ( ) . hasAnyError ( ) ) {
return result ;
}
if ( nodes . size ( ) = = 1 ) {
return nullptr ;
}
// Catch
// Get the error message
auto error = ( Error : : the ( ) . hasOtherError ( ) )
? makePtr < String > ( Error : : the ( ) . otherError ( ) )
: Error : : the ( ) . exception ( ) ;
Error : : the ( ) . clearErrors ( ) ;
VALUE_CAST ( catch_list , List , nodes . back ( ) ) ;
const auto & catch_nodes = catch_list - > nodes ( ) ;
CHECK_ARG_COUNT_IS ( " catch* " , catch_nodes . size ( ) - 1 , 2 ) ;
VALUE_CAST ( catch_symbol , Symbol , catch_nodes . front ( ) ) ;
if ( catch_symbol - > symbol ( ) ! = " catch* " ) {
Error : : the ( ) . add ( " catch block must begin with catch* " ) ;
return nullptr ;
}
VALUE_CAST ( catch_binding , Symbol , ( * std : : next ( catch_nodes . begin ( ) ) ) ) ;
// Create new Environment that binds 'y' to the value of the exception
auto catch_env = Environment : : create ( env ) ;
catch_env - > set ( catch_binding - > symbol ( ) , error ) ;
// Evaluate 'z' using the new Environment
m_ast = catch_nodes . back ( ) ;
m_env = catch_env ;
return evalImpl ( ) ;
}
// -----------------------------------------
// (do 1 2 3)
// (do 1 2 3)
void Eval : : evalDo ( const ValueVector & nodes , EnvironmentPtr env )
void Eval : : evalDo ( const ValueVector & nodes , EnvironmentPtr env )
{
{
@ -167,14 +118,14 @@ void Eval::evalDo(const ValueVector& nodes, EnvironmentPtr env)
// Evaluate all nodes except the last
// Evaluate all nodes except the last
for ( auto it = nodes . begin ( ) ; it ! = std : : prev ( nodes . end ( ) , 1 ) ; + + it ) {
for ( auto it = nodes . begin ( ) ; it ! = std : : prev ( nodes . end ( ) , 1 ) ; + + it ) {
m_ast = * it ;
m_ast_stack . push ( * it ) ;
m_env = env ;
m_env_stack . push ( env ) ;
evalImpl ( ) ;
evalImpl ( ) ;
}
}
// Eval last node
// Eval last node
m_ast = nodes . back ( ) ;
m_ast_stack . push ( nodes . back ( ) ) ;
m_env = env ;
m_env_stack . push ( env ) ;
return ; // TCO
return ; // TCO
}
}
@ -187,18 +138,18 @@ void Eval::evalIf(const ValueVector& nodes, EnvironmentPtr env)
auto second_argument = * std : : next ( nodes . begin ( ) ) ;
auto second_argument = * std : : next ( nodes . begin ( ) ) ;
auto third_argument = ( nodes . size ( ) = = 3 ) ? * std : : next ( std : : next ( nodes . begin ( ) ) ) : makePtr < Constant > ( Constant : : Nil ) ;
auto third_argument = ( nodes . size ( ) = = 3 ) ? * std : : next ( std : : next ( nodes . begin ( ) ) ) : makePtr < Constant > ( Constant : : Nil ) ;
m_ast = first_argument ;
m_ast_stack . push ( first_argument ) ;
m_env = env ;
m_env_stack . push ( env ) ;
auto first_evaluated = evalImpl ( ) ;
auto first_evaluated = evalImpl ( ) ;
if ( ! is < Constant > ( first_evaluated . get ( ) )
if ( ! is < Constant > ( first_evaluated . get ( ) )
| | std : : static_pointer_cast < Constant > ( first_evaluated ) - > state ( ) = = Constant : : True ) {
| | std : : static_pointer_cast < Constant > ( first_evaluated ) - > state ( ) = = Constant : : True ) {
m_ast = second_argument ;
m_ast_stack . push ( second_argument ) ;
m_env = env ;
m_env_stack . push ( env ) ;
return ; // TCO
return ; // TCO
}
}
m_ast = third_argument ;
m_ast_stack . push ( third_argument ) ;
m_env = env ;
m_env_stack . push ( env ) ;
return ; // TCO
return ; // TCO
}
}
@ -222,16 +173,16 @@ void Eval::evalLet(const ValueVector& nodes, EnvironmentPtr env)
VALUE_CAST ( elt , Symbol , ( * it ) , void ( ) ) ;
VALUE_CAST ( elt , Symbol , ( * it ) , void ( ) ) ;
std : : string key = elt - > symbol ( ) ;
std : : string key = elt - > symbol ( ) ;
m_ast = * std : : next ( it ) ;
m_ast_stack . push ( * std : : next ( it ) ) ;
m_env = let_env ;
m_env_stack . push ( let_env ) ;
ValuePtr value = evalImpl ( ) ;
ValuePtr value = evalImpl ( ) ;
let_env - > set ( key , value ) ;
let_env - > set ( key , value ) ;
}
}
// TODO: Remove limitation of 3 arguments
// TODO: Remove limitation of 3 arguments
// Eval all arguments in this new env, return last sexp of the result
// Eval all arguments in this new env, return last sexp of the result
m_ast = * std : : next ( nodes . begin ( ) ) ;
m_ast_stack . push ( * std : : next ( nodes . begin ( ) ) ) ;
m_env = let_env ;
m_env_stack . push ( let_env ) ;
return ; // TCO
return ; // TCO
}
}
@ -326,8 +277,53 @@ void Eval::evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env)
auto result = evalQuasiQuoteImpl ( nodes . front ( ) ) ;
auto result = evalQuasiQuoteImpl ( nodes . front ( ) ) ;
m_ast = result ;
m_ast_stack . push ( result ) ;
m_env = env ;
m_env_stack . push ( env ) ;
return ; // TCO
}
// (try* x (catch* y z))
void Eval : : evalTry ( const ValueVector & nodes , EnvironmentPtr env )
{
CHECK_ARG_COUNT_AT_LEAST ( " try* " , nodes . size ( ) , 1 , void ( ) ) ;
// Try 'x'
m_ast_stack . push ( nodes . front ( ) ) ;
m_env_stack . push ( env ) ;
auto result = evalImpl ( ) ;
// Catch
if ( nodes . size ( ) = = 2 & & ( Error : : the ( ) . hasOtherError ( ) | | Error : : the ( ) . hasException ( ) ) ) {
// Get the exception
auto error = ( Error : : the ( ) . hasOtherError ( ) )
? makePtr < String > ( Error : : the ( ) . otherError ( ) )
: Error : : the ( ) . exception ( ) ;
Error : : the ( ) . clearErrors ( ) ;
VALUE_CAST ( catch_list , List , nodes . back ( ) , void ( ) ) ;
const auto & catch_nodes = catch_list - > nodes ( ) ;
CHECK_ARG_COUNT_IS ( " catch* " , catch_nodes . size ( ) - 1 , 2 , void ( ) ) ;
VALUE_CAST ( catch_symbol , Symbol , catch_nodes . front ( ) , void ( ) ) ;
if ( catch_symbol - > symbol ( ) ! = " catch* " ) {
Error : : the ( ) . add ( " catch block must begin with catch* " ) ;
return ;
}
VALUE_CAST ( catch_binding , Symbol , ( * std : : next ( catch_nodes . begin ( ) ) ) , void ( ) ) ;
// Create new Environment that binds 'y' to the value of the exception
auto catch_env = Environment : : create ( env ) ;
catch_env - > set ( catch_binding - > symbol ( ) , error ) ;
// Evaluate 'z' using the new Environment
m_ast_stack . push ( catch_nodes . back ( ) ) ;
m_env_stack . push ( catch_env ) ;
return ; // TCO
}
m_ast_stack . push ( result ) ;
m_env_stack . push ( env ) ;
return ; // TCO
return ; // TCO
}
}