// Copyright 2021 Benjamin Barenblat // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "src/builtin.h" #include #include #include #include #include "src/language.h" #include "third_party/abseil/absl/container/flat_hash_map.h" #include "third_party/abseil/absl/memory/memory.h" #include "third_party/abseil/absl/strings/string_view.h" namespace ec { namespace { // Requires the compiler to select the double-valued overload of its argument. double (*DoubleOverload(double (*f)(double)) noexcept)(double) { return f; } double (*DoubleOverload(double (*f)(double, double)) noexcept)(double, double) { return f; } // Pops the top of the stack and returns it as a GroundTerm; throws TypeError if // it's not. std::shared_ptr PopGroundTerm(absl::string_view op, State& s) { if (s.stack.empty()) { throw StackUnderflow(op); } auto ground = std::dynamic_pointer_cast(s.stack.back()); if (ground == nullptr) { throw TypeError( absl::StrCat("expected number; got ", s.stack.back()->Show())); } s.stack.pop_back(); return ground; } // Executes a unary operation on the top of the stack. void Unop(absl::string_view op, std::function f, State& s) { if (s.stack.empty()) { throw StackUnderflow(op); } s.stack.push_back(GroundTerm::Make(f(PopGroundTerm(op, s)->value()))); } // Executes a binary operation on the top of the stack. void Binop(absl::string_view op, std::function f, State& s) { if (s.stack.size() < 2) { throw StackUnderflow(op); } std::shared_ptr right, left; right = PopGroundTerm(op, s); left = PopGroundTerm(op, s); s.stack.push_back(GroundTerm::Make(f(left->value(), right->value()))); } } // namespace absl::flat_hash_map> BuiltinEnvironment() noexcept { return { {"dup", ForeignProgramTerm::Make(BuiltinDup)}, // {"drop", ForeignProgramTerm::Make(BuiltinDrop)}, // {"swap", ForeignProgramTerm::Make(BuiltinSwap)}, {"pi", GroundTerm::Make(M_PI)}, // {"e", GroundTerm::Make(M_E)}, {"neg", ForeignProgramTerm::Make(BuiltinNeg)}, // {"inv", ForeignProgramTerm::Make(BuiltinInv)}, // {"sq", ForeignProgramTerm::Make(BuiltinSq)}, // {"sqrt", ForeignProgramTerm::Make(BuiltinSqrt)}, // {"alog", ForeignProgramTerm::Make(BuiltinAlog)}, // {"log", ForeignProgramTerm::Make(BuiltinLog)}, // {"exp", ForeignProgramTerm::Make(BuiltinExp)}, // {"ln", ForeignProgramTerm::Make(BuiltinLn)}, // {"sin", ForeignProgramTerm::Make(BuiltinSin)}, // {"cos", ForeignProgramTerm::Make(BuiltinCos)}, // {"tan", ForeignProgramTerm::Make(BuiltinTan)}, // {"asin", ForeignProgramTerm::Make(BuiltinAsin)}, // {"acos", ForeignProgramTerm::Make(BuiltinAcos)}, // {"atan", ForeignProgramTerm::Make(BuiltinAtan)}, // {"abs", ForeignProgramTerm::Make(BuiltinAbs)}, {"add", ForeignProgramTerm::Make(BuiltinAdd)}, // {"sub", ForeignProgramTerm::Make(BuiltinSub)}, // {"mul", ForeignProgramTerm::Make(BuiltinMul)}, // {"div", ForeignProgramTerm::Make(BuiltinDiv)}, // {"pow", ForeignProgramTerm::Make(BuiltinPow)}, // {"xroot", ForeignProgramTerm::Make(BuiltinXroot)}, }; } void BuiltinDup(State& s) { if (s.stack.empty()) { throw StackUnderflow("dup"); } s.stack.push_back(s.stack.back()->Clone()); } void BuiltinDrop(State& s) { if (s.stack.empty()) { throw StackUnderflow("drop"); } s.stack.pop_back(); } void BuiltinSwap(State& s) { if (s.stack.size() < 2) { throw StackUnderflow("swap"); } std::shared_ptr x, y; x = s.stack.back(); s.stack.pop_back(); y = s.stack.back(); s.stack.pop_back(); s.stack.insert(s.stack.end(), {x, y}); } void BuiltinNeg(State& s) { Unop("neg", std::negate(), s); } void BuiltinInv(State& s) { Unop( "inv", [](double d) { return 1 / d; }, s); } void BuiltinSq(State& s) { Unop( "sq", [](double d) { return d * d; }, s); } void BuiltinSqrt(State& s) { Unop("sqrt", DoubleOverload(sqrt), s); } void BuiltinAlog(State& s) { Unop( "alog", [](double d) { return pow(10, d); }, s); } void BuiltinLog(State& s) { Unop("log", DoubleOverload(log10), s); } void BuiltinExp(State& s) { Unop("exp", DoubleOverload(exp), s); } void BuiltinLn(State& s) { Unop("ln", DoubleOverload(log), s); } void BuiltinSin(State& s) { Unop("sin", DoubleOverload(sin), s); } void BuiltinCos(State& s) { Unop("cos", DoubleOverload(cos), s); } void BuiltinTan(State& s) { Unop("tan", DoubleOverload(tan), s); } void BuiltinAsin(State& s) { Unop("asin", DoubleOverload(asin), s); } void BuiltinAcos(State& s) { Unop("acos", DoubleOverload(acos), s); } void BuiltinAtan(State& s) { Unop("atan", DoubleOverload(atan), s); } void BuiltinAbs(State& s) { Unop("abs", DoubleOverload(fabs), s); } void BuiltinAdd(State& s) { Binop("add", std::plus(), s); } void BuiltinSub(State& s) { Binop("sub", std::minus(), s); } void BuiltinMul(State& s) { Binop("mul", std::multiplies(), s); } void BuiltinDiv(State& s) { Binop("div", std::divides(), s); } void BuiltinPow(State& s) { Binop("div", DoubleOverload(pow), s); } void BuiltinXroot(State& s) { Binop( "xroot", [](double y, double x) { return pow(y, 1 / x); }, s); } } // namespace ec