EnvPtr Env::InitializeGlobalEnv() { EnvPtr global = make_shared<Env>(); global->AddProcedure("+", [] (const List& lst) -> LispData { auto summator = [] (const LispData& a, const DataPtr b) -> LispData { if (a.GetType() == integer_type && b->GetType() == integer_type) { return LispData(a.GetInt() + b->GetInt()); } else { return LispData(a.GetFloat() + b->GetFloat()); } }; return accumulate(begin(lst), end(lst), LispData(0L), summator); }); global->AddProcedure("-", [] (const List& lst) -> LispData { if (lst.size() != 2) { throw WrongArity("-"); } LispData a = *lst.front(); LispData b = *lst.back(); if (a.GetType() == integer_type && b.GetType() == integer_type) { return LispData(a.GetInt() - b.GetInt()); } else { return LispData(a.GetFloat() - b.GetFloat()); } }); global->AddProcedure("*", [] (const List& lst) -> LispData { auto multiplicator = [] (const LispData& a, const DataPtr b) -> LispData { if (a.GetType() == integer_type && b->GetType() == integer_type) { return LispData(a.GetInt() * b->GetInt()); } else { return LispData(a.GetFloat() * b->GetFloat()); } }; return accumulate(begin(lst), end(lst), LispData(1), multiplicator); }); global->AddProcedure("/", [] (const List& lst) -> LispData { if (lst.size() != 2) { throw WrongArity("/"); } LispData a = *lst.front(); LispData b = *lst.back(); if (fabs(b.GetFloat()) < 1e-15) { throw runtime_error("Zero division"); } if (a.GetType() == integer_type && b.GetType() == integer_type) { return LispData(a.GetInt() / b.GetInt()); } else { return LispData(a.GetFloat() / b.GetFloat()); } }); global->AddProcedure("=", [] (const List& lst) -> LispData { if (lst.size() != 2) { throw WrongArity("="); } LispData a = *lst.front(); LispData b = *lst.back(); return LispData(a.GetFloat() == b.GetFloat()); }); global->AddProcedure("cons", [] (const List& lst) -> LispData { if (lst.size() != 2) { throw WrongArity("cons"); } return LispData(lst); }); global->AddProcedure("car", [] (const List& lst) -> LispData { if (lst.size() != 1) { throw WrongArity("car"); } if (lst.front()->GetType() != list_type) { throw runtime_error("Not pair type given to 'car'."); } return LispData(*lst.front()->GetListRef()->front()); }); global->AddProcedure("cdr", [] (const List& lst) -> LispData { if (lst.size() != 1) { throw WrongArity("cdr"); } auto pair = lst.front(); if (pair->GetType() != list_type || pair->GetListRef()->size() != 2) { throw runtime_error("Not pair type given to 'cdr'."); } return LispData(*pair->GetListRef()->back()); }); global->AddProcedure("null?", [] (const List& lst) -> LispData { if (lst.size() != 1) { throw WrongArity("null?"); } auto pair = lst.front(); if (pair->GetType() != list_type) { throw runtime_error("Not pair type given to 'null?'."); } return LispData(pair->GetListRef()->empty()); }); (*global)["nil"] = LispData(List()); global->AddProcedure("exit", [] (const List&) -> LispData { exit(0); }); return global; }